[gnome-shell/wip/rstrode/login-screen-extensions: 45/134] extensionPrefs: Switch to D-Bus API to get extension live state




commit 15adec4be3b37f527819fa975f326c30767f7f7c
Author: Didier Roche <didrocks ubuntu com>
Date:   Thu Nov 1 13:55:17 2018 +0100

    extensionPrefs: Switch to D-Bus API to get extension live state
    
    By direclty using the underlying GSetting, whether or not an extension
    appears as enabled or disabled currently depends only on whether it is
    included in the 'enabled-extensions' list or not.
    
    However this doesn't necessarily reflect the real extension state, as an
    extension may be in error state, or enabled via the session mode.
    
    Switch to the extensions D-Bus API to ensure that the list of extensions
    and each extension's state correctly reflects the state in gnome-shell.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=789852

 js/extensionPrefs/main.js | 166 ++++++++++++++++++++++++++++++----------------
 1 file changed, 110 insertions(+), 56 deletions(-)
---
diff --git a/js/extensionPrefs/main.js b/js/extensionPrefs/main.js
index 29de8202a5..f1b732e85c 100644
--- a/js/extensionPrefs/main.js
+++ b/js/extensionPrefs/main.js
@@ -8,6 +8,8 @@ const Config = imports.misc.config;
 const ExtensionUtils = imports.misc.extensionUtils;
 const { loadInterfaceXML } = imports.misc.fileUtils;
 
+const { ExtensionState } = ExtensionUtils;
+
 const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
 const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
 
@@ -32,6 +34,11 @@ var Application = GObject.registerClass({
         this._startupUuid = null;
         this._loaded = false;
         this._skipMainWindow = false;
+        this._shellProxy = null;
+    }
+
+    get shellProxy() {
+        return this._shellProxy;
     }
 
     _showPrefs(uuid) {
@@ -218,10 +225,8 @@ var Application = GObject.registerClass({
         this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder');
 
         this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
-        this._shellProxy.connectSignal('ExtensionStateChanged', (proxy, senderName, [uuid, state]) => {
-            if (ExtensionUtils.extensions[uuid] !== undefined)
-                this._scanExtensions();
-        });
+        this._shellProxy.connectSignal('ExtensionStateChanged',
+            this._onExtensionStateChanged.bind(this));
 
         this._window.show_all();
     }
@@ -238,14 +243,51 @@ var Application = GObject.registerClass({
         row.set_header(sep);
     }
 
+    _findExtensionRow(uuid) {
+        return this._extensionSelector.get_children().find(c => c.uuid === uuid);
+    }
+
+    _onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
+        let row = this._findExtensionRow(uuid);
+        if (row) {
+            let { state } = ExtensionUtils.deserializeExtension(newState);
+            if (state == ExtensionState.UNINSTALLED)
+                row.destroy();
+            return; // we only deal with new and deleted extensions here
+        }
+
+        this._shellProxy.GetExtensionInfoRemote(uuid, ([serialized]) => {
+            let extension = ExtensionUtils.deserializeExtension(serialized);
+            if (!extension)
+                return;
+            // check the extension wasn't added in between
+            if (this._findExtensionRow(uuid) != null)
+                return;
+            this._addExtensionRow(extension);
+        });
+    }
+
     _scanExtensions() {
-        let finder = new ExtensionUtils.ExtensionFinder();
-        finder.connect('extension-found', this._extensionFound.bind(this));
-        finder.scanExtensions();
-        this._extensionsLoaded();
+        this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => {
+            if (e) {
+                if (e instanceof Gio.DBusError) {
+                    log(`Failed to connect to shell proxy: ${e}`);
+                    this._mainStack.add_named(new NoShellPlaceholder(), 'noshell');
+                    this._mainStack.visible_child_name = 'noshell';
+                } else
+                    throw e;
+                return;
+            }
+
+            for (let uuid in extensionsMap) {
+                let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]);
+                this._addExtensionRow(extension);
+            }
+            this._extensionsLoaded();
+        });
     }
 
