[gnome-shell/eos3.8: 62/255] overview: Show dialog when toggling to showing windows with no apps running



commit 3077712045761599103310eb983fd9d213d339a2
Author: Mario Sanchez Prada <mario endlessm com>
Date:   Tue Sep 12 15:55:03 2017 +0100

    overview: Show dialog when toggling to showing windows with no apps running
    
    When there are no applications opened and the user presses the super key,
    clicks on the Endless button or uses the hot corner, we show a dialog with
    a message informing about that.
    
     * 2020-03-16: Squash with 9940dc3d8
    
    https://phabricator.endlessm.com/T17227

 js/ui/modalDialog.js | 124 +++++++++++++++++++++++++++++++++++++++++++++++++--
 js/ui/overview.js    |  80 +++++++++++++++++++++++++++++++--
 2 files changed, 198 insertions(+), 6 deletions(-)
---
diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js
index caa874454f..7615c06c25 100644
--- a/js/ui/modalDialog.js
+++ b/js/ui/modalDialog.js
@@ -1,10 +1,9 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
-/* exported ModalDialog */
+/* exported ModalDialog, NoWindowsDialog */
 
 const { Atk, Clutter, GObject, Shell, St } = imports.gi;
 
 const Dialog = imports.ui.dialog;
-const Layout = imports.ui.layout;
 const Lightbox = imports.ui.lightbox;
 const Main = imports.ui.main;
 const Params = imports.misc.params;
@@ -20,6 +19,125 @@ var State = {
     FADED_OUT: 4,
 };
 
