Merge lp:~karl-qdh/indicator-datetime/multiplecalendarsources_and_timezones into lp:indicator-datetime/0.3

Proposed by Karl Lattimer
Status: Merged
Merged at revision: 44
Proposed branch: lp:~karl-qdh/indicator-datetime/multiplecalendarsources_and_timezones
Merge into: lp:indicator-datetime/0.3
Diff against target: 1234 lines (+542/-174)
5 files modified
configure.ac (+7/-0)
data/com.canonical.indicator.datetime.gschema.xml (+8/-0)
src/datetime-service.c (+296/-88)
src/dbus-shared.h (+1/-2)
src/indicator-datetime.c (+230/-84)
To merge this branch: bzr merge lp:~karl-qdh/indicator-datetime/multiplecalendarsources_and_timezones
Reviewer Review Type Date Requested Status
Ted Gould (community) Needs Fixing
Review via email: mp+50011@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote :

On Wed, 2011-02-16 at 17:07 +0000, Karl Lattimer wrote:
> +// Authentication function taken from http://git.gnome.org/browse/evolution/tree/calendar/common/authentication.c

In order to maintain clean copyright on the code we can't cut-and-paste
code from other sources.

  review needsfixing

review: Needs Fixing
62. By Karl Lattimer

Merged in mterrys time updates

63. By Karl Lattimer

Testing eds signal (FAIL) seems when evolution changes an entry no signal is emitted to eds clients

64. By Karl Lattimer

