[gnome-shell] Sync clone stacking order with MetaStackTracker



commit 20b29ff48fa992c83228cb25cb01842123558749
Author: Colin Walters <walters verbum org>
Date:   Mon Sep 28 19:48:03 2009 -0400

    Sync clone stacking order with MetaStackTracker
    
    Previously, we initialized actor stacking order from the return
    value of global.get_windows() once, which is defined to be in
    stack order.  However it was not updated later.  Furthermore,
    the way stackAbove was called from onAnimationComplete in
    WindowClone was highly dubious, since there are lots of animations
    which apply to the clones, and we want the stacking to be right
    all of the time, not when some animation completes.
    
    Fix this by connecting to 'restacked' on the screen and syncing
    the clones.
    
    I also snuck in another bugfix here; we weren't disconnecting
    from the 'showing' signal handler, which had various bad
    consequences.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=596263

 js/ui/workspaces.js |  123 +++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 99 insertions(+), 24 deletions(-)
---
diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js
index def2fd1..3f461d8 100644
--- a/js/ui/workspaces.js
+++ b/js/ui/workspaces.js
@@ -111,6 +111,8 @@ WindowClone.prototype = {
         this.origX = realWindow.x;
         this.origY = realWindow.y;
 
+        this._stackAbove = null;
+
         this._title = null;
 
         this.actor.connect('button-release-event',
@@ -129,6 +131,8 @@ WindowClone.prototype = {
         this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
         this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
         this._inDrag = false;
+
+        this._zooming = false;
     },
 
     setVisibleWithChrome: function(visible) {
@@ -143,6 +147,14 @@ WindowClone.prototype = {
         }
     },
 
+    setStackAbove: function (actor) {
+        this._stackAbove = actor;
+        if (this._inDrag || this._zooming)
+            // We'll fix up the stack after the drag/zooming
+            return;
+        this.actor.raise(this._stackAbove);
+    },
+
     destroy: function () {
         this.actor.destroy();
         if (this._title)
@@ -157,7 +169,6 @@ WindowClone.prototype = {
 
         this._havePointer = true;
 
-        actor.raise_top();
         this._updateTitle();
     },
 
@@ -206,6 +217,8 @@ WindowClone.prototype = {
     },
 
     _zoomStart : function () {
+        this._zooming = true;
+
         this._zoomLightbox = new Lightbox.Lightbox(global.stage);
 
         this._zoomLocalOrig  = new ScaledPoint(this.actor.x, this.actor.y, this.actor.scale_x, this.actor.scale_y);
@@ -232,7 +245,10 @@ WindowClone.prototype = {
     },
 
     _zoomEnd : function () {
+        this._zooming = false;
+
         this.actor.reparent(this._origParent);
+        this.actor.raise(this._stackAbove);
 
         [this.actor.x, this.actor.y]             = this._zoomLocalOrig.getPosition();
         [this.actor.scale_x, this.actor.scale_y] = this._zoomLocalOrig.getScale();
@@ -272,6 +288,12 @@ WindowClone.prototype = {
         // mysteriously present
         this._havePointer = false;
 
+        // We may not have a parent if DnD completed successfully, in
+        // which case our clone will shortly be destroyed and replaced
+        // with a new one on the target workspace.
+        if (this.actor.get_parent() != null)
+            this.actor.raise(this._stackAbove);
+
         this.emit('drag-end');
     },
 
@@ -283,7 +305,6 @@ WindowClone.prototype = {
     // Called by Tweener
     onAnimationComplete : function () {
         this._updateTitle();
-        this.actor.raise(this.stackAbove);
     },
 
     _createTitle : function () {
@@ -618,12 +639,43 @@ Workspace.prototype = {
                              this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
     },
 
+    _isCloneVisible: function(clone) {
+        return this._showOnlyWindows == null || (clone.metaWindow in this._showOnlyWindows);
+    },
+
+    /**
+     * _getVisibleClones:
+     *
+     * Returns a list WindowClone objects where the clone isn't filtered
+     * out by any application filter.  The clone for the desktop is excluded.
+     * The returned array will always be newly allocated; it is not in any
+     * defined order, and thus it's convenient to call .sort() with your
+     * choice of sorting function.
+     */
+    _getVisibleClones: function() {
+        let visible = [];
+
+        for (let i = 1; i < this._windows.length; i++) {
+            let clone = this._windows[i];
+
+            if (!this._isCloneVisible(clone))
+                continue;
+
+            visible.push(clone);
+        }
+        return visible;
+    },
+
+    _getVisibleWindows: function() {
+        return this._getVisibleClones().map(function (clone) { return clone.metaWindow; });
+    },
+
     _resetCloneVisibility: function () {
         for (let i = 1; i < this._windows.length; i++) {
             let clone = this._windows[i];
             let icon = this._windowIcons[i];
 
-            if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows)) {
+            if (!this._isCloneVisible(clone)) {
                 clone.setVisibleWithChrome(false);
                 icon.hide();
             } else {
@@ -853,21 +905,12 @@ Workspace.prototype = {
     positionWindows : function(workspaceZooming) {
         let totalVisible = 0;
 
-        let visibleWindows = [];
-
-        for (let i = 1; i < this._windows.length; i++) {
-            let clone = this._windows[i];
-
-            if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
-                continue;
-
-            visibleWindows.push(clone.metaWindow);
-        }
+        let visibleWindows = this._getVisibleWindows();
 
+        // Start the animations
         let slots = this._computeAllWindowSlots(visibleWindows.length);
         visibleWindows = this._orderWindowsByMotionAndStartup(visibleWindows, slots);
 
-        let previousWindow = this._windows[0];
         for (let i = 0; i < visibleWindows.length; i++) {
             let slot = slots[i];
             let metaWindow = visibleWindows[i];
@@ -875,9 +918,6 @@ Workspace.prototype = {
             let clone = metaWindow._delegate;
             let icon = this._windowIcons[mainIndex];
 
-            clone.stackAbove = previousWindow.actor;
-            previousWindow = clone;
-
             let [x, y, scale] = this._computeWindowRelativeLayout(metaWindow, slot);
 
             icon.hide();
@@ -896,6 +936,24 @@ Workspace.prototype = {
         }
     },
 
+    syncStacking: function(stackIndices) {
+        let desktopClone = this._windows[0];
+
+        let visibleClones = this._getVisibleClones();
+        visibleClones.sort(function (a, b) { return stackIndices[a.metaWindow.get_stable_sequence()] - stackIndices[b.metaWindow.get_stable_sequence()]; });
+
+        for (let i = 0; i < visibleClones.length; i++) {
+            let clone = visibleClones[i];
+            let metaWindow = clone.metaWindow;
+            if (i == 0) {
+                clone.setStackAbove(desktopClone.actor);
+            } else {
+                let previousClone = visibleClones[i - 1];
+                clone.setStackAbove(previousClone.actor);
+            }
+        }
+    },
+
     _fadeInWindowIcon: function (clone, icon) {
         icon.opacity = 0;
         icon.show();
@@ -1320,10 +1378,12 @@ Workspaces.prototype = {
         // workspaces have been created. This cannot be done first because
         // window movement depends on the Workspaces object being accessible
         // as an Overview member.
-        Main.overview.connect('showing',
-                             Lang.bind(this, function() {
-            for (let w = 0; w < this._workspaces.length; w++)
-                this._workspaces[w].zoomToOverview();
+        this._overviewShowingId =
+            Main.overview.connect('showing',
+                                 Lang.bind(this, function() {
+                this._onRestacked();
+                for (let w = 0; w < this._workspaces.length; w++)
+                    this._workspaces[w].zoomToOverview();
         }));
 
         // Track changes to the number of workspaces
@@ -1333,6 +1393,9 @@ Workspaces.prototype = {
         this._switchWorkspaceNotifyId =
             global.window_manager.connect('switch-workspace',
                                           Lang.bind(this, this._activeWorkspaceChanged));
+        this._restackedNotifyId =
+            global.screen.connect('restacked',
+                                  Lang.bind(this, this._onRestacked));
     },
 
     _lookupWorkspaceForMetaWindow: function (metaWindow) {
@@ -1422,9 +1485,6 @@ Workspaces.prototype = {
             this._clearApplicationWindowSelection(false);
         }
 
-        let clone = this._lookupCloneForMetaWindow (metaWindow);
-        clone.actor.raise_top();
-
         Main.activateWindow(metaWindow, time);
         Main.overview.hide();
     },
@@ -1448,8 +1508,10 @@ Workspaces.prototype = {
         this.actor.destroy();
         this.actor = null;
 
+        Main.overview.disconnect(this._overviewShowingId);
         global.screen.disconnect(this._nWorkspacesNotifyId);
         global.window_manager.disconnect(this._switchWorkspaceNotifyId);
+        global.screen.disconnect(this._restackedNotifyId);
     },
 
     getScale : function() {
@@ -1595,6 +1657,19 @@ Workspaces.prototype = {
         this.actor.add_actor(workspace.actor);
     },
 
+    _onRestacked: function() {
+        let stack = global.get_windows();
+        let stackIndices = {};
+
+        for (let i = 0; i < stack.length; i++) {
+            // Use the stable sequence for an integer to use as a hash key
+            stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
+        }
+
+        for (let i = 0; i < this._workspaces.length; i++)
+            this._workspaces[i].syncStacking(stackIndices);
+    },
+
     // Handles a drop onto the (+) button; assumes the new workspace
     // has already been added
     acceptNewWorkspaceDrop : function(source, dropActor, x, y, time) {



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