[gnome-shell] status/system: Port to quick settings



commit ea00da7fd7fbc90fff62369552583afe3f6750db
Author: Florian Müllner <fmuellner gnome org>
Date:   Sat Jul 30 02:17:15 2022 +0200

    status/system: Port to quick settings
    
    This port is a bit messier than the previous ones, because the
    existing menu section translates less directly to the new UI,
    which uses a row of individual toggles for settings, lock and
    shutdown.
    
    In order to not complicate the grid layout further by supporting
    rows with a different number of columns than the overall grid and
    children at their natural size, create a custom, non-reactive
    SystemItem item that spans an entire row, and contains the individual
    toggles.
    
    This works quite well, even with the shutdown item that uses a menu
    for the various actions.
    
    Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2393>

 .../gnome-shell-sass/widgets/_quick-settings.scss  |   4 +
 js/ui/panel.js                                     |  10 +-
 js/ui/status/system.js                             | 262 +++++++++++----------
 3 files changed, 150 insertions(+), 126 deletions(-)
---
diff --git a/data/theme/gnome-shell-sass/widgets/_quick-settings.scss 
b/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
index 664f24ca82..82d88b4b3d 100644
--- a/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
+++ b/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
@@ -83,3 +83,7 @@
 .quick-toggle-menu-container {
   padding: 2 * $base_padding $base_padding 0;
  }
+
+.quick-settings-system-item {
+  & > StBoxLayout { spacing: 2 * $base_padding; }
+}
diff --git a/js/ui/panel.js b/js/ui/panel.js
index e1f4f65a69..f439557819 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -378,18 +378,11 @@ class AggregateMenu extends PanelMenu.Button {
         else
             this._network = null;
 
-        this._system = new imports.ui.status.system.Indicator();
-
         if (this._network)
             this._indicators.add_child(this._network);
 
         if (this._network)
             this.menu.addMenuItem(this._network.menu);
-
-        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
-        this.menu.addMenuItem(this._system.menu);
-
-        menuLayout.addSizeChild(this._system.menu.actor);
     }
 });
 
