import gnome-shell-3.32.2-40.el8

This commit is contained in:
CentOS Sources 2021-09-03 04:19:47 +00:00 committed by Andrew Lukoshko
parent d29e4b3ec0
commit 07cadf247c
6 changed files with 871 additions and 772 deletions

View File

@ -0,0 +1,87 @@
From 1b6eb29ade832647510b36ddc13c9b88a25036df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Wed, 11 Sep 2019 20:18:20 +0200
Subject: [PATCH 1/4] extensionSystem: Handle added or removed sessionMode
extensions
Right now we're only handling added sessionMode extensions correctly on
sessionMode updates, also handle the other case and disable removed
sessionMode extensions on sessionMode updates.
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/96
---
js/ui/extensionSystem.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 81804ea5e..77929f2a6 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -515,62 +515,62 @@ var ExtensionManager = class {
if (!this._initted) {
this._loadExtensions();
this._initted = true;
} else {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid);
});
}
this._enabled = true;
}
_disableAllExtensions() {
if (!this._enabled)
return;
if (this._initted) {
this._extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
}
this._enabled = false;
}
_sessionUpdated() {
// For now sessionMode.allowExtensions controls extensions from both the
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
// property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
- if (this._initted)
- this._enabledExtensions = this._getEnabledExtensions();
+ // Take care of added or removed sessionMode extensions
+ this._onEnabledExtensionsChanged();
this._enableAllExtensions();
} else {
this._disableAllExtensions();
}
}
};
Signals.addSignalMethods(ExtensionManager.prototype);
class ExtensionUpdateSource extends MessageTray.Source {
constructor() {
const appSys = Shell.AppSystem.get_default();
this._app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
super(this._app.get_name());
}
getIcon() {
return this._app.app_info.get_icon();
}
_createPolicy() {
return new MessageTray.NotificationApplicationPolicy(this._app.id);
}
open() {
this._app.activate();
Main.overview.hide();
Main.panel.closeCalendar();
}
}
--
2.27.0

View File

