[gnome-shell] weather: Stop accessing app settings directly



commit 933c037c6eedf2af1551bc3e9909c2b9358f035a
Author: Florian Müllner <fmuellner gnome org>
Date:   Tue Jul 23 10:49:40 2019 +0000

    weather: Stop accessing app settings directly
    
    Our current Weather integration depends on poking around the app's
    settings, which we cannot do when the app is sandboxed (as its
    filesystem is "hidden away" in a container in that case).
    
    So instead, use our own GSettings schema for the settings, and sync
    it with GNOME Weather via a custom D-Bus interface.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/issues/1158

 .../org.gnome.Shell.WeatherIntegration.xml         | 16 +++++
 data/gnome-shell-dbus-interfaces.gresource.xml     |  1 +
 data/org.gnome.shell.gschema.xml.in                | 19 +++++
 js/misc/weather.js                                 | 82 +++++++++++++++++++---
 4 files changed, 107 insertions(+), 11 deletions(-)
---
diff --git a/data/dbus-interfaces/org.gnome.Shell.WeatherIntegration.xml 
b/data/dbus-interfaces/org.gnome.Shell.WeatherIntegration.xml
new file mode 100644
index 000000000..1e89bbe1d
--- /dev/null
+++ b/data/dbus-interfaces/org.gnome.Shell.WeatherIntegration.xml
@@ -0,0 +1,16 @@
+<node>
+
+  <!--
+      org.gnome.Shell.WeatherIntegration:
+      @short_description: Weather integration interface
+
+      The interface used for exporting location settings to GNOME Shell's
+      weather integration.
+  -->
+  <interface name="org.gnome.Shell.WeatherIntegration">
+
+  <property name="AutomaticLocation" type="b" access="read"/>
+  <property name="Locations" type="av" access="read"/>
+
+  </interface>
+</node>
diff --git a/data/gnome-shell-dbus-interfaces.gresource.xml b/data/gnome-shell-dbus-interfaces.gresource.xml
index 3352e0dcd..21fdfa949 100644
--- a/data/gnome-shell-dbus-interfaces.gresource.xml
+++ b/data/gnome-shell-dbus-interfaces.gresource.xml
@@ -48,6 +48,7 @@
     <file preprocess="xml-stripblanks">org.gnome.Shell.Screencast.xml</file>
     <file preprocess="xml-stripblanks">org.gnome.Shell.Screenshot.xml</file>
     <file preprocess="xml-stripblanks">org.gnome.Shell.Wacom.PadOsd.xml</file>
+    <file preprocess="xml-stripblanks">org.gnome.Shell.WeatherIntegration.xml</file>
     <file preprocess="xml-stripblanks">org.gnome.Shell.xml</file>
     <file preprocess="xml-stripblanks">org.Gtk.MountOperationHandler.xml</file>
     <file preprocess="xml-stripblanks">org.gtk.Notifications.xml</file>
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
index 4aca92162..9c3e42c94 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -233,6 +233,25 @@
     </key>
   </schema>
 
+  <schema id="org.gnome.shell.weather" path="/org/gnome/shell/weather/"
+          gettext-domain="@GETTEXT_PACKAGE@">
+    <key name="automatic-location" type="b">
+      <summary>Automatic location</summary>
+      <description>
+        Whether to fetch the current location or not
+      </description>
+      <default>false</default>
+    </key>
+
+    <key name="locations" type="av">
+      <summary>Location</summary>
+      <description>
+        The location for which to show a forecast
+      </description>
+      <default>[]</default>
+    </key>
+  </schema>
+
   <!-- unused, change 00_org.gnome.shell.gschema.override instead -->
   <schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
          gettext-domain="@GETTEXT_PACKAGE@">
diff --git a/js/misc/weather.js b/js/misc/weather.js
index efd8ce82d..4d63d745b 100644
--- a/js/misc/weather.js
+++ b/js/misc/weather.js
@@ -1,10 +1,19 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
-const { Geoclue, Gio, GLib, GWeather } = imports.gi;
+const { Geoclue, Gio, GLib, GWeather, Shell } = imports.gi;
 const Signals = imports.signals;
 
 const PermissionStore = imports.misc.permissionStore;
