[mutter] Avoid restacking animating hidden actors



commit 455486db7c1fd379e423a404f329b584318f9ede
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Fri Jun 26 17:05:11 2009 -0400

    Avoid restacking animating hidden actors
    
    Since the stack passed to the compositor now accurately reflects
    the X stacking order, we need to treat hidden windows (which are
    at the bottom of the X stacking order) specially - when the
    compositor stacking order is synced, try to keep animating hidden
    actors in their old positions in the stack.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=585984

 src/compositor/mutter/compositor-mutter.c |   85 ++++++++++++++++++++++++-----
 1 files changed, 72 insertions(+), 13 deletions(-)
---
diff --git a/src/compositor/mutter/compositor-mutter.c b/src/compositor/mutter/compositor-mutter.c
index 299575b..92f797a 100644
--- a/src/compositor/mutter/compositor-mutter.c
+++ b/src/compositor/mutter/compositor-mutter.c
@@ -2429,26 +2429,85 @@ clutter_cmp_sync_stack (MetaCompositor *compositor,
 			MetaScreen     *screen,
 			GList	       *stack)
 {
-  GList *tmp;
+  GList *old_stack;
   MetaCompScreen *info = meta_screen_get_compositor_data (screen);
 
   DEBUG_TRACE ("clutter_cmp_sync_stack\n");
-  /* NB: The first entry in stack, is stacked the highest */
 
-  for (tmp = stack; tmp != NULL; tmp = tmp->next)
+  /* This is painful because hidden windows that we are in the process
+   * of animating out of existence. They'll be at the bottom of the
+   * stack of X windows, but we want to leave them in their old position
+   * until the animation effect finishes.
+   */
+
+  /* Sources: first window is the highest */
+  stack = g_list_copy (stack); /* The new stack of MetaWindow */
+  old_stack = g_list_reverse (info->windows); /* The old stack of MutterWindow */
+  info->windows = NULL;
+
+  while (TRUE)
     {
-      MetaWindow    *window = tmp->data;
-      MutterWindow  *cw = MUTTER_WINDOW (meta_window_get_compositor_private (window));
+      MutterWindow *old_actor = NULL, *stack_actor = NULL, *actor;
+      MetaWindow *old_window = NULL, *stack_window = NULL, *window;
 
-      if (!cw)
-	{
-	  meta_verbose ("Failed to find corresponding MutterWindow "
-			"for window %p\n", window);
-	  continue;
-	}
+      /* Find the remaining top actor in our existing stack (ignoring
+       * windows that have been hidden and are no longer animating) */
+      while (old_stack)
+        {
+          old_actor = old_stack->data;
+          old_window = mutter_window_get_meta_window (old_actor);
+
+          if (old_window->hidden &&
+              !effect_in_progress (old_actor, TRUE))
+            old_stack = g_list_delete_link (old_stack, old_stack);
+          else
+            break;
+        }
+
+      /* And the remaining top actor in the new stack */
+      while (stack)
+        {
+          stack_window = stack->data;
+          stack_actor = MUTTER_WINDOW (meta_window_get_compositor_private (stack_window));
+          if (!stack_actor)
+            {
+              meta_verbose ("Failed to find corresponding MutterWindow "
+                            "for window %s\n", meta_window_get_description (stack_window));
+              stack = g_list_delete_link (stack, stack);
+            }
+          else
+            break;
+        }
+
+      if (!old_actor && !stack_actor) /* Nothing more to stack */
+        break;
+
+      /* We usually prefer the window in the new stack, but if if we
+       * found a hidden window in the process of being animated out
+       * of existence in the old stack we use that instead. We've
+       * filtered out non-animating hidden windows above.
+       */
+      if (old_actor &&
+          (!stack_actor || old_window->hidden))
+        {
+          actor = old_actor;
+          window = old_window;
+        }
+      else
+        {
+          actor = stack_actor;
+          window = stack_window;
+        }
+
+      /* OK, we know what actor we want next. Add it to our window
+       * list, and remove it from both source lists. (It will
+       * be at the front of at least one, hopefully it will be
+       * near the front of the other.)
+       */
+      info->windows = g_list_prepend (info->windows, actor);
 
-      info->windows = g_list_remove (info->windows, (gconstpointer)cw);
-      info->windows = g_list_prepend (info->windows, cw);
+      stack = g_list_remove (stack, window);
+      old_stack = g_list_remove (old_stack, actor);
     }
 
   sync_actor_stacking (info->windows);



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