[gnome-weather] Split between the application and the background service



commit 35edc748a1eda81c7553e696f347713bfd36730e
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Wed May 14 10:27:36 2014 +0200

    Split between the application and the background service
    
    The main reason for the split is to avoid doing geolocation
    in the service that handles the search provider (which causes
    the geoclue indicator to appear for every shell search).
    In the future, the background service will also handle severe
    weather advisories, if enabled (and will be able to do so
    across sessions, if launched on the user bus).
    
    And besides, it is clean this way too.

 data/Makefile.am                                   |   24 ++++-
 ...rg.gnome.Weather.Application.data.gresource.xml |    3 -
 ...g.gnome.Weather.Application.search-provider.ini |    4 +-
 ...me.Weather.BackgroundService.data.gresource.xml |    8 ++
 .../org.gnome.Weather.BackgroundService.service.in |    3 +
 po/POTFILES.in                                     |   14 ++--
 src/Makefile.am                                    |   29 +++++-
 src/{ => app}/city.js                              |    6 +-
 src/{ => app}/currentLocationController.js         |   20 +++-
 src/{ => app}/forecast.js                          |    6 +-
 src/{ => app}/main.js                              |   62 +++++++----
 src/{ => app}/window.js                            |   12 +-
 src/{ => misc}/params.js                           |    0
 src/{ => misc}/util.js                             |    2 +-
 src/org.gnome.Weather.Application.in               |    3 +-
 ...org.gnome.Weather.Application.src.gresource.xml |   19 ++--
 src/org.gnome.Weather.BackgroundService.in         |    7 ++
 ...ome.Weather.BackgroundService.src.gresource.xml |   11 ++
 src/service/main.js                                |  106 ++++++++++++++++++++
 src/{ => service}/searchProvider.js                |   51 ++++++++--
 src/{ => shared}/strings.js                        |    0
 src/{ => shared}/world.js                          |   67 +++++++++----
 22 files changed, 353 insertions(+), 104 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index a718125..f3fb26c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -2,12 +2,15 @@
 # 5 different directory declarations
 SUBDIRS = icons
 
-resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/$(PACKAGE_NAME).Application.data.gresource.xml)
-$(PACKAGE_NAME).Application.data.gresource: $(PACKAGE_NAME).Application.data.gresource.xml $(resource_files)
+app_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/$(PACKAGE_NAME).Application.data.gresource.xml)
+$(PACKAGE_NAME).Application.data.gresource: $(PACKAGE_NAME).Application.data.gresource.xml 
$(app_resource_files)
+       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) $<
+service_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/$(PACKAGE_NAME).BackgroundService.data.gresource.xml)
+$(PACKAGE_NAME).BackgroundService.data.gresource: $(PACKAGE_NAME).BackgroundService.data.gresource.xml 
$(service_resource_files)
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) $<
 
 resourcedir = $(pkgdatadir)
-resource_DATA = $(PACKAGE_NAME).Application.data.gresource
+resource_DATA = $(PACKAGE_NAME).Application.data.gresource $(PACKAGE_NAME).BackgroundService.data.gresource
 
 appsdir = $(datadir)/applications
 apps_DATA = $(PACKAGE_NAME).Application.desktop
@@ -30,9 +33,15 @@ $(PACKAGE_NAME).Application.service: $(PACKAGE_NAME).Application.service.in
                -e "s|[ ]pkglibdir@|$(pkglibdir)|g" \
                $< > $@
 
+$(PACKAGE_NAME).BackgroundService.service: $(PACKAGE_NAME).BackgroundService.service.in
+       $(AM_V_GEN) sed \
+               -e "s|[ ]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
+               -e "s|[ ]pkgdatadir@|$(pkgdatadir)|g" \
+               -e "s|[ ]pkglibdir@|$(pkglibdir)|g" \
+               $< > $@
 
 servicedir = $(datadir)/dbus-1/services
-service_DATA = $(PACKAGE_NAME).Application.service
+service_DATA = $(PACKAGE_NAME).Application.service $(PACKAGE_NAME).BackgroundService.service
 
 searchproviderdir = $(datadir)/gnome-shell/search-providers
 dist_searchprovider_DATA = $(PACKAGE_NAME).Application.search-provider.ini
