← Back to team overview

ayatana-commits team mailing list archive

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

 

Karl Lattimer has proposed merging lp:~karl-qdh/indicator-datetime/multiplecalendarsources_and_timezones into lp:indicator-datetime.

Requested reviews:
  Ted Gould (ted)
Related bugs:
  #715844 Locations in datetime indicator
  https://bugs.launchpad.net/bugs/715844
  #717209 Support remote calendars, asynchronously
  https://bugs.launchpad.net/bugs/717209

For more details, see:
https://code.launchpad.net/~karl-qdh/indicator-datetime/multiplecalendarsources_and_timezones/+merge/50011
-- 
https://code.launchpad.net/~karl-qdh/indicator-datetime/multiplecalendarsources_and_timezones/+merge/50011
Your team ayatana-commits is subscribed to branch lp:indicator-datetime.
=== modified file 'configure.ac'
--- configure.ac	2011-02-09 03:37:50 +0000
+++ configure.ac	2011-02-16 17:06:57 +0000
@@ -91,6 +91,7 @@
 	                             libecal-1.2 >= $ECAL_REQUIRED_VERSION
 	                             libical >= $ICAL_REQUIRED_VERSION
 	                             libedataserver-1.2 >= EDS_REQUIRED_VERSION
+	                             libedataserverui-1.2 >= EDS_REQUIRED_VERSION
 	                             cairo >= CAIRO_REQUIRED_VERSION
 	                             gdk-2.0 >= GDK_REQUIRED_VERSION)
 		],
@@ -105,6 +106,7 @@
 	                             libecal-1.2 >= $ECAL_REQUIRED_VERSION
 	                             libical >= $ICAL_REQUIRED_VERSION
 	                             libedataserver-1.2 >= EDS_REQUIRED_VERSION
+	                             libedataserverui-1.2 >= EDS_REQUIRED_VERSION
 	                             cairo >= CAIRO_REQUIRED_VERSION
 	                             gdk-2.0 >= GDK_REQUIRED_VERSION)
         ],

=== modified file 'data/com.canonical.indicator.datetime.gschema.xml'
--- data/com.canonical.indicator.datetime.gschema.xml	2011-01-17 17:50:14 +0000
+++ data/com.canonical.indicator.datetime.gschema.xml	2011-02-16 17:06:57 +0000
@@ -57,5 +57,13 @@
 			  more information.
 			</description>
 		</key>
+		<key name="locations" type="as">
+			<default>[]</default>
+			<summary>A List of locations</summary>
+			<description>
+			  Adds the list of locations the user has configured to display in the 
+			  indicator-datetime menu.
+			</description>
+		</key>
 	</schema>
 </schemalist>

=== modified file 'src/datetime-service.c'
--- src/datetime-service.c	2011-02-09 04:26:31 +0000
+++ src/datetime-service.c	2011-02-16 17:06:57 +0000
@@ -42,6 +42,7 @@
 #include <libical/ical.h>
 #include <libecal/e-cal-time-util.h>
 #include <libedataserver/e-source.h>
+#include <libedataserverui/e-passwords.h>
 // Other users of ecal seem to also include these, not sure why they should be included by the above
 #include <libical/icaltime.h>
 #include <cairo/cairo.h>
@@ -52,8 +53,13 @@
 #include "datetime-interface.h"
 #include "dbus-shared.h"
 
+
+#define SETTINGS_INTERFACE "com.canonical.indicator.datetime"
+#define SETTINGS_LOCATIONS "locations"
+
 static void geo_create_client (GeoclueMaster * master, GeoclueMasterClient * client, gchar * path, GError * error, gpointer user_data);
 static gboolean update_appointment_menu_items (gpointer user_data);
+static gboolean update_timezone_menu_items(gpointer user_data);
 static void setup_timer (void);
 static void geo_client_invalid (GeoclueMasterClient * client, gpointer user_data);
 static void geo_address_change (GeoclueMasterClient * client, gchar * a, gchar * b, gchar * c, gchar * d, gpointer user_data);
@@ -63,30 +69,35 @@
 static DbusmenuServer * server = NULL;
 static DbusmenuMenuitem * root = NULL;
 static DatetimeInterface * dbus = NULL;
