← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~karl-qdh/indicator-datetime/fixed-appointment-icon-colours into lp:indicator-datetime

 

Karl Lattimer has proposed merging lp:~karl-qdh/indicator-datetime/fixed-appointment-icon-colours into lp:indicator-datetime.

Requested reviews:
  Indicator Applet Developers (indicator-applet-developers)
Related bugs:
  #715848 Coloured icons for appointments
  https://bugs.launchpad.net/bugs/715848

For more details, see:
https://code.launchpad.net/~karl-qdh/indicator-datetime/fixed-appointment-icon-colours/+merge/52080

Add coloured squares to the indicator appointments 
-- 
https://code.launchpad.net/~karl-qdh/indicator-datetime/fixed-appointment-icon-colours/+merge/52080
Your team ayatana-commits is subscribed to branch lp:indicator-datetime.
=== modified file 'src/datetime-service.c'
--- src/datetime-service.c	2011-03-01 04:05:10 +0000
+++ src/datetime-service.c	2011-03-03 15:04:13 +0000
@@ -73,6 +73,7 @@
 static DbusmenuMenuitem * date = NULL;
 static DbusmenuMenuitem * calendar = NULL;
 static DbusmenuMenuitem * settings = NULL;
+static DbusmenuMenuitem * events_separator = NULL;
 static DbusmenuMenuitem * locations_separator = NULL;
 static DbusmenuMenuitem * geo_location = NULL;
 static DbusmenuMenuitem * current_location = NULL;
@@ -80,6 +81,8 @@
 static DbusmenuMenuitem * add_appointment = NULL;
 static GList			* appointments = NULL;
 static GList			* dconflocations = NULL;
+static GList			* comp_instances = NULL;
+static gboolean           updating_appointments = FALSE;
 GSettings *conf;
 
 
@@ -91,6 +94,13 @@
 static gchar 			* current_timezone = NULL;
 static gchar 			* geo_timezone = NULL;
 
+struct comp_instance {
+        ECalComponent *comp;
+        time_t start;
+        time_t end;
+        ESource *source;
+};
+
 static void
 set_timezone_label (DbusmenuMenuitem * mi, const gchar * location)
 {
@@ -278,8 +288,50 @@
 	return TRUE;
 }
 