+var ModalDialogConstraint = GObject.registerClass({
+    Properties: {
+        'primary': GObject.ParamSpec.boolean('primary',
+                                             'Primary', 'Track primary monitor',
+                                             GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+                                             false),
+        'index': GObject.ParamSpec.int('index',
+                                       'Monitor index', 'Track specific monitor',
+                                       GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+                                       -1, 64, -1),
+        'work-area': GObject.ParamSpec.boolean('work-area',
+                                               'Work-area', 'Track monitor\'s work-area',
+                                               GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+                                               false),
+    },
+}, class ModalDialogConstraint extends Clutter.Constraint {
+    _init(props) {
+        this._primary = false;
+        this._index = -1;
+        this._workArea = false;
+
+        super._init(props);
+    }
+
+    get primary() {
+        return this._primary;
+    }
+
+    set primary(v) {
+        if (v)
+            this._index = -1;
+        this._primary = v;
+        if (this.actor)
+            this.actor.queue_relayout();
+        this.notify('primary');
+    }
+
+    get index() {
+        return this._index;
+    }
+
+    set index(v) {
+        this._primary = false;
+        this._index = v;
+        if (this.actor)
+            this.actor.queue_relayout();
+        this.notify('index');
+    }
+
+    // eslint-disable-next-line camelcase
+    get work_area() {
+        return this._workArea;
+    }
+
+    // eslint-disable-next-line camelcase
+    set work_area(v) {
+        if (v == this._workArea)
+            return;
+        this._workArea = v;
+        if (this.actor)
+            this.actor.queue_relayout();
+        this.notify('work-area');
+    }
+
+    vfunc_set_actor(actor) {
+        if (actor) {
+            if (!this._monitorsChangedId) {
+                this._monitorsChangedId =
+                    Main.layoutManager.connect('monitors-changed', () => {
+                        this.actor.queue_relayout();
+                    });
+            }
+
+            if (!this._workareasChangedId) {
+                this._workareasChangedId =
+                    global.display.connect('workareas-changed', () => {
+                        if (this._workArea)
+                            this.actor.queue_relayout();
+                    });
+            }
+        } else {
+            if (this._monitorsChangedId)
+                Main.layoutManager.disconnect(this._monitorsChangedId);
+            this._monitorsChangedId = 0;
+
+            if (this._workareasChangedId)
+                global.display.disconnect(this._workareasChangedId);
+            this._workareasChangedId = 0;
+        }
+
+        super.vfunc_set_actor(actor);
+    }
+
+    vfunc_update_allocation(actor, actorBox) {
+        if (!this._primary && this._index < 0)
+            return;
+
+        if (!Main.layoutManager.primaryMonitor)
+            return;
+
+        let index;
+        if (this._primary)
+            index = Main.layoutManager.primaryIndex;
+        else
+            index = Math.min(this._index, Main.layoutManager.monitors.length - 1);
+
+        let rect;
+        if (this._workArea) {
+            let workspaceManager = global.workspace_manager;
+            let ws = workspaceManager.get_workspace_by_index(0);
+            rect = ws.get_work_area_for_monitor(index);
+        } else {
+            rect = Main.layoutManager.monitors[index];
+        }
+
+        actorBox.init_rect(rect.x, rect.y, rect.width, rect.height);
+    }
+});
+
 var ModalDialog = GObject.registerClass({
     Properties: {
         'state': GObject.ParamSpec.int('state', 'Dialog state', 'state',
@@ -63,7 +181,7 @@ var ModalDialog = GObject.registerClass({
             y_expand: true,
         });
         this._backgroundBin = new St.Bin({ child: this.backgroundStack });
-        this._monitorConstraint = new Layout.MonitorConstraint();
+        this._monitorConstraint = new ModalDialogConstraint();
         this._backgroundBin.add_constraint(this._monitorConstraint);
         this.add_actor(this._backgroundBin);
 
diff --git a/js/ui/overview.js b/js/ui/overview.js
index 5eb3c5dd62..371d3971d7 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -1,7 +1,7 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /* exported Overview */
 
-const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
+const { Clutter, GLib, GObject, Meta, Pango, Shell, St } = imports.gi;
 const Signals = imports.signals;
 
 const Background = imports.ui.background;
@@ -10,6 +10,7 @@ const LayoutManager = imports.ui.layout;
 const Lightbox = imports.ui.lightbox;
 const Main = imports.ui.main;
 const MessageTray = imports.ui.messageTray;
+const ModalDialog = imports.ui.modalDialog;
 const OverviewControls = imports.ui.overviewControls;
 const Params = imports.misc.params;
 const ViewSelector = imports.ui.viewSelector;
@@ -27,6 +28,8 @@ var DND_WINDOW_SWITCH_TIMEOUT = 750;
 
 var OVERVIEW_ACTIVATION_TIMEOUT = 0.5;
 
+var NO_WINDOWS_OPEN_DIALOG_TIMEOUT = 2000; // ms
+
 var ShellInfo = class {
     constructor() {
         this._source = null;
@@ -94,6 +97,58 @@ var ShellInfo = class {
     }
 };
 
+var NoWindowsDialog = GObject.registerClass(
+class NoWindowsDialog extends ModalDialog.ModalDialog {
+    _init() {
+        super._init({
+            styleClass: 'prompt-dialog',
+            shellReactive: true,
+            destroyOnClose: false,
+        });
+
+        this._timeoutId = 0;
+
+        let descriptionLabel = new St.Label({
+            style_class: 'prompt-dialog-headline headline',
+            text: _('No apps are open'),
+            x_expand: true,
+            x_align: Clutter.ActorAlign.CENTER,
+        });
+        descriptionLabel.clutter_text.line_wrap = true;
+        descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
+
+        this.contentLayout.add_child(descriptionLabel);
+
+        this.connect('key-press-event', () => {
+            this.close(global.get_current_time());
+            return Clutter.EVENT_PROPAGATE;
+        });
+    }
+
+    popup() {
+        if (this._timeoutId !== 0)
+            GLib.source_remove(this._timeoutId);
+
+        this._timeoutId =
+            GLib.timeout_add(
+                GLib.PRIORITY_DEFAULT,
+                NO_WINDOWS_OPEN_DIALOG_TIMEOUT,
+                () => {
+                    this.popdown();
+                    return GLib.SOURCE_REMOVE;
+                });
+        this.open(global.get_current_time());
+    }
+
+    popdown() {
+        if (this._timeoutId !== 0) {
+            GLib.source_remove(this._timeoutId);
+            this._timeoutId = 0;
+        }
+        this.close(global.get_current_time());
+    }
+});
+
 var OverviewActor = GObject.registerClass(
 class OverviewActor extends St.BoxLayout {
     _init() {
@@ -153,6 +208,8 @@ var Overview = class {
         this._initCalled = false;
         this._visible = false;
 
+        this._noWindowsDialog = new NoWindowsDialog();
+
         Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
         this._sessionUpdated();
     }
@@ -532,6 +589,11 @@ var Overview = class {
             return;
         }
 
+        if (!Main.workspaceMonitor.hasActiveWindows) {
+            this._noWindowsDialog.popup();
+            return;
+        }
+
         if (!Main.workspaceMonitor.hasVisibleWindows) {
             // There are active windows but all of them are hidden, so activate
             // the most recently used one before hiding the overview.
@@ -549,8 +611,17 @@ var Overview = class {
         if (this.isDummy)
             return;
 
-        if (!this.visible ||
-            this.viewSelector.getActivePage() !== ViewSelector.ViewPage.WINDOWS) {
+        if (!this.visible) {
+            this.showWindows();
+            return;
+        }
+
+        if (!Main.workspaceMonitor.hasActiveWindows) {
+            this._noWindowsDialog.popup();
+            return;
+        }
+
+        if (this.viewSelector.getActivePage() !== ViewSelector.ViewPage.WINDOWS) {
             this.showWindows();
             return;
         }
@@ -705,6 +776,9 @@ var Overview = class {
 
         this._shown = false;
 
+        // Hide the 'No windows dialog' in case it is open
+        this._noWindowsDialog.popdown();
+
         this._animateNotVisible();
         this._syncGrab();
     }


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