-static gchar * current_timezone = NULL;
 
 /* Global Items */
 static DbusmenuMenuitem * date = NULL;
 static DbusmenuMenuitem * calendar = NULL;
 static DbusmenuMenuitem * settings = NULL;
-static DbusmenuMenuitem * tzchange = NULL;
+static DbusmenuMenuitem * locations_separator = NULL;
+static DbusmenuMenuitem * geo_location = NULL;
+static DbusmenuMenuitem * current_location = NULL;
+//static DbusmenuMenuitem * ecal_location = NULL;
 static DbusmenuMenuitem * add_appointment = NULL;
-// static DbusmenuMenuitem * add_location = NULL;
 static GList			* appointments = NULL;
-static ECal				* ecal = NULL;
-static const gchar		* ecal_timezone = NULL;
-static icaltimezone     *tzone;
+static GList			* dconflocations = NULL;
+GSettings *conf;
+
 
 /* Geoclue trackers */
 static GeoclueMasterClient * geo_master = NULL;
 static GeoclueAddress * geo_address = NULL;
-static gchar * geo_timezone = NULL;
+
+/* Our 2 important timezones */
+static gchar 			* current_timezone = NULL;
+static gchar 			* geo_timezone = NULL;
 
 /* Check to see if our timezones are the same */
 static void
 check_timezone_sync (void) {
+	gchar * label;
 	gboolean in_sync = FALSE;
-
+	
 	if (geo_timezone == NULL) {
 		in_sync = TRUE;
 	}
@@ -105,18 +116,67 @@
 		g_debug("Timezones are different");
 	}
 
