Merge lp:~charlesk/indicator-datetime/make-timezones-and-clock-mockable into lp:indicator-datetime/14.04

Proposed by Charles Kerr
Status: Merged
Approved by: Charles Kerr
Approved revision: 287
Merged at revision: 278
Proposed branch: lp:~charlesk/indicator-datetime/make-timezones-and-clock-mockable
Merge into: lp:indicator-datetime/14.04
Diff against target: 1362 lines (+751/-231)
9 files modified
src/Makefile.am (+4/-2)
src/clock-live.c (+281/-0)
src/clock-live.h (+73/-0)
src/clock.c (+110/-0)
src/clock.h (+76/-0)
src/main.c (+9/-34)
src/service.c (+191/-190)
src/service.h (+7/-3)
src/timezone.h (+0/-2)
To merge this branch: bzr merge lp:~charlesk/indicator-datetime/make-timezones-and-clock-mockable
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Ted Gould (community) Approve
Review via email: mp+192174@code.launchpad.net

Commit message

Make timezone detection and localtime mockable.

Description of the change

This is step 1 of work to increase test coverage in indicator-datetime for bug #1237509. This step decouples some datetime's code to make unit tests possible, step 2 switches the build system to cmake, and step 3 adds the tests.

Changes in this MP:

1. Make an IndicatorDatetimeClock interface that provides localtime and timezone information to its users.

2. IndicatorDatetimeService now takes a clock in its constructor rather than instantiating one internally. This way we can pass it a live clock in production or a fake one in testing.

3. In main(), instantiate a live clock and pass it to the service

4. In main(), remove the last-minute appointment/alarm testing hacks that were added for 13.10. Move IndicatorDatetimePlannerMock to the tests/ subdirectory for future use by "make check"

5. Cache a couple of variables in IndicatorDatetimeClock and IndicatorDatetimeService: the const strv of timezones returned by indicator_datetime_clock_get_timezones(), the time format string used by the desktop header's action state, some GVariants used by the service when building action states.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ted Gould (ted) wrote :

Don't see anything. Realize this is a MR-series in progress so I won't comment on the lack of tests :-)

One little thing:

1226 + properties[PROP_CLOCK] = g_param_spec_object ("clock",
1227 + "Clock",
1228 + "The clock",
1229 + G_TYPE_OBJECT,
1230 + flags);

Should probably be INDICATOR_TYPE_DATETIME_CLOCK instead of G_TYPE_OBJECT, no reason to not be more specific.

review: Approve
Revision history for this message
Charles Kerr (charlesk) wrote :

You can't make a g_param_spec for an interface because the object won't know how to memory manage it. So you require it to be a GObject that implements the interface s.t. IndicatorDatetimeService can use g_object_ref / g_object_unref().

Revision history for this message
Charles Kerr (charlesk) wrote :

Actually, you're right. That's possible once the G_TYPE_INDICATOR_DATETIME has specified GObject as a prerequisite.

Fixed r286

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
287. By Charles Kerr

