[gnome-shell] extensionSystem: Implement new live enable/disable system
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] extensionSystem: Implement new live enable/disable system
- Date: Wed, 24 Aug 2011 17:59:13 +0000 (UTC)
commit 2d813cbdd8d29c9f73403ddeacf057dac3a8f25d
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Wed Jun 22 21:56:24 2011 -0400
extensionSystem: Implement new live enable/disable system
The rough sketches of the system are outlined here:
http://mail.gnome.org/archives/gnome-shell-list/2011-June/msg00283.html
Additionally, enable/disable extensions when the 'enabled-extensions' setting
changes. Two new DBus methods, "EnableExtension" and "DisableExtension" allow
users to manipulate this setting quite easily.
https://bugzilla.gnome.org/show_bug.cgi?id=654770
js/ui/extensionSystem.js | 111 ++++++++++++++++++++++++++++++++----
js/ui/shellDBus.js | 22 +++++++
src/gnome-shell-extension-tool.in | 22 +++++---
3 files changed, 134 insertions(+), 21 deletions(-)
---
diff --git a/js/ui/extensionSystem.js b/js/ui/extensionSystem.js
index c4723a0..6bd6b91 100644
--- a/js/ui/extensionSystem.js
+++ b/js/ui/extensionSystem.js
@@ -14,7 +14,11 @@ const ExtensionState = {
ENABLED: 1,
DISABLED: 2,
ERROR: 3,
- OUT_OF_DATE: 4
+ OUT_OF_DATE: 4,
+
+ // Used as an error state for operations on unknown extensions,
+ // should never be in a real extensionMeta object.
+ UNINSTALLED: 99
};
const ExtensionType = {
@@ -26,6 +30,8 @@ const ExtensionType = {
const extensionMeta = {};
// Maps uuid -> importer object (extension directory tree)
const extensions = {};
+// Maps uuid -> extension state object (returned from init())
+const extensionStateObjs = {};
// Arrays of uuids
var enabledExtensions;
// GFile for user extensions
@@ -75,6 +81,46 @@ function versionCheck(required, current) {
return false;
}
+function disableExtension(uuid) {
+ let meta = extensionMeta[uuid];
+ if (!meta)
+ return;
+
+ if (meta.state != ExtensionState.ENABLED)
+ return;
+
+ let extensionState = extensionStateObjs[uuid];
+
+ try {
+ extensionState.disable();
+ } catch(e) {
+ logExtensionError(uuid, e.toString());
+ return;
+ }
+
+ meta.state = ExtensionState.DISABLED;
+}
+
+function enableExtension(uuid) {
+ let meta = extensionMeta[uuid];
+ if (!meta)
+ return;
+
+ if (meta.state != ExtensionState.DISABLED)
+ return;
+
+ let extensionState = extensionStateObjs[uuid];
+
+ try {
+ extensionState.enable();
+ } catch(e) {
+ logExtensionError(uuid, e.toString());
+ return;
+ }
+
+ meta.state = ExtensionState.ENABLED;
+}
+
function logExtensionError(uuid, message) {
if (!errors[uuid]) errors[uuid] = [];
errors[uuid].push(message);
@@ -136,16 +182,12 @@ function loadExtension(dir, enabled, type) {
return;
}
- extensionMeta[meta.uuid] = meta;
- extensionMeta[meta.uuid].type = type;
- extensionMeta[meta.uuid].path = dir.get_path();
- if (!enabled) {
- extensionMeta[meta.uuid].state = ExtensionState.DISABLED;
- return;
- }
+ extensionMeta[uuid] = meta;
+ meta.type = type;
+ meta.path = dir.get_path();
// Default to error, we set success as the last step
- extensionMeta[meta.uuid].state = ExtensionState.ERROR;
+ meta.state = ExtensionState.ERROR;
let extensionJs = dir.get_child('extension.js');
if (!extensionJs.query_exists(null)) {
@@ -166,6 +208,7 @@ function loadExtension(dir, enabled, type) {
}
let extensionModule;
+ let extensionState = null;
try {
global.add_extension_importer('imports.ui.extensionSystem.extensions', meta.uuid, dir.get_path());
extensionModule = extensions[meta.uuid].extension;
@@ -175,24 +218,65 @@ function loadExtension(dir, enabled, type) {
logExtensionError(uuid, e);
return;
}
- if (!extensionModule.main) {
- logExtensionError(uuid, 'missing \'main\' function');
+
+ if (!extensionModule.init) {
+ logExtensionError(uuid, 'missing \'init\' function');
return;
}
+
try {
- extensionModule.main(meta);
+ extensionState = extensionModule.init(meta);
} catch (e) {
if (stylesheetPath != null)
theme.unload_stylesheet(stylesheetPath);
logExtensionError(uuid, 'Failed to evaluate init function:' + e);
return;
}
- extensionMeta[meta.uuid].state = ExtensionState.ENABLED;
+
+ if (!extensionState)
+ extensionState = extensionModule;
+ extensionStateObjs[uuid] = extensionState;
+
+ if (!extensionState.enable) {
+ logExtensionError(uuid, 'missing \'enable\' function');
+ return;
+ }
+ if (!extensionState.disable) {
+ logExtensionError(uuid, 'missing \'disable\' function');
+ return;
+ }
+
+ meta.state = ExtensionState.DISABLED;
+
+ if (enabled)
+ enableExtension(uuid);
_signals.emit('extension-loaded', meta.uuid);
global.log('Loaded extension ' + meta.uuid);
}
+function onEnabledExtensionsChanged() {
+ let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
+
+ // Find and enable all the newly enabled extensions: UUIDs found in the
+ // new setting, but not in the old one.
+ newEnabledExtensions.filter(function(uuid) {
+ return enabledExtensions.indexOf(uuid) == -1;
+ }).forEach(function(uuid) {
+ enableExtension(uuid);
+ });
+
+ // Find and disable all the newly disabled extensions: UUIDs found in the
+ // old setting, but not in the new one.
+ enabledExtensions.filter(function(item) {
+ return newEnabledExtensions.indexOf(item) == -1;
+ }).forEach(function(uuid) {
+ disableExtension(uuid);
+ });
+
+ enabledExtensions = newEnabledExtensions;
+}
+
function init() {
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
@@ -202,6 +286,7 @@ function init() {
global.logError('' + e);
}
+ global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
}
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 03adae9..ae679ad 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -35,6 +35,14 @@ const GnomeShellIface = {
{ name: 'Screenshot',
inSignature: 's',
outSignature: 'b'
+ },
+ { name: 'EnableExtension',
+ inSignature: 's',
+ outSignature: ''
+ },
+ { name: 'DisableExtension',
+ inSignature: 's',
+ outSignature: ''
}
],
signals: [],
@@ -144,6 +152,20 @@ GnomeShell.prototype = {
return ExtensionSystem.errors[uuid] || [];
},
+ EnableExtension: function(uuid) {
+ let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
+ if (enabledExtensions.indexOf(uuid) == -1)
+ enabledExtensions.push(uuid);
+ global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
+ },
+
+ DisableExtension: function(uuid) {
+ let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
+ while (enabledExtensions.indexOf(uuid) != -1)
+ enabledExtensions.splice(enabledExtensions.indexOf(uuid), 1);
+ global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
+ },
+
get OverviewActive() {
return Main.overview.visible;
},
diff --git a/src/gnome-shell-extension-tool.in b/src/gnome-shell-extension-tool.in
index 4693573..e610b46 100644
--- a/src/gnome-shell-extension-tool.in
+++ b/src/gnome-shell-extension-tool.in
@@ -33,7 +33,7 @@ const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
-let text;
+let text, button;
function _hideHello() {
Main.uiGroup.remove_actor(text);
@@ -60,22 +60,28 @@ function _showHello() {
onComplete: _hideHello });
}
-function main() {
- let button = new St.Bin({ style_class: 'panel-button',
- reactive: true,
- can_focus: true,
- x_fill: true,
- y_fill: false,
- track_hover: true });
+function init() {
+ button = new St.Bin({ style_class: 'panel-button',
+ reactive: true,
+ can_focus: true,
+ x_fill: true,
+ y_fill: false,
+ track_hover: true });
let icon = new St.Icon({ icon_name: 'system-run',
icon_type: St.IconType.SYMBOLIC,
style_class: 'system-status-icon' });
button.set_child(icon);
button.connect('button-press-event', _showHello);
+}
+function enable() {
Main.panel._rightBox.insert_actor(button, 0);
}
+
+function disable() {
+ Main.panel._rightBox.remove_actor(button);
+}
""",
"stylesheet.css": """
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]