-	if (tzchange != NULL) {
+	if (geo_location != NULL && current_location != NULL) {
+		g_debug("Got timezone %s", current_timezone);
+		g_debug("Got timezone %s", geo_timezone);
+		// Show neither current location nor geo location if both are the same
+		// however, we want to set their time and label accordingly
 		if (in_sync) {
-			dbusmenu_menuitem_property_set_bool(tzchange, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			if (current_timezone == NULL && geo_timezone == NULL) {
+				dbusmenu_menuitem_property_set_bool(locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+				dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+				dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+				update_timezone_menu_items(NULL); // Update the timezone menu items 
+				return;
+			}
+			
+			dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+			dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+			
+			if (current_timezone != NULL) {
+				label = current_timezone;
+			} else {
+				label = geo_timezone;
+			}
+			
+			if (label != NULL) {
+				// TODO work out the current location name in a nice way
+				dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_LABEL, label);
+				// TODO work out the current time at that location 
+				dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
+				dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+				dbusmenu_menuitem_property_set_bool(current_location, TIMEZONE_MENUITEM_PROP_RADIO, TRUE);
+			} else {
+				g_debug("Label for current location is null, this shouldn't happen");
+			}
+			if (geo_timezone != NULL) {	
+				// TODO work out the geo location name in a nice way
+				dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_LABEL, geo_timezone);
+				// TODO work out the current time at that location 
+				dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
+				dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+			}
 		} else {
-			gchar * label = g_strdup_printf(_("Change timezone to: %s"), geo_timezone);
-
-			dbusmenu_menuitem_property_set(tzchange, DBUSMENU_MENUITEM_PROP_LABEL, label);
-			dbusmenu_menuitem_property_set_bool(tzchange, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-
-			g_free(label);
+			// TODO work out the geo location name in a nice way
+			dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_LABEL, geo_timezone);
+			// TODO work out the current time at that location 
+			dbusmenu_menuitem_property_set (geo_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
+			dbusmenu_menuitem_property_set_bool(geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+			
+			// TODO work out the current location name in a nice way
+			dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_LABEL, current_timezone);
+			// TODO work out the current time at that location 
+			dbusmenu_menuitem_property_set (current_location, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
+			dbusmenu_menuitem_property_set_bool(current_location, TIMEZONE_MENUITEM_PROP_RADIO, TRUE);
+			dbusmenu_menuitem_property_set_bool(current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+			dbusmenu_menuitem_property_set_bool(locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 		}
 	}
+	g_debug("Finished checking timezone sync");
+	update_timezone_menu_items(NULL); // Update the timezone menu items 
 
 	return;
 }
@@ -169,17 +229,22 @@
 
 /* Set the timezone to the Geoclue discovered one */
 static void
-quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, const gchar *command)
+quick_set_tz (DbusmenuMenuitem * menuitem, guint timestamp, gpointer user_data)
 {
-	g_debug("Quick setting timezone to: %s", geo_timezone);
-
-	g_return_if_fail(geo_timezone != NULL);
+	const gchar * tz = dbusmenu_menuitem_property_get(menuitem, TIMEZONE_MENUITEM_PROP_LABEL);
+
+	g_debug("Quick setting timezone to: %s", tz);
+
+	g_return_if_fail(tz != NULL);
+
+	if (g_strcmp0(tz, current_timezone) == 0)
+		return;
 
 	OobsObject * obj = oobs_time_config_get();
 	g_return_if_fail(obj != NULL);
 
 	OobsTimeConfig * timeconfig = OOBS_TIME_CONFIG(obj);
-	oobs_time_config_set_timezone(timeconfig, geo_timezone);
+	oobs_time_config_set_timezone(timeconfig, tz);
 
 	oobs_object_commit_async(obj, quick_set_tz_cb, NULL);
 
@@ -239,9 +304,7 @@
 		g_debug("Found the calendar application: %s", evo);
 		dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
 		dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-		dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
-		dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-
+/*
 		GError *gerror = NULL;
 		// TODO: In reality we should iterate sources of calendar, but getting the local one doens't lag for > a minute
 		g_debug("Setting up ecal.");
@@ -265,15 +328,26 @@
 			ecal = NULL;
 		}
 	
-		/* This timezone represents the timezone of the calendar, this might be different to the current UTC offset.
+		 This timezone represents the timezone of the calendar, this might be different to the current UTC offset.
 		 * this means we'll have some geoclue interaction going on, and possibly the user will be involved in setting
 		 * their location manually, case in point: trains have satellite links which often geoclue to sweden,
 		 * this shouldn't automatically set the location and mess up all the appointments for the user.
-		 */
+		 
 		if (ecal) ecal_timezone = icaltimezone_get_tzid(tzone);
-	
+		*/
+		DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
+		dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
+		dbusmenu_menuitem_child_add_position(root, separator, 3);
+
+		add_appointment = dbusmenu_menuitem_new();
+		dbusmenu_menuitem_property_set     (add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Appointment"));
+		dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+		dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+		g_signal_connect(G_OBJECT(add_appointment), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), "evolution -c calendar");
+		dbusmenu_menuitem_child_add_position (root, add_appointment, 3);
+
 		update_appointment_menu_items(NULL);
-		g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_appointment_menu_items), NULL);		
+		g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_appointment_menu_items), NULL);	
 
 		g_free(evo);
 	} else {
@@ -285,18 +359,97 @@
 	return FALSE;
 }
 
