From feb60b1977c1fe3fa45452bc40f6635f56b0e39f Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Tue, 11 Jan 2011 12:21:36 +0000 Subject: Added initial support for ecal (untested) --- src/datetime-service.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 8a31940..1e4404d 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -33,6 +33,13 @@ with this program. If not, see . #include #include +#include +#include +#include +// Other users of ecal seem to also include these, not sure why they should be included by the above +#include +#include + #include #include "datetime-interface.h" @@ -53,6 +60,9 @@ static DbusmenuMenuitem * date = NULL; static DbusmenuMenuitem * calendar = NULL; static DbusmenuMenuitem * settings = NULL; static DbusmenuMenuitem * tzchange = NULL; +static GList * appointments = NULL; +static ECal * ecal = NULL; +static gchar * ecal_timezone = NULL; /* Geoclue trackers */ static GeoclueMasterClient * geo_master = NULL; @@ -225,6 +235,98 @@ check_for_calendar (gpointer user_data) return FALSE; } +/* Populate the menu with todays, next 5 appointments. We probably want to shift this off to an idle-add + */ +static gboolean +update_calendar_menu_items (gpointer user_data) { + ecal = e_cal_new_system_calendar(); + if (!ecal) { + g_debug("e_cal_new_system_calendar failed"); + ecal = NULL; + return FALSE; + } + if (!e_cal_open(ecal, FALSE, &gerror) ) { + g_debug("e_cal_open: %s\n", gerror->message); + g_free(ecal); + ecal = NULL; + return FALSE; + } + + if (!e_cal_get_timezone(ecal, "UTC", &tzone, &gerror) { + g_debug("failed to get time zone\n"); + g_free(ecal); + ecal = NULL; + return FALSE; + } + + ecal_timezone = icaltimezone_get_tzid(tzone); + + time_t t1, t2; + gchar *query, *is, *ie; + GList *objects = NULL, *l; + GError *gerror = NULL; + DbusmenuMenuitem * item = NULL; + gint i; + + // TODO: Remove all the existing menu items which are appointments. + + time(&t1); + time(&t2); + t2 += (time_t) (24 * 60 * 60); /* 1 day ahead of now */ + + is = isodate_from_time_t(t1); + ie = isodate_from_time_t(t2); + // FIXME can we put a limit on the number of results? + query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie); + + if (!e_cal_get_object_list(ecal, query, &objects, &gerror);) { + g_debug("Failed to get objects\n"); + g_free(ecal); + ecal = NULL; + return TRUE; + } + i = 0; + gint width, height; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + + for (l = objects; l; l = l->next) { + icalcomponent *icalcomp = l->data; + icalproperty* p; + icalvalue *v; + gchar *name, due; + p = icalcomponent_get_first_property(icalcomp, ICAL_NAME_PROPERTY); + v = icalproperty_get_value(p); + name = icalvalue_get_string(v); + + p = icalcomponent_get_first_property(icalcomp, ICAL_DUE_PROPERTY); + v = icalproperty_get_value(p); + due = icalvalue_get_string(v); + + + // TODO: now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution + + //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + //cairo_t *cr = cairo_create(cs); + + // TODO: Draw the correct icon for the appointment type and then tint it using mask fill. + + //GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)cs, 0,0,0,0, width, height); + + // TODO: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time + item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set (item, "type", INDICATOR_MENUITEM_TYPE); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, name); + //dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, due); + 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_append (root, item); + + if (i == 4) break; // See above FIXME regarding query result limit + i++; + } +} + /* Looks for the time and date admin application and enables the item we have one */ static gboolean -- cgit v1.2.3 From ed67c38fc82ed34fc7fe7afeb94a5af56f963c52 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Tue, 11 Jan 2011 15:48:58 +0000 Subject: Updated some minor things, the last commit wasn't exactly great, still untested, looking for a way to pull the evolution URI out of the events. --- src/datetime-service.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 1e4404d..cd8ca92 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -236,9 +236,19 @@ check_for_calendar (gpointer user_data) } /* Populate the menu with todays, next 5 appointments. We probably want to shift this off to an idle-add + * the problem is the inserting order of items and updating them might be difficult. + * we should hook into the ABOUT TO SHOW signal and use that to update the appointments. */ static gboolean -update_calendar_menu_items (gpointer user_data) { +update_appointment_menu_items (gpointer user_data) { + + time_t t1, t2; + gchar *query, *is, *ie; + GList *objects = NULL, *l; + GError *gerror = NULL; + DbusmenuMenuitem * item = NULL; + gint i; + ecal = e_cal_new_system_calendar(); if (!ecal) { g_debug("e_cal_new_system_calendar failed"); @@ -261,13 +271,6 @@ update_calendar_menu_items (gpointer user_data) { ecal_timezone = icaltimezone_get_tzid(tzone); - time_t t1, t2; - gchar *query, *is, *ie; - GList *objects = NULL, *l; - GError *gerror = NULL; - DbusmenuMenuitem * item = NULL; - gint i; - // TODO: Remove all the existing menu items which are appointments. time(&t1); @@ -283,7 +286,7 @@ update_calendar_menu_items (gpointer user_data) { g_debug("Failed to get objects\n"); g_free(ecal); ecal = NULL; - return TRUE; + return FALSE; } i = 0; gint width, height; @@ -293,7 +296,7 @@ update_calendar_menu_items (gpointer user_data) { icalcomponent *icalcomp = l->data; icalproperty* p; icalvalue *v; - gchar *name, due; + gchar *name, *due, *uri; p = icalcomponent_get_first_property(icalcomp, ICAL_NAME_PROPERTY); v = icalproperty_get_value(p); name = icalvalue_get_string(v); @@ -302,7 +305,6 @@ update_calendar_menu_items (gpointer user_data) { v = icalproperty_get_value(p); due = icalvalue_get_string(v); - // TODO: now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); @@ -321,10 +323,14 @@ update_calendar_menu_items (gpointer user_data) { 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_append (root, item); + //g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + // G_CALLBACK (activate_cb), "evolution %s", uri); if (i == 4) break; // See above FIXME regarding query result limit i++; } + g_free(ecal); // Really we should do the setup somewhere where we know it'll only run once, right now, we'll do it every time and free it. + return TRUE; } /* Looks for the time and date admin application and enables the @@ -374,8 +380,17 @@ build_menus (DbusmenuMenuitem * root) 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); + + // This just populates the items on startup later we want to be able to update the appointments before + // presenting the menu. + update_appointment_menu_items(NULL); - DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); + separator = dbusmenu_menuitem_new(); dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); dbusmenu_menuitem_child_append(root, separator); -- cgit v1.2.3 From afdb696699f886959a92476cf76f30718f097838 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Wed, 12 Jan 2011 09:49:16 +0000 Subject: Added most likely broken URI callback, but at least our debugging messages will show us something :) --- src/datetime-service.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index cd8ca92..814c9c6 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -296,7 +296,7 @@ update_appointment_menu_items (gpointer user_data) { icalcomponent *icalcomp = l->data; icalproperty* p; icalvalue *v; - gchar *name, *due, *uri; + gchar *name, *due, *uri, *cmd; p = icalcomponent_get_first_property(icalcomp, ICAL_NAME_PROPERTY); v = icalproperty_get_value(p); name = icalvalue_get_string(v); @@ -306,6 +306,11 @@ update_appointment_menu_items (gpointer user_data) { due = icalvalue_get_string(v); // TODO: now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution + // not sure if the ical URL property is actually an evolution compatible URI and no real way to tell other than testing + p = icalcomponent_get_first_property(icalcomp, ICAL_URL_PROPERTY); + v = icalproperty_get_value(p); + uri = icalvalue_get_string(v); + cmd = g_strconcat("evolution ", uri, NULL); //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); //cairo_t *cr = cairo_create(cs); @@ -323,8 +328,8 @@ update_appointment_menu_items (gpointer user_data) { 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_append (root, item); - //g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - // G_CALLBACK (activate_cb), "evolution %s", uri); + g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activate_cb), cmd); if (i == 4) break; // See above FIXME regarding query result limit i++; -- cgit v1.2.3 From b54626d404eccdc07b2bac09301d5e28dcc838f2 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Wed, 12 Jan 2011 11:25:04 +0000 Subject: Added missing stuff, getting it ready to be buildable --- src/datetime-service.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 814c9c6..33c8f30 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -307,6 +307,7 @@ update_appointment_menu_items (gpointer user_data) { // TODO: now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution // not sure if the ical URL property is actually an evolution compatible URI and no real way to tell other than testing + // We may need to change this to ecalcomponenets to get something closer to the evolution URI p = icalcomponent_get_first_property(icalcomp, ICAL_URL_PROPERTY); v = icalproperty_get_value(p); uri = icalvalue_get_string(v); -- cgit v1.2.3 From add30ba3ce73f5b10f592cc1cd23132a9c04d980 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Wed, 19 Jan 2011 15:21:14 +0000 Subject: Updated the eds code to use ecalcomponents rather than ical so we get colours etc... --- src/datetime-service.c | 168 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 131 insertions(+), 37 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 33c8f30..e06b76d 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -36,10 +36,14 @@ with this program. If not, see . #include #include #include +#include +#include +#include // Other users of ecal seem to also include these, not sure why they should be included by the above #include #include + #include #include "datetime-interface.h" @@ -235,21 +239,37 @@ check_for_calendar (gpointer user_data) return FALSE; } -/* Populate the menu with todays, next 5 appointments. We probably want to shift this off to an idle-add - * the problem is the inserting order of items and updating them might be difficult. - * we should hook into the ABOUT TO SHOW signal and use that to update the appointments. +static gboolean +timezone_clicked_cb() { + + return FALSE; +} + +static gboolean +update_timezone_menu_items(gpointer user_data) { + + return FALSE; +} + +/* Populate the menu with todays, next 5 appointments. + * we should hook into the ABOUT TO SHOW signal and use that to update the appointments. + * Experience has shown that caldav's and webcals can be slow to load from eds + * this is a problem mainly on the EDS side of things, not ours. */ static gboolean 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. time_t t1, t2; gchar *query, *is, *ie; GList *objects = NULL, *l; GError *gerror = NULL; DbusmenuMenuitem * item = NULL; gint i; + gint width, height; ecal = e_cal_new_system_calendar(); + if (!ecal) { g_debug("e_cal_new_system_calendar failed"); ecal = NULL; @@ -269,50 +289,119 @@ update_appointment_menu_items (gpointer user_data) { return FALSE; } + /* 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. + */ ecal_timezone = icaltimezone_get_tzid(tzone); - // TODO: Remove all the existing menu items which are appointments. - time(&t1); time(&t2); - t2 += (time_t) (24 * 60 * 60); /* 1 day ahead of now */ + t2 += (time_t) (7 * 24 * 60 * 60); /* 7 days ahead of now */ is = isodate_from_time_t(t1); ie = isodate_from_time_t(t2); - // FIXME can we put a limit on the number of results? + // FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie); - if (!e_cal_get_object_list(ecal, query, &objects, &gerror);) { + 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; } - i = 0; - gint width, height; gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + if (appointments != NULL) { + for (l = appointments; l; l = l->next) { + item = l->data; + // TODO: Remove all the existing menu items which are in appointments. + + // pop it out of the dbus menu + // remove it from the appointments glist + // free it + } + appointments = NULL; + } + + i = 0; for (l = objects; l; l = l->next) { - icalcomponent *icalcomp = l->data; - icalproperty* p; - icalvalue *v; - gchar *name, *due, *uri, *cmd; - p = icalcomponent_get_first_property(icalcomp, ICAL_NAME_PROPERTY); - v = icalproperty_get_value(p); - name = icalvalue_get_string(v); + ECalComponent *ecalcomp = l->data; + ECalComponentText valuetext; + ECalComponentDateTime datetime; + icaltimezone *appointment_zone; + time_t appointment_time, ti; + icalproperty_status status; + gchar *summary, right[20], *cmd; + const gchar *uri; + struct tm *tmp_tm, *tm_today; + + vtype = e_cal_component_get_vtype (comp); + + // 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; + + // INPROGRESS: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time + item = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set (item, "type", INDICATOR_MENUITEM_TYPE); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - p = icalcomponent_get_first_property(icalcomp, ICAL_DUE_PROPERTY); - v = icalproperty_get_value(p); - due = icalvalue_get_string(v); + // Label text + e_cal_component_get_summary (ecalcomp, &valuetext); + summary = g_strdup (valuetext.value); + e_cal_component_free_text (&valuetext); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, 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); + + if (datetime.value) { + appointment_zone = get_zone_from_tzid (client, datetime.tzid); + if (!appointment_zone || datetime.value->is_date) + appointment_zone = ecal_timezone; + appointment_time = icaltime_as_timet_with_zone (*datetime.value, appointment_zone); + } + e_cal_component_free_datetime (&datetime); + tmp_tm = convert_timet_to_struct_tm (appointment_time, appointment_zone); - // TODO: now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution - // not sure if the ical URL property is actually an evolution compatible URI and no real way to tell other than testing - // We may need to change this to ecalcomponenets to get something closer to the evolution URI - p = icalcomponent_get_first_property(icalcomp, ICAL_URL_PROPERTY); - v = icalproperty_get_value(p); - uri = icalvalue_get_string(v); + // Get today + time(&ti); + tm_today = convert_timet_to_struct_tm (ti, appointment_zone); + if (tm_today->mday == tmp_tm->mday && tm_today->mon == tmp_tm->mon && tm_today->year == tmp_tm->year) + strftime(&right, sizeof(right), "%X", tmp_tm); + else + strftime(&right, sizeof(right), "%a %X", tmp_tm); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, &right); + + // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution + e_cal_component_get_url(ecalcomp, &uri); cmd = g_strconcat("evolution ", uri, NULL); + g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activate_cb), cmd); + // Get the colour E_CAL_COMPONENT_FIELD_COLOR + // Get the icon, either EVENT or MEMO or TODO? + gdouble red, blue, green; + ECalSource *source = e_cal_get_source (ecalcomp->client); + if (!ecalcomp->color && e_source_get_color (source, &source_color)) { + g_free (comp_data->color); + ecalcomp->color = g_strdup_printf ("#%06x", source_color & 0xffffff); + } + //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); //cairo_t *cr = cairo_create(cs); @@ -320,17 +409,10 @@ update_appointment_menu_items (gpointer user_data) { //GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)cs, 0,0,0,0, width, height); - // TODO: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time - item = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set (item, "type", INDICATOR_MENUITEM_TYPE); - dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, name); //dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf); - dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, due); - 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_append (root, item); - g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, - G_CALLBACK (activate_cb), cmd); + appointments = g_list_append(appointments, item); // Keep track of the items here to make them east to remove if (i == 4) break; // See above FIXME regarding query result limit i++; @@ -395,7 +477,19 @@ build_menus (DbusmenuMenuitem * root) // This just populates the items on startup later we want to be able to update the appointments before // presenting the menu. update_appointment_menu_items(NULL); - + if (calendar != NULL) { + // TODO Create "Add appointment" menu item + } + // TODO Create FFR? "Add timer" menu item + + separator = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + dbusmenu_menuitem_child_append(root, separator); + + update_timezone_menu_items(NULL); + // TODO Create "detected location" menu item? (defaults to the geoclue location) + // TODO Create "Add location" menu item + separator = dbusmenu_menuitem_new(); dbusmenu_menuitem_property_set(separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); dbusmenu_menuitem_child_append(root, separator); -- cgit v1.2.3 From 665f9ece45a30a255c85aab6b9a855dda8a56b1d Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Mon, 24 Jan 2011 17:22:35 +0000 Subject: Final few fixes making it buildable --- src/datetime-service.c | 80 ++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 42 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index e06b76d..020371f 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -23,6 +23,7 @@ with this program. If not, see . #include #include +#include #include #include @@ -36,11 +37,9 @@ with this program. If not, see . #include #include #include -#include #include #include // Other users of ecal seem to also include these, not sure why they should be included by the above -#include #include @@ -66,7 +65,7 @@ static DbusmenuMenuitem * settings = NULL; static DbusmenuMenuitem * tzchange = NULL; static GList * appointments = NULL; static ECal * ecal = NULL; -static gchar * ecal_timezone = NULL; +static const gchar * ecal_timezone = NULL; /* Geoclue trackers */ static GeoclueMasterClient * geo_master = NULL; @@ -239,15 +238,9 @@ check_for_calendar (gpointer user_data) return FALSE; } -static gboolean -timezone_clicked_cb() { - - return FALSE; -} - static gboolean update_timezone_menu_items(gpointer user_data) { - + // Get the location preferences and the current location, highlight the current location somehow return FALSE; } @@ -261,6 +254,7 @@ 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. time_t t1, t2; + icaltimezone *tzone; gchar *query, *is, *ie; GList *objects = NULL, *l; GError *gerror = NULL; @@ -268,7 +262,8 @@ update_appointment_menu_items (gpointer user_data) { gint i; gint width, height; - ecal = e_cal_new_system_calendar(); + if (!ecal) + ecal = e_cal_new_system_calendar(); if (!ecal) { g_debug("e_cal_new_system_calendar failed"); @@ -282,7 +277,7 @@ update_appointment_menu_items (gpointer user_data) { return FALSE; } - if (!e_cal_get_timezone(ecal, "UTC", &tzone, &gerror) { + if (!e_cal_get_timezone(ecal, "UTC", &tzone, &gerror)) { g_debug("failed to get time zone\n"); g_free(ecal); ecal = NULL; @@ -305,22 +300,20 @@ update_appointment_menu_items (gpointer user_data) { // FIXME can we put a limit on the number of results? Or if not complete, or is event/todo? query = g_strdup_printf("(occur-in-time-range? (make-time\"%s\") (make-time\"%s\"))", is, ie); - if (!e_cal_get_object_list_as_comp(ecal, query, &objects, &gerror);) { + 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; } gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - if (appointments != NULL) { for (l = appointments; l; l = l->next) { item = l->data; - // TODO: Remove all the existing menu items which are in appointments. - - // pop it out of the dbus menu - // remove it from the appointments glist - // free it + // Remove all the existing menu items which are in appointments. + dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(item)); + appointments = g_list_remove(appointments, item); + g_free(item); } appointments = NULL; } @@ -330,14 +323,13 @@ update_appointment_menu_items (gpointer user_data) { ECalComponent *ecalcomp = l->data; ECalComponentText valuetext; ECalComponentDateTime datetime; - icaltimezone *appointment_zone; - time_t appointment_time, ti; + icaltimezone *appointment_zone = NULL; icalproperty_status status; gchar *summary, right[20], *cmd; const gchar *uri; - struct tm *tmp_tm, *tm_today; - - vtype = e_cal_component_get_vtype (comp); + struct tm tmp_tm; + + 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 @@ -352,15 +344,16 @@ update_appointment_menu_items (gpointer user_data) { // INPROGRESS: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time item = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set (item, "type", INDICATOR_MENUITEM_TYPE); + dbusmenu_menuitem_property_set (item, "type", APPOINTMENT_MENUITEM_TYPE); dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); // Label text e_cal_component_get_summary (ecalcomp, &valuetext); summary = g_strdup (valuetext.value); - e_cal_component_free_text (&valuetext); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, summary); + g_free (summary); // Due text @@ -369,23 +362,26 @@ update_appointment_menu_items (gpointer user_data) { else e_cal_component_get_due (ecalcomp, &datetime); - if (datetime.value) { - appointment_zone = get_zone_from_tzid (client, datetime.tzid); - if (!appointment_zone || datetime.value->is_date) - appointment_zone = ecal_timezone; - appointment_time = icaltime_as_timet_with_zone (*datetime.value, appointment_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; } + + if (!appointment_zone || datetime.value->is_date) { // If it's today put in the current timezone? + appointment_zone = tzone; + } + tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, tzone); + e_cal_component_free_datetime (&datetime); - tmp_tm = convert_timet_to_struct_tm (appointment_time, appointment_zone); // Get today - time(&ti); - tm_today = convert_timet_to_struct_tm (ti, appointment_zone); - if (tm_today->mday == tmp_tm->mday && tm_today->mon == tmp_tm->mon && tm_today->year == tmp_tm->year) - strftime(&right, sizeof(right), "%X", tmp_tm); + if (datetime.value->is_date) + strftime(right, sizeof(right), "%X", &tmp_tm); else - strftime(&right, sizeof(right), "%a %X", tmp_tm); - dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, &right); + strftime(right, sizeof(right), "%a %X", &tmp_tm); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right); // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution e_cal_component_get_url(ecalcomp, &uri); @@ -395,12 +391,13 @@ update_appointment_menu_items (gpointer user_data) { // Get the colour E_CAL_COMPONENT_FIELD_COLOR // Get the icon, either EVENT or MEMO or TODO? - gdouble red, blue, green; + /*gdouble red, blue, green; ECalSource *source = e_cal_get_source (ecalcomp->client); if (!ecalcomp->color && e_source_get_color (source, &source_color)) { g_free (comp_data->color); ecalcomp->color = g_strdup_printf ("#%06x", source_color & 0xffffff); - } + }*/ + //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); //cairo_t *cr = cairo_create(cs); @@ -412,7 +409,7 @@ update_appointment_menu_items (gpointer user_data) { //dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf); dbusmenu_menuitem_child_append (root, item); - appointments = g_list_append(appointments, item); // Keep track of the items here to make them east to remove + appointments = g_list_append (appointments, item); // Keep track of the items here to make them east to remove if (i == 4) break; // See above FIXME regarding query result limit i++; @@ -487,7 +484,6 @@ build_menus (DbusmenuMenuitem * root) dbusmenu_menuitem_child_append(root, separator); update_timezone_menu_items(NULL); - // TODO Create "detected location" menu item? (defaults to the geoclue location) // TODO Create "Add location" menu item separator = dbusmenu_menuitem_new(); -- cgit v1.2.3 From c023a16ebdef8c0bdbd10cdfe9cf753afad1191b Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Wed, 26 Jan 2011 11:12:48 -0500 Subject: fix some crashes --- src/datetime-service.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 020371f..d80fc18 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -415,6 +415,7 @@ update_appointment_menu_items (gpointer user_data) { i++; } g_free(ecal); // Really we should do the setup somewhere where we know it'll only run once, right now, we'll do it every time and free it. + ecal = NULL; return TRUE; } -- cgit v1.2.3 From e0718f3613ae3a39a58e87cf1f4b2c4c00b76117 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Mon, 31 Jan 2011 17:30:19 +0000 Subject: Removed all buggy code from the datetime-service to push for A2 --- src/datetime-service.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 173 insertions(+), 5 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 3fe6ebb..5961df8 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -63,6 +63,9 @@ static DbusmenuMenuitem * date = NULL; static DbusmenuMenuitem * calendar = NULL; static DbusmenuMenuitem * settings = NULL; static DbusmenuMenuitem * tzchange = NULL; +static GList * appointments = NULL; +static ECal * ecal = NULL; +static const gchar * ecal_timezone = NULL; /* Geoclue trackers */ static GeoclueMasterClient * geo_master = NULL; @@ -248,15 +251,180 @@ update_timezone_menu_items(gpointer user_data) { */ static gboolean 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. + time_t t1, t2; + icaltimezone *tzone; + gchar *query, *is, *ie; + GList *objects = NULL, *l; + GError *gerror = NULL; DbusmenuMenuitem * item = NULL; - gint i; - for (i = 0; i < 5; i++) { + gint width, height; + g_debug("Setting up ecal."); + if (!ecal) + ecal = e_cal_new_system_calendar(); + + if (!ecal) { + g_debug("e_cal_new_system_calendar failed"); + ecal = NULL; + return FALSE; + } + g_debug("Open calendar."); + if (!e_cal_open(ecal, FALSE, &gerror) ) { + g_debug("e_cal_open: %s\n", gerror->message); + g_free(ecal); + ecal = NULL; + return FALSE; + } + g_debug("Get calendar timezone."); + if (!e_cal_get_timezone(ecal, "UTC", &tzone, &gerror)) { + g_debug("failed to get time zone\n"); + g_free(ecal); + ecal = NULL; + return FALSE; + } + + /* 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. + */ + ecal_timezone = icaltimezone_get_tzid(tzone); + + time(&t1); + time(&t2); + t2 += (time_t) (7 * 24 * 60 * 60); /* 7 days ahead of now */ + + 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? + 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); + /*if (appointments != NULL) { + for (l = appointments; l; l = l->next) { + item = l->data; + // Remove all the existing menu items which are in appointments. + dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(item)); + appointments = g_list_remove(appointments, item); + g_free(item); + } + appointments = NULL; + }*/ + + i = 0; + for (l = objects; l; l = l->next) { + ECalComponent *ecalcomp = l->data; + ECalComponentText valuetext; + ECalComponentDateTime datetime; + icaltimezone *appointment_zone = NULL; + icalproperty_status status; + gchar *summary, *cmd; + const gchar *uri; + struct tm tmp_tm; + + 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; + + // INPROGRESS: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time item = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, APPOINTMENT_MENUITEM_TYPE); - dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, "fake summary"); - dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, "9:00pm"); + //dbusmenu_menuitem_property_set (item, "type", APPOINTMENT_MENUITEM_TYPE); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); + + // Label text + g_debug("Label Summary."); + e_cal_component_get_summary (ecalcomp, &valuetext); + summary = g_strdup (valuetext.value); + + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_LABEL, 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); + + // FIXME need to get the timezone of the above datetime, + // and get the icaltimezone of the geoclue timezone/selected timezone (whichever is preferred) + + g_debug("Check for a datetime."); // Should always have one + if (!datetime.value) { + g_free(item); + continue; + } + + g_debug("Set appointment zone."); + if (!appointment_zone || datetime.value->is_date) { // If it's today put in the current timezone? + appointment_zone = tzone; + } + tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, tzone); + + g_debug("Free datetime."); + e_cal_component_free_datetime (&datetime); + + // Get today + /*g_debug("Generate strings"); + if (datetime.value->is_date) + strftime(right, sizeof(right), "%X", &tmp_tm); + else + strftime(right, sizeof(right), "%a %X", &tmp_tm);*/ + //dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right); + + g_debug("Set callback"); + // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution + e_cal_component_get_url(ecalcomp, &uri); + cmd = g_strconcat("evolution ", uri, NULL); + g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activate_cb), cmd); + + // Get the colour E_CAL_COMPONENT_FIELD_COLOR + // Get the icon, either EVENT or MEMO or TODO? + /*gdouble red, blue, green; + ECalSource *source = e_cal_get_source (ecalcomp->client); + if (!ecalcomp->color && e_source_get_color (source, &source_color)) { + g_free (comp_data->color); + ecalcomp->color = g_strdup_printf ("#%06x", source_color & 0xffffff); + }*/ + + + //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + //cairo_t *cr = cairo_create(cs); + + // TODO: Draw the correct icon for the appointment type and then tint it using mask fill. + + //GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)cs, 0,0,0,0, width, height); + + //dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf); + g_debug("Add to menu."); dbusmenu_menuitem_child_append (root, item); + appointments = g_list_append (appointments, item); // Keep track of the items here to make them east to remove + + if (i == 4) break; // See above FIXME regarding query result limit + i++; + } + g_debug("Free-ing ecal."); + if (ecal) { + //g_free(ecal); // Really we should do the setup somewhere where we know it'll only run once, right now, we'll do it every time and free it. } return TRUE; } -- cgit v1.2.3 From 5734c96d1e10bbc78532b07cb3fe127c609a7e16 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Wed, 2 Feb 2011 11:14:26 +0000 Subject: Getting the menu working almost correctly --- src/datetime-service.c | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 5961df8..85fcc2d 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -261,6 +261,7 @@ update_appointment_menu_items (gpointer user_data) { DbusmenuMenuitem * item = NULL; gint i; gint width, height; + g_debug("Setting up ecal."); if (!ecal) ecal = e_cal_new_system_calendar(); @@ -309,7 +310,7 @@ update_appointment_menu_items (gpointer user_data) { } g_debug("Number of objects returned: %d", g_list_length(objects)); gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - /*if (appointments != NULL) { + if (appointments != NULL) { for (l = appointments; l; l = l->next) { item = l->data; // Remove all the existing menu items which are in appointments. @@ -318,8 +319,8 @@ update_appointment_menu_items (gpointer user_data) { g_free(item); } appointments = NULL; - }*/ - + } + i = 0; for (l = objects; l; l = l->next) { ECalComponent *ecalcomp = l->data; @@ -328,6 +329,7 @@ update_appointment_menu_items (gpointer user_data) { icaltimezone *appointment_zone = NULL; icalproperty_status status; gchar *summary, *cmd; + char right[20]; const gchar *uri; struct tm tmp_tm; @@ -345,17 +347,19 @@ update_appointment_menu_items (gpointer user_data) { continue; // INPROGRESS: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time + item = dbusmenu_menuitem_new(); - //dbusmenu_menuitem_property_set (item, "type", APPOINTMENT_MENUITEM_TYPE); + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, APPOINTMENT_MENUITEM_TYPE); 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 - g_debug("Label Summary."); e_cal_component_get_summary (ecalcomp, &valuetext); summary = g_strdup (valuetext.value); - dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_LABEL, summary); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_LABEL, summary); + g_debug("Summary: %s", summary); g_free (summary); // Due text @@ -367,36 +371,40 @@ update_appointment_menu_items (gpointer user_data) { // FIXME need to get the timezone of the above datetime, // and get the icaltimezone of the geoclue timezone/selected timezone (whichever is preferred) - g_debug("Check for a datetime."); // Should always have one + //g_debug("Check for a datetime."); // Should always have one if (!datetime.value) { g_free(item); continue; } - g_debug("Set appointment zone."); + //g_debug("Set appointment zone."); if (!appointment_zone || datetime.value->is_date) { // If it's today put in the current timezone? appointment_zone = tzone; } tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, tzone); - g_debug("Free datetime."); - e_cal_component_free_datetime (&datetime); // Get today - /*g_debug("Generate strings"); - if (datetime.value->is_date) - strftime(right, sizeof(right), "%X", &tmp_tm); + g_debug("Generate strings"); + if (datetime.value->is_date) // Is today - not working :/ + strftime(right, 20, "%l:%M %P", &tmp_tm); else - strftime(right, sizeof(right), "%a %X", &tmp_tm);*/ - //dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right); + strftime(right, 20, "%a %l:%M %P", &tmp_tm); + + g_debug("Appointment time: %s", right); + dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right); + + //g_debug("Free datetime."); + e_cal_component_free_datetime (&datetime); - g_debug("Set callback"); // Now we pull out the URI for the calendar event and try to create a URI that'll work when we execute evolution - e_cal_component_get_url(ecalcomp, &uri); - cmd = g_strconcat("evolution ", uri, NULL); + e_cal_component_get_uid(ecalcomp, &uri); + cmd = g_strconcat("evolution calendar://", uri, NULL); g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_cb), cmd); + g_debug("Command to Execute: %s", cmd); + // Get the colour E_CAL_COMPONENT_FIELD_COLOR // Get the icon, either EVENT or MEMO or TODO? /*gdouble red, blue, green; @@ -415,14 +423,14 @@ update_appointment_menu_items (gpointer user_data) { //GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)cs, 0,0,0,0, width, height); //dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf); - g_debug("Add to menu."); + dbusmenu_menuitem_child_append (root, item); appointments = g_list_append (appointments, item); // Keep track of the items here to make them east to remove if (i == 4) break; // See above FIXME regarding query result limit i++; } - g_debug("Free-ing ecal."); + g_debug("End of objects"); if (ecal) { //g_free(ecal); // Really we should do the setup somewhere where we know it'll only run once, right now, we'll do it every time and free it. } -- cgit v1.2.3 From 9c3aeee0b80f691a468812b097fda30332676e20 Mon Sep 17 00:00:00 2001 From: karl-qdh Date: Fri, 4 Feb 2011 12:26:38 +0000 Subject: Updated the service, better memory handling, menu item sorting, triggered by about to show signal, discovered a new bug in dbusmenu https://bugs.launchpad.net/dbusmenu/+bug/713041 --- src/datetime-service.c | 169 +++++++++++++++++++++++++++++++------------------ 1 file changed, 107 insertions(+), 62 deletions(-) (limited to 'src/datetime-service.c') diff --git a/src/datetime-service.c b/src/datetime-service.c index 85fcc2d..736e89e 100644 --- a/src/datetime-service.c +++ b/src/datetime-service.c @@ -66,6 +66,7 @@ static DbusmenuMenuitem * tzchange = NULL; static GList * appointments = NULL; static ECal * ecal = NULL; static const gchar * ecal_timezone = NULL; +static icaltimezone *tzone; /* Geoclue trackers */ static GeoclueMasterClient * geo_master = NULL; @@ -244,6 +245,41 @@ update_timezone_menu_items(gpointer user_data) { return FALSE; } +// 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; + + ECalComponentVType vtype = e_cal_component_get_vtype (a); + 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) + 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; +} + /* Populate the menu with todays, next 5 appointments. * we should hook into the ABOUT TO SHOW signal and use that to update the appointments. * Experience has shown that caldav's and webcals can be slow to load from eds @@ -251,55 +287,25 @@ update_timezone_menu_items(gpointer user_data) { */ 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; - icaltimezone *tzone; - gchar *query, *is, *ie; + gchar *query, *is, *ie, *ad; GList *objects = NULL, *l; - GError *gerror = NULL; DbusmenuMenuitem * item = NULL; + GError *gerror = NULL; gint i; gint width, height; - g_debug("Setting up ecal."); - if (!ecal) - ecal = e_cal_new_system_calendar(); - - if (!ecal) { - g_debug("e_cal_new_system_calendar failed"); - ecal = NULL; - return FALSE; - } - g_debug("Open calendar."); - if (!e_cal_open(ecal, FALSE, &gerror) ) { - g_debug("e_cal_open: %s\n", gerror->message); - g_free(ecal); - ecal = NULL; - return FALSE; - } - g_debug("Get calendar timezone."); - if (!e_cal_get_timezone(ecal, "UTC", &tzone, &gerror)) { - g_debug("failed to get time zone\n"); - g_free(ecal); - ecal = NULL; - return FALSE; - } - - /* 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. - */ - ecal_timezone = icaltimezone_get_tzid(tzone); - time(&t1); time(&t2); t2 += (time_t) (7 * 24 * 60 * 60); /* 7 days ahead of now */ 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? + + // 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)) { @@ -311,16 +317,21 @@ update_appointment_menu_items (gpointer user_data) { g_debug("Number of objects returned: %d", g_list_length(objects)); gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); if (appointments != NULL) { + g_debug("Freeing old appointments"); for (l = appointments; l; l = l->next) { + g_debug("Freeing old appointment"); item = l->data; // Remove all the existing menu items which are in appointments. - dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(item)); appointments = g_list_remove(appointments, item); - g_free(item); + dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(item)); + //g_free(item); freeing makes it crash :/ is that a double free from child delete? + item = NULL; } appointments = NULL; } + // Sort the list see above FIXME regarding queries + objects = g_list_sort(objects, (GCompareFunc) compare_appointment_items); i = 0; for (l = objects; l; l = l->next) { ECalComponent *ecalcomp = l->data; @@ -330,7 +341,7 @@ update_appointment_menu_items (gpointer user_data) { icalproperty_status status; gchar *summary, *cmd; char right[20]; - const gchar *uri; + //const gchar *uri; struct tm tmp_tm; ECalComponentVType vtype = e_cal_component_get_vtype (ecalcomp); @@ -346,8 +357,6 @@ update_appointment_menu_items (gpointer user_data) { if (status == ICAL_STATUS_COMPLETED || status == ICAL_STATUS_CANCELLED) continue; - // INPROGRESS: Create a menu item for each of them, try to include helpful metadata e.g. colours, due time - 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); @@ -370,23 +379,23 @@ update_appointment_menu_items (gpointer user_data) { // FIXME need to get the timezone of the above datetime, // and get the icaltimezone of the geoclue timezone/selected timezone (whichever is preferred) - - //g_debug("Check for a datetime."); // Should always have one if (!datetime.value) { g_free(item); continue; } - //g_debug("Set appointment zone."); if (!appointment_zone || datetime.value->is_date) { // If it's today put in the current timezone? appointment_zone = tzone; } tmp_tm = icaltimetype_to_tm_with_zone (datetime.value, appointment_zone, tzone); - + g_debug("Generate time string"); // Get today - g_debug("Generate strings"); - if (datetime.value->is_date) // Is today - not working :/ + 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); else strftime(right, 20, "%a %l:%M %P", &tmp_tm); @@ -394,12 +403,15 @@ update_appointment_menu_items (gpointer user_data) { g_debug("Appointment time: %s", right); dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right); - //g_debug("Free datetime."); e_cal_component_free_datetime (&datetime); + ad = is = 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 - e_cal_component_get_uid(ecalcomp, &uri); - cmd = g_strconcat("evolution calendar://", uri, NULL); + // 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); + cmd = g_strconcat("evolution calendar:///?startdate=", ad, NULL); g_signal_connect (G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_cb), cmd); @@ -407,33 +419,34 @@ update_appointment_menu_items (gpointer user_data) { // Get the colour E_CAL_COMPONENT_FIELD_COLOR // Get the icon, either EVENT or MEMO or TODO? - /*gdouble red, blue, green; - ECalSource *source = e_cal_get_source (ecalcomp->client); - if (!ecalcomp->color && e_source_get_color (source, &source_color)) { - g_free (comp_data->color); - ecalcomp->color = g_strdup_printf ("#%06x", source_color & 0xffffff); - }*/ - + // needs EDS, ecal component colours are broken... + //gdouble red, blue, green; + //ECalSource *source = e_cal_get_source (ecalcomp->client); + //if (!ecalcomp->color && e_source_get_color (source, &source_color)) { + //g_free (comp_data->color); + //ecalcomp->color = g_strdup_printf ("#%06x", source_color & 0xffffff); + //} + //g_debug("Colour to use: %s", ecalcomp->color); //cairo_surface_t *cs = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); //cairo_t *cr = cairo_create(cs); // TODO: Draw the correct icon for the appointment type and then tint it using mask fill. - + // For now we'll create a circle + + //GdkPixbuf * pixbuf = gdk_pixbuf_get_from_drawable(NULL, (GdkDrawable*)cs, 0,0,0,0, width, height); //dbusmenu_menuitem_property_set_image (item, APPOINTMENT_MENUITEM_PROP_ICON, pixbuf); - dbusmenu_menuitem_child_append (root, item); + dbusmenu_menuitem_child_add_position (root, item, 4+i); appointments = g_list_append (appointments, item); // Keep track of the items here to make them east to remove if (i == 4) break; // See above FIXME regarding query result limit i++; } + g_list_free(objects); g_debug("End of objects"); - if (ecal) { - //g_free(ecal); // Really we should do the setup somewhere where we know it'll only run once, right now, we'll do it every time and free it. - } return TRUE; } @@ -492,8 +505,39 @@ build_menus (DbusmenuMenuitem * root) // This just populates the items on startup later we want to be able to update the appointments before // presenting the menu. - update_appointment_menu_items(NULL); if (calendar != NULL) { + 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."); + if (!ecal) + ecal = e_cal_new_system_calendar(); + + if (!ecal) { + g_debug("e_cal_new_system_calendar failed"); + ecal = NULL; + } + g_debug("Open calendar."); + if (!e_cal_open(ecal, FALSE, &gerror) ) { + g_debug("e_cal_open: %s\n", gerror->message); + g_free(ecal); + ecal = NULL; + } + g_debug("Get calendar timezone."); + if (!e_cal_get_timezone(ecal, "UTC", &tzone, &gerror)) { + g_debug("failed to get time zone\n"); + g_free(ecal); + ecal = NULL; + } + + /* 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); + + g_signal_connect(root, DBUSMENU_MENUITEM_SIGNAL_ABOUT_TO_SHOW, G_CALLBACK(update_appointment_menu_items), NULL); + update_appointment_menu_items(NULL); // TODO Create "Add appointment" menu item } // TODO Create FFR? "Add timer" menu item @@ -751,6 +795,7 @@ main (int argc, char ** argv) server = dbusmenu_server_new(MENU_OBJ); root = dbusmenu_menuitem_new(); dbusmenu_server_set_root(server, root); + build_menus(root); /* Setup geoclue */ -- cgit v1.2.3