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 +++++++++++++++++++++++++++++++++++++++++++++++ src/dbus-shared.h | 4 ++ src/indicator-datetime.c | 78 ++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) (limited to 'src') 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 diff --git a/src/dbus-shared.h b/src/dbus-shared.h index 357beb5..4ecd64b 100644 --- a/src/dbus-shared.h +++ b/src/dbus-shared.h @@ -29,3 +29,7 @@ with this program. If not, see . #define DBUSMENU_CALENDAR_MENUITEM_TYPE "x-canonical-calendar-item" +#define APPOINTMENT_MENUITEM_TYPE "indicator-item" +#define APPOINTMENT_MENUITEM_PROP_LABEL "indicator-label" +#define APPOINTMENT_MENUITEM_PROP_ICON "indicator-icon" +#define APPOINTMENT_MENUITEM_PROP_RIGHT "right-side-text" diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index acdc340..4c3b315 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -923,6 +923,83 @@ generate_format_string (IndicatorDatetime * self) return g_strdup_printf(_("%s, %s"), date_string, time_string); } +/* We have a small little menuitem type that handles all + of the fun stuff for indicators. Mostly this is the + shifting over and putting the icon in with some right + side text that'll be determined by the service. + Copied verbatim from an old revision (including comments) of indicator-messages +*/ +static gboolean +new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client) +{ + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + /* Note: not checking parent, it's reasonable for it to be NULL */ + + 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); + + /* Icon, probably someone's face or avatar on an IM */ + mi_data->icon = gtk_image_new(); + GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, INDICATOR_MENUITEM_PROP_ICON); + + if (pixbuf != NULL) { + /* If we've got a pixbuf we need to make sure it's of a reasonable + size to fit in the menu. If not, rescale it. */ + GdkPixbuf * resized_pixbuf; + gint width, height; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + if (gdk_pixbuf_get_width(pixbuf) > width || + gdk_pixbuf_get_height(pixbuf) > height) { + g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); + resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, + width, + height, + GDK_INTERP_BILINEAR); + } else { + g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + resized_pixbuf = pixbuf; + } + + gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); + + /* The other pixbuf should be free'd by the dbusmenu. */ + if (resized_pixbuf != pixbuf) { + g_object_unref(resized_pixbuf); + } + } + gtk_misc_set_alignment(GTK_MISC(mi_data->icon), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), mi_data->icon, FALSE, FALSE, 0); + gtk_widget_show(mi_data->icon); + + /* Label, probably a username, chat room or mailbox name */ + mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_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, INDICATOR_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_widget_show(hbox); + + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); + + g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data); + g_signal_connect(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data); + + return TRUE; +} + static gboolean new_calendar_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, @@ -986,6 +1063,7 @@ get_menu (IndicatorObject * io) g_object_set_data (G_OBJECT (client), "indicator", io); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item); + dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_indicator_item); return GTK_MENU(self->priv->menu); } -- 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') 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') 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 + src/indicator-datetime.c | 63 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 4 deletions(-) (limited to 'src') 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); diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index 4c3b315..364c7b4 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -40,6 +40,7 @@ with this program. If not, see . /* DBusMenu */ #include #include +#include #include "dbus-shared.h" @@ -99,6 +100,13 @@ enum { PROP_CUSTOM_TIME_FORMAT }; +typedef struct _indicator_item_t indicator_item_t; +struct _indicator_item_t { + GtkWidget * icon; + GtkWidget * label; + GtkWidget * right; +}; + #define PROP_TIME_FORMAT_S "time-format" #define PROP_SHOW_SECONDS_S "show-seconds" #define PROP_SHOW_DAY_S "show-day" @@ -150,6 +158,8 @@ INDICATOR_SET_TYPE(INDICATOR_DATETIME_TYPE) G_DEFINE_TYPE (IndicatorDatetime, indicator_datetime, INDICATOR_OBJECT_TYPE); +static GtkSizeGroup * indicator_right_group = NULL; + static void indicator_datetime_class_init (IndicatorDatetimeClass *klass) { @@ -923,6 +933,51 @@ generate_format_string (IndicatorDatetime * self) return g_strdup_printf(_("%s, %s"), date_string, time_string); } +/* 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) +{ + if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_LABEL)) { + /* Set the main label */ + gtk_label_set_text(GTK_LABEL(mi_data->label), value); + } else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_RIGHT)) { + /* Set the right label */ + gtk_label_set_text(GTK_LABEL(mi_data->right), value); + } 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 + is already cached, shouldn't be a big deal really. */ + GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(mi, APPOINTMENT_MENUITEM_PROP_ICON); + if (pixbuf != NULL) { + /* If we've got a pixbuf we need to make sure it's of a reasonable + size to fit in the menu. If not, rescale it. */ + GdkPixbuf * resized_pixbuf; + gint width, height; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + if (gdk_pixbuf_get_width(pixbuf) > width || + gdk_pixbuf_get_height(pixbuf) > height) { + g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); + resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, + width, + height, + GDK_INTERP_BILINEAR); + } else { + g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + resized_pixbuf = pixbuf; + } + gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); + /* The other pixbuf should be free'd by the dbusmenu. */ + if (resized_pixbuf != pixbuf) { + g_object_unref(resized_pixbuf); + } + } + } else { + g_warning("Indicator Item property '%s' unknown", prop); + } + return; +} + /* We have a small little menuitem type that handles all of the fun stuff for indicators. Mostly this is the shifting over and putting the icon in with some right @@ -944,7 +999,7 @@ new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu /* Icon, probably someone's face or avatar on an IM */ mi_data->icon = gtk_image_new(); - GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, INDICATOR_MENUITEM_PROP_ICON); + GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, APPOINTMENT_MENUITEM_PROP_ICON); if (pixbuf != NULL) { /* If we've got a pixbuf we need to make sure it's of a reasonable @@ -976,14 +1031,14 @@ new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu gtk_widget_show(mi_data->icon); /* Label, probably a username, chat room or mailbox name */ - mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_LABEL)); + mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_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, INDICATOR_MENUITEM_PROP_RIGHT)); + mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_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); @@ -1063,7 +1118,7 @@ get_menu (IndicatorObject * io) g_object_set_data (G_OBJECT (client), "indicator", io); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item); - dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_indicator_item); + dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item); return GTK_MENU(self->priv->menu); } -- 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 ++++++++++++++++++++++++++++++++++++----------- src/indicator-datetime.c | 10 +++ 2 files changed, 141 insertions(+), 37 deletions(-) (limited to 'src') 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); diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index 364c7b4..c6dc2c1 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -1081,6 +1081,16 @@ new_calendar_item (DbusmenuMenuitem * newitem, return TRUE; } +static gboolean +new_timezone_item(DbusmenuMenuitem * newitem, + DbusmenuMenuitem * parent, + DbusmenuClient * client) +{ + // Menu item with a radio button and a right aligned time + + return TRUE; +} + /* Grabs the label. Creates it if it doesn't exist already */ static GtkLabel * -- 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 +++++++++++++++++++++++------------------------- src/dbus-shared.h | 13 +++++--- src/indicator-datetime.c | 1 + 3 files changed, 48 insertions(+), 46 deletions(-) (limited to 'src') 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(); diff --git a/src/dbus-shared.h b/src/dbus-shared.h index 4ecd64b..1f90ca7 100644 --- a/src/dbus-shared.h +++ b/src/dbus-shared.h @@ -29,7 +29,12 @@ with this program. If not, see . #define DBUSMENU_CALENDAR_MENUITEM_TYPE "x-canonical-calendar-item" -#define APPOINTMENT_MENUITEM_TYPE "indicator-item" -#define APPOINTMENT_MENUITEM_PROP_LABEL "indicator-label" -#define APPOINTMENT_MENUITEM_PROP_ICON "indicator-icon" -#define APPOINTMENT_MENUITEM_PROP_RIGHT "right-side-text" +#define APPOINTMENT_MENUITEM_TYPE "appointment-item" +#define APPOINTMENT_MENUITEM_PROP_LABEL "appointment-label" +#define APPOINTMENT_MENUITEM_PROP_ICON "appointment-icon" +#define APPOINTMENT_MENUITEM_PROP_RIGHT "appointment-time" + +#define TIMEZONE_MENUITEM_TYPE "timezone-item" +#define TIMEZONE_MENUITEM_PROP_LABEL "timezone-label" +#define TIMEZONE_MENUITEM_PROP_RADIO "timezone-radio" +#define TIMEZONE_MENUITEM_PROP_RIGHT "timezone-time" diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index 5d92296..a07e667 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -1263,6 +1263,7 @@ get_menu (IndicatorObject * io) dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item); + dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item); return GTK_MENU(self->priv->menu); } -- 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 + src/indicator-datetime.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') 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; } diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index a07e667..288ab26 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -340,7 +340,7 @@ service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data) } if (error != NULL) { - g_error("Could not grab DBus proxy for %s: %s", SERVICE_NAME, error->message); + g_warning("Could not grab DBus proxy for %s: %s", SERVICE_NAME, error->message); g_error_free(error); return; } @@ -1182,7 +1182,7 @@ new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data); - g_signal_connect(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data); + g_signal_connect_swapped(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data); 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 +++++++++++++++++++++++++++++++++++++++++++++-- src/indicator-datetime.c | 122 ++------------------------------ 2 files changed, 180 insertions(+), 120 deletions(-) (limited to 'src') 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; } diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index e7a448e..44740a6 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -182,7 +182,7 @@ INDICATOR_SET_TYPE(INDICATOR_DATETIME_TYPE) G_DEFINE_TYPE (IndicatorDatetime, indicator_datetime, INDICATOR_OBJECT_TYPE); -static GtkSizeGroup * indicator_right_group = NULL; +//static GtkSizeGroup * indicator_right_group = NULL; static void indicator_datetime_class_init (IndicatorDatetimeClass *klass) @@ -1067,48 +1067,7 @@ generate_format_string (IndicatorDatetime * self) /* 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) -{ - if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_LABEL)) { - /* Set the main label */ - gtk_label_set_text(GTK_LABEL(mi_data->label), value); - } else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_RIGHT)) { - /* Set the right label */ - gtk_label_set_text(GTK_LABEL(mi_data->right), value); - } 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 - is already cached, shouldn't be a big deal really. */ - GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(mi, APPOINTMENT_MENUITEM_PROP_ICON); - if (pixbuf != NULL) { - /* If we've got a pixbuf we need to make sure it's of a reasonable - size to fit in the menu. If not, rescale it. */ - GdkPixbuf * resized_pixbuf; - gint width, height; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - if (gdk_pixbuf_get_width(pixbuf) > width || - gdk_pixbuf_get_height(pixbuf) > height) { - g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); - resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, - width, - height, - GDK_INTERP_BILINEAR); - } else { - g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); - resized_pixbuf = pixbuf; - } - gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); - /* The other pixbuf should be free'd by the dbusmenu. */ - if (resized_pixbuf != pixbuf) { - g_object_unref(resized_pixbuf); - } - } - } else { - g_warning("Indicator Item property '%s' unknown", prop); - } - return; -} +// indicator prop changed removed /* We have a small little menuitem type that handles all of the fun stuff for indicators. Mostly this is the @@ -1116,76 +1075,8 @@ indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, in side text that'll be determined by the service. Copied verbatim from an old revision (including comments) of indicator-messages */ -static gboolean -new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) -{ - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - /* Note: not checking parent, it's reasonable for it to be NULL */ +// new appointment item removed - 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); - - /* Icon, probably someone's face or avatar on an IM */ - mi_data->icon = gtk_image_new(); - GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, APPOINTMENT_MENUITEM_PROP_ICON); - - if (pixbuf != NULL) { - /* If we've got a pixbuf we need to make sure it's of a reasonable - size to fit in the menu. If not, rescale it. */ - GdkPixbuf * resized_pixbuf; - gint width, height; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - if (gdk_pixbuf_get_width(pixbuf) > width || - gdk_pixbuf_get_height(pixbuf) > height) { - g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); - resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, - width, - height, - GDK_INTERP_BILINEAR); - } else { - g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); - resized_pixbuf = pixbuf; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); - - /* The other pixbuf should be free'd by the dbusmenu. */ - if (resized_pixbuf != pixbuf) { - g_object_unref(resized_pixbuf); - } - } - gtk_misc_set_alignment(GTK_MISC(mi_data->icon), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), mi_data->icon, FALSE, FALSE, 0); - gtk_widget_show(mi_data->icon); - - /* Label, probably a username, chat room or mailbox name */ - mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_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)); - 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_widget_show(hbox); - - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, 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); - - return TRUE; -} static gboolean new_calendar_item (DbusmenuMenuitem * newitem, @@ -1213,7 +1104,7 @@ new_calendar_item (DbusmenuMenuitem * newitem, return TRUE; } - +/* static gboolean new_timezone_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, @@ -1224,6 +1115,7 @@ new_timezone_item(DbusmenuMenuitem * newitem, return TRUE; } +*/ /* Grabs the label. Creates it if it doesn't exist already */ @@ -1264,8 +1156,8 @@ get_menu (IndicatorObject * io) g_object_set_data (G_OBJECT (client), "indicator", io); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item); - dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item); - dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item); + //dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item); + //dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item); return GTK_MENU(self->priv->menu); } -- 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 +++++++++++-------- src/indicator-datetime.c | 123 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 145 insertions(+), 28 deletions(-) (limited to 'src') 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. } diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c index 44740a6..7748a8c 100644 --- a/src/indicator-datetime.c +++ b/src/indicator-datetime.c @@ -182,7 +182,7 @@ INDICATOR_SET_TYPE(INDICATOR_DATETIME_TYPE) G_DEFINE_TYPE (IndicatorDatetime, indicator_datetime, INDICATOR_OBJECT_TYPE); -//static GtkSizeGroup * indicator_right_group = NULL; +static GtkSizeGroup * indicator_right_group = NULL; static void indicator_datetime_class_init (IndicatorDatetimeClass *klass) @@ -1067,7 +1067,48 @@ generate_format_string (IndicatorDatetime * self) /* Whenever we have a property change on a DbusmenuMenuitem we need to be responsive to that. */ -// indicator prop changed removed +static void +indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * 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); + } else if (!g_strcmp0(prop, APPOINTMENT_MENUITEM_PROP_RIGHT)) { + /* Set the right label */ + gtk_label_set_text(GTK_LABEL(mi_data->right), value); + } 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 + is already cached, shouldn't be a big deal really. */ + GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(mi, APPOINTMENT_MENUITEM_PROP_ICON); + if (pixbuf != NULL) { + /* If we've got a pixbuf we need to make sure it's of a reasonable + size to fit in the menu. If not, rescale it. */ + GdkPixbuf * resized_pixbuf; + gint width, height; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + if (gdk_pixbuf_get_width(pixbuf) > width || + gdk_pixbuf_get_height(pixbuf) > height) { + g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); + resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, + width, + height, + GDK_INTERP_BILINEAR); + } else { + g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + resized_pixbuf = pixbuf; + } + gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); + /* The other pixbuf should be free'd by the dbusmenu. */ + if (resized_pixbuf != pixbuf) { + g_object_unref(resized_pixbuf); + } + } + } else { + g_warning("Indicator Item property '%s' unknown", prop); + } + return; +} /* We have a small little menuitem type that handles all of the fun stuff for indicators. Mostly this is the @@ -1075,7 +1116,76 @@ generate_format_string (IndicatorDatetime * self) side text that'll be determined by the service. Copied verbatim from an old revision (including comments) of indicator-messages */ -// new appointment item removed +static gboolean +new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) +{ + g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); + g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); + /* Note: not checking parent, it's reasonable for it to be NULL */ + + 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); + + /* Icon, probably someone's face or avatar on an IM */ + mi_data->icon = gtk_image_new(); + GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, APPOINTMENT_MENUITEM_PROP_ICON); + + if (pixbuf != NULL) { + /* If we've got a pixbuf we need to make sure it's of a reasonable + size to fit in the menu. If not, rescale it. */ + GdkPixbuf * resized_pixbuf; + gint width, height; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); + if (gdk_pixbuf_get_width(pixbuf) > width || + gdk_pixbuf_get_height(pixbuf) > height) { + g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); + resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, + width, + height, + GDK_INTERP_BILINEAR); + } else { + g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + resized_pixbuf = pixbuf; + } + + gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); + + /* The other pixbuf should be free'd by the dbusmenu. */ + if (resized_pixbuf != pixbuf) { + g_object_unref(resized_pixbuf); + } + } + gtk_misc_set_alignment(GTK_MISC(mi_data->icon), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), mi_data->icon, FALSE, FALSE, 0); + gtk_widget_show(mi_data->icon); + + /* Label, probably a username, chat room or mailbox name */ + mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_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)); + 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_widget_show(hbox); + + dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, 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); + + return TRUE; +} static gboolean @@ -1104,7 +1214,7 @@ new_calendar_item (DbusmenuMenuitem * newitem, return TRUE; } -/* + static gboolean new_timezone_item(DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, @@ -1115,7 +1225,6 @@ new_timezone_item(DbusmenuMenuitem * newitem, return TRUE; } -*/ /* Grabs the label. Creates it if it doesn't exist already */ @@ -1156,8 +1265,8 @@ get_menu (IndicatorObject * io) g_object_set_data (G_OBJECT (client), "indicator", io); dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item); - //dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item); - //dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item); + dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item); + dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item); return GTK_MENU(self->priv->menu); } -- 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') 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