[gnome-shell] extensionSystem: Implement new live enable/disable system



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]