[gnome-shell] Improve tracking of fullscreen windows



commit 6119b447469c71c36b15c0d0fa8c1cfa24289778
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Mar 12 15:27:51 2013 -0400

    Improve tracking of fullscreen windows
    
    It's possible in some corner cases for the status of the topwindow
    to change and make it not fullscreen without ::restacked being
    changed. One way that it could happen with the old code was if the
    layer of the top window changed from NORMAL to FULLSCREEN.
    
    Change the logic not to look at the layer, which is a function of
    Mutter's *intended* stacking, rather than the *actual* stacking,
    which is what ::restacked gives you. Instead, look at the top
    portion of the stack, down to the first non-override-redirect
    window, and see if their are any monitor-sized windows there.
    
    Connect to changes on the top portion of the stack, so we know
    if conditions change.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=649748

 js/ui/layout.js |  120 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 104 insertions(+), 16 deletions(-)
---
diff --git a/js/ui/layout.js b/js/ui/layout.js
index 4ca2680..1fff9cc 100644
--- a/js/ui/layout.js
+++ b/js/ui/layout.js
@@ -142,6 +142,7 @@ const LayoutManager = new Lang.Class({
         this._updateRegionIdle = 0;
 
         this._trackedActors = [];
+        this._topActors = [];
         this._isPopupWindowVisible = false;
         this._startingUp = true;
 
@@ -888,36 +889,78 @@ const LayoutManager = new Lang.Class({
         });
     },
 
+   _disconnectTopActor: function(window) {
+       /* O-R status is immutable in Mutter */
+       if (window.metaWindow.is_override_redirect()) {
+           window.disconnect(window._topActorPositionChangedId);
+           delete window._topActorPositionChangedId;
+           window.disconnect(window._topActorSizeChangedId);
+           delete window._topActorSizeChangedId;
+       }
+   },
+
+   _disconnectTopWindow: function(metaWindow) {
+       metaWindow.disconnect(metaWindow._topActorUnmanagedId);
+       delete window._topActorUnmanagedId;
+       metaWindow.disconnect(metaWindow._topActorNotifyFullscreenId);
+       delete window._topActorNotifyFullscreenId;
+   },
+
+    _topActorUnmanaged: function(metaWindow, window) {
+        /* Actor is already destroyed, so don't disconnect it */
+        this._disconnectTopWindow(metaWindow);
+
+        let i = this._topActors.indexOf(window);
+        this._topActors.splice(i, 1);
+    },
+
+    _topActorChanged: function() {
+        this._windowsRestacked();
+    },
+
     _updateFullscreen: function() {
+        // Ordinary chrome should be visible unless the top window in
+        // the stack is monitor sized. We allow override-redirect
+        // windows to be above this "top window" because there can be
+        // O-R windows that are offscreen, or otherwise have no
+        // semantic meaning to the user.
+        //
+        // If we wanted to be extra clever, we could figure out when
+        // an OVERRIDE_REDIRECT window was trying to partially overlap
+        // us, and then adjust the input region and our clip region
+        // accordingly...
+
+        // @windows is sorted bottom to top.
         let windows = this._getWindowActorsForWorkspace(global.screen.get_active_workspace());
 
         // Reset all monitors to not fullscreen
         for (let i = 0; i < this.monitors.length; i++)
             this.monitors[i].inFullscreen = false;
 
-        // Ordinary chrome should be visible unless there is a window
-        // with layer FULLSCREEN, or a window with layer
-        // OVERRIDE_REDIRECT that covers the whole screen.
-        // ('override_redirect' is not actually a layer above all
-        // other windows, but this seems to be how mutter treats it
-        // currently...) If we wanted to be extra clever, we could
-        // figure out when an OVERRIDE_REDIRECT window was trying to
-        // partially overlap us, and then adjust the input region and
-        // our clip region accordingly...
-
-        // @windows is sorted bottom to top.
+        let oldTopActors = this._topActors;
+        let newTopActors = [];
 
         for (let i = windows.length - 1; i > -1; i--) {
             let window = windows[i];
             let metaWindow = window.meta_window;
-            let layer = metaWindow.get_layer();
 
-            // Skip minimized windows
-            if (!metaWindow.showing_on_its_workspace())
+            // Because we are working with the list of actors, not the list of
+            // windows, we have an uncomfortable corner case to deal with.
+            // If a window is being hidden, it's actor will be left on top
+            // of the actor stack until any animation is done. (See
+            // meta_compositor_sync_stack()). These windows are actually at
+            // the bottom of the window stack, so if they return and become
+            // relevant again, we'll get another ::restacked signal, so we
+            // can just ignore them. This check *DOES NOT* handle destroyed
+            // windows correctly, but we don't currently animate such windows.
+            // If bugs show up here, instead of making this more complex,
+            // add a function to get the window stack from MetaStackTracker.
+            if (!metaWindow.showing_on_its_workspace ())
                 continue;
 
-            if (layer == Meta.StackLayer.FULLSCREEN ||
-               (layer == Meta.StackLayer.OVERRIDE_REDIRECT && metaWindow.is_monitor_sized())) {
+            newTopActors.push(window);
+
+            if (metaWindow.is_monitor_sized()) {
                 if (metaWindow.is_screen_sized()) {
                     for (let i = 0; i < this.monitors.length; i++)
                         this.monitors[i].inFullscreen = true;
@@ -928,8 +971,53 @@ const LayoutManager = new Lang.Class({
                         this.monitors[index].inFullscreen = true;
                     }
                 }
+                break;
+            }
+
+            if (!window.is_override_redirect())
+                break;
+        }
+
+        // Deal with windows being added or removed from the "top actors" set.
+        // These are the actors that a change to could cause a change in
+        // our computed fullscreen status without a change in the stack.
+        for (let i = 0; i < oldTopActors.length; i++) {
+            let window = oldTopActors[i];
+            if (newTopActors.indexOf(window) < 0) {
+                this._disconnectTopActor(window);
+                this._disconnectTopWindow(window.metaWindow);
             }
         }
+
+        for (let i = 0; i < newTopActors.length; i++) {
+            let window = newTopActors[i];
+
+            if (oldTopActors.indexOf(window) < 0) {
+                window.metaWindow._topActorUnmanagedId =
+                    window.metaWindow.connect('unmanaged',
+                                              Lang.bind(this, this._topActorUnmanaged, window));
+                window.metaWindow._topActorNotifyFullscreenId =
+                    window.metaWindow.connect('notify::fullscreen',
+                                              Lang.bind(this, this._topActorChanged));
+
+                /* In almost all cases, meta_window_is_monitor_size() depends
+                 * on position only for O-R windows. The remaining case is a non-OR,
+                 * non-fullscreen window which is screen sized. That is highly
+                 * unlikely and probably should be excluded in
+                 * meta_window_is_monitor_size().
+                 */
+                if (window.metaWindow.is_override_redirect()) {
+                    window._topActorPositionChangedId =
+                        window.connect('position-changed',
+                                       Lang.bind(this, this._topActorChanged));
+                    window._topActorSizeChangedId =
+                        window.connect('size-changed',
+                                       Lang.bind(this, this._topActorChanged));
+                }
+            }
+        }
+
+        this._topActors = newTopActors;
     },
 
     _windowsRestacked: function() {


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