[gnome-shell] Track fullscreen status per-monitor in Chrome



commit 885f668d53a30bd3dc56daadedeec995dfecd1b0
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Feb 23 17:08:09 2011 +0100

    Track fullscreen status per-monitor in Chrome
    
    This is required since we can have chrome on multiple monitors (due to
    per-monitor hot-corners).
    
    Windows are primary associated with the monitor that their center is on.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=642881

 js/ui/chrome.js |  127 +++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 99 insertions(+), 28 deletions(-)
---
diff --git a/js/ui/chrome.js b/js/ui/chrome.js
index 9d2e84f..f5e8292 100644
--- a/js/ui/chrome.js
+++ b/js/ui/chrome.js
@@ -31,11 +31,13 @@ Chrome.prototype = {
         Main.uiGroup.add_actor(this.actor);
         this.actor.connect('allocate', Lang.bind(this, this._allocated));
 
-        this._inFullscreen = false;
+        this._monitors = [];
         this._inOverview = false;
 
         this._trackedActors = [];
 
+        global.gdk_screen.connect('monitors-changed',
+                                  Lang.bind(this, this._monitorsChanged));
         global.screen.connect('restacked',
                               Lang.bind(this, this._windowsRestacked));
 
@@ -48,6 +50,8 @@ Chrome.prototype = {
         Main.overview.connect('hidden',
                              Lang.bind(this, this._overviewHidden));
 
+        this._updateMonitors();
+        this._updateFullscreen();
         this._queueUpdateRegions();
     },
 
@@ -187,7 +191,8 @@ Chrome.prototype = {
             let actorData = this._trackedActors[i];
             if (this._inOverview && !actorData.visibleInOverview)
                 this.actor.set_skip_paint(actorData.actor, true);
-            else if (!this._inOverview && this._inFullscreen && !actorData.visibleInFullscreen)
+            else if (!this._inOverview && !actorData.visibleInFullscreen &&
+                     this._findMonitorForActor(actorData.actor).inFullscreen)
                 this.actor.set_skip_paint(actorData.actor, true);
             else
                 this.actor.set_skip_paint(actorData.actor, false);
@@ -206,15 +211,77 @@ Chrome.prototype = {
         this._queueUpdateRegions();
     },
 
+    _updateMonitors: function() {
+        let monitors = global.get_monitors();
+        let primary = global.get_primary_monitor();
+        this._monitors = monitors;
+        for (let i = 0; i < monitors.length; i++) {
+            let monitor = monitors[i];
+            if (monitor.x == primary.x &&
+                monitor.y == primary.y &&
+                monitor.width == primary.width &&
+                monitor.height == primary.height)
+                this._primaryMonitor = monitor;
+        }
+    },
+
+    _findMonitorForRect: function(x, y, w, h) {
+        // First look at what monitor the center of the rectangle is at
+        let cx = x + w/2;
+        let cy = y + h/2;
+        for (let i = 0; i < this._monitors.length; i++) {
+            let monitor = this._monitors[i];
+            if (cx >= monitor.x && cx < monitor.x + monitor.width &&
+                cy >= monitor.y && cy < monitor.y + monitor.height)
+                return monitor;
+        }
+        // If the center is not on a monitor, return the first overlapping monitor
+        for (let i = 0; i < this._monitors.length; i++) {
+            let monitor = this._monitors[i];
+            if (x + w > monitor.x && x < monitor.x + monitor.width &&
+                y + h > monitor.y && y < monitor.y + monitor.height)
+                return monitor;
+        }
+        // otherwise on no monitor
+        return null;
+    },
+
+    _findMonitorForWindow: function(window) {
+        return this._findMonitorForRect(window.x, window.y, window.width, window.height);
+    },
+
+    // This call guarantees that we return some monitor to simplify usage of it
+    // In practice all tracked actors should be visible on some monitor anyway
+    _findMonitorForActor: function(actor) {
+        let [x, y] = actor.get_transformed_position();
+        let [w, h] = actor.get_transformed_size();
+        let monitor = this._findMonitorForRect(x, y, w, h);
+        if (monitor)
+            return monitor;
+        return this._primaryMonitor; // Not on any monitor, pretend its on the primary
+    },
+
+    _monitorsChanged: function() {
+        this._updateMonitors();
+
+        // Update everything that depends on monitor positions
+        this._updateFullscreen();
+        this._updateVisibility();
+        this._queueUpdateRegions();
+    },
+
     _queueUpdateRegions: function() {
         if (!this._updateRegionIdle)
             this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
                                                        Meta.PRIORITY_BEFORE_REDRAW);
     },
 
-    _windowsRestacked: function() {
+    _updateFullscreen: function() {
         let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
-        let primary = global.get_primary_monitor();
+
+        // Reset all monitors to not fullscreen
+        for (let i = 0; i < this._monitors.length; i++)
+            this._monitors[i].inFullscreen = false;
 
         // The chrome layer should be visible unless there is a window
         // with layer FULLSCREEN, or a window with layer
@@ -228,39 +295,43 @@ Chrome.prototype = {
 
         // @windows is sorted bottom to top.
 
-        let wasInFullscreen = this._inFullscreen;
-        this._inFullscreen = false;
         for (let i = windows.length - 1; i > -1; i--) {
-            let layer = windows[i].get_meta_window().get_layer();
-
-            // There are 3 cases we check here for:
-            // 1.) Monitor sized window
-            // 2.) Window with a position somewhere on the primary screen having the _NET_WM_FULLSCREEN flag set
-            // 3.) Window that is partly off screen (tries to hide its decorations) which might have negative coords
-            // We check for 1.) and 2.) by checking if the upper right corner is on the primary monitor, but avoid the case
-            // where it overlaps with the secondary screen (like window.x + window.width == primary.x + primary.width)
-            // For 3.) we just ignore negative values as they don't really make sense
+            let window = windows[i];
+            let layer = window.get_meta_window().get_layer();
 
             if (layer == Meta.StackLayer.FULLSCREEN) {
-                if (Math.max(windows[i].x, 0) >= primary.x && Math.max(windows[i].x, 0) < primary.x + primary.width &&
-                    Math.max(windows[i].y, 0) >= primary.y && Math.max(windows[i].y, 0) < primary.y + primary.height) {
-                        this._inFullscreen = true;
-                        break;
-                }
+                let monitor = this._findMonitorForWindow(window);
+                if (monitor)
+                    monitor.inFullscreen = true;
             }
             if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
-                if (windows[i].x <= primary.x &&
-                    windows[i].x + windows[i].width >= primary.x + primary.width &&
-                    windows[i].y <= primary.y &&
-                    windows[i].y + windows[i].height >= primary.y + primary.height) {
-                    this._inFullscreen = true;
-                    break;
-                }
+                let monitor = this._findMonitorForWindow(window);
+                if (monitor &&
+                    window.x <= monitor.x &&
+                    window.x + window.width >= monitor.x + monitor.width &&
+                    window.y <= monitor.y &&
+                    window.y + window.height >= monitor.y + monitor.height)
+                    monitor.inFullscreen = true;
             } else
                 break;
         }
+    },
+
+    _windowsRestacked: function() {
+        let wasInFullscreen = [];
+        for (let i = 0; i < this._monitors.length; i++)
+            wasInFullscreen[i] = this._monitors[i].inFullscreen;
+
+        this._updateFullscreen();
 
-        if (this._inFullscreen != wasInFullscreen) {
+        let changed = false;
+        for (let i = 0; i < wasInFullscreen.length; i++) {
+            if (wasInFullscreen[i] != this._monitors[i].inFullscreen) {
+                changed = true;
+                break;
+            }
+        }
+        if (changed) {
             this._updateVisibility();
             this._queueUpdateRegions();
         }



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