mirror of
https://github.com/edu4rdshl/gnome-shell.git
synced 2026-07-18 07:34:54 +00:00
panel: Make quick settings configurable in session mode
Right now the gnome-initial-setup mode has quick settings that aren't that useful (like "Power Mode" and "Dark Style"). It also has some that are useful (like "Wi-Fi"). Ths commit allows gnome-initial-setup to decide which settings to show by adjusting its session mode configuration. This will also give us the flexibility later to evaluate and change which quick settings are shown in the lock screen, as well. The changes are 4-fold: 1. Updating the session mode configuration to include a new quickSettings property which contains the list of quick settings to load for the given mode. For backward compatibility, by default, this property is null which means "load the default set of quick settings". 2. A new QuickSettingsManager class that's akin to ComponentManager but for quick settings instead of components. It handles importing the status modules that provide system indicators and quick setting menu items. 3. Changing the QuickSettings panel menu button to use the QuickSettingsManager instead of importing the status modules itself. 4. Changing the modules that provide quick settings that are supposed to span multiple columns in the grid to announce that requirement by setting a new "expand" propery on the modules indicator quick settings items array.
This commit is contained in:
parent
c9827cdaa6
commit
030d2e1182
7 changed files with 192 additions and 109 deletions
158
js/ui/panel.js
158
js/ui/panel.js
|
|
@ -11,32 +11,15 @@ import St from 'gi://St';
|
|||
|
||||
import * as Animation from './animation.js';
|
||||
import {AppMenu} from './appMenu.js';
|
||||
import * as Config from '../misc/config.js';
|
||||
import * as CtrlAltTab from './ctrlAltTab.js';
|
||||
import * as DND from './dnd.js';
|
||||
import * as Overview from './overview.js';
|
||||
import * as PopupMenu from './popupMenu.js';
|
||||
import * as PanelMenu from './panelMenu.js';
|
||||
import {QuickSettingsMenu} from './quickSettings.js';
|
||||
import {QuickSettingsManager, QuickSettingsMenu} from './quickSettings.js';
|
||||
import * as Main from './main.js';
|
||||
import * as Util from '../misc/util.js';
|
||||
|
||||
import * as RemoteAccessStatus from './status/remoteAccess.js';
|
||||
import * as PowerProfileStatus from './status/powerProfiles.js';
|
||||
import * as RFKillStatus from './status/rfkill.js';
|
||||
import * as CameraStatus from './status/camera.js';
|
||||
import * as VolumeStatus from './status/volume.js';
|
||||
import * as BrightnessStatus from './status/brightness.js';
|
||||
import * as SystemStatus from './status/system.js';
|
||||
import * as LocationStatus from './status/location.js';
|
||||
import * as NightLightStatus from './status/nightLight.js';
|
||||
import * as DarkModeStatus from './status/darkMode.js';
|
||||
import * as UnsafeModeStatus from './status/unsafeMode.js';
|
||||
import * as BacklightStatus from './status/backlight.js';
|
||||
import * as ThunderboltStatus from './status/thunderbolt.js';
|
||||
import * as AutoRotateStatus from './status/autoRotate.js';
|
||||
import * as BackgroundAppsStatus from './status/backgroundApps.js';
|
||||
|
||||
import {DateMenuButton} from './dateMenu.js';
|
||||
import {ATIndicator} from './status/accessibility.js';
|
||||
import {InputSourceIndicator} from './status/keyboard.js';
|
||||
|
|
@ -489,11 +472,20 @@ class ActivitiesButton extends PanelMenu.Button {
|
|||
}
|
||||
});
|
||||
|
||||
const QuickSettingsOrderings = {
|
||||
privacy: ['remoteAccess', 'camera', 'volume.InputIndicator', 'location'],
|
||||
internal: ['brightness', 'thunderbolt', 'nightLight', 'network', 'darkMode', 'backlight', 'powerProfiles', 'bluetooth', 'rfkill', 'autoRotate', 'volume.OutputIndicator', 'unsafeMode', 'system'],
|
||||
menu: ['system', 'volume.OutputIndicator', 'volume.InputIndicator', 'brightness', 'camera', 'remoteAccess', 'thunderbolt', 'network', 'bluetooth', 'powerProfiles', 'nightLight', 'darkMode', 'backlight', 'rfkill', 'autoRotate', 'unsafeMode'],
|
||||
menuEnd: ['backgroundApps'],
|
||||
};
|
||||
|
||||
const QuickSettings = GObject.registerClass(
|
||||
class QuickSettings extends PanelMenu.Button {
|
||||
constructor() {
|
||||
super(0.0, C_('System menu in the top bar', 'System'), true);
|
||||
|
||||
this._quickSettingsManager = new QuickSettingsManager();
|
||||
|
||||
this._indicators = new St.BoxLayout({
|
||||
style_class: 'panel-status-indicators-box',
|
||||
});
|
||||
|
|
@ -501,100 +493,50 @@ class QuickSettings extends PanelMenu.Button {
|
|||
|
||||
this.setMenu(new QuickSettingsMenu(this, N_QUICK_SETTINGS_COLUMNS));
|
||||
|
||||
this._setupIndicators().catch(error =>
|
||||
logError(error, 'Failed to setup quick settings'));
|
||||
this._quickSettingsManager.connect('disable-indicators', this._disableIndicators.bind(this));
|
||||
this._quickSettingsManager.connect('enable-indicators', this._enableIndicators.bind(this));
|
||||
}
|
||||
|
||||
async _setupIndicators() {
|
||||
if (Config.HAVE_NETWORKMANAGER) {
|
||||
/** @type {import('./status/network.js')} */
|
||||
const NetworkStatus = await import('./status/network.js');
|
||||
_disableIndicators(manager, indicatorsToDisable) {
|
||||
indicatorsToDisable.forEach(indicator => {
|
||||
this.menu.removeItems(indicator.quickSettingsItems);
|
||||
this._indicators.remove_child(indicator);
|
||||
});
|
||||
}
|
||||
|
||||
this._network = new NetworkStatus.Indicator();
|
||||
} else {
|
||||
this._network = null;
|
||||
_insertIndicatorAndItems(indicator, indicatorOrdering, menuOrdering, colSpan = 1) {
|
||||
if (indicatorOrdering.includes(indicator.name)) {
|
||||
const nextIndicator = this._quickSettingsManager.findIndicatorAfter(indicator, indicatorOrdering, laterIndicator => {
|
||||
return this._indicators.get_children().includes(laterIndicator);
|
||||
});
|
||||
|
||||
if (nextIndicator)
|
||||
this._indicators.insert_child_below(indicator, nextIndicator);
|
||||
else
|
||||
this._indicators.add_child(indicator);
|
||||
}
|
||||
|
||||
if (Config.HAVE_BLUETOOTH) {
|
||||
/** @type {import('./status/bluetooth.js')} */
|
||||
const BluetoothStatus = await import('./status/bluetooth.js');
|
||||
if (menuOrdering.includes(indicator.name)) {
|
||||
let nextQuickSettingsItem = null;
|
||||
this._quickSettingsManager.findIndicatorAfter(indicator, menuOrdering, laterIndicator => {
|
||||
nextQuickSettingsItem = laterIndicator.quickSettingsItems.find(item => this.menu.hasItem(item));
|
||||
return !!nextQuickSettingsItem;
|
||||
});
|
||||
if (!nextQuickSettingsItem)
|
||||
nextQuickSettingsItem = this.menu.getFirstItem();
|
||||
|
||||
this._bluetooth = new BluetoothStatus.Indicator();
|
||||
} else {
|
||||
this._bluetooth = null;
|
||||
this._addItemsBefore(indicator.quickSettingsItems, nextQuickSettingsItem, colSpan);
|
||||
}
|
||||
}
|
||||
|
||||
this._system = new SystemStatus.Indicator();
|
||||
this._camera = new CameraStatus.Indicator();
|
||||
this._volumeOutput = new VolumeStatus.OutputIndicator();
|
||||
this._volumeInput = new VolumeStatus.InputIndicator();
|
||||
this._brightness = new BrightnessStatus.Indicator();
|
||||
this._remoteAccess = new RemoteAccessStatus.RemoteAccessApplet();
|
||||
this._location = new LocationStatus.Indicator();
|
||||
this._thunderbolt = new ThunderboltStatus.Indicator();
|
||||
this._nightLight = new NightLightStatus.Indicator();
|
||||
this._darkMode = new DarkModeStatus.Indicator();
|
||||
this._backlight = new BacklightStatus.Indicator();
|
||||
this._powerProfiles = new PowerProfileStatus.Indicator();
|
||||
this._rfkill = new RFKillStatus.Indicator();
|
||||
this._autoRotate = new AutoRotateStatus.Indicator();
|
||||
this._unsafeMode = new UnsafeModeStatus.Indicator();
|
||||
this._backgroundApps = new BackgroundAppsStatus.Indicator();
|
||||
_enableIndicators(manager, indicatorsToEnable) {
|
||||
const indicatorOrdering = [...QuickSettingsOrderings['privacy'], ...QuickSettingsOrderings['internal']];
|
||||
const menuOrdering = [...QuickSettingsOrderings['menu'], ...QuickSettingsOrderings['menuEnd']];
|
||||
|
||||
// add privacy-related indicators before any external indicators
|
||||
let pos = 0;
|
||||
this._indicators.insert_child_at_index(this._remoteAccess, pos++);
|
||||
this._indicators.insert_child_at_index(this._camera, pos++);
|
||||
this._indicators.insert_child_at_index(this._volumeInput, pos++);
|
||||
this._indicators.insert_child_at_index(this._location, pos++);
|
||||
|
||||
// append all other indicators
|
||||
this._indicators.add_child(this._brightness);
|
||||
this._indicators.add_child(this._thunderbolt);
|
||||
this._indicators.add_child(this._nightLight);
|
||||
if (this._network)
|
||||
this._indicators.add_child(this._network);
|
||||
this._indicators.add_child(this._darkMode);
|
||||
this._indicators.add_child(this._backlight);
|
||||
this._indicators.add_child(this._powerProfiles);
|
||||
if (this._bluetooth)
|
||||
this._indicators.add_child(this._bluetooth);
|
||||
this._indicators.add_child(this._rfkill);
|
||||
this._indicators.add_child(this._autoRotate);
|
||||
this._indicators.add_child(this._volumeOutput);
|
||||
this._indicators.add_child(this._unsafeMode);
|
||||
this._indicators.add_child(this._system);
|
||||
|
||||
// add our quick settings items before any external ones
|
||||
const sibling = this.menu.getFirstItem();
|
||||
this._addItemsBefore(this._system.quickSettingsItems,
|
||||
sibling, N_QUICK_SETTINGS_COLUMNS);
|
||||
this._addItemsBefore(this._volumeOutput.quickSettingsItems,
|
||||
sibling, N_QUICK_SETTINGS_COLUMNS);
|
||||
this._addItemsBefore(this._volumeInput.quickSettingsItems,
|
||||
sibling, N_QUICK_SETTINGS_COLUMNS);
|
||||
this._addItemsBefore(this._brightness.quickSettingsItems,
|
||||
sibling, N_QUICK_SETTINGS_COLUMNS);
|
||||
|
||||
this._addItemsBefore(this._camera.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._remoteAccess.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._thunderbolt.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._location.quickSettingsItems, sibling);
|
||||
if (this._network)
|
||||
this._addItemsBefore(this._network.quickSettingsItems, sibling);
|
||||
if (this._bluetooth)
|
||||
this._addItemsBefore(this._bluetooth.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._powerProfiles.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._nightLight.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._darkMode.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._backlight.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._rfkill.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._autoRotate.quickSettingsItems, sibling);
|
||||
this._addItemsBefore(this._unsafeMode.quickSettingsItems, sibling);
|
||||
|
||||
// append background apps
|
||||
this._backgroundApps.quickSettingsItems.forEach(
|
||||
item => this.menu.addItem(item, N_QUICK_SETTINGS_COLUMNS));
|
||||
indicatorsToEnable.forEach(indicator => {
|
||||
const colSpan = indicator.quickSettingsItems.expand ? N_QUICK_SETTINGS_COLUMNS : 1;
|
||||
this._insertIndicatorAndItems(indicator, indicatorOrdering, menuOrdering, colSpan);
|
||||
});
|
||||
}
|
||||
|
||||
_addItemsBefore(items, sibling, colSpan = 1) {
|
||||
|
|
@ -609,13 +551,11 @@ class QuickSettings extends PanelMenu.Button {
|
|||
* @param {number=} colSpan
|
||||
*/
|
||||
addExternalIndicator(indicator, colSpan = 1) {
|
||||
// Insert before first non-privacy indicator if it exists
|
||||
let sibling = this._brightness ?? null;
|
||||
this._indicators.insert_child_below(indicator, sibling);
|
||||
// Note indicator.name may legitimately be undefined
|
||||
const indicatorOrdering = [...QuickSettingsOrderings['privacy'], indicator.name, ...QuickSettingsOrderings['internal']];
|
||||
const menuOrdering = [...QuickSettingsOrderings['menu'], indicator.name, ...QuickSettingsOrderings['menuEnd']];
|
||||
|
||||
// Insert before background apps if it exists
|
||||
sibling = this._backgroundApps?.quickSettingsItems?.at(-1) ?? null;
|
||||
this._addItemsBefore(indicator.quickSettingsItems, sibling, colSpan);
|
||||
this._insertIndicatorAndItems(indicator, indicatorOrdering, menuOrdering, colSpan);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,115 @@ import St from 'gi://St';
|
|||
|
||||
import * as Main from './main.js';
|
||||
import * as PopupMenu from './popupMenu.js';
|
||||
import * as SessionMode from './sessionMode.js';
|
||||
import * as Signals from '../misc/signals.js';
|
||||
import {Slider} from './slider.js';
|
||||
import * as Util from '../misc/util.js';
|
||||
|
||||
import {PopupAnimation} from './boxpointer.js';
|
||||
|
||||
|
||||
const DIM_BRIGHTNESS = -0.4;
|
||||
const POPUP_ANIMATION_TIME = 400;
|
||||
const MENU_BUTTON_BRIGHTNESS = 0.1;
|
||||
|
||||
export class QuickSettingsManager extends Signals.EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.indicators = {};
|
||||
|
||||
Main.sessionMode.connect('updated', this._syncQuickSettings.bind(this));
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, this._syncQuickSettings.bind(this));
|
||||
}
|
||||
|
||||
findIndicatorAfter(indicator, ordering, callback) {
|
||||
const index = ordering.indexOf(indicator.name);
|
||||
|
||||
if (index === -1)
|
||||
return null;
|
||||
|
||||
const nextIndicatorName = ordering.slice(index + 1)
|
||||
.filter(name => this.indicators[name])
|
||||
.find(name => callback(this.indicators[name]));
|
||||
|
||||
if (!nextIndicatorName)
|
||||
return null;
|
||||
|
||||
return this.indicators[nextIndicatorName];
|
||||
}
|
||||
|
||||
_syncQuickSettings() {
|
||||
this._updateQuickSettings().catch(logError);
|
||||
}
|
||||
|
||||
async _updateQuickSettings() {
|
||||
const enabledIndicatorNames = Object.keys(this.indicators);
|
||||
const quickSettings = Main.sessionMode.quickSettings || SessionMode.DEFAULT_QUICK_SETTINGS;
|
||||
const quickSettingsToEnable = quickSettings.filter(name => !enabledIndicatorNames.includes(name));
|
||||
await Promise.allSettled(quickSettingsToEnable
|
||||
.map(name => this._ensureIndicator(name)));
|
||||
|
||||
const disabledQuickSettings = enabledIndicatorNames
|
||||
.filter(name => !quickSettingsToEnable.includes(name));
|
||||
|
||||
const disabledIndicators = disabledQuickSettings
|
||||
.map(name => this.indicators[name])
|
||||
.filter(indicator => indicator);
|
||||
|
||||
if (disabledIndicators.length > 0)
|
||||
this.emit('disable-indicators', disabledIndicators);
|
||||
|
||||
disabledQuickSettings.forEach(name => {
|
||||
delete this.indicators[name];
|
||||
});
|
||||
|
||||
const enabledIndicators = quickSettingsToEnable
|
||||
.map(name => this.indicators[name])
|
||||
.filter(indicator => indicator);
|
||||
|
||||
if (enabledIndicators.length > 0)
|
||||
this.emit('enable-indicators', enabledIndicators);
|
||||
}
|
||||
|
||||
async _importQuickSetting(name) {
|
||||
let moduleName = name;
|
||||
let className = null;
|
||||
|
||||
if (name.includes('.'))
|
||||
[moduleName, className] = name.split('.', 2);
|
||||
|
||||
const module = await import(`./status/${moduleName}.js`);
|
||||
|
||||
if (className) {
|
||||
if (Util.classExtends(module[className], SystemIndicator))
|
||||
return module[className];
|
||||
return null;
|
||||
}
|
||||
|
||||
const indicatorClassName = Object.keys(module).find(exportedName => {
|
||||
return Util.classExtends(module[exportedName], SystemIndicator);
|
||||
});
|
||||
|
||||
if (!indicatorClassName)
|
||||
return null;
|
||||
|
||||
return module[indicatorClassName];
|
||||
}
|
||||
|
||||
async _ensureIndicator(name) {
|
||||
let indicator = this.indicators[name];
|
||||
if (indicator)
|
||||
return indicator;
|
||||
|
||||
const constructor = await this._importQuickSetting(name);
|
||||
indicator = new constructor();
|
||||
this.indicators[name] = indicator;
|
||||
indicator.name = name;
|
||||
|
||||
return indicator;
|
||||
}
|
||||
}
|
||||
|
||||
export const QuickSettingsItem = GObject.registerClass({
|
||||
Properties: {
|
||||
'has-menu': GObject.ParamSpec.boolean(
|
||||
|
|
@ -788,6 +889,14 @@ export const QuickSettingsMenu = class extends PopupMenu.PopupMenu {
|
|||
this._completeAddItem(item, colSpan);
|
||||
}
|
||||
|
||||
removeItems(items) {
|
||||
items.forEach(item => this._grid.remove_child(item));
|
||||
}
|
||||
|
||||
hasItem(item) {
|
||||
return this._grid.get_children().includes(item);
|
||||
}
|
||||
|
||||
_completeAddItem(item, colSpan) {
|
||||
this._grid.layout_manager.child_set_property(
|
||||
this._grid, item, 'column-span', colSpan);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,31 @@ const USER_SESSION_COMPONENTS = [
|
|||
if (Config.HAVE_NETWORKMANAGER)
|
||||
USER_SESSION_COMPONENTS.push('networkAgent');
|
||||
|
||||
export const DEFAULT_QUICK_SETTINGS = [
|
||||
'autoRotate',
|
||||
'backgroundApps',
|
||||
'backlight',
|
||||
'brightness',
|
||||
'camera',
|
||||
'darkMode',
|
||||
'location',
|
||||
'nightLight',
|
||||
'powerProfiles',
|
||||
'remoteAccess',
|
||||
'rfkill',
|
||||
'system',
|
||||
'thunderbolt',
|
||||
'unsafeMode',
|
||||
'volume.InputIndicator',
|
||||
'volume.OutputIndicator',
|
||||
];
|
||||
|
||||
if (Config.HAVE_NETWORKMANAGER)
|
||||
DEFAULT_QUICK_SETTINGS.push('network');
|
||||
|
||||
if (Config.HAVE_BLUETOOTH)
|
||||
DEFAULT_QUICK_SETTINGS.push('bluetooth');
|
||||
|
||||
const _modes = {
|
||||
'restrictive': {
|
||||
parentMode: null,
|
||||
|
|
@ -49,6 +74,7 @@ const _modes = {
|
|||
right: [],
|
||||
},
|
||||
panelStyle: null,
|
||||
quickSettings: [],
|
||||
},
|
||||
|
||||
'gdm': {
|
||||
|
|
@ -65,6 +91,7 @@ const _modes = {
|
|||
right: ['dwellClick', 'a11y', 'keyboard', 'quickSettings'],
|
||||
},
|
||||
panelStyle: 'login-screen',
|
||||
quickSettings: null,
|
||||
},
|
||||
|
||||
'unlock-dialog': {
|
||||
|
|
@ -77,6 +104,7 @@ const _modes = {
|
|||
right: ['dwellClick', 'a11y', 'keyboard', 'quickSettings'],
|
||||
},
|
||||
panelStyle: 'unlock-screen',
|
||||
quickSettings: null,
|
||||
},
|
||||
|
||||
'user': {
|
||||
|
|
@ -99,6 +127,7 @@ const _modes = {
|
|||
center: ['dateMenu'],
|
||||
right: ['screenRecording', 'screenSharing', 'dwellClick', 'a11y', 'keyboard', 'quickSettings'],
|
||||
},
|
||||
quickSettings: null,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -265,5 +265,6 @@ class Indicator extends SystemIndicator {
|
|||
super._init();
|
||||
|
||||
this.quickSettingsItems.push(new BackgroundAppsToggle());
|
||||
this.quickSettingsItems.expand = true;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -60,5 +60,6 @@ class Indicator extends SystemIndicator {
|
|||
super._init();
|
||||
|
||||
this.quickSettingsItems.push(new BrightnessItem());
|
||||
this.quickSettingsItems.expand = true;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ class Indicator extends SystemIndicator {
|
|||
this);
|
||||
|
||||
this.quickSettingsItems.push(this._systemItem);
|
||||
this.quickSettingsItems.expand = true;
|
||||
|
||||
this._sync();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -453,6 +453,7 @@ class OutputIndicator extends VolumeIndicator {
|
|||
});
|
||||
|
||||
this.quickSettingsItems.push(this._output);
|
||||
this.quickSettingsItems.expand = true;
|
||||
|
||||
this._onControlStateChanged();
|
||||
}
|
||||
|
|
@ -498,6 +499,7 @@ class InputIndicator extends VolumeIndicator {
|
|||
GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
this.quickSettingsItems.push(this._input);
|
||||
this.quickSettingsItems.expand = true;
|
||||
|
||||
this._onControlStateChanged();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue