[gnome-shell/T27795: 60/138] workspaceMonitor: Add a monitor to track when there are visible windows on the desktop.



commit 3f6ba6ce6c8a23e9967e3f0d28ecbfa227ede06c
Author: Mario Sanchez Prada <mario endlessm com>
Date:   Sat May 27 04:38:26 2017 +0100

    workspaceMonitor: Add a monitor to track when there are visible windows on the desktop.
    
    This will be useful to implement the "Endless button" in the bottom panel (to
    decide when we need to show the apps view or blink the search entry box) and
    for any other actions that depend on not having any window opened in the desktop.
    
    Starting in EOS 3.4 / GNOME Shell 3.26, this also fixes a corner case that has not
    been contemplated before, because it normally happens when manipulating the status
    icon in the tray area, which was fairly hidden in a sliding panel until now: when
    you have an app hidden (not minimized) because of interacting with it via the tray
    area icon (e.g. Telegram) and clicking on its icon again should make it visible again,
    the previous code prevented that from happening unless some other windows wass already
    visible, because nothing would hide the overview in this scenario, keeping the app hidden.
    
    https://phabricator.endlessm.com/T17937

 js/js-resources.gresource.xml |  1 +
 js/ui/main.js                 |  5 +++
 js/ui/workspaceMonitor.js     | 96 +++++++++++++++++++++++++++++++++++++++++++
 src/shell-wm.c                | 20 +++++++++
 4 files changed, 122 insertions(+)
---
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 80fe22fcd8..8213970de6 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -154,5 +154,6 @@
     <file>ui/status/orientation.js</file>
     <file>ui/userMenu.js</file>
     <file>ui/watermark.js</file>
+    <file>ui/workspaceMonitor.js</file>
   </gresource>
 </gresources>
diff --git a/js/ui/main.js b/js/ui/main.js
index 6a109bf6a3..8c67e17000 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -48,6 +48,7 @@ const KbdA11yDialog = imports.ui.kbdA11yDialog;
 const LocatePointer = imports.ui.locatePointer;
 const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
 const Watermark = imports.ui.watermark;
+const WorkspaceMonitor = imports.ui.workspaceMonitor;
 
 const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
 const STICKY_KEYS_ENABLE = 'stickykeys-enable';
@@ -90,6 +91,7 @@ var inputMethod = null;
 var introspectService = null;
 var locatePointer = null;
 var trayArea = null;
+var workspaceMonitor = null;
 let _startDate;
 let _defaultCssStylesheet = null;
 let _cssStylesheet = null;
