add opaque minimize/shade feature. The wireframe seemed kind of confusing

2001-08-06  Havoc Pennington  <hp@pobox.com>

	* src/effects.c: add opaque minimize/shade feature.  The wireframe
	seemed kind of confusing and unclear from a UI standpoint.
	I know, I know. The bloat begins here.

	Also, we don't need to grab the server during opaque min/shade,
	which has some nice implications.

	* src/ui.c: Add features to render a window with an image in it,
	and also wrap pixbuf_from_drawable

	* src/effects.c (meta_effects_draw_box_animation):
	modify to be smoother (at least theoretically) by
	syncing to current time and "dropping frames"
	as appropriate.

	* src/window.c (meta_window_shade): draw animation
	for shading too
This commit is contained in:
Havoc Pennington 2001-08-06 07:58:49 +00:00 committed by rhp
parent d8561cb4c3
commit 11b14d327f
6 changed files with 269 additions and 54 deletions

View File

@ -1,10 +1,19 @@
2001-08-06 Havoc Pennington <hp@pobox.com>
* src/effects.c: add opaque minimize/shade feature. The wireframe
seemed kind of confusing and unclear from a UI standpoint.
I know, I know. The bloat begins here.
Also, we don't need to grab the server during opaque min/shade,
which has some nice implications.
* src/ui.c: Add features to render a window with an image in it,
and also wrap pixbuf_from_drawable
* src/effects.c (meta_effects_draw_box_animation):
modify to be smoother (at least theoretically) by
syncing to current time and "dropping frames"
as appropriate. A precursor to flashier animations
that take more CPU to do.
as appropriate.
* src/window.c (meta_window_shade): draw animation
for shading too

View File