-/*
+
 static gboolean
 update_timezone_menu_items(gpointer user_data) {
-	// Get the current location as specified by the user as a place name and time and add it,
-	// Get the location from geoclue as a place and time and add it,
-	// Get the evolution calendar timezone as a place and time and add it,
-	// Get the current timezone that the clock uses and select that
-	// Iterate over configured places and add any which aren't already listed
-	// Hook up each of these to setting the time/current timezone
+	g_debug("Updating timezone menu items");
+	gchar ** locations = g_settings_get_strv(conf, SETTINGS_LOCATIONS);
+	if (locations == NULL) { 
+		g_debug("No locations configured (NULL)");
+		return FALSE;
+	} 
+	guint len = g_strv_length(locations);
+	DbusmenuMenuitem *item;
+	gint i, offset;
+	
+	/* Remove all of the previous locations */
+	if (dconflocations != NULL) {
+		g_debug("Freeing old locations");
+		while (dconflocations != NULL) {
+			DbusmenuMenuitem * litem =  DBUSMENU_MENUITEM(dconflocations->data);
+			g_debug("Freeing old location: %p", litem);
+			// Remove all the existing menu items which are in dconflocations.
+			dconflocations = g_list_remove(dconflocations, litem);
+			dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(litem));
+			g_object_unref(G_OBJECT(litem));
+		}
+	}
+	
+	// TODO: Remove items from the dconflocations at the end of the iteration
+	// Make sure if there are multiple locations, our current location is shown
+	if (len > 0) {
+		dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+		dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+		dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+	} else {
+		g_debug("No locations configured (Empty List)");
+		return FALSE;
+	}
+	
+	offset = dbusmenu_menuitem_get_position (current_location, root)+1;
+	for (i = 0; i < len; i++) {
+		// Iterate over configured places and add any which aren't already listed
+		if (g_strcmp0(locations[i], current_timezone) != 0 &&
+		    g_strcmp0(locations[i], geo_timezone) != 0) {
+			g_debug("Adding timezone in update_timezones %s", locations[i]);
+			item = dbusmenu_menuitem_new();
+			dbusmenu_menuitem_property_set      (item, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
+			dbusmenu_menuitem_property_set		(item, TIMEZONE_MENUITEM_PROP_LABEL, locations[i]);
+			dbusmenu_menuitem_property_set 		(item, TIMEZONE_MENUITEM_PROP_RIGHT, "+tzone");
+			dbusmenu_menuitem_property_set_bool (item, TIMEZONE_MENUITEM_PROP_RADIO, FALSE);
+			dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+			dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+			dbusmenu_menuitem_child_add_position (root, item, offset++);
+			g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
+			dconflocations = g_list_append(dconflocations, item);
+		}
+	}
+	g_strfreev (locations);
+	// Get the evolution calendar timezone as a place and time and add it
 	return FALSE;
 }
-*/
+
+// Authentication function taken from http://git.gnome.org/browse/evolution/tree/calendar/common/authentication.c
+static gchar *
+auth_func_cb (ECal *ecal,
+              const gchar *prompt,
+              const gchar *key,
+              gpointer user_data)
+{
+	gboolean remember;
+	gchar *password, *auth_domain;
+	ESource *source;
+	const gchar *component_name;
+
+	source = e_cal_get_source (ecal);
+	auth_domain = e_source_get_duped_property (source, "auth-domain");
+	component_name = auth_domain ? auth_domain : "Calendar";
+	password = e_passwords_get_password (component_name, key);
+
+	if (!password)
+		password = e_passwords_ask_password (
+			_("Enter password"),
+			component_name, key, prompt,
+			E_PASSWORDS_REMEMBER_FOREVER |
+			E_PASSWORDS_SECRET |
+			E_PASSWORDS_ONLINE,
+			&remember, NULL);
+
+	g_free (auth_domain);
+
+	return password;
+}
+
 
 // Compare function for g_list_sort of ECalComponent objects
 static gint 
@@ -307,8 +460,13 @@
 	struct tm tm_a, tm_b;
 	time_t t_a, t_b;
 	gint retval = 0;
-	
+
+	if (a == NULL || b == NULL) return retval;
+
 	ECalComponentVType vtype = e_cal_component_get_vtype (a);
+	
+	if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return -1;
+	
 	if (vtype == E_CAL_COMPONENT_EVENT)
 		e_cal_component_get_dtstart (a, &datetime_a);
 	else
@@ -317,6 +475,8 @@
 	t_a = mktime(&tm_a);
 	
 	vtype = e_cal_component_get_vtype (b);
+	if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return 1;
+	
 	if (vtype == E_CAL_COMPONENT_EVENT)
 		e_cal_component_get_dtstart (b, &datetime_b);
 	else
@@ -340,15 +500,17 @@
  */
 static gboolean
 update_appointment_menu_items (gpointer user_data) {
-	if (!ecal) return FALSE;
 	// FFR: we should take into account short term timers, for instance
 	// tea timers, pomodoro timers etc... that people may add, this is hinted to in the spec.
 	time_t t1, t2;
 	gchar *query, *is, *ie, *ad;
 	GList *objects = NULL, *l;
+	GList *allobjects = NULL;
+	GSList *g;
 	GError *gerror = NULL;
 	gint i;
 	gint width, height;
+	ESourceList * sources = NULL;
 	
 	time(&t1);
 	time(&t2);
@@ -357,16 +519,6 @@
 	is = isodate_from_time_t(t1);
 	ie = isodate_from_time_t(t2);
 	
-	// FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? Or sort it by date?
-	query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie);
-	g_debug("Getting objects with query: %s", query);
-	if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror)) {
-		g_debug("Failed to get objects\n");
-		g_free(ecal);
-		ecal = NULL;
-		return FALSE;
-	}
-	g_debug("Number of objects returned: %d", g_list_length(objects));
 	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
 
 	/* Remove all of the previous appointments */
