[gnome-shell] status/network: Make NMConnectionItem a menu item
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] status/network: Make NMConnectionItem a menu item
- Date: Wed, 10 Aug 2022 13:56:29 +0000 (UTC)
commit 9e3cb0b797eaf5a16489db19d7857f78f223cc41
Author: Florian Müllner <fmuellner gnome org>
Date: Tue Aug 2 12:34:18 2022 +0200
status/network: Make NMConnectionItem a menu item
Instead of the current radioItem/labelItem shenanigans, implement
a custom menu item with a :radio-mode property to switch between
the different presentations.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2407>
js/ui/status/network.js | 188 +++++++++++++++++++++++++++++-------------------
1 file changed, 113 insertions(+), 75 deletions(-)
---
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index 0bddc621a4..9d7b3f0aaf 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NMApplet */
-const { Clutter, Gio, GLib, GObject, Meta, NM, Polkit, St } = imports.gi;
+const {Atk, Clutter, Gio, GLib, GObject, Meta, NM, Polkit, St} = imports.gi;
const Signals = imports.misc.signals;
const Animation = imports.ui.animation;
@@ -98,7 +98,25 @@ function launchSettingsPanel(panel, ...args) {
}
}
-var NMConnectionItem = class extends Signals.EventEmitter {
+const NMConnectionItem = GObject.registerClass({
+ Properties: {
+ 'radio-mode': GObject.ParamSpec.boolean('radio-mode', '', '',
+ GObject.ParamFlags.READWRITE,
+ false),
+ 'is-active': GObject.ParamSpec.boolean('is-active', '', '',
+ GObject.ParamFlags.READABLE,
+ false),
+ 'name': GObject.ParamSpec.string('name', '', '',
+ GObject.ParamFlags.READWRITE,
+ ''),
+ 'icon-name': GObject.ParamSpec.string('icon-name', '', '',
+ GObject.ParamFlags.READWRITE,
+ ''),
+ },
+ Signals: {
+ 'activation-failed': {},
+ },
+}, class NMConnectionItem extends PopupMenu.PopupBaseMenuItem {
constructor(section, connection) {
super();
@@ -106,22 +124,30 @@ var NMConnectionItem = class extends Signals.EventEmitter {
this._connection = connection;
this._activeConnection = null;
- this._buildUI();
+ this._label = new St.Label({
+ y_expand: true,
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ this.add_child(this._label);
+ this.label_actor = this._label;
+
+ this.connectObject(
+ 'notify::radio-mode', () => this._sync(),
+ this);
this._sync();
}
- _buildUI() {
- this.labelItem = new PopupMenu.PopupMenuItem('');
- this.labelItem.connect('activate', this._toggle.bind(this));
+ get name() {
+ return this._connection.get_id();
+ }
- this.radioItem = new PopupMenu.PopupMenuItem(this._connection.get_id(), false);
- this.radioItem.connect('activate', this._activate.bind(this));
+ get state() {
+ return this._activeConnection?.state ??
+ NM.ActiveConnectionState.DEACTIVATED;
}
- destroy() {
- this._activeConnection?.disconnectObject(this);
- this.labelItem.destroy();
- this.radioItem.destroy();
+ get is_active() {
+ return this.state <= NM.ActiveConnectionState.ACTIVATED;
}
updateForConnection(connection) {
@@ -132,46 +158,43 @@ var NMConnectionItem = class extends Signals.EventEmitter {
// Just to be safe, we set it here again
this._connection = connection;
- this.radioItem.label.text = connection.get_id();
+ this.notify('name');
this._sync();
- this.emit('name-changed');
}
- getName() {
- return this._connection.get_id();
- }
-
- isActive() {
- if (this._activeConnection == null)
- return false;
-
- return this._activeConnection.state <= NM.ActiveConnectionState.ACTIVATED;
+ _updateOrnament() {
+ this.setOrnament(this.radio_mode && this.is_active
+ ? PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
}
_sync() {
- let isActive = this.isActive();
- this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
- this.radioItem.setOrnament(isActive ? PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
- this.emit('icon-changed');
+ if (this.radioMode) {
+ this._label.text = this._connection.get_id();
+ this.accessible_role = Atk.Role.CHECK_MENU_ITEM;
+ } else {
+ this._label.text = this.is_active
+ ? _('Turn Off') : this._section.getConnectLabel();
+ this.accessible_role = Atk.Role.MENU_ITEM;
+ }
+ this._updateOrnament();
}
- _toggle() {
- if (this._activeConnection == null)
- this._section.activateConnection(this._connection);
- else
- this._section.deactivateConnection(this._activeConnection);
+ activate() {
+ super.activate(Clutter.get_current_event());
- this._sync();
- }
+ if (this.radio_mode && this._activeConnection != null)
+ return; // only activate in radio mode
- _activate() {
if (this._activeConnection == null)
this._section.activateConnection(this._connection);
+ else
+ this._section.deactivateConnection(this._activeConnection);
this._sync();
}
_connectionStateChanged(_ac, _newstate, _reason) {
+ this.notify('is-active');
this._sync();
}
@@ -185,7 +208,7 @@ var NMConnectionItem = class extends Signals.EventEmitter {
this._sync();
}
-};
+});
var NMConnectionSection = class NMConnectionSection extends Signals.EventEmitter {
constructor(client) {
@@ -199,12 +222,10 @@ var NMConnectionSection = class NMConnectionSection extends Signals.EventEmitter
this._connectionItems = new Map();
this._connections = [];
- this._labelSection = new PopupMenu.PopupMenuSection();
- this._radioSection = new PopupMenu.PopupMenuSection();
+ this._section = new PopupMenu.PopupMenuSection();
this.item = new PopupMenu.PopupSubMenuMenuItem('', true);
- this.item.menu.addMenuItem(this._labelSection);
- this.item.menu.addMenuItem(this._radioSection);
+ this.item.menu.addMenuItem(this._section);
this._client.connectObject('notify::connectivity',
this._iconChanged.bind(this), this);
@@ -223,8 +244,8 @@ var NMConnectionSection = class NMConnectionSection extends Signals.EventEmitter
_sync() {
let nItems = this._connectionItems.size;
- this._radioSection.actor.visible = nItems > 1;
- this._labelSection.actor.visible = nItems == 1;
+ for (const item of this._connectionItems.values())
+ item.radio_mode = nItems > 1;
this.item.label.text = this._getStatus();
this.item.icon.icon_name = this._getMenuIcon();
@@ -275,8 +296,7 @@ var NMConnectionSection = class NMConnectionSection extends Signals.EventEmitter
this._connections.splice(pos, 1);
pos = Util.insertSorted(this._connections, connection, this._connectionSortFunction.bind(this));
- this._labelSection.moveMenuItem(item.labelItem, pos);
- this._radioSection.moveMenuItem(item.radioItem, pos);
+ this._section.moveMenuItem(item, pos);
item.updateForConnection(connection);
}
@@ -286,13 +306,12 @@ var NMConnectionSection = class NMConnectionSection extends Signals.EventEmitter
if (!item)
return;
- item.connect('icon-changed', () => this._iconChanged());
+ item.connect('notify::icon-name', () => this._iconChanged());
item.connect('activation-failed', () => this.emit('activation-failed'));
- item.connect('name-changed', this._sync.bind(this));
+ item.connect('notify::name', this._sync.bind(this));
let pos = Util.insertSorted(this._connections, connection, this._connectionSortFunction.bind(this));
- this._labelSection.addMenuItem(item.labelItem, pos);
- this._radioSection.addMenuItem(item.radioItem, pos);
+ this._section.addMenuItem(item, pos);
this._connectionItems.set(connection.get_uuid(), item);
this._sync();
}
@@ -324,7 +343,8 @@ var NMDeviceItem = class NMDeviceItem extends NMConnectionSection {
this._deviceName = '';
this._autoConnectItem = this.item.menu.addAction(_("Connect"), this._autoConnect.bind(this));
- this._deactivateItem = this._radioSection.addAction(_("Turn Off"),
this.deactivateConnection.bind(this));
+ this._deactivateItem = this.item.menu.addAction(_('Turn Off'),
+ () => this.deactivateConnection());
this._client.connectObject(
'notify::primary-connection', () => this._iconChanged(),
@@ -404,7 +424,7 @@ var NMDeviceItem = class NMDeviceItem extends NMConnectionSection {
_sync() {
let nItems = this._connectionItems.size;
this._autoConnectItem.visible = nItems === 0;
- this._deactivateItem.visible = this._device.state > NM.DeviceState.DISCONNECTED;
+ this._deactivateItem.visible = this.radioMode && this.isActive;
if (this._activeConnection == null) {
let activeConnection = this._device.active_connection;
@@ -1396,20 +1416,39 @@ var NMWirelessDeviceItem = class extends Signals.EventEmitter {
}
};
-var NMVpnConnectionItem = class extends NMConnectionItem {
- _buildUI() {
- this.labelItem = new PopupMenu.PopupMenuItem('');
- this.labelItem.connect('activate', this._toggle.bind(this));
+const NMVpnConnectionItem = GObject.registerClass(
+class NMVpnConnectionItem extends NMConnectionItem {
+ constructor(section, connection) {
+ super(section, connection);
+
+ this._label.x_expand = true;
+
+ this._switch = new PopupMenu.Switch(this.is_active);
+ this.add_child(this._switch);
+
+ this.bind_property('radio-mode',
+ this._switch, 'visible',
+ GObject.BindingFlags.SYNC_CREATE);
+ this.bind_property('is-active',
+ this._switch, 'state',
+ GObject.BindingFlags.SYNC_CREATE);
+ }
- this.radioItem = new PopupMenu.PopupSwitchMenuItem(this._connection.get_id(), false);
- this.radioItem.connect('toggled', this._toggle.bind(this));
+ get name() {
+ return this._connection?.get_id() ?? '';
+ }
+
+ _updateOrnament() {
+ this.setOrnament(PopupMenu.Ornament.NONE);
}
_sync() {
- let isActive = this.isActive();
- this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
- this.radioItem.setToggleState(isActive);
- this.emit('icon-changed');
+ super._sync();
+
+ if (this.radio_mode && this.is_active)
+ this.add_accessible_state(Atk.StateType.CHECKED);
+ else
+ this.remove_accessible_state(Atk.StateType.CHECKED);
}
_connectionStateChanged() {
@@ -1421,21 +1460,21 @@ var NMVpnConnectionItem = class extends NMConnectionItem {
reason !== NM.ActiveConnectionStateReason.USER_DISCONNECTED)
this.emit('activation-failed');
- this.emit('icon-changed');
+ this.notify('icon-name');
super._connectionStateChanged();
}
- getIndicatorIcon() {
- if (this._activeConnection) {
- if (this._activeConnection.state < NM.ActiveConnectionState.ACTIVATED)
- return 'network-vpn-acquiring-symbolic';
- else
- return 'network-vpn-symbolic';
- } else {
- return '';
+ get icon_name() {
+ switch (this.state) {
+ case NM.ActiveConnectionState.ACTIVATING:
+ return 'network-vpn-acquiring-symbolic';
+ case NM.ActiveConnectionState.ACTIVATED:
+ return 'network-vpn-symbolic';
+ default:
+ return 'network-vpn-disabled-symbolic';
}
}
-};
+});
var NMVpnSection = class extends NMConnectionSection {
constructor(client) {
@@ -1464,8 +1503,8 @@ var NMVpnSection = class extends NMConnectionSection {
_getStatus() {
let values = this._connectionItems.values();
for (let item of values) {
- if (item.isActive())
- return item.getName();
+ if (item.is_active)
+ return item.name;
}
return _("VPN Off");
@@ -1503,9 +1542,8 @@ var NMVpnSection = class extends NMConnectionSection {
getIndicatorIcon() {
let items = this._connectionItems.values();
for (let item of items) {
- let icon = item.getIndicatorIcon();
- if (icon)
- return icon;
+ if (item.is_active)
+ return item.icon_name;
}
return '';
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]