@ -0,0 +1,237 @@
From b70cf463e08bff43b242b851fc7c79244f54e76b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 13:25:57 -0400
Subject: [PATCH 2/4] extensionSystem: Get rid of _enabled boolean optimization
At the moment a session mode either allows extensions or it doesn't.
If it allows extensions, then the entire available list of
configured extensions get enabled as soon as the session mode is
entered.
Since enabling or disabling extensions is an all or nothing situation,
the code tracks whether extensions are already enabled when entering
the session mode, and if so, avoids iterating through the extension list
needlessly. It does this using a boolean named _enabled.
In the future, the extensions themselves will be given some say on
whether or not they should be enabled in a given session mode. This
means, the configured extension list may contain extensions that
shouldn't be enabled for a given session mode, and the _enabled boolean
will no longer be appropriated.
This commit drops the _enabled boolean optimization.
---
js/ui/extensionSystem.js | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 77929f2a6..05630ed54 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -1,53 +1,52 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { GLib, Gio, GObject, St } = imports.gi;
const Signals = imports.signals;
const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const { ExtensionState, ExtensionType } = ExtensionUtils;
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
const UPDATE_CHECK_TIMEOUT = 24 * 60 * 60; // 1 day in seconds
var ExtensionManager = class {
constructor() {
this._initted = false;
- this._enabled = false;
this._updateNotified = false;
this._extensions = new Map();
this._enabledExtensions = [];
this._extensionOrder = [];
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
}
init() {
this._installExtensionUpdates();
this._sessionUpdated();
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
ExtensionDownloader.checkForUpdates();
return GLib.SOURCE_CONTINUE;
});
ExtensionDownloader.checkForUpdates();
}
lookup(uuid) {
return this._extensions.get(uuid);
}
getUuids() {
return [...this._extensions.keys()];
}
_callExtensionDisable(uuid) {
let extension = this.lookup(uuid);
@@ -375,63 +374,60 @@ var ExtensionManager = class {
let hasError =
extension.state == ExtensionState.ERROR ||
extension.state == ExtensionState.OUT_OF_DATE;
let isMode = this._getModeExtensions().includes(extension.uuid);
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
extension.canChange =
!hasError &&
global.settings.is_writable(ENABLED_EXTENSIONS_KEY) &&
(isMode || !modeOnly);
}
_getEnabledExtensions() {
let extensions = this._getModeExtensions();
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
return extensions;
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
}
_onUserExtensionsEnabledChanged() {
this._onEnabledExtensionsChanged();
this._onSettingsWritableChanged();
}
_onEnabledExtensionsChanged() {
let newEnabledExtensions = this._getEnabledExtensions();
- if (!this._enabled)
- return;
-
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions.filter(
uuid => !this._enabledExtensions.includes(uuid)
).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one.
this._enabledExtensions.filter(
item => !newEnabledExtensions.includes(item)
).forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions;
}
_onSettingsWritableChanged() {
for (let extension of this._extensions.values()) {
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
}
_onVersionValidationChanged() {
// we want to reload all extensions, but only enable
// extensions when allowed by the sessionMode, so
// temporarily disable them all
@@ -482,85 +478,76 @@ var ExtensionManager = class {
this._enabledExtensions = this._getEnabledExtensions();
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let existing = this.lookup(uuid);
if (existing) {
log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`);
return;
}
let extension;
let type = dir.has_prefix(perUserDir)
? ExtensionType.PER_USER
: ExtensionType.SYSTEM;
try {
extension = this.createExtensionObject(uuid, dir, type);
} catch (e) {
logError(e, `Could not load extension ${uuid}`);
return;
}
this.loadExtension(extension);
});
}
_enableAllExtensions() {
- if (this._enabled)
- return;
-
if (!this._initted) {
this._loadExtensions();
this._initted = true;
} else {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid);
});
}
- this._enabled = true;
}
_disableAllExtensions() {
- if (!this._enabled)
- return;
-
if (this._initted) {
this._extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
}
-
- this._enabled = false;
}
_sessionUpdated() {
// For now sessionMode.allowExtensions controls extensions from both the
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
// property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
// Take care of added or removed sessionMode extensions
this._onEnabledExtensionsChanged();
this._enableAllExtensions();
} else {
this._disableAllExtensions();
}
}
};
Signals.addSignalMethods(ExtensionManager.prototype);
class ExtensionUpdateSource extends MessageTray.Source {
constructor() {
const appSys = Shell.AppSystem.get_default();
this._app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
super(this._app.get_name());
}
getIcon() {
return this._app.app_info.get_icon();
}
--
2.27.0

View File

@ -0,0 +1,393 @@
From 7300ae2eac743fa06f40f6459ac8fbf739ab28ea Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 15:03:50 -0400
Subject: [PATCH 3/4] extensionSystem: Allow extensions to run on the login
screen
At the moment it's not realy possible to extend the login screen to do
things it doesn't have built-in support for. This means in order
to support niche use cases, those cases have to change the main
code base. For instance, oVirt and Vmware deployments want to be able
to automaticaly log in guest VMs when a user pre-authenticates through a
console on a management host. To support those use cases, we added
code to the login screen directly, even though most machines will never
be associated with oVirt or Vmware management hosts.
We also get requests from e.g. government users that need certain features
at the login screen that wouldn't get used much outside of government
deployments. For instance, we've gotten requests that a machine contains
prominently displays that it has "Top Secret" information.
All of these use cases seem like they would better handled via
extensions that could be installed in the specific deployments. The
problem is extensions only run in the user session, and get
disabled at the login screen automatically.
This commit changes that. Now extensions can specify in their metadata
via a new sessionModes property, which modes that want to run in. For
backward compatibility, if an extension doesn't specify which session
modes it works in, its assumed the extension only works in the user
session.
---
js/ui/extensionSystem.js | 43 ++++++++++++++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 4 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 05630ed54..dfe82821e 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -21,119 +21,147 @@ var ExtensionManager = class {
constructor() {
this._initted = false;
this._updateNotified = false;
this._extensions = new Map();
this._enabledExtensions = [];
this._extensionOrder = [];
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
}
init() {
this._installExtensionUpdates();
this._sessionUpdated();
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
ExtensionDownloader.checkForUpdates();
return GLib.SOURCE_CONTINUE;
});
ExtensionDownloader.checkForUpdates();
}
lookup(uuid) {
return this._extensions.get(uuid);
}
getUuids() {
return [...this._extensions.keys()];
}
+ _extensionSupportsSessionMode(uuid) {
+ let extension = this.lookup(uuid);
+
+ if (!extension)
+ return false;
+
+ if (extension.sessionModes.includes(Main.sessionMode.currentMode))
+ return true;
+
+ if (extension.sessionModes.includes(Main.sessionMode.parentMode))
+ return true;
+
+ return false;
+ }
+
+ _sessionModeCanUseExtension(uuid) {
+ if (!Main.sessionMode.allowExtensions)
+ return false;
+
+ if (!this._extensionSupportsSessionMode(uuid))
+ return false;
+
+ return true;
+ }
+
_callExtensionDisable(uuid) {
let extension = this.lookup(uuid);
if (!extension)
return;
if (extension.state != ExtensionState.ENABLED)
return;
// "Rebase" the extension order by disabling and then enabling extensions
// in order to help prevent conflicts.
// Example:
// order = [A, B, C, D, E]
// user disables C
// this should: disable E, disable D, disable C, enable D, enable E
let orderIdx = this._extensionOrder.indexOf(uuid);
let order = this._extensionOrder.slice(orderIdx + 1);
let orderReversed = order.slice().reverse();
for (let i = 0; i < orderReversed.length; i++) {
let uuid = orderReversed[i];
try {
this.lookup(uuid).stateObj.disable();
} catch (e) {
this.logExtensionError(uuid, e);
}
}
if (extension.stylesheet) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet;
}
try {
extension.stateObj.disable();
} catch(e) {
this.logExtensionError(uuid, e);
}
for (let i = 0; i < order.length; i++) {
let uuid = order[i];
try {
this.lookup(uuid).stateObj.enable();
} catch (e) {
this.logExtensionError(uuid, e);
}
}
this._extensionOrder.splice(orderIdx, 1);
if (extension.state != ExtensionState.ERROR) {
extension.state = ExtensionState.DISABLED;
this.emit('extension-state-changed', extension);
}
}
_callExtensionEnable(uuid) {
+ if (!this._sessionModeCanUseExtension(uuid))
+ return;
+
let extension = this.lookup(uuid);
if (!extension)
return;
if (extension.state == ExtensionState.INITIALIZED)
this._callExtensionInit(uuid);
if (extension.state != ExtensionState.DISABLED)
return;
this._extensionOrder.push(uuid);
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
for (let i = 0; i < stylesheetNames.length; i++) {
try {
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
theme.load_stylesheet(stylesheetFile);
extension.stylesheet = stylesheetFile;
break;
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
continue; // not an error
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
return;
}
}
try {
extension.stateObj.enable();
@@ -231,61 +259,62 @@ var ExtensionManager = class {
throw new Error(`Failed to load metadata.json: ${e}`);
}
let meta;
try {
meta = JSON.parse(metadataContents);
} catch (e) {
throw new Error(`Failed to parse metadata.json: ${e}`);
}
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
for (let i = 0; i < requiredProperties.length; i++) {
let prop = requiredProperties[i];
if (!meta[prop]) {
throw new Error(`missing "${prop}" property in metadata.json`);
}
}
if (uuid != meta.uuid) {
throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`);
}
let extension = {
metadata: meta,
uuid: meta.uuid,
type,
dir,
path: dir.get_path(),
error: '',
hasPrefs: dir.get_child('prefs.js').query_exists(null),
hasUpdate: false,
- canChange: false
+ canChange: false,
+ sessionModes: meta['session-modes'] ? meta['session-modes'] : [ 'user' ],
};
this._extensions.set(uuid, extension);
return extension;
}
loadExtension(extension) {
// Default to error, we set success as the last step
extension.state = ExtensionState.ERROR;
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE;
} else {
let enabled = this._enabledExtensions.includes(extension.uuid);
if (enabled) {
if (!this._callExtensionInit(extension.uuid))
return;
if (extension.state == ExtensionState.DISABLED)
this._callExtensionEnable(extension.uuid);
} else {
extension.state = ExtensionState.INITIALIZED;
}
}
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
@@ -296,60 +325,63 @@ var ExtensionManager = class {
this._callExtensionDisable(extension.uuid);
extension.state = ExtensionState.UNINSTALLED;
this.emit('extension-state-changed', extension);
this._extensions.delete(extension.uuid);
return true;
}
reloadExtension(oldExtension) {
// Grab the things we'll need to pass to createExtensionObject
// to reload it.
let { uuid: uuid, dir: dir, type: type } = oldExtension;
// Then unload the old extension.
this.unloadExtension(oldExtension);
// Now, recreate the extension and load it.
let newExtension;
try {
newExtension = this.createExtensionObject(uuid, dir, type);
} catch (e) {
this.logExtensionError(uuid, e);
return;
}
this.loadExtension(newExtension);
}
_callExtensionInit(uuid) {
+ if (!this._sessionModeCanUseExtension(uuid))
+ return false;
+
let extension = this.lookup(uuid);
let dir = extension.dir;
if (!extension)
throw new Error("Extension was not properly created. Call loadExtension first");
let extensionJs = dir.get_child('extension.js');
if (!extensionJs.query_exists(null)) {
this.logExtensionError(uuid, new Error('Missing extension.js'));
return false;
}
let extensionModule;
let extensionState = null;
ExtensionUtils.installImporter(extension);
try {
extensionModule = extension.imports.extension;
} catch(e) {
this.logExtensionError(uuid, e);
return false;
}
if (extensionModule.init) {
try {
extensionState = extensionModule.init(extension);
} catch (e) {
this.logExtensionError(uuid, e);
return false;
}
@@ -377,69 +409,72 @@ var ExtensionManager = class {
let isMode = this._getModeExtensions().includes(extension.uuid);
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
extension.canChange =
!hasError &&
global.settings.is_writable(ENABLED_EXTENSIONS_KEY) &&
(isMode || !modeOnly);
}
_getEnabledExtensions() {
let extensions = this._getModeExtensions();
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
return extensions;
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
}
_onUserExtensionsEnabledChanged() {
this._onEnabledExtensionsChanged();
this._onSettingsWritableChanged();
}
_onEnabledExtensionsChanged() {
let newEnabledExtensions = this._getEnabledExtensions();
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions.filter(
- uuid => !this._enabledExtensions.includes(uuid)
+ uuid => !this._enabledExtensions.includes(uuid) &&
+ this._extensionSupportsSessionMode(uuid)
).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the
- // old setting, but not in the new one.
+ // old setting, but not in the new one, and extensions that don't work with
+ // the current session mode.
this._enabledExtensions.filter(
- item => !newEnabledExtensions.includes(item)
+ item => !newEnabledExtensions.includes(item) ||
+ !this._extensionSupportsSessionMode(item)
).forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions;
}
_onSettingsWritableChanged() {
for (let extension of this._extensions.values()) {
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
}
_onVersionValidationChanged() {
// we want to reload all extensions, but only enable
// extensions when allowed by the sessionMode, so
// temporarily disable them all
this._enabledExtensions = [];
// The loop modifies the extensions map, so iterate over a copy
let extensions = [...this._extensions.values()];
for (let extension of extensions)
this.reloadExtension(extension);
this._enabledExtensions = this._getEnabledExtensions();
if (Main.sessionMode.allowExtensions) {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid);
});
--
2.27.0

View File

@ -0,0 +1,116 @@
From 5fad989ca773f9e0ff6fdbeb0cb7c9cb70cc6148 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 15:31:00 -0400
Subject: [PATCH 4/4] sessionMode: Allow extensions at the login and unlock
screens
Now extensions can specify which session modes they work in,
but specifying the login screen or unlock screen session modes in
an extensions metadata still won't work, because those session
modes disallow extensions.
This commit fixes that.
---
js/ui/sessionMode.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index fa7f83416..8d8ce1a64 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -12,89 +12,92 @@ const Config = imports.misc.config;
const DEFAULT_MODE = 'restrictive';
const _modes = {
'restrictive': {
parentMode: null,
stylesheetName: 'gnome-shell.css',
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
allowScreencast: false,
enabledExtensions: [],
hasRunDialog: false,
hasWorkspaces: false,
hasWindows: false,
hasNotifications: false,
isLocked: false,
isGreeter: false,
isPrimary: false,
unlockDialog: null,
components: [],
panel: {
left: [],
center: [],
right: []
},
panelStyle: null
},
'gdm': {
+ allowExtensions: true,
hasNotifications: true,
isGreeter: true,
isPrimary: true,
unlockDialog: imports.gdm.loginDialog.LoginDialog,
components: Config.HAVE_NETWORKMANAGER
? ['networkAgent', 'polkitAgent']
: ['polkitAgent'],
panel: {
left: [],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'aggregateMenu']
},
panelStyle: 'login-screen'
},
'lock-screen': {
+ allowExtensions: true,
isLocked: true,
isGreeter: undefined,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
center: [],
right: ['aggregateMenu']
},
panelStyle: 'lock-screen'
},
'unlock-dialog': {
+ allowExtensions: true,
isLocked: true,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
center: [],
right: ['a11y', 'keyboard', 'aggregateMenu']
},
panelStyle: 'unlock-screen'
},
'user': {
hasOverview: true,
showCalendarEvents: true,
allowSettings: true,
allowExtensions: true,
allowScreencast: true,
hasRunDialog: true,
hasWorkspaces: true,
hasWindows: true,
hasNotifications: true,
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: Config.HAVE_NETWORKMANAGER ?
['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'] :
['polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'],
--
2.27.0

View File

@ -1,7 +1,7 @@
From ab3a275e20c36cc21e529bb2c4328ea36024ecba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sat, 6 Jul 2019 15:31:57 +0200
Subject: [PATCH 01/29] extensionUtils: Move ExtensionState definition here
Subject: [PATCH 01/26] extensionUtils: Move ExtensionState definition here
It makes sense to keep extension-related enums in the same module instead
of spreading them between ExtensionSystem and ExtensionUtils.
@ -108,7 +108,7 @@ index 958211df0..fefb3f731 100644
From c16d1589d093dac4e0efe21c7f1aeb635afabd0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 7 Mar 2019 01:45:45 +0100
Subject: [PATCH 02/29] extensionSystem: Turn into a class
Subject: [PATCH 02/26] extensionSystem: Turn into a class
The extension system started out as a set of simple functions, but
gained more state later, and even some hacks to emit signals without
@ -932,7 +932,7 @@ index 112d60feb..4b04e68ac 100644
From 7419ee28b5b568dd4478db7f3c890ff01678637a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 8 Jul 2019 02:53:32 +0200
Subject: [PATCH 03/29] extensionSystem: Make methods to call extension
Subject: [PATCH 03/26] extensionSystem: Make methods to call extension
functions private
While public methods to enable/disable extensions make sense for an
@ -1083,7 +1083,7 @@ index b7e908223..c5fb007ae 100644
From e88419278531b136984f9f05a8c056145d03edba Mon Sep 17 00:00:00 2001
From: Didier Roche <didrocks@ubuntu.com>
Date: Wed, 17 Jan 2018 13:43:11 +0100
Subject: [PATCH 04/29] extensionSystem: Add methods to enable/disable
Subject: [PATCH 04/26] extensionSystem: Add methods to enable/disable
extensions
Extensions are currently enabled or disabled by directly changing the
@ -1238,7 +1238,7 @@ index 4b04e68ac..0ded84874 100644
From 2787cff52570d1343f46e4f6ea96aa338a769182 Mon Sep 17 00:00:00 2001
From: Didier Roche <didrocks@ubuntu.com>
Date: Thu, 1 Nov 2018 13:55:17 +0100
Subject: [PATCH 05/29] extensionUtils: Add functions to (de)serialize
Subject: [PATCH 05/26] extensionUtils: Add functions to (de)serialize
extensions
Serializing an extension for sending over D-Bus is currently done by the
@ -1397,7 +1397,7 @@ index 0ded84874..af5889789 100644
From 779025379a32f0c6457cc9518bd1f4eff1330239 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 8 Jul 2019 12:21:10 +0200
Subject: [PATCH 06/29] shellDBus: Add new 'ExtensionStateChanged' signal
Subject: [PATCH 06/26] shellDBus: Add new 'ExtensionStateChanged' signal
The existing 'ExtensionStatusChanged' signal has a fixed set of parameters,
which means we cannot add additional state without an API break. Deprecate
@ -1489,7 +1489,7 @@ index af5889789..23274c0a3 100644
From 47d185f8964f9e04430f4ef97d6d712faaf32078 Mon Sep 17 00:00:00 2001
From: Didier Roche <didrocks@ubuntu.com>
Date: Tue, 4 Dec 2018 09:31:27 +0100
Subject: [PATCH 07/29] extensionSystem: Add canChange property to extensions
Subject: [PATCH 07/26] extensionSystem: Add canChange property to extensions
Whether or not an extension can be enabled/disabled depends on various
factors: Whether the extension is in error state, whether user extensions
@ -1618,7 +1618,7 @@ index 98eaf5259..a83e53c83 100644
From ce14c00ca0707c78dc920ede3a157b7c9d55fff5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Tue, 28 May 2019 23:22:37 +0200
Subject: [PATCH 08/29] extensionPrefs: Inherit from Gtk.Application
Subject: [PATCH 08/26] extensionPrefs: Inherit from Gtk.Application
Extension preferences Application class is just a container for a GtkApplication
so instead of using composition we can inherit from the base GObject class.
@ -1727,7 +1727,7 @@ index 2b4ce5753..94a5b12fe 100644
From ea202d21b65c027db03e773a51bd8fecf4a2fb0a Mon Sep 17 00:00:00 2001
From: Didier Roche <didrocks@ubuntu.com>
Date: Thu, 1 Nov 2018 13:50:30 +0100
Subject: [PATCH 09/29] extensionPrefs: Attach extension object to each row
Subject: [PATCH 09/26] extensionPrefs: Attach extension object to each row
Each row represents an extension, so it makes sense to associate the
rows with the actual extensions instead of linking rows and extensions
@ -1990,7 +1990,7 @@ index 94a5b12fe..7e7b2dcc7 100644
From 8d80e6667ded38dac53fe245a10191b5d4a3150b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sat, 6 Jul 2019 01:48:05 +0200
Subject: [PATCH 10/29] extensionPrefs: Override getCurrentExtension() for
Subject: [PATCH 10/26] extensionPrefs: Override getCurrentExtension() for
extensions
Extensions are used to calling the getCurrentExtension() utility function,
@ -2028,7 +2028,7 @@ index 7e7b2dcc7..29de8202a 100644
From e03a21b1f768405050bbfda1eb2bbf2ffcf7b4ca Mon Sep 17 00:00:00 2001
From: Didier Roche <didrocks@ubuntu.com>
Date: Thu, 1 Nov 2018 13:55:17 +0100
Subject: [PATCH 11/29] extensionPrefs: Switch to D-Bus API to get extension
Subject: [PATCH 11/26] extensionPrefs: Switch to D-Bus API to get extension
live state
By direclty using the underlying GSetting, whether or not an extension
@ -2295,7 +2295,7 @@ index 29de8202a..f1b732e85 100644
From 9baf77dcae765618902d958549801276156f1255 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sun, 7 Jul 2019 23:38:27 +0200
Subject: [PATCH 12/29] extensionSystem: Move extension loading into
Subject: [PATCH 12/26] extensionSystem: Move extension loading into
ExtensionManager
Now that extension loading and the extensions map are no longer shared
@ -2812,7 +2812,7 @@ index 23274c0a3..dc3a61df6 100644
From 776b82542aa705ea527dfbdd1a6d3fb1588092e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 8 Jul 2019 00:01:11 +0200
Subject: [PATCH 13/29] extensionSystem: Store extensions in a Map
Subject: [PATCH 13/26] extensionSystem: Store extensions in a Map
After making the extensions map private to the ExtensionManager, we can
switch it to a proper hash table which is more appropriate.
@ -3088,7 +3088,7 @@ index dc3a61df6..be9b10491 100644
From 2cc95ba7c93c04bae0006b7d018928600d9cbb13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 22 Jan 2020 14:45:15 +0100
Subject: [PATCH 14/29] extensionSystem: Add hasUpdate state
Subject: [PATCH 14/26] extensionSystem: Add hasUpdate state
The current support for extension updates is half-baked at best.
We are about to change that, and implement offline updates similar
@ -3159,7 +3159,7 @@ index cd3e78301..93faf48d4 100644
From 07330eaac64fc115851ec9d5a0969bd046599e12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 22 Jan 2020 15:07:45 +0100
Subject: [PATCH 15/29] extensionDownloader: Make checkForUpdates() check for
Subject: [PATCH 15/26] extensionDownloader: Make checkForUpdates() check for
updates
Currently the method installs updates instead of merely checking for
@ -3262,7 +3262,7 @@ index 77d013ffb..66cb13d56 100644
From 49eaf28202787f0802663aa609ee9f87eb548b03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 22 Jan 2020 15:42:06 +0100
Subject: [PATCH 16/29] extensionDownloader: Only check updates for user
Subject: [PATCH 16/26] extensionDownloader: Only check updates for user
extensions
System extensions cannot be updated through the website, so don't
@ -3296,7 +3296,7 @@ index 66cb13d56..c8f6735c5 100644
From 67d709de14b083a013b3b1160e5cc451cf96bfde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 27 Jan 2020 01:13:49 +0100
Subject: [PATCH 17/29] extensionDownloader: Exclude extensions with pending
Subject: [PATCH 17/26] extensionDownloader: Exclude extensions with pending
updates from check
While it is possible that an extension has a newer version available
@ -3332,7 +3332,7 @@ index c8f6735c5..ede276c37 100644
From 2fa19162c71787fbb9aa9af1d35e0e9cab11c1d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 22 Jan 2020 16:53:32 +0100
Subject: [PATCH 18/29] extensionDownloader: Include version validation in
Subject: [PATCH 18/26] extensionDownloader: Include version validation in
update check
The extensions website will consider the setting to find the best suitable
@ -3370,7 +3370,7 @@ index ede276c37..f957c6c62 100644
From ccb0095b1981233ca980d44c260c0d36eef910bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 22 Jan 2020 15:09:05 +0100
Subject: [PATCH 19/29] extensionSystem: Install pending updates on startup
Subject: [PATCH 19/26] extensionSystem: Install pending updates on startup
Now that we have a way to check for updates and download them, we
should actually apply them as well. Do this on startup before any
@ -3431,7 +3431,7 @@ index 93faf48d4..36a248dc1 100644
From e377b16ffb667be40a850ff03e092f2f9dfe8fe8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 24 Jan 2020 18:09:34 +0100
Subject: [PATCH 20/29] extensionPrefs: Add application icon
Subject: [PATCH 20/26] extensionPrefs: Add application icon
We are about to make the tool a user-visible application, so we
need an icon. Add one (plus its symbolic variant).
@ -3520,7 +3520,7 @@ index 0acaba705..2dd1bbc7a 100644
From 6b3fa1549f9682f54f55cdd963a242cd279ff17c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Sun, 26 Jan 2020 23:47:24 +0100
Subject: [PATCH 21/29] extensionSystem: Show notification when updates are
Subject: [PATCH 21/26] extensionSystem: Show notification when updates are
available
Now that the extensions app has the ability to handle updates, we
@ -3610,7 +3610,7 @@ index 36a248dc1..805e08cae 100644
From f6a5e2731f487d7a0ac088aff53ca1e76006c118 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 27 Jan 2020 00:59:19 +0100
Subject: [PATCH 22/29] extensionSystem: Periodically check for extension
Subject: [PATCH 22/26] extensionSystem: Periodically check for extension
updates
Now that we can download, apply and display extension updates, it is time
@ -3663,7 +3663,7 @@ index 805e08cae..914abb309 100644
From cb3ed33a72fea3ae6b8df031abca48b99dba75a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 9 Mar 2020 16:49:34 +0100
Subject: [PATCH 23/29] extensionDownloader: Remove pending updates with
Subject: [PATCH 23/26] extensionDownloader: Remove pending updates with
extension
When an extension is uninstalled, there is no point in keeping
@ -3702,7 +3702,7 @@ index f957c6c62..0bd77e125 100644
From 6abb5a189a7c97de8c0ed28c40f34fb625363223 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 9 Mar 2020 16:45:22 +0100
Subject: [PATCH 24/29] extensionSystem: Catch errors when updating extensions
Subject: [PATCH 24/26] extensionSystem: Catch errors when updating extensions
Extension updates are installed at startup, so any errors that bubble
up uncaught will prevent the startup to complete.
@ -3745,7 +3745,7 @@ index 914abb309..320af54e4 100644
From 405897a9930362dad590eb8bd425c130dc636083 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 26 Jan 2021 17:12:04 +0100
Subject: [PATCH 25/29] extensionSystem: Fix opening Extensions app from
Subject: [PATCH 25/26] extensionSystem: Fix opening Extensions app from
notification
Launching the app is implemented by the source's open() method, but
@ -3775,7 +3775,7 @@ index 320af54e4..81804ea5e 100644
From 8d50b96701eefa7f9bff4af8c855087eee35739a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 1 Feb 2021 18:26:00 +0100
Subject: [PATCH 26/29] extensionDownloader: Refuse to override system
Subject: [PATCH 26/26] extensionDownloader: Refuse to override system
extensions
The website allows to "update" system extensions by installing the
@ -3808,748 +3808,3 @@ index 0bd77e125..1e6f5340a 100644
--
2.29.2
From 116c96c5a20baff845adf87142ec2feb294524b5 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 13:25:57 -0400
Subject: [PATCH 27/29] extensionSystem: Get rid of _enabled boolean optimization
At the moment a session mode either allows extensions or it doesn't.
If it allows extensions, then the entire available list of
configured extensions get enabled as soon as the session mode is
entered.
Since enabling or disabling extensions is an all or nothing situation,
the code tracks whether extensions are already enabled when entering
the session mode, and if so, avoids iterating through the extension list
needlessly. It does this using a boolean named _enabled.
In the future, the extensions themselves will be given some say on
whether or not they should be enabled in a given session mode. This
means, the configured extension list may contain extensions that
shouldn't be enabled for a given session mode, and the _enabled boolean
will no longer be appropriated.
This commit drops the _enabled boolean optimization.
---
js/ui/extensionSystem.js | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index 81804ea5e..e282a834a 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -1,53 +1,52 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { GLib, Gio, GObject, St } = imports.gi;
const Signals = imports.signals;
const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const { ExtensionState, ExtensionType } = ExtensionUtils;
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
const UPDATE_CHECK_TIMEOUT = 24 * 60 * 60; // 1 day in seconds
var ExtensionManager = class {
constructor() {
this._initted = false;
- this._enabled = false;
this._updateNotified = false;
this._extensions = new Map();
this._enabledExtensions = [];
this._extensionOrder = [];
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
}
init() {
this._installExtensionUpdates();
this._sessionUpdated();
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
ExtensionDownloader.checkForUpdates();
return GLib.SOURCE_CONTINUE;
});
ExtensionDownloader.checkForUpdates();
}
lookup(uuid) {
return this._extensions.get(uuid);
}
getUuids() {
return [...this._extensions.keys()];
}
_callExtensionDisable(uuid) {
let extension = this.lookup(uuid);
@@ -375,63 +374,60 @@ var ExtensionManager = class {
let hasError =
extension.state == ExtensionState.ERROR ||
extension.state == ExtensionState.OUT_OF_DATE;
let isMode = this._getModeExtensions().includes(extension.uuid);
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
extension.canChange =
!hasError &&
global.settings.is_writable(ENABLED_EXTENSIONS_KEY) &&
(isMode || !modeOnly);
}
_getEnabledExtensions() {
let extensions = this._getModeExtensions();
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
return extensions;
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
}
_onUserExtensionsEnabledChanged() {
this._onEnabledExtensionsChanged();
this._onSettingsWritableChanged();
}
_onEnabledExtensionsChanged() {
let newEnabledExtensions = this._getEnabledExtensions();
- if (!this._enabled)
- return;
-
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions.filter(
uuid => !this._enabledExtensions.includes(uuid)
).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one.
this._enabledExtensions.filter(
item => !newEnabledExtensions.includes(item)
).forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions;
}
_onSettingsWritableChanged() {
for (let extension of this._extensions.values()) {
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
}
_onVersionValidationChanged() {
// we want to reload all extensions, but only enable
// extensions when allowed by the sessionMode, so
// temporarily disable them all
@@ -482,85 +478,76 @@ var ExtensionManager = class {
this._enabledExtensions = this._getEnabledExtensions();
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let existing = this.lookup(uuid);
if (existing) {
log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`);
return;
}
let extension;
let type = dir.has_prefix(perUserDir)
? ExtensionType.PER_USER
: ExtensionType.SYSTEM;
try {
extension = this.createExtensionObject(uuid, dir, type);
} catch (e) {
logError(e, `Could not load extension ${uuid}`);
return;
}
this.loadExtension(extension);
});
}
_enableAllExtensions() {
- if (this._enabled)
- return;
-
if (!this._initted) {
this._loadExtensions();
this._initted = true;
} else {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid);
});
}
- this._enabled = true;
}
_disableAllExtensions() {
- if (!this._enabled)
- return;
-
if (this._initted) {
this._extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
}
-
- this._enabled = false;
}
_sessionUpdated() {
// For now sessionMode.allowExtensions controls extensions from both the
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
// property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
if (this._initted)
this._enabledExtensions = this._getEnabledExtensions();
this._enableAllExtensions();
} else {
this._disableAllExtensions();
}
}
};
Signals.addSignalMethods(ExtensionManager.prototype);
class ExtensionUpdateSource extends MessageTray.Source {
constructor() {
const appSys = Shell.AppSystem.get_default();
this._app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
super(this._app.get_name());
}
getIcon() {
return this._app.app_info.get_icon();
}
--
2.27.0
From 6732b1821f6edd0eb97025d60ecc4530d1f668ff Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 15:03:50 -0400
Subject: [PATCH 28/29] extensionSystem: Allow extensions to run on the login
screen
At the moment it's not realy possible to extend the login screen to do
things it doesn't have built-in support for. This means in order
to support niche use cases, those cases have to change the main
code base. For instance, oVirt and Vmware deployments want to be able
to automaticaly log in guest VMs when a user pre-authenticates through a
console on a management host. To support those use cases, we added
code to the login screen directly, even though most machines will never
be associated with oVirt or Vmware management hosts.
We also get requests from e.g. government users that need certain features
at the login screen that wouldn't get used much outside of government
deployments. For instance, we've gotten requests that a machine contains
prominently displays that it has "Top Secret" information.
All of these use cases seem like they would better handled via
extensions that could be installed in the specific deployments. The
problem is extensions only run in the user session, and get
disabled at the login screen automatically.
This commit changes that. Now extensions can specify in their metadata
via a new sessionModes property, which modes that want to run in. For
backward compatibility, if an extension doesn't specify which session
modes it works in, its assumed the extension only works in the user
session.
---
js/ui/extensionSystem.js | 40 ++++++++++++++++++++++++++++++++++++----
1 file changed, 36 insertions(+), 4 deletions(-)
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index e282a834a..efb231aa1 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -21,119 +21,144 @@ var ExtensionManager = class {
constructor() {
this._initted = false;
this._updateNotified = false;
this._extensions = new Map();
this._enabledExtensions = [];
this._extensionOrder = [];
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
}
init() {
this._installExtensionUpdates();
this._sessionUpdated();
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, UPDATE_CHECK_TIMEOUT, () => {
ExtensionDownloader.checkForUpdates();
return GLib.SOURCE_CONTINUE;
});
ExtensionDownloader.checkForUpdates();
}
lookup(uuid) {
return this._extensions.get(uuid);
}
getUuids() {
return [...this._extensions.keys()];
}
+ _extensionSupportsSessionMode(uuid) {
+ let extension = this.lookup(uuid);
+
+ if (extension.sessionModes.includes(Main.sessionMode.currentMode))
+ return true;
+
+ if (extension.sessionModes.includes(Main.sessionMode.parentMode))
+ return true;
+
+ return false;
+ }
+
+ _sessionModeCanUseExtension(uuid) {
+ if (!Main.sessionMode.allowExtensions)
+ return false;
+
+ if (!this._extensionSupportsSessionMode(uuid))
+ return false;
+
+ return true;
+ }
+
_callExtensionDisable(uuid) {
let extension = this.lookup(uuid);
if (!extension)
return;
if (extension.state != ExtensionState.ENABLED)
return;
// "Rebase" the extension order by disabling and then enabling extensions
// in order to help prevent conflicts.
// Example:
// order = [A, B, C, D, E]
// user disables C
// this should: disable E, disable D, disable C, enable D, enable E
let orderIdx = this._extensionOrder.indexOf(uuid);
let order = this._extensionOrder.slice(orderIdx + 1);
let orderReversed = order.slice().reverse();
for (let i = 0; i < orderReversed.length; i++) {
let uuid = orderReversed[i];
try {
this.lookup(uuid).stateObj.disable();
} catch (e) {
this.logExtensionError(uuid, e);
}
}
if (extension.stylesheet) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet;
}
try {
extension.stateObj.disable();
} catch(e) {
this.logExtensionError(uuid, e);
}
for (let i = 0; i < order.length; i++) {
let uuid = order[i];
try {
this.lookup(uuid).stateObj.enable();
} catch (e) {
this.logExtensionError(uuid, e);
}
}
this._extensionOrder.splice(orderIdx, 1);
if (extension.state != ExtensionState.ERROR) {
extension.state = ExtensionState.DISABLED;
this.emit('extension-state-changed', extension);
}
}
_callExtensionEnable(uuid) {
+ if (!this._sessionModeCanUseExtension(uuid))
+ return;
+
let extension = this.lookup(uuid);
if (!extension)
return;
if (extension.state == ExtensionState.INITIALIZED)
this._callExtensionInit(uuid);
if (extension.state != ExtensionState.DISABLED)
return;
this._extensionOrder.push(uuid);
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
for (let i = 0; i < stylesheetNames.length; i++) {
try {
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
theme.load_stylesheet(stylesheetFile);
extension.stylesheet = stylesheetFile;
break;
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
continue; // not an error
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
return;
}
}
try {
extension.stateObj.enable();
@@ -231,61 +256,62 @@ var ExtensionManager = class {
throw new Error(`Failed to load metadata.json: ${e}`);
}
let meta;
try {
meta = JSON.parse(metadataContents);
} catch (e) {
throw new Error(`Failed to parse metadata.json: ${e}`);
}
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
for (let i = 0; i < requiredProperties.length; i++) {
let prop = requiredProperties[i];
if (!meta[prop]) {
throw new Error(`missing "${prop}" property in metadata.json`);
}
}
if (uuid != meta.uuid) {
throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`);
}
let extension = {
metadata: meta,
uuid: meta.uuid,
type,
dir,
path: dir.get_path(),
error: '',
hasPrefs: dir.get_child('prefs.js').query_exists(null),
hasUpdate: false,
- canChange: false
+ canChange: false,
+ sessionModes: meta['session-modes'] ? meta['session-modes'] : [ 'user' ],
};
this._extensions.set(uuid, extension);
return extension;
}
loadExtension(extension) {
// Default to error, we set success as the last step
extension.state = ExtensionState.ERROR;
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE;
} else {
let enabled = this._enabledExtensions.includes(extension.uuid);
if (enabled) {
if (!this._callExtensionInit(extension.uuid))
return;
if (extension.state == ExtensionState.DISABLED)
this._callExtensionEnable(extension.uuid);
} else {
extension.state = ExtensionState.INITIALIZED;
}
}
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
@@ -296,60 +322,63 @@ var ExtensionManager = class {
this._callExtensionDisable(extension.uuid);
extension.state = ExtensionState.UNINSTALLED;
this.emit('extension-state-changed', extension);
this._extensions.delete(extension.uuid);
return true;
}
reloadExtension(oldExtension) {
// Grab the things we'll need to pass to createExtensionObject
// to reload it.
let { uuid: uuid, dir: dir, type: type } = oldExtension;
// Then unload the old extension.
this.unloadExtension(oldExtension);
// Now, recreate the extension and load it.
let newExtension;
try {
newExtension = this.createExtensionObject(uuid, dir, type);
} catch (e) {
this.logExtensionError(uuid, e);
return;
}
this.loadExtension(newExtension);
}
_callExtensionInit(uuid) {
+ if (!this._sessionModeCanUseExtension(uuid))
+ return false;
+
let extension = this.lookup(uuid);
let dir = extension.dir;
if (!extension)
throw new Error("Extension was not properly created. Call loadExtension first");
let extensionJs = dir.get_child('extension.js');
if (!extensionJs.query_exists(null)) {
this.logExtensionError(uuid, new Error('Missing extension.js'));
return false;
}
let extensionModule;
let extensionState = null;
ExtensionUtils.installImporter(extension);
try {
extensionModule = extension.imports.extension;
} catch(e) {
this.logExtensionError(uuid, e);
return false;
}
if (extensionModule.init) {
try {
extensionState = extensionModule.init(extension);
} catch (e) {
this.logExtensionError(uuid, e);
return false;
}
@@ -377,69 +406,72 @@ var ExtensionManager = class {
let isMode = this._getModeExtensions().includes(extension.uuid);
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
extension.canChange =
!hasError &&
global.settings.is_writable(ENABLED_EXTENSIONS_KEY) &&
(isMode || !modeOnly);
}
_getEnabledExtensions() {
let extensions = this._getModeExtensions();
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
return extensions;
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
}
_onUserExtensionsEnabledChanged() {
this._onEnabledExtensionsChanged();
this._onSettingsWritableChanged();
}
_onEnabledExtensionsChanged() {
let newEnabledExtensions = this._getEnabledExtensions();
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions.filter(
- uuid => !this._enabledExtensions.includes(uuid)
+ uuid => !this._enabledExtensions.includes(uuid) &&
+ this._extensionSupportsSessionMode(uuid)
).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the
- // old setting, but not in the new one.
+ // old setting, but not in the new one, and extensions that don't work with
+ // the current session mode.
this._enabledExtensions.filter(
- item => !newEnabledExtensions.includes(item)
+ item => !newEnabledExtensions.includes(item) ||
+ !this._extensionSupportsSessionMode(uuid)
).forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions;
}
_onSettingsWritableChanged() {
for (let extension of this._extensions.values()) {
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
}
_onVersionValidationChanged() {
// we want to reload all extensions, but only enable
// extensions when allowed by the sessionMode, so
// temporarily disable them all
this._enabledExtensions = [];
// The loop modifies the extensions map, so iterate over a copy
let extensions = [...this._extensions.values()];
for (let extension of extensions)
this.reloadExtension(extension);
this._enabledExtensions = this._getEnabledExtensions();
if (Main.sessionMode.allowExtensions) {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid);
});
--
2.27.0
From d6a3a70ec7a1fefb2ea03ed750570ce49a0fcfd9 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 10 Aug 2021 15:31:00 -0400
Subject: [PATCH 29/29] sessionMode: Allow extensions at the login and unlock
screens
Now extensions can specify which session modes they work in,
but specifying the login screen or unlock screen session modes in
an extensions metadata still won't work, because those session
modes disallow extensions.
This commit fixes that.
---
js/ui/sessionMode.js | 3 +++
1 file changed, 3 insertions(+)
diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js
index fa7f83416..8d8ce1a64 100644
--- a/js/ui/sessionMode.js
+++ b/js/ui/sessionMode.js
@@ -12,89 +12,92 @@ const Config = imports.misc.config;
const DEFAULT_MODE = 'restrictive';
const _modes = {
'restrictive': {
parentMode: null,
stylesheetName: 'gnome-shell.css',
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
allowScreencast: false,
enabledExtensions: [],
hasRunDialog: false,
hasWorkspaces: false,
hasWindows: false,
hasNotifications: false,
isLocked: false,
isGreeter: false,
isPrimary: false,
unlockDialog: null,
components: [],
panel: {
left: [],
center: [],
right: []
},
panelStyle: null
},
'gdm': {
+ allowExtensions: true,
hasNotifications: true,
isGreeter: true,
isPrimary: true,
unlockDialog: imports.gdm.loginDialog.LoginDialog,
components: Config.HAVE_NETWORKMANAGER
? ['networkAgent', 'polkitAgent']
: ['polkitAgent'],
panel: {
left: [],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'aggregateMenu']
},
panelStyle: 'login-screen'
},
'lock-screen': {
+ allowExtensions: true,
isLocked: true,
isGreeter: undefined,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
center: [],
right: ['aggregateMenu']
},
panelStyle: 'lock-screen'
},
'unlock-dialog': {
+ allowExtensions: true,
isLocked: true,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
center: [],
right: ['a11y', 'keyboard', 'aggregateMenu']
},
panelStyle: 'unlock-screen'
},
'user': {
hasOverview: true,
showCalendarEvents: true,
allowSettings: true,
allowExtensions: true,
allowScreencast: true,
hasRunDialog: true,
hasWorkspaces: true,
hasWindows: true,
hasNotifications: true,
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: Config.HAVE_NETWORKMANAGER ?
['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'] :
['polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'],
--
2.27.0

View File

@ -1,6 +1,6 @@
Name: gnome-shell
Version: 3.32.2
Release: 39%{?dist}
Release: 40%{?dist}
Summary: Window management and application launching for GNOME
Group: User Interface/Desktops
@ -88,6 +88,12 @@ Patch10002: 0002-background-rebuild-background-not-just-animation-on-.patch
Patch10003: 0003-st-texture-cache-purge-on-resume.patch
Patch10004: 0004-background-refresh-background-on-gl-video-memory-pur.patch
# Allow login screen extensions (#1651378)
Patch20001: 0001-extensionSystem-Handle-added-or-removed-sessionMode-.patch
Patch20002: 0002-extensionSystem-Get-rid-of-_enabled-boolean-optimiza.patch
Patch20003: 0003-extensionSystem-Allow-extensions-to-run-on-the-login.patch
Patch20004: 0004-sessionMode-Allow-extensions-at-the-login-and-unlock.patch
%define libcroco_version 0.6.8
%define eds_version 3.17.2
%define gnome_desktop_version 3.7.90
@ -265,6 +271,11 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/evolution-calendar.de
%{_mandir}/man1/%{name}.1.gz
%changelog
* Tue Aug 31 2021 Ray Strode <rstrode@redhat.com> - 3.32.2-40
- Add bugs introduced in backport for #1651378
Related: #1999758
- Tidy up patch list a bit
* Wed Aug 25 2021 Ray Strode <rstrode@redhat.com> - 3.32.2-39
- Allow extensions on the login screen
Related: #1651378