@@ -382,14 +534,61 @@
 		}
 	}
 	
+	// TODO Remove all highlights from the calendar widget
+
+	// FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? Or sort it by date?
+	query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie);
+	
+	if (!e_cal_get_sources(&sources, E_CAL_SOURCE_TYPE_EVENT, &gerror)) {
+		g_debug("Failed to get ecal sources\n");
+		return FALSE;
+	}
+
+	// iterate the query for all sources
+	for (g = e_source_list_peek_groups (sources); g; g = g->next) {
+		ESourceGroup *group = E_SOURCE_GROUP (g->data);
+		GSList *s;
+		
+		for (s = e_source_group_peek_sources (group); s; s = s->next) {
+			ESource *source = E_SOURCE (s->data);
+			ECal *ecal = e_cal_new(source, E_CAL_SOURCE_TYPE_EVENT);
+			e_cal_set_auth_func (ecal, (ECalAuthFunc) auth_func_cb, NULL);
+			//icaltimezone * tzone;
+			
+			if (!e_cal_open(ecal, FALSE, &gerror)) {
+				g_debug("Failed to get ecal sources %s", gerror->message);
+				g_error_free(gerror);
+				gerror = NULL;
+				continue;
+        	}
+			
+			g_debug("Getting objects with query: %s", query);
+			if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror)) {
+				g_debug("Failed to get objects\n");
+				g_free(ecal);
+				return FALSE;
+			}
+			g_debug("Number of objects returned: %d", g_list_length(objects));
+			
+			if (allobjects == NULL) {
+				allobjects = objects;
+			} else if (objects != NULL) {
+				allobjects = g_list_concat(allobjects, objects);
+				g_object_unref(objects);
+			}
+		}
+	}
+	
 	// Sort the list see above FIXME regarding queries
-	objects = g_list_sort(objects, (GCompareFunc) compare_appointment_items);
+	g_debug("Sorting objects list");
+	allobjects = g_list_sort(allobjects, (GCompareFunc) compare_appointment_items);
 	i = 0;
-	for (l = objects; l; l = l->next) {
+	for (l = allobjects; l; l = l->next) {
 		ECalComponent *ecalcomp = l->data;
 		ECalComponentText valuetext;
 		ECalComponentDateTime datetime;
 		icaltimezone *appointment_zone = NULL;
+		icaltimezone *current_zone = NULL;
 		icalproperty_status status;
 		gchar *summary, *cmd;
 		char right[20];
@@ -397,6 +596,7 @@
 		struct tm tmp_tm;
 		DbusmenuMenuitem * item;
 
+		g_debug("Start Object");
 		ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp);
 
 		// See above FIXME regarding query result
@@ -415,7 +615,6 @@
 		dbusmenu_menuitem_property_set_bool  (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
 		dbusmenu_menuitem_property_set_bool  (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 	
-		g_debug("Start Object");
         // Label text        
 		e_cal_component_get_summary (ecalcomp, &valuetext);
 		summary = g_strdup (valuetext.value);
@@ -437,10 +636,15 @@
 			continue;
 		}
 		
+		appointment_zone = icaltimezone_get_builtin_timezone_from_tzid(datetime.tzid);
+		current_zone = icaltimezone_get_builtin_timezone_from_tzid(current_timezone);
 		if (!appointment_zone || datetime.value->is_date) { // If it's today put in the current timezone?
-			appointment_zone = tzone;
+			appointment_zone = current_zone;
 		}
-		tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, tzone);
+		// TODO: Convert the timezone into a 3 letter abbreviation if it's different to current_timezone
+		// TODO: Add the appointment timezone to the list if it's not already there. 
+		
+		tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, current_zone);
 		
 		g_debug("Generate time string");
 		// Get today