@@ -210,6 +212,9 @@ function _initializeUI() {
 
     (new PointerA11yTimeout.PointerA11yTimeout());
 
+    // WorkspaceMonitor expects layoutManager to be ready, initialize it here.
+    workspaceMonitor = new WorkspaceMonitor.WorkspaceMonitor();
+
     _a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA });
 
     global.display.connect('overlay-key', () => {
diff --git a/js/ui/workspaceMonitor.js b/js/ui/workspaceMonitor.js
new file mode 100644
index 0000000000..8fa667fe40
--- /dev/null
+++ b/js/ui/workspaceMonitor.js
@@ -0,0 +1,96 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const { Shell } = imports.gi;
+
+const Main = imports.ui.main;
+const ViewSelector = imports.ui.viewSelector;
+
+var WorkspaceMonitor = class {
+    constructor() {
+        this._shellwm = global.window_manager;
+        this._shellwm.connect('minimize-completed', this._windowDisappeared.bind(this));
+        this._shellwm.connect('destroy-completed', this._windowDisappeared.bind(this));
+
+        this._windowTracker = Shell.WindowTracker.get_default();
+        this._windowTracker.connect('tracked-windows-changed', this._trackedWindowsChanged.bind(this));
+
+        global.display.connect('in-fullscreen-changed', this._fullscreenChanged.bind(this));
+
+        let primaryMonitor = Main.layoutManager.primaryMonitor;
+        this._inFullscreen = primaryMonitor && primaryMonitor.inFullscreen;
+
+        this._appSystem = Shell.AppSystem.get_default();
+    }
+
+    _fullscreenChanged() {
+        let primaryMonitor = Main.layoutManager.primaryMonitor;
+        let inFullscreen = primaryMonitor && primaryMonitor.inFullscreen;
+
+        if (this._inFullscreen != inFullscreen) {
+            this._inFullscreen = inFullscreen;
+            this._updateOverview();
+        }
+    }
+
+    _updateOverview() {
+        let visibleApps = this._getVisibleApps();
+        if (visibleApps.length != 0 && this._inFullscreen)
+            Main.overview.hide();
+    }
+
+    _windowDisappeared(shellwm, actor) {
+        this._updateOverview();
+    }
+
+    _trackedWindowsChanged() {
+        let visibleApps = this._getVisibleApps();
+        let isShowingAppsGrid = Main.overview.visible &&
+            Main.overview.getActivePage() === ViewSelector.ViewPage.APPS;
+
+        if (visibleApps.length > 0 && isShowingAppsGrid) {
+            // Make sure to hide the apps grid so that running apps whose
+            // windows are becoming visible are shown to the user.
+            Main.overview.hide();
+        } else {
+            // Fallback to the default logic used for dissapearing windows.
+            this._updateOverview();
+        }
+    }
+
+    _getVisibleApps() {
+        let runningApps = this._appSystem.get_running();
+        return runningApps.filter(function(app) {
+            let windows = app.get_windows();
+            for (let window of windows) {
+                // We do not count transient windows because of an issue with Audacity
+                // where a transient window was always being counted as visible even
+                // though it was minimized
+                if (window.get_transient_for())
+                    continue;
+
+                if (!window.minimized)
+                    return true;
+            }
+
+            return false;
+        });
+    }
+
+    get hasActiveWindows() {
+        // Count anything fullscreen as an extra window
+        if (this._inFullscreen)
+            return true;
+
+        let apps = this._appSystem.get_running();
+        return apps.length > 0;
+    }
+
+    get hasVisibleWindows() {
+        // Count anything fullscreen as an extra window
+        if (this._inFullscreen)
+            return true;
+
+        let visibleApps = this._getVisibleApps();
+        return visibleApps.length > 0;
+    }
+};
diff --git a/src/shell-wm.c b/src/shell-wm.c
index 1e579ad8c2..aa648591a6 100644
--- a/src/shell-wm.c
+++ b/src/shell-wm.c
@@ -20,11 +20,13 @@ struct _ShellWM {
 enum
 {
   MINIMIZE,
+  MINIMIZE_COMPLETED,
   UNMINIMIZE,
   SIZE_CHANGED,
   SIZE_CHANGE,
   MAP,
   DESTROY,
+  DESTROY_COMPLETED,
   SWITCH_WORKSPACE,
   KILL_SWITCH_WORKSPACE,
   KILL_WINDOW_EFFECTS,
@@ -70,6 +72,14 @@ shell_wm_class_init (ShellWMClass *klass)
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 1,
                   META_TYPE_WINDOW_ACTOR);
+  shell_wm_signals[MINIMIZE_COMPLETED] =
+    g_signal_new ("minimize-completed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1,
+                  META_TYPE_WINDOW_ACTOR);
   shell_wm_signals[UNMINIMIZE] =
     g_signal_new ("unminimize",
                   G_TYPE_FROM_CLASS (klass),
@@ -110,6 +120,14 @@ shell_wm_class_init (ShellWMClass *klass)
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 1,
                   META_TYPE_WINDOW_ACTOR);
+  shell_wm_signals[DESTROY_COMPLETED] =
+    g_signal_new ("destroy-completed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1,
+                  META_TYPE_WINDOW_ACTOR);
   shell_wm_signals[SWITCH_WORKSPACE] =
     g_signal_new ("switch-workspace",
                  G_TYPE_FROM_CLASS (klass),
@@ -247,6 +265,7 @@ shell_wm_completed_minimize (ShellWM         *wm,
                              MetaWindowActor *actor)
 {
   meta_plugin_minimize_completed (wm->plugin, actor);
+  g_signal_emit (wm, shell_wm_signals[MINIMIZE_COMPLETED], 0, actor);
 }
 
 /**
@@ -296,6 +315,7 @@ shell_wm_completed_destroy (ShellWM         *wm,
                             MetaWindowActor *actor)
 {
   meta_plugin_destroy_completed (wm->plugin, actor);
+  g_signal_emit (wm, shell_wm_signals[DESTROY_COMPLETED], 0, actor);
 }
 
 /**


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