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>
This commit is contained in:
parent
b63c6ac0ef
commit
9e3cb0b797
@ -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));
|
||||
|
||||
this.radioItem = new PopupMenu.PopupMenuItem(this._connection.get_id(), false);
|
||||
this.radioItem.connect('activate', this._activate.bind(this));
|
||||
get name() {
|
||||
return this._connection.get_id();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._activeConnection?.disconnectObject(this);
|
||||
this.labelItem.destroy();
|
||||
this.radioItem.destroy();
|
||||
get state() {
|
||||
return this._activeConnection?.state ??
|
||||
NM.ActiveConnectionState.DEACTIVATED;
|
||||
}
|
||||
|
||||
get is_active() {
|
||||
return this.state <= NM.ActiveConnectionState.ACTIVATED;
|
||||
}
|
||||
|
||||
updateForConnection(connection) {
|
||||
@ -132,30 +158,33 @@ 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() {
|
||||
activate() {
|
||||
super.activate(Clutter.get_current_event());
|
||||
|
||||
if (this.radio_mode && this._activeConnection != null)
|
||||
return; // only activate in radio mode
|
||||
|
||||
if (this._activeConnection == null)
|
||||
this._section.activateConnection(this._connection);
|
||||
else
|
||||
@ -164,14 +193,8 @@ var NMConnectionItem = class extends Signals.EventEmitter {
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_activate() {
|
||||
if (this._activeConnection == null)
|
||||
this._section.activateConnection(this._connection);
|
||||
|
||||
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.radioItem = new PopupMenu.PopupSwitchMenuItem(this._connection.get_id(), false);
|
||||
this.radioItem.connect('toggled', this._toggle.bind(this));
|
||||
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);
|
||||
}
|
||||
|
||||
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 '';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user