[mutter] Move window repair and reshape to a paint function



commit 9244f0f1137e02752d02d985856b191c44817f88
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Sun Jun 28 12:26:23 2009 -0400

    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 7d4e97e..02fe426 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 08dd9b9..13c5fe9 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 68be514..8dfa4b3 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 5c3261d..13ff437 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 cddf732..613eb2a 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 d1a53b0..370fb4d 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,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]