@@ -41,15 +50,20 @@ EXTRA_DIST = \
        CREDITS \
        $(PACKAGE_NAME).Application.desktop.in \
        $(PACKAGE_NAME).Application.service.in \
+       $(PACKAGE_NAME).BackgroundService.service.in \
        $(PACKAGE_NAME).Application.data.gresource.xml \
+       $(PACKAGE_NAME).BackgroundService.data.gresource.xml \
        $(gsettings_SCHEMAS) \
        $(PACKAGE_NAME).Application.appdata.xml.in \
-       $(resource_files) \
+       $(app_resource_files) \
+       $(service_resource_files) \
        $(NULL)
 
 CLEANFILES = \
        $(PACKAGE_NAME).Application.service \
+       $(PACKAGE_NAME).BackgroundService.service \
        $(PACKAGE_NAME).Application.data.gresource \
+       $(PACKAGE_NAME).BackgroundService.data.gresource \
        $(PACKAGE_NAME).Application.appdata.xml \
        $(apps_DATA) \
        *.valid \
diff --git a/data/org.gnome.Weather.Application.data.gresource.xml 
b/data/org.gnome.Weather.Application.data.gresource.xml
index 384e249..d0ae379 100644
--- a/data/org.gnome.Weather.Application.data.gresource.xml
+++ b/data/org.gnome.Weather.Application.data.gresource.xml
@@ -16,7 +16,4 @@
     <file>weather-snow.jpg</file>
     <file>weather-storm.jpg</file>
   </gresource>
-  <gresource prefix="/org/gnome/shell">
-    <file>ShellSearchProvider2.xml</file>
-  </gresource>
 </gresources>
diff --git a/data/org.gnome.Weather.Application.search-provider.ini 
b/data/org.gnome.Weather.Application.search-provider.ini
index 0d4c42e..df21a87 100644
--- a/data/org.gnome.Weather.Application.search-provider.ini
+++ b/data/org.gnome.Weather.Application.search-provider.ini
@@ -1,5 +1,5 @@
 [Shell Search Provider]
 DesktopId=org.gnome.Weather.Application.desktop
-BusName=org.gnome.Weather.Application
-ObjectPath=/org/gnome/Weather/Application
+BusName=org.gnome.Weather.BackgroundService
+ObjectPath=/org/gnome/Weather/BackgroundService
 Version=2
diff --git a/data/org.gnome.Weather.BackgroundService.data.gresource.xml 
b/data/org.gnome.Weather.BackgroundService.data.gresource.xml
new file mode 100644
index 0000000..367e15b
--- /dev/null
+++ b/data/org.gnome.Weather.BackgroundService.data.gresource.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/Weather/BackgroundService">
+  </gresource>
+  <gresource prefix="/org/gnome/shell">
+    <file>ShellSearchProvider2.xml</file>
+  </gresource>
+</gresources>
diff --git a/data/org.gnome.Weather.BackgroundService.service.in 
b/data/org.gnome.Weather.BackgroundService.service.in
new file mode 100644
index 0000000..484a690
--- /dev/null
+++ b/data/org.gnome.Weather.BackgroundService.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name= PACKAGE_NAME@.BackgroundService
+Exec= pkgdatadir@/@PACKAGE_NAME  BackgroundService
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5515508..2b261b6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -5,10 +5,10 @@ data/org.gnome.Weather.Application.appdata.xml.in
 [type: gettext/glade]data/new-location-dialog.ui
 data/org.gnome.Weather.Application.gschema.xml
 [type: gettext/glade]data/window.ui
-src/city.js
-src/forecast.js
-src/main.js
-src/searchProvider.js
-src/strings.js
-src/window.js
-src/world.js
+src/app/city.js
+src/app/forecast.js
+src/app/main.js
+src/app/window.js
+src/service/searchProvider.js
+src/shared/strings.js
+src/shared/world.js
diff --git a/src/Makefile.am b/src/Makefile.am
index 5d1cb85..fa8e8e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,14 +1,18 @@
 NULL =
 
 appdir = $(pkgdatadir)
-nodist_app_SCRIPTS = org.gnome.Weather.Application
+nodist_app_SCRIPTS = org.gnome.Weather.Application org.gnome.Weather.BackgroundService
 
-resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/$(PACKAGE_NAME).Application.src.gresource.xml)
-$(PACKAGE_NAME).Application.src.gresource: $(PACKAGE_NAME).Application.src.gresource.xml $(resource_files)
+app_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/$(PACKAGE_NAME).Application.src.gresource.xml)
+$(PACKAGE_NAME).Application.src.gresource: $(PACKAGE_NAME).Application.src.gresource.xml 
$(app_resource_files)
+       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) $<
+
+service_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/$(PACKAGE_NAME).BackgroundService.src.gresource.xml)
+$(PACKAGE_NAME).BackgroundService.src.gresource: $(PACKAGE_NAME).BackgroundService.src.gresource.xml 
$(service_resource_files)
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) $<
 
 resourcedir = $(pkgdatadir)
-resource_DATA = $(PACKAGE_NAME).Application.src.gresource
+resource_DATA = $(PACKAGE_NAME).Application.src.gresource $(PACKAGE_NAME).BackgroundService.src.gresource
 
 # Legacy, until we can depend on package.js provided by gjs
 jsdir = $(pkgdatadir)
@@ -24,15 +28,30 @@ org.gnome.Weather.Application: org.gnome.Weather.Application.in
                $< > $@
        @chmod +x $@
 
+org.gnome.Weather.BackgroundService: org.gnome.Weather.BackgroundService.in
+       $(AM_V_GEN) sed \
+               -e "s|[ ]GJS@|$(GJS)|g" \
+               -e "s|[ ]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
+               -e "s|[ ]prefix@|$(prefix)|g" \
+               -e "s|[ ]libdir@|$(libdir)|g" \
+               -e "s|[ ]pkgdatadir@|$(pkgdatadir)|g" \
+               $< > $@
+       @chmod +x $@
+
 EXTRA_DIST = \
        $(PACKAGE_NAME).Application.in \
        $(PACKAGE_NAME).Application.src.gresource.xml \
-       $(resource_files) \
+       $(PACKAGE_NAME).BackgroundService.in \
+       $(PACKAGE_NAME).BackgroundService.src.gresource.xml \
+       $(app_resource_files) \
+       $(service_resource_files) \
        $(NULL)
 
 CLEANFILES = \
        $(PACKAGE_NAME).Application \
        $(PACKAGE_NAME).Application.src.gresource \
+       $(PACKAGE_NAME).BackgroundService \
+       $(PACKAGE_NAME).BackgroundService.src.gresource \
        $(NULL)
 
 install-exec-hook:
diff --git a/src/city.js b/src/app/city.js
similarity index 98%
rename from src/city.js
rename to src/app/city.js
index 6ab5122..86bed8b 100644
--- a/src/city.js
+++ b/src/app/city.js
@@ -23,9 +23,9 @@ const GLib = imports.gi.GLib;
 const Gnome = imports.gi.GnomeDesktop;
 const Lang = imports.lang;
 
-const Forecast = imports.forecast;
-const Params = imports.params;
-const Util = imports.util;
+const Forecast = imports.app.forecast;
+const Params = imports.misc.params;
+const Util = imports.misc.util;
 
 const SPINNER_SIZE = 128;
 
