diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | src/effects.c | 157 | ||||
-rw-r--r-- | src/effects.h | 4 | ||||
-rw-r--r-- | src/ui.c | 91 | ||||
-rw-r--r-- | src/ui.h | 24 | ||||
-rw-r--r-- | src/window.c | 36 |
6 files changed, 270 insertions, 55 deletions
@@ -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 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); } + + + diff --git a/src/effects.h b/src/effects.h index 9b057441..801b099c 100644 --- a/src/effects.h +++ b/src/effects.h @@ -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, @@ -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; +} + @@ -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 diff --git a/src/window.c b/src/window.c index bce536b9..5bfc6573 100644 --- a/src/window.c +++ b/src/window.c @@ -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; |