@ -21,12 +21,11 @@
#include "effects.h"
#include "display.h"
#include "ui.h"
typedef struct
{
MetaScreen *screen;
GC gc;
double millisecs_duration;
GTimeVal start_time;
@ -38,6 +37,18 @@ typedef struct
/* rect to erase */
MetaRectangle last_rect;
/* used instead of the global flag, since
* we don't want to change midstream.
*/
gboolean use_opaque;
/* For wireframe */
GC gc;
/* For opaque */
MetaImageWindow *image_window;
GdkPixbuf *orig_pixbuf;
} BoxAnimationContext;
@ -51,12 +62,15 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
if (!context->first_time)
{
/* Restore the previously drawn background */
XDrawRectangle (context->screen->display->xdisplay,
context->screen->xroot,
context->gc,
context->last_rect.x, context->last_rect.y,
context->last_rect.width, context->last_rect.height);
if (!context->use_opaque)
{
/* Restore the previously drawn background */
XDrawRectangle (context->screen->display->xdisplay,
context->screen->xroot,
context->gc,
context->last_rect.x, context->last_rect.y,
context->last_rect.width, context->last_rect.height);
}
}
context->first_time = FALSE;
@ -78,9 +92,18 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
if (elapsed > context->millisecs_duration)
{
/* All done */
meta_display_ungrab (context->screen->display);
XFreeGC (context->screen->display->xdisplay,
context->gc);
if (context->use_opaque)
{
g_object_unref (G_OBJECT (context->orig_pixbuf));
meta_image_window_free (context->image_window);
}
else
{
meta_display_ungrab (context->screen->display);
XFreeGC (context->screen->display->xdisplay,
context->gc);
}
g_free (context);
return FALSE;
}
@ -96,24 +119,54 @@ effects_draw_box_animation_timeout (BoxAnimationContext *context)
draw_rect.width += (context->end_rect.width - context->start_rect.width) * fraction;
draw_rect.height += (context->end_rect.height - context->start_rect.height) * fraction;
/* don't confuse X with bogus rectangles */
/* don't confuse X or gdk-pixbuf with bogus rectangles */
if (draw_rect.width < 1)
draw_rect.width = 1;
if (draw_rect.height < 1)
draw_rect.height = 1;
context->last_rect = draw_rect;
/* Draw the rectangle */
XDrawRectangle (context->screen->display->xdisplay,
context->screen->xroot,
context->gc,
draw_rect.x, draw_rect.y,
draw_rect.width, draw_rect.height);
if (context->use_opaque)
{
GdkPixbuf *scaled;
scaled = gdk_pixbuf_scale_simple (context->orig_pixbuf,
draw_rect.width,
draw_rect.height,
GDK_INTERP_BILINEAR);
meta_image_window_set_image (context->image_window,
scaled);
meta_image_window_set_position (context->image_window,
draw_rect.x, draw_rect.y);
g_object_unref (G_OBJECT (scaled));
}
else
{
/* Draw the rectangle */
XDrawRectangle (context->screen->display->xdisplay,
context->screen->xroot,
context->gc,
draw_rect.x, draw_rect.y,
draw_rect.width, draw_rect.height);
}
/* kick changes onto the server */
XFlush (context->screen->display->xdisplay);
return TRUE;
}
/* I really don't want this to be a configuration option,
* but I think the wireframe is sucky from a UI standpoint
* (more confusing than opaque), but the opaque is maybe
* too slow on some systems; so perhaps we could autodetect
* system beefiness or someting, or have some global
* "my system is slow" config option.
*/
static gboolean use_opaque_animations = TRUE;
void
meta_effects_draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect,
@ -121,7 +174,6 @@ meta_effects_draw_box_animation (MetaScreen *screen,
double seconds_duration)
{
BoxAnimationContext *context;
XGCValues gc_values;
g_return_if_fail (seconds_duration > 0.0);
@ -129,26 +181,62 @@ meta_effects_draw_box_animation (MetaScreen *screen,
seconds_duration *= 10; /* slow things down */
/* Create the animation context */
context = g_new (BoxAnimationContext, 1);
gc_values.subwindow_mode = IncludeInferiors;
gc_values.function = GXinvert;
/* Create a gc for the root window */
context = g_new0 (BoxAnimationContext, 1);
context->screen = screen;
context->gc = XCreateGC (screen->display->xdisplay,
screen->xroot,
GCSubwindowMode | GCFunction,
&gc_values);
context->millisecs_duration = seconds_duration * 1000.0;
g_get_current_time (&context->start_time);
context->first_time = TRUE;
context->start_rect = *initial_rect;
context->end_rect = *destination_rect;
/* Grab the X server to avoid screen dirt */
meta_display_grab (context->screen->display);
context->use_opaque = use_opaque_animations;
if (context->use_opaque)
{
GdkPixbuf *pix;
pix = meta_gdk_pixbuf_get_from_window (NULL,
screen->xroot,
initial_rect->x,
initial_rect->y,
0, 0,
initial_rect->width,
initial_rect->height);
if (pix == NULL)
{
/* Fall back to wireframe */
context->use_opaque = FALSE;
}
else
{
context->image_window = meta_image_window_new ();
context->orig_pixbuf = pix;
meta_image_window_set_position (context->image_window,
initial_rect->x,
initial_rect->y);
meta_image_window_set_showing (context->image_window, TRUE);
}
}
/* Not an else, so that fallback works */
if (!context->use_opaque)
{
XGCValues gc_values;
gc_values.subwindow_mode = IncludeInferiors;
gc_values.function = GXinvert;
context->gc = XCreateGC (screen->display->xdisplay,
screen->xroot,
GCSubwindowMode | GCFunction,
&gc_values);
/* Grab the X server to avoid screen dirt */
meta_display_grab (context->screen->display);
}
/* Add the timeout - a short one, could even use an idle,
* but this is maybe more CPU-friendly.
@ -157,3 +245,6 @@ meta_effects_draw_box_animation (MetaScreen *screen,
(GSourceFunc)effects_draw_box_animation_timeout,
context);
}

View File

@ -25,8 +25,8 @@
#include "util.h"
#include "screen.h"
#define META_MINIMIZE_ANIMATION_LENGTH 0.3
#define META_SHADE_ANIMATION_LENGTH 0.15
#define META_MINIMIZE_ANIMATION_LENGTH 0.5
#define META_SHADE_ANIMATION_LENGTH 0.2
void meta_effects_draw_box_animation (MetaScreen *screen,
MetaRectangle *initial_rect,

View File

@ -232,3 +232,94 @@ meta_ui_window_menu_free (MetaWindowMenu *menu)
meta_window_menu_free (menu);
}
struct _MetaImageWindow
{
GtkWidget *window;
GtkWidget *image;
};
MetaImageWindow*
meta_image_window_new (void)
{
MetaImageWindow *iw;
iw = g_new (MetaImageWindow, 1);
iw->window = gtk_window_new (GTK_WINDOW_POPUP);
iw->image = g_object_new (GTK_TYPE_IMAGE, NULL);
gtk_container_add (GTK_CONTAINER (iw->window), iw->image);
/* Ensure we auto-shrink to fit image */
gtk_window_set_resizable (GTK_WINDOW (iw->window),
FALSE);
return iw;
}
void
meta_image_window_free (MetaImageWindow *iw)
{
gtk_widget_destroy (iw->window);
g_free (iw);
}
void
meta_image_window_set_showing (MetaImageWindow *iw,
gboolean showing)
{
if (showing)
gtk_widget_show_all (iw->window);
else
gtk_widget_hide (iw->window);
}
void
meta_image_window_set_image (MetaImageWindow *iw,
GdkPixbuf *pixbuf)
{
gtk_image_set_from_pixbuf (GTK_IMAGE (iw->image), pixbuf);
}
void
meta_image_window_set_position (MetaImageWindow *iw,
int x,
int y)
{
gtk_widget_set_uposition (iw->window, x, y);
}
GdkPixbuf*
meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
Window xwindow,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height)
{
GdkDrawable *drawable;
GdkPixbuf *retval;
retval = NULL;
drawable = gdk_xid_table_lookup (xwindow);
if (drawable)
g_object_ref (G_OBJECT (drawable));
else
drawable = gdk_window_foreign_new (xwindow);
retval = gdk_pixbuf_get_from_drawable (dest,
drawable,
/* We assume root window cmap */
gdk_colormap_get_system (),
src_x, src_y,
dest_x, dest_y,
width, height);
g_object_unref (G_OBJECT (drawable));
return retval;
}

