[gnome-initial-setup/shell/4765: 15/362] location: add automatic timezone discovery
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-initial-setup/shell/4765: 15/362] location: add automatic timezone discovery
- Date: Thu, 19 Mar 2015 01:22:19 +0000 (UTC)
commit f9ff42b2d3d5312ae3bb5e34d7e02f42ce1ad19e
Author: Cosimo Cecchi <cosimo endlessm com>
Date: Fri Apr 18 12:24:14 2014 -0700
location: add automatic timezone discovery
configure.ac | 8 +
gnome-initial-setup/pages/location/Makefile.am | 10 +
.../pages/location/cc-timezone-monitor.c | 442 ++++++++++++++++++++
.../pages/location/cc-timezone-monitor.h | 56 +++
.../pages/location/gis-location-page.c | 27 ++
gnome-initial-setup/pages/location/tz.c | 2 +-
gnome-initial-setup/pages/location/tz.h | 1 +
gnome-initial-setup/pages/location/weather-tz.c | 136 ++++++
gnome-initial-setup/pages/location/weather-tz.h | 31 ++
9 files changed, 712 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e21edf7..ac6145d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,8 @@ PKG_CHECK_MODULES(INITIAL_SETUP,
gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION
gstreamer-1.0
fontconfig
+ geoclue-2.0
+ geocode-glib-1.0
gweather-3.0
goa-1.0
goa-backend-1.0
@@ -54,6 +56,12 @@ PKG_CHECK_MODULES(INITIAL_SETUP,
PKG_CHECK_MODULES(COPY_WORKER, gio-2.0)
+GEOCLUE_DBUS_INTERFACE_XML=`pkg-config --variable=dbus_interface geoclue-2.0`
+if test "x$GEOCLUE_DBUS_INTERFACE_XML" = "x"; then
+ AC_MSG_ERROR([Cannot find dbus_interface variable in geoclue-2.0.pc])
+fi
+AC_SUBST(GEOCLUE_DBUS_INTERFACE_XML)
+
AC_ARG_ENABLE(ibus,
AS_HELP_STRING([--disable-ibus],
[Disable IBus support]),
diff --git a/gnome-initial-setup/pages/location/Makefile.am b/gnome-initial-setup/pages/location/Makefile.am
index 02fe6c1..badf8a0 100644
--- a/gnome-initial-setup/pages/location/Makefile.am
+++ b/gnome-initial-setup/pages/location/Makefile.am
@@ -7,6 +7,14 @@ BUILT_SOURCES =
AM_CPPFLAGS = \
-DGNOMECC_DATA_DIR="\"$(datadir)/gnome-control-center\""
+geoclue.c: geoclue.h
+geoclue.h: $(GEOCLUE_DBUS_INTERFACE_XML)
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix org.freedesktop.GeoClue2 \
+ --generate-c-code geoclue \
+ --c-namespace Geoclue $<
+BUILT_SOURCES += geoclue.c geoclue.h
+
timedated.c: timedated.h
timedated.h: $(srcdir)/timedated1-interface.xml
$(AM_V_GEN) gdbus-codegen \
@@ -30,7 +38,9 @@ BUILT_SOURCES += location-resources.c location-resources.h
libgislocation_la_SOURCES = \
tz.c tz.h \
+ weather-tz.c weather-tz.h \
cc-timezone-map.c cc-timezone-map.h \
+ cc-timezone-monitor.c cc-timezone-monitor.h \
gis-location-page.c gis-location-page.h \
date-endian.c date-endian.h \
$(BUILT_SOURCES)
diff --git a/gnome-initial-setup/pages/location/cc-timezone-monitor.c
b/gnome-initial-setup/pages/location/cc-timezone-monitor.c
new file mode 100644
index 0000000..996063d
--- /dev/null
+++ b/gnome-initial-setup/pages/location/cc-timezone-monitor.c
@@ -0,0 +1,442 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Kalev Lember <kalevlember gmail com>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include "cc-timezone-monitor.h"
+
+#include "geoclue.h"
+#include "timedated.h"
+#include "tz.h"
+#include "weather-tz.h"
+
+#include <geocode-glib/geocode-glib.h>
+#include <polkit/polkit.h>
+
+#define DESKTOP_ID "gnome-datetime-panel"
+#define SET_TIMEZONE_PERMISSION "org.freedesktop.timedate1.set-timezone"
+
+/* Defines from geoclue private header src/public-api/gclue-enums.h */
+#define GCLUE_ACCURACY_LEVEL_CITY 4
+
+enum {
+ TIMEZONE_CHANGED,
+ LAST_SIGNAL
+};
+
+static int signals[LAST_SIGNAL] = { 0 };
+
+typedef struct
+{
+ GCancellable *cancellable;
+ GeoclueClient *geoclue_client;
+ GeoclueManager *geoclue_manager;
+
+ TzDB *tzdb;
+ WeatherTzDB *weather_tzdb;
+} CcTimezoneMonitorPrivate;
+
+#define GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE((object), CC_TYPE_TIMEZONE_MONITOR,
CcTimezoneMonitorPrivate))
+G_DEFINE_TYPE (CcTimezoneMonitor, cc_timezone_monitor, G_TYPE_OBJECT)
+
+static gint
+compare_locations (TzLocation *a,
+ TzLocation *b)
+{
+ if (a->dist > b->dist)
+ return 1;
+
+ if (a->dist < b->dist)
+ return -1;
+
+ return 0;
+}
+
+static GList *
+sort_by_closest_to (GList *locations,
+ GeocodeLocation *location)
+{
+ GList *l;
+
+ for (l = locations; l; l = l->next) {
+ GeocodeLocation *loc;
+ TzLocation *tz_location = l->data;
+
+ loc = geocode_location_new (tz_location->latitude,
+ tz_location->longitude,
+ GEOCODE_LOCATION_ACCURACY_UNKNOWN);
+ tz_location->dist = geocode_location_get_distance_from (loc, location);
+ g_object_unref (loc);
+ }
+
+ return g_list_sort (locations, (GCompareFunc) compare_locations);
+}
+
+static GList *
+ptr_array_to_list (GPtrArray *array)
+{
+ GList *l = NULL;
+ gint i;
+
+ for (i = 0; i < array->len; i++)
+ l = g_list_prepend (l, g_ptr_array_index (array, i));
+
+ return l;
+}
+
+static GList *
+find_by_country (GList *locations,
+ const gchar *country_code)
+{
+ GList *l, *found = NULL;
+ gchar *c1;
+ gchar *c2;
+
+ c1 = g_ascii_strdown (country_code, -1);
+
+ for (l = locations; l; l = l->next) {
+ TzLocation *loc = l->data;
+
+ c2 = g_ascii_strdown (loc->country, -1);
+ if (g_strcmp0 (c1, c2) == 0)
+ found = g_list_prepend (found, loc);
+ g_free (c2);
+ }
+ g_free (c1);
+
+ return found;
+}
+
+static TzLocation *
+find_tzlocation (CcTimezoneMonitor *self,
+ GeocodeLocation *location,
+ const gchar *country_code)
+{
+ GList *filtered;
+ GList *locations;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+ TzLocation *closest_tz_location;
+
+ /* First load locations from Olson DB */
+ locations = ptr_array_to_list (tz_get_locations (priv->tzdb));
+ g_return_val_if_fail (locations != NULL, NULL);
+
+ /* ... and then add libgweather's locations as well */
+ locations = g_list_concat (locations,
+ weather_tz_db_get_locations (priv->weather_tzdb));
+
+ /* Filter tz locations by country */
+ filtered = find_by_country (locations, country_code);
+ if (filtered != NULL) {
+ g_list_free (locations);
+ locations = filtered;
+ } else {
+ g_debug ("No match for country code '%s' in tzdb", country_code);
+ }
+
+ /* Find the closest tz location */
+ locations = sort_by_closest_to (locations, location);
+ closest_tz_location = (TzLocation *) locations->data;
+
+ g_list_free (locations);
+
+ return closest_tz_location;
+}
+
+static void
+process_location (CcTimezoneMonitor *self,
+ GeocodePlace *place)
+{
+ GeocodeLocation *location;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+ TzLocation *new_tzlocation;
+ const gchar *country_code;
+ const gchar *new_timezone;
+
+ country_code = geocode_place_get_country_code (place);
+ location = geocode_place_get_location (place);
+
+ new_tzlocation = find_tzlocation (self, location, country_code);
+
+ g_signal_emit (G_OBJECT (self),
+ signals[TIMEZONE_CHANGED],
+ 0, new_tzlocation);
+}
+
+static void
+on_reverse_geocoding_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GeocodePlace *place;
+ GError *error = NULL;
+ CcTimezoneMonitor *self = user_data;
+
+ place = geocode_reverse_resolve_finish (GEOCODE_REVERSE (source_object),
+ res,
+ &error);
+ if (error != NULL) {
+ g_debug ("Reverse geocoding failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ g_debug ("Geocode lookup resolved country to '%s'",
+ geocode_place_get_country (place));
+
+ process_location (self, place);
+ g_object_unref (place);
+}
+
+static void
+start_reverse_geocoding (CcTimezoneMonitor *self,
+ gdouble latitude,
+ gdouble longitude)
+{
+ GeocodeLocation *location;
+ GeocodeReverse *reverse;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ location = geocode_location_new (latitude,
+ longitude,
+ GEOCODE_LOCATION_ACCURACY_CITY);
+
+ reverse = geocode_reverse_new_for_location (location);
+ geocode_reverse_resolve_async (reverse,
+ priv->cancellable,
+ on_reverse_geocoding_ready,
+ self);
+
+ g_object_unref (location);
+ g_object_unref (reverse);
+}
+
+static void
+on_location_proxy_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GeoclueLocation *location;
+ gdouble latitude, longitude;
+ GError *error = NULL;
+ CcTimezoneMonitor *self = user_data;
+
+ location = geoclue_location_proxy_new_for_bus_finish (res, &error);
+ if (error != NULL) {
+ g_critical ("Failed to connect to GeoClue2 service: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ latitude = geoclue_location_get_latitude (location);
+ longitude = geoclue_location_get_longitude (location);
+
+ start_reverse_geocoding (self, latitude, longitude);
+
+ g_object_unref (location);
+}
+
+static void
+on_location_updated (GDBusProxy *client,
+ gchar *location_path_old,
+ gchar *location_path_new,
+ gpointer user_data)
+{
+ CcTimezoneMonitor *self = user_data;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ geoclue_location_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.GeoClue2",
+ location_path_new,
+ priv->cancellable,
+ on_location_proxy_ready,
+ self);
+}
+
+static void
+on_start_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ if (!geoclue_client_call_start_finish (GEOCLUE_CLIENT (source_object),
+ res,
+ &error)) {
+ g_critical ("Failed to start GeoClue2 client: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+}
+
+static void
+on_client_proxy_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ CcTimezoneMonitor *self = user_data;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ priv->geoclue_client = geoclue_client_proxy_new_for_bus_finish (res, &error);
+ if (error != NULL) {
+ g_critical ("Failed to connect to GeoClue2 service: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ //geoclue_client_set_desktop_id (priv->geoclue_client, DESKTOP_ID);
+ geoclue_client_set_distance_threshold (priv->geoclue_client,
+ GEOCODE_LOCATION_ACCURACY_CITY);
+ //geoclue_client_set_requested_accuracy_level (priv->geoclue_client,
+ // GCLUE_ACCURACY_LEVEL_CITY);
+
+ g_signal_connect (priv->geoclue_client, "location-updated",
+ G_CALLBACK (on_location_updated), self);
+
+ geoclue_client_call_start (priv->geoclue_client,
+ priv->cancellable,
+ on_start_ready,
+ self);
+}
+
+static void
+on_get_client_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *client_path;
+ GError *error = NULL;
+ CcTimezoneMonitor *self = user_data;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ if (!geoclue_manager_call_get_client_finish (GEOCLUE_MANAGER (source_object),
+ &client_path,
+ res,
+ &error)) {
+ g_critical ("Failed to connect to GeoClue2 service: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ geoclue_client_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.GeoClue2",
+ client_path,
+ priv->cancellable,
+ on_client_proxy_ready,
+ self);
+}
+
+static void
+on_manager_proxy_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+
+ GError *error = NULL;
+ CcTimezoneMonitor *self = user_data;
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ priv->geoclue_manager = geoclue_manager_proxy_new_for_bus_finish (res, &error);
+ if (error != NULL) {
+ g_critical ("Failed to connect to GeoClue2 service: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ geoclue_manager_call_get_client (priv->geoclue_manager,
+ priv->cancellable,
+ on_get_client_ready,
+ self);
+}
+
+static void
+register_geoclue (CcTimezoneMonitor *self)
+{
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ geoclue_manager_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.freedesktop.GeoClue2",
+ "/org/freedesktop/GeoClue2/Manager",
+ priv->cancellable,
+ on_manager_proxy_ready,
+ self);
+}
+
+CcTimezoneMonitor *
+cc_timezone_monitor_new (void)
+{
+ return g_object_new (CC_TYPE_TIMEZONE_MONITOR, NULL);
+}
+
+static void
+cc_timezone_monitor_finalize (GObject *obj)
+{
+ CcTimezoneMonitor *monitor = CC_TIMEZONE_MONITOR (obj);
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (monitor);
+
+ g_debug ("Stopping timezone monitor");
+
+ if (priv->cancellable) {
+ g_cancellable_cancel (priv->cancellable);
+ g_clear_object (&priv->cancellable);
+ }
+
+ g_clear_object (&priv->geoclue_client);
+ g_clear_object (&priv->geoclue_manager);
+ g_clear_pointer (&priv->tzdb, tz_db_free);
+ g_clear_pointer (&priv->weather_tzdb, weather_tz_db_free);
+
+ G_OBJECT_CLASS (cc_timezone_monitor_parent_class)->finalize (obj);
+}
+
+static void
+cc_timezone_monitor_class_init (CcTimezoneMonitorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = cc_timezone_monitor_finalize;
+
+ signals[TIMEZONE_CHANGED] =
+ g_signal_new ("timezone-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CcTimezoneMonitorClass, timezone_changed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ g_type_class_add_private (object_class, sizeof(CcTimezoneMonitorPrivate));
+}
+
+static void
+cc_timezone_monitor_init (CcTimezoneMonitor *self)
+{
+ CcTimezoneMonitorPrivate *priv = GET_PRIVATE (self);
+
+ g_debug ("Starting timezone monitor");
+
+ priv->cancellable = g_cancellable_new ();
+
+ priv->tzdb = tz_load_db ();
+ priv->weather_tzdb = weather_tz_db_new ();
+
+ register_geoclue (self);
+}
diff --git a/gnome-initial-setup/pages/location/cc-timezone-monitor.h
b/gnome-initial-setup/pages/location/cc-timezone-monitor.h
new file mode 100644
index 0000000..10c8bb3
--- /dev/null
+++ b/gnome-initial-setup/pages/location/cc-timezone-monitor.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Kalev Lember <kalevlember gmail com>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __CC_TIMEZONE_MONITOR_H
+#define __CC_TIMEZONE_MONITOR_H
+
+#include <glib-object.h>
+#include "tz.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_TIMEZONE_MONITOR (cc_timezone_monitor_get_type ())
+#define CC_TIMEZONE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
CC_TYPE_TIMEZONE_MONITOR, CcTimezoneMonitor))
+#define CC_IS_TIMEZONE_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
CC_TYPE_TIMEZONE_MONITOR))
+#define CC_TIMEZONE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
CC_TYPE_TIMEZONE_MONITOR, CcTimezoneMonitorClass))
+#define CC_IS_TIMEZONE_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
CC_TYPE_TIMEZONE_MONITOR))
+#define CC_TIMEZONE_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
CC_TYPE_TIMEZONE_MONITOR, CcTimezoneMonitorClass))
+
+typedef struct _CcTimezoneMonitor CcTimezoneMonitor;
+typedef struct _CcTimezoneMonitorClass CcTimezoneMonitorClass;
+
+struct _CcTimezoneMonitor
+{
+ GObject parent_instance;
+};
+
+struct _CcTimezoneMonitorClass
+{
+ GObjectClass parent_class;
+
+ void (*timezone_changed) (CcTimezoneMonitor *monitor, TzLocation *new_tzlocation);
+};
+
+GType cc_timezone_monitor_get_type (void) G_GNUC_CONST;
+
+CcTimezoneMonitor *cc_timezone_monitor_new (void);
+
+G_END_DECLS
+
+#endif /* __CC_TIMEZONE_MONITOR_H */
diff --git a/gnome-initial-setup/pages/location/gis-location-page.c
b/gnome-initial-setup/pages/location/gis-location-page.c
index ee22b89..9876469 100644
--- a/gnome-initial-setup/pages/location/gis-location-page.c
+++ b/gnome-initial-setup/pages/location/gis-location-page.c
@@ -41,6 +41,7 @@
#include <libgweather/location-entry.h>
#include "cc-timezone-map.h"
+#include "cc-timezone-monitor.h"
#include "timedated.h"
#define GNOME_DESKTOP_USE_UNSTABLE_API
@@ -58,6 +59,8 @@ struct _GisLocationPagePrivate
Timedate1 *dtm;
GCancellable *cancellable;
+
+ CcTimezoneMonitor *timezone_monitor;
};
typedef struct _GisLocationPagePrivate GisLocationPagePrivate;
@@ -162,6 +165,24 @@ location_changed_cb (CcTimezoneMap *map,
}
static void
+timezone_changed_cb (CcTimezoneMonitor *timezone_monitor,
+ TzLocation *location,
+ GisLocationPage *page)
+{
+ GisLocationPagePrivate *priv = gis_location_page_get_instance_private (page);
+
+ g_debug ("timezone changed to %s/%s", location->country, location->zone);
+
+ priv->current_location = location;
+
+ cc_timezone_map_set_timezone (priv->map, location->zone);
+
+ update_timezone (page);
+
+ queue_set_timezone (page);
+}
+
+static void
set_location_from_gweather_location (GisLocationPage *page,
GWeatherLocation *gloc)
{
@@ -708,6 +729,11 @@ gis_location_page_constructed (GObject *object)
g_signal_connect (priv->clock_tracker, "notify::clock",
G_CALLBACK (clock_changed), page);
+ /* add automatic timezone */
+ priv->timezone_monitor = cc_timezone_monitor_new ();
+ g_signal_connect (priv->timezone_monitor, "timezone-changed",
+ G_CALLBACK (timezone_changed_cb), page);
+
update_time (page);
gis_page_set_complete (GIS_PAGE (page), TRUE);
@@ -723,6 +749,7 @@ gis_location_page_dispose (GObject *object)
g_clear_object (&priv->dtm);
g_clear_object (&priv->clock_tracker);
+ g_clear_object (&priv->timezone_monitor);
g_clear_pointer (&priv->date, g_date_time_unref);
if (priv->cancellable) {
g_cancellable_cancel (priv->cancellable);
diff --git a/gnome-initial-setup/pages/location/tz.c b/gnome-initial-setup/pages/location/tz.c
index c539d59..5465d32 100644
--- a/gnome-initial-setup/pages/location/tz.c
+++ b/gnome-initial-setup/pages/location/tz.c
@@ -131,7 +131,7 @@ tz_load_db (void)
return tz_db;
}
-static void
+void
tz_location_free (TzLocation *loc)
{
g_free (loc->country);
diff --git a/gnome-initial-setup/pages/location/tz.h b/gnome-initial-setup/pages/location/tz.h
index 71c1c23..7329233 100644
--- a/gnome-initial-setup/pages/location/tz.h
+++ b/gnome-initial-setup/pages/location/tz.h
@@ -78,6 +78,7 @@ char * tz_info_get_clean_name (TzDB *tz_db,
GPtrArray *tz_get_locations (TzDB *db);
void tz_location_get_position (TzLocation *loc,
double *longitude, double *latitude);
+void tz_location_free (TzLocation *loc);
char *tz_location_get_country (TzLocation *loc);
gchar *tz_location_get_zone (TzLocation *loc);
gchar *tz_location_get_comment (TzLocation *loc);
diff --git a/gnome-initial-setup/pages/location/weather-tz.c b/gnome-initial-setup/pages/location/weather-tz.c
new file mode 100644
index 0000000..2666846
--- /dev/null
+++ b/gnome-initial-setup/pages/location/weather-tz.c
@@ -0,0 +1,136 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Kalev Lember <kalevlember gmail com>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+
+#include "weather-tz.h"
+#include "tz.h"
+
+#define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
+#include <libgweather/gweather.h>
+
+struct _WeatherTzDB
+{
+ GList *tz_locations;
+};
+
+static GList *
+location_get_cities (GWeatherLocation *parent_location)
+{
+ GList *cities = NULL;
+ GWeatherLocation **children;
+ gint i;
+
+ children = gweather_location_get_children (parent_location);
+ for (i = 0; children[i]; i++) {
+ if (gweather_location_get_level (children[i]) == GWEATHER_LOCATION_CITY) {
+ cities = g_list_prepend (cities,
+ children[i]);
+ } else {
+ cities = g_list_concat (cities,
+ location_get_cities (children[i]));
+ }
+ }
+
+ return cities;
+}
+
+static gboolean
+weather_location_has_timezone (GWeatherLocation *loc)
+{
+ return gweather_location_get_timezone (loc) != NULL;
+}
+
+/**
+ * load_timezones:
+ * @cities: a list of #GWeatherLocation
+ *
+ * Returns: a list of #TzLocation
+ */
+static GList *
+load_timezones (GList *cities)
+{
+ GList *l;
+ GList *tz_locations = NULL;
+
+ for (l = cities; l; l = l->next) {
+ TzLocation *loc;
+ const gchar *country;
+ const gchar *timezone_id;
+ gdouble latitude;
+ gdouble longitude;
+
+ if (!gweather_location_has_coords (l->data) ||
+ !weather_location_has_timezone (l->data)) {
+ g_debug ("Incomplete GWeather location entry: (%s) %s",
+ gweather_location_get_country (l->data),
+ gweather_location_get_city_name (l->data));
+ continue;
+ }
+
+ country = gweather_location_get_country (l->data);
+ timezone_id = gweather_timezone_get_tzid (gweather_location_get_timezone (l->data));
+ gweather_location_get_coords (l->data,
+ &latitude,
+ &longitude);
+
+ loc = g_new0 (TzLocation, 1);
+ loc->country = g_strdup (country);
+ loc->latitude = latitude;
+ loc->longitude = longitude;
+ loc->zone = g_strdup (timezone_id);
+ loc->comment = NULL;
+
+ tz_locations = g_list_prepend (tz_locations, loc);
+ }
+
+ return tz_locations;
+}
+
+GList *
+weather_tz_db_get_locations (WeatherTzDB *tzdb)
+{
+ return g_list_copy (tzdb->tz_locations);
+}
+
+WeatherTzDB *
+weather_tz_db_new (void)
+{
+ GList *cities;
+ GWeatherLocation *world;
+ WeatherTzDB *tzdb;
+
+ world = gweather_location_get_world ();
+ cities = location_get_cities (world);
+
+ tzdb = g_new0 (WeatherTzDB, 1);
+ tzdb->tz_locations = load_timezones (cities);
+
+ g_list_free (cities);
+
+ return tzdb;
+}
+
+void
+weather_tz_db_free (WeatherTzDB *tzdb)
+{
+ g_list_free_full (tzdb->tz_locations, (GDestroyNotify) tz_location_free);
+
+ g_free (tzdb);
+}
diff --git a/gnome-initial-setup/pages/location/weather-tz.h b/gnome-initial-setup/pages/location/weather-tz.h
new file mode 100644
index 0000000..14de449
--- /dev/null
+++ b/gnome-initial-setup/pages/location/weather-tz.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Kalev Lember <kalevlember gmail com>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __WEATHER_TZ_H
+#define __WEATHER_TZ_H
+
+#include <glib.h>
+
+typedef struct _WeatherTzDB WeatherTzDB;
+
+WeatherTzDB *weather_tz_db_new (void);
+GList *weather_tz_db_get_locations (WeatherTzDB *db);
+void weather_tz_db_free (WeatherTzDB *db);
+
+#endif /* __WEATHER_TZ_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]