instead of keeping IndicatorDatetimeTimezone objects in separate fields, keep them in a list so they can be handled in a loop.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Makefile.am'
2--- src/Makefile.am 2013-10-10 02:31:13 +0000
3+++ src/Makefile.am 2013-10-23 18:14:52 +0000
4@@ -18,10 +18,12 @@
5 $(SHARED_CFLAGS)
6
7 libindicator_datetime_service_a_SOURCES = \
8+ clock.c \
9+ clock.h \
10+ clock-live.c \
11+ clock-live.h \
12 planner.c \
13 planner.h \
14- planner-mock.c \
15- planner-mock.h \
16 planner-eds.c \
17 planner-eds.h \
18 service.c \
19
20=== added file 'src/clock-live.c'
21--- src/clock-live.c 1970-01-01 00:00:00 +0000
22+++ src/clock-live.c 2013-10-23 18:14:52 +0000
23@@ -0,0 +1,281 @@
24+/*
25+ * Copyright 2013 Canonical Ltd.
26+ *
27+ * Authors:
28+ * Charles Kerr <charles.kerr@canonical.com>
29+ *
30+ * This program is free software: you can redistribute it and/or modify it
31+ * under the terms of the GNU General Public License version 3, as published
32+ * by the Free Software Foundation.
33+ *
34+ * This program is distributed in the hope that it will be useful, but
35+ * WITHOUT ANY WARRANTY; without even the implied warranties of
36+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
37+ * PURPOSE. See the GNU General Public License for more details.
38+ *
39+ * You should have received a copy of the GNU General Public License along
40+ * with this program. If not, see <http://www.gnu.org/licenses/>.
41+ */
42+
43+#include <glib.h>
44+#include <gio/gio.h>
45+
46+#include "config.h"
47+
48+#include "clock-live.h"
49+#include "settings-shared.h"
50+#include "timezone-file.h"
51+#include "timezone-geoclue.h"
52+
53+/***
54+**** private struct
55+***/
56+
57+struct _IndicatorDatetimeClockLivePriv
58+{
59+ GSettings * settings;
60+
61+ GSList * timezones; /* IndicatorDatetimeTimezone */
62+ gchar ** timezones_strv;
63+ GTimeZone * localtime_zone;
64+};
65+
66+typedef IndicatorDatetimeClockLivePriv priv_t;
67+
68+/***
69+**** GObject boilerplate
70+***/
71+
72+static void indicator_datetime_clock_interface_init (
73+ IndicatorDatetimeClockInterface * iface);
74+
75+G_DEFINE_TYPE_WITH_CODE (
76+ IndicatorDatetimeClockLive,
77+ indicator_datetime_clock_live,
78+ G_TYPE_OBJECT,
79+ G_IMPLEMENT_INTERFACE (INDICATOR_TYPE_DATETIME_CLOCK,
80+ indicator_datetime_clock_interface_init));
81+
82+/***
83+**** Timezones
84+***/
85+
86+static void
87+on_current_timezone_changed (IndicatorDatetimeClockLive * self)
88+{
89+ priv_t * p = self->priv;
90+
91+ /* Invalidate the timezone information.
92+ These fields will be lazily regenerated by rebuild_timezones() */
93+ g_clear_pointer (&p->timezones_strv, g_strfreev);
94+ g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
95+
96+ indicator_datetime_clock_emit_changed (INDICATOR_DATETIME_CLOCK (self));
97+}
98+
99+static void
100+set_detect_location_enabled (IndicatorDatetimeClockLive * self, gboolean enabled)
101+{
102+ GSList * l;
103+ priv_t * p = self->priv;
104+ gboolean changed = FALSE;
105+
106+ /* clear out the old timezone objects */
107+ if (p->timezones != NULL)
108+ {
109+ for (l=p->timezones; l!=NULL; l=l->next)
110+ {
111+ g_signal_handlers_disconnect_by_func (l->data, on_current_timezone_changed, self);
112+ g_object_unref (l->data);
113+ }
114+
115+ g_slist_free (p->timezones);
116+ p->timezones = NULL;
117+ changed = TRUE;
118+ }
119+
120+ /* maybe add new timezone objects */
121+ if (enabled)
122+ {
123+ p->timezones = g_slist_append (p->timezones, indicator_datetime_timezone_geoclue_new ());
124+ p->timezones = g_slist_append (p->timezones, indicator_datetime_timezone_file_new (TIMEZONE_FILE));
125+
126+ for (l=p->timezones; l!=NULL; l=l->next)
127+ {
128+ g_signal_connect_swapped (l->data, "notify::timezone",
129+ G_CALLBACK(on_current_timezone_changed), self);
130+ }
131+
132+ changed = TRUE;
133+ }
134+
135+ if (changed)
136+ on_current_timezone_changed (self);
137+}
138+
139+/* When the 'auto-detect timezone' boolean setting changes,
140+ start or stop watching geoclue and /etc/timezone */
141+static void
142+on_detect_location_changed (IndicatorDatetimeClockLive * self)
143+{
144+ const gboolean enabled = g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_DETECTED_S);
145+ set_detect_location_enabled (self, enabled);
146+}
147+
148+/***
149+**** IndicatorDatetimeClock virtual functions
150+***/
151+
152+static void
153+rebuild_timezones (IndicatorDatetimeClockLive * self)
154+{
155+ priv_t * p;
156+ GHashTable * hash;
157+ GSList * l;
158+ int i;
159+ GHashTableIter iter;
160+ gpointer key;
161+
162+ p = self->priv;
163+
164+ /* Build a hashtable of timezone strings.
165+ This will weed out duplicates. */
166+ hash = g_hash_table_new (g_str_hash, g_str_equal);
167+ for (l=p->timezones; l!=NULL; l=l->next)
168+ {
169+ const gchar * tz = indicator_datetime_timezone_get_timezone (l->data);
170+ if (tz && *tz)
171+ g_hash_table_add (hash, (gpointer) tz);
172+ }
173+
174+ /* rebuild p->timezone_strv */
175+ g_strfreev (p->timezones_strv);
176+ p->timezones_strv = g_new0 (gchar*, g_hash_table_size(hash) + 1);
177+ i = 0;
178+ g_hash_table_iter_init (&iter, hash);
179+ while (g_hash_table_iter_next (&iter, &key, NULL))
180+ p->timezones_strv[i++] = g_strdup (key);
181+
182+ /* rebuild localtime_zone */
183+ g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
184+ p->localtime_zone = g_time_zone_new (p->timezones_strv ? p->timezones_strv[0] : NULL);
185+
186+ /* cleanup */
187+ g_hash_table_unref (hash);
188+}
189+
190+static const gchar **
191+my_get_timezones (IndicatorDatetimeClock * clock)
192+{
193+ IndicatorDatetimeClockLive * self = INDICATOR_DATETIME_CLOCK_LIVE (clock);
194+ priv_t * p = self->priv;
195+
196+ if (G_UNLIKELY (p->timezones_strv == NULL))
197+ rebuild_timezones (self);
198+
199+ return (const gchar **) p->timezones_strv;
200+}
201+
202+static GDateTime *
203+my_get_localtime (IndicatorDatetimeClock * clock)
204+{
205+ IndicatorDatetimeClockLive * self = INDICATOR_DATETIME_CLOCK_LIVE (clock);
206+ priv_t * p = self->priv;
207+
208+ if (G_UNLIKELY (p->localtime_zone == NULL))
209+ rebuild_timezones (self);
210+
211+ return g_date_time_new_now (p->localtime_zone);
212+}
213+
214+/***
215+**** GObject virtual functions
216+***/
217+
218+static void
219+my_dispose (GObject * o)
220+{
221+ IndicatorDatetimeClockLive * self;
222+ priv_t * p;
223+
224+ self = INDICATOR_DATETIME_CLOCK_LIVE(o);
225+ p = self->priv;
226+
227+ if (p->settings != NULL)
228+ {
229+ g_signal_handlers_disconnect_by_data (p->settings, self);
230+ g_clear_object (&p->settings);
231+ }
232+
233+ set_detect_location_enabled (self, FALSE);
234+
235+ G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o);
236+}
237+
238+static void
239+my_finalize (GObject * o)
240+{
241+ IndicatorDatetimeClockLive * self;
242+ priv_t * p;
243+
244+ self = INDICATOR_DATETIME_CLOCK_LIVE(o);
245+ p = self->priv;
246+
247+ g_clear_pointer (&p->localtime_zone, g_time_zone_unref);
248+ g_strfreev (p->timezones_strv);
249+
250+ G_OBJECT_CLASS (indicator_datetime_clock_live_parent_class)->dispose (o);
251+}
252+
253+/***
254+**** Instantiation
255+***/
256+
257+static void
258+indicator_datetime_clock_live_class_init (IndicatorDatetimeClockLiveClass * klass)
259+{
260+ GObjectClass * object_class = G_OBJECT_CLASS (klass);
261+
262+ object_class->dispose = my_dispose;
263+ object_class->finalize = my_finalize;
264+
265+ g_type_class_add_private (klass,
266+ sizeof (IndicatorDatetimeClockLivePriv));
267+}
268+
269+static void
270+indicator_datetime_clock_interface_init (IndicatorDatetimeClockInterface * iface)
271+{
272+ iface->get_localtime = my_get_localtime;
273+ iface->get_timezones = my_get_timezones;
274+}
275+
276+static void
277+indicator_datetime_clock_live_init (IndicatorDatetimeClockLive * self)
278+{
279+ IndicatorDatetimeClockLivePriv * p;
280+
281+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
282+ INDICATOR_TYPE_DATETIME_CLOCK_LIVE,
283+ IndicatorDatetimeClockLivePriv);
284+ self->priv = p;
285+
286+ p->settings = g_settings_new (SETTINGS_INTERFACE);
287+ g_signal_connect (p->settings, "changed::" SETTINGS_SHOW_DETECTED_S,
288+ G_CALLBACK(on_detect_location_changed), self);
289+
290+
291+ on_detect_location_changed (self);
292+}
293+
294+/***
295+**** Public API
296+***/
297+
298+IndicatorDatetimeClock *
299+indicator_datetime_clock_live_new (void)
300+{
301+ gpointer o = g_object_new (INDICATOR_TYPE_DATETIME_CLOCK_LIVE, NULL);
302+
303+ return INDICATOR_DATETIME_CLOCK (o);
304+}
305
306=== added file 'src/clock-live.h'
307--- src/clock-live.h 1970-01-01 00:00:00 +0000
308+++ src/clock-live.h 2013-10-23 18:14:52 +0000
309@@ -0,0 +1,73 @@
310+/*
311+ * Copyright 2013 Canonical Ltd.
312+ *
313+ * Authors:
314+ * Charles Kerr <charles.kerr@canonical.com>
315+ *
316+ * This program is free software: you can redistribute it and/or modify it
317+ * under the terms of the GNU General Public License version 3, as published
318+ * by the Free Software Foundation.
319+ *
320+ * This program is distributed in the hope that it will be useful, but
321+ * WITHOUT ANY WARRANTY; without even the implied warranties of
322+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
323+ * PURPOSE. See the GNU General Public License for more details.
324+ *
325+ * You should have received a copy of the GNU General Public License along
326+ * with this program. If not, see <http://www.gnu.org/licenses/>.
327+ */
328+
329+#ifndef __INDICATOR_DATETIME_CLOCK_LIVE__H__
330+#define __INDICATOR_DATETIME_CLOCK_LIVE__H__
331+
332+#include <glib-object.h> /* parent class */
333+
334+#include "clock.h"
335+
336+G_BEGIN_DECLS
337+
338+#define INDICATOR_TYPE_DATETIME_CLOCK_LIVE \
339+ (indicator_datetime_clock_live_get_type())
340+
341+#define INDICATOR_DATETIME_CLOCK_LIVE(o) \
342+ (G_TYPE_CHECK_INSTANCE_CAST ((o), \
343+ INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \
344+ IndicatorDatetimeClockLive))
345+
346+#define INDICATOR_DATETIME_CLOCK_LIVE_GET_CLASS(o) \
347+ (G_TYPE_INSTANCE_GET_CLASS ((o), \
348+ INDICATOR_TYPE_DATETIME_CLOCK_LIVE, \
349+ IndicatorDatetimeClockLiveClass))
350+
351+#define INDICATOR_IS_DATETIME_CLOCK_LIVE(o) \
352+ (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
353+ INDICATOR_TYPE_DATETIME_CLOCK_LIVE))
354+
355+typedef struct _IndicatorDatetimeClockLive
356+ IndicatorDatetimeClockLive;
357+typedef struct _IndicatorDatetimeClockLivePriv
358+ IndicatorDatetimeClockLivePriv;
359+typedef struct _IndicatorDatetimeClockLiveClass
360+ IndicatorDatetimeClockLiveClass;
361+
362+/**
363+ * An IndicatorDatetimeClock which gives live clock times
364+ * from timezones determined by geoclue and /etc/timezone
365+ */
366+struct _IndicatorDatetimeClockLive
367+{
368+ GObject parent_instance;
369+
370+ IndicatorDatetimeClockLivePriv * priv;
371+};
372+
373+struct _IndicatorDatetimeClockLiveClass
374+{
375+ GObjectClass parent_class;
376+};
377+
378+IndicatorDatetimeClock * indicator_datetime_clock_live_new (void);
379+
380+G_END_DECLS
381+
382+#endif /* __INDICATOR_DATETIME_CLOCK_LIVE__H__ */
383
384=== added file 'src/clock.c'
385--- src/clock.c 1970-01-01 00:00:00 +0000
386+++ src/clock.c 2013-10-23 18:14:52 +0000
387@@ -0,0 +1,110 @@
388+/*
389+ * Copyright 2013 Canonical Ltd.
390+ *
391+ * Authors:
392+ * Charles Kerr <charles.kerr@canonical.com>
393+ *
394+ * This program is free software: you can redistribute it and/or modify it
395+ * under the terms of the GNU General Public License version 3, as published
396+ * by the Free Software Foundation.
397+ *
398+ * This program is distributed in the hope that it will be useful, but
399+ * WITHOUT ANY WARRANTY; without even the implied warranties of
400+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
401+ * PURPOSE. See the GNU General Public License for more details.
402+ *
403+ * You should have received a copy of the GNU General Public License along
404+ * with this program. If not, see <http://www.gnu.org/licenses/>.
405+ */
406+
407+#include "clock.h"
408+
409+enum
410+{
411+ SIGNAL_CHANGED,
412+ SIGNAL_LAST
413+};
414+
415+static guint signals[SIGNAL_LAST] = { 0 };
416+
417+G_DEFINE_INTERFACE (IndicatorDatetimeClock,
418+ indicator_datetime_clock,
419+ G_TYPE_OBJECT);
420+
421+static void
422+indicator_datetime_clock_default_init (IndicatorDatetimeClockInterface * klass)
423+{
424+ signals[SIGNAL_CHANGED] = g_signal_new (
425+ "changed",
426+ G_TYPE_FROM_CLASS(klass),
427+ G_SIGNAL_RUN_LAST,
428+ G_STRUCT_OFFSET (IndicatorDatetimeClockInterface, changed),
429+ NULL, NULL,
430+ g_cclosure_marshal_VOID__VOID,
431+ G_TYPE_NONE, 0);
432+}
433+
434+/***
435+**** PUBLIC API
436+***/
437+
438+/**
439+ * Get a strv of timezones.
440+ *
441+ * Return value: (element-type char*)
442+ * (transfer full):
443+ * array of timezone strings
444+ */
445+const gchar **
446+indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * self)
447+{
448+ const gchar ** timezones;
449+ IndicatorDatetimeClockInterface * iface;
450+
451+ g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL);
452+ iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self);
453+
454+ if (iface->get_timezones != NULL)
455+ timezones = iface->get_timezones (self);
456+ else
457+ timezones = NULL;
458+
459+ return timezones;
460+}
461+
462+/**
463+ * Get the current time.
464+ *
465+ * Return value: (element-type GDateTime*)
466+ * (transfer full):
467+ * the current time.
468+ */
469+GDateTime *
470+indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * self)
471+{
472+ GDateTime * now;
473+ IndicatorDatetimeClockInterface * iface;
474+
475+ g_return_val_if_fail (INDICATOR_IS_DATETIME_CLOCK(self), NULL);
476+ iface = INDICATOR_DATETIME_CLOCK_GET_INTERFACE(self);
477+
478+ if (iface->get_localtime != NULL)
479+ now = iface->get_localtime (self);
480+ else
481+ now = NULL;
482+
483+ return now;
484+}
485+
486+/**
487+ * Emits the "changed" signal.
488+ *
489+ * This should only be called by subclasses.
490+ */
491+void
492+indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * self)
493+{
494+ g_return_if_fail (INDICATOR_IS_DATETIME_CLOCK (self));
495+
496+ g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL);
497+}
498
499=== added file 'src/clock.h'
500--- src/clock.h 1970-01-01 00:00:00 +0000
501+++ src/clock.h 2013-10-23 18:14:52 +0000
502@@ -0,0 +1,76 @@
503+/*
504+ * Copyright 2013 Canonical Ltd.
505+ *
506+ * Authors:
507+ * Charles Kerr <charles.kerr@canonical.com>
508+ *
509+ * This program is free software: you can redistribute it and/or modify it
510+ * under the terms of the GNU General Public License version 3, as published
511+ * by the Free Software Foundation.
512+ *
513+ * This program is distributed in the hope that it will be useful, but
514+ * WITHOUT ANY WARRANTY; without even the implied warranties of
515+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
516+ * PURPOSE. See the GNU General Public License for more details.
517+ *
518+ * You should have received a copy of the GNU General Public License along
519+ * with this program. If not, see <http://www.gnu.org/licenses/>.
520+ */
521+
522+#ifndef __INDICATOR_DATETIME_CLOCK__H__
523+#define __INDICATOR_DATETIME_CLOCK__H__
524+
525+#include <glib-object.h>
526+
527+G_BEGIN_DECLS
528+
529+#define INDICATOR_TYPE_DATETIME_CLOCK \
530+ (indicator_datetime_clock_get_type ())
531+
532+#define INDICATOR_DATETIME_CLOCK(obj) \
533+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
534+ INDICATOR_TYPE_DATETIME_CLOCK, \
535+ IndicatorDatetimeClock))
536+
537+#define INDICATOR_IS_DATETIME_CLOCK(obj) \
538+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DATETIME_CLOCK))
539+
540+#define INDICATOR_DATETIME_CLOCK_GET_INTERFACE(inst) \
541+ (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
542+ INDICATOR_TYPE_DATETIME_CLOCK, \
543+ IndicatorDatetimeClockInterface))
544+
545+typedef struct _IndicatorDatetimeClock
546+ IndicatorDatetimeClock;
547+
548+typedef struct _IndicatorDatetimeClockInterface
549+ IndicatorDatetimeClockInterface;
550+
551+struct _IndicatorDatetimeClockInterface
552+{
553+ GTypeInterface parent_iface;
554+
555+ /* signals */
556+ void (*changed) (IndicatorDatetimeClock * self);
557+
558+ /* virtual functions */
559+ const gchar** (*get_timezones) (IndicatorDatetimeClock * self);
560+ GDateTime* (*get_localtime) (IndicatorDatetimeClock * self);
561+};
562+
563+GType indicator_datetime_clock_get_type (void);
564+
565+/***
566+****
567+***/
568+
569+const gchar ** indicator_datetime_clock_get_timezones (IndicatorDatetimeClock * clock);
570+
571+GDateTime * indicator_datetime_clock_get_localtime (IndicatorDatetimeClock * clock);
572+
573+void indicator_datetime_clock_emit_changed (IndicatorDatetimeClock * clock);
574+
575+
576+G_END_DECLS
577+
578+#endif /* __INDICATOR_DATETIME_CLOCK__H__ */
579
580=== modified file 'src/main.c'
581--- src/main.c 2013-10-16 22:14:11 +0000
582+++ src/main.c 2013-10-23 18:14:52 +0000
583@@ -26,36 +26,26 @@
584 #include <gio/gio.h>
585 #include <libnotify/notify.h>
586
587+#include "clock-live.h"
588 #include "planner-eds.h"
589-#include "planner-mock.h"
590 #include "service.h"
591
592 /***
593 ****
594 ***/
595
596-/* When enabled, new alarms will show up every minute to test snap decisions */
597-static gboolean test_alarms = FALSE;
598-
599-static GOptionEntry entries[] = {
600- { "test-alarms", '\0', 0, G_OPTION_ARG_NONE, &test_alarms, "Test Alarms", NULL },
601- { NULL }
602-};
603-
604 static void
605 on_name_lost (gpointer instance G_GNUC_UNUSED, gpointer loop)
606 {
607 g_message ("exiting: service couldn't acquire or lost ownership of busname");
608
609- if (!test_alarms)
610- g_main_loop_quit ((GMainLoop*)loop);
611+ g_main_loop_quit ((GMainLoop*)loop);
612 }
613
614 int
615 main (int argc G_GNUC_UNUSED, char ** argv G_GNUC_UNUSED)
616 {
617- GOptionContext * context;
618- GError * error;
619+ IndicatorDatetimeClock * clock;
620 IndicatorDatetimePlanner * planner;
621 IndicatorDatetimeService * service;
622 GMainLoop * loop;
623@@ -69,36 +59,21 @@
624 if (!notify_init ("indicator-datetime-service"))
625 g_critical ("libnotify initialization failed");
626
627- /* parse command-line options */
628- context = g_option_context_new (NULL);
629- g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
630- if (!g_option_context_parse (context, &argc, &argv, &error))
631- {
632- g_print("option parsing failed: %s\n", error->message);
633- return EXIT_FAILURE;
634- }
635-
636- /* set up the planner */
637- if (test_alarms)
638- {
639- g_message ("Using fake appointment book for testing alarms.");
640- planner = indicator_datetime_planner_mock_new ();
641- }
642- else
643- {
644- planner = indicator_datetime_planner_eds_new ();
645- }
646+ /* create the service */
647+ clock = indicator_datetime_clock_live_new ();
648+ planner = indicator_datetime_planner_eds_new ();
649+ service = indicator_datetime_service_new (clock, planner);
650
651 /* run */
652- service = indicator_datetime_service_new (planner);
653 loop = g_main_loop_new (NULL, FALSE);
654 g_signal_connect (service, INDICATOR_DATETIME_SERVICE_SIGNAL_NAME_LOST,
655 G_CALLBACK(on_name_lost), loop);
656 g_main_loop_run (loop);
657+ g_main_loop_unref (loop);
658
659 /* cleanup */
660- g_main_loop_unref (loop);
661 g_object_unref (service);
662 g_object_unref (planner);
663+ g_object_unref (clock);
664 return 0;
665 }
666
667=== modified file 'src/service.c'
668--- src/service.c 2013-10-17 03:39:12 +0000
669+++ src/service.c 2013-10-23 18:14:52 +0000
670@@ -29,8 +29,6 @@
671 #include <url-dispatcher.h>
672
673 #include "dbus-shared.h"
674-#include "timezone-file.h"
675-#include "timezone-geoclue.h"
676 #include "service.h"
677 #include "settings-shared.h"
678 #include "utils.h"
679@@ -54,6 +52,7 @@
680 enum
681 {
682 PROP_0,
683+ PROP_CLOCK,
684 PROP_PLANNER,
685 PROP_LAST
686 };
687@@ -101,16 +100,14 @@
688
689 GSettings * settings;
690
691- IndicatorDatetimeTimezone * tz_file;
692- IndicatorDatetimeTimezone * tz_geoclue;
693+ IndicatorDatetimeClock * clock;
694 IndicatorDatetimePlanner * planner;
695
696- /* cached GTimeZone for use by indicator_datetime_service_get_localtime() */
697- GTimeZone * internal_timezone;
698-
699 /* the clock app's icon filename */
700 gchar * clock_app_icon_filename;
701
702+ gchar * header_label_format_string;
703+
704 /* Whether or not we've tried to load the clock app's icon.
705 This way we don't keep trying to reload it on the desktop */
706 gboolean clock_app_icon_initialized;
707@@ -150,6 +147,13 @@
708 /* appointments over the next few weeks.
709 Used when building SECTION_APPOINTMENTS */
710 GSList * upcoming_appointments;
711+
712+ /* variant cache */
713+ GVariant * desktop_title_variant;
714+ GVariant * phone_title_variant;
715+ GVariant * visible_true_variant;
716+ GVariant * visible_false_variant;
717+ GVariant * alarm_icon_variant;
718 };
719
720 typedef IndicatorDatetimeServicePrivate priv_t;
721@@ -168,6 +172,12 @@
722 }
723 }
724
725+static inline GDateTime *
726+indicator_datetime_service_get_localtime (IndicatorDatetimeService * self)
727+{
728+ return indicator_datetime_clock_get_localtime (self->priv->clock);
729+}
730+
731 /***
732 ****
733 ***/
734@@ -178,6 +188,8 @@
735 static inline void
736 rebuild_header_soon (IndicatorDatetimeService * self)
737 {
738+ g_clear_pointer (&self->priv->header_label_format_string, g_free);
739+
740 rebuild_soon (self, SECTION_HEADER);
741 }
742
743@@ -360,7 +372,7 @@
744 return G_SOURCE_REMOVE;
745 }
746
747-static char * get_header_label_format_string (IndicatorDatetimeService *);
748+static const char * get_header_label_format_string (IndicatorDatetimeService *);
749
750 static void
751 start_header_timer (IndicatorDatetimeService * self)
752@@ -374,11 +386,10 @@
753
754 if (g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_CLOCK_S))
755 {
756- char * fmt = get_header_label_format_string (self);
757+ const char * fmt = get_header_label_format_string (self);
758 header_shows_seconds = fmt && (strstr(fmt,"%s") || strstr(fmt,"%S") ||
759 strstr(fmt,"%T") || strstr(fmt,"%X") ||
760 strstr(fmt,"%c"));
761- g_free (fmt);
762 }
763
764 if (header_shows_seconds)
765@@ -589,23 +600,6 @@
766 ****
767 ***/
768
769-static void
770-update_internal_timezone (IndicatorDatetimeService * self)
771-{
772- priv_t * p = self->priv;
773- const char * id;
774-
775- /* find the id from tz_file or tz_geoclue if possible; NULL otherwise */
776- id = NULL;
777- if (!id && p->tz_file)
778- id = indicator_datetime_timezone_get_timezone (p->tz_file);
779- if (!id && p->tz_geoclue)
780- id = indicator_datetime_timezone_get_timezone (p->tz_geoclue);
781-
782- g_clear_pointer (&p->internal_timezone, g_time_zone_unref);
783- p->internal_timezone = g_time_zone_new (id);
784-}
785-
786 /**
787 * General purpose handler for rebuilding sections and restarting their timers
788 * when time jumps for whatever reason:
789@@ -624,7 +618,6 @@
790 1. rebuild the necessary states / menuitems when time jumps
791 2. restart the timers so their new wait interval is correct */
792
793- update_internal_timezone (self);
794 on_header_timer (self);
795 on_timezone_timer (self);
796 }
797@@ -656,38 +649,46 @@
798 ****
799 ***/
800
801-static gchar *
802+static const gchar *
803 get_header_label_format_string (IndicatorDatetimeService * self)
804 {
805- char * fmt;
806- GSettings * s = self->priv->settings;
807- const TimeFormatMode mode = g_settings_get_enum (s, SETTINGS_TIME_FORMAT_S);
808-
809- if (mode == TIME_FORMAT_MODE_CUSTOM)
810- {
811- fmt = g_settings_get_string (s, SETTINGS_CUSTOM_TIME_FORMAT_S);
812- }
813- else
814- {
815- gboolean show_day = g_settings_get_boolean (s, SETTINGS_SHOW_DAY_S);
816- gboolean show_date = g_settings_get_boolean (s, SETTINGS_SHOW_DATE_S);
817- fmt = generate_full_format_string (show_day, show_date, s);
818- }
819-
820- return fmt;
821+ priv_t * p = self->priv;
822+
823+ if (p->header_label_format_string == NULL)
824+ {
825+ char * fmt;
826+ GSettings * s = p->settings;
827+ const TimeFormatMode mode = g_settings_get_enum (s, SETTINGS_TIME_FORMAT_S);
828+
829+ if (mode == TIME_FORMAT_MODE_CUSTOM)
830+ {
831+ fmt = g_settings_get_string (s, SETTINGS_CUSTOM_TIME_FORMAT_S);
832+ }
833+ else
834+ {
835+ gboolean show_day = g_settings_get_boolean (s, SETTINGS_SHOW_DAY_S);
836+ gboolean show_date = g_settings_get_boolean (s, SETTINGS_SHOW_DATE_S);
837+ fmt = generate_full_format_string (show_day, show_date, s);
838+ }
839+
840+ p->header_label_format_string = fmt;
841+ }
842+
843+ return p->header_label_format_string;
844 }
845
846 static GVariant *
847 create_desktop_header_state (IndicatorDatetimeService * self)
848 {
849+ priv_t * p = self->priv;
850 GVariantBuilder b;
851- gchar * fmt;
852+ const gchar * fmt;
853 gchar * str;
854 gboolean visible;
855 GDateTime * now;
856- const gchar * title = _("Date and Time");
857+ GVariant * label_variant;
858
859- visible = g_settings_get_boolean (self->priv->settings, SETTINGS_SHOW_CLOCK_S);
860+ visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_CLOCK_S);
861
862 /* build the time string for the label & a11y */
863 fmt = get_header_label_format_string (self);
864@@ -699,15 +700,15 @@
865 g_warning ("%s", str);
866 }
867
868+ label_variant = g_variant_new_take_string (str);
869 g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
870- g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_string (str));
871- g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (str));
872- g_variant_builder_add (&b, "{sv}", "title", g_variant_new_string (title));
873- g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (visible));
874+ g_variant_builder_add (&b, "{sv}", "accessible-desc", label_variant);
875+ g_variant_builder_add (&b, "{sv}", "label", label_variant);
876+ g_variant_builder_add_value (&b, p->desktop_title_variant);
877+ g_variant_builder_add_value (&b, visible ? p->visible_true_variant : p->visible_false_variant);
878
879 /* cleanup */
880 g_date_time_unref (now);
881- g_free (fmt);
882 return g_variant_builder_end (&b);
883 }
884
885@@ -717,43 +718,37 @@
886 static GVariant *
887 create_phone_header_state (IndicatorDatetimeService * self)
888 {
889+ priv_t * p = self->priv;
890+ const gboolean has_alarms = service_has_alarms (self);
891 GVariantBuilder b;
892 GDateTime * now;
893 const gchar * fmt;
894- gchar * label;
895- gboolean has_alarms;
896- gchar * a11y;
897- const gchar * title = _("Upcoming");
898
899 g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
900-
901- /* label */
902+ g_variant_builder_add_value (&b, p->phone_title_variant);
903+ g_variant_builder_add_value (&b, p->visible_true_variant);
904+
905+ /* icon */
906+ if (has_alarms)
907+ g_variant_builder_add_value (&b, p->alarm_icon_variant);
908+
909+ /* label, a11y */
910 now = indicator_datetime_service_get_localtime (self);
911 fmt = get_terse_header_time_format_string ();
912- label = g_date_time_format (now, fmt);
913-
914- /* icon */
915- if ((has_alarms = service_has_alarms (self)))
916- {
917- GIcon * icon;
918- icon = g_themed_icon_new_with_default_fallbacks (ALARM_CLOCK_ICON_NAME);
919- g_variant_builder_add (&b, "{sv}", "icon", g_icon_serialize (icon));
920- g_object_unref (icon);
921- }
922-
923- /* a11y */
924 if (has_alarms)
925- a11y = g_strdup_printf (_("%s (has alarms)"), label);
926+ {
927+ gchar * label = g_date_time_format (now, fmt);
928+ gchar * a11y = g_strdup_printf (_("%s (has alarms)"), label);
929+ g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (label));
930+ g_variant_builder_add (&b, "{sv}", "accessible-desc", g_variant_new_take_string (a11y));
931+ }
932 else
933- a11y = g_strdup (label);
934- g_variant_builder_add (&b, "{sv}", "accessible-desc",
935- g_variant_new_take_string (a11y));
936-
937- g_variant_builder_add (&b, "{sv}", "visible", g_variant_new_boolean (TRUE));
938- g_variant_builder_add (&b, "{sv}", "label", g_variant_new_take_string (label));
939- g_variant_builder_add (&b, "{sv}", "title", g_variant_new_string (title));
940-
941- /* cleanup */
942+ {
943+ GVariant * v = g_variant_new_take_string (g_date_time_format (now, fmt));
944+ g_variant_builder_add (&b, "{sv}", "label", v);
945+ g_variant_builder_add (&b, "{sv}", "accessible-desc", v);
946+ }
947+
948 g_date_time_unref (now);
949 return g_variant_builder_end (&b);
950 }
951@@ -1100,61 +1095,6 @@
952 ****
953 ***/
954
955-static void
956-on_current_timezone_changed (IndicatorDatetimeService * self)
957-{
958- on_local_time_jumped (self);
959-}
960-
961-/* When the 'auto-detect timezone' boolean setting changes,
962- start or stop watching geoclue and /etc/timezone */
963-static void
964-set_detect_location_enabled (IndicatorDatetimeService * self, gboolean enabled)
965-{
966- gboolean changed = FALSE;
967- priv_t * p = self->priv;
968-
969- /* geoclue */
970-
971- if (!p->tz_geoclue && enabled)
972- {
973- p->tz_geoclue = indicator_datetime_timezone_geoclue_new ();
974- g_signal_connect_swapped (p->tz_geoclue, "notify::timezone",
975- G_CALLBACK(on_current_timezone_changed),
976- self);
977- changed = TRUE;
978- }
979- else if (p->tz_geoclue && !enabled)
980- {
981- g_signal_handlers_disconnect_by_func (p->tz_geoclue,
982- on_current_timezone_changed,
983- self);
984- g_clear_object (&p->tz_geoclue);
985- changed = TRUE;
986- }
987-
988- /* timezone file */
989-
990- if (!p->tz_file && enabled)
991- {
992- p->tz_file = indicator_datetime_timezone_file_new (TIMEZONE_FILE);
993- g_signal_connect_swapped (p->tz_file, "notify::timezone",
994- G_CALLBACK(on_current_timezone_changed),
995- self);
996- changed = TRUE;
997- }
998- else if (p->tz_file && !enabled)
999- {
1000- g_signal_handlers_disconnect_by_func (p->tz_file,
1001- on_current_timezone_changed,
1002- self);
1003- g_clear_object (&p->tz_file);
1004- changed = TRUE;
1005- }
1006-
1007- if (changed)
1008- on_current_timezone_changed (self);
1009-}
1010
1011 /* A temp struct used by create_locations_section()
1012 for pruning duplicates and sorting. */
1013@@ -1240,44 +1180,30 @@
1014 GSList * l;
1015 GSList * locations = NULL;
1016 gchar ** user_locations;
1017- gboolean visible;
1018- IndicatorDatetimeTimezone * detected_timezones[2];
1019+ const gchar ** detected_timezones;
1020 priv_t * p = self->priv;
1021 GDateTime * now = indicator_datetime_service_get_localtime (self);
1022
1023- set_detect_location_enabled (self,
1024- g_settings_get_boolean (p->settings, SETTINGS_SHOW_DETECTED_S));
1025-
1026 menu = g_menu_new ();
1027
1028 /***
1029- **** Build a list of locations to add: use geo_timezone,
1030- **** current_timezone, and SETTINGS_LOCATIONS_S, but omit duplicates.
1031+ **** Build a list of locations to add, omitting duplicates
1032 ***/
1033
1034- /* maybe add the auto-detected timezones */
1035- detected_timezones[0] = p->tz_geoclue;
1036- detected_timezones[1] = p->tz_file;
1037- visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_DETECTED_S);
1038- for (i=0; i<G_N_ELEMENTS(detected_timezones); i++)
1039+ detected_timezones = indicator_datetime_clock_get_timezones (p->clock);
1040+ for (i=0; detected_timezones && detected_timezones[i]; i++)
1041 {
1042- if (detected_timezones[i] != NULL)
1043- {
1044- const char * tz = indicator_datetime_timezone_get_timezone (detected_timezones[i]);
1045- if (tz && *tz)
1046- {
1047- gchar * name = get_current_zone_name (tz, p->settings);
1048- locations = locations_add (locations, tz, name, visible);
1049- g_free (name);
1050- }
1051- }
1052+ const char * tz = detected_timezones[i];
1053+ gchar * name = get_current_zone_name (tz, p->settings);
1054+ locations = locations_add (locations, tz, name, TRUE);
1055+ g_free (name);
1056 }
1057
1058 /* maybe add the user-specified locations */
1059 user_locations = g_settings_get_strv (p->settings, SETTINGS_LOCATIONS_S);
1060 if (user_locations != NULL)
1061 {
1062- visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_LOCATIONS_S);
1063+ const gboolean visible = g_settings_get_boolean (p->settings, SETTINGS_SHOW_LOCATIONS_S);
1064
1065 for (i=0; user_locations[i] != NULL; i++)
1066 {
1067@@ -1735,6 +1661,9 @@
1068 struct ProfileMenuInfo * desktop = &p->menus[PROFILE_DESKTOP];
1069 struct ProfileMenuInfo * greeter = &p->menus[PROFILE_GREETER];
1070
1071+ if (p->actions == NULL)
1072+ return;
1073+
1074 if (sections & SECTION_HEADER)
1075 {
1076 g_simple_action_set_state (p->desktop_header_action,
1077@@ -2088,6 +2017,10 @@
1078
1079 switch (property_id)
1080 {
1081+ case PROP_CLOCK:
1082+ g_value_set_object (value, self->priv->clock);
1083+ break;
1084+
1085 case PROP_PLANNER:
1086 g_value_set_object (value, self->priv->planner);
1087 break;
1088@@ -2107,6 +2040,10 @@
1089
1090 switch (property_id)
1091 {
1092+ case PROP_CLOCK:
1093+ indicator_datetime_service_set_clock (self, g_value_get_object (value));
1094+ break;
1095+
1096 case PROP_PLANNER:
1097 indicator_datetime_service_set_planner (self, g_value_get_object (value));
1098 break;
1099@@ -2138,8 +2075,7 @@
1100 g_clear_object (&p->cancellable);
1101 }
1102
1103- set_detect_location_enabled (self, FALSE);
1104-
1105+ indicator_datetime_service_set_clock (self, NULL);
1106 indicator_datetime_service_set_planner (self, NULL);
1107
1108 if (p->login1_manager != NULL)
1109@@ -2165,12 +2101,17 @@
1110 for (i=0; i<N_PROFILES; ++i)
1111 g_clear_object (&p->menus[i].menu);
1112
1113- g_clear_pointer (&p->internal_timezone, g_time_zone_unref);
1114 g_clear_object (&p->calendar_action);
1115 g_clear_object (&p->desktop_header_action);
1116 g_clear_object (&p->phone_header_action);
1117 g_clear_object (&p->conn);
1118
1119+ g_clear_pointer (&p->desktop_title_variant, g_variant_unref);
1120+ g_clear_pointer (&p->phone_title_variant, g_variant_unref);
1121+ g_clear_pointer (&p->visible_true_variant, g_variant_unref);
1122+ g_clear_pointer (&p->visible_false_variant, g_variant_unref);
1123+ g_clear_pointer (&p->alarm_icon_variant, g_variant_unref);
1124+
1125 G_OBJECT_CLASS (indicator_datetime_service_parent_class)->dispose (o);
1126 }
1127
1128@@ -2181,6 +2122,7 @@
1129 priv_t * p = self->priv;
1130
1131 g_free (p->clock_app_icon_filename);
1132+ g_free (p->header_label_format_string);
1133 g_clear_pointer (&p->skew_time, g_date_time_unref);
1134 g_clear_pointer (&p->calendar_date, g_date_time_unref);
1135
1136@@ -2194,9 +2136,45 @@
1137 static void
1138 indicator_datetime_service_init (IndicatorDatetimeService * self)
1139 {
1140+ GIcon * icon;
1141+ priv_t * p;
1142+
1143+ /* init the priv pointer */
1144+
1145+ p = G_TYPE_INSTANCE_GET_PRIVATE (self,
1146+ INDICATOR_TYPE_DATETIME_SERVICE,
1147+ IndicatorDatetimeServicePrivate);
1148+ self->priv = p;
1149+
1150+ p->cancellable = g_cancellable_new ();
1151+
1152+ p->settings = g_settings_new (SETTINGS_INTERFACE);
1153+
1154+ p->desktop_title_variant = g_variant_new ("{sv}", "title", g_variant_new_string (_("Date and Time")));
1155+ g_variant_ref_sink (p->desktop_title_variant);
1156+
1157+ p->phone_title_variant = g_variant_new ("{sv}", "title", g_variant_new_string (_("Upcoming")));
1158+ g_variant_ref_sink (p->phone_title_variant);
1159+
1160+ p->visible_true_variant = g_variant_new ("{sv}", "visible", g_variant_new_boolean (TRUE));
1161+ g_variant_ref_sink (p->visible_true_variant);
1162+
1163+ p->visible_false_variant = g_variant_new ("{sv}", "visible", g_variant_new_boolean (FALSE));
1164+ g_variant_ref_sink (p->visible_false_variant);
1165+
1166+ icon = g_themed_icon_new_with_default_fallbacks (ALARM_CLOCK_ICON_NAME);
1167+ p->alarm_icon_variant = g_variant_new ("{sv}", "icon", g_icon_serialize (icon));
1168+ g_variant_ref_sink (p->alarm_icon_variant);
1169+ g_object_unref (icon);
1170+}
1171+
1172+static void
1173+my_constructed (GObject * gself)
1174+{
1175+ IndicatorDatetimeService * self = INDICATOR_DATETIME_SERVICE (gself);
1176+ priv_t * p = self->priv;
1177+ GString * gstr = g_string_new (NULL);
1178 guint i, n;
1179- priv_t * p;
1180- GString * gstr = g_string_new (NULL);
1181
1182 /* these are the settings that affect the
1183 contents of the respective sections */
1184@@ -2233,20 +2211,10 @@
1185 };
1186
1187
1188- /* init the priv pointer */
1189-
1190- p = G_TYPE_INSTANCE_GET_PRIVATE (self,
1191- INDICATOR_TYPE_DATETIME_SERVICE,
1192- IndicatorDatetimeServicePrivate);
1193- self->priv = p;
1194-
1195- p->cancellable = g_cancellable_new ();
1196-
1197 /***
1198- **** Create the settings object and listen for changes
1199+ **** Listen for settings changes
1200 ***/
1201
1202- p->settings = g_settings_new (SETTINGS_INTERFACE);
1203 for (i=0, n=G_N_ELEMENTS(header_settings); i<n; i++)
1204 {
1205 g_string_printf (gstr, "changed::%s", header_settings[i]);
1206@@ -2327,6 +2295,7 @@
1207
1208 object_class->dispose = my_dispose;
1209 object_class->finalize = my_finalize;
1210+ object_class->constructed = my_constructed;
1211 object_class->get_property = my_get_property;
1212 object_class->set_property = my_set_property;
1213
1214@@ -2345,6 +2314,12 @@
1215
1216 properties[PROP_0] = NULL;
1217
1218+ properties[PROP_CLOCK] = g_param_spec_object ("clock",
1219+ "Clock",
1220+ "The clock",
1221+ INDICATOR_TYPE_DATETIME_CLOCK,
1222+ flags);
1223+
1224 properties[PROP_PLANNER] = g_param_spec_object ("planner",
1225 "Planner",
1226 "The appointment provider",
1227@@ -2359,28 +2334,17 @@
1228 ***/
1229
1230 IndicatorDatetimeService *
1231-indicator_datetime_service_new (IndicatorDatetimePlanner * planner)
1232+indicator_datetime_service_new (IndicatorDatetimeClock * clock,
1233+ IndicatorDatetimePlanner * planner)
1234 {
1235 GObject * o = g_object_new (INDICATOR_TYPE_DATETIME_SERVICE,
1236+ "clock", clock,
1237 "planner", planner,
1238 NULL);
1239
1240 return INDICATOR_DATETIME_SERVICE (o);
1241 }
1242
1243-/* This currently just returns the system time,
1244- As we add test coverage, we'll need this to bypass the system time. */
1245-GDateTime *
1246-indicator_datetime_service_get_localtime (IndicatorDatetimeService * self)
1247-{
1248- priv_t * p = self->priv;
1249-
1250- if (G_UNLIKELY (p->internal_timezone == NULL))
1251- update_internal_timezone (self);
1252-
1253- return g_date_time_new_now (p->internal_timezone);
1254-}
1255-
1256 void
1257 indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self,
1258 GDateTime * date)
1259@@ -2400,6 +2364,43 @@
1260 update_appointment_lists (self);
1261 }
1262
1263+static void
1264+on_clock_changed (IndicatorDatetimeService * self)
1265+{
1266+ on_local_time_jumped (self);
1267+}
1268+
1269+void
1270+indicator_datetime_service_set_clock (IndicatorDatetimeService * self,
1271+ IndicatorDatetimeClock * clock)
1272+{
1273+ priv_t * p;
1274+
1275+ g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self));
1276+ g_return_if_fail ((clock == NULL) || INDICATOR_IS_DATETIME_CLOCK (clock));
1277+
1278+ p = self->priv;
1279+
1280+ /* clear the old clock */
1281+
1282+ if (p->clock != NULL)
1283+ {
1284+ g_signal_handlers_disconnect_by_data (p->clock, self);
1285+ g_clear_object (&p->clock);
1286+ }
1287+
1288+ /* set the new clock */
1289+
1290+ if (clock != NULL)
1291+ {
1292+ p->clock = g_object_ref (clock);
1293+
1294+ g_signal_connect_swapped (p->clock, "changed",
1295+ G_CALLBACK(on_clock_changed), self);
1296+ on_clock_changed (self);
1297+ }
1298+}
1299+
1300 void
1301 indicator_datetime_service_set_planner (IndicatorDatetimeService * self,
1302 IndicatorDatetimePlanner * planner)
1303@@ -2407,7 +2408,7 @@
1304 priv_t * p;
1305
1306 g_return_if_fail (INDICATOR_IS_DATETIME_SERVICE (self));
1307- g_return_if_fail (INDICATOR_IS_DATETIME_PLANNER (planner));
1308+ g_return_if_fail ((planner == NULL) || INDICATOR_IS_DATETIME_PLANNER (planner));
1309
1310 p = self->priv;
1311
1312
1313=== modified file 'src/service.h'
1314--- src/service.h 2013-10-10 02:02:17 +0000
1315+++ src/service.h 2013-10-23 18:14:52 +0000
1316@@ -22,6 +22,8 @@
1317
1318 #include <glib.h>
1319 #include <glib-object.h>
1320+
1321+#include "clock.h"
1322 #include "planner.h"
1323
1324 G_BEGIN_DECLS
1325@@ -63,9 +65,8 @@
1326
1327 GType indicator_datetime_service_get_type (void);
1328
1329-IndicatorDatetimeService * indicator_datetime_service_new (IndicatorDatetimePlanner * planner);
1330-
1331-GDateTime * indicator_datetime_service_get_localtime (IndicatorDatetimeService * service);
1332+IndicatorDatetimeService * indicator_datetime_service_new (IndicatorDatetimeClock * clock,
1333+ IndicatorDatetimePlanner * planner);
1334
1335 void indicator_datetime_service_set_calendar_date (IndicatorDatetimeService * self,
1336 GDateTime * date);
1337@@ -74,6 +75,9 @@
1338 IndicatorDatetimePlanner * planner);
1339
1340
1341+void indicator_datetime_service_set_clock (IndicatorDatetimeService * self,
1342+ IndicatorDatetimeClock * clock);
1343+
1344
1345 G_END_DECLS
1346
1347
1348=== modified file 'src/timezone.h'
1349--- src/timezone.h 2013-09-09 17:43:31 +0000
1350+++ src/timezone.h 2013-10-23 18:14:52 +0000
1351@@ -37,8 +37,6 @@
1352
1353 GType indicator_datetime_timezone_get_type (void);
1354
1355-#define INDICATOR_DATETIME_TIMEZONE_PROPERTY_TIMEZONE "timezone"
1356-
1357 /**
1358 * Abstract Base Class for objects that provide a timezone.
1359 *
1360
1361=== renamed file 'src/planner-mock.c' => 'tests/planner-mock.c'
1362=== renamed file 'src/planner-mock.h' => 'tests/planner-mock.h'

Subscribers

People subscribed via source and target branches