@@ -454,11 +658,15 @@
 			strftime(right, 20, "%a %l:%M %P", &tmp_tm);
 			
 		g_debug("Appointment time: %s", right);
+		g_debug("Appointment timezone: %s", datetime.tzid);
+		g_debug("Appointment timezone: %s", icaltimezone_get_tzid(appointment_zone)); // These two should be the same
+		//g_debug("Calendar timezone: %s", ecal_timezone);
+		
 		dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right);
 		
 		e_cal_component_free_datetime (&datetime);
 		
-		ad = is = isodate_from_time_t(mktime(&tmp_tm));
+		ad = isodate_from_time_t(mktime(&tmp_tm));
 		
 		// Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution
 		// FIXME Because the URI stuff is really broken, we're going to open the calendar at todays date instead
@@ -470,15 +678,18 @@
 		
 		g_debug("Command to Execute: %s", cmd);
 		
-		ESource *source = e_cal_get_source (ecal);
+		// FIXME This is now more difficult to get right with more sources, as we need to keep track
+		// of which ecal or source goes with each ECalComponent :/
+		
+		//ESource *source = e_cal_get_source (ecal);
         //e_source_get_color (source, &source_color); api has been changed
-        const gchar *color_spec = e_source_peek_color_spec(source);
-        GdkColor color;
+        const gchar *color_spec = NULL; //e_source_peek_color_spec(source);
         g_debug("Colour to use: %s", color_spec);
 			
 		// Draw the correct icon for the appointment type and then tint it using mask fill.
 		// For now we'll create a circle
         if (color_spec != NULL) {
+        	GdkColor color;
         	gdk_color_parse (color_spec, &color);
         	
 			cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
@@ -493,14 +704,14 @@
 			
 			dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf);
 		}
-		dbusmenu_menuitem_child_add_position (root, item, 4+i);
+		dbusmenu_menuitem_child_add_position (root, item, 3+i);
 		appointments = g_list_append         (appointments, item); // Keep track of the items here to make them east to remove
 		g_debug("Adding appointment: %p", item);
 		
 		if (i == 4) break; // See above FIXME regarding query result limit
 		i++;
 	}
-	g_list_free(objects);
+	g_object_unref(allobjects);
 	g_debug("End of objects");
 	return TRUE;
 }
@@ -552,31 +763,32 @@
 
 		g_idle_add(check_for_calendar, NULL);
 	}
