[gnome-shell] status/network: Replace wi-fi selection dialog
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] status/network: Replace wi-fi selection dialog
- Date: Wed, 10 Aug 2022 13:56:30 +0000 (UTC)
commit 50671a78ecd0a25290b78c08de97943101744739
Author: Florian Müllner <fmuellner gnome org>
Date: Sat Aug 6 02:43:29 2022 +0200
status/network: Replace wi-fi selection dialog
Now that wi-fi devices will be handled by a separate menu toggle
instead of as part of a combined system menu, there is no longer
a need of delegating network selection to a separate dialog.
To keep the menu from growing too much, the (sorted) list of
displayed networks is kept at a limit of eight. There is always
Settings for a complete list…
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2407>
data/theme/gnome-shell-sass/_widgets.scss | 1 -
.../gnome-shell-sass/widgets/_network-dialog.scss | 52 ---
.../gnome-shell-sass/widgets/_quick-settings.scss | 4 +
data/theme/meson.build | 1 -
js/ui/status/network.js | 497 +++++----------------
5 files changed, 116 insertions(+), 439 deletions(-)
---
diff --git a/data/theme/gnome-shell-sass/_widgets.scss b/data/theme/gnome-shell-sass/_widgets.scss
index 875baf5827..a09e0b5495 100644
--- a/data/theme/gnome-shell-sass/_widgets.scss
+++ b/data/theme/gnome-shell-sass/_widgets.scss
@@ -24,7 +24,6 @@
@import 'widgets/hotplug';
// Dialogs
@import 'widgets/dialogs';
-@import 'widgets/network-dialog';
// OSDs
@import 'widgets/osd';
@import 'widgets/switcher-popup';
diff --git a/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
b/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
index 1324865904..50342434de 100644
--- a/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
+++ b/data/theme/gnome-shell-sass/widgets/_quick-settings.scss
@@ -101,3 +101,7 @@
}
}
}
+
+.nm-network-item {
+ .wireless-secure-icon { icon-size: 0.5 * $base_icon_size; }
+}
diff --git a/data/theme/meson.build b/data/theme/meson.build
index fbf2938b88..e6c1723dbc 100644
--- a/data/theme/meson.build
+++ b/data/theme/meson.build
@@ -23,7 +23,6 @@ theme_sources = files([
'gnome-shell-sass/widgets/_looking-glass.scss',
'gnome-shell-sass/widgets/_message-list.scss',
'gnome-shell-sass/widgets/_misc.scss',
- 'gnome-shell-sass/widgets/_network-dialog.scss',
'gnome-shell-sass/widgets/_notifications.scss',
'gnome-shell-sass/widgets/_osd.scss',
'gnome-shell-sass/widgets/_overview.scss',
diff --git a/js/ui/status/network.js b/js/ui/status/network.js
index 693f499f74..81e1fb4253 100644
--- a/js/ui/status/network.js
+++ b/js/ui/status/network.js
@@ -1,15 +1,12 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NMApplet */
-const {Atk, Clutter, Gio, GLib, GObject, Meta, NM, Polkit, St} = imports.gi;
+const {Atk, Clutter, Gio, GLib, GObject, NM, Polkit, St} = imports.gi;
-const Animation = imports.ui.animation;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const MessageTray = imports.ui.messageTray;
-const ModalDialog = imports.ui.modalDialog;
const ModemManager = imports.misc.modemManager;
-const Rfkill = imports.ui.status.rfkill;
const Util = imports.misc.util;
const {loadInterfaceXML} = imports.misc.fileUtils;
@@ -28,6 +25,7 @@ const NMConnectionCategory = {
VPN: 'vpn',
};
+const MAX_VISIBLE_NETWORKS = 8;
var MAX_DEVICE_ITEMS = 4;
// small optimization, to avoid using [] all the time
@@ -952,53 +950,35 @@ const WirelessNetwork = GObject.registerClass({
});
registerDestroyableType(WirelessNetwork);
-var NMWirelessDialogItem = GObject.registerClass({
- Signals: {
- 'selected': {},
- },
-}, class NMWirelessDialogItem extends St.BoxLayout {
+const NMWirelessNetworkItem = GObject.registerClass(
+class NMWirelessNetworkItem extends PopupMenu.PopupBaseMenuItem {
_init(network) {
+ super._init({style_class: 'nm-network-item'});
+
this._network = network;
- super._init({
- style_class: 'nm-dialog-item',
- can_focus: true,
- reactive: true,
- });
+ const icons = new St.BoxLayout();
+ this.add_child(icons);
- let action = new Clutter.ClickAction();
- action.connect('clicked', () => this.grab_key_focus());
- this.add_action(action);
+ this._signalIcon = new St.Icon({style_class: 'popup-menu-icon'});
+ icons.add_child(this._signalIcon);
- this._label = new St.Label({
- x_expand: true,
+ this._secureIcon = new St.Icon({
+ style_class: 'wireless-secure-icon',
+ y_align: Clutter.ActorAlign.END,
});
+ icons.add_actor(this._secureIcon);
+ this._label = new St.Label();
this.label_actor = this._label;
this.add_child(this._label);
this._selectedIcon = new St.Icon({
- style_class: 'nm-dialog-icon nm-dialog-network-selected',
+ style_class: 'popup-menu-icon',
icon_name: 'object-select-symbolic',
});
this.add(this._selectedIcon);
- this._icons = new St.BoxLayout({
- style_class: 'nm-dialog-icons',
- x_align: Clutter.ActorAlign.END,
- });
- this.add_child(this._icons);
-
- this._secureIcon = new St.Icon({
- style_class: 'nm-dialog-icon',
- });
- this._icons.add_actor(this._secureIcon);
-
- this._signalIcon = new St.Icon({
- style_class: 'nm-dialog-icon',
- });
- this._icons.add_actor(this._signalIcon);
-
this._network.bind_property('icon-name',
this._signalIcon, 'icon-name',
GObject.BindingFlags.SYNC_CREATE);
@@ -1018,321 +998,6 @@ var NMWirelessDialogItem = GObject.registerClass({
get network() {
return this._network;
}
-
- vfunc_key_focus_in() {
- this.emit('selected');
- }
-});
-
-var NMWirelessDialog = GObject.registerClass(
-class NMWirelessDialog extends ModalDialog.ModalDialog {
- _init(client, device) {
- super._init({ styleClass: 'nm-dialog' });
-
- this._client = client;
- this._device = device;
-
- this._client.connectObject('notify::wireless-enabled',
- this._syncView.bind(this), this);
-
- this._rfkill = Rfkill.getRfkillManager();
- this._rfkill.connectObject(
- 'notify::airplane-mode', () => this._syncView(),
- 'notify::hw-airplane-mode', () => this._syncView(),
- this);
-
- this._networkItems = new Map();
- this._buildLayout();
-
- let connections = client.get_connections();
- this._connections = connections.filter(
- connection => device.connection_valid(connection));
-
- device.connectObject(
- 'notify::active-access-point', () => this._updateSensitivity(),
- 'notify::available-connections', () => this._availableConnectionsChanged(),
- 'access-point-added', (d, ap) => {
- this._addAccessPoint(ap);
- this._syncNetworksList();
- this._syncView();
- },
- 'access-point-removed', (d, ap) => {
- this._removeAccessPoint(ap);
- this._syncNetworksList();
- this._syncView();
- },
- this);
-
- for (const ap of this._device.get_access_points())
- this._addAccessPoint(ap);
-
- this._selectedNetwork = null;
- this._availableConnectionsChanged();
- this._updateSensitivity();
- this._syncView();
-
- this._scanTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 15,
this._onScanTimeout.bind(this));
- GLib.Source.set_name_by_id(this._scanTimeoutId, '[gnome-shell] this._onScanTimeout');
- this._onScanTimeout();
-
- let id = Main.sessionMode.connect('updated', () => {
- if (Main.sessionMode.allowSettings)
- return;
-
- Main.sessionMode.disconnect(id);
- this.close();
- });
-
- this.connect('destroy', this._onDestroy.bind(this));
- }
-
- _onDestroy() {
- if (this._scanTimeoutId) {
- GLib.source_remove(this._scanTimeoutId);
- this._scanTimeoutId = 0;
- }
-
- if (this._syncVisibilityId) {
- Meta.later_remove(this._syncVisibilityId);
- this._syncVisibilityId = 0;
- }
- }
-
- _onScanTimeout() {
- this._device.request_scan_async(null, null);
- return GLib.SOURCE_CONTINUE;
- }
-
- _availableConnectionsChanged() {
- const connections = this._device.get_available_connections();
- for (const net of this._networkItems.keys())
- net.checkConnections(connections);
- this._syncNetworksList();
- }
-
- _updateSensitivity() {
- const connectSensitive =
- this._client.wireless_enabled && this._selectedNetwork && !this._selectedNetwork.isActive;
- this._connectButton.reactive = connectSensitive;
- this._connectButton.can_focus = connectSensitive;
- }
-
- _syncView() {
- if (this._rfkill.airplaneMode) {
- this._airplaneBox.show();
-
- this._airplaneIcon.icon_name = 'airplane-mode-symbolic';
- this._airplaneHeadline.text = _("Airplane Mode is On");
- this._airplaneText.text = _("Wi-Fi is disabled when airplane mode is on.");
- this._airplaneButton.label = _("Turn Off Airplane Mode");
-
- this._airplaneButton.visible = !this._rfkill.hwAirplaneMode;
- this._airplaneInactive.visible = this._rfkill.hwAirplaneMode;
- this._noNetworksBox.hide();
- } else if (!this._client.wireless_enabled) {
- this._airplaneBox.show();
-
- this._airplaneIcon.icon_name = 'dialog-information-symbolic';
- this._airplaneHeadline.text = _("Wi-Fi is Off");
- this._airplaneText.text = _("Wi-Fi needs to be turned on in order to connect to a network.");
- this._airplaneButton.label = _("Turn On Wi-Fi");
-
- this._airplaneButton.show();
- this._airplaneInactive.hide();
- this._noNetworksBox.hide();
- } else {
- this._airplaneBox.hide();
-
- this._noNetworksBox.visible = this._networkItems.size === 0;
- }
-
- if (this._noNetworksBox.visible)
- this._noNetworksSpinner.play();
- else
- this._noNetworksSpinner.stop();
- }
-
- _buildLayout() {
- let headline = new St.BoxLayout({ style_class: 'nm-dialog-header-hbox' });
-
- const icon = new St.Icon({
- style_class: 'nm-dialog-header-icon',
- icon_name: 'network-wireless-symbolic',
- });
-
- let titleBox = new St.BoxLayout({ vertical: true });
- const title = new St.Label({
- style_class: 'nm-dialog-header',
- text: _('Wi-Fi Networks'),
- });
- const subtitle = new St.Label({
- style_class: 'nm-dialog-subheader',
- text: _('Select a network'),
- });
- titleBox.add(title);
- titleBox.add(subtitle);
-
- headline.add(icon);
- headline.add(titleBox);
-
- this.contentLayout.style_class = 'nm-dialog-content';
- this.contentLayout.add(headline);
-
- this._stack = new St.Widget({
- layout_manager: new Clutter.BinLayout(),
- y_expand: true,
- });
-
- this._itemBox = new St.BoxLayout({ vertical: true });
- this._scrollView = new St.ScrollView({ style_class: 'nm-dialog-scroll-view' });
- this._scrollView.set_x_expand(true);
- this._scrollView.set_y_expand(true);
- this._scrollView.set_policy(St.PolicyType.NEVER,
- St.PolicyType.AUTOMATIC);
- this._scrollView.add_actor(this._itemBox);
- this._stack.add_child(this._scrollView);
-
- this._noNetworksBox = new St.BoxLayout({
- vertical: true,
- style_class: 'no-networks-box',
- x_align: Clutter.ActorAlign.CENTER,
- y_align: Clutter.ActorAlign.CENTER,
- });
-
- this._noNetworksSpinner = new Animation.Spinner(16);
- this._noNetworksBox.add_actor(this._noNetworksSpinner);
- this._noNetworksBox.add_actor(new St.Label({
- style_class: 'no-networks-label',
- text: _('No Networks'),
- }));
- this._stack.add_child(this._noNetworksBox);
-
- this._airplaneBox = new St.BoxLayout({
- vertical: true,
- style_class: 'nm-dialog-airplane-box',
- x_align: Clutter.ActorAlign.CENTER,
- y_align: Clutter.ActorAlign.CENTER,
- });
- this._airplaneIcon = new St.Icon({ icon_size: 48 });
- this._airplaneHeadline = new St.Label({ style_class: 'nm-dialog-airplane-headline headline' });
- this._airplaneText = new St.Label({ style_class: 'nm-dialog-airplane-text' });
-
- let airplaneSubStack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
- this._airplaneButton = new St.Button({ style_class: 'modal-dialog-button button' });
- this._airplaneButton.connect('clicked', () => {
- if (this._rfkill.airplaneMode)
- this._rfkill.airplaneMode = false;
- else
- this._client.wireless_enabled = true;
- });
- airplaneSubStack.add_actor(this._airplaneButton);
- this._airplaneInactive = new St.Label({
- style_class: 'nm-dialog-airplane-text',
- text: _('Use hardware switch to turn off'),
- });
- airplaneSubStack.add_actor(this._airplaneInactive);
-
- this._airplaneBox.add_child(this._airplaneIcon);
- this._airplaneBox.add_child(this._airplaneHeadline);
- this._airplaneBox.add_child(this._airplaneText);
- this._airplaneBox.add_child(airplaneSubStack);
- this._stack.add_child(this._airplaneBox);
-
- this.contentLayout.add_child(this._stack);
-
- this._disconnectButton = this.addButton({
- action: () => this.close(),
- label: _('Cancel'),
- key: Clutter.KEY_Escape,
- });
- this._connectButton = this.addButton({
- action: this._connect.bind(this),
- label: _('Connect'),
- key: Clutter.KEY_Return,
- });
- }
-
- _connect() {
- this._selectedNetwork?.activate();
- this.close();
- }
-
- _addAccessPoint(ap) {
- if (ap.get_ssid() == null) {
- // This access point is not visible yet
- // Wait for it to get a ssid
- ap.connectObject('notify::ssid', () => {
- if (!ap.ssid)
- return;
- ap.disconnectObject(this);
- this._addAccessPoint(ap);
- }, this);
- return;
- }
-
- let network = [...this._networkItems.keys()]
- .find(n => n.checkAccessPoint(ap));
-
- if (!network) {
- network = new WirelessNetwork(this._device);
- network.connectObject(
- 'notify::icon-name', () => this._syncNetworksList(),
- 'notify::is-active', () => this._syncNetworksList(),
- this);
- const item = this._createNetworkItem(network);
- this._itemBox.add_child(item);
- this._networkItems.set(network, item);
- }
-
- network.addAccessPoint(ap);
- }
-
- _removeAccessPoint(ap) {
- const network = [...this._networkItems.keys()]
- .find(n => n.removeAccessPoint(ap));
-
- if (!network || network.hasAccessPoints())
- return;
-
- this._networkItems.get(network)?.destroy();
- this._networkItems.delete(network);
- network.destroy();
- }
-
- _syncNetworksList() {
- const {hasWindows} = Main.sessionMode;
- const sortedItems = [...this._networkItems.values()]
- .sort((one, two) => one.network.compare(two.network));
-
- for (const [index, item] of sortedItems.entries())
- this._itemBox.set_child_at_index(item, index);
-
- for (const [net, item] of this._networkItems) {
- item.visible =
- hasWindows || net.hasConnections() || net.canAutoconnect();
- }
- }
-
- _selectNetwork(network) {
- this._networkItems.get(this._selectedNetwork)?.remove_style_pseudo_class('selected');
- this._selectedNetwork = network;
- this._updateSensitivity();
- this._networkItems.get(this._selectedNetwork)?.add_style_pseudo_class('selected');
- }
-
- _createNetworkItem(network) {
- const item = new NMWirelessDialogItem(network);
- item.connect('selected', () => {
- Util.ensureActorVisibleInScrollView(this._scrollView, item);
- this._selectNetwork(network);
- });
- item.connect('destroy', () => {
- let keyFocus = global.stage.key_focus;
- if (keyFocus && keyFocus.contains(item))
- this._itemBox.grab_key_focus();
- });
- return item;
- }
});
const NMWirelessDeviceItem = GObject.registerClass({
@@ -1347,23 +1012,17 @@ const NMWirelessDeviceItem = GObject.registerClass({
this._device = device;
this._deviceName = '';
- this.useSubmenu = true;
-
- this.section.addAction(_('Select Network'), this._showDialog.bind(this));
- this._toggleItem = new PopupMenu.PopupMenuItem('');
- this._toggleItem.connect('activate', this._toggleWifi.bind(this));
- this.section.addMenuItem(this._toggleItem);
+ this._networkItems = new Map();
+ this._itemSorter = new ItemSorter({
+ sortFunc: (one, two) => one.network.compare(two.network),
+ });
this.section.addSettingsAction(_('Wi-Fi Settings'),
'gnome-wifi-panel.desktop');
this._client.connectObject(
- 'notify::wireless-enabled', () => {
- this.notify('icon-name');
- this._sync();
- },
- 'notify::wireless-hardware-enabled', this._sync.bind(this),
+ 'notify::wireless-enabled', () => this.notify('icon-name'),
'notify::connectivity', () => this.notify('icon-name'),
'notify::primary-connection', () => this.notify('icon-name'),
this);
@@ -1371,16 +1030,28 @@ const NMWirelessDeviceItem = GObject.registerClass({
this._device.connectObject(
'notify::active-access-point', this._activeApChanged.bind(this),
'notify::active-connection', () => this._activeConnectionChanged(),
- 'state-changed', this._deviceStateChanged.bind(this), this);
+ 'state-changed', this._deviceStateChanged.bind(this),
+ 'notify::available-connections', () => this._availableConnectionsChanged(),
+ 'access-point-added', (d, ap) => {
+ this._addAccessPoint(ap);
+ this._updateItemsVisibility();
+ },
+ 'access-point-removed', (d, ap) => {
+ this._removeAccessPoint(ap);
+ this._updateItemsVisibility();
+ }, this);
- this.connect('destroy', () => {
- this._dialog?.destroy();
- this._dialog = null;
- });
+ Main.sessionMode.connectObject('updated',
+ () => this._updateItemsVisibility(),
+ this);
+
+ for (const ap of this._device.get_access_points())
+ this._addAccessPoint(ap);
this._activeApChanged();
this._activeConnectionChanged();
- this._sync();
+ this._availableConnectionsChanged();
+ this._updateItemsVisibility();
}
get category() {
@@ -1445,20 +1116,6 @@ const NMWirelessDeviceItem = GObject.registerClass({
this._sync();
}
- _toggleWifi() {
- this._client.wireless_enabled = !this._client.wireless_enabled;
- }
-
- _showDialog() {
- this._dialog = new NMWirelessDialog(this._client, this._device);
- this._dialog.connect('closed', this._dialogClosed.bind(this));
- this._dialog.open();
- }
-
- _dialogClosed() {
- this._dialog = null;
- }
-
_activeApChanged() {
this._activeAccessPoint?.disconnectObject(this);
this._activeAccessPoint = this._device.active_access_point;
@@ -1475,9 +1132,79 @@ const NMWirelessDeviceItem = GObject.registerClass({
this._setActiveConnection(this._device.active_connection);
}
- _sync() {
- this._toggleItem.label.text = this._client.wireless_enabled ? _("Turn Off") : _("Turn On");
- this._toggleItem.visible = this._client.wireless_hardware_enabled;
+ _availableConnectionsChanged() {
+ const connections = this._device.get_available_connections();
+ for (const net of this._networkItems.keys())
+ net.checkConnections(connections);
+ }
+
+ _addAccessPoint(ap) {
+ if (ap.get_ssid() == null) {
+ // This access point is not visible yet
+ // Wait for it to get a ssid
+ ap.connectObject('notify::ssid', () => {
+ if (!ap.ssid)
+ return;
+ ap.disconnectObject(this);
+ this._addAccessPoint(ap);
+ }, this);
+ return;
+ }
+
+ let network = [...this._networkItems.keys()]
+ .find(n => n.checkAccessPoint(ap));
+
+ if (!network) {
+ network = new WirelessNetwork(this._device);
+
+ const item = new NMWirelessNetworkItem(network);
+ item.connect('activate', () => network.activate());
+
+ network.connectObject(
+ 'notify::icon-name', () => this._resortItem(item),
+ 'notify::is-active', () => this._resortItem(item),
+ this);
+
+ const pos = this._itemSorter.upsert(item);
+ this.section.addMenuItem(item, pos);
+ this._networkItems.set(network, item);
+ }
+
+ network.addAccessPoint(ap);
+ }
+
+ _removeAccessPoint(ap) {
+ const network = [...this._networkItems.keys()]
+ .find(n => n.removeAccessPoint(ap));
+
+ if (!network || network.hasAccessPoints())
+ return;
+
+ const item = this._networkItems.get(network);
+ this._itemSorter.delete(item);
+ this._networkItems.delete(network);
+
+ item?.destroy();
+ network.destroy();
+ }
+
+ _resortItem(item) {
+ const pos = this._itemSorter.upsert(item);
+ this.section.moveMenuItem(item, pos);
+
+ this._updateItemsVisibility();
+ }
+
+ _updateItemsVisibility() {
+ const {hasWindows} = Main.sessionMode;
+
+ let nVisible = 0;
+ for (const item of this._itemSorter) {
+ const {network: net} = item;
+ item.visible =
+ (hasWindows || net.hasConnections() || net.canAutoconnect()) &&
+ nVisible++ < MAX_VISIBLE_NETWORKS;
+ }
}
setDeviceName(name) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]