Merge lp:~charlesk/indicator-datetime/make-timezones-and-clock-mockable into lp:indicator-datetime/14.04
- make-timezones-and-clock-mockable
- Merge into trunk.14.04
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 | ||||
Related bugs: |
|
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 IndicatorDateti
2. IndicatorDateti
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 IndicatorDateti
5. Cache a couple of variables in IndicatorDateti
PS Jenkins bot (ps-jenkins) wrote : | # |
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[
1227 + "Clock",
1228 + "The clock",
1229 + G_TYPE_OBJECT,
1230 + flags);
Should probably be INDICATOR_
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. IndicatorDateti
Charles Kerr (charlesk) wrote : | # |
Actually, you're right. That's possible once the G_TYPE_
Fixed r286
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:286
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 287. By Charles Kerr
-
instead of keeping IndicatorDateti
meTimezone objects in separate fields, keep them in a list so they can be handled in a loop.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:287
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:287
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
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' |
PASSED: Continuous integration, rev:285 jenkins. qa.ubuntu. com/job/ indicator- datetime- ci/120/ jenkins. qa.ubuntu. com/job/ indicator- datetime- saucy-amd64- ci/74 jenkins. qa.ubuntu. com/job/ indicator- datetime- saucy-armhf- ci/75 jenkins. qa.ubuntu. com/job/ indicator- datetime- saucy-armhf- ci/75/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: 10.97.0. 26:8080/ job/indicator- datetime- ci/120/ rebuild
http://