-	DbusmenuMenuitem * separator;
-	
-	separator = dbusmenu_menuitem_new();
-	dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
-	dbusmenu_menuitem_child_append(root, separator);
-
-	add_appointment = dbusmenu_menuitem_new();
-	dbusmenu_menuitem_property_set     (add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Appointment"));
-	dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
-	dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-	g_signal_connect(G_OBJECT(add_appointment), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), "evolution -c calendar");
-	dbusmenu_menuitem_child_add_position (root, add_appointment, 4);
-	
-	separator = dbusmenu_menuitem_new();
-	dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
-	dbusmenu_menuitem_child_append(root, separator);
-
-	tzchange = dbusmenu_menuitem_new();
-	dbusmenu_menuitem_property_set(tzchange, DBUSMENU_MENUITEM_PROP_LABEL, "Set specific timezone");
-	dbusmenu_menuitem_property_set_bool(tzchange, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
-	g_signal_connect(G_OBJECT(tzchange), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
-	dbusmenu_menuitem_child_append(root, tzchange);
+	
+	locations_separator = dbusmenu_menuitem_new();
+	dbusmenu_menuitem_property_set(locations_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
+	dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+	dbusmenu_menuitem_child_append(root, locations_separator);
+
+	geo_location = dbusmenu_menuitem_new();
+	dbusmenu_menuitem_property_set      (geo_location, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
+	dbusmenu_menuitem_property_set		(geo_location, TIMEZONE_MENUITEM_PROP_LABEL, "Updating location information...");
+	dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+	dbusmenu_menuitem_property_set_bool (geo_location, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+	g_signal_connect(G_OBJECT(geo_location), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
+	dbusmenu_menuitem_child_append(root, geo_location);
+
+	current_location = dbusmenu_menuitem_new();
+	dbusmenu_menuitem_property_set      (current_location, DBUSMENU_MENUITEM_PROP_TYPE, TIMEZONE_MENUITEM_TYPE);
+	dbusmenu_menuitem_property_set		(current_location, TIMEZONE_MENUITEM_PROP_LABEL, "Current Timezone");
+	dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+	dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+	g_signal_connect(G_OBJECT(current_location), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(quick_set_tz), NULL);
+	dbusmenu_menuitem_child_append(root, current_location);
+	
 	check_timezone_sync();
-
-	separator = dbusmenu_menuitem_new();
+	//g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_timezone_menu_items), NULL);
+	
+	DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
 	dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
 	dbusmenu_menuitem_child_append(root, separator);
 
@@ -859,8 +1071,9 @@
 	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
 	textdomain (GETTEXT_PACKAGE);
 
-	/* Cache the timezone */
-	update_current_timezone();
+	/* Set up GSettings */
+	conf = g_settings_new(SETTINGS_INTERFACE);
+	// TODO Add a signal handler to catch gsettings changes and respond to them
 
 	/* Building the base menu */
 	server = dbusmenu_server_new(MENU_OBJ);
@@ -868,6 +1081,9 @@
 	dbusmenu_server_set_root(server, root);
 	
 	build_menus(root);
+	
+	/* Cache the timezone */
+	update_current_timezone();
 
 	/* Setup geoclue */
 	GeoclueMaster * master = geoclue_master_get_default();
@@ -885,14 +1101,15 @@
 	mainloop = g_main_loop_new(NULL, FALSE);
 	g_main_loop_run(mainloop);
 
-	geo_address_clean();
-	geo_client_clean();
-
+	g_object_unref(G_OBJECT(conf));
 	g_object_unref(G_OBJECT(master));
 	g_object_unref(G_OBJECT(dbus));
 	g_object_unref(G_OBJECT(service));
 	g_object_unref(G_OBJECT(server));
 	g_object_unref(G_OBJECT(root));
 
+	geo_address_clean();
+	geo_client_clean();
+
 	return 0;
 }

=== modified file 'src/indicator-datetime.c'
--- src/indicator-datetime.c	2011-02-09 03:37:50 +0000
+++ src/indicator-datetime.c	2011-02-16 17:06:57 +0000
@@ -105,7 +105,7 @@
 
 typedef struct _indicator_item_t indicator_item_t;
 struct _indicator_item_t {
-	GtkWidget * radio;
+	GtkWidget * gmi;
 	GtkWidget * icon;
 	GtkWidget * label;
 	GtkWidget * right;
@@ -176,7 +176,6 @@
 static void receive_signal                (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data);
 static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
 static gint generate_strftime_bitmask     (const char *time_str);
-static GSList *location_group = NULL;
 
 /* Indicator Module Config */
 INDICATOR_SET_VERSION
@@ -1070,14 +1069,14 @@
 /* Whenever we have a property change on a DbusmenuMenuitem
    we need to be responsive to that. */
 static void
-indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, indicator_item_t * mi_data)
+indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant *value, indicator_item_t * mi_data)
 {
 	if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_LABEL)) {
 		/* Set the main label */
-		gtk_label_set_text(GTK_LABEL(mi_data->label), value);
+		gtk_label_set_text(GTK_LABEL(mi_data->label), g_variant_get_string(value, NULL));
 	} else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_RIGHT)) {
 		/* Set the right label */
-		gtk_label_set_text(GTK_LABEL(mi_data->right), value);
+		gtk_label_set_text(GTK_LABEL(mi_data->right), g_variant_get_string(value, NULL));
 	} else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_ICON)) {
 		/* We don't use the value here, which is probably less efficient, 
 		   but it's easier to use the easy function.  And since th value
@@ -1106,6 +1105,14 @@
 				g_object_unref(resized_pixbuf);
 			}
 		}
+	} else if (!g_strcmp0(prop, TIMEZONE_MENUITEM_PROP_LABEL)) {
+		/* Set the main label */
+		gtk_label_set_text(GTK_LABEL(mi_data->label), g_variant_get_string(value, NULL));
+	} else if (!g_strcmp0(prop, TIMEZONE_MENUITEM_PROP_RIGHT)) {
+		/* Set the right label */
+		gtk_label_set_text(GTK_LABEL(mi_data->right), g_variant_get_string(value, NULL));
+	} else if (!g_strcmp0(prop, TIMEZONE_MENUITEM_PROP_RADIO)) {
+		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi_data->gmi), g_variant_get_boolean(value));
 	} else {
 		g_warning("Indicator Item property '%s' unknown", prop);
 	}