@@ -410,6 +403,7 @@ class QuickSettings extends PanelMenu.Button {
         else
             this._bluetooth = null;
 
+        this._system = new imports.ui.status.system.Indicator();
         this._volume = new imports.ui.status.volume.Indicator();
         this._brightness = new imports.ui.status.brightness.Indicator();
         this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet();
@@ -437,7 +431,9 @@ class QuickSettings extends PanelMenu.Button {
         this._indicators.add_child(this._volume);
         this._indicators.add_child(this._unsafeMode);
         this._indicators.add_child(this._power);
+        this._indicators.add_child(this._system);
 
+        this._addItems(this._system.quickSettingsItems, N_QUICK_SETTINGS_COLUMNS);
         this._addItems(this._volume.quickSettingsItems, N_QUICK_SETTINGS_COLUMNS);
         this._addItems(this._brightness.quickSettingsItems, N_QUICK_SETTINGS_COLUMNS);
 
diff --git a/js/ui/status/system.js b/js/ui/status/system.js
index b218e3e541..ed9e3cf7e3 100644
--- a/js/ui/status/system.js
+++ b/js/ui/status/system.js
@@ -1,157 +1,181 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 /* exported Indicator */
 
-const { GObject, Shell, St } = imports.gi;
+const {Clutter, GObject, Shell, St} = imports.gi;
 
-const BoxPointer = imports.ui.boxpointer;
 const SystemActions = imports.misc.systemActions;
 const Main = imports.ui.main;
-const PanelMenu = imports.ui.panelMenu;
 const PopupMenu = imports.ui.popupMenu;
 
+const {QuickSettingsItem, SystemIndicator} = imports.ui.quickSettings;
 
-var Indicator = GObject.registerClass(
-class Indicator extends PanelMenu.SystemIndicator {
+const SettingsItem = GObject.registerClass(
+class SettingsItem extends QuickSettingsItem {
     _init() {
-        super._init();
+        super._init({
+            style_class: 'icon-button',
+            can_focus: true,
+            child: new St.Icon(),
+        });
+
+        this._settingsApp = Shell.AppSystem.get_default().lookup_app(
+            'org.gnome.Settings.desktop');
+
+        if (!this._settingsApp)
+            console.warn('Missing required core component Settings, expect trouble…');
+
+        this.child.gicon = this._settingsApp?.get_icon() ?? null;
+        this.accessible_name = this._settingsApp?.get_name() ?? null;
+
+        this.connect('clicked', () => {
+            Main.overview.hide();
+            Main.panel.closeQuickSettings();
+            this._settingsApp.activate();
+        });
+
+        Main.sessionMode.connectObject('updated', () => this._sync(), this);
+        this._sync();
+    }
+
+    _sync() {
+        this.visible =
+            this._settingsApp != null && Main.sessionMode.allowSettings;
+    }
+});
+
+const ShutdownItem = GObject.registerClass(
+class ShutdownItem extends QuickSettingsItem {
+    _init() {
+        super._init({
+            style_class: 'icon-button',
+            hasMenu: true,
+            canFocus: true,
+            child: new St.Icon({
+                icon_name: 'system-shutdown-symbolic',
+            }),
+            accessible_name: _('Power Off Menu'),
+        });
 
         this._systemActions = new SystemActions.getDefault();
+        this._items = [];
+
+        this.menu.setHeader('system-shutdown-symbolic', 'Power Off');
+
+        this._addSystemAction(_('Suspend'), 'can-suspend', () => {
+            this._systemActions.activateSuspend();
+            Main.panel.closeQuickSettings();
+        });
+
+        this._addSystemAction(_('Restart…'), 'can-restart', () => {
+            this._systemActions.activateRestart();
+            Main.panel.closeQuickSettings();
+        });
+
+        this._addSystemAction(_('Power Off…'), 'can-power-off', () => {
+            this._systemActions.activatePowerOff();
+            Main.panel.closeQuickSettings();
+        });
+
+        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+
+        this._addSystemAction(_('Log Out'), 'can-logout', () => {
+            this._systemActions.activateLogout();
+            Main.panel.closeQuickSettings();
+        });
+
+        this._addSystemAction(_('Switch User…'), 'can-switch-user', () => {
+            this._systemActions.activateSwitchUser();
+            Main.panel.closeQuickSettings();
+        });
 
-        this._createSubMenu();
-
-        this._loginScreenItem.connect('notify::visible',
-            () => this._updateSessionSubMenu());
-        this._logoutItem.connect('notify::visible',
-            () => this._updateSessionSubMenu());
-        this._suspendItem.connect('notify::visible',
-            () => this._updateSessionSubMenu());
-        this._powerOffItem.connect('notify::visible',
-            () => this._updateSessionSubMenu());
-        this._restartItem.connect('notify::visible',
-            () => this._updateSessionSubMenu());
         // Whether shutdown is available or not depends on both lockdown
         // settings (disable-log-out) and Polkit policy - the latter doesn't
-        // notify, so we update the menu item each time the menu opens or
+        // notify, so we update the item each time we become visible or
         // the lockdown setting changes, which should be close enough.
-        this.menu.connect('open-state-changed', (menu, open) => {
-            if (!open)
+        this.connect('notify::mapped', () => {
+            if (!this.mapped)
                 return;
 
             this._systemActions.forceUpdate();
         });
-        this._updateSessionSubMenu();
 
-        Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
-        this._sessionUpdated();
+        this.connect('clicked', () => this.menu.open());
+        this.connect('popup-menu', () => this.menu.open());
     }
 
-    _sessionUpdated() {
-        this._settingsItem.visible = Main.sessionMode.allowSettings;
+    _addSystemAction(label, propName, callback) {
+        const item = this.menu.addAction(label, callback);
+        this._items.push(item);
+
+        this._systemActions.bind_property(propName,
+            item, 'visible',
+            GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE);
+        item.connect('notify::visible', () => this._sync());
     }
 
-    _updateSessionSubMenu() {
-        this._sessionSubMenu.visible =
-            this._loginScreenItem.visible ||
-            this._logoutItem.visible ||
-            this._suspendItem.visible ||
-            this._restartItem.visible ||
-            this._powerOffItem.visible;
+    _sync() {
+        this.visible = this._items.some(i => i.visible);
     }
+});
 
-    _createSubMenu() {
-        let bindFlags = GObject.BindingFlags.DEFAULT | GObject.BindingFlags.SYNC_CREATE;
-        let item;
+const LockItem = GObject.registerClass(
+class LockItem extends QuickSettingsItem {
+    _init() {
+        this._systemActions = new SystemActions.getDefault();
 
-        let app = this._settingsApp = Shell.AppSystem.get_default().lookup_app(
-            'org.gnome.Settings.desktop');
-        if (app) {
-            const [icon] = app.app_info.get_icon().names;
-            const name = app.app_info.get_name();
-            item = new PopupMenu.PopupImageMenuItem(name, icon);
-            item.connect('activate', () => {
-                this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-                Main.overview.hide();
-                this._settingsApp.activate();
-            });
-            this.menu.addMenuItem(item);
-            this._settingsItem = item;
-        } else {
-            log('Missing required core component Settings, expect trouble…');
-            this._settingsItem = new St.Widget();
-        }
-
-        item = new PopupMenu.PopupImageMenuItem(_('Lock'), 'changes-prevent-symbolic');
-        item.connect('activate', () => {
-            this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-            this._systemActions.activateLockScreen();
+        super._init({
+            style_class: 'icon-button',
+            can_focus: true,
+            child: new St.Icon({
+                icon_name: 'system-lock-screen-symbolic',
+            }),
+            accessible_name: _('Lock Screen'),
         });
-        this.menu.addMenuItem(item);
-        this._lockScreenItem = item;
+
         this._systemActions.bind_property('can-lock-screen',
-            this._lockScreenItem, 'visible',
-            bindFlags);
+            this, 'visible',
+            GObject.BindingFlags.DEFAULT |
+            GObject.BindingFlags.SYNC_CREATE);
 
-        this._sessionSubMenu = new PopupMenu.PopupSubMenuMenuItem(
-            _('Power Off / Log Out'), true);
-        this._sessionSubMenu.icon.icon_name = 'system-shutdown-symbolic';
+        this.connect('clicked',
+            () => this._systemActions.activateLockScreen());
+    }
+});
 
-        item = new PopupMenu.PopupMenuItem(_('Suspend'));
-        item.connect('activate', () => {
-            this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-            this._systemActions.activateSuspend();
-        });
-        this._sessionSubMenu.menu.addMenuItem(item);
-        this._suspendItem = item;
-        this._systemActions.bind_property('can-suspend',
-            this._suspendItem, 'visible',
-            bindFlags);
-
-        item = new PopupMenu.PopupMenuItem(_('Restart…'));
-        item.connect('activate', () => {
-            this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-            this._systemActions.activateRestart();
-        });
-        this._sessionSubMenu.menu.addMenuItem(item);
-        this._restartItem = item;
-        this._systemActions.bind_property('can-restart',
-            this._restartItem, 'visible',
-            bindFlags);
-
-        item = new PopupMenu.PopupMenuItem(_('Power Off…'));
-        item.connect('activate', () => {
-            this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-            this._systemActions.activatePowerOff();
+
+const SystemItem = GObject.registerClass(
+class SystemItem extends QuickSettingsItem {
+    _init() {
+        super._init({
+            style_class: 'quick-settings-system-item',
+            reactive: false,
         });
-        this._sessionSubMenu.menu.addMenuItem(item);
-        this._powerOffItem = item;
-        this._systemActions.bind_property('can-power-off',
-            this._powerOffItem, 'visible',
-            bindFlags);
 
-        this._sessionSubMenu.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+        this.child = new St.BoxLayout();
 
-        item = new PopupMenu.PopupMenuItem(_('Log Out'));
-        item.connect('activate', () => {
-            this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-            this._systemActions.activateLogout();
-        });
-        this._sessionSubMenu.menu.addMenuItem(item);
-        this._logoutItem = item;
-        this._systemActions.bind_property('can-logout',
-            this._logoutItem, 'visible',
-            bindFlags);
-
-        item = new PopupMenu.PopupMenuItem(_('Switch User…'));
-        item.connect('activate', () => {
-            this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
-            this._systemActions.activateSwitchUser();
-        });
-        this._sessionSubMenu.menu.addMenuItem(item);
-        this._loginScreenItem = item;
-        this._systemActions.bind_property('can-switch-user',
-            this._loginScreenItem, 'visible',
-            bindFlags);
+        // spacer
+        this.child.add_child(new Clutter.Actor({x_expand: true}));
+
+        const settingsItem = new SettingsItem();
+        this.child.add_child(settingsItem);
+
+        const lockItem = new LockItem();
+        this.child.add_child(lockItem);
+
+        const shutdownItem = new ShutdownItem();
+        this.child.add_child(shutdownItem);
+
+        this.menu = shutdownItem.menu;
+    }
+});
+
+var Indicator = GObject.registerClass(
+class Indicator extends SystemIndicator {
+    _init() {
+        super._init();
+
+        const item = new SystemItem();
 
-        this.menu.addMenuItem(this._sessionSubMenu);
+        this.quickSettingsItems.push(item);
     }
 });


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