View File

@ -22,13 +22,16 @@
#ifndef META_UI_H
#define META_UI_H
/* Don't include gtk.h here */
/* Don't include gtk.h or gdk.h here */
#include "common.h"
#include <X11/Xlib.h>
#include <glib.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
typedef struct _MetaUI MetaUI;
typedef struct _MetaImageWindow MetaImageWindow;
typedef gboolean (* MetaEventFunc) (XEvent *xevent, gpointer data);
void meta_ui_init (int *argc, char ***argv);
@ -88,5 +91,22 @@ void meta_ui_window_menu_popup (MetaWindowMenu *menu,
void meta_ui_window_menu_free (MetaWindowMenu *menu);
MetaImageWindow* meta_image_window_new (void);
void meta_image_window_free (MetaImageWindow *iw);
void meta_image_window_set_showing (MetaImageWindow *iw,
gboolean showing);
void meta_image_window_set_image (MetaImageWindow *iw,
GdkPixbuf *pixbuf);
void meta_image_window_set_position (MetaImageWindow *iw,
int x,
int y);
GdkPixbuf* meta_gdk_pixbuf_get_from_window (GdkPixbuf *dest,
Window xwindow,
int src_x,
int src_y,
int dest_x,
int dest_y,
int width,
int height);
#endif

View File

@ -1063,22 +1063,26 @@ meta_window_shade (MetaWindow *window)
meta_verbose ("Shading %s\n", window->desc);
if (!window->shaded)
{
{
/* Animation */
MetaRectangle starting_size;
MetaRectangle titlebar_size;
meta_window_get_outer_rect (window, &starting_size);
if (window->frame)
starting_size.y += window->frame->child_y;
titlebar_size = starting_size;
titlebar_size.height = 0;
meta_effects_draw_box_animation (window->screen,
&starting_size,
&titlebar_size,
META_SHADE_ANIMATION_LENGTH);
}
if (window->mapped)
{
/* Animation */
MetaRectangle starting_size;
MetaRectangle titlebar_size;
meta_window_get_outer_rect (window, &starting_size);
if (window->frame)
{
starting_size.y += window->frame->child_y;
starting_size.height -= window->frame->child_y;
}
titlebar_size = starting_size;
titlebar_size.height = 0;
meta_effects_draw_box_animation (window->screen,
&starting_size,
&titlebar_size,
META_SHADE_ANIMATION_LENGTH);
}
window->shaded = TRUE;