[mutter] Move compositor-stack handling to MetaStackTracker



commit 6314ee8780493880f1207ff49f92f4d38bed9a33
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Sun Jun 14 08:04:28 2009 -0400

    Move compositor-stack handling to MetaStackTracker
    
    In order to properly track the stacking order for override-redirect
    windows, move meta_compositor_sync_stack() call into MetaStackTracker.
    In the new location, we sync the stack as a before-redraw idle function,
    rather then using the freeze-thaw facilities of MetaStack. This is
    simpler, and also properly compresses multiple stack changes on
    notifications received from the X server.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=585984

 src/core/screen.c        |    5 +-
 src/core/stack-tracker.c |  130 ++++++++++++++++++++++++++++++++++++++++------
 src/core/stack-tracker.h |    9 ++-
 src/core/stack.c         |   10 ----
 src/core/window.c        |   13 +++++
 5 files changed, 135 insertions(+), 32 deletions(-)
---
diff --git a/src/core/screen.c b/src/core/screen.c
index a72a21d..9b0a95e 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -953,9 +953,8 @@ meta_screen_composite_all_windows (MetaScreen *screen)
     meta_compositor_add_window (display->compositor, tmp->data);
   g_slist_free (windows);
   
-  /* trigger a stack_sync_to_server: */
-  meta_stack_freeze (screen->stack);
-  meta_stack_thaw (screen->stack);
+  /* initialize the compositor's view of the stacking order */
+  meta_stack_tracker_sync_stack (screen->stack_tracker);
 #endif
 }
 
diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c
index 8ea85a2..1c6cdca 100644
--- a/src/core/stack-tracker.c
+++ b/src/core/stack-tracker.c
@@ -27,6 +27,8 @@
 #include "stack-tracker.h"
 #include "util.h"
 
+#include "compositor.h"
+
 /* The complexity here comes from resolving two competing factors:
  *
  *  - We need to have a view of the stacking order that takes into
@@ -128,6 +130,11 @@ struct _MetaStackTracker
    * on requests we've made subsequent to server_stack
    */
   GArray *predicted_stack;
+
+  /* Idle function used to sync the compositor's view of the window
+   * stack up with our best guess before a frame is drawn.
+   */
+  guint sync_stack_idle;
 };
 
 static void
@@ -209,7 +216,8 @@ find_window (GArray *stack,
   return -1;
 }
 
