From 9244f0f1137e02752d02d985856b191c44817f88 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Sun, 28 Jun 2009 12:26:23 -0400 Subject: [PATCH] Move window repair and reshape to a paint function Add a paint function that checks all windows for repair and shape updates; this: - simplifies the logic for when a window needs to be repaired - avoids duplicate work when we get multiple damage effects - avoids the need to look ahead in the event queue Instead of relying on repair to implicitly resize the MutterWindow actor, set the size explicitly when the core code updates the geometry. (This is needed because we haven't repaired yet when we start an animation, and the animation may depend on the size to, e.g., rescale from the center.) Because the core geometry update happens before we start maximize/unmaximize effects we need to work around this by passing both the old and new geometry to the compositor. http://bugzilla.gnome.org/show_bug.cgi?id=587251 --- src/compositor/compositor-private.h | 1 + src/compositor/compositor.c | 44 ++++++- src/compositor/mutter-window-private.h | 8 +- src/compositor/mutter-window.c | 168 +++++++++++++++++-------- src/core/window.c | 21 ++-- src/include/compositor.h | 6 +- 6 files changed, 178 insertions(+), 70 deletions(-) diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 7d4e97ee6..02fe426a4 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -19,6 +19,7 @@ struct _MetaCompositor Atom atom_x_root_pixmap; Atom atom_x_set_root; Atom atom_net_wm_window_opacity; + guint repaint_func_id; ClutterActor *shadow_src; diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 08dd9b984..13c5fe9a0 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -142,6 +142,7 @@ mutter_switch_workspace_completed (MetaScreen *screen) void meta_compositor_destroy (MetaCompositor *compositor) { + clutter_threads_remove_repaint_func (compositor->repaint_func_id); } static void @@ -704,27 +705,29 @@ meta_compositor_unminimize_window (MetaCompositor *compositor, void meta_compositor_maximize_window (MetaCompositor *compositor, MetaWindow *window, - MetaRectangle *window_rect) + MetaRectangle *old_rect, + MetaRectangle *new_rect) { MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_maximize_window\n"); if (!cw) return; - mutter_window_maximize (cw, window_rect); + mutter_window_maximize (cw, old_rect, new_rect); } void meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaWindow *window, - MetaRectangle *window_rect) + MetaRectangle *old_rect, + MetaRectangle *new_rect) { MutterWindow *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window)); DEBUG_TRACE ("meta_compositor_unmaximize_window\n"); if (!cw) return; - mutter_window_unmaximize (cw, window_rect); + mutter_window_unmaximize (cw, old_rect, new_rect); } void @@ -976,6 +979,35 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor, width, height); } +static void +pre_paint_windows (MetaCompScreen *info) +{ + GList *l; + + for (l = info->windows; l; l = l->next) + mutter_window_pre_paint (l->data); +} + +static gboolean +mutter_repaint_func (gpointer data) +{ + MetaCompositor *compositor = data; + GSList *screens = meta_display_get_screens (compositor->display); + GSList *l; + + for (l = screens; l; l = l->next) + { + MetaScreen *screen = l->data; + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + if (!info) + continue; + + pre_paint_windows (info); + } + + return TRUE; +} + MetaCompositor * meta_compositor_new (MetaDisplay *display) { @@ -1006,6 +1038,10 @@ meta_compositor_new (MetaDisplay *display) compositor->atom_x_set_root = atoms[1]; compositor->atom_net_wm_window_opacity = atoms[2]; + compositor->repaint_func_id = clutter_threads_add_repaint_func (mutter_repaint_func, + compositor, + NULL); + return compositor; } diff --git a/src/compositor/mutter-window-private.h b/src/compositor/mutter-window-private.h index 68be514dc..8dfa4b319 100644 --- a/src/compositor/mutter-window-private.h +++ b/src/compositor/mutter-window-private.h @@ -14,12 +14,16 @@ void mutter_window_minimize (MutterWindow *cw); void mutter_window_destroy (MutterWindow *cw); void mutter_window_maximize (MutterWindow *cw, - MetaRectangle *window_rect); + MetaRectangle *old_rect, + MetaRectangle *new_rect); void mutter_window_unmaximize (MutterWindow *cw, - MetaRectangle *window_rect); + MetaRectangle *old_rect, + MetaRectangle *new_rect); void mutter_window_process_damage (MutterWindow *cw, XDamageNotifyEvent *event); +void mutter_window_pre_paint (MutterWindow *self); + gboolean mutter_window_effect_in_progress (MutterWindow *cw, gboolean include_destroy); void mutter_window_sync_actor_position (MutterWindow *cw); diff --git a/src/compositor/mutter-window.c b/src/compositor/mutter-window.c index 5c3261d5c..13ff437d2 100644 --- a/src/compositor/mutter-window.c +++ b/src/compositor/mutter-window.c @@ -61,6 +61,8 @@ struct _MutterWindowPrivate guint needs_map : 1; guint needs_unmap : 1; guint needs_repair : 1; + guint needs_reshape : 1; + guint size_changed : 1; guint needs_destroy : 1; @@ -94,7 +96,6 @@ static void mutter_window_detach (MutterWindow *self); static gboolean mutter_window_has_shadow (MutterWindow *self); -static void repair_win (MutterWindow *self); static gboolean is_shaped (MetaDisplay *display, Window xwindow); /* @@ -739,6 +740,27 @@ mutter_window_effect_in_progress (MutterWindow *self, (include_destroy && self->priv->destroy_in_progress)); } +static void +mutter_window_mark_for_repair (MutterWindow *self) +{ + MutterWindowPrivate *priv = self->priv; + + priv->needs_repair = TRUE; + + if (priv->attrs.map_state == IsUnmapped) + return; + + /* This will cause the compositor paint function to be run + * if the actor is visible or a clone of the actor is visible. + * if the actor isn't visible in any way, then we don't + * need to repair the window anyways, and can wait until + * the stage is redrawn for some other reason + * + * The compositor paint function repairs all windows. + */ + clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); +} + void mutter_window_effect_completed (MutterWindow *self, gulong event) @@ -839,8 +861,7 @@ mutter_window_effect_completed (MutterWindow *self, MetaRectangle rect; meta_window_get_outer_rect (priv->window, &rect); clutter_actor_set_position (actor, rect.x, rect.y); - mutter_window_detach (self); - repair_win (self); + clutter_actor_set_size (actor, rect.width,rect.height); effect_done = TRUE; } break; @@ -857,8 +878,7 @@ mutter_window_effect_completed (MutterWindow *self, MetaRectangle rect; meta_window_get_outer_rect (priv->window, &rect); clutter_actor_set_position (actor, rect.x, rect.y); - mutter_window_detach (self); - repair_win (self); + clutter_actor_set_size (actor, rect.width, rect.height); effect_done = TRUE; } break; @@ -895,11 +915,22 @@ mutter_window_effect_completed (MutterWindow *self, return; } + if (effect_done && + (priv->needs_repair || priv->needs_reshape)) + { + /* Make sure that pre_paint function gets called */ + clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); + } default: break; } } +/* Called to drop our reference to a window backing pixmap that we + * previously obtained with XCompositeNameWindowPixmap. We do this + * when the window is unmapped or when we want to update to a new + * pixmap for a new size. + */ static void mutter_window_detach (MutterWindow *self) { @@ -913,6 +944,7 @@ mutter_window_detach (MutterWindow *self) XFreePixmap (xdisplay, priv->back_pixmap); priv->back_pixmap = None; + mutter_window_mark_for_repair (self); } void @@ -990,7 +1022,10 @@ mutter_window_sync_actor_position (MutterWindow *self) if (priv->attrs.width != window_rect.width || priv->attrs.height != window_rect.height) - mutter_window_detach (self); + { + priv->size_changed = TRUE; + mutter_window_mark_for_repair (self); + } /* XXX deprecated: please use meta_window_get_outer_rect instead */ priv->attrs.width = window_rect.width; @@ -1002,7 +1037,9 @@ mutter_window_sync_actor_position (MutterWindow *self) return; clutter_actor_set_position (CLUTTER_ACTOR (self), - window_rect.x, window_rect.y); + window_rect.x, window_rect.y); + clutter_actor_set_size (CLUTTER_ACTOR (self), + window_rect.width, window_rect.height); } void @@ -1022,13 +1059,7 @@ mutter_window_map (MutterWindow *self) priv->attrs.map_state = IsViewable; - /* - * Now repair the window; this ensures that the actor is correctly sized - * before we run any effects on it. - */ - priv->needs_map = FALSE; - mutter_window_detach (self); - repair_win (self); + mutter_window_mark_for_repair (self); /* * Make sure the position is set correctly (we might have got moved while @@ -1131,18 +1162,25 @@ mutter_window_minimize (MutterWindow *self) void mutter_window_maximize (MutterWindow *self, - MetaRectangle *window_rect) + MetaRectangle *old_rect, + MetaRectangle *new_rect) { MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + /* The window has already been resized (in order to compute new_rect), + * which by side effect caused the actor to be resized. Restore it to the + * old size and position */ + clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y); + clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height); + self->priv->maximize_in_progress++; if (!info->plugin_mgr || !mutter_plugin_manager_event_maximize (info->plugin_mgr, self, MUTTER_PLUGIN_MAXIMIZE, - window_rect->x, window_rect->y, - window_rect->width, window_rect->height)) + new_rect->x, new_rect->y, + new_rect->width, new_rect->height)) { self->priv->maximize_in_progress--; @@ -1151,18 +1189,25 @@ mutter_window_maximize (MutterWindow *self, void mutter_window_unmaximize (MutterWindow *self, - MetaRectangle *window_rect) + MetaRectangle *old_rect, + MetaRectangle *new_rect) { MetaCompScreen *info = meta_screen_get_compositor_data (self->priv->screen); + /* The window has already been resized (in order to compute new_rect), + * which by side effect caused the actor to be resized. Restore it to the + * old size and position */ + clutter_actor_set_position (CLUTTER_ACTOR (self), old_rect->x, old_rect->y); + clutter_actor_set_size (CLUTTER_ACTOR (self), old_rect->width, old_rect->height); + self->priv->unmaximize_in_progress++; if (!info->plugin_mgr || !mutter_plugin_manager_event_maximize (info->plugin_mgr, self, MUTTER_PLUGIN_UNMAXIMIZE, - window_rect->x, window_rect->y, - window_rect->width, window_rect->height)) + new_rect->x, new_rect->y, + new_rect->width, new_rect->height)) { self->priv->unmaximize_in_progress--; } @@ -1202,8 +1247,7 @@ mutter_window_new (MetaWindow *window) priv = self->priv; - clutter_actor_set_position (CLUTTER_ACTOR (self), - priv->attrs.x, priv->attrs.y); + mutter_window_sync_actor_position (self); /* Hang our compositor window state off the MetaWindow for fast retrieval */ meta_window_set_compositor_private (window, G_OBJECT (self)); @@ -1230,7 +1274,7 @@ mutter_window_new (MetaWindow *window) } static void -repair_win (MutterWindow *self) +check_needs_repair (MutterWindow *self) { MutterWindowPrivate *priv = self->priv; MetaScreen *screen = priv->screen; @@ -1241,12 +1285,24 @@ repair_win (MutterWindow *self) Window xwindow = priv->xwindow; gboolean full = FALSE; + if (!priv->needs_repair) + return; + + if (priv->attrs.map_state == IsUnmapped) + return; + if (xwindow == meta_screen_get_xroot (screen) || xwindow == clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage))) return; compositor = meta_display_get_compositor (display); + if (priv->size_changed) + { + mutter_window_detach (self); + priv->size_changed = FALSE; + } + meta_error_trap_push (display); if (priv->back_pixmap == None) @@ -1367,33 +1423,7 @@ void mutter_window_process_damage (MutterWindow *self, XDamageNotifyEvent *event) { - MutterWindowPrivate *priv = self->priv; - Display *dpy = event->display; - Drawable drawable = event->drawable; - XEvent next; - - if (priv->destroy_pending || - priv->maximize_in_progress || - priv->unmaximize_in_progress) - { - priv->needs_repair = TRUE; - return; - } - - /* - * Check if the event queue does not already contain DetstroyNotify for this - * window -- if it does, we need to stop updating the pixmap (to avoid damage - * notifications that come from the window teardown), and process the destroy - * immediately. - */ - if (XCheckTypedWindowEvent (dpy, drawable, DestroyNotify, &next)) - { - priv->destroy_pending = TRUE; - mutter_window_destroy (self); - return; - } - - repair_win (self); + mutter_window_mark_for_repair (self); } void @@ -1412,13 +1442,13 @@ mutter_window_finish_workspace_switch (MutterWindow *self) } } -void -mutter_window_update_shape (MutterWindow *self, - gboolean shaped) +static void +check_needs_reshape (MutterWindow *self) { MutterWindowPrivate *priv = self->priv; - priv->shaped = shaped; + if (!priv->needs_reshape) + return; mutter_shaped_texture_clear_rectangles (MUTTER_SHAPED_TEXTURE (priv->actor)); @@ -1444,6 +1474,36 @@ mutter_window_update_shape (MutterWindow *self, } } #endif + + priv->needs_reshape = FALSE; +} + +void +mutter_window_update_shape (MutterWindow *self, + gboolean shaped) +{ + MutterWindowPrivate *priv = self->priv; + + priv->shaped = shaped; + priv->needs_reshape = TRUE; + + clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); +} + +void +mutter_window_pre_paint (MutterWindow *self) +{ + MutterWindowPrivate *priv = self->priv; + + /* The window is frozen due to a pending animation: we'll wait until + * the animation finishes to reshape and repair the window */ + if (priv->destroy_in_progress || + priv->maximize_in_progress || + priv->unmaximize_in_progress) + return; + + check_needs_reshape (self); + check_needs_repair (self); } void diff --git a/src/core/window.c b/src/core/window.c index cddf73235..613eb2a0a 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -2919,14 +2919,18 @@ meta_window_maximize (MetaWindow *window, if (window->display->compositor) { - MetaRectangle window_rect; + MetaRectangle old_rect; + MetaRectangle new_rect; + + meta_window_get_outer_rect (window, &old_rect); meta_window_move_resize_now (window); - meta_window_get_outer_rect (window, &window_rect); + meta_window_get_outer_rect (window, &new_rect); meta_compositor_maximize_window (window->display->compositor, window, - &window_rect); + &old_rect, + &new_rect); } else { @@ -3035,7 +3039,9 @@ meta_window_unmaximize (MetaWindow *window, if (window->display->compositor) { - MetaRectangle window_rect; + MetaRectangle old_rect, new_rect; + + meta_window_get_outer_rect (window, &old_rect); meta_window_move_resize (window, FALSE, @@ -3043,13 +3049,12 @@ meta_window_unmaximize (MetaWindow *window, target_rect.y, target_rect.width, target_rect.height); - meta_window_move_resize_now (window); - - meta_window_get_outer_rect (window, &window_rect); + meta_window_get_outer_rect (window, &new_rect); meta_compositor_unmaximize_window (window->display->compositor, window, - &window_rect); + &old_rect, + &new_rect); } else { diff --git a/src/include/compositor.h b/src/include/compositor.h index d1a53b07e..370fb4d7c 100644 --- a/src/include/compositor.h +++ b/src/include/compositor.h @@ -84,10 +84,12 @@ void meta_compositor_unminimize_window (MetaCompositor *compositor, MetaRectangle *icon_rect); void meta_compositor_maximize_window (MetaCompositor *compositor, MetaWindow *window, - MetaRectangle *window_rect); + MetaRectangle *old_rect, + MetaRectangle *new_rect); void meta_compositor_unmaximize_window (MetaCompositor *compositor, MetaWindow *window, - MetaRectangle *window_rect); + MetaRectangle *old_rect, + MetaRectangle *new_rect); void meta_compositor_switch_workspace (MetaCompositor *compositor, MetaScreen *screen, MetaWorkspace *from,