[gnome-shell/eos3.8: 24/255] workspaceMonitor: Add a monitor to track visible windows on the desktop



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

    workspaceMonitor: Add a monitor to track 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     | 97 +++++++++++++++++++++++++++++++++++++++++++
 src/shell-wm.c                | 20 +++++++++
 4 files changed, 123 insertions(+)
---
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 03ff04d5aa..f0ed005e7c 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -144,5 +144,6 @@
     <file>ui/appActivation.js</file>
     <file>ui/appIconBar.js</file>
     <file>ui/forceAppExitDialog.js</file>
+    <file>ui/workspaceMonitor.js</file>
   </gresource>
 </gresources>
diff --git a/js/ui/main.js b/js/ui/main.js
index fbfc8a058d..26c6defa0c 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -47,6 +47,7 @@ const XdndHandler = imports.ui.xdndHandler;
 const KbdA11yDialog = imports.ui.kbdA11yDialog;
 const LocatePointer = imports.ui.locatePointer;
 const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
+const WorkspaceMonitor = imports.ui.workspaceMonitor;
 
 const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
 const STICKY_KEYS_ENABLE = 'stickykeys-enable';
@@ -87,6 +88,7 @@ var kbdA11yDialog = null;
 var inputMethod = null;
 var introspectService = null;
 var locatePointer = null;
+var workspaceMonitor = null;
 let _startDate;
 let _defaultCssStylesheet = null;
 let _cssStylesheet = null;
@@ -216,6 +218,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..1935ffa4cb
--- /dev/null
+++ b/js/ui/workspaceMonitor.js
@@ -0,0 +1,97 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+/* exported WorkspaceMonitor */
+
+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() {
+        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(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]