@@ -1127,7 +1134,7 @@
 
 	indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
 
-	GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
+	mi_data->gmi = gtk_menu_item_new();
 
 	GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
 
@@ -1178,10 +1185,10 @@
 	gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
 	gtk_widget_show(mi_data->right);
 
-	gtk_container_add(GTK_CONTAINER(gmi), hbox);
+	gtk_container_add(GTK_CONTAINER(mi_data->gmi), hbox);
 	gtk_widget_show(hbox);
 
-	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(mi_data->gmi), parent);
 
 	g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
 	g_signal_connect_swapped(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data);
@@ -1217,6 +1224,22 @@
 	return TRUE;
 }
 
+static void
+timezone_toggled_cb (GtkCheckMenuItem *checkmenuitem, DbusmenuMenuitem * dbusitem)
+{
+	/* Make sure that the displayed radio-active setting is always 
+	   consistent with the dbus menuitem */
+	gtk_check_menu_item_set_active(checkmenuitem,
+		dbusmenu_menuitem_property_get_bool(dbusitem, TIMEZONE_MENUITEM_PROP_RADIO));
+}
+
+static void
+timezone_destroyed_cb (DbusmenuMenuitem * dbusitem, indicator_item_t * mi_data)
+{
+	g_signal_handlers_disconnect_by_func(G_OBJECT(mi_data->gmi), G_CALLBACK(timezone_toggled_cb), dbusitem);
+	g_free(mi_data);
+}
+
 static gboolean
 new_timezone_item(DbusmenuMenuitem * newitem,
 				   DbusmenuMenuitem * parent,
@@ -1230,41 +1253,36 @@
 	// Menu item with a radio button and a right aligned time
 	indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
 
-	GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
-
-	GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
-
-	mi_data->radio = gtk_radio_button_new(location_group);
-	if (location_group == NULL)
-		location_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(mi_data->radio));
-	
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mi_data->radio),
+	mi_data->gmi = gtk_check_menu_item_new();
+
+	gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(mi_data->gmi), TRUE);
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi_data->gmi),
 		dbusmenu_menuitem_property_get_bool(newitem, TIMEZONE_MENUITEM_PROP_RADIO));
-  
-	gtk_box_pack_start(GTK_BOX(hbox), mi_data->radio, FALSE, FALSE, 0);
-	gtk_widget_show(mi_data->radio);
-	
+
+	GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
+
   	/* Label, probably a username, chat room or mailbox name */
-	mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_MENUITEM_PROP_LABEL));
+	mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, TIMEZONE_MENUITEM_PROP_LABEL));
 	gtk_misc_set_alignment(GTK_MISC(mi_data->label), 0.0, 0.5);
 	gtk_box_pack_start(GTK_BOX(hbox), mi_data->label, TRUE, TRUE, 0);
 	gtk_widget_show(mi_data->label);
 
 	/* Usually either the time or the count on the individual
 	   item. */
-	mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_MENUITEM_PROP_RIGHT));
+	mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, TIMEZONE_MENUITEM_PROP_RIGHT));
 	gtk_size_group_add_widget(indicator_right_group, mi_data->right);
 	gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5);
 	gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
 	gtk_widget_show(mi_data->right);
 
-	gtk_container_add(GTK_CONTAINER(gmi), hbox);
+	gtk_container_add(GTK_CONTAINER(mi_data->gmi), hbox);
 	gtk_widget_show(hbox);
 
-	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(mi_data->gmi), parent);
 
+	g_signal_connect(G_OBJECT(mi_data->gmi), "toggled", G_CALLBACK(timezone_toggled_cb), newitem);
 	g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
-	g_signal_connect_swapped(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data);
+	g_signal_connect(G_OBJECT(newitem), "destroyed", G_CALLBACK(timezone_destroyed_cb), mi_data);
 
 	return TRUE;
 }


Follow ups