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,