+static guint ecaltimer = 0;
+
+static void
+start_ecal_timer(void)
+{
+	if (ecaltimer != 0) g_source_remove(ecaltimer);
+	if (update_appointment_menu_items(NULL))
+		ecaltimer = g_timeout_add_seconds(60*5, update_appointment_menu_items, NULL); 	
+}
+
+static void
+stop_ecal_timer(void)
+{
+	if (ecaltimer != 0) g_source_remove(ecaltimer);
+}
+
+static void
+show_events_changed (void)
+{
+	if (g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) {
+		dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+		dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+		start_ecal_timer();
+	} else {
+		dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+		dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+		/* Remove all of the previous appointments */
+		if (appointments != NULL) {
+			g_debug("Freeing old appointments");
+			while (appointments != NULL) {
+				DbusmenuMenuitem * litem =  DBUSMENU_MENUITEM(appointments->data);
+				g_debug("Freeing old appointment: %p", litem);
+				// Remove all the existing menu items which are in appointments.
+				appointments = g_list_remove(appointments, litem);
+				dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(litem));
+				g_object_unref(G_OBJECT(litem));
+			}
+		}
+		stop_ecal_timer();
+	}
+}
+
 /* Looks for the calendar application and enables the item if
-   we have one */
+   we have one, starts ecal timer if events are turned on */
 static gboolean
 check_for_calendar (gpointer user_data)
 {
@@ -293,21 +345,26 @@
 		dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
 		dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 
-		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, 2);
-
+		events_separator = dbusmenu_menuitem_new();
+		dbusmenu_menuitem_property_set(events_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
+		dbusmenu_menuitem_child_add_position(root, events_separator, 2);
 		add_appointment = dbusmenu_menuitem_new();
-		dbusmenu_menuitem_property_set     (add_appointment, DBUSMENU_MENUITEM_PROP_LABEL, _("Add Appointment"));
+		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 the calendar items every 5 minutes if it updates the first time
-		if (update_appointment_menu_items(NULL))
-			g_timeout_add_seconds(60*5, update_appointment_menu_items, NULL); 
-			
+
+		if (g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) {
+			dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+			dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+			start_ecal_timer();
+		} else {
+			dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			stop_ecal_timer();
+		}
+		
 		// Connect to event::month-changed 
 		g_signal_connect(calendar, "event::month-changed", G_CALLBACK(month_changed_cb), NULL);
 		g_free(evo);
@@ -381,7 +438,11 @@
 
 // Authentication function
 static gchar *
-auth_func (ECal *ecal, const gchar *prompt, const gchar *key, gpointer user_data) {
+auth_func (ECal *ecal, 
+           const gchar *prompt, 
+           const gchar *key, 
+           gpointer user_data)
+{
 	gboolean remember; // TODO: Is this useful?  Should we be storing it somewhere?
 	ESource *source = e_cal_get_source (ecal);
 	gchar *auth_domain = e_source_get_duped_property (source, "auth-domain");
@@ -407,47 +468,92 @@
 	return password;
 }
 
-
-// Compare function for g_list_sort of ECalComponent objects
-static gint 
-compare_appointment_items (ECalComponent *a,
-                           ECalComponent *b) {
-                                       
-	ECalComponentDateTime datetime_a, datetime_b;
-	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
-	    e_cal_component_get_due (a, &datetime_a);
-	tm_a = icaltimetype_to_tm(datetime_a.value);
-	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
-	    e_cal_component_get_due (b, &datetime_b);
-	tm_b = icaltimetype_to_tm(datetime_b.value);
-	t_b = mktime(&tm_b);
-
-	// Compare datetime_a and datetime_b, newest first in this sort.
-	if (t_a > t_b) retval = 1;
-	else if (t_a < t_b) retval = -1;
-	
-	e_cal_component_free_datetime (&datetime_a);
-	e_cal_component_free_datetime (&datetime_b);
-	return retval;
+static gint
+compare_comp_instances (gconstpointer a, 
+                        gconstpointer b)
+{
+        const struct comp_instance *ci_a = a;
+        const struct comp_instance *ci_b = b;
+        time_t d = ci_a->start - ci_b->start;
+		if (d < 0) return -1;
+		else if (d > 0) return 1; 
+		return 0;
+}
+
+static gboolean
+populate_appointment_instances (ECalComponent *comp,
+                                time_t instance_start,
+                                time_t instance_end,
+                                gpointer data)
+{
+	g_debug("Appending item %p", comp);
+	
+	ECalComponentVType vtype = e_cal_component_get_vtype (comp);
+	if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO) return FALSE;
+	
+	icalproperty_status status;
+	e_cal_component_get_status (comp, &status);
+	if (status == ICAL_STATUS_COMPLETED || status == ICAL_STATUS_CANCELLED) return FALSE;
+	
+	g_object_ref(comp);
+	
+	ECalComponentDateTime datetime;
+	icaltimezone *appointment_zone = NULL;
+	icaltimezone *current_zone = NULL;
+	
+	if (vtype == E_CAL_COMPONENT_EVENT)
+		e_cal_component_get_dtstart (comp, &datetime);
+	else
+	    e_cal_component_get_due (comp, &datetime);
+
+	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 = current_zone;
+	}
+	
+	// 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. 
+		
+	GSList *period_list = NULL, *l;
+	if (e_cal_component_has_recurrences (comp)) {
+		e_cal_component_get_rdate_list (comp, &period_list);
+		g_debug("ECalComponent has recurrences");
+	} else {
+		g_debug("ECalComponent doesn't have recurrences");
+	}
+	
+	struct comp_instance *ci;
+	ci = g_new (struct comp_instance, 1);
+	
+	// Do we get rdate_list?
+	if (period_list != NULL) {
+		g_debug("Got recurring periods");
+		for (l = period_list; l; l = l->next) {
+			ECalComponentPeriod *period = l->data;
+			struct tm tmp_tm  = icaltimetype_to_tm_with_zone (&period->start, appointment_zone, current_zone);
+			time_t start = mktime(&tmp_tm);
+			g_debug("period time: %d", (int)start);
+		
+			tmp_tm = icaltimetype_to_tm_with_zone (&period->u.end, appointment_zone, current_zone);
+			time_t end = mktime(&tmp_tm);
+		
+			if (start >= instance_start && end < instance_end) {
+				ci->start = start;
+				ci->end = end;
+			}
+		}
+	} else {
+		ci->start = instance_start;
+		ci->end = instance_end;
+		g_debug("Got no recurring periods set time to start %s, end %s", ctime(&instance_start), ctime(&instance_end));
+	}
+	
+	ci->comp = comp;
+	ci->source = E_SOURCE(data);
+	
+	comp_instances = g_list_append(comp_instances, ci);
+	return TRUE;
 }
 
 /* Populate the menu with todays, next 5 appointments. 
@@ -456,22 +562,38 @@
  * this is a problem mainly on the EDS side of things, not ours. 
  */
 static gboolean
-update_appointment_menu_items (gpointer user_data) {
+update_appointment_menu_items (gpointer user_data)
+{
 	// 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.
 	if (calendar == NULL) return FALSE;
 	if (!g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) return FALSE;
+	if (updating_appointments) return TRUE;
+	updating_appointments = TRUE;
 	
+<<<<<<< TREE
 	gchar *query, *ad;
 	GList *objects = NULL, *l;
 	GList *allobjects = NULL;
+=======
+	time_t t1, t2;
+	gchar *ad;
+	GList *l;
+	//GList *allobjects = NULL;
+>>>>>>> MERGE-SOURCE
 	GSList *g;
 	GError *gerror = NULL;
 	gint i;
 	gint width, height;
 	ESourceList * sources = NULL;
 	
+<<<<<<< TREE
 	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+=======
+	time(&t1);
+	time(&t2);
+	t2 += (time_t) (7 * 24 * 60 * 60); /* 7 days ahead of now, we actually need number_of_days_in_this_month */
+>>>>>>> MERGE-SOURCE
 
 	/* Remove all of the previous appointments */
 	if (appointments != NULL) {
@@ -487,15 +609,29 @@
 	}
 	
 	// TODO Remove all highlights from the calendar widget
+<<<<<<< TREE
 
 	// 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? (time-now) (time-add-day (time-now) 7))");
+=======
+>>>>>>> MERGE-SOURCE
 	
 	if (!e_cal_get_sources(&sources, E_CAL_SOURCE_TYPE_EVENT, &gerror)) {
 		g_debug("Failed to get ecal sources\n");
 		return FALSE;
 	}
-
+	
+	// Free comp_instances if not NULL
+	if (comp_instances != NULL) {
+		g_debug("Freeing comp_instances: may be an overlap\n");
+		for (l = comp_instances; l; l = l->next) {
+			const struct comp_instance *ci = l->data;
+			g_object_unref(ci->comp);
+			g_list_free(comp_instances);
+			comp_instances = NULL;
+		}
+	}
+	
 	// 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);
@@ -503,7 +639,7 @@
 		
 		for (s = e_source_group_peek_sources (group); s; s = s->next) {
 			ESource *source = E_SOURCE (s->data);
-			g_signal_connect (G_OBJECT(source), "changed", G_CALLBACK (update_appointment_menu_items), NULL);
+			//g_signal_connect (G_OBJECT(source), "changed", G_CALLBACK (update_appointment_menu_items), NULL);
 			ECal *ecal = e_cal_new(source, E_CAL_SOURCE_TYPE_EVENT);
 			e_cal_set_auth_func (ecal, (ECalAuthFunc) auth_func, NULL);
 			
@@ -514,55 +650,35 @@
 				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);
-				gerror = NULL;
-				continue;
-			}
-			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);
-			}
+			g_debug("Generating instances");
+			e_cal_generate_instances (ecal, t1, t2, (ECalRecurInstanceFn) populate_appointment_instances, (gpointer) source);
+			g_debug("Number of objects returned: %d", g_list_length(comp_instances));
 		}
 	}
