Honestly, I don't see anything odd. I'm going to have to look closer tomorrow. Especially nothing that would cause the craziness that you're getting! Uhg...
On Wed, 2011-01-26 at 11:50 +0000, Karl Lattimer wrote: > Karl Lattimer has proposed merging > lp:~karl-qdh/ubuntu/natty/indicator-datetime/indicator-datetime.withappointments > into lp:indicator-datetime. > > Requested reviews: > Ted Gould (ted) > Related bugs: > #542218 integration with Evolution calendar events and time locations > https://bugs.launchpad.net/bugs/542218 > > For more details, see: > https://code.launchpad.net/~karl-qdh/ubuntu/natty/indicator-datetime/indicator-datetime.withappointments/+merge/47514 > > This change introduces a new dbusmenu item type of APPOINTMENT_MENUITEM_TYPE > which has 3 columns of <image><appointment summary> -- <due time/date> > > with the new item type, we also introduce a small part of code to > datetime-service which reads the EDS data for ecal and produces the values to > fill into the menu items. > > However, there are issues with this. > > For some bizarre reason this indicator is affecting other indicators. Most > notably the sound indicator which switches the volume up/down repeatedly, > other indicators have strange effects too and it's difficult to see why this > can happen in the code itself. > differences between files attachment (review-diff.txt) > === modified file 'configure.ac' > --- configure.ac 2011-01-11 16:19:07 +0000 > +++ configure.ac 2011-01-26 11:50:11 +0000 > @@ -59,6 +59,8 @@ > INDICATOR_DISPLAY_OBJECTS=0.1.10 > GEOCLUE_REQUIRED_VERSION=0.12.0 > OOBS_REQUIRED_VERSION=2.31.0 > +ECAL_REQUIRED_VERSION=2.30 > +ICAL_REQUIRED_VERSION=0.44 > > AS_IF([test "x$with_gtk" = x3], > [PKG_CHECK_MODULES(INDICATOR, indicator3 >= $INDICATOR_REQUIRED_VERSION > @@ -80,7 +82,9 @@ > libido-0.1 >= $INDICATOR_DISPLAY_OBJECTS > gio-2.0 >= $GIO_REQUIRED_VERSION > geoclue >= $GEOCLUE_REQUIRED_VERSION > - liboobs-1 >= $OOBS_REQUIRED_VERSION) > + liboobs-1 >= $OOBS_REQUIRED_VERSION > + libecal-1.2 >= $ECAL_REQUIRED_VERSION > + libical >= $ICAL_REQUIRED_VERSION) > > AC_SUBST(INDICATOR_CFLAGS) > AC_SUBST(INDICATOR_LIBS) > > === modified file 'src/datetime-service.c' > --- src/datetime-service.c 2010-10-22 13:31:37 +0000 > +++ src/datetime-service.c 2011-01-26 11:50:11 +0000 > @@ -23,6 +23,7 @@ > #include <libindicator/indicator-service.h> > #include <locale.h> > > +#include <gtk/gtk.h> > #include <glib/gi18n.h> > #include <gio/gio.h> > > @@ -33,6 +34,15 @@ > #include <geoclue/geoclue-master.h> > #include <geoclue/geoclue-master-client.h> > > +#include <time.h> > +#include <libecal/e-cal.h> > +#include <libical/ical.h> > +#include <libecal/e-cal-time-util.h> > +#include <libedataserver/e-source.h> > +// Other users of ecal seem to also include these, not sure why they should > be included by the above > +#include <libical/icaltime.h> > + > + > #include <oobs/oobs-timeconfig.h> > > #include "datetime-interface.h" > @@ -53,6 +63,9 @@ > 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; > @@ -225,6 +238,186 @@ > 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; > +} > + > +/* 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; > + icaltimezone *tzone; > + gchar *query, *is, *ie; > + GList *objects = NULL, *l; > + GError *gerror = NULL; > + DbusmenuMenuitem * item = NULL; > + gint i; > + gint width, height; > + > + if (!ecal) > + 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; > + } > + > + /* 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); > + > + 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; > + // 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, right[20], *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, "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); > + > + 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); > + > + // 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); > + > + // Get today > + 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); > + > + // 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); > + > + 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_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 > item we have one */ > static gboolean > @@ -272,8 +465,28 @@ > > 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); > > - DbusmenuMenuitem * separator = dbusmenu_menuitem_new(); > + // 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 "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); > > > === modified file 'src/dbus-shared.h' > --- src/dbus-shared.h 2010-08-31 12:57:01 +0000 > +++ src/dbus-shared.h 2011-01-26 11:50:11 +0000 > @@ -29,3 +29,12 @@ > > #define DBUSMENU_CALENDAR_MENUITEM_TYPE "x-canonical-calendar-item" > > +#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" > > === modified file 'src/indicator-datetime.c' > --- src/indicator-datetime.c 2011-01-14 06:19:05 +0000 > +++ src/indicator-datetime.c 2011-01-26 11:50:11 +0000 > @@ -41,6 +41,7 @@ > /* DBusMenu */ > #include <libdbusmenu-gtk/menu.h> > #include <libido/idocalendarmenuitem.h> > +#include <libdbusmenu-gtk/menuitem.h> > > #include "dbus-shared.h" > > @@ -102,6 +103,13 @@ > 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" > @@ -174,6 +182,8 @@ > > G_DEFINE_TYPE (IndicatorDatetime, indicator_datetime, INDICATOR_OBJECT_TYPE); > > +static GtkSizeGroup * indicator_right_group = NULL; > + > static void > indicator_datetime_class_init (IndicatorDatetimeClass *klass) > { > @@ -1055,6 +1065,128 @@ > return g_strdup_printf(T_("%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 > + 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, > 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(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), > mi_data); > + > + return TRUE; > +} > + > static gboolean > new_calendar_item (DbusmenuMenuitem * newitem, > DbusmenuMenuitem * parent, > @@ -1081,6 +1213,16 @@ > 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 * > @@ -1120,6 +1262,8 @@ > 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); > > return GTK_MENU(self->priv->menu); > } > -- https://code.launchpad.net/~karl-qdh/ubuntu/natty/indicator-datetime/indicator-datetime.withappointments/+merge/47514 Your team ayatana-commits is subscribed to branch lp:indicator-datetime. _______________________________________________ Mailing list: https://launchpad.net/~ayatana-commits Post to : [email protected] Unsubscribe : https://launchpad.net/~ayatana-commits More help : https://help.launchpad.net/ListHelp