-    _extensionFound(finder, extension) {
+    _addExtensionRow(extension) {
         let row = new ExtensionRow(extension);
 
         row.prefsButton.connect('clicked', () => {
@@ -466,6 +508,35 @@ class EmptyPlaceholder extends Gtk.Box {
     }
 });
 
+var NoShellPlaceholder = GObject.registerClass(
+class NoShellPlaceholder extends Gtk.Box {
+    _init() {
+        super._init({
+            orientation: Gtk.Orientation.VERTICAL,
+            spacing: 12,
+            margin: 100,
+            margin_bottom: 60
+        });
+
+        let label = new Gtk.Label({
+            label: '<span size="x-large">%s</span>'.format(
+                _("Something’s gone wrong")),
+            use_markup: true
+        });
+        label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
+        this.add(label);
+
+        label = new Gtk.Label({
+            label: _("We’re very sorry, but it was not possible to get the list of installed extensions. 
Make sure you are logged into GNOME and try again."),
+            justify: Gtk.Justification.CENTER,
+            wrap: true
+        });
+        this.add(label);
+
+        this.show_all();
+    }
+});
+
 var DescriptionLabel = GObject.registerClass(
 class DescriptionLabel extends Gtk.Label {
     vfunc_get_preferred_height_for_width(width) {
@@ -481,22 +552,23 @@ class ExtensionRow extends Gtk.ListBoxRow {
     _init(extension) {
         super._init();
 
+        this._app = Gio.Application.get_default();
         this._extension = extension;
         this._prefsModule = null;
 
-        this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
-        this._settings.connect('changed::enabled-extensions', () => {
-            this._switch.state = this._isEnabled();
-        });
-        this._settings.connect('changed::disable-extension-version-validation',
-            () => {
-                this._switch.sensitive = this._canEnable();
-            });
-        this._settings.connect('changed::disable-user-extensions',
-            () => {
-                this._switch.sensitive = this._canEnable();
+        this._extensionStateChangedId = this._app.shellProxy.connectSignal(
+            'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
+                if (this.uuid !== uuid)
+                    return;
+
+                this._extension = ExtensionUtils.deserializeExtension(newState);
+                let state = (this._extension.state == ExtensionState.ENABLED);
+                this._switch.state = state;
+                this._switch.sensitive = this._canToggle();
             });
 
+        this.connect('destroy', this._onDestroy.bind(this));
+
         this._buildUI();
     }
 
@@ -516,6 +588,15 @@ class ExtensionRow extends Gtk.ListBoxRow {
         return this._extension.metadata.url;
     }
 
+    _onDestroy() {
+        if (!this._app.shellProxy)
+            return;
+
+        if (this._extensionStateChangedId)
+            this._app.shellProxy.disconnectSignal(this._extensionStateChangedId);
+        this._extensionStateChangedId = 0;
+    }
+
     _buildUI() {
         let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
                                  hexpand: true, margin_end: 24, spacing: 24,
@@ -549,50 +630,23 @@ class ExtensionRow extends Gtk.ListBoxRow {
 
         this.prefsButton = button;
 
-        this._switch = new Gtk.Switch({ valign: Gtk.Align.CENTER,
-                                        sensitive: this._canEnable(),
-                                        state: this._isEnabled() });
+        this._switch = new Gtk.Switch({
+            valign: Gtk.Align.CENTER,
+            sensitive: this._canToggle(),
+            state: this._extension.state === ExtensionState.ENABLED
+        });
         this._switch.connect('notify::active', () => {
             if (this._switch.active)
-                this._enable();
+                this._app.shellProxy.EnableExtensionRemote(this.uuid);
             else
-                this._disable();
+                this._app.shellProxy.DisableExtensionRemote(this.uuid);
         });
         this._switch.connect('state-set', () => true);
         hbox.add(this._switch);
     }
 
-    _canEnable() {
-        let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
-
-        return !this._settings.get_boolean('disable-user-extensions') &&
-               !(checkVersion && ExtensionUtils.isOutOfDate(this._extension));
-    }
-
-    _isEnabled() {
-        let extensions = this._settings.get_strv('enabled-extensions');
-        return extensions.indexOf(this.uuid) != -1;
-    }
-
-    _enable() {
-        let extensions = this._settings.get_strv('enabled-extensions');
-        if (extensions.indexOf(this.uuid) != -1)
-            return;
-
-        extensions.push(this.uuid);
-        this._settings.set_strv('enabled-extensions', extensions);
-    }
-
-    _disable() {
-        let extensions = this._settings.get_strv('enabled-extensions');
-        let pos = extensions.indexOf(this.uuid);
-        if (pos == -1)
-            return;
-        do {
-            extensions.splice(pos, 1);
-            pos = extensions.indexOf(this.uuid);
-        } while (pos != -1);
-        this._settings.set_strv('enabled-extensions', extensions);
+    _canToggle() {
+        return this._extension.canChange;
     }
 
     get prefsModule() {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]