From 11b14d327f72a941c8a6db31077ad41b86c2cf80 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 6 Aug 2001 07:58:49 +0000 Subject: add opaque minimize/shade feature. The wireframe seemed kind of confusing 2001-08-06 Havoc Pennington * 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 --- src/effects.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 33 deletions(-) (limited to 'src/effects.c') diff --git a/src/effects.c b/src/effects.c index bb9694fd..bc9f7606 100644 --- a/src/effects.c +++ b/src/effects.c @@ -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); } + + + -- cgit v1.2.1