diff --git a/src/currentLocationController.js b/src/app/currentLocationController.js
similarity index 91%
rename from src/currentLocationController.js
rename to src/app/currentLocationController.js
index 139522c..c4df077 100644
--- a/src/currentLocationController.js
+++ b/src/app/currentLocationController.js
@@ -68,8 +68,8 @@ const LocationProxy = Gio.DBusProxy.makeProxyWrapper(LocationInterface);
 const CurrentLocationController = new Lang.Class({
     Name: 'CurrentLocationController',
 
-    _init: function(callback) {
-        this._callback = callback;
+    _init: function(world) {
+        this._world = world;
         this._managerProxy = new ManagerProxy(Gio.DBus.system,
                                                "org.freedesktop.GeoClue2",
                                                "/org/freedesktop/GeoClue2/Manager");
@@ -117,11 +117,21 @@ const CurrentLocationController = new Lang.Class({
                                               description: geoclueLocation.Description });
 
         this.currentLocation = GWeather.Location.get_world().find_nearest_city (location.latitude, 
location.longitude);
-        if (this.currentLocation)
-            this._callback(this.currentLocation);
+        this._addCurrentLocation();
     },
 
-    isLocationSimilar: function(location) {
+    _addCurrentLocation: function() {
+        let allLocations = this._world.getAllSavedLocations();
+        let isSimilar = Lang.bind(this, function(location) {
+            return this._isLocationSimilar(location);
+        });
+        if (allLocations.some(isSimilar))
+            return;
+
+        this._world.addLocation(this.currentLocation, false);
+    },
+
+    _isLocationSimilar: function(location) {
         if (this.currentLocation != null) {
             let station_code = location.get_code ();
             let currentLocationCode = this.currentLocation.get_code();
diff --git a/src/forecast.js b/src/app/forecast.js
similarity index 99%
rename from src/forecast.js
rename to src/app/forecast.js
index 9aebca1..a13c7c0 100644
--- a/src/forecast.js
+++ b/src/app/forecast.js
@@ -22,9 +22,9 @@ const Gtk = imports.gi.Gtk;
 const GWeather = imports.gi.GWeather;
 const Lang = imports.lang;
 
-const Params = imports.params;
-const Strings = imports.strings;
-const Util = imports.util;
+const Params = imports.misc.params;
+const Strings = imports.shared.strings;
+const Util = imports.misc.util;
 
 // In microseconds
 const ONE_DAY = 24*3600*1000*1000;
diff --git a/src/main.js b/src/app/main.js
similarity index 74%
rename from src/main.js
rename to src/app/main.js
index 5b83776..43ffc7a 100644
--- a/src/main.js
+++ b/src/app/main.js
@@ -36,10 +36,10 @@ const Gtk = imports.gi.Gtk;
 const GWeather = imports.gi.GWeather;
 const Lang = imports.lang;
 
-const Util = imports.util;
-const Window = imports.window;
-const World = imports.world;
-const SearchProvider = imports.searchProvider;
+const Util = imports.misc.util;
+const Window = imports.app.window;
+const World = imports.shared.world;
+const CurrentLocationController = imports.app.currentLocationController;
 
 function initEnvironment() {
     window.getApp = function() {
@@ -54,35 +54,39 @@ const Application = new Lang.Class({
     _init: function() {
         this.parent({ application_id: pkg.name });
         GLib.set_application_name(_("Weather"));
-        if (pkg.moduledir.startsWith('resource:///'))
-            this.set_inactivity_timeout(60000);
-
-        this._searchProvider = new SearchProvider.SearchProvider(this);
     },
 
     _onQuit: function() {
         this.quit();
     },
 
-    _initAppMenu: function() {
-        let builder = new Gtk.Builder();
-        builder.add_from_resource('/org/gnome/Weather/Application/app-menu.ui');
+    _onShowLocation: function(action, parameter) {
+        let location = this.world.deserialize(parameter.deep_unpack());
+        let win = this._createWindow();
 
-        let menu = builder.get_object('app-menu');
-        this.set_app_menu(menu);
+        let info = this.model.getLocationInfo(location);
+        if (!info) {
+            this.model.addLocation(location, false);
+            info = this.model.getLocationInfo(location);
+        }
+
+        win.showInfo(info);
     },
 
-    vfunc_dbus_register: function(connection, path) {
-        this.parent(connection, path);
+    _onNewLocation: function(action, parameter) {
+        let win = this.get_active_window();
+        if (!win)
+            win = this._createWindow();
 
-        this._searchProvider.export(connection, path);
-        return true;
+        win.activate_action('new-location', null);
     },
 
-    vfunc_dbus_unregister: function(connection, path) {
-        this._searchProvider.unexport(connection);
+    _initAppMenu: function() {
+        let builder = new Gtk.Builder();
+        builder.add_from_resource('/org/gnome/Weather/Application/app-menu.ui');
 
-        this.parent(connection, path);
+        let menu = builder.get_object('app-menu');
+        this.set_app_menu(menu);
     },
 
     vfunc_startup: function() {
@@ -95,7 +99,8 @@ const Application = new Lang.Class({
         settings.gtk_application_prefer_dark_theme = true;
 
         this.world = GWeather.Location.get_world();
-        this.model = new World.WorldModel(this.world);
+        this.model = new World.WorldModel(this.world, true);
+        this._currentLocationController = new 
CurrentLocationController.CurrentLocationController(this.model);
 
         this.model.connect('notify::loading', Lang.bind(this, function() {
             if (this.model.loading)
@@ -108,7 +113,12 @@ const Application = new Lang.Class({
 
         Util.initActions(this,
                          [{ name: 'quit',
-                            activate: this._onQuit }]);
+                            activate: this._onQuit },
+                          { name: 'show-location',
+                            activate: this._onShowLocation,
+                            parameter_type: new GLib.VariantType('v') },
+                          { name: 'new-location',
+                            activate: this._onNewLocation }]);
 
         let gwSettings = new Gio.Settings({ schema: 'org.gnome.GWeather' });
         this.add_action(gwSettings.create_action('temperature-unit'));
@@ -119,7 +129,7 @@ const Application = new Lang.Class({
         this.add_accelerator("<Primary>a", "win.select-all", null);
     },
 
-    vfunc_activate: function() {
+    _createWindow: function() {
         let win = new Window.MainWindow({ application: this });
 
         if (this.model.loading) {
@@ -140,6 +150,12 @@ const Application = new Lang.Class({
         } else {
             win.show();
         }
+
+        return win;
+    },
+
+    vfunc_activate: function() {
+        this._createWindow();
     },
 
     vfunc_shutdown: function() {
diff --git a/src/window.js b/src/app/window.js
similarity index 97%
rename from src/window.js
rename to src/app/window.js
index 42f67db..08fa89c 100644
--- a/src/window.js
+++ b/src/app/window.js
@@ -22,10 +22,10 @@ const Gtk = imports.gi.Gtk;
 const GWeather = imports.gi.GWeather;
 const Lang = imports.lang;
 
-const City = imports.city;
-const Params = imports.params;
-const World = imports.world;
-const Util = imports.util;
+const City = imports.app.city;
+const Params = imports.misc.params;
+const World = imports.shared.world;
+const Util = imports.misc.util;
 
 const Gettext = imports.gettext;
 const Tweener = imports.tweener.tweener;
@@ -73,11 +73,11 @@ const NewLocationController = new Lang.Class({
         if (!location)
             return;
 
-        this._worldModel.addLocation(location);
+        this._worldModel.addLocation(location, true);
     },
 
     _locationChanged: function(entry) {
-       this._dialog.set_response_sensitive(Gtk.ResponseType.OK, entry.location != null);
+           this._dialog.set_response_sensitive(Gtk.ResponseType.OK, entry.location != null);
     }
 });
 
diff --git a/src/params.js b/src/misc/params.js
similarity index 100%
rename from src/params.js
rename to src/misc/params.js
diff --git a/src/util.js b/src/misc/util.js
similarity index 99%
rename from src/util.js
rename to src/misc/util.js
index 6f61fe7..fc08e3f 100644
--- a/src/util.js
+++ b/src/misc/util.js
@@ -30,7 +30,7 @@ const GLib = imports.gi.GLib;
 const Gtk = imports.gi.Gtk;
 const System = imports.system;
 
-const Params = imports.params;
+const Params = imports.misc.params;
 
 function loadUI(resourcePath, objects) {
     let ui = new Gtk.Builder();
diff --git a/src/org.gnome.Weather.Application.in b/src/org.gnome.Weather.Application.in
index 124ffb4..7736e47 100644
--- a/src/org.gnome.Weather.Application.in
+++ b/src/org.gnome.Weather.Application.in
@@ -1,6 +1,7 @@
 #! GJS@
 imports.searchPath.push("@pkgdatadir@");
-imports.package.start({ name: "org.gnome.Weather",
+imports.package.init({ name: "org.gnome.Weather",
                         version: "@PACKAGE_VERSION@",
                         prefix: "@prefix@",
                         libdir: "@libdir@" });
+imports.package.run(imports.app.main);
\ No newline at end of file
diff --git a/src/org.gnome.Weather.Application.src.gresource.xml 
b/src/org.gnome.Weather.Application.src.gresource.xml
index c22b280..3e59a63 100644
--- a/src/org.gnome.Weather.Application.src.gresource.xml
+++ b/src/org.gnome.Weather.Application.src.gresource.xml
@@ -1,15 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
   <gresource prefix="/org/gnome/Weather/Application/js">
-    <file>city.js</file>
-    <file>currentLocationController.js</file>
-    <file>forecast.js</file>
-    <file>main.js</file>
-    <file>params.js</file>
-    <file>searchProvider.js</file>
-    <file>strings.js</file>
-    <file>util.js</file>
-    <file>window.js</file>
-    <file>world.js</file>
+    <file>app/city.js</file>
+    <file>app/currentLocationController.js</file>
+    <file>app/forecast.js</file>
+    <file>app/main.js</file>
+    <file>app/window.js</file>
+    <file>misc/params.js</file>
+    <file>misc/util.js</file>
+    <file>shared/strings.js</file>
+    <file>shared/world.js</file>
   </gresource>
 </gresources>
diff --git a/src/org.gnome.Weather.BackgroundService.in b/src/org.gnome.Weather.BackgroundService.in
new file mode 100644
index 0000000..54f254e
--- /dev/null
+++ b/src/org.gnome.Weather.BackgroundService.in
@@ -0,0 +1,7 @@
+#! GJS@
+imports.searchPath.push("@pkgdatadir@");
+imports.package.init({ name: "org.gnome.Weather",
+                        version: "@PACKAGE_VERSION@",
+                        prefix: "@prefix@",
+                        libdir: "@libdir@" });
+imports.package.run(imports.service.main);
\ No newline at end of file
diff --git a/src/org.gnome.Weather.BackgroundService.src.gresource.xml 
b/src/org.gnome.Weather.BackgroundService.src.gresource.xml
new file mode 100644
index 0000000..35a2899
--- /dev/null
+++ b/src/org.gnome.Weather.BackgroundService.src.gresource.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/Weather/BackgroundService/js">
+    <file>service/main.js</file>
+    <file>service/searchProvider.js</file>
+    <file>misc/params.js</file>
+    <file>misc/util.js</file>
+    <file>shared/strings.js</file>
+    <file>shared/world.js</file>
+  </gresource>
+</gresources>
diff --git a/src/service/main.js b/src/service/main.js
new file mode 100644
index 0000000..dd778be
--- /dev/null
+++ b/src/service/main.js
@@ -0,0 +1,106 @@
+// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
+//
+// Copyright (c) 2012 Giovanni Campagna <scampa giovanni gmail com>
+//
+// Gnome Weather is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// Gnome Weather is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with Gnome Weather; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+pkg.initSubmodule('libgd');
+pkg.initGettext();
+pkg.initFormat();
+pkg.require({ 'Gd': '1.0',
+              'Gio': '2.0',
+              'GLib': '2.0',
+              'GObject': '2.0',
+              'GWeather': '3.0' });
+
+const Gd = imports.gi.Gd;
+const Gdk = imports.gi.Gdk;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const GWeather = imports.gi.GWeather;
+const Lang = imports.lang;
+
+const Util = imports.misc.util;
+const SearchProvider = imports.service.searchProvider;
+const World = imports.shared.world;
+
+function initEnvironment() {
+    window.getApp = function() {
+        return Gio.Application.get_default();
+    };
+}
+
+const BackgroundService = new Lang.Class({
+    Name: 'WeatherBackgroundService',
+    Extends: Gio.Application,
+
+    _init: function() {
+        this.parent({ application_id: pkg.name,
+                      flags: Gio.ApplicationFlags.IS_SERVICE,
+                      inactivity_timeout: 60000 });
+        GLib.set_application_name(_("Weather"));
+
+        this._searchProvider = new SearchProvider.SearchProvider(this);
+    },
+
+    _onQuit: function() {
+        this.quit();
+    },
+
+    vfunc_dbus_register: function(connection, path) {
+        this.parent(connection, path);
+
+        this._searchProvider.export(connection, path);
+        return true;
+    },
+
+/*
+  Can't do until GApplication is fixed.
+
+    vfunc_dbus_unregister: function(connection, path) {
+        this._searchProvider.unexport(connection);
+
+        this.parent(connection, path);
+    },
+*/
+
+    vfunc_startup: function() {
+        this.parent();
+
+        this.world = GWeather.Location.get_world();
+        this.model = new World.WorldModel(this.world, false);
+
+        Util.initActions(this,
+                         [{ name: 'quit',
+                            activate: this._onQuit }]);
+    },
+
+    vfunc_activate: function() {
+        // do nothing, this is a background service
+    },
+
+    vfunc_shutdown: function() {
+        GWeather.Info.store_cache();
+
+        this.parent();
+    }
+});
+
+function main(argv) {
+    initEnvironment();
+
+    return (new BackgroundService()).run(argv);
+}
diff --git a/src/searchProvider.js b/src/service/searchProvider.js
similarity index 78%
rename from src/searchProvider.js
rename to src/service/searchProvider.js
index 2b03ecd..aaaefd2 100644
--- a/src/searchProvider.js
+++ b/src/service/searchProvider.js
@@ -21,9 +21,8 @@ const GLib = imports.gi.GLib;
 const GWeather = imports.gi.GWeather;
 const Lang = imports.lang;
 
-const Util = imports.util;
-const Window = imports.window;
-const World = imports.world;
+const Util = imports.misc.util;
+const World = imports.shared.world;
 
 const SearchProviderInterface = Gio.resources_lookup_data('/org/gnome/shell/ShellSearchProvider2.xml', 
0).toArray().toString();
 
@@ -179,20 +178,54 @@ const SearchProvider = new Lang.Class({
         return ret;
     },
 
+    _getPlatformData: function(timestamp) {
+        return {'desktop-startup-id': new GLib.Variant('s', '_TIME' + timestamp) };
+    },
+
+    _activateAction: function(action, parameter, timestamp) {
+        let wrappedParam;
+        if (parameter)
+            wrappedParam = [parameter];
+        else
+            wrappedParam = [];
+
+        Gio.DBus.session.call('org.gnome.Weather.Application',
+                              '/org/gnome/Weather/Application',
+                              'org.freedesktop.Application',
+                              'ActivateAction',
+                              new GLib.Variant('(sava{sv})', [action, wrappedParam,
+                                                              this._getPlatformData(timestamp)]),
+                              null,
+                              Gio.DBusCallFlags.NONE,
+                              -1, null, Lang.bind(this, function(connection, result) {
+                                  try {
+                                      connection.call_finish(result);
+                                  } catch(e) {
+                                      log('Failed to launch application: ' + e);
+                                  }
+
+                                  this._app.release();
+                              }));
+    },
+
     ActivateResult: function(id, terms, timestamp) {
         this._app.hold();
 
         let model = this._app.model;
         let [ok, iter] = model.get_iter_from_string(id);
-        if (!ok)
+        if (!ok) {
+            this._app.release();
             return;
+        }
 
         let info = model.get_value(iter, World.Columns.INFO);
-        let win = new Window.MainWindow({ application: this._app });
+        let location = info.get_location().serialize();
 
-        win.showInfo(info);
-        win.present_with_time(timestamp);
+        this._activateAction('show-location', new GLib.Variant('v', location), timestamp);
+    },
 
-        this._app.release();
-    }
+    LaunchSearch: function(terms, timestamp) {
+        this._app.hold();
+        this._activateAction('new-location', null, timestamp);
+    },
 });
diff --git a/src/strings.js b/src/shared/strings.js
similarity index 100%
rename from src/strings.js
rename to src/shared/strings.js
diff --git a/src/world.js b/src/shared/world.js
similarity index 88%
rename from src/world.js
rename to src/shared/world.js
index 0566f67..4c6861e 100644
--- a/src/world.js
+++ b/src/shared/world.js
@@ -24,9 +24,8 @@ const Gtk = imports.gi.Gtk;
 const GWeather = imports.gi.GWeather;
 const Lang = imports.lang;
 
-const Params = imports.params;
-const Util = imports.util;
-const CurrentLocationController = imports.currentLocationController;
+const Params = imports.misc.params;
+const Util = imports.misc.util;
 
 const Columns = {
     ID: Gd.MainColumns.ID,
@@ -69,7 +68,7 @@ const WorldModel = new Lang.Class({
         'loading': GObject.ParamSpec.boolean('loading', '', '', GObject.ParamFlags.READABLE, false)
     },
 
-    _init: function(world) {
+    _init: function(world, enableGtk) {
         this.parent();
         this.set_column_types([ColumnTypes[c] for (c in ColumnTypes)]);
         this._world = world;
@@ -95,9 +94,7 @@ const WorldModel = new Lang.Class({
 
         this._settings.connect('changed::locations', Lang.bind(this, this._onChanged));
 
-        let currentLocationController = new 
CurrentLocationController.CurrentLocationController(Lang.bind(this,
-                                                                                                          
this._addCurrentLocation));
-        this._currentLocationController = currentLocationController;
+        this._enableGtk = enableGtk;
     },
 
     _updateLoadingCount: function(delta) {
@@ -123,11 +120,15 @@ const WorldModel = new Lang.Class({
                                        enabled_providers: this._providers });
         let iter;
         info.connect('updated', Lang.bind(this, function(info) {
-            let icon = Util.loadIcon(info.get_symbolic_icon_name(), ICON_SIZE);
             let secondary_text = Util.getWeatherConditions(info);
-            this.set(iter,
-                     [Columns.ICON, Columns.SECONDARY_TEXT],
-                     [icon, secondary_text]);
+            if (this._enableGtk) {
+                let icon = Util.loadIcon(info.get_symbolic_icon_name(), ICON_SIZE);
+                this.set(iter,
+                         [Columns.ICON, Columns.SECONDARY_TEXT],
+                         [icon, secondary_text]);
+            } else {
+                this.set_value(iter, Columns.SECONDARY_TEXT, secondary_text);
+            }
 
             this._updateLoadingCount(-1);
             this.emit('updated', info);
@@ -135,19 +136,21 @@ const WorldModel = new Lang.Class({
         this.updateInfo(info);
 
         let primary_text = location.get_city_name();
-        let icon = Util.loadIcon('view-refresh-symbolic', ICON_SIZE);
 
         iter = this.insert_with_valuesv(-1,
                                         [Columns.PRIMARY_TEXT,
-                                         Columns.ICON,
                                          Columns.LOCATION,
                                          Columns.INFO,
                                          Columns.AUTOMATIC],
                                         [primary_text,
-                                         icon,
                                          location,
                                          info,
                                          automatic]);
+
+        if (this._enableGtk) {
+            let icon = Util.loadIcon('view-refresh-symbolic', ICON_SIZE);
+            this.set_value(iter, Columns.ICON, icon);
+        }
     },
 
     _onChanged: function() {
@@ -197,25 +200,47 @@ const WorldModel = new Lang.Class({
         }
     },
 
-    addLocation: function(location) {
+    _addSavedLocation: function(location) {
         let newLocations = this._settings.get_value('locations').deep_unpack();
         newLocations.push(location.serialize());
         this._settings.set_value('locations', new GLib.Variant('av', newLocations));
     },
 
-    _addCurrentLocation: function(currentLocation) {
+    getAllSavedLocations: function() {
         let locations = this._settings.get_value('locations').deep_unpack();
+        let returnValue = [];
 
         for (let i = 0; i < locations.length; i++) {
             let variant = locations[i];
-            if (variant == null)
+            if (variant == null) {
+                log('null stored in GSettings?');
                 continue;
+            }
 
-            let location = this._world.deserialize(variant);
-            if (this._currentLocationController.isLocationSimilar(location))
-                return;
+            returnValue.push(this._world.deserialize(variant));
         }
-        this._addLocationInternal(currentLocation, true);
+
+        return returnValue;
+    },
+
+    getLocationInfo: function(location) {
+        let [ok, iter] = this.get_iter_first();
+        while (ok) {
+            let storedLocation = this.get_value(iter, Columns.LOCATION);
+            if (storedLocation.equal(location))
+                return this.get_value(iter, Columns.INFO);
+
+            ok = this.iter_next(iter);
+        }
+
+        return null;
+    },
+
+    addLocation: function(location, saved) {
+        if (saved)
+            this._addSavedLocation(location);
+        else
+            this._addLocationInternal(location, true);
     },
 
     removeLocation: function(iter) {


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