Rewrote auth_func at tedg's request.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2011-02-09 03:37:50 +0000
3+++ configure.ac 2011-02-17 15:54:42 +0000
4@@ -64,15 +64,18 @@
5 ICAL_REQUIRED_VERSION=0.44
6 CAIRO_REQUIRED_VERSION=1.10
7 GDK_REQUIRED_VERSION=2.22
8+GLIB_REQUIRED_VERSION=2.26
9
10 AS_IF([test "x$with_gtk" = x3],
11 [PKG_CHECK_MODULES(INDICATOR, indicator3 >= $INDICATOR_REQUIRED_VERSION
12+ glib-2.0 >= $GLIB_REQUIRED_VERSION
13 dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION
14 dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION
15 libido3-0.1 >= $INDICATOR_DISPLAY_OBJECTS)
16 ],
17 [test "x$with_gtk" = x2],
18 [PKG_CHECK_MODULES(INDICATOR, indicator >= $INDICATOR_REQUIRED_VERSION
19+ glib-2.0 >= $GLIB_REQUIRED_VERSION
20 dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION
21 dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION
22 libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS)
23@@ -82,6 +85,7 @@
24
25 AS_IF([test "x$with_gtk" = x3],
26 [PKG_CHECK_MODULES(SERVICE, indicator >= $INDICATOR_REQUIRED_VERSION
27+ glib-2.0 >= $GLIB_REQUIRED_VERSION
28 dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION
29 dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION
30 libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS
31@@ -91,11 +95,13 @@
32 libecal-1.2 >= $ECAL_REQUIRED_VERSION
33 libical >= $ICAL_REQUIRED_VERSION
34 libedataserver-1.2 >= EDS_REQUIRED_VERSION
35+ libedataserverui-1.2 >= EDS_REQUIRED_VERSION
36 cairo >= CAIRO_REQUIRED_VERSION
37 gdk-2.0 >= GDK_REQUIRED_VERSION)
38 ],
39 [test "x$with_gtk" = x2],
40 [PKG_CHECK_MODULES(SERVICE, indicator >= $INDICATOR_REQUIRED_VERSION
41+ glib-2.0 >= $GLIB_REQUIRED_VERSION
42 dbusmenu-glib-0.4 >= $DBUSMENUGLIB_REQUIRED_VERSION
43 dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION
44 libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS
45@@ -105,6 +111,7 @@
46 libecal-1.2 >= $ECAL_REQUIRED_VERSION
47 libical >= $ICAL_REQUIRED_VERSION
48 libedataserver-1.2 >= EDS_REQUIRED_VERSION
49+ libedataserverui-1.2 >= EDS_REQUIRED_VERSION
50 cairo >= CAIRO_REQUIRED_VERSION
51 gdk-2.0 >= GDK_REQUIRED_VERSION)
52 ],
53
54=== modified file 'data/com.canonical.indicator.datetime.gschema.xml'
55--- data/com.canonical.indicator.datetime.gschema.xml 2011-01-17 17:50:14 +0000
56+++ data/com.canonical.indicator.datetime.gschema.xml 2011-02-17 15:54:42 +0000
57@@ -57,5 +57,13 @@
58 more information.
59 </description>
60 </key>
61+ <key name="locations" type="as">
62+ <default>[]</default>
63+ <summary>A List of locations</summary>
64+ <description>
65+ Adds the list of locations the user has configured to display in the
66+ indicator-datetime menu.
67+ </description>
68+ </key>
69 </schema>
70 </schemalist>
71
72=== modified file 'src/datetime-service.c'
73--- src/datetime-service.c 2011-02-09 04:26:31 +0000
74+++ src/datetime-service.c 2011-02-17 15:54:42 +0000
75@@ -42,6 +42,7 @@
76 #include <libical/ical.h>
77 #include <libecal/e-cal-time-util.h>
78 #include <libedataserver/e-source.h>
79+#include <libedataserverui/e-passwords.h>
80 // Other users of ecal seem to also include these, not sure why they should be included by the above
81 #include <libical/icaltime.h>
82 #include <cairo/cairo.h>
83@@ -52,8 +53,13 @@
84 #include "datetime-interface.h"
85 #include "dbus-shared.h"
86
87+
88+#define SETTINGS_INTERFACE "com.canonical.indicator.datetime"
89+#define SETTINGS_LOCATIONS "locations"
90+
91 static void geo_create_client (GeoclueMaster * master, GeoclueMasterClient * client, gchar * path, GError * error, gpointer user_data);
92 static gboolean update_appointment_menu_items (gpointer user_data);
93+static gboolean update_timezone_menu_items(gpointer user_data);
94 static void setup_timer (void);
95 static void geo_client_invalid (GeoclueMasterClient * client, gpointer user_data);
96 static void geo_address_change (GeoclueMasterClient * client, gchar * a, gchar * b, gchar * c, gchar * d, gpointer user_data);
97@@ -63,30 +69,35 @@
98 static DbusmenuServer * server = NULL;
99 static DbusmenuMenuitem * root = NULL;
100 static DatetimeInterface * dbus = NULL;
101-static gchar * current_timezone = NULL;
102
103 /* Global Items */
104 static DbusmenuMenuitem * date = NULL;
105 static DbusmenuMenuitem * calendar = NULL;
106 static DbusmenuMenuitem * settings = NULL;
107-static DbusmenuMenuitem * tzchange = NULL;
108+static DbusmenuMenuitem * locations_separator = NULL;
109+static DbusmenuMenuitem * geo_location = NULL;
110+static DbusmenuMenuitem * current_location = NULL;
111+//static DbusmenuMenuitem * ecal_location = NULL;
112 static DbusmenuMenuitem * add_appointment = NULL;
113-// static DbusmenuMenuitem * add_location = NULL;
114 static GList * appointments = NULL;
115-static ECal * ecal = NULL;
116-static const gchar * ecal_timezone = NULL;
117-static icaltimezone *tzone;
118+static GList * dconflocations = NULL;
119+GSettings *conf;
120+
121
122 /* Geoclue trackers */
123 static GeoclueMasterClient * geo_master = NULL;
124 static GeoclueAddress * geo_address = NULL;
125-static gchar * geo_timezone = NULL;
126+
127+/* Our 2 important timezones */
128+static gchar * current_timezone = NULL;
129+static gchar * geo_timezone = NULL;
130
131 /* Check to see if our timezones are the same */
132 static void
133 check_timezone_sync (void) {
134+ gchar * label;
135 gboolean in_sync = FALSE;
136-
137+
138 if (geo_timezone == NULL) {
139 in_sync = TRUE;
140 }
141@@ -105,18 +116,63 @@
142 g_debug("Timezones are different");
143 }
144
145- if (tzchange != NULL) {
146+ if (geo_location != NULL && current_location != NULL) {
147+ g_debug("Got timezone %s", current_timezone);
148+ g_debug("Got timezone %s", geo_timezone);
149+ // Show neither current location nor geo location if both are the same
150+ // however, we want to set their time and label accordingly
151 if (in_sync) {
152- dbusmenu_menuitem_property_set_bool(tzchange, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
153+ if (current_timezone == NULL && geo_timezone == NULL) {
154+ dbusmenu_menuitem_property_set_bool(locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
155+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
156+ dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
157+ update_timezone_menu_items(NULL); // Update the timezone menu items
158+ return;
159+ }
160+
161+ dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
162+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
163+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
164+ dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
165+ dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
166+
167+ if (current_timezone != NULL) {
168+ label = current_timezone;
169+ } else {
170+ label = geo_timezone;
171+ }
172+
173+ if (label != NULL) {
174+ // TODO work out the current location name in a nice way
175+ dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_ZONE, label);
176+ // TODO work out the current time at that location
177+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
178+ dbusmenu_menuitem_property_set_bool(current_location, TIMEZONE_MENUITEM_PROP_RADIO, TRUE);
179+ } else {
180+ g_debug("Label for current location is null, this shouldn't happen");
181+ }
182+ if (geo_timezone != NULL) {
183+ // TODO work out the geo location name in a nice way
184+ dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_ZONE, geo_timezone);
185+ // TODO work out the current time at that location
186+ dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
187+ }
188 } else {
189- gchar * label = g_strdup_printf(_("Change timezone to: %s"), geo_timezone);
190-
191- dbusmenu_menuitem_property_set(tzchange, DBUSMENU_MENUITEM_PROP_LABEL, label);
192- dbusmenu_menuitem_property_set_bool(tzchange, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
193-
194- g_free(label);
195+ // TODO work out the geo location name in a nice way
196+ dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_ZONE, geo_timezone);
197+ // TODO work out the current time at that location
198+ dbusmenu_menuitem_property_set_bool(geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
199+
200+ // TODO work out the current location name in a nice way
201+ dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_ZONE, current_timezone);
202+ // TODO work out the current time at that location
203+ dbusmenu_menuitem_property_set_bool(current_location, TIMEZONE_MENUITEM_PROP_RADIO, TRUE);
204+ dbusmenu_menuitem_property_set_bool(current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
205+ dbusmenu_menuitem_property_set_bool(locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
206 }
207 }
208+ g_debug("Finished checking timezone sync");
209+ update_timezone_menu_items(NULL); // Update the timezone menu items
210
211 return;
212 }
213@@ -169,17 +225,22 @@
214
215 /* Set the timezone to the Geoclue discovered one */
216 static void
217-quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, const gchar *command)
218+quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, gpointer user_data)
219 {
220- g_debug("Quick setting timezone to: %s", geo_timezone);
221-
222- g_return_if_fail(geo_timezone != NULL);
223+ const gchar * tz = dbusmenu_menuitem_property_get(menuitem, TIMEZONE_MENUITEM_PROP_ZONE);
224+
225+ g_debug("Quick setting timezone to: %s", tz);
226+
227+ g_return_if_fail(tz != NULL);
228+
229+ if (g_strcmp0(tz, current_timezone) == 0)
230+ return;
231
232 OobsObject * obj = oobs_time_config_get();
233 g_return_if_fail(obj != NULL);
234
235 OobsTimeConfig * timeconfig = OOBS_TIME_CONFIG(obj);
236- oobs_time_config_set_timezone(timeconfig, geo_timezone);
237+ oobs_time_config_set_timezone(timeconfig, tz);
238
239 oobs_object_commit_async(obj, quick_set_tz_cb, NULL);
240
241@@ -239,9 +300,7 @@
242 g_debug("Found the calendar application: %s", evo);
243 dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
244 dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
245- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
246- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
247-
248+/*
249 GError *gerror = NULL;
250 // TODO: In reality we should iterate sources of calendar, but getting the local one doens't lag for > a minute
251 g_debug("Setting up ecal.");
252@@ -265,15 +324,26 @@
253 ecal = NULL;
254 }
255
256- /* This timezone represents the timezone of the calendar, this might be different to the current UTC offset.
257+ This timezone represents the timezone of the calendar, this might be different to the current UTC offset.
258 * this means we'll have some geoclue interaction going on, and possibly the user will be involved in setting
259 * their location manually, case in point: trains have satellite links which often geoclue to sweden,
260 * this shouldn't automatically set the location and mess up all the appointments for the user.
261- */
262+
263 if (ecal) ecal_timezone = icaltimezone_get_tzid(tzone);
264-
265+ */
266+ DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
267+ dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
268+ dbusmenu_menuitem_child_add_position(root, separator, 3);
269+
270+ add_appointment = dbusmenu_menuitem_new();
271+ dbusmenu_menuitem_property_set (add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Appointment"));
272+ dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
273+ dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
274+ g_signal_connect(G_OBJECT(add_appointment), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), "evolution -c calendar");
275+ dbusmenu_menuitem_child_add_position (root, add_appointment, 3);
276+
277 update_appointment_menu_items(NULL);
278- g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_appointment_menu_items), NULL);
279+ g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_appointment_menu_items), NULL);
280
281 g_free(evo);
282 } else {
283@@ -285,18 +355,92 @@
284 return FALSE;
285 }
286
287-/*
288+
289 static gboolean
290 update_timezone_menu_items(gpointer user_data) {
291- // Get the current location as specified by the user as a place name and time and add it,
292- // Get the location from geoclue as a place and time and add it,
293- // Get the evolution calendar timezone as a place and time and add it,
294- // Get the current timezone that the clock uses and select that
295- // Iterate over configured places and add any which aren't already listed
296- // Hook up each of these to setting the time/current timezone
297+ g_debug("Updating timezone menu items");
298+ gchar ** locations = g_settings_get_strv(conf, SETTINGS_LOCATIONS);
299+ if (locations == NULL) {
300+ g_debug("No locations configured (NULL)");
301+ return FALSE;
302+ }
303+ guint len = g_strv_length(locations);
304+ DbusmenuMenuitem *item;
305+ gint i, offset;
306+
307+ /* Remove all of the previous locations */
308+ if (dconflocations != NULL) {
309+ g_debug("Freeing old locations");
310+ while (dconflocations != NULL) {
311+ DbusmenuMenuitem * litem = DBUSMENU_MENUITEM(dconflocations->data);
312+ g_debug("Freeing old location: %p", litem);
313+ // Remove all the existing menu items which are in dconflocations.
314+ dconflocations = g_list_remove(dconflocations, litem);
315+ dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(litem));
316+ g_object_unref(G_OBJECT(litem));
317+ }
318+ }
319+
320+ // TODO: Remove items from the dconflocations at the end of the iteration
321+ // Make sure if there are multiple locations, our current location is shown
322+ if (len > 0) {
323+ dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
324+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
325+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
326+ } else {
327+ g_debug("No locations configured (Empty List)");
328+ return FALSE;
329+ }
330+
331+ offset = dbusmenu_menuitem_get_position (current_location, root)+1;
332+ for (i = 0; i < len; i++) {
333+ // Iterate over configured places and add any which aren't already listed
334+ if (g_strcmp0(locations[i], current_timezone) != 0 &&
335+ g_strcmp0(locations[i], geo_timezone) != 0) {
336+ g_debug("Adding timezone in update_timezones %s", locations[i]);
337+ item = dbusmenu_menuitem_new();
338+ dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
339+ dbusmenu_menuitem_property_set (item, TIMEZONE_MENUITEM_PROP_ZONE, locations[i]);
340+ dbusmenu_menuitem_property_set_bool (item, TIMEZONE_MENUITEM_PROP_RADIO, FALSE);
341+ dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
342+ dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
343+ dbusmenu_menuitem_child_add_position (root, item, offset++);
344+ g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
345+ dconflocations = g_list_append(dconflocations, item);
346+ }
347+ }
348+ g_strfreev (locations);
349+ // Get the evolution calendar timezone as a place and time and add it
350 return FALSE;
351 }
352-*/
353+
354+// Authentication function
355+static gchar *
356+auth_func (ECal *ecal, const gchar *prompt, const gchar *key, gpointer user_data) {
357+ ESource *source = e_cal_get_source (ecal);
358+ gchar *auth_domain = e_source_get_duped_property (source, "auth-domain");
359+
360+ const gchar *component_name;
361+ if (auth_domain) component_name = auth_domain;
362+ else component_name = "Calendar";
363+
364+ gchar *password = e_passwords_get_password (component_name, key);
365+
366+ if (password == NULL) {
367+ password = e_passwords_ask_password (
368+ _("Enter password"),
369+ component_name, key, prompt,
370+ E_PASSWORDS_REMEMBER_FOREVER |
371+ E_PASSWORDS_SECRET |
372+ E_PASSWORDS_ONLINE,
373+ &remember, NULL);
374+ }
375+
376+ g_free (auth_domain);
377+
378+ return password;
379+}
380+
381
382 // Compare function for g_list_sort of ECalComponent objects
383 static gint
384@@ -307,8 +451,13 @@
385 struct tm tm_a, tm_b;
386 time_t t_a, t_b;
387 gint retval = 0;
388-
389+
390+ if (a == NULL || b == NULL) return retval;
391+
392 ECalComponentVType vtype = e_cal_component_get_vtype (a);
393+
394+ if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return -1;
395+
396 if (vtype == E_CAL_COMPONENT_EVENT)
397 e_cal_component_get_dtstart (a, &datetime_a);
398 else
399@@ -317,6 +466,8 @@
400 t_a = mktime(&tm_a);
401
402 vtype = e_cal_component_get_vtype (b);
403+ if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return 1;
404+
405 if (vtype == E_CAL_COMPONENT_EVENT)
406 e_cal_component_get_dtstart (b, &datetime_b);
407 else
408@@ -340,15 +491,17 @@
409 */
410 static gboolean
411 update_appointment_menu_items (gpointer user_data) {
412- if (!ecal) return FALSE;
413 // FFR: we should take into account short term timers, for instance
414 // tea timers, pomodoro timers etc... that people may add, this is hinted to in the spec.
415 time_t t1, t2;
416 gchar *query, *is, *ie, *ad;
417 GList *objects = NULL, *l;
418+ GList *allobjects = NULL;
419+ GSList *g;
420 GError *gerror = NULL;
421 gint i;
422 gint width, height;
423+ ESourceList * sources = NULL;
424
425 time(&t1);
426 time(&t2);
427@@ -357,16 +510,6 @@
428 is = isodate_from_time_t(t1);
429 ie = isodate_from_time_t(t2);
430
431- // FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? Or sort it by date?
432- query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie);
433- g_debug("Getting objects with query: %s", query);
434- if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror)) {
435- g_debug("Failed to get objects\n");
436- g_free(ecal);
437- ecal = NULL;
438- return FALSE;
439- }
440- g_debug("Number of objects returned: %d", g_list_length(objects));
441 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
442
443 /* Remove all of the previous appointments */
444@@ -382,14 +525,62 @@
445 }
446 }
447
448+ // TODO Remove all highlights from the calendar widget
449+
450+ // FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? Or sort it by date?
451+ query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie);
452+
453+ if (!e_cal_get_sources(&sources, E_CAL_SOURCE_TYPE_EVENT, &gerror)) {
454+ g_debug("Failed to get ecal sources\n");
455+ return FALSE;
456+ }
457+
458+ // iterate the query for all sources
459+ for (g = e_source_list_peek_groups (sources); g; g = g->next) {
460+ ESourceGroup *group = E_SOURCE_GROUP (g->data);
461+ GSList *s;
462+
463+ for (s = e_source_group_peek_sources (group); s; s = s->next) {
464+ ESource *source = E_SOURCE (s->data);
465+ g_signal_connect (G_OBJECT(source), "changed", G_CALLBACK (update_appointment_menu_items), NULL);
466+ ECal *ecal = e_cal_new(source, E_CAL_SOURCE_TYPE_EVENT);
467+ e_cal_set_auth_func (ecal, (ECalAuthFunc) auth_func, NULL);
468+ //icaltimezone * tzone;
469+
470+ if (!e_cal_open(ecal, FALSE, &gerror)) {
471+ g_debug("Failed to get ecal sources %s", gerror->message);
472+ g_error_free(gerror);
473+ gerror = NULL;
474+ continue;
475+ }
476+
477+ g_debug("Getting objects with query: %s", query);
478+ if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror)) {
479+ g_debug("Failed to get objects\n");
480+ g_free(ecal);
481+ return FALSE;
482+ }
483+ g_debug("Number of objects returned: %d", g_list_length(objects));
484+
485+ if (allobjects == NULL) {
486+ allobjects = objects;
487+ } else if (objects != NULL) {
488+ allobjects = g_list_concat(allobjects, objects);
489+ g_object_unref(objects);
490+ }
491+ }
492+ }
493+
494 // Sort the list see above FIXME regarding queries
495- objects = g_list_sort(objects, (GCompareFunc) compare_appointment_items);
496+ g_debug("Sorting objects list");
497+ allobjects = g_list_sort(allobjects, (GCompareFunc) compare_appointment_items);
498 i = 0;
499- for (l = objects; l; l = l->next) {
500+ for (l = allobjects; l; l = l->next) {
501 ECalComponent *ecalcomp = l->data;
502 ECalComponentText valuetext;
503 ECalComponentDateTime datetime;
504 icaltimezone *appointment_zone = NULL;
505+ icaltimezone *current_zone = NULL;
506 icalproperty_status status;
507 gchar *summary, *cmd;
508 char right[20];
509@@ -397,6 +588,7 @@
510 struct tm tmp_tm;
511 DbusmenuMenuitem * item;
512
513+ g_debug("Start Object");
514 ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp);
515
516 // See above FIXME regarding query result
517@@ -415,7 +607,6 @@
518 dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
519 dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
520
521- g_debug("Start Object");
522 // Label text
523 e_cal_component_get_summary (ecalcomp, &valuetext);
524 summary = g_strdup (valuetext.value);
525@@ -437,10 +628,15 @@
526 continue;
527 }
528
529+ appointment_zone = icaltimezone_get_builtin_timezone_from_tzid(datetime.tzid);
530+ current_zone = icaltimezone_get_builtin_timezone_from_tzid(current_timezone);
531 if (!appointment_zone || datetime.value->is_date) { // If it's today put in the current timezone?
532- appointment_zone = tzone;
533+ appointment_zone = current_zone;
534 }
535- tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, tzone);
536+ // TODO: Convert the timezone into a 3 letter abbreviation if it's different to current_timezone
537+ // TODO: Add the appointment timezone to the list if it's not already there.
538+
539+ tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, current_zone);
540
541 g_debug("Generate time string");
542 // Get today
543@@ -454,11 +650,15 @@
544 strftime(right, 20, "%a %l:%M %P", &tmp_tm);
545
546 g_debug("Appointment time: %s", right);
547+ g_debug("Appointment timezone: %s", datetime.tzid);
548+ g_debug("Appointment timezone: %s", icaltimezone_get_tzid(appointment_zone)); // These two should be the same
549+ //g_debug("Calendar timezone: %s", ecal_timezone);
550+
551 dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right);
552
553 e_cal_component_free_datetime (&datetime);
554
555- ad = is = isodate_from_time_t(mktime(&tmp_tm));
556+ ad = isodate_from_time_t(mktime(&tmp_tm));
557
558 // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution
559 // FIXME Because the URI stuff is really broken, we're going to open the calendar at todays date instead
560@@ -470,15 +670,18 @@
561
562 g_debug("Command to Execute: %s", cmd);
563
564- ESource *source = e_cal_get_source (ecal);
565+ // FIXME This is now more difficult to get right with more sources, as we need to keep track
566+ // of which ecal or source goes with each ECalComponent :/
567+
568+ //ESource *source = e_cal_get_source (ecal);
569 //e_source_get_color (source, &source_color); api has been changed
570- const gchar *color_spec = e_source_peek_color_spec(source);
571- GdkColor color;
572+ const gchar *color_spec = NULL; //e_source_peek_color_spec(source);
573 g_debug("Colour to use: %s", color_spec);
574
575 // Draw the correct icon for the appointment type and then tint it using mask fill.
576 // For now we'll create a circle
577 if (color_spec != NULL) {
578+ GdkColor color;
579 gdk_color_parse (color_spec, &color);
580
581 cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
582@@ -493,14 +696,14 @@
583
584 dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf);
585 }
586- dbusmenu_menuitem_child_add_position (root, item, 4+i);
587+ dbusmenu_menuitem_child_add_position (root, item, 3+i);
588 appointments = g_list_append (appointments, item); // Keep track of the items here to make them east to remove
589 g_debug("Adding appointment: %p", item);
590
591 if (i == 4) break; // See above FIXME regarding query result limit
592 i++;
593 }
594- g_list_free(objects);
595+ g_object_unref(allobjects);
596 g_debug("End of objects");
597 return TRUE;
598 }
599@@ -552,31 +755,31 @@
600
601 g_idle_add(check_for_calendar, NULL);
602 }
603- DbusmenuMenuitem * separator;
604-
605- separator = dbusmenu_menuitem_new();
606- dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
607- dbusmenu_menuitem_child_append(root, separator);
608-
609- add_appointment = dbusmenu_menuitem_new();
610- dbusmenu_menuitem_property_set (add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Appointment"));
611- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
612- dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
613- g_signal_connect(G_OBJECT(add_appointment), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), "evolution -c calendar");
614- dbusmenu_menuitem_child_add_position (root, add_appointment, 4);
615-
616- separator = dbusmenu_menuitem_new();
617- dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
618- dbusmenu_menuitem_child_append(root, separator);
619-
620- tzchange = dbusmenu_menuitem_new();
621- dbusmenu_menuitem_property_set(tzchange, DBUSMENU_MENUITEM_PROP_LABEL, "Set specific timezone");
622- dbusmenu_menuitem_property_set_bool(tzchange, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
623- g_signal_connect(G_OBJECT(tzchange), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
624- dbusmenu_menuitem_child_append(root, tzchange);
625+
626+ locations_separator = dbusmenu_menuitem_new();
627+ dbusmenu_menuitem_property_set(locations_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
628+ dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
629+ dbusmenu_menuitem_child_append(root, locations_separator);
630+
631+ geo_location = dbusmenu_menuitem_new();
632+ dbusmenu_menuitem_property_set (geo_location, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
633+ dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_ZONE, "");
634+ dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
635+ dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
636+ g_signal_connect(G_OBJECT(geo_location), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
637+ dbusmenu_menuitem_child_append(root, geo_location);
638+
639+ current_location = dbusmenu_menuitem_new();
640+ dbusmenu_menuitem_property_set (current_location, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
641+ dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_ZONE, "");
642+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
643+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
644+ g_signal_connect(G_OBJECT(current_location), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
645+ dbusmenu_menuitem_child_append(root, current_location);
646+
647 check_timezone_sync();
648-
649- separator = dbusmenu_menuitem_new();
650+
651+ DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
652 dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
653 dbusmenu_menuitem_child_append(root, separator);
654
655@@ -859,8 +1062,9 @@
656 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
657 textdomain (GETTEXT_PACKAGE);
658
659- /* Cache the timezone */
660- update_current_timezone();
661+ /* Set up GSettings */
662+ conf = g_settings_new(SETTINGS_INTERFACE);
663+ // TODO Add a signal handler to catch gsettings changes and respond to them
664
665 /* Building the base menu */
666 server = dbusmenu_server_new(MENU_OBJ);
667@@ -868,6 +1072,9 @@
668 dbusmenu_server_set_root(server, root);
669
670 build_menus(root);
671+
672+ /* Cache the timezone */
673+ update_current_timezone();
674
675 /* Setup geoclue */
676 GeoclueMaster * master = geoclue_master_get_default();
677@@ -885,14 +1092,15 @@
678 mainloop = g_main_loop_new(NULL, FALSE);
679 g_main_loop_run(mainloop);
680
681- geo_address_clean();
682- geo_client_clean();
683-
684+ g_object_unref(G_OBJECT(conf));
685 g_object_unref(G_OBJECT(master));
686 g_object_unref(G_OBJECT(dbus));
687 g_object_unref(G_OBJECT(service));
688 g_object_unref(G_OBJECT(server));
689 g_object_unref(G_OBJECT(root));
690
691+ geo_address_clean();
692+ geo_client_clean();
693+
694 return 0;
695 }
696
697=== modified file 'src/dbus-shared.h'
698--- src/dbus-shared.h 2011-01-31 10:32:24 +0000
699+++ src/dbus-shared.h 2011-02-17 15:54:42 +0000
700@@ -35,6 +35,5 @@
701 #define APPOINTMENT_MENUITEM_PROP_RIGHT "appointment-time"
702
703 #define TIMEZONE_MENUITEM_TYPE "timezone-item"
704-#define TIMEZONE_MENUITEM_PROP_LABEL "timezone-label"
705+#define TIMEZONE_MENUITEM_PROP_ZONE "timezone-zone"
706 #define TIMEZONE_MENUITEM_PROP_RADIO "timezone-radio"
707-#define TIMEZONE_MENUITEM_PROP_RIGHT "timezone-time"
708
709=== modified file 'src/indicator-datetime.c'
710--- src/indicator-datetime.c 2011-02-09 03:37:50 +0000
711+++ src/indicator-datetime.c 2011-02-17 15:54:42 +0000
712@@ -89,6 +89,8 @@
713 GDBusProxy * service_proxy;
714 IdoCalendarMenuItem *ido_calendar;
715
716+ GList * timezone_items;
717+
718 GSettings * settings;
719 };
720
721@@ -105,7 +107,9 @@
722
723 typedef struct _indicator_item_t indicator_item_t;
724 struct _indicator_item_t {
725- GtkWidget * radio;
726+ IndicatorDatetime * self;
727+ DbusmenuMenuitem * mi;
728+ GtkWidget * gmi;
729 GtkWidget * icon;
730 GtkWidget * label;
731 GtkWidget * right;
732@@ -168,15 +172,16 @@
733 static GtkMenu * get_menu (IndicatorObject * io);
734 static GVariant * bind_enum_set (const GValue * value, const GVariantType * type, gpointer user_data);
735 static gboolean bind_enum_get (GValue * value, GVariant * variant, gpointer user_data);
736-static gchar * generate_format_string (IndicatorDatetime * self);
737-static struct tm * update_label (IndicatorDatetime * io);
738+static gchar * generate_format_string_now (IndicatorDatetime * self);
739+static gchar * generate_format_string_at_time (IndicatorDatetime * self, GDateTime * time);
740+static void update_label (IndicatorDatetime * io, GDateTime ** datetime);
741 static void guess_label_size (IndicatorDatetime * self);
742-static void setup_timer (IndicatorDatetime * self, struct tm * ltime);
743+static void setup_timer (IndicatorDatetime * self, GDateTime * datetime);
744 static void update_time (IndicatorDatetime * self);
745 static void receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data);
746 static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
747 static gint generate_strftime_bitmask (const char *time_str);
748-static GSList *location_group = NULL;
749+static void timezone_update_labels (indicator_item_t * mi_data);
750
751 /* Indicator Module Config */
752 INDICATOR_SET_VERSION
753@@ -263,7 +268,7 @@
754 self->priv->custom_string = g_strdup(DEFAULT_TIME_FORMAT);
755 self->priv->custom_show_seconds = FALSE;
756
757- self->priv->time_string = generate_format_string(self);
758+ self->priv->time_string = generate_format_string_now(self);
759
760 self->priv->service_proxy = NULL;
761
762@@ -460,6 +465,13 @@
763 return TRUE;
764 }
765
766+static void
767+timezone_update_all_labels (IndicatorDatetime * self)
768+{
769+ IndicatorDatetimePrivate *priv = INDICATOR_DATETIME_GET_PRIVATE(self);
770+ g_list_foreach(priv->timezone_items, (GFunc)timezone_update_labels, NULL);
771+}
772+
773 /* Sets a property on the object */
774 static void
775 set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
776@@ -529,7 +541,7 @@
777 }
778
779 /* Get the new format string */
780- gchar * newformat = generate_format_string(self);
781+ gchar * newformat = generate_format_string_now(self);
782
783 /* check to ensure the format really changed */
784 if (g_strcmp0(self->priv->time_string, newformat) == 0) {
785@@ -545,7 +557,8 @@
786 self->priv->time_string = newformat;
787
788 /* And update everything */
789- update_label(self);
790+ update_label(self, NULL);
791+ timezone_update_all_labels(self);
792 guess_label_size(self);
793
794 return;
795@@ -603,54 +616,72 @@
796 return FALSE;
797 }
798
799-/* Updates the label to be the current time. */
800-static struct tm *
801-update_label (IndicatorDatetime * io)
802+static void
803+set_label_to_time_in_zone (IndicatorDatetime * self, GtkLabel * label,
804+ GTimeZone * tz, const gchar * format,
805+ GDateTime ** datetime)
806 {
807- IndicatorDatetime * self = INDICATOR_DATETIME(io);
808-
809- if (self->priv->label == NULL) return NULL;
810-
811- gchar longstr[256];
812- time_t t;
813- struct tm *ltime;
814- gboolean use_markup;
815-
816- t = time(NULL);
817- ltime = localtime(&t);
818- if (ltime == NULL) {
819- g_debug("Error getting local time");
820- gtk_label_set_label(self->priv->label, _("Error getting time"));
821- return NULL;
822- }
823-
824- strftime(longstr, 256, self->priv->time_string, ltime);
825-
826- gchar * utf8 = g_locale_to_utf8(longstr, -1, NULL, NULL, NULL);
827-
828- if (pango_parse_markup(utf8, -1, 0, NULL, NULL, NULL, NULL))
829+ GDateTime * datetime_now;
830+ if (tz == NULL)
831+ datetime_now = g_date_time_new_now_local();
832+ else
833+ datetime_now = g_date_time_new_now(tz);
834+
835+ gchar * timestr;
836+ if (format == NULL) {
837+ gchar * format_for_time = generate_format_string_at_time(self, datetime_now);
838+ timestr = g_date_time_format(datetime_now, format_for_time);
839+ g_free(format_for_time);
840+ }
841+ else {
842+ timestr = g_date_time_format(datetime_now, format);
843+ }
844+
845+ gboolean use_markup = FALSE;
846+ if (pango_parse_markup(timestr, -1, 0, NULL, NULL, NULL, NULL))
847 use_markup = TRUE;
848
849 if (use_markup)
850- gtk_label_set_markup(self->priv->label, utf8);
851- else
852- gtk_label_set_text(self->priv->label, utf8);
853-
854- g_free(utf8);
855+ gtk_label_set_markup(label, timestr);
856+ else
857+ gtk_label_set_text(label, timestr);
858+
859+ g_free(timestr);
860+
861+ if (datetime)
862+ *datetime = datetime_now;
863+ else
864+ g_date_time_unref(datetime_now);
865+
866+ return;
867+}
868+
869+/* Updates the label to be the current time. */
870+static void
871+update_label (IndicatorDatetime * io, GDateTime ** datetime)
872+{
873+ IndicatorDatetime * self = INDICATOR_DATETIME(io);
874+
875+ if (self->priv->label == NULL) return;
876+
877+ set_label_to_time_in_zone(self, self->priv->label, NULL, self->priv->time_string, datetime);
878
879 if (self->priv->idle_measure == 0) {
880 self->priv->idle_measure = g_idle_add(idle_measure, io);
881 }
882
883- return ltime;
884+ return;
885 }
886
887 /* Update the time right now. Usually the result of a timezone switch. */
888 static void
889 update_time (IndicatorDatetime * self)
890 {
891- struct tm * ltime = update_label(self);
892- setup_timer(self, ltime);
893+ GDateTime * dt;
894+ update_label(self, &dt);
895+ timezone_update_all_labels(self);
896+ setup_timer(self, dt);
897+ g_date_time_unref(dt);
898 return;
899 }
900
901@@ -674,15 +705,20 @@
902 {
903 IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
904 self->priv->timer = 0;
905- struct tm * ltime = update_label(self);
906- setup_timer(self, ltime);
907+ GDateTime * dt;
908+ update_label(self, &dt);
909+ timezone_update_all_labels(self);
910+ setup_timer(self, dt);
911+ g_date_time_unref(dt);
912 return FALSE;
913 }
914
915 /* Configure the timer to run the next time through */
916 static void
917-setup_timer (IndicatorDatetime * self, struct tm * ltime)
918+setup_timer (IndicatorDatetime * self, GDateTime * datetime)
919 {
920+ gboolean unref = FALSE;
921+
922 if (self->priv->timer != 0) {
923 g_source_remove(self->priv->timer);
924 self->priv->timer = 0;
925@@ -692,14 +728,18 @@
926 (self->priv->time_mode == SETTINGS_TIME_CUSTOM && self->priv->custom_show_seconds)) {
927 self->priv->timer = g_timeout_add_seconds(1, timer_func, self);
928 } else {
929- if (ltime == NULL) {
930- time_t t;
931- t = time(NULL);
932- ltime = localtime(&t);
933+ if (datetime == NULL) {
934+ datetime = g_date_time_new_now_local();
935+ unref = TRUE;
936 }
937
938 /* Plus 2 so we're just after the minute, don't want to be early. */
939- self->priv->timer = g_timeout_add_seconds(60 - ltime->tm_sec + 2, timer_func, self);
940+ gint seconds = (gint)g_date_time_get_seconds(datetime);
941+ self->priv->timer = g_timeout_add_seconds(60 - seconds + 2, timer_func, self);
942+
943+ if (unref) {
944+ g_date_time_unref(datetime);
945+ }
946 }
947
948 return;
949@@ -926,7 +966,8 @@
950 g_debug("New style for time label");
951 IndicatorDatetime * self = INDICATOR_DATETIME(data);
952 guess_label_size(self);
953- update_label(self);
954+ update_label(self, NULL);
955+ timezone_update_all_labels(self);
956 return;
957 }
958
959@@ -1001,12 +1042,8 @@
960 /* Tries to figure out what our format string should be. Lots
961 of translator comments in here. */
962 static gchar *
963-generate_format_string (IndicatorDatetime * self)
964+generate_format_string_full (IndicatorDatetime * self, gboolean show_day, gboolean show_date)
965 {
966- if (self->priv->time_mode == SETTINGS_TIME_CUSTOM) {
967- return g_strdup(self->priv->custom_string);
968- }
969-
970 gboolean twelvehour = TRUE;
971
972 if (self->priv->time_mode == SETTINGS_TIME_LOCALE) {
973@@ -1039,20 +1076,20 @@
974
975 /* If there's no date or day let's just leave now and
976 not worry about the rest of this code */
977- if (!self->priv->show_date && !self->priv->show_day) {
978+ if (!show_date && !show_day) {
979 return g_strdup(time_string);
980 }
981
982 const gchar * date_string = NULL;
983- if (self->priv->show_date && self->priv->show_day) {
984+ if (show_date && show_day) {
985 /* TRANSLATORS: This is a format string passed to strftime to represent
986 the day of the week, the month and the day of the month. */
987 date_string = T_("%a %b %e");
988- } else if (self->priv->show_date) {
989+ } else if (show_date) {
990 /* TRANSLATORS: This is a format string passed to strftime to represent
991 the month and the day of the month. */
992 date_string = T_("%b %e");
993- } else if (self->priv->show_day) {
994+ } else if (show_day) {
995 /* TRANSLATORS: This is a format string passed to strftime to represent
996 the day of the week. */
997 date_string = T_("%a");
998@@ -1067,17 +1104,94 @@
999 return g_strdup_printf(T_("%s, %s"), date_string, time_string);
1000 }
1001
1002+static gchar *
1003+generate_format_string_now (IndicatorDatetime * self)
1004+{
1005+ if (self->priv->time_mode == SETTINGS_TIME_CUSTOM) {
1006+ return g_strdup(self->priv->custom_string);
1007+ }
1008+ else {
1009+ return generate_format_string_full(self,
1010+ self->priv->show_day,
1011+ self->priv->show_date);
1012+ }
1013+}
1014+
1015+static gchar *
1016+generate_format_string_at_time (IndicatorDatetime * self, GDateTime * time)
1017+{
1018+ /* This is a bit less free-form than for the main "now" time label. */
1019+ /* If it is today, just the time should be shown (e.g. “3:55 PM”)
1020+ If it is a different day this week, the day and time should be shown (e.g. “Wed 3:55 PM”)
1021+ If it is after this week, the day, date, and time should be shown (e.g. “Wed 21 Apr 3:55 PM”).
1022+ In addition, when presenting the times of upcoming events, the time should be followed by the timezone if it is different from the one the computer is currently set to. For example, “Wed 3:55 PM UTC−5”. */
1023+ gboolean show_day = FALSE;
1024+ gboolean show_date = FALSE;
1025+
1026+ GDateTime * now = g_date_time_new_now_local();
1027+
1028+ /* First, are we same day? */
1029+ gint time_year, time_month, time_day;
1030+ gint now_year, now_month, now_day;
1031+ g_date_time_get_ymd(time, &time_year, &time_month, &time_day);
1032+ g_date_time_get_ymd(now, &now_year, &now_month, &now_day);
1033+
1034+ if (time_year != now_year ||
1035+ time_month != now_month ||
1036+ time_day != now_day) {
1037+ /* OK, different days so we must at least show the day. */
1038+ show_day = TRUE;
1039+
1040+ /* Is it this week? */
1041+ /* Here, we define "is this week" as yesterday, today, or the next five days */
1042+ GDateTime * past = g_date_time_add_days(now, -1);
1043+ GDateTime * future = g_date_time_add_days(now, 5);
1044+ GDateTime * past_bound = g_date_time_new_local(g_date_time_get_year(past),
1045+ g_date_time_get_month(past),
1046+ g_date_time_get_day_of_month(past),
1047+ 0, 0, 0.0);
1048+ GDateTime * future_bound = g_date_time_new_local(g_date_time_get_year(future),
1049+ g_date_time_get_month(future),
1050+ g_date_time_get_day_of_month(future),
1051+ 23, 59, 59.9);
1052+ if (g_date_time_compare(time, past_bound) < 0 ||
1053+ g_date_time_compare(time, future_bound) > 0) {
1054+ show_date = TRUE;
1055+ }
1056+ g_date_time_unref(past);
1057+ g_date_time_unref(future);
1058+ g_date_time_unref(past_bound);
1059+ g_date_time_unref(future_bound);
1060+ }
1061+
1062+ return generate_format_string_full(self, show_day, show_date);
1063+}
1064+
1065+static void
1066+timezone_update_labels (indicator_item_t * mi_data)
1067+{
1068+ const gchar * zone_name = dbusmenu_menuitem_property_get(mi_data->mi, TIMEZONE_MENUITEM_PROP_ZONE);
1069+
1070+ /* TODO: Make zone name a little more user friendly */
1071+ gtk_label_set_text(GTK_LABEL(mi_data->label), zone_name);
1072+
1073+ /* Show current time in that zone on the right */
1074+ GTimeZone * tz = g_time_zone_new(zone_name);
1075+ set_label_to_time_in_zone(mi_data->self, GTK_LABEL(mi_data->right), tz, NULL, NULL);
1076+ g_time_zone_unref(tz);
1077+}
1078+
1079 /* Whenever we have a property change on a DbusmenuMenuitem
1080 we need to be responsive to that. */
1081 static void
1082-indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, indicator_item_t * mi_data)
1083+indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant *value, indicator_item_t * mi_data)
1084 {
1085 if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_LABEL)) {
1086 /* Set the main label */
1087- gtk_label_set_text(GTK_LABEL(mi_data->label), value);
1088+ gtk_label_set_text(GTK_LABEL(mi_data->label), g_variant_get_string(value, NULL));
1089 } else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_RIGHT)) {
1090 /* Set the right label */
1091- gtk_label_set_text(GTK_LABEL(mi_data->right), value);
1092+ gtk_label_set_text(GTK_LABEL(mi_data->right), g_variant_get_string(value, NULL));
1093 } else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_ICON)) {
1094 /* We don't use the value here, which is probably less efficient,
1095 but it's easier to use the easy function. And since th value
1096@@ -1106,6 +1220,10 @@
1097 g_object_unref(resized_pixbuf);
1098 }
1099 }
1100+ } else if (!g_strcmp0(prop, TIMEZONE_MENUITEM_PROP_ZONE)) {
1101+ timezone_update_labels(mi_data);
1102+ } else if (!g_strcmp0(prop, TIMEZONE_MENUITEM_PROP_RADIO)) {
1103+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi_data->gmi), g_variant_get_boolean(value));
1104 } else {
1105 g_warning("Indicator Item property '%s' unknown", prop);
1106 }
1107@@ -1127,7 +1245,7 @@
1108
1109 indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
1110
1111- GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
1112+ mi_data->gmi = gtk_menu_item_new();
1113
1114 GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
1115
1116@@ -1178,10 +1296,10 @@
1117 gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
1118 gtk_widget_show(mi_data->right);
1119
1120- gtk_container_add(GTK_CONTAINER(gmi), hbox);
1121+ gtk_container_add(GTK_CONTAINER(mi_data->gmi), hbox);
1122 gtk_widget_show(hbox);
1123
1124- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
1125+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(mi_data->gmi), parent);
1126
1127 g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
1128 g_signal_connect_swapped(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data);
1129@@ -1217,6 +1335,24 @@
1130 return TRUE;
1131 }
1132
1133+static void
1134+timezone_toggled_cb (GtkCheckMenuItem *checkmenuitem, DbusmenuMenuitem * dbusitem)
1135+{
1136+ /* Make sure that the displayed radio-active setting is always
1137+ consistent with the dbus menuitem */
1138+ gtk_check_menu_item_set_active(checkmenuitem,
1139+ dbusmenu_menuitem_property_get_bool(dbusitem, TIMEZONE_MENUITEM_PROP_RADIO));
1140+}
1141+
1142+static void
1143+timezone_destroyed_cb (DbusmenuMenuitem * dbusitem, indicator_item_t * mi_data)
1144+{
1145+ IndicatorDatetimePrivate *priv = INDICATOR_DATETIME_GET_PRIVATE(mi_data->self);
1146+ priv->timezone_items = g_list_remove(priv->timezone_items, mi_data);
1147+ g_signal_handlers_disconnect_by_func(G_OBJECT(mi_data->gmi), G_CALLBACK(timezone_toggled_cb), dbusitem);
1148+ g_free(mi_data);
1149+}
1150+
1151 static gboolean
1152 new_timezone_item(DbusmenuMenuitem * newitem,
1153 DbusmenuMenuitem * parent,
1154@@ -1227,44 +1363,54 @@
1155 g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
1156 /* Note: not checking parent, it's reasonable for it to be NULL */
1157
1158+ IndicatorObject *io = g_object_get_data (G_OBJECT (client), "indicator");
1159+ if (io == NULL) {
1160+ g_warning ("found no indicator to attach the timezone to");
1161+ return FALSE;
1162+ }
1163+
1164+ IndicatorDatetime *self = INDICATOR_DATETIME(io);
1165+ IndicatorDatetimePrivate *priv = INDICATOR_DATETIME_GET_PRIVATE(self);
1166+
1167 // Menu item with a radio button and a right aligned time
1168 indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
1169
1170- GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
1171-
1172- GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
1173-
1174- mi_data->radio = gtk_radio_button_new(location_group);
1175- if (location_group == NULL)
1176- location_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(mi_data->radio));
1177-
1178- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mi_data->radio),
1179+ priv->timezone_items = g_list_prepend(priv->timezone_items, mi_data);
1180+
1181+ mi_data->self = self;
1182+ mi_data->mi = newitem;
1183+ mi_data->gmi = gtk_check_menu_item_new();
1184+
1185+ gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(mi_data->gmi), TRUE);
1186+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi_data->gmi),
1187 dbusmenu_menuitem_property_get_bool(newitem, TIMEZONE_MENUITEM_PROP_RADIO));
1188-
1189- gtk_box_pack_start(GTK_BOX(hbox), mi_data->radio, FALSE, FALSE, 0);
1190- gtk_widget_show(mi_data->radio);
1191-
1192+
1193+ GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
1194+
1195 /* Label, probably a username, chat room or mailbox name */
1196- mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_MENUITEM_PROP_LABEL));
1197+ mi_data->label = gtk_label_new("");
1198 gtk_misc_set_alignment(GTK_MISC(mi_data->label), 0.0, 0.5);
1199 gtk_box_pack_start(GTK_BOX(hbox), mi_data->label, TRUE, TRUE, 0);
1200 gtk_widget_show(mi_data->label);
1201
1202 /* Usually either the time or the count on the individual
1203 item. */
1204- mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_MENUITEM_PROP_RIGHT));
1205+ mi_data->right = gtk_label_new("");
1206 gtk_size_group_add_widget(indicator_right_group, mi_data->right);
1207 gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5);
1208 gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
1209 gtk_widget_show(mi_data->right);
1210
1211- gtk_container_add(GTK_CONTAINER(gmi), hbox);
1212+ timezone_update_labels(mi_data);
1213+
1214+ gtk_container_add(GTK_CONTAINER(mi_data->gmi), hbox);
1215 gtk_widget_show(hbox);
1216
1217- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
1218+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(mi_data->gmi), parent);
1219
1220+ g_signal_connect(G_OBJECT(mi_data->gmi), "toggled", G_CALLBACK(timezone_toggled_cb), newitem);
1221 g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
1222- g_signal_connect_swapped(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data);
1223+ g_signal_connect(G_OBJECT(newitem), "destroyed", G_CALLBACK(timezone_destroyed_cb), mi_data);
1224
1225 return TRUE;
1226 }
1227@@ -1284,7 +1430,7 @@
1228 g_signal_connect(G_OBJECT(self->priv->label), "style-set", G_CALLBACK(style_changed), self);
1229 g_signal_connect(G_OBJECT(self->priv->label), "screen-changed", G_CALLBACK(update_text_gravity), self);
1230 guess_label_size(self);
1231- update_label(self);
1232+ update_label(self, NULL);
1233 gtk_widget_show(GTK_WIDGET(self->priv->label));
1234 }
1235

Subscribers

People subscribed via source and target branches