-	
-	// Sort the list see above FIXME regarding queries
-	g_debug("Sorting objects list");
-	allobjects = g_list_sort(allobjects, (GCompareFunc) compare_appointment_items);
+	GList *sorted_comp_instances = g_list_sort(comp_instances, compare_comp_instances);
+	comp_instances = NULL;
 	i = 0;
-	for (l = allobjects; l; l = l->next) {
-		ECalComponent *ecalcomp = l->data;
+	
+	gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+	if (width == 0) width = 12;
+	if (height == 0) height = 12;
+	for (l = sorted_comp_instances; l; l = l->next) {
+		struct comp_instance *ci = l->data;
+		ECalComponent *ecalcomp = ci->comp;
 		ECalComponentText valuetext;
-		ECalComponentDateTime datetime;
-		icaltimezone *appointment_zone = NULL;
-		icaltimezone *current_zone = NULL;
-		icalproperty_status status;
+		//ECalComponentDateTime datetime;
 		gchar *summary, *cmd;
 		char right[20];
 		//const gchar *uri;
-		struct tm tmp_tm;
 		DbusmenuMenuitem * item;
 
-		g_debug("Start Object");
-		ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp);
-
-		// See above FIXME regarding query result
-		// If it's not an event or todo, continue no-increment
-        if (vtype != E_CAL_COMPONENT_EVENT && vtype != E_CAL_COMPONENT_TODO)
-			continue;
-
-		// See above FIXME regarding query result
-		// if the status is completed, continue no-increment
-		e_cal_component_get_status (ecalcomp, &status);
-		if (status == ICAL_STATUS_COMPLETED || status == ICAL_STATUS_CANCELLED)
-			continue;
-
+		g_debug("Start Object %p", ecalcomp);
+		
+		// TODO Mark days
+		
+		if (i >= 5) continue;
+		i++;
+		
 		item = dbusmenu_menuitem_new();
 		dbusmenu_menuitem_property_set       (item, DBUSMENU_MENUITEM_PROP_TYPE, APPOINTMENT_MENUITEM_TYPE);
 		dbusmenu_menuitem_property_set_bool  (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
@@ -576,97 +692,143 @@
 		g_debug("Summary: %s", summary);
 		g_free (summary);
 		
-		// Due text
-		if (vtype == E_CAL_COMPONENT_EVENT)
-			e_cal_component_get_dtstart (ecalcomp, &datetime);
-		else
-		    e_cal_component_get_due (ecalcomp, &datetime);
-		
+		//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 = current_zone;
+		//}
 		// FIXME need to get the timezone of the above datetime, 
 		// and get the icaltimezone of the geoclue timezone/selected timezone (whichever is preferred)
-		if (!datetime.value) {
-			g_free(item);
-			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 = current_zone;
-		}
 		// 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");
+		//tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, current_zone);
+		
+		// Due text
+		ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp);
+		
 		// Get today
 		time_t curtime = time(NULL);
-  		struct tm* today = localtime(&curtime);
-		if (today->tm_mday == tmp_tm.tm_mday && 
-		    today->tm_mon == tmp_tm.tm_mon && 
-		    today->tm_year == tmp_tm.tm_year)
-			strftime(right, 20, "%l:%M %P", &tmp_tm);
+  		struct tm *today = localtime(&curtime);
+		
+		int mday = today->tm_mday;
+		int mon = today->tm_mon;
+		int year = today->tm_year;
+		
+		struct tm *due;
+		g_debug("Start time %s", ctime(&ci->start));
+		if (vtype == E_CAL_COMPONENT_EVENT) due = localtime(&ci->start);
+		else if (vtype == E_CAL_COMPONENT_TODO) due = localtime(&ci->end);
+		else continue;
+		
+		strftime(right, 20, "%a %l:%M %p", due);
+		g_debug("Start time %s -> %s", asctime(due), right);
+
+		int dmday = due->tm_mday;
+		int dmon = due->tm_mon;
+		int dyear = due->tm_year;
+		
+		if ((mday == dmday) && (mon == dmon) && (year == dyear))
+			strftime(right, 20, "%l:%M %p", due);
 		else
-			strftime(right, 20, "%a %l:%M %P", &tmp_tm);
+			strftime(right, 20, "%a %l:%M %p", due);
 			
 		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("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);
+		//e_cal_component_free_datetime (&datetime);
 		
-		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
-		
 		//e_cal_component_get_uid(ecalcomp, &uri);
+		ad = isodate_from_time_t(mktime(due));
 		cmd = g_strconcat("evolution calendar:///?startdate=", ad, NULL);
 		g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
 						  G_CALLBACK (activate_cb), cmd);
 		
 		g_debug("Command to Execute: %s", cmd);
-		
-		// 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 = NULL; //e_source_peek_color_spec(source);
+
+        const gchar *color_spec = e_source_peek_color_spec(ci->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) {
+        	// Fixme causes segfault, but we have colours now yay!
         	GdkColor color;
-        	gdk_color_parse (color_spec, &color);
-        	
-			cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-			cairo_t *cr = cairo_create(cs);
-			cairo_arc (cr, width/2, height/2, width/2, 0, 2 * M_PI);
+        	gdk_color_parse (color_spec, &color);	
+			                                    
+        	cairo_surface_t *surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height ); 
+			// Width keeps becoming zero!!
+			if (width == 0) width = 12;
+			if (height == 0) height = 12;
+    		cairo_t *cr = cairo_create(surface);
 			gdk_cairo_set_source_color(cr, &color);
-			cairo_fill(cr);
-		
-			GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)cs, 
-				gdk_colormap_new(gdk_drawable_get_visual((GdkDrawable*)cs), TRUE), 0,0,0,0, width, height);
-			cairo_destroy(cr);
+			cairo_paint(cr);
+    		cairo_set_source_rgba(cr, 0,0,0,0.5);
+    		cairo_set_line_width(cr, 1);
+    		cairo_rectangle (cr, 0.5, 0.5, width-1, height-1);
+    		cairo_stroke(cr);
+			// Convert to pixbuf, in gtk3 this is done with gdk_pixbuf_get_from_surface
+			cairo_content_t content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
+			// Width keeps becoming zero!!
+			if (width == 0) width = 12;
+			if (height == 0) height = 12;
+			GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
+			                                    !!(content & CAIRO_CONTENT_ALPHA), 
+			                                    8, width, height);
+			if (pixbuf != NULL) {               
+				gint sstride = cairo_image_surface_get_stride( surface ); 
+				gint dstride = gdk_pixbuf_get_rowstride (pixbuf);
+				guchar *spixels = cairo_image_surface_get_data( surface );
+				guchar *dpixels = gdk_pixbuf_get_pixels (pixbuf);
+
+	  			int x, y;
+	  			for (y = 0; y < height; y++) {
+					guint32 *src = (guint32 *) spixels;
+
+					for (x = 0; x < width; x++) {
+						guint alpha = src[x] >> 24;
+
+						if (alpha == 0) {
+		      				dpixels[x * 4 + 0] = 0;
+		      				dpixels[x * 4 + 1] = 0;
+		      				dpixels[x * 4 + 2] = 0;
+		    			} else {
+							dpixels[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+							dpixels[x * 4 + 1] = (((src[x] & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
+							dpixels[x * 4 + 2] = (((src[x] & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
+						}
+						dpixels[x * 4 + 3] = alpha;
+					}
+					spixels += sstride;
+					dpixels += dstride;
+	  			}
+
+				cairo_surface_destroy (surface);
+				cairo_destroy(cr);
 			
-			dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf);
+				dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf);
+			}
 		}
-		dbusmenu_menuitem_child_add_position (root, item, 3+i);
+		dbusmenu_menuitem_child_add_position (root, item, 2+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++;
 	}
 	
     if (gerror != NULL) g_error_free(gerror);
-	g_object_unref(allobjects);
+	for (l = sorted_comp_instances; l; l = l->next) { 
+		const struct comp_instance *ci = l->data;
+		g_object_unref(ci->comp);
+		g_list_free(sorted_comp_instances);
+	}
+	
+	updating_appointments = FALSE;
 	g_debug("End of objects");
 	return TRUE;
 }
@@ -748,6 +910,8 @@
 	check_timezone_sync();
 	
 	g_signal_connect (conf, "changed::" SETTINGS_SHOW_LOCATIONS_S, G_CALLBACK (show_locations_changed), NULL);
+	g_signal_connect (conf, "changed::" SETTINGS_LOCATIONS_S, G_CALLBACK (show_locations_changed), NULL);
+	g_signal_connect (conf, "changed::" SETTINGS_SHOW_EVENTS_S, G_CALLBACK (show_events_changed), NULL);
 
 	DbusmenuMenuitem * separator = dbusmenu_menuitem_new();
 	dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);


Follow ups