[gnome-shell] util: Add AppSettingsMonitor



commit b5130c5943de6d0f415493d39dd32e9d4210e20a
Author: Florian Müllner <fmuellner gnome org>
Date:   Thu Feb 23 22:50:04 2017 +0100

    util: Add AppSettingsMonitor
    
    When integrating with optional components like Clocks, it is not safe
    to access their GSettings right after the application became visible
    to the AppSystem:
    Installation is usually not atomic, so the .desktop file may appear
    before the settings schema, in which case Gio will abort due to an
    "invalid" schema ID.
    To address this, add a small helper class that wraps the settings
    access in a safe way.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=766410

 js/misc/util.js |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 93 insertions(+), 0 deletions(-)
---
diff --git a/js/misc/util.js b/js/misc/util.js
index 7c6d111..0221e15 100644
--- a/js/misc/util.js
+++ b/js/misc/util.js
@@ -4,6 +4,8 @@ const Clutter = imports.gi.Clutter;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Signals = imports.signals;
 const Shell = imports.gi.Shell;
 const St = imports.gi.St;
 
@@ -398,3 +400,94 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
                        time: SCROLL_TIME,
                        transition: 'easeOutQuad' });
 }
+
+const AppSettingsMonitor = new Lang.Class({
+    Name: 'AppSettingsMonitor',
+
+    _init: function(appId, schemaId) {
+        this._appId = appId;
+        this._schemaId = schemaId;
+
+        this._app = null;
+        this._settings = null;
+        this._handlers = [];
+
+        this._schemaSource = Gio.SettingsSchemaSource.get_default();
+
+        this._appSystem = Shell.AppSystem.get_default();
+        this._appSystem.connect('installed-changed',
+                                Lang.bind(this, this._onInstalledChanged));
+        this._onInstalledChanged();
+    },
+
+    get available() {
+        return this._app != null && this._settings != null;
+    },
+
+    activateApp: function() {
+        if (this._app)
+            this._app.activate();
+    },
+
+    watchSetting: function(key, callback) {
+        let handler = { id: 0, key: key, callback: callback };
+        this._handlers.push(handler);
+
+        this._connectHandler(handler);
+    },
+
+    _connectHandler: function(handler) {
+        if (!this._settings || handler.id > 0)
+            return;
+
+        handler.id = this._settings.connect('changed::' + handler.key,
+                                            handler.callback);
+        handler.callback(this._settings, handler.key);
+    },
+
+    _disconnectHandler: function(handler) {
+        if (this._settings && handler.id > 0)
+            this._settings.disconnect(handler.id);
+        handler.id = 0;
+    },
+
+    _onInstalledChanged: function() {
+        let hadApp = (this._app != null);
+        this._app = this._appSystem.lookup_app(this._appId);
+        let haveApp = (this._app != null);
+
+        if (hadApp == haveApp)
+            return;
+
+        if (haveApp)
+            this._checkSettings();
+        else
+            this._setSettings(null);
+    },
+
+    _setSettings(settings) {
+        this._handlers.forEach((handler) => { this._disconnectHandler(handler); });
+
+        let hadSettings = (this._settings != null);
+        this._settings = settings;
+        let haveSettings = (this._settings != null);
+
+        this._handlers.forEach((handler) => { this._connectHandler(handler); });
+
+        if (hadSettings != haveSettings)
+            this.emit('available-changed');
+    },
+
+    _checkSettings: function() {
+        let schema = this._schemaSource.lookup(this._schemaId, true);
+        if (schema) {
+            this._setSettings(new Gio.Settings({ settings_schema: schema }));
+        } else if (this._app) {
+            Mainloop.timeout_add_seconds(1, () => {
+                this._checkSettings();
+                return GLib.SOURCE_REMOVE;
+            });
+        }
+    }
+});
+Signals.addSignalMethods(AppSettingsMonitor.prototype);


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