1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 
5 #include <dirent.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <time.h>
13 #include <unistd.h>
14 #include <math.h>
15 
16 #include <glib.h>
17 #include <gio/gio.h>
18 #include <gtk/gtk.h>
19 
20 #include "clock-location.h"
21 #include "clock-marshallers.h"
22 #include "set-timezone.h"
23 #include "system-timezone.h"
24 
25 typedef struct {
26         gchar *name;
27         gchar *city;
28 
29         SystemTimezone *systz;
30 
31         gchar *timezone;
32 
33         gchar *tzname;
34 
35         gfloat latitude;
36         gfloat longitude;
37 
38         gchar *weather_code;
39         WeatherInfo *weather_info;
40         guint weather_timeout;
41         guint weather_retry_time;
42 
43         TempUnit temperature_unit;
44         SpeedUnit speed_unit;
45 } ClockLocationPrivate;
46 
47 G_DEFINE_TYPE_WITH_PRIVATE (ClockLocation, clock_location, G_TYPE_OBJECT)
48 
49 #define WEATHER_TIMEOUT_BASE 30
50 #define WEATHER_TIMEOUT_MAX  1800
51 #define WEATHER_EMPTY_CODE   "-"
52 
53 enum {
54         WEATHER_UPDATED,
55         SET_CURRENT,
56         LAST_SIGNAL
57 };
58 
59 static guint location_signals[LAST_SIGNAL] = { 0 };
60 
61 static void clock_location_finalize (GObject *);
62 static void clock_location_set_tz (ClockLocation *this);
63 static void clock_location_unset_tz (ClockLocation *this);
64 static gboolean update_weather_info (gpointer data);
65 static void setup_weather_updates (ClockLocation *loc);
66 
67 static gchar *clock_location_get_valid_weather_code (const gchar *code);
68 
69 ClockLocation *
clock_location_find_and_ref(GSList * locations,const gchar * name,const gchar * city,const gchar * timezone,gfloat latitude,gfloat longitude,const gchar * code)70 clock_location_find_and_ref (GSList       *locations,
71                              const gchar *name,
72                              const gchar *city,
73                              const gchar *timezone,
74                              gfloat       latitude,
75                              gfloat       longitude,
76                              const gchar *code)
77 {
78         GSList *l;
79 
80         for (l = locations; l != NULL; l = l->next) {
81 
82                 ClockLocationPrivate *priv =
83                         clock_location_get_instance_private (l->data);
84 
85                 if (priv->latitude == latitude &&
86                     priv->longitude == longitude &&
87                     g_strcmp0 (priv->weather_code, code) == 0 &&
88                     g_strcmp0 (priv->timezone, timezone) == 0 &&
89                     g_strcmp0 (priv->city, city) == 0 &&
90                     g_strcmp0 (priv->name, name) == 0)
91                         break;
92         }
93 
94         if (l != NULL)
95                 return CLOCK_LOCATION (l->data);
96         else
97                 return NULL;
98 }
99 
100 ClockLocation *
clock_location_new(const gchar * name,const gchar * city,const gchar * timezone,gfloat latitude,gfloat longitude,const gchar * code,WeatherPrefs * prefs)101 clock_location_new (const gchar *name, const gchar *city,
102                     const gchar *timezone,
103                     gfloat latitude, gfloat longitude,
104                     const gchar *code, WeatherPrefs *prefs)
105 {
106         ClockLocation *this;
107         ClockLocationPrivate *priv;
108 
109         this = g_object_new (CLOCK_LOCATION_TYPE, NULL);
110         priv = clock_location_get_instance_private (this);
111 
112         priv->name = g_strdup (name);
113         priv->city = g_strdup (city);
114         priv->timezone = g_strdup (timezone);
115 
116         /* initialize priv->tzname */
117         clock_location_set_tz (this);
118         clock_location_unset_tz (this);
119 
120         priv->latitude = latitude;
121         priv->longitude = longitude;
122 
123         priv->weather_code = clock_location_get_valid_weather_code (code);
124 
125         if (prefs) {
126                 priv->temperature_unit = prefs->temperature_unit;
127                 priv->speed_unit = prefs->speed_unit;
128         }
129 
130         setup_weather_updates (this);
131 
132         return this;
133 }
134 
135 static ClockLocation *current_location = NULL;
136 
137 static void
clock_location_class_init(ClockLocationClass * this_class)138 clock_location_class_init (ClockLocationClass *this_class)
139 {
140         GObjectClass *g_obj_class = G_OBJECT_CLASS (this_class);
141 
142         g_obj_class->finalize = clock_location_finalize;
143 
144         location_signals[WEATHER_UPDATED] =
145                 g_signal_new ("weather-updated",
146                               G_OBJECT_CLASS_TYPE (g_obj_class),
147                               G_SIGNAL_RUN_FIRST,
148                               G_STRUCT_OFFSET (ClockLocationClass, weather_updated),
149                               NULL, NULL,
150                               g_cclosure_marshal_VOID__POINTER,
151                               G_TYPE_NONE, 1, G_TYPE_POINTER);
152 
153         location_signals[SET_CURRENT] =
154                 g_signal_new ("set-current",
155                               G_OBJECT_CLASS_TYPE (g_obj_class),
156                               G_SIGNAL_RUN_FIRST,
157                               G_STRUCT_OFFSET (ClockLocationClass, set_current),
158                               NULL, NULL,
159                               g_cclosure_marshal_VOID__VOID,
160                               G_TYPE_NONE, 0);
161 }
162 
163 static void
network_changed(GNetworkMonitor * monitor,gboolean available,ClockLocation * loc)164 network_changed (GNetworkMonitor *monitor,
165                  gboolean         available,
166                  ClockLocation   *loc)
167 {
168         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
169 
170         if (available) {
171                 priv->weather_retry_time = WEATHER_TIMEOUT_BASE;
172                 update_weather_info (loc);
173         }
174 }
175 
176 static void
clock_location_init(ClockLocation * this)177 clock_location_init (ClockLocation *this)
178 {
179         ClockLocationPrivate *priv = clock_location_get_instance_private (this);
180         GNetworkMonitor *monitor;
181 
182         priv->name = NULL;
183         priv->city = NULL;
184 
185         priv->systz = system_timezone_new ();
186 
187         priv->timezone = NULL;
188 
189         priv->tzname = NULL;
190 
191         priv->latitude = 0;
192         priv->longitude = 0;
193 
194         monitor = g_network_monitor_get_default();
195         g_signal_connect (monitor, "network-changed",
196                           G_CALLBACK (network_changed), this);
197 
198         priv->temperature_unit = TEMP_UNIT_CENTIGRADE;
199         priv->speed_unit = SPEED_UNIT_MS;
200 }
201 
202 static void
clock_location_finalize(GObject * g_obj)203 clock_location_finalize (GObject *g_obj)
204 {
205         ClockLocationPrivate *priv = clock_location_get_instance_private (CLOCK_LOCATION(g_obj));
206         GNetworkMonitor      *monitor;
207 
208         monitor = g_network_monitor_get_default ();
209         g_signal_handlers_disconnect_by_func (monitor,
210                                               G_CALLBACK (network_changed),
211                                               CLOCK_LOCATION (g_obj));
212 
213         g_free (priv->name);
214         g_free (priv->city);
215 
216         if (priv->systz) {
217                 g_object_unref (priv->systz);
218                 priv->systz = NULL;
219         }
220 
221         g_free (priv->timezone);
222         g_free (priv->tzname);
223         g_free (priv->weather_code);
224 
225         if (priv->weather_info) {
226                 weather_info_free (priv->weather_info);
227                 priv->weather_info = NULL;
228         }
229 
230         if (priv->weather_timeout) {
231                 g_source_remove (priv->weather_timeout);
232                 priv->weather_timeout = 0;
233         }
234 
235         G_OBJECT_CLASS (clock_location_parent_class)->finalize (g_obj);
236 }
237 
238 const gchar *
clock_location_get_display_name(ClockLocation * loc)239 clock_location_get_display_name (ClockLocation *loc)
240 {
241         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
242 
243         if (priv->name && priv->name[0])
244                 return priv->name;
245         else
246                 return priv->city;
247 }
248 
249 const gchar *
clock_location_get_name(ClockLocation * loc)250 clock_location_get_name (ClockLocation *loc)
251 {
252         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
253 
254         return priv->name;
255 }
256 
257 void
clock_location_set_name(ClockLocation * loc,const gchar * name)258 clock_location_set_name (ClockLocation *loc, const gchar *name)
259 {
260         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
261 
262         g_free (priv->name);
263         priv->name = g_strdup (name);
264 }
265 
266 const gchar *
clock_location_get_city(ClockLocation * loc)267 clock_location_get_city (ClockLocation *loc)
268 {
269         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
270 
271         return priv->city;
272 }
273 
274 void
clock_location_set_city(ClockLocation * loc,const gchar * city)275 clock_location_set_city (ClockLocation *loc, const gchar *city)
276 {
277         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
278 
279         g_free (priv->city);
280         priv->city = g_strdup (city);
281 }
282 
283 gchar *
clock_location_get_timezone(ClockLocation * loc)284 clock_location_get_timezone (ClockLocation *loc)
285 {
286         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
287 
288         return priv->timezone;
289 }
290 
291 void
clock_location_set_timezone(ClockLocation * loc,const gchar * timezone)292 clock_location_set_timezone (ClockLocation *loc, const gchar *timezone)
293 {
294         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
295 
296         g_free (priv->timezone);
297         priv->timezone = g_strdup (timezone);
298 }
299 
300 gchar *
clock_location_get_tzname(ClockLocation * loc)301 clock_location_get_tzname (ClockLocation *loc)
302 {
303         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
304 
305         return priv->tzname;
306 }
307 
308 void
clock_location_get_coords(ClockLocation * loc,gfloat * latitude,gfloat * longitude)309 clock_location_get_coords (ClockLocation *loc, gfloat *latitude,
310                                gfloat *longitude)
311 {
312         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
313 
314         *latitude = priv->latitude;
315         *longitude = priv->longitude;
316 }
317 
318 void
clock_location_set_coords(ClockLocation * loc,gfloat latitude,gfloat longitude)319 clock_location_set_coords (ClockLocation *loc, gfloat latitude,
320                                gfloat longitude)
321 {
322         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
323 
324         priv->latitude = latitude;
325         priv->longitude = longitude;
326 }
327 
328 static void
clock_location_set_tzname(ClockLocation * this,const char * tzname)329 clock_location_set_tzname (ClockLocation *this, const char *tzname)
330 {
331         ClockLocationPrivate *priv = clock_location_get_instance_private (CLOCK_LOCATION(this));
332 
333         if (priv->tzname && strcmp (priv->tzname, tzname) == 0)
334                 return;
335 
336         g_free (priv->tzname);
337         if (tzname && *tzname != '\0') {
338                 priv->tzname = g_strdup (tzname);
339         } else {
340                 priv->tzname = NULL;
341         }
342 }
343 
344 static void
clock_location_set_tz(ClockLocation * this)345 clock_location_set_tz (ClockLocation *this)
346 {
347         ClockLocationPrivate *priv = clock_location_get_instance_private (this);
348 
349         time_t now_t;
350         struct tm now;
351 
352         if (priv->timezone == NULL) {
353                 return;
354         }
355 
356         setenv ("TZ", priv->timezone, 1);
357         tzset();
358 
359         now_t = time (NULL);
360         localtime_r (&now_t, &now);
361 
362         if (now.tm_isdst > 0) {
363                 clock_location_set_tzname (this, tzname[1]);
364         } else {
365                 clock_location_set_tzname (this, tzname[0]);
366         }
367 }
368 
369 static void
clock_location_unset_tz(ClockLocation * this)370 clock_location_unset_tz (ClockLocation *this)
371 {
372         ClockLocationPrivate *priv = clock_location_get_instance_private (this);
373         const char *env_timezone;
374 
375         if (priv->timezone == NULL) {
376                 return;
377         }
378 
379         env_timezone = system_timezone_get_env (priv->systz);
380 
381         if (env_timezone) {
382                 setenv ("TZ", env_timezone, 1);
383         } else {
384                 unsetenv ("TZ");
385         }
386         tzset();
387 }
388 
389 void
clock_location_localtime(ClockLocation * loc,struct tm * tm)390 clock_location_localtime (ClockLocation *loc, struct tm *tm)
391 {
392         time_t now;
393 
394         clock_location_set_tz (loc);
395 
396         time (&now);
397         localtime_r (&now, tm);
398 
399         clock_location_unset_tz (loc);
400 }
401 
402 gboolean
clock_location_is_current_timezone(ClockLocation * loc)403 clock_location_is_current_timezone (ClockLocation *loc)
404 {
405         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
406         const char *zone;
407 
408         zone = system_timezone_get (priv->systz);
409 
410         if (zone)
411                 return strcmp (zone, priv->timezone) == 0;
412         else
413                 return clock_location_get_offset (loc) == 0;
414 }
415 
416 gboolean
clock_location_is_current(ClockLocation * loc)417 clock_location_is_current (ClockLocation *loc)
418 {
419         if (current_location == loc)
420                 return TRUE;
421         else if (current_location != NULL)
422                 return FALSE;
423 
424         if (clock_location_is_current_timezone (loc)) {
425                 /* Note that some code in clock.c depends on the fact that
426                  * calling this function can set the current location if
427                  * there's none */
428                 current_location = loc;
429                 g_object_add_weak_pointer (G_OBJECT (current_location),
430                                            (gpointer *)&current_location);
431                 g_signal_emit (current_location, location_signals[SET_CURRENT],
432                                0, NULL);
433 
434                 return TRUE;
435         }
436 
437         return FALSE;
438 }
439 
440 
441 glong
clock_location_get_offset(ClockLocation * loc)442 clock_location_get_offset (ClockLocation *loc)
443 {
444         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
445         glong sys_timezone, local_timezone;
446         glong offset;
447         time_t t;
448         struct tm *tm;
449 
450         t = time (NULL);
451 
452         unsetenv ("TZ");
453         tm = localtime (&t);
454         sys_timezone = timezone;
455 
456         if (tm->tm_isdst > 0) {
457                 sys_timezone -= 3600;
458         }
459 
460         setenv ("TZ", priv->timezone, 1);
461         tm = localtime (&t);
462         local_timezone = timezone;
463 
464         if (tm->tm_isdst > 0) {
465                 local_timezone -= 3600;
466         }
467 
468         offset = local_timezone - sys_timezone;
469 
470         clock_location_unset_tz (loc);
471 
472         return offset;
473 }
474 
475 typedef struct {
476         ClockLocation *location;
477         GFunc callback;
478         gpointer data;
479         GDestroyNotify destroy;
480 } MakeCurrentData;
481 
482 static void
make_current_cb(gpointer data,GError * error)483 make_current_cb (gpointer data, GError *error)
484 {
485         MakeCurrentData *mcdata = data;
486 
487         if (error == NULL) {
488                 if (current_location)
489                         g_object_remove_weak_pointer (G_OBJECT (current_location),
490                                                       (gpointer *)&current_location);
491                 current_location = mcdata->location;
492                 g_object_add_weak_pointer (G_OBJECT (current_location),
493                                            (gpointer *)&current_location);
494                 g_signal_emit (current_location, location_signals[SET_CURRENT],
495                                0, NULL);
496         }
497 
498         if (mcdata->callback)
499                 mcdata->callback (mcdata->data, error);
500 }
501 
502 static void
free_make_current_data(gpointer data)503 free_make_current_data (gpointer data)
504 {
505         MakeCurrentData *mcdata = data;
506 
507         if (mcdata->destroy)
508                 mcdata->destroy (mcdata->data);
509 
510         g_object_unref (mcdata->location);
511         g_free (mcdata);
512 }
513 
514 void
clock_location_make_current(ClockLocation * loc,GFunc callback,gpointer data,GDestroyNotify destroy)515 clock_location_make_current (ClockLocation *loc,
516                              GFunc          callback,
517                              gpointer       data,
518                              GDestroyNotify destroy)
519 {
520         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
521         gchar *filename;
522         MakeCurrentData *mcdata;
523 
524         if (loc == current_location) {
525                 if (destroy)
526                         destroy (data);
527                 return;
528         }
529 
530         if (clock_location_is_current_timezone (loc)) {
531                 if (current_location)
532                         g_object_remove_weak_pointer (G_OBJECT (current_location),
533                                                       (gpointer *)&current_location);
534                 current_location = loc;
535                 g_object_add_weak_pointer (G_OBJECT (current_location),
536                                            (gpointer *)&current_location);
537                 g_signal_emit (current_location, location_signals[SET_CURRENT],
538                                0, NULL);
539                 if (callback)
540                                callback (data, NULL);
541                 if (destroy)
542                         destroy (data);
543                 return;
544         }
545 
546         mcdata = g_new (MakeCurrentData, 1);
547 
548         mcdata->location = g_object_ref (loc);
549         mcdata->callback = callback;
550         mcdata->data = data;
551         mcdata->destroy = destroy;
552 
553         filename = g_build_filename (SYSTEM_ZONEINFODIR, priv->timezone, NULL);
554         set_system_timezone_async (filename,
555                                    (GFunc)make_current_cb,
556                                    mcdata,
557                                    free_make_current_data);
558         g_free (filename);
559 }
560 
561 static gchar *
clock_location_get_valid_weather_code(const gchar * code)562 clock_location_get_valid_weather_code (const gchar *code)
563 {
564         if (!code || *code == '\0')
565                 return g_strdup (WEATHER_EMPTY_CODE);
566         else
567                 return g_strdup (code);
568 }
569 
570 const gchar *
clock_location_get_weather_code(ClockLocation * loc)571 clock_location_get_weather_code (ClockLocation *loc)
572 {
573         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
574 
575         return priv->weather_code;
576 }
577 
578 void
clock_location_set_weather_code(ClockLocation * loc,const gchar * code)579 clock_location_set_weather_code (ClockLocation *loc, const gchar *code)
580 {
581         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
582 
583         g_free (priv->weather_code);
584         priv->weather_code = clock_location_get_valid_weather_code (code);
585 
586         setup_weather_updates (loc);
587 }
588 
589 WeatherInfo *
clock_location_get_weather_info(ClockLocation * loc)590 clock_location_get_weather_info (ClockLocation *loc)
591 {
592         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
593 
594         return priv->weather_info;
595 }
596 
597 static void
set_weather_update_timeout(ClockLocation * loc)598 set_weather_update_timeout (ClockLocation *loc)
599 {
600         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
601         guint timeout;
602 
603         if (!weather_info_network_error (priv->weather_info)) {
604                 /* The last update succeeded; set the next update to
605                  * happen in half an hour, and reset the retry timer.
606                  */
607                 timeout = WEATHER_TIMEOUT_MAX;
608                 priv->weather_retry_time = WEATHER_TIMEOUT_BASE;
609         } else {
610                 /* The last update failed; set the next update
611                  * according to the retry timer, and exponentially
612                  * back off the retry timer.
613                  */
614                 timeout = priv->weather_retry_time;
615                 priv->weather_retry_time *= 2;
616                 if (priv->weather_retry_time > WEATHER_TIMEOUT_MAX)
617                         priv->weather_retry_time = WEATHER_TIMEOUT_MAX;
618         }
619 
620         if (priv->weather_timeout)
621                 g_source_remove (priv->weather_timeout);
622         priv->weather_timeout =
623                 g_timeout_add_seconds (timeout, update_weather_info, loc);
624 }
625 
626 static void
weather_info_updated(WeatherInfo * info,gpointer data)627 weather_info_updated (WeatherInfo *info, gpointer data)
628 {
629         ClockLocation *loc = data;
630         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
631 
632         set_weather_update_timeout (loc);
633         g_signal_emit (loc, location_signals[WEATHER_UPDATED],
634                        0, priv->weather_info);
635 }
636 
637 static gboolean
update_weather_info(gpointer data)638 update_weather_info (gpointer data)
639 {
640         ClockLocation *loc = (ClockLocation *) data;
641         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
642         WeatherPrefs prefs = {
643                 FORECAST_STATE,
644                 FALSE,
645                 NULL,
646                 TEMP_UNIT_CENTIGRADE,
647                 SPEED_UNIT_MS,
648                 PRESSURE_UNIT_MB,
649                 DISTANCE_UNIT_KM
650         };
651 
652         /* set temperature and speed units only if different from
653          * invalid/default
654          */
655         if (priv->temperature_unit > TEMP_UNIT_DEFAULT)
656                 prefs.temperature_unit = priv->temperature_unit;
657         if (priv->speed_unit > SPEED_UNIT_DEFAULT)
658                 prefs.speed_unit = priv->speed_unit;
659 
660         weather_info_abort (priv->weather_info);
661         weather_info_update (priv->weather_info,
662                              &prefs, weather_info_updated, loc);
663 
664         return TRUE;
665 }
666 
667 static gchar *
rad2dms(gfloat lat,gfloat lon)668 rad2dms (gfloat lat, gfloat lon)
669 {
670         gchar h, h2;
671         gfloat d, deg, min, d2, deg2, min2;
672 
673         h = lat > 0 ? 'N' : 'S';
674         d = fabs (lat);
675         deg = floor (d);
676         min = floor (60 * (d - deg));
677         h2 = lon > 0 ? 'E' : 'W';
678         d2 = fabs (lon);
679         deg2 = floor (d2);
680         min2 = floor (60 * (d2 - deg2));
681         return g_strdup_printf ("%02d-%02d%c %02d-%02d%c",
682                                 (int)deg, (int)min, h,
683                                 (int)deg2, (int)min2, h2);
684 }
685 
686 static void
setup_weather_updates(ClockLocation * loc)687 setup_weather_updates (ClockLocation *loc)
688 {
689         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
690         WeatherLocation *wl;
691         WeatherPrefs prefs = {
692                 FORECAST_STATE,
693                 FALSE,
694                 NULL,
695                 TEMP_UNIT_CENTIGRADE,
696                 SPEED_UNIT_MS,
697                 PRESSURE_UNIT_MB,
698                 DISTANCE_UNIT_KM
699         };
700 
701         gchar *dms;
702 
703         prefs.temperature_unit = priv->temperature_unit;
704         prefs.speed_unit = priv->speed_unit;
705 
706         if (priv->weather_info) {
707                 weather_info_free (priv->weather_info);
708                 priv->weather_info = NULL;
709         }
710 
711         if (priv->weather_timeout) {
712                 g_source_remove (priv->weather_timeout);
713                 priv->weather_timeout = 0;
714         }
715 
716         if (!priv->weather_code ||
717             strcmp (priv->weather_code, WEATHER_EMPTY_CODE) == 0)
718                 return;
719 
720         dms = rad2dms (priv->latitude, priv->longitude);
721         wl = weather_location_new (priv->city, priv->weather_code,
722                                    NULL, NULL, dms, NULL, NULL);
723 
724         priv->weather_info =
725                 weather_info_new (wl, &prefs, weather_info_updated, loc);
726 
727         set_weather_update_timeout (loc);
728 
729         weather_location_free (wl);
730         g_free (dms);
731 }
732 
733 void
clock_location_set_weather_prefs(ClockLocation * loc,WeatherPrefs * prefs)734 clock_location_set_weather_prefs (ClockLocation *loc,
735                                   WeatherPrefs *prefs)
736 {
737         ClockLocationPrivate *priv = clock_location_get_instance_private (loc);
738 
739         priv->temperature_unit = prefs->temperature_unit;
740         priv->speed_unit = prefs->speed_unit;
741 
742         update_weather_info (loc);
743 }
744 
745