-static void
+/* Returns TRUE if stack was changed */
+static gboolean
 move_window_above (GArray *stack,
                    Window  window,
                    int     old_pos,
@@ -223,6 +231,8 @@ move_window_above (GArray *stack,
 	g_array_index (stack, Window, i) = g_array_index (stack, Window, i + 1);
 
       g_array_index (stack, Window, above_pos) = window;
+
+      return TRUE;
     }
   else if (old_pos > above_pos + 1)
     {
@@ -230,10 +240,15 @@ move_window_above (GArray *stack,
 	g_array_index (stack, Window, i) = g_array_index (stack, Window, i - 1);
 
       g_array_index (stack, Window, above_pos + 1) = window;
+
+      return TRUE;
     }
+  else
+    return FALSE;
 }
 
-static void
+/* Returns TRUE if stack was changed */
+static gboolean
 meta_stack_op_apply (MetaStackOp *op,
 		     GArray      *stack)
 {
@@ -246,11 +261,11 @@ meta_stack_op_apply (MetaStackOp *op,
 	  {
 	    g_warning ("STACK_OP_ADD: window %#lx already in stack",
 		       op->add.window);
-	    return;
+	    return FALSE;
 	  }
 
 	g_array_append_val (stack, op->add.window);
-	break;
+	return TRUE;
       }
     case STACK_OP_REMOVE:
       {
@@ -259,11 +274,11 @@ meta_stack_op_apply (MetaStackOp *op,
 	  {
 	    g_warning ("STACK_OP_REMOVE: window %#lx not in stack",
 		       op->remove.window);
-	    return;
+	    return FALSE;
 	  }
 
 	g_array_remove_index (stack, old_pos);
-	break;
+	return TRUE;
       }
     case STACK_OP_RAISE_ABOVE:
       {
@@ -273,7 +288,7 @@ meta_stack_op_apply (MetaStackOp *op,
 	  {
 	    g_warning ("STACK_OP_RAISE_ABOVE: window %#lx not in stack",
 		       op->raise_above.window);
-	    return;
+	    return FALSE;
 	  }
 
 	if (op->raise_above.sibling != None)
@@ -283,7 +298,7 @@ meta_stack_op_apply (MetaStackOp *op,
 	      {
 		g_warning ("STACK_OP_RAISE_ABOVE: sibling window %#lx not in stack",
 			   op->raise_above.sibling);
-		return;
+		return FALSE;
 	      }
 	  }
 	else
@@ -291,8 +306,7 @@ meta_stack_op_apply (MetaStackOp *op,
 	    above_pos = -1;
 	  }
 
-	move_window_above (stack, op->raise_above.window, old_pos, above_pos);
-	break;
+	return move_window_above (stack, op->raise_above.window, old_pos, above_pos);
       }
     case STACK_OP_LOWER_BELOW:
       {
@@ -302,7 +316,7 @@ meta_stack_op_apply (MetaStackOp *op,
 	  {
 	    g_warning ("STACK_OP_LOWER_BELOW: window %#lx not in stack",
 		       op->lower_below.window);
-	    return;
+	    return FALSE;
 	  }
 
 	if (op->lower_below.sibling != None)
@@ -312,7 +326,7 @@ meta_stack_op_apply (MetaStackOp *op,
 	      {
 		g_warning ("STACK_OP_LOWER_BELOW: sibling window %#lx not in stack",
 			   op->lower_below.sibling);
-		return;
+		return FALSE;
 	      }
 
 	    above_pos = below_pos - 1;
@@ -322,10 +336,12 @@ meta_stack_op_apply (MetaStackOp *op,
 	    above_pos = stack->len - 1;
 	  }
 
-	move_window_above (stack, op->lower_below.window, old_pos, above_pos);
-	break;
+	return move_window_above (stack, op->lower_below.window, old_pos, above_pos);
       }
     }
+
+  g_assert_not_reached ();
+  return FALSE;
 }
 
 static GArray *
@@ -367,6 +383,9 @@ meta_stack_tracker_new (MetaScreen *screen)
 void
 meta_stack_tracker_free (MetaStackTracker *tracker)
 {
+  if (tracker->sync_stack_idle)
+    g_source_remove (tracker->sync_stack_idle);
+
   g_array_free (tracker->server_stack, TRUE);
   if (tracker->predicted_stack)
     g_array_free (tracker->predicted_stack, TRUE);
@@ -382,8 +401,10 @@ stack_tracker_queue_request (MetaStackTracker *tracker,
 {
   meta_stack_op_dump (op, "Queueing: ", "\n");
   g_queue_push_tail (tracker->queued_requests, op);
-  if (tracker->predicted_stack)
-    meta_stack_op_apply (op, tracker->predicted_stack);
+  if (!tracker->predicted_stack ||
+      meta_stack_op_apply (op, tracker->predicted_stack))
+    meta_stack_tracker_queue_sync_stack (tracker);
+
   meta_stack_tracker_dump (tracker);
 }
 
@@ -509,6 +530,8 @@ stack_tracker_event_received (MetaStackTracker *tracker,
     }
 
   meta_stack_tracker_dump (tracker);
+
+  meta_stack_tracker_queue_sync_stack (tracker);
 }
 
 void
@@ -628,3 +651,78 @@ meta_stack_tracker_get_stack (MetaStackTracker *tracker,
   if (n_windows)
     *n_windows = stack->len;
 }
+
+/**
+ * meta_stack_tracker_sync_stack:
+ * @tracker: a #MetaStackTracker
+ *
+ * Informs the compositor of the current stacking order of windows,
+ * based on the predicted view maintained by the #MetaStackTracker.
+ */
+void
+meta_stack_tracker_sync_stack (MetaStackTracker *tracker)
+{
+  GList *meta_windows;
+  Window *windows;
+  int n_windows;
+  int i;
+
+  if (tracker->sync_stack_idle)
+    {
+      g_source_remove (tracker->sync_stack_idle);
+      tracker->sync_stack_idle = 0;
+    }
+
+  meta_stack_tracker_get_stack (tracker, &windows, &n_windows);
+
+  meta_windows = NULL;
+  for (i = 0; i < n_windows; i++)
+    {
+      MetaWindow *meta_window;
+
+      meta_window = meta_display_lookup_x_window (tracker->screen->display,
+                                                  windows[i]);
+      if (meta_window)
+        meta_windows = g_list_prepend (meta_windows, meta_window);
+    }
+
+  meta_compositor_sync_stack (tracker->screen->display->compositor,
+			      tracker->screen,
+			      meta_windows);
+  g_list_free (meta_windows);
+
+  meta_screen_restacked (tracker->screen);
+}
+
+static gboolean
+stack_tracker_sync_stack_idle (gpointer data)
+{
+  meta_stack_tracker_sync_stack (data);
+
+  return FALSE;
+}
+
+/**
+ * meta_stack_tracker_queue_sync_stack:
+ * @tracker: a #MetaStackTracker
+ *
+ * Queue informing the compositor of the new stacking order before the
+ * next redraw. (See meta_stack_tracker_sync_stack()). This is called
+ * internally when the stack of X windows changes, but also needs be
+ * called directly when we an undecorated window is first shown or
+ * withdrawn since the compositor's stacking order (which contains only
+ * the windows that have a corresponding MetaWindow) will change without
+ * any change to the stacking order of the X windows, if we are creating
+ * or destroying MetaWindows.
+ */
+void
+meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker)
+{
+  if (tracker->sync_stack_idle == 0)
+    {
+      tracker->sync_stack_idle = g_idle_add_full (META_PRIORITY_BEFORE_REDRAW,
+                                                  stack_tracker_sync_stack_idle,
+                                                  tracker, NULL);
+    }
+}
+
diff --git a/src/core/stack-tracker.h b/src/core/stack-tracker.h
index 6df3299..557c459 100644
--- a/src/core/stack-tracker.h
+++ b/src/core/stack-tracker.h
@@ -79,8 +79,11 @@ void meta_stack_tracker_reparent_event  (MetaStackTracker    *tracker,
 void meta_stack_tracker_configure_event (MetaStackTracker    *tracker,
 					 XConfigureEvent     *event);
 
-void meta_stack_tracker_get_stack (MetaStackTracker *tracker,
-				   Window          **windows,
-				   int              *n_windows);
+void meta_stack_tracker_get_stack  (MetaStackTracker  *tracker,
+                                    Window           **windows,
+                                    int               *n_windows);
+
+void meta_stack_tracker_sync_stack       (MetaStackTracker *tracker);
+void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker);
 
 #endif /* META_STACK_TRACKER_H */
diff --git a/src/core/stack.c b/src/core/stack.c
index f2f36f0..de70fb8 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -35,10 +35,6 @@
 #include "prefs.h"
 #include "workspace.h"
 
-#ifdef HAVE_COMPOSITE_EXTENSIONS
-#include "compositor.h"
-#endif
-
 #include <X11/Xatom.h>
 
 #define WINDOW_HAS_TRANSIENT_TYPE(w)                    \
@@ -1091,10 +1087,6 @@ stack_sync_to_server (MetaStack *stack)
 
   stack_ensure_sorted (stack);
 
-  meta_compositor_sync_stack (stack->screen->display->compositor,
-			      stack->screen,
-			      stack->sorted);
-  
   /* Create stacked xwindow arrays.
    * Painfully, "stacked" is in bottom-to-top order for the
    * _NET hints, and "root_children_stacked" is in top-to-bottom
@@ -1312,8 +1304,6 @@ stack_sync_to_server (MetaStack *stack)
   if (stack->last_root_children_stacked)
     g_array_free (stack->last_root_children_stacked, TRUE);
   stack->last_root_children_stacked = root_children_stacked;
-  
-  meta_screen_restacked (stack->screen);
 
   /* That was scary... */
 }
diff --git a/src/core/window.c b/src/core/window.c
index c76a4dd..77d000a 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1001,6 +1001,13 @@ meta_window_new_with_attrs (MetaDisplay       *display,
   /* Sync stack changes */
   meta_stack_thaw (window->screen->stack);
 
+  /* Usually the we'll have queued a stack sync anyways, because we've
+   * added a new frame window or restacked. But if an undecorated
+   * window is mapped, already stacked in the right place, then we
+   * might need to do this explicitly.
+   */
+  meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
+
   /* disable show desktop mode unless we're a desktop component */
   maybe_leave_show_desktop_mode (window);
 
@@ -1309,6 +1316,12 @@ meta_window_unmanage (MetaWindow  *window,
   if (window->frame)
     meta_window_destroy_frame (window);
 
+  /* If an undecorated window is being withdrawn, that will change the
+   * stack as presented to the compositing manager, without actually
+   * changing the stacking order of X windows.
+   */
+  meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
+
   if (window->withdrawn)
     {
       /* We need to clean off the window's state so it



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