aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/datetime-service.c102
-rw-r--r--src/dbus-shared.h4
-rw-r--r--src/indicator-datetime.c78
3 files changed, 184 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
#include <geoclue/geoclue-master.h>
#include <geoclue/geoclue-master-client.h>
+#include <time.h>
+#include <libecal/e-cal.h>
+#include <libical/ical.h>
+// Other users of ecal seem to also include these, not sure why they should be included by the above
+#include <libecal/e-cal-time-util.h>
+#include <libical/icaltime.h>
+
#include <oobs/oobs-timeconfig.h>
#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 <http://www.gnu.org/licenses/>.
#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);
}