-const Util = imports.misc.util;
+
+const { loadInterfaceXML } = imports.misc.fileUtils;
+
+const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
+
+const WEATHER_BUS_NAME = 'org.gnome.Weather';
+const WEATHER_OBJECT_PATH = '/org/gnome/Weather';
+const WEATHER_INTEGRATION_IFACE = 'org.gnome.Shell.WeatherIntegration';
+
+const WEATHER_APP_ID = 'org.gnome.Weather.desktop';
 
 // Minimum time between updates to show loading indication
 var UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE;
@@ -66,17 +75,36 @@ var WeatherClient = class {
             this.emit('changed');
         });
 
-        this._weatherAppMon = new Util.AppSettingsMonitor('org.gnome.Weather.desktop',
-                                                          'org.gnome.Weather');
-        this._weatherAppMon.connect('available-changed', () => this.emit('changed'));
-        this._weatherAppMon.watchSetting('automatic-location',
-                                         this._onAutomaticLocationChanged.bind(this));
-        this._weatherAppMon.watchSetting('locations',
-                                         this._onLocationsChanged.bind(this));
+        this._weatherApp = null;
+        this._weatherProxy = null;
+
+        let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
+        Gio.DBusProxy.new(
+            Gio.DBus.session,
+            Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
+            nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
+            WEATHER_BUS_NAME,
+            WEATHER_OBJECT_PATH,
+            WEATHER_INTEGRATION_IFACE,
+            null,
+            this._onWeatherProxyReady.bind(this));
+
+        this._settings = new Gio.Settings({
+            schema_id: 'org.gnome.shell.weather'
+        });
+        this._settings.connect('changed::automatic-location',
+            this._onAutomaticLocationChanged.bind(this));
+        this._settings.connect('changed::locations',
+            this._onLocationsChanged.bind(this));
+
+        this._appSystem = Shell.AppSystem.get_default();
+        this._appSystem.connect('installed-changed',
+            this._onInstalledChanged.bind(this));
+        this._onInstalledChanged();
     }
 
     get available() {
-        return this._weatherAppMon.available;
+        return this._weatherApp != null;
     }
 
     get loading() {
@@ -92,7 +120,8 @@ var WeatherClient = class {
     }
 
     activateApp() {
-        this._weatherAppMon.activateApp();
+        if (this._weatherApp)
+            this._weatherApp.activate();
     }
 
     update() {
@@ -114,6 +143,37 @@ var WeatherClient = class {
                this._weatherAuthorized;
     }
 
+    _onWeatherProxyReady(o, res) {
+        try {
+            this._weatherProxy = Gio.DBusProxy.new_finish(res);
+        } catch (e) {
+            log(`Failed to create GNOME Weather proxy: ${e}`);
+            return;
+        }
+
+        this._weatherProxy.connect('g-properties-changed',
+            this._onWeatherPropertiesChanged.bind(this));
+
+        if (this._weatherProxy.g_owner != null)
+            this._onWeatherPropertiesChanged();
+    }
+
+    _onWeatherPropertiesChanged() {
+        this._settings.set_boolean('automatic-location',
+            this._weatherProxy.AutomaticLocation);
+        this._settings.set_value('locations',
+            new GLib.Variant('av', this._weatherProxy.Locations));
+    }
+
+    _onInstalledChanged() {
+        let hadApp = (this._weatherApp != null);
+        this._weatherApp = this._appSystem.lookup_app(WEATHER_APP_ID);
+        let haveApp = (this._weatherApp != null);
+
+        if (hadApp !== haveApp)
+            this.emit('changed');
+    }
+
     _loadInfo() {
         let id = this._weatherInfo.connect('updated', () => {
             this._weatherInfo.disconnect(id);


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