Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/openmoko-today.pro
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/openmoko-today.pro	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/openmoko-today.pro	(revision 2548)
@@ -0,0 +1,20 @@
+######################################################################
+# Automatically generated by qmake (1.07a) Mon Apr 2 17:42:14 2007
+######################################################################
+
+TEMPLATE = app
+DEPENDPATH += src tests
+INCLUDEPATH += . src
+
+# Input
+HEADERS += src/today-events-area.h src/today-utils.h src/xutil.h
+SOURCES += src/today-events-area.c \
+           src/today-main.c \
+           src/today-utils.c \
+           src/xutil.c
+
+MOKOCONFIG = mokoui
+PKGCONFIG += libebook-1.2 libecal-1.2 startup-notification-1.0
+DEFINES += RSSREADER_LOCALE_DIR=\\\"/tmp/\\\"
+include ( $(OPENMOKODIR)/devel/qmake/openmoko-include.pro )
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/ChangeLog
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/ChangeLog	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/ChangeLog	(revision 2548)
@@ -0,0 +1,220 @@
+2007-06-12  Daniel Willmann <daniel@totalueberwachung.de>
+
+	* src/today-events-area.c: (init_left_hand_side): Check if icon is
+	NULL befor unref'ing (prevents segfaulting on older gtk versions)
+
+2007-06-06  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-events-area.c: (get_property), (init_left_hand_side): Add icon to
+	events area
+	* src/today-main.c: (today_launcher_button_new): Fix launchers
+
+2007-06-06  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-main.c: (today_infoline_new), (child_setup),
+	(today_launcher_clicked_cb), (create_ui):
+	Use argv array to start applications. Open the dialer with --show-missed when
+	missed call info is clicked
+
+2007-06-05  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-main.c: (today_launcher_clicked_cb), (create_ui): Update launcher
+	code to use g_spawn_async ()
+
+2007-06-01  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-main.c: (network_register_cb), (create_ui), (main): Add MokoGsmdConnection object
+
+2007-06-01  Thomas Wood  <thomas@openedhand.com>
+
+	reviewed by: <delete if not using a buddy>
+
+	* src/today-main.c: (network_register_cb), (create_ui), (main):
+
+2007-05-31  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-main.c: (today_update_date), (today_infoline_new),
+	(today_launcher_button_new): Run appropriate program when an infoline is
+	clicked
+
+2007-05-31  Thomas Wood  <thomas@openedhand.com>
+
+	* configure.ac:
+	* src/today-main.c: (today_infoline_new): Add startup-notification support
+
+2007-05-30  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-main.c: (today_infoline_new),
+	(today_launcher_button_new), (today_setup_events_area),
+	(create_ui): Use correct icons in Missed Calls/Unread Messages lines
+
+2007-05-09  Thomas Wood  <thomas@openedhand.com>
+
+	* Makefile.am:
+	* configure.ac:
+	* src/Makefile.am:
+	Fix various issues so that make distcheck works. Closes bug 534.
+
+2007-05-09  Thomas Wood  <thomas@openedhand.com>
+
+	* src/today-main.c: (today_update_date), (create_ui): Remove the clock. Closes bug 469.
+
+Fri, 30 Mar 2007 13:18:28 +0200 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-events-area.c:
+	  (today_events_area_set_events_auto): don' t g_object_unref() NULL
+	   objects.
+
+Tue, 27 Mar 2007 16:41:20 +0100 Thomas Wood
+
+	* src/today-events-area.c: (update_paging_info): Set page numbers
+	rather than number of events on pager widget
+
+Mon, 26 Mar 2007 11:12:04 +0100 Thomas Wood
+
+	* src/Makefile.am: Change binary name to openmoko-today to be more
+	consistent with other openmoko applications
+
+Thu, 22 Mar 2007 18:04:50 +0100 Dodji Sekteli
+
+	* applications/openmoko-today/src/today-events-area.c:
+	  Update the widget to show (in real time) modified
+	  events/todo items.
+
+Thu, 22 Mar 2007 15:51:59 +0000 Thomas Wood
+
+	* src/xutil.c:
+	* src/xutil.h:
+
+	Add license headers. These files were taken from matchbox-panel-2.
+
+Thu, 22 Mar 2007 15:36:29 +0000 Thomas Wood
+
+	* src/Makefile.am:
+	* src/today-main.c: (today_update_date), (today_setup_events_area),
+	(create_ui):
+	* src/xutil.c:
+	* src/xutil.h:
+
+	Add --enable-desktop option
+
+Thu, 22 Mar 2007 12:59:43 +0000 Thomas Wood
+
+	* src/today-main.c: (create_ui): Set window title to keep hrw happy
+
+Thu, 22 Mar 2007 09:51:27 +0100 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-events-area.[c|h]:
+	  Port this over the ECalView API. This allows updating the
+	  interface whenever an event or todo item is added to
+	  or deleted from e-d-s.
+	  Basically, after calling today_events_area_new(),
+	  one just have to call today_events_area_set_events_auto().
+	  The widget pulls events and tasks from e-d-s, show them,
+	  paginate them, and update itself whenever an event is modified
+	  in e-d-s. It is no more compulsory to feed the widget
+	  with today_events_area_set_events().
+	* applications/openmoko-today/src/today-main.c: change this to
+	  today_setup_events_area(): change this to use the
+	  new today_events_area_set_event_auto() entry point.
+	* applications/openmoko-today/src/today-utils.[c|]:
+	  Added today_clone_icalcomponent_list() to be able
+	  to clone list of icalcomponents, as we have to do that
+	  when using the signal driven ECalView API.
+
+Wed, 21 Mar 2007 17:34:34 +0000 Thomas Wood
+
+	* src/today-main.c: Add support for icon themes, and assign applications to
+	the remaining launchers
+
+Tue, 20 Mar 2007 11:01:20 +0000 Thomas Wood
+
+	* src/today-events-area.c: (render_event):
+	* src/today-main.c: (today_infoline_new):
+
+	Use invisible windows for GtkEventBox where appropriate.
+
+Tue, 20 Mar 2007 10:40:23 +0000 Thomas Wood
+
+	Patch by: Daniel Willmann <daniel@totalueberwachung.de>
+
+	* src/today-main.c: (today_launcher_clicked_cb): Initialise the GError
+	pointer to prevent segfault. Fixes bug 268.
+
+Mon, 19 Mar 2007 23:15:46 +0100 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-events-area.c:
+	  Do not use ECalComponent anymore, but rather
+	  the underlying icalcomponent.
+	  ECalComponent was actually useless and was
+	  just eating more memory.
+	* applications/openmoko-today/src/today-utils.c,h:
+	  ditto.
+	  Added icalcomponent_has_alarm() to detect if an
+	  icalcomponent has alarms.
+
+Mon, 19 Mar 2007 19:59:27 +0100 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-events-area.c:
+	  move utils functions into
+	  applications/openmoko-today/src/today-utils.[c|h].
+	  Get todo items as well.
+	  Render todo items, events, and alarmed event using
+	  the theme icons.
+	* applications/openmoko-today/src/today-utils.c: move util functions in
+	  here
+
+Mon, 19 Mar 2007 15:29:03 +0000 Thomas Wood
+
+	* src/today-main.c: Use MokoPixmapButton for launchers
+
+Mon, 19 Mar 2007 10:55:46 +0100 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-main.c: added vi modelines
+
+Thu, 15 Mar 2007 23:20:45 +0100 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-events-area.c,h:
+	  add a bunch a GObject properties for all the getters/setters.
+	  Use g_object_new() in the constructors.
+	  Add a today_events_area_new_from_events() for better convenience.
+	* applications/openmoko-today/src/today-main.c: use the
+	  new today_events_area_new_from_events() method.
+
+Thu, 15 Mar 2007 15:47:58 +0100 Dodji Seketeli
+
+	* applications/openmoko-today/src/today-events-area.c:
+	  today_events_area_get_nb_pages(): new function
+	  When events get added, compute the widget name accordingly.
+	  The widget name depends on wheter there are multiple event
+	  pages in the widget or not. Based on that name, the widget
+	  will use an appropriate post-it widget.
+
+Thu, 15 Mar 2007 13:43:47 +0100 Dodji Seketeli
+
+	* src/today-events-area.c: don't forget to emit the signal
+	  events-added, when edited.
+
+Thu, 15 Mar 2007 12:44:51 +0100 Dodji Seketeli
+
+	* src/today-events-area.c,h: expose signals
+	  event-added, event-selected, page-switched.
+	  Make the internals use these.
+	  added today_events_area_switch_to_prev_page() and
+	  today_events_area_switch_to_next_page().
+
+
+Tue, 13 Mar 2007 17:53:33 +0100 Dodji Seketeli <dodji@o-hand.com>
+
+	* autogen.sh: remove my specific --prefix
+
+Tue, 13 Mar 2007 17:31:00 +0100 Dodji Seketeli <dodji@o-hand.com>
+
+	* src/today-events-area.c,h: initial attempt at coding an
+	EventArea widget that takes a list of ECalComponent representing
+	a list of event and showing these events "page by page".
+	You can select events, and cycle through the event pages.
+	* src/today-main.c: use the new EventArea widget for testing
+	For now,the code loads all the events from the calendar, not only
+	those of today. This is just to test the paging code.
+	* tests/events-area-test.c: a small test program for the widget
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-main.c
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-main.c	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-main.c	(revision 2548)
@@ -0,0 +1,384 @@
+/* vi: set sw=2: */
+/*
+ *  Today - At a glance view of date, time, calender events, todo items and
+ *  other images.
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by OpenedHand Ltd <info@openedhand.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <unistd.h>
+#include <libmokoui/moko-ui.h>
+
+#define SN_API_NOT_YET_FROZEN 1
+#include <libsn/sn-launcher.h>
+#include <gdk/gdkx.h>
+
+#include <libmokogsmd/moko-gsmd-connection.h>
+#include "today-events-area.h"
+#include "today-utils.h"
+#include "xutil.h"
+
+#define LOG_ERROR \
+g_warning ("Got error '%s', code '%d'", \
+           error->message, error->code);
+
+#define FREE_ERROR g_error_free (error) ; error = NULL ;
+
+
+/*** functions ***/
+static void today_launcher_clicked_cb (GtkWidget *widget, gchar **argv);
+
+
+/*** configuration options ***/
+/* default to false, although this might want to be reversed in the future */
+static gboolean enable_desktop = FALSE;
+
+static GOptionEntry option_entries[] =
+{
+  { "enable-desktop", 'd', 0, G_OPTION_ARG_NONE,  &enable_desktop, "Set as desktop window", NULL},
+  { NULL }
+};
+
+
+/**
+ * today_update_date ()
+ *
+ * Update the specified GtkLabel with the current date
+ */
+static void
+today_update_date (GtkLabel * label)
+{
+  time_t t;
+  struct tm *tmp;
+  gchar date_str[64];
+
+  t = time (NULL);
+  tmp = localtime (&t);
+
+  if (tmp == NULL)
+  {
+    // error = could not get localtime
+    return;
+  }
+
+  /* TODO: use something nicer from the locale here */
+  strftime (date_str, sizeof (date_str), "<big>%a %d/%b/%Y</big>", tmp);
+  gtk_label_set_markup (label, date_str);
+
+}
+
+static void
+network_register_cb (MokoGsmdConnection* self, int type, int lac, int cell, GtkLabel *label)
+{
+  // TODO: get operator name somehow?
+  // update label with operator name
+  //gtk_label_set_markup (label, "<span size=\"x-large\">%s</span>", operator_name);
+}
+
+/* information lines */
+
+static void
+today_infoline_clicked_cb (GtkWidget *widget, GdkEventButton *button, gchar *data)
+{
+  gchar *argv[1];
+  argv[0] = data;
+  today_launcher_clicked_cb (widget, argv);
+}
+
+/**
+ * today_infoline_new:
+ * @stock_id: name of the stock icon to use
+ * @message: string containing the message
+ *
+ * Utility function to create new info lines
+ *
+ * Return value: The parent widget of the new widgets
+ */
+
+static GtkWidget *
+today_infoline_new (gchar **argv, gchar * message)
+{
+  GtkWidget *eventbox, *hbox, *icon, *label;
+  GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
+  GdkPixbuf *pb;
+
+  eventbox = gtk_event_box_new ();
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (eventbox), FALSE);
+  gtk_container_set_border_width (GTK_CONTAINER (eventbox), 6);
+
+  gtk_widget_add_events (eventbox, GDK_BUTTON_PRESS_MASK);
+
+  g_signal_connect (G_OBJECT (eventbox), "button-press-event", (GCallback) today_infoline_clicked_cb, argv);
+
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (eventbox), hbox);
+
+  if (gtk_icon_theme_has_icon (icon_theme, argv[0]))
+  {
+    pb = gtk_icon_theme_load_icon (icon_theme, argv[0], 32, GTK_ICON_LOOKUP_NO_SVG, NULL);
+  }
+  else
+  {
+    pb = gtk_icon_theme_load_icon (icon_theme, GTK_STOCK_MISSING_IMAGE, 32, GTK_ICON_LOOKUP_NO_SVG, NULL);
+  }
+  icon = gtk_image_new_from_pixbuf (pb);
+  g_object_unref (pb);
+  gtk_misc_set_alignment (GTK_MISC (icon), 0, 0);
+  gtk_widget_show (icon) ;
+  gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
+
+  // FIXME: get this from the style... somehow
+  gtk_widget_set_size_request (icon, 51, -1);
+
+
+  label = gtk_label_new (message);
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+  return eventbox;
+}
+
+/* launcher buttons */
+
+/**
+ * callback for luncher buttons
+ */
+
+static void
+child_setup (gpointer user_data)
+{
+  if (user_data) {
+    sn_launcher_context_setup_child_process (user_data);
+  }
+}
+
+static void
+today_launcher_clicked_cb (GtkWidget *widget, gchar **argv)
+{
+  /* The following code is a modified version of code from launcher-util.c in
+   * matchbox-desktop-2 and is copyright (C) 2007 OpenedHand Ltd, made available
+   * under the GNU General Public License.
+   */
+  SnLauncherContext *context;
+  SnDisplay *sn_dpy;
+  Display *display;
+  int screen;
+  GError *error = NULL;
+
+  display = gdk_x11_display_get_xdisplay (gtk_widget_get_display (widget));
+  sn_dpy = sn_display_new (display, NULL, NULL);
+
+  screen = gdk_screen_get_number (gtk_widget_get_screen (widget));
+  context = sn_launcher_context_new (sn_dpy, screen);
+  sn_display_unref (sn_dpy);
+
+  /* sn_launcher_context_set_name (context, data->name); */
+  sn_launcher_context_set_binary_name (context, argv[0]);
+  sn_launcher_context_initiate (context, "openmoko-today", argv[0], CurrentTime);
+
+  if (!g_spawn_async (NULL, argv, NULL,
+                            G_SPAWN_SEARCH_PATH, child_setup, context,
+                            NULL, &error))
+  {
+    g_warning ("Cannot launch %s: %s", argv[0], error->message);
+    g_error_free (error);
+    sn_launcher_context_complete (context);
+  }
+  sn_launcher_context_unref (context);
+}
+
+/**
+ * today_launcher_button_new:
+ * @exec: command to execute when the button is clicked
+ *
+ * Utility function to create new launcher buttons
+ *
+ * Return value: The parent widget of the new widgets
+ */
+static GtkWidget *
+today_launcher_button_new (gchar *exec)
+{
+  GtkWidget *button = moko_pixmap_button_new ();
+  GdkPixbuf *pb;
+  GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
+  gchar **argv;
+
+  if (gtk_icon_theme_has_icon (icon_theme, exec))
+  {
+    pb = gtk_icon_theme_load_icon (icon_theme, exec, 48, GTK_ICON_LOOKUP_NO_SVG, NULL);
+  }
+  else
+  {
+    pb = gtk_icon_theme_load_icon (icon_theme, GTK_STOCK_MISSING_IMAGE, 48, GTK_ICON_LOOKUP_NO_SVG, NULL);
+  }
+
+  moko_pixmap_button_set_finger_toolbox_btn_center_image_pixbuf (
+      MOKO_PIXMAP_BUTTON (button), pb);
+  g_object_unref (pb);
+  gtk_widget_set_name (button, "mokofingertoolbox-toolbutton");
+
+  /* FIXME: this is less than ideal */
+  argv = g_malloc0 (2);
+  argv[0] = exec;
+  g_signal_connect (G_OBJECT (button),
+                    "clicked",
+                    G_CALLBACK (today_launcher_clicked_cb),
+                    argv);
+  return button;
+}
+
+/**
+ * today_setup_events_area:
+ *
+ * Return value: The widget to use as the events area
+ *
+ */
+static GtkWidget *
+today_setup_events_area (const gchar *stock_id)
+{
+  GtkWidget        *events_area;
+  /*GList            *events;
+
+  events = today_get_today_events () ;
+  events_area = today_events_area_new_with_events (events) ;
+  */
+  events_area = today_events_area_new () ;
+  today_events_area_set_events_auto (TODAY_EVENTS_AREA (events_area)) ;
+
+  return events_area;
+}
+
+static void
+create_ui ()
+{
+  GtkWidget *window, *vbox;
+  GtkWidget *date;
+  GtkWidget *message;
+
+  GtkWidget *alignment;
+  GtkWidget *infoline;
+  GtkWidget *button_box;
+
+  gchar *missed_calls_cmd[] = { "openmoko-dialer", "--show-missed" };
+  gchar *messages_inbox_cmd[] = { "openmoko-messages" };
+
+  /* main window */
+  window = moko_window_new ();
+  gtk_widget_set_name (window, "today-application-window");
+  gtk_window_set_title (GTK_WINDOW (window), "Today");
+
+  if (enable_desktop)
+  {
+    gint x, y, w, h;
+    gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DESKTOP);
+    gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
+    if (x_get_workarea (&x, &y, &w, &h))
+    {
+      gtk_window_set_default_size (GTK_WINDOW (window), w, h);
+      gtk_window_move (GTK_WINDOW (window), x, y);
+    }
+  }
+
+  vbox = gtk_vbox_new (FALSE, 12);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  /* date */
+  alignment = gtk_alignment_new (1, 0, 0, 0);
+  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 12);
+  date = gtk_label_new (NULL);
+  gtk_container_add (GTK_CONTAINER (alignment), date);
+  gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
+  today_update_date (GTK_LABEL (date));
+  g_timeout_add (60 * 60 * 1000, (GSourceFunc) today_update_date, date);
+
+  /* main message */
+  alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
+  message = gtk_label_new (NULL);
+  gtk_label_set_markup (GTK_LABEL (message),
+                        "<span size=\"x-large\">Welcome to OpenMoko</span>");
+  gtk_container_add (GTK_CONTAINER (alignment), message);
+  gtk_box_pack_start (GTK_BOX (vbox), alignment, TRUE, FALSE, 0);
+
+
+  /* unread messages */
+  infoline = today_infoline_new (messages_inbox_cmd, "Unread Messages");
+  gtk_box_pack_start (GTK_BOX (vbox), infoline, FALSE, FALSE, 0);
+
+  /* missed calls */
+  infoline = today_infoline_new (missed_calls_cmd, "Missed Calls");
+  gtk_box_pack_start (GTK_BOX (vbox), infoline, FALSE, FALSE, 0);
+
+  /* upcoming events */
+  infoline = today_setup_events_area (GTK_STOCK_NO);
+  gtk_box_pack_start (GTK_BOX (vbox), infoline, FALSE, FALSE, 0);
+
+  /* shurtcut buttons */
+  button_box = gtk_hbutton_box_new ();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (button_box),
+                             GTK_BUTTONBOX_SPREAD);
+  gtk_box_pack_start (GTK_BOX (vbox), button_box, FALSE, FALSE, 0);
+
+  gtk_container_add (GTK_CONTAINER (button_box),
+                     today_launcher_button_new ("openmoko-dialer"));
+  gtk_container_add (GTK_CONTAINER (button_box),
+                     today_launcher_button_new ("contacts"));
+  gtk_container_add (GTK_CONTAINER (button_box),
+                     today_launcher_button_new ("openmoko-messages"));
+  gtk_container_add (GTK_CONTAINER (button_box),
+                     today_launcher_button_new ("openmoko-gps"));
+  gtk_container_add (GTK_CONTAINER (button_box),
+                     today_launcher_button_new ("dates"));
+
+  /* signals */
+  g_signal_connect (G_OBJECT (window), "delete-event",
+                    (GCallback) gtk_main_quit, NULL);
+
+  /* set up connection management */
+  MokoGsmdConnection *connection = moko_gsmd_connection_new ();
+  g_signal_connect (G_OBJECT (connection), "network-registration", (GCallback) network_register_cb, message);
+
+
+  gtk_widget_show_all (window);
+
+}
+
+int
+main (int argc, char **argv)
+{
+  GError *error = NULL;
+  GOptionContext *context;
+
+  gtk_init (&argc, &argv);
+
+  /* parse command line options */
+  context = g_option_context_new ("- OpenMoko Today Application");
+  g_option_context_add_main_entries (context, option_entries, NULL);
+  g_option_context_add_group (context, gtk_get_option_group (TRUE));
+  g_option_context_parse (context, &argc, &argv, &error);
+
+  /* create the UI and run */
+  create_ui ();
+
+
+  gtk_main ();
+
+  return 0;
+}
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-utils.h
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-utils.h	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-utils.h	(revision 2548)
@@ -0,0 +1,38 @@
+/* vi: set sw=2: */
+/*
+ *  Today - At a glance view of date, time, calender events, todo items and
+ *  other images.
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by OpenedHand Ltd <info@openedhand.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef __TODAY_UTILS_H__
+#define  __TODAY_UTILS_H__
+
+#include <glib.h>
+#include <libical/icalcomponent.h>
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-time-util.h>
+
+GList* today_get_today_events () ;
+void e_cal_component_list_free (GList * list) ;
+gchar* icaltime_to_pretty_string (const icaltimetype *timetype) ;
+gboolean icalcomponent_has_alarm (icalcomponent *a_icalcomp) ;
+GList* today_clone_icalcomponent_list (const GList *a_list) ;
+#endif /*__TODAY_UTILS_H__*/
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/xutil.c
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/xutil.c	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/xutil.c	(revision 2548)
@@ -0,0 +1,70 @@
+/* 
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+char *
+x_strerror (int code)
+{
+#define BUFFER_SIZE 255
+  char *s;
+
+  s = g_malloc (BUFFER_SIZE);
+
+  XGetErrorText (GDK_DISPLAY (), code, s, BUFFER_SIZE);
+
+  return s;
+}
+
+
+gboolean
+x_get_workarea (int *x, int *y, int *w, int *h)
+{
+  Atom real_type;
+  int result, xres, real_format;
+  unsigned long items_read, items_left;
+  long *coords;
+
+  Atom workarea_atom = XInternAtom (GDK_DISPLAY (), "_NET_WORKAREA", False);
+  
+  gdk_error_trap_push ();
+  result = XGetWindowProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
+                               workarea_atom, 0L, 4L, False,
+                               XA_CARDINAL, &real_type, &real_format,
+                               &items_read, &items_left,
+                               (unsigned char **) (void*)&coords);
+  if ((xres = gdk_error_trap_pop ()) != 0) {
+    char *s = x_strerror (xres);
+    g_warning ("Cannot get property: %s", s);
+    g_free (s);
+    return FALSE;
+  }
+
+  if (result == Success && items_read) {
+    *x = coords[0];
+    *y = coords[1];
+    *w = coords[2];
+    *h = coords[3];
+    XFree(coords);
+    return TRUE;
+  }
+  return FALSE;
+}
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/Makefile.am
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/Makefile.am	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/Makefile.am	(revision 2548)
@@ -0,0 +1,18 @@
+INCLUDES = 						\
+	-I$(top_srcdir)
+
+AM_CPPFLAGS           =-DPKGDATADIR=\"$(pkgdatadir)\" \
+-DDATADIR=\""$(datadir)"\"
+
+AM_CFLAGS             = -Wall -pedantic -std=c99 @TODAY_CFLAGS@
+
+bin_PROGRAMS          = openmoko-today
+
+openmoko_today_SOURCES         = today-main.c \
+today-events-area.h today-events-area.c \
+today-utils.h today-utils.c xutil.c xutil.h
+
+openmoko_today_LDADD          = @TODAY_LIBS@
+
+MAINTAINERCLEANFILES  = config.h.in Makefile.in
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-events-area.c
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-events-area.c	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-events-area.c	(revision 2548)
@@ -0,0 +1,1403 @@
+/* vi:set sw=2: */
+
+/*
+ *  Today - At a glance view of date, time, calender events, todo items and
+ *  other images.
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by OpenedHand Ltd <info@openedhand.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <string.h>
+/*#include <libecal/e-cal-time-util.h>*/
+#include <libecal/e-cal-view.h>
+#include <libical/icalcomponent.h>
+#include <gtk/gtk.h>
+#include "today-utils.h"
+#include "today-events-area.h"
+#include <math.h>
+
+
+struct _TodayEventsAreaPrivate {
+  GList *events ;
+  GtkWidget *left ;
+  GtkWidget *left_event_box ;
+  GtkWidget *paging_info ;
+  GtkWidget *right ;
+
+  GList *cur_event ;
+  GList *page_start ;
+  int page_start_index ;
+  int cur_event_index ;
+  int max_visible_events ;
+  int nb_events ;
+  ECalView *events_view ;
+  ECalView *tasks_view ;
+  ECal *events_ecal ;
+  ECal *tasks_ecal ;
+};
+
+enum TodayEventsAreaSignals
+{
+  EVENTS_ADDED_SIGNAL,
+  EVENT_SELECTED_SIGNAL,
+  PAGE_SWITCHED_SIGNAL,
+  LAST_SIGNAL
+};
+
+enum TodayEventsAreaProps
+{
+  EVENTS_PROP=1,
+  NB_EVENTS_PROP,
+  NB_PAGES_PROP,
+  CUR_EVENT_PROP,
+  CUR_EVENT_INDEX_PROP,
+  MAX_VISIBLE_EVENTS_PROP
+};
+
+static guint signals[LAST_SIGNAL] ;
+
+static void     today_events_area_finalize  (GObject *a_obj);
+static void     today_events_area_init      (TodayEventsArea *a_this);
+static void     clear_right_hand_side       (TodayEventsArea *a_this);
+static void     init_right_hand_side        (TodayEventsArea *a_this);
+static void     clear_left_hand_side        (TodayEventsArea *a_this);
+static void     init_left_hand_side         (TodayEventsArea *a_this);
+static void     reinit_area                 (TodayEventsArea *a_this) ;
+static int      get_nb_events_real          (TodayEventsArea *a_this) ;
+static gboolean update_paging_info          (TodayEventsArea *a_this) ;
+static GList*   find_event                  (TodayEventsArea *a_this,
+                                             const gchar *a_uid) ;
+static GList*   find_event_from_icalcomp    (TodayEventsArea *a_this,
+                                             const icalcomponent *a_comp) ;
+static GList*   select_event                (TodayEventsArea *a_this,
+                                             GList *a_event) ;
+static void     render_event                (TodayEventsArea *a_this,
+                                             GList *a_event) ;
+static void     render_events_page          (TodayEventsArea *a_this,
+                                             GList *a_from) ;
+static gboolean is_event_visible            (TodayEventsArea *a_this,
+                                             GList *a_event) ;
+static void     render_events_page_auto     (TodayEventsArea *a_this) ;
+static gboolean remove_event                (TodayEventsArea *a_this,
+                                             GList *a_event) ;
+static void     set_events_view             (TodayEventsArea *a_this,
+                                             ECalView *a_view) ;
+static void     event_selected_signal       (TodayEventsArea *a_this,
+                                             guint a_index) ;
+static void     events_added_signal       (TodayEventsArea *a_this,
+                                           GList *a_index) ;
+static void     on_objects_added_cb       (ECalView *a_view,
+                                           GList *a_objects,
+                                           TodayEventsArea *a_this) ;
+static void     on_objects_removed_cb     (ECalView *a_view,
+                                           GList *a_uids,
+                                           TodayEventsArea *a_this) ;
+static void     on_objects_modified_cb    (ECalView *a_view,
+                                           GList *a_objects,
+                                           TodayEventsArea *a_events) ;
+static void     get_property (GObject *a_this, guint a_prop_id,
+                              GValue *a_val, GParamSpec *a_pspec) ;
+static void     set_property (GObject *a_this, guint a_prop_id,
+                              const GValue *a_value, GParamSpec *a_pspec) ;
+
+G_DEFINE_TYPE (TodayEventsArea, today_events_area, GTK_TYPE_TABLE)
+
+static void
+today_events_area_class_init (TodayEventsAreaClass *a_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (a_class);
+  object_class->finalize = today_events_area_finalize;
+  object_class->get_property = get_property ;
+  object_class->set_property = set_property ;
+
+  g_type_class_add_private (object_class, sizeof (TodayEventsAreaPrivate));
+
+  a_class->event_selected = event_selected_signal ;
+  a_class->events_added = events_added_signal ;
+
+  g_object_class_install_property
+                    (object_class,
+                     EVENTS_PROP,
+                     g_param_spec_pointer ("events",
+                                           "events",
+                                           "a GList of calendar events"
+                                            ", instances of ECalComponent",
+                                           G_PARAM_READWRITE));
+  g_object_class_install_property
+                          (object_class,
+                           NB_EVENTS_PROP,
+                           g_param_spec_uint ("nb-events",
+                                              "nb-events",
+                                              "Number of events set",
+                                              0, G_MAXUINT, 0,
+                                              G_PARAM_READABLE)) ;
+  g_object_class_install_property
+                          (object_class,
+                           NB_PAGES_PROP,
+                           g_param_spec_uint ("nb-event-pages",
+                                              "nb-event-pages",
+                                              "Number of event pages",
+                                              0, G_MAXUINT, 0,
+                                              G_PARAM_READABLE)) ;
+  g_object_class_install_property
+                          (object_class,
+                           CUR_EVENT_PROP,
+                           g_param_spec_pointer ("cur-event",
+                                                 "cur-event",
+                                                 "Currently selected event",
+                                                 G_PARAM_READABLE)) ;
+  g_object_class_install_property
+                    (object_class,
+                     CUR_EVENT_INDEX_PROP,
+                     g_param_spec_uint ("cur-event-index",
+                                        "cur-event-index",
+                                        "The index of the currently "
+                                         "selected event",
+                                         0, G_MAXUINT, 0,
+                                        G_PARAM_READABLE)) ;
+  g_object_class_install_property
+                          (object_class,
+                           MAX_VISIBLE_EVENTS_PROP,
+                           g_param_spec_uint ("max-visible-events",
+                                              "max-visible-events",
+                                              "The max number of events in "
+                                              "a page",
+                                              0, G_MAXUINT, 0,
+                                              G_PARAM_READWRITE)) ;
+
+  signals[EVENTS_ADDED_SIGNAL] =
+    g_signal_new ("event-added",
+                  TODAY_TYPE_EVENTS_AREA,
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (TodayEventsAreaClass, events_added),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__POINTER,
+                  G_TYPE_NONE,
+                  1, G_TYPE_POINTER) ;
+
+  signals[EVENT_SELECTED_SIGNAL] =
+    g_signal_new ("event-selected",
+                   TODAY_TYPE_EVENTS_AREA,
+                   G_SIGNAL_RUN_FIRST,
+                   G_STRUCT_OFFSET (TodayEventsAreaClass, event_selected),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__UINT,
+                   G_TYPE_NONE,
+                   1, G_TYPE_UINT) ;
+
+  signals[PAGE_SWITCHED_SIGNAL] =
+    g_signal_new ("page-switched",
+                  TODAY_TYPE_EVENTS_AREA,
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (TodayEventsAreaClass, page_switched),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__UINT,
+                  G_TYPE_NONE,
+                  1, G_TYPE_UINT) ;
+}
+
+static void
+today_events_area_init (TodayEventsArea *a_this)
+{
+  g_return_if_fail (GTK_IS_TABLE (a_this)) ;
+
+  a_this->priv = G_TYPE_INSTANCE_GET_PRIVATE (a_this,
+                                              TODAY_TYPE_EVENTS_AREA,
+                                              TodayEventsAreaPrivate);
+
+  gtk_table_resize (GTK_TABLE (a_this), 1, 2) ;
+  reinit_area (a_this) ;
+}
+
+static void
+today_events_area_finalize (GObject *a_obj)
+{
+  TodayEventsArea *self = TODAY_EVENTS_AREA (a_obj) ;
+  g_return_if_fail (self && self->priv) ;
+
+  if (self->priv->events)
+  {
+    e_cal_free_object_list (self->priv->events) ;
+    self->priv->events = NULL ;
+  }
+  if (self->priv->events_view)
+  {
+    g_object_unref (G_OBJECT (self->priv->events_view)) ;
+    self->priv->events_view = NULL;
+  }
+  if (self->priv->tasks_view)
+  {
+    g_object_unref (G_OBJECT (self->priv->tasks_view)) ;
+    self->priv->tasks_view = NULL;
+  }
+  if (self->priv->events_ecal)
+  {
+    g_object_unref (G_OBJECT (self->priv->events_ecal)) ;
+    self->priv->events_ecal = NULL;
+  }
+  if (self->priv->tasks_ecal)
+  {
+    g_object_unref (G_OBJECT (self->priv->tasks_ecal)) ;
+    self->priv->tasks_ecal = NULL ;
+  }
+  self->priv->cur_event = NULL ;
+  self->priv->cur_event_index = 0 ;
+  self->priv->page_start = NULL ;
+  self->priv->max_visible_events = 0 ;
+
+  self->priv = NULL ;
+
+  /*chain up*/
+  (*G_OBJECT_CLASS (today_events_area_parent_class)->finalize) (a_obj);
+}
+/********************
+ * <signal callbacks>
+ ********************/
+gboolean
+on_button_pressed_in_left_cb (GtkWidget *a_event_box,
+                              GdkEventButton *a_button,
+                              TodayEventsArea *a_area)
+{
+    g_return_val_if_fail (a_area && TODAY_IS_EVENTS_AREA (a_area), FALSE) ;
+    if (a_event_box) {/*keep compiler happy*/}
+
+    if (a_button->type == GDK_BUTTON_PRESS)
+      today_events_area_switch_to_next_page (a_area) ;
+
+    return FALSE ;
+}
+
+gboolean
+on_button_pressed_in_infoline_cb (GtkWidget *a_event_box,
+                                  GdkEventButton *a_button,
+                                  TodayEventsArea *a_area)
+{
+  int event_index = 0 ;
+
+  g_return_val_if_fail (a_area && TODAY_IS_EVENTS_AREA (a_area), FALSE) ;
+
+  if (a_button->type != GDK_BUTTON_PRESS)
+    return FALSE ;
+
+  event_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (a_event_box),
+                                                    "event-index")) ;
+  g_return_val_if_fail (event_index >= 0, FALSE) ;
+  g_signal_emit (G_OBJECT (a_area),
+                 signals[EVENT_SELECTED_SIGNAL], 0, event_index) ;
+
+  return FALSE;
+}
+
+/********************
+ * </signal callbacks>
+ ********************/
+
+/**********************
+ * <private api>
+ **********************/
+
+static void
+event_selected_signal (TodayEventsArea *a_this,
+                       guint a_index)
+{
+  GList *elem ;
+
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv) ;
+
+  elem = g_list_nth (a_this->priv->events, a_index) ;
+  select_event (a_this, elem) ;
+}
+
+static void
+events_added_signal (TodayEventsArea *a_this,
+                     GList *a_events)
+{
+  if (a_events) {/*keep compiler happy*/}
+
+
+  if (today_events_area_get_nb_pages (a_this) > 1)
+  {
+     gtk_widget_set_name (a_this->priv->left_event_box,
+                          "today-events-area-postit-multi");
+  }
+  else
+  {
+     gtk_widget_set_name (a_this->priv->left_event_box,
+                          "today-events-area-postit-single");
+  }
+  /*
+   * reload the styles to render the left hand side correctly
+   * so that it matches the new widget name
+   */
+  gtk_widget_reset_rc_styles (GTK_WIDGET (a_this)) ;
+}
+
+static void
+on_objects_added_cb (ECalView *a_view,
+                     GList *a_objects,
+                     TodayEventsArea *a_this)
+{
+  if (a_view) {/*compiler is happy*/}
+  today_events_area_append_events (a_this, a_objects) ;
+  gtk_widget_queue_draw (GTK_WIDGET (a_this)) ;
+}
+
+static void
+on_objects_removed_cb (ECalView *a_view,
+                       GList *a_uids,
+                       TodayEventsArea *a_this)
+{
+  GList *cur ;
+
+  if (a_view) {/*compiler is happy*/}
+  for (cur = a_uids ; cur ; cur = cur->next)
+    today_events_area_remove_event (a_this, cur->data) ;
+  gtk_widget_queue_draw (GTK_WIDGET (a_this)) ;
+}
+
+static void
+on_objects_modified_cb (ECalView *a_view,
+                        GList *a_objects,
+                        TodayEventsArea *a_this)
+{
+  GList *cur=NULL ;
+
+  if (a_view) {/*happy compiler*/}
+
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+
+  g_debug ("in %s:%d", __func__, __LINE__) ;
+  for (cur = a_objects ; cur ; cur = cur->next)
+  {
+    GList *event=NULL ;
+    if (!cur->data)
+      continue ;
+    event = find_event_from_icalcomp (a_this, cur->data) ;
+    if (event && event->data && icalcomponent_isa_component (event->data))
+    {
+      icalcomponent_free (event->data) ;
+      event->data = icalcomponent_new_clone (cur->data) ;
+    }
+    g_debug ("in %s:%d", __func__, __LINE__) ;
+    if (event && is_event_visible (a_this, event))
+    {
+      g_debug ("in %s:%d", __func__, __LINE__) ;
+      render_events_page (a_this, a_this->priv->page_start) ;
+    }
+  }
+  gtk_widget_queue_draw (GTK_WIDGET (a_this)) ;
+}
+
+static void
+get_property (GObject *a_this, guint a_prop_id,
+              GValue *a_val, GParamSpec *a_pspec)
+{
+  TodayEventsArea *area ;
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_val && a_pspec) ;
+
+  area = TODAY_EVENTS_AREA (a_this) ;
+
+  switch (a_prop_id)
+  {
+    case EVENTS_PROP:
+      g_value_set_pointer (a_val, today_events_area_get_events (area)) ;
+      break ;
+    case NB_EVENTS_PROP:
+      g_value_set_uint (a_val, today_events_area_get_nb_events (area)) ;
+      break ;
+    case NB_PAGES_PROP:
+      g_value_set_uint (a_val, today_events_area_get_nb_pages (area)) ;
+      break ;
+    case CUR_EVENT_PROP:
+      g_value_set_pointer (a_val, today_events_area_get_cur_event (area)) ;
+      break ;
+    case CUR_EVENT_INDEX_PROP:
+      g_value_set_uint (a_val, today_events_area_get_cur_event_index (area)) ;
+      break ;
+    case MAX_VISIBLE_EVENTS_PROP:
+      g_value_set_uint (a_val, today_events_area_get_max_visible_events (area));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (a_this, a_prop_id, a_pspec) ;
+      break ;
+  }
+}
+
+static void
+set_property (GObject *a_this, guint a_prop_id,
+              const GValue *a_val, GParamSpec *a_pspec)
+{
+  TodayEventsArea * area ;
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_val && a_pspec) ;
+
+  area = TODAY_EVENTS_AREA (a_this) ;
+
+  switch (a_prop_id)
+  {
+    case EVENTS_PROP:
+      today_events_area_set_events (area, g_value_get_pointer (a_val)) ;
+      break ;
+    case MAX_VISIBLE_EVENTS_PROP:
+      today_events_area_set_max_visible_events (area, g_value_get_uint (a_val));
+      break ;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (a_this, a_prop_id, a_pspec) ;
+      break ;
+  }
+}
+
+static void
+clear_right_hand_side (TodayEventsArea *a_this)
+{
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv) ;
+
+  if (a_this->priv->right)
+  {
+    gtk_widget_destroy (a_this->priv->right) ;
+    a_this->priv->right = NULL ;
+  }
+}
+
+static void
+init_right_hand_side (TodayEventsArea *a_this)
+{
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv) ;
+
+  if (a_this->priv->right)
+    clear_right_hand_side (a_this) ;
+
+  a_this->priv->right = gtk_vbox_new (TRUE, 0) ;
+  gtk_widget_show (a_this->priv->right) ;
+  gtk_table_attach_defaults (GTK_TABLE (a_this),
+                             a_this->priv->right,
+                             1, 2, 0, 1) ;
+}
+
+static void
+clear_left_hand_side (TodayEventsArea *a_this)
+{
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv) ;
+
+  if (a_this->priv->left)
+  {
+    gtk_widget_destroy (a_this->priv->left) ;
+    a_this->priv->left = NULL ;
+    a_this->priv->left_event_box = NULL ;
+    a_this->priv->paging_info = NULL ;
+  }
+}
+
+static void
+init_left_hand_side (TodayEventsArea *a_this)
+{
+  GtkWidget *vbox, *image;
+  GdkPixbuf *icon;
+
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv) ;
+
+  if (a_this->priv->left)
+    clear_left_hand_side (a_this) ;
+
+  a_this->priv->left_event_box = gtk_event_box_new ();
+
+  gtk_widget_set_name (a_this->priv->left_event_box,
+                       "today-events-area-postit-single");
+
+  // FIXME: get this size from the style... somehow
+  gtk_widget_set_size_request (a_this->priv->left_event_box, 51, 131);
+
+  gtk_widget_add_events (a_this->priv->left_event_box,
+                         GDK_BUTTON_PRESS_MASK) ;
+  g_signal_connect (G_OBJECT (a_this->priv->left_event_box),
+                    "button-press-event",
+                    G_CALLBACK (on_button_pressed_in_left_cb),
+                    a_this) ;
+  a_this->priv->paging_info = gtk_label_new ("0/0") ;
+
+  icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "openmoko-sketchbook", 32, 0, NULL);
+  image = gtk_image_new_from_pixbuf (icon);
+  if (icon)
+    g_object_unref (icon);
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), a_this->priv->paging_info, FALSE, FALSE, 6);
+
+
+  gtk_container_add (GTK_CONTAINER (a_this->priv->left_event_box), vbox);
+
+  a_this->priv->left = gtk_vbox_new (TRUE, 0) ;
+  gtk_box_pack_start (GTK_BOX (a_this->priv->left),
+                      a_this->priv->left_event_box,
+                      FALSE, FALSE, 0) ;
+
+  gtk_table_attach (GTK_TABLE (a_this),
+                    a_this->priv->left,
+                    0, 1, 0, 1,
+                    GTK_FILL, GTK_FILL, 0, 0) ;
+  gtk_widget_show_all (a_this->priv->left) ;
+}
+
+static void
+reinit_area (TodayEventsArea *a_this)
+{
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+
+  init_left_hand_side (a_this) ;
+  init_right_hand_side (a_this) ;
+}
+
+static int
+get_nb_events_real (TodayEventsArea *a_this)
+{
+  GList *cur = NULL ;
+  int result = 0 ;
+
+  g_return_val_if_fail (a_this
+                        && TODAY_IS_EVENTS_AREA (a_this)
+                        && a_this->priv,
+                        -1) ;
+
+  for (cur = a_this->priv->events ; cur ; cur = cur->next)
+    ++result ;
+  return result ;
+}
+
+static gboolean
+update_paging_info (TodayEventsArea *a_this)
+{
+  gchar *str ;
+
+  g_return_val_if_fail (a_this
+                        && TODAY_IS_EVENTS_AREA (a_this)
+                        && a_this->priv,
+                        FALSE) ;
+
+  g_return_val_if_fail (a_this->priv->paging_info, FALSE) ;
+  g_return_val_if_fail (a_this->priv->cur_event, FALSE) ;
+  g_return_val_if_fail (a_this->priv->events, FALSE) ;
+
+  /* Set the page label to display the current and number of pages */
+
+  gdouble num = a_this->priv->max_visible_events;
+  int num_pages = ceil (a_this->priv->nb_events / num);
+  int curr_page = a_this->priv->cur_event_index / num + 1;
+
+  str = g_strdup_printf ("%d/%d",
+                         curr_page,
+                          num_pages) ;
+
+  gtk_label_set_text (GTK_LABEL (a_this->priv->paging_info), str) ;
+  g_free (str) ;
+
+  return TRUE ;
+}
+
+static GList*
+find_event (TodayEventsArea *a_this,
+            const gchar *a_uid)
+{
+  GList *cur=NULL ;
+  int uid_len=0 ;
+
+  g_return_val_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this), NULL) ;
+  g_return_val_if_fail (a_this->priv, NULL) ;
+  g_return_val_if_fail (a_uid, NULL) ;
+
+  uid_len = strlen (a_uid) ;
+  for (cur = a_this->priv->events ; cur ; cur = cur->next)
+  {
+    if (!cur->data || !icalcomponent_isa_component (cur->data))
+      continue ;
+    if (!strncmp (a_uid, icalcomponent_get_uid (cur->data), uid_len))
+    {
+      return cur ;
+    }
+  }
+  return NULL ;
+}
+
+static GList*
+find_event_from_icalcomp (TodayEventsArea *a_this,
+                          const icalcomponent *a_comp)
+{
+  g_return_val_if_fail (a_comp, NULL) ;
+  g_return_val_if_fail (icalcomponent_isa_component ((icalcomponent*)a_comp),
+                        NULL) ;
+
+  return find_event (a_this, icalcomponent_get_uid ((icalcomponent*)a_comp)) ;
+}
+
+static GList*
+select_event (TodayEventsArea *a_this,
+              GList *a_event)
+{
+  int event_index = 0 ;
+
+  g_return_val_if_fail (a_this
+                        && TODAY_IS_EVENTS_AREA (a_this)
+                        && a_this->priv,
+                        FALSE) ;
+
+  if (!a_this->priv->events || !a_event)
+  {
+    return NULL ;
+  }
+  event_index = g_list_position (a_this->priv->events,
+                                 a_event) ;
+  g_return_val_if_fail (event_index >= 0, NULL) ;
+
+  a_this->priv->cur_event = a_event ;
+  a_this->priv->cur_event_index = event_index ;
+
+  /*
+   * if the index of the current event is out of the range of the
+   * currently visible page, move the range of the page and re-render the
+   * page so that the current event becomes visible
+   */
+  if ((a_this->priv->page_start_index + a_this->priv->max_visible_events
+      <= a_this->priv->cur_event_index)
+      ||
+      (a_this->priv->cur_event_index < a_this->priv->page_start_index))
+  {
+    render_events_page_auto (a_this) ;
+  }
+
+  /*update the left hand side page info label*/
+  update_paging_info (a_this) ;
+
+  return a_event;
+
+}
+
+static void
+render_event (TodayEventsArea *a_this,
+              GList *a_event)
+{
+  GtkWidget *infoline, *label, *event_box, *icon ;
+  icaltimetype date ;
+  icalcomponent *event=NULL ;
+  int event_index=0 ;
+  gchar *tmp_str=NULL, *tmp_str2=NULL, *summary=NULL ;
+  gboolean has_alarm=FALSE, is_todo=FALSE, is_event=FALSE ;
+
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv
+                    && a_this->priv->right
+                    && GTK_IS_BOX (a_this->priv->right)) ;
+
+  g_return_if_fail (a_event && a_event->data) ;
+
+  event = a_event->data ;
+  g_return_if_fail (icalcomponent_isa_component (event)) ;
+
+  event_index = g_list_position (a_this->priv->events, a_event) ;
+  g_return_if_fail (event_index >= 0) ;
+
+  /*does the comp has an alarm ?*/
+  has_alarm = icalcomponent_has_alarm (event);
+
+  /*is the comp a todo item ? */
+  is_todo = (icalcomponent_isa (event) == ICAL_VTODO_COMPONENT);
+
+  /*is the comp a calendar event ?*/
+  is_event = (icalcomponent_isa (event) == ICAL_VEVENT_COMPONENT);
+
+  /*a comp must be either a calendar event or a todo item*/
+  g_return_if_fail (is_event != is_todo) ;
+
+  /*get the event summary*/
+  summary = (gchar*) icalcomponent_get_summary (event) ;
+
+  /*get the event starting date*/
+  if (is_event)
+  {
+    date = icalcomponent_get_dtstart (event) ;
+    tmp_str = icaltime_to_pretty_string (&date) ;
+  }
+  else if (is_todo)
+  {
+    date = icalcomponent_get_due (event) ;
+    tmp_str = icaltime_to_pretty_string (&date) ;
+  }
+
+
+  /*build event infoline*/
+  if (tmp_str)
+  {
+    tmp_str2 = g_strdup_printf ("%s %s", summary, tmp_str) ;
+    g_free (tmp_str) ;
+  }
+  else
+  {
+    tmp_str2 = g_strdup_printf ("%s", summary) ;
+  }
+  label = gtk_label_new (tmp_str2) ;
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0) ;
+  gtk_widget_show (label) ;
+  g_free (tmp_str2) ;
+  infoline = gtk_hbox_new (TRUE, 0) ;
+  gtk_box_set_homogeneous (GTK_BOX (infoline), FALSE) ;
+  gtk_widget_show (infoline) ;
+  gtk_box_pack_start (GTK_BOX (infoline), label, FALSE, FALSE, 0) ;
+  icon = gtk_image_new () ;
+
+  if (has_alarm)
+  {
+    gtk_image_set_from_stock (GTK_IMAGE (icon),
+                              "openmoko-today-bell",
+                              GTK_ICON_SIZE_MENU);
+  }
+  else if (is_event)
+  {
+    gtk_image_set_from_stock (GTK_IMAGE (icon),
+                              "openmoko-today-event",
+                              GTK_ICON_SIZE_MENU);
+  }
+  else if (is_todo)
+  {
+    gtk_image_set_from_stock (GTK_IMAGE (icon),
+                              "openmoko-today-todo",
+                              GTK_ICON_SIZE_MENU);
+  }
+
+  gtk_misc_set_alignment (GTK_MISC (icon), 0, 0);
+  gtk_widget_show_all (icon) ;
+  gtk_box_pack_start (GTK_BOX (infoline), icon, FALSE, FALSE, 6) ;
+  event_box = gtk_event_box_new () ;
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE) ;
+  gtk_widget_show (event_box) ;
+  g_object_set_data (G_OBJECT (event_box),
+                     "event-index",
+                     GINT_TO_POINTER (event_index)) ;
+  g_signal_connect (G_OBJECT (event_box), "button-press-event",
+                    G_CALLBACK (on_button_pressed_in_infoline_cb),
+                    a_this) ;
+  gtk_container_add (GTK_CONTAINER (event_box), infoline) ;
+  gtk_box_pack_start_defaults (GTK_BOX (a_this->priv->right), event_box) ;
+}
+
+static void
+render_events_page (TodayEventsArea *a_this, GList *a_from)
+{
+  GList *cur = NULL ;
+  int nb_rendered = 0 ;
+  int prev_page_start_index = 0 ;
+
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv
+                    && a_this->priv->right
+                    && GTK_IS_BOX (a_this->priv->right)) ;
+
+  if (!a_this->priv->events)
+    return ;
+
+  prev_page_start_index = a_this->priv->page_start_index ;
+
+  if (a_from)
+  {
+    a_this->priv->page_start = a_from ;
+  }
+  else
+  {
+    a_this->priv->page_start = a_this->priv->events ;
+  }
+  g_return_if_fail (a_this->priv->page_start) ;
+
+  a_this->priv->page_start_index =
+    g_list_position (a_this->priv->events, a_this->priv->page_start) ;
+
+  init_right_hand_side (a_this) ;
+  for (cur = a_this->priv->page_start ;
+       cur && (nb_rendered < a_this->priv->max_visible_events);
+       cur = cur->next, ++nb_rendered)
+  {
+    render_event (a_this, cur) ;
+  }
+
+  /*if we rendered a new page, tell the world about it*/
+  if (a_this->priv->page_start_index != prev_page_start_index)
+  {
+    int page_num = (a_this->priv->page_start_index+1) %
+                      a_this->priv->max_visible_events ;
+    g_signal_emit (G_OBJECT (a_this), signals[PAGE_SWITCHED_SIGNAL], 0,
+                   page_num) ;
+  }
+}
+
+static gboolean
+is_event_visible (TodayEventsArea *a_this,
+                  GList *a_event)
+{
+  gint event_index=-1 ;
+  g_return_val_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this),
+                        FALSE) ;
+
+  event_index = g_list_position (a_this->priv->events, a_event) ;
+  g_return_val_if_fail (event_index >= 0, FALSE) ;
+
+  g_debug ("in %s:%d", __func__, __LINE__) ;
+  if (event_index >= a_this->priv->page_start_index
+      && (event_index <= a_this->priv->page_start_index
+          + a_this->priv->max_visible_events))
+  {
+    g_debug ("in %s:%d", __func__, __LINE__) ;
+    return TRUE ;
+  }
+  g_debug ("in %s:%d", __func__, __LINE__) ;
+  return FALSE ;
+}
+
+static void
+render_events_page_auto (TodayEventsArea *a_this)
+{
+  int page_end = 0 ;
+  int page_start = 0 ;
+  GList *from = NULL ;
+
+  g_return_if_fail (a_this
+                    && TODAY_IS_EVENTS_AREA (a_this)
+                    && a_this->priv) ;
+
+  /*
+   * compute a page start index so that the current event index
+   * is inside [page_start page_end],
+   * with page_end - page_start == max_visible_events
+   */
+  if (a_this->priv->cur_event_index > a_this->priv->page_start_index)
+  {
+    for (page_end = a_this->priv->max_visible_events ;
+         page_end <= a_this->priv->cur_event_index;
+         page_end += a_this->priv->max_visible_events)
+    {
+    }
+    page_start = page_end - a_this->priv->max_visible_events ;
+  }
+  else
+  {
+    for (page_start = 0 ;
+         page_start +  a_this->priv->max_visible_events <=
+         a_this->priv->cur_event_index;
+         page_start += a_this->priv->max_visible_events)
+    {
+    }
+  }
+
+  /*now we have a decent page range. We can just render the page*/
+  from = g_list_nth (a_this->priv->events, page_start) ;
+  g_return_if_fail (from) ;
+  render_events_page (a_this, from) ;
+}
+
+static gboolean
+remove_event (TodayEventsArea *a_this,
+              GList *a_event)
+{
+  g_return_val_if_fail (a_this
+                        && TODAY_IS_EVENTS_AREA (a_this)
+                        && a_this->priv,
+                        FALSE) ;
+
+  if (!a_event || !a_this->priv->events)
+    return TRUE ;
+
+  if (a_event == a_this->priv->cur_event)
+  {
+    if (a_this->priv->cur_event->prev)
+      a_this->priv->cur_event = a_this->priv->cur_event->prev ;
+    else
+      a_this->priv->cur_event = a_this->priv->cur_event->next ;
+  }
+
+  a_this->priv->events = g_list_remove_link (a_this->priv->events, a_event) ;
+  g_return_val_if_fail (a_event, FALSE) ;
+
+  if (a_event->data)
+  {
+    icalcomponent_free (a_event->data) ;
+    a_event->data = NULL ;
+  }
+  g_list_free (a_event) ;
+  a_this->priv->nb_events-- ;
+
+  if (select_event (a_this, a_this->priv->cur_event))
+  {
+    render_events_page_auto (a_this) ;
+    return TRUE ;
+  }
+  return FALSE ;
+}
+
+static void
+set_events_view (TodayEventsArea *a_this,
+                 ECalView *a_view)
+{
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_this->priv) ;
+
+  if (!a_view)
+  {
+    return ;
+  }
+  if (a_view == a_this->priv->events_view)
+    return ;
+  a_this->priv->events_view = a_view ;
+
+  g_return_if_fail (E_IS_CAL_VIEW (a_view)) ;
+  g_signal_connect (G_OBJECT (a_view), "objects-added",
+                    G_CALLBACK (on_objects_added_cb),
+                    a_this) ;
+  g_signal_connect (G_OBJECT (a_view), "objects-removed",
+                    G_CALLBACK (on_objects_removed_cb),
+                    a_this) ;
+
+  g_object_ref (G_OBJECT (a_view)) ;
+  e_cal_view_start (a_view) ;
+}
+
+static void
+set_tasks_view (TodayEventsArea *a_this,
+                ECalView *a_view)
+{
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_this->priv) ;
+
+  if (!a_view)
+  {
+    return ;
+  }
+  if (a_view == a_this->priv->tasks_view)
+    return ;
+
+  a_this->priv->tasks_view = a_view ;
+
+  g_return_if_fail (E_IS_CAL_VIEW (a_view)) ;
+  g_signal_connect (G_OBJECT (a_view), "objects-added",
+                    G_CALLBACK (on_objects_added_cb),
+                    a_this) ;
+  g_signal_connect (G_OBJECT (a_view), "objects-removed",
+                    G_CALLBACK (on_objects_removed_cb),
+                    a_this) ;
+  g_signal_connect (G_OBJECT (a_view), "objects-modified",
+                    G_CALLBACK (on_objects_modified_cb),
+                    a_this) ;
+
+  g_object_ref (G_OBJECT (a_view)) ;
+  e_cal_view_start (a_view) ;
+}
+
+/**********************
+ * </private api>
+ **********************/
+
+/**********************
+ * <public api>
+ **********************/
+
+GtkWidget*
+today_events_area_new ()
+{
+  GObject *result;
+  result = g_object_new (TODAY_TYPE_EVENTS_AREA,
+                         "max-visible-events", 4,
+                         NULL) ;
+  return GTK_WIDGET (result);
+}
+
+GtkWidget*
+today_events_area_new_with_events (GList *a_events)
+{
+  GObject *result ;
+
+  result = g_object_new (TODAY_TYPE_EVENTS_AREA,
+                         "max-visible-events", 4,
+                         "events", a_events,
+                         NULL) ;
+  return GTK_WIDGET (result) ;
+}
+
+/**
+ *today_events_area_set_events:
+ *@a_this: current instance of TodayEventsArea
+ *@a_events: the events to set. Once set, the events belong to
+ *the current instance of EventsArea and will be freed by it
+ */
+void
+today_events_area_set_events (TodayEventsArea *a_this,
+                              GList *a_events)
+{
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_this->priv) ;
+
+  if (a_this->priv->events)
+    e_cal_free_object_list (a_this->priv->events) ;
+
+  a_this->priv->events = a_events ;
+  a_this->priv->nb_events = get_nb_events_real (a_this) ;
+  a_this->priv->cur_event = NULL ;
+  a_this->priv->page_start = NULL ;
+  a_this->priv->cur_event_index = 0 ;
+
+  reinit_area (a_this) ;
+
+  if (!a_this->priv->events)
+    return ;
+
+  today_events_area_select_next_event (a_this) ;
+
+  /*
+   * walk the events and render them
+   * on the right hand side
+   * of the event area
+   */
+  render_events_page (a_this, a_events) ;
+  update_paging_info (a_this) ;
+  g_signal_emit (G_OBJECT (a_this), signals[EVENTS_ADDED_SIGNAL], 0,
+                 a_events) ;
+}
+
+void
+today_events_area_set_events_auto (TodayEventsArea *a_this)
+{
+  ECalView *events_view=NULL, *tasks_view=NULL;
+
+  g_return_if_fail (a_this && TODAY_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_this->priv) ;
+
+  if (!a_this->priv->events_ecal)
+  {
+    a_this->priv->events_ecal = e_cal_new_system_calendar () ;
+    if(!e_cal_open (a_this->priv->events_ecal, FALSE, NULL))
+    {
+      g_warning ("failed to open calendar") ;
+      if (a_this->priv->events_ecal)
+      {
+        g_object_unref (G_OBJECT (a_this->priv->events_ecal)) ;
+        a_this->priv->events_ecal = NULL ;
+      }
+    }
+  }
+  g_return_if_fail (a_this->priv->events_ecal) ;
+
+  if (!a_this->priv->tasks_ecal)
+  {
+    a_this->priv->tasks_ecal = e_cal_new_system_tasks () ;
+    if (!e_cal_open (a_this->priv->tasks_ecal, FALSE, NULL))
+    {
+      g_warning ("failed to open tasks") ;
+      if (a_this->priv->tasks_ecal)
+      {
+        g_object_unref (G_OBJECT (a_this->priv->tasks_ecal)) ;
+        a_this->priv->tasks_ecal = NULL ;
+      }
+    }
+  }
+  g_return_if_fail (a_this->priv->tasks_ecal) ;
+
+  if (!a_this->priv->events_view)
+  {
+    if (e_cal_get_query (a_this->priv->events_ecal,
+                          "#t",
+                          &events_view,
+                          NULL))
+    {
+      set_events_view (a_this, events_view) ;
+    }
+    else
+    {
+      g_warning ("failed to query the calendar") ;
+    }
+  }
+
+  if (!a_this->priv->tasks_view)
+  {
+    if (e_cal_get_query (a_this->priv->tasks_ecal,
+                         "#t",
+                         &tasks_view,
+                         NULL))
+    {
+      set_tasks_view (a_this, tasks_view) ;
+    }
+    else
+    {
+      g_warning ("failed to query task store") ;
+    }
+  }
+}
+
+void
+today_events_area_append_events (TodayEventsArea *a_this,
+                                 const GList *a_events)
+{
+  g_return_if_fail (a_this && TODAY_IS_EVENTS_AREA (a_this)) ;
+  g_return_if_fail (a_this->priv) ;
+
+  GList *events = today_clone_icalcomponent_list (a_events) ;
+  if (!a_this->priv->events)
+  {
+    today_events_area_set_events (a_this, events) ;
+    return ;
+  }
+  a_this->priv->events = g_list_concat (a_this->priv->events,
+                                        events) ;
+  a_this->priv->nb_events = get_nb_events_real (a_this) ;
+  reinit_area (a_this) ;
+  render_events_page (a_this, NULL) ;
+  update_paging_info (a_this) ;
+  g_signal_emit (G_OBJECT (a_this), signals[EVENTS_ADDED_SIGNAL], 0,
+                 a_events) ;
+}
+
+gboolean
+today_events_area_remove_event (TodayEventsArea *a_this,
+                                const gchar* a_uid)
+{
+  GList *cur=NULL ;
+  gchar *uid=NULL ;
+
+  g_return_val_if_fail (a_this
+                        && TODAY_IS_EVENTS_AREA (a_this)
+                        && a_this->priv,
+                        FALSE) ;
+  g_return_val_if_fail (a_uid, FALSE) ;
+
+  if (!a_this->priv->events)
+    return FALSE ;
+
+  for (cur = a_this->priv->events ; cur ; cur = cur->next)
+  {
+    /*sanity check*/
+    if (!cur->data || !icalcomponent_isa_component (cur->data))
+      continue ;
+
+    uid = (gchar*)icalcomponent_get_uid (cur->data);
+    if (uid && ! strncmp (a_uid, uid, strlen (a_uid)))
+      return remove_event (a_this, cur) ;
+  }
+  return FALSE ;
+}
+
+GList*
+today_events_area_get_events (TodayEventsArea *a_this)
+{
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        NULL);
+  return a_this->priv->events ;
+}
+
+int
+today_events_area_get_nb_events (TodayEventsArea *a_this)
+{
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        -1);
+  return a_this->priv->nb_events ;
+}
+
+int
+today_events_area_get_nb_pages (TodayEventsArea *a_this)
+{
+  int res = 0 ;
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        -1);
+
+  if (!a_this->priv->max_visible_events)
+    return 0 ;
+
+  res = a_this->priv->nb_events / a_this->priv->max_visible_events ;
+  if (a_this->priv->nb_events % a_this->priv->max_visible_events)
+    ++res ;
+  return res ;
+}
+
+ECalComponent*
+today_events_area_get_cur_event (TodayEventsArea *a_this)
+{
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        NULL);
+
+  return a_this->priv->cur_event->data ;
+}
+
+int
+today_events_area_get_cur_event_index (TodayEventsArea *a_this)
+{
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        -1);
+  return a_this->priv->cur_event_index ;
+}
+
+ECalComponent*
+today_events_area_get_event_from_index (TodayEventsArea *a_this,
+                                        int a_index)
+{
+  GList *elem ;
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        NULL);
+  g_return_val_if_fail (a_this->priv->events, NULL) ;
+
+  elem = g_list_nth (a_this->priv->events, a_index) ;
+  if (elem)
+  {
+    return elem->data ;
+  }
+  return NULL ;
+}
+
+ECalComponent*
+today_events_area_select_next_event (TodayEventsArea *a_this)
+{
+  GList *result = NULL ;
+
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        NULL);
+
+  if (!a_this->priv->events)
+  {
+    a_this->priv->cur_event = NULL ;
+    a_this->priv->cur_event_index = -1 ;
+    goto out ;
+  }
+
+  if (!a_this->priv->cur_event)
+  {
+    result = select_event (a_this, a_this->priv->events) ;
+    goto out ;
+  }
+
+  if (a_this->priv->cur_event->next)
+  {
+    result = select_event (a_this, a_this->priv->cur_event->next) ;
+  }
+  else
+  {
+    /*reached end of events, cycle to the first event in list*/
+    result = select_event (a_this, a_this->priv->events) ;
+  }
+
+out:
+  if (!result)
+    return NULL ;
+  return result->data ;
+}
+
+void
+today_events_area_set_max_visible_events (TodayEventsArea *a_this,
+                                          int a_max)
+{
+  g_return_if_fail (a_this &&
+                    TODAY_IS_EVENTS_AREA (a_this) &&
+                    a_this->priv);
+
+  a_this->priv->max_visible_events = a_max ;
+}
+
+int
+today_events_area_get_max_visible_events (TodayEventsArea *a_this)
+{
+  g_return_val_if_fail (a_this &&
+                        TODAY_IS_EVENTS_AREA (a_this) &&
+                        a_this->priv,
+                        -1);
+
+  return a_this->priv->max_visible_events ;
+}
+
+void
+today_events_area_switch_to_next_page (TodayEventsArea *a_this)
+{
+  GList *event_elem ;
+  int event_index ;
+
+  g_return_if_fail (a_this &&
+                    TODAY_IS_EVENTS_AREA (a_this) &&
+                    a_this->priv);
+  g_return_if_fail (a_this->priv->events) ;
+
+  if (a_this->priv->nb_events <= a_this->priv->max_visible_events)
+    return ;
+
+  event_index = a_this->priv->cur_event_index ;
+  event_index += a_this->priv->max_visible_events ;
+
+  event_elem = g_list_nth (a_this->priv->events, event_index) ;
+  if (!event_elem)
+    event_elem = a_this->priv->events ;
+
+  select_event (a_this, event_elem) ;
+}
+
+void
+today_events_area_switch_to_prev_page (TodayEventsArea *a_this)
+{
+  GList *event_elem ;
+  int event_index ;
+
+  g_return_if_fail (a_this &&
+                    TODAY_IS_EVENTS_AREA (a_this) &&
+                    a_this->priv);
+  g_return_if_fail (a_this->priv->events) ;
+
+  if (a_this->priv->nb_events <= a_this->priv->max_visible_events)
+    return ;
+
+  event_index = a_this->priv->cur_event_index ;
+  if (event_index > a_this->priv->max_visible_events)
+    event_index -= a_this->priv->max_visible_events ;
+  else
+    event_index = a_this->priv->nb_events - a_this->priv->max_visible_events-1;
+  event_index = MAX (event_index, 0) ;
+
+  event_elem = g_list_nth (a_this->priv->events, event_index) ;
+  g_return_if_fail (event_elem) ;
+
+  select_event (a_this, event_elem) ;
+}
+
+/**********************
+ * </public api>
+ **********************/
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/xutil.h
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/xutil.h	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/xutil.h	(revision 2548)
@@ -0,0 +1,21 @@
+/* 
+ * Copyright (C) 2007 OpenedHand Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+char * x_strerror (int code);
+
+gboolean x_get_workarea (int *x, int *y, int *w, int *h);
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-events-area.h
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-events-area.h	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-events-area.h	(revision 2548)
@@ -0,0 +1,91 @@
+/* vi:set sw=2: */
+
+/*
+ *  Today - At a glance view of date, time, calender events, todo items and
+ *  other images.
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by OpenedHand Ltd <info@openedhand.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __TODAY_EVENTS_AREA_H__
+#define __TODAY_EVENTS_AREA_H__
+
+#include <libecal/e-cal-component.h>
+#include <gtk/gtktable.h>
+
+G_BEGIN_DECLS
+
+#define TODAY_TYPE_EVENTS_AREA (today_events_area_get_type ())
+#define TODAY_EVENTS_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TODAY_TYPE_EVENTS_AREA, TodayEventsArea))
+#define TODAY_EVENTS_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TODAY_TYPE_EVENTS_AREA, TodayEventsAreaClass))
+#define TODAY_IS_EVENTS_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TODAY_TYPE_EVENTS_AREA))
+#define TODAY_IS_EVENTS_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TODAY_TYPE_EVENTS_AREA))
+#define TODAY_EVENTS_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TODAY_TYPE_EVENTS_AREATodayEventsAreaClass))
+
+typedef struct _TodayEventsAreaPrivate TodayEventsAreaPrivate;
+typedef struct _TodayEventsAreaClass TodayEventsAreaClass;
+typedef struct _TodayEventsArea TodayEventsArea;
+
+struct _TodayEventsArea {
+  GtkTable table;
+  TodayEventsAreaPrivate *priv;
+};
+
+struct _TodayEventsAreaClass {
+  GtkTableClass parent_class;
+
+  /*
+   * <noticeable events>
+   */
+  void (*events_added) (TodayEventsArea *self, GList *events) ;
+  void (*event_selected) (TodayEventsArea *self, guint event_index) ;
+  void (*page_switched) (TodayEventsArea *self, guint page_index) ;
+  /*
+   * </noticeable events>
+   */
+};
+
+GType          today_events_area_get_type (void);
+GtkWidget*     today_events_area_new ();
+GtkWidget*     today_events_area_new_with_events (GList *events);
+void           today_events_area_set_events (TodayEventsArea *self,
+                                             GList *events);
+void           today_events_area_set_events_auto (TodayEventsArea *self) ;
+void           today_events_area_append_events (TodayEventsArea *self,
+                                                const GList *events) ;
+gboolean       today_events_area_remove_event (TodayEventsArea *self,
+                                               const gchar* event_uid) ;
+GList*         today_events_area_get_events (TodayEventsArea *self);
+int            today_events_area_get_nb_events (TodayEventsArea *self);
+int            today_events_area_get_nb_pages (TodayEventsArea *self);
+ECalComponent* today_events_area_get_cur_event (TodayEventsArea *self);
+int            today_events_area_get_cur_event_index (TodayEventsArea *self);
+ECalComponent* today_events_area_get_event_from_index (TodayEventsArea *self,
+                                                       int index) ;
+ECalComponent* today_events_area_select_next_event (TodayEventsArea *self) ;
+void           today_events_area_set_max_visible_events (TodayEventsArea *self,
+                                                         int max) ;
+int            today_events_area_get_max_visible_events (TodayEventsArea *self);
+void           today_events_area_switch_to_next_page (TodayEventsArea *self) ;
+void           today_events_area_switch_to_prev_page (TodayEventsArea *self) ;
+
+G_END_DECLS
+
+#endif /*__TODAY_EVENTS_AREA_H__*/
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-utils.c
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-utils.c	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/src/today-utils.c	(revision 2548)
@@ -0,0 +1,241 @@
+/* vi: set sw=2: */
+/*
+ *  Today - At a glance view of date, time, calender events, todo items and
+ *  other images.
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by OpenedHand Ltd <info@openedhand.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/**
+ * e_cal_component_list_free:
+ * @list: the list ECalComooment to free
+ *
+ * Free a list of ECalComponent
+ */
+#include <string.h>
+#include "today-utils.h"
+#include <libical/icalcomponent.h>
+
+#define LOG_ERROR \
+g_warning ("Got error '%s', code '%d'", \
+           error->message, error->code);
+
+#define FREE_ERROR g_error_free (error) ; error = NULL ;
+
+static ECal *calendar_db = NULL;
+static ECal *tasks_db = NULL;
+
+void
+e_cal_component_list_free (GList * list)
+{
+  GList *cur = NULL;
+
+  for (cur = list; cur; cur = cur->next)
+  {
+    /*if an element of the list is not of type ECalComponent, leak it */
+    if (cur->data && E_IS_CAL_COMPONENT (cur->data))
+    {
+      g_object_unref (G_OBJECT (cur->data));
+      cur->data = NULL;
+    }
+    else
+    {
+      g_warning ("cur->data is not of type ECalComponent !");
+    }
+  }
+  g_list_free (list);
+}
+
+/*
+ * if the timetype is today, then only display it's hour part,
+ * without the seconds
+ * If it's not today, then only display it's date part, without the year
+ */
+gchar*
+icaltime_to_pretty_string (const icaltimetype *timetype)
+{
+#define TMP_STR_LEN 10
+    icaltimetype today ;
+    gboolean     hour_only              = FALSE ;
+    gboolean     date_only              = FALSE ;
+    gchar        *result                = NULL  ;
+    gchar        tmp_str[TMP_STR_LEN+1]         ;
+    struct tm    native_tm                      ;
+
+    g_return_val_if_fail (timetype, NULL) ;
+
+    today = icaltime_today () ;
+    if (!icaltime_compare_date_only (*timetype, today))
+    {
+        hour_only = TRUE ;
+    }
+    else
+    {
+        date_only = TRUE ;
+    }
+    if (hour_only)
+    {
+        result = g_strdup_printf ("%d:%d", timetype->hour, timetype->minute) ;
+    }
+    else if (date_only)
+    {
+        native_tm = icaltimetype_to_tm ((icaltimetype*)timetype) ;
+        memset (tmp_str, 0, TMP_STR_LEN+1) ;
+        strftime (tmp_str, TMP_STR_LEN, "%d/%b", &native_tm) ;
+        result = g_strdup (tmp_str) ;
+    }
+    return result ;
+}
+
+GList*
+today_clone_icalcomponent_list (const GList *a_list)
+{
+  GList *result=NULL, *cur=NULL ;
+
+  for (cur =(GList*)a_list ; cur ; cur = cur->next)
+  {
+    if (!icalcomponent_isa_component (cur->data))
+      continue ;
+    result = g_list_prepend (result, icalcomponent_new_clone (cur->data)) ;
+  }
+  return result ;
+}
+
+/**
+ * today_get_today_events:
+ *
+ * Return value:  a list of ECalComponents, of type VEVENT
+ * or VTODO
+ * must be freed with e_cal_component_list_free()
+ */
+GList *
+today_get_today_events ()
+{
+  GList *result=NULL, *ical_comps=NULL, *ical_comps2=NULL;
+  GError *error = NULL;
+  gchar *query = NULL;
+
+  if (!calendar_db)
+  {
+    calendar_db = e_cal_new_system_calendar ();
+    g_return_val_if_fail (calendar_db, NULL);
+
+    if (!e_cal_open (calendar_db, TRUE, &error))
+    {
+      g_warning ("failed to open the calendar");
+    }
+    if (error)
+    {
+      LOG_ERROR;
+      goto out;
+    }
+  }
+
+  /*
+  query = g_strdup_printf ("(occur-in-time-range? "
+                               "(time-day-begin (time-now)) "
+                               "(time-day-end   (time-now)) "
+                           ")");
+   */
+  query = g_strdup_printf ("#t");
+  e_cal_get_object_list (calendar_db, query, &ical_comps, &error);
+  g_free (query) ;
+  query = NULL ;
+  if (error)
+  {
+    LOG_ERROR;
+    FREE_ERROR;
+  }
+
+  if (!tasks_db)
+  {
+    tasks_db = e_cal_new_system_tasks ();
+    g_return_val_if_fail (tasks_db, NULL);
+    if (!e_cal_open (tasks_db, TRUE, &error))
+    {
+      g_warning ("failed to open the tasks");
+    }
+    if (error)
+    {
+      LOG_ERROR;
+      goto out;
+    }
+  }
+
+  query = g_strdup_printf ("#t");
+  e_cal_get_object_list (tasks_db, query, &ical_comps2, &error);
+  g_free (query) ;
+  query = NULL ;
+  if (error)
+  {
+    LOG_ERROR;
+    FREE_ERROR ;
+  }
+  ical_comps = g_list_concat (ical_comps, ical_comps2) ;
+
+  result = ical_comps;
+  ical_comps = ical_comps2 = NULL;
+
+out:
+  if (ical_comps)
+  {
+    e_cal_free_object_list (ical_comps);
+  }
+
+  if (ical_comps2)
+  {
+    e_cal_free_object_list (ical_comps);
+  }
+
+  /*
+   the calender must stay alive during the app's lifetime
+  if (ecal)
+  {
+    g_object_unref (G_OBJECT (ecal));
+  }
+  */
+
+  if (error)
+  {
+    g_error_free (error);
+  }
+  if (query)
+  {
+    g_free (query);
+  }
+  return result;
+}
+
+gboolean
+icalcomponent_has_alarm (icalcomponent *a_icalcomp)
+{
+  icalcompiter iter ;
+
+  g_return_val_if_fail (a_icalcomp, FALSE) ;
+  g_return_val_if_fail (icalcomponent_isa_component (a_icalcomp), FALSE) ;
+
+  for (iter = icalcomponent_begin_component (a_icalcomp,
+                                             ICAL_VALARM_COMPONENT);
+      icalcompiter_deref (&iter) != NULL ;
+      icalcompiter_next (&iter))
+  {
+    return TRUE ;
+  }
+  return FALSE ;
+}
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/COPYING
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/COPYING	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/COPYING	(revision 2548)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/Makefile.am
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/Makefile.am	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/Makefile.am	(revision 2548)
@@ -0,0 +1,21 @@
+SUBDIRS = src tests po
+
+INTLTOOL_BUILT = \
+        intltool-extract \
+        intltool-merge \
+        intltool-update
+
+EXTRA_DIST = $(INTLTOOL_BUILT:=.in)
+
+DISTCLEANFILES = $(INTLTOOL_BUILT)
+
+# Extra clean files so that maintainer-clean removes *everything*
+MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub \
+                       configure depcomp install-sh ltmain.sh     \
+                       Makefile.in missing config.h.in            \
+                       intltool-extract intltool-extract.in \
+                       intltool-merge intltool-merge.in \
+                       intltool-update intltool-update.in \
+                       mkinstalldirs
+
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/autogen.sh
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/autogen.sh	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/autogen.sh	(revision 2548)
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+REQUIRED_AUTOMAKE_VERSION=1.8
+PKG_NAME=today
+
+(test -f $srcdir/configure.ac \
+  && test -f $srcdir/src/today-main.c) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level $PKG_NAME directory"
+    exit 1
+}
+
+
+which gnome-autogen.sh || {
+    echo "You need to install gnome-common from the GNOME CVS"
+    exit 1
+}
+USE_GNOME2_MACROS=1 . gnome-autogen.sh
+
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/events-area-test.c
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/events-area-test.c	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/events-area-test.c	(revision 2548)
@@ -0,0 +1,112 @@
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-component.h>
+#include <gtk/gtk.h>
+#include "src/today-events-area.h"
+
+#define LOG_ERROR \
+g_warning ("Got error '%s', code '%d'", \
+           error->message, error->code);
+
+#define FREE_ERROR g_error_free (error) ; error = NULL ;
+
+static GList* get_calendar_events (ECal *a_cal) ;
+
+static GList*
+get_calendar_events (ECal *a_cal)
+{
+  char   *query = NULL ;
+  GError *error = NULL ;
+  GList *objects = NULL ;
+  GList *events = NULL ;
+  GList *cur = NULL ;
+
+
+  if (!e_cal_open (a_cal, TRUE, &error))
+  {
+    g_warning ("failed to open the calendar") ;
+    goto out;
+  }
+  if (error)
+  {
+      LOG_ERROR ;
+      FREE_ERROR ;
+      goto out;
+  }
+  /*
+  query = g_strdup_printf ("(occur-in-time-range? "
+                               "(time-day-begin (time-now)) "
+                               "(time-day-end   (time-now))"
+                           ")");
+   */
+  query = g_strdup_printf ("#t");
+
+  if (!e_cal_get_object_list (a_cal, query, &objects, &error))
+  {
+    g_message ("Querying system calendar failed for query '%s'",
+               query) ;
+    goto out ;
+  }
+  if (error)
+  {
+      LOG_ERROR ;
+      FREE_ERROR ;
+      goto out;
+  }
+
+  for (cur = objects ; cur ; cur = cur->next)
+  {
+    ECalComponent *comp ;
+    comp = e_cal_component_new () ;
+    e_cal_component_set_icalcomponent (comp, cur->data) ;
+    events = g_list_prepend (events, comp) ;
+    cur->data = NULL ;
+  }
+  g_list_free (objects) ;
+  objects = NULL ;
+
+out:
+  g_free (query) ;
+  if (objects)
+  {
+    e_cal_free_object_list (objects) ;
+  }
+
+  return events ;
+}
+
+int
+main (int argc, char **argv)
+{
+  ECal *cal = NULL ;
+  GtkWidget *window = NULL ;
+  GtkWidget *ta = NULL ;
+  GList *events = NULL ;
+
+  gtk_init (&argc, &argv) ;
+
+  cal = e_cal_new_system_calendar () ;
+  g_return_val_if_fail (cal, -1) ;
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL) ;
+  g_signal_connect (G_OBJECT (window),
+                    "destroy",
+                    G_CALLBACK (gtk_exit),
+                    NULL) ;
+  ta = today_events_area_new () ;
+  today_events_area_set_max_visible_events (TODAY_EVENTS_AREA (ta),
+                                            2) ;
+  events = get_calendar_events (cal) ;
+  g_return_val_if_fail (events, -1) ;
+  today_events_area_set_events (TODAY_EVENTS_AREA (ta), events) ;
+  gtk_container_add (GTK_CONTAINER (window), ta) ;
+
+  gtk_widget_show_all (window) ;
+
+  gtk_main () ;
+
+  if (cal)
+  {
+    g_object_unref (G_OBJECT (cal)) ;
+  }
+  return 0 ;
+}
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/Makefile.am
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/Makefile.am	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/Makefile.am	(revision 2548)
@@ -0,0 +1,13 @@
+noinst_PROGRAMS    = ecaltest eventsareatest
+
+ecaltest_SOURCES	   = ecal-test.c
+ecaltest_LDADD		   = @TODAY_LIBS@
+
+eventsareatest_SOURCES     = events-area-test.c \
+$(top_srcdir)/src/today-events-area.c \
+$(top_srcdir)/src/today-utils.c
+
+eventsareatest_LDADD       = @TODAY_LIBS@
+
+INCLUDES           = -I$(top_srcdir) @TODAY_CFLAGS@
+
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/ecal-test.c
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/ecal-test.c	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/tests/ecal-test.c	(revision 2548)
@@ -0,0 +1,159 @@
+/* vi:set sw=2: */
+/*
+ *  Today - At a glance view of date, time, calender events, todo items and
+ *  other images.
+ *
+ * Copyright (C) 2007 by OpenMoko, Inc.
+ * Written by OpenedHand Ltd <info@openedhand.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <libecal/e-cal-component.h>
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-time-util.h>
+
+#define LOG_ERROR \
+g_warning ("Got error '%s', code '%d'", \
+           error->message, error->code);
+
+#define FREE_ERROR g_error_free (error) ; error = NULL ;
+/*static const char *s_query = "" ;*/
+
+void
+display_usage (const char *prog_name)
+{
+    g_return_if_fail (prog_name) ;
+    printf ("usage: %s <query sexpression>\n", prog_name) ;
+    printf ("or: %s\n", prog_name) ;
+}
+
+void
+display_events (GList *a_events/*list of icalcomponents*/)
+{
+  GList          *cur         = NULL ;
+  ECalComponent  *cal_comp    = NULL ;
+  char           *event_str   = NULL ;
+  char           *categories  = NULL ;
+
+  if (!a_events)
+  {
+    g_message ("No events") ;
+    return ;
+  }
+  cal_comp = e_cal_component_new () ;
+  g_return_if_fail (cal_comp) ;
+
+  for (cur = a_events ; cur ; cur = cur->next)
+  {
+    if (!cur->data) {continue;}
+    e_cal_component_set_icalcomponent (cal_comp, cur->data) ;
+    if (e_cal_component_get_vtype (cal_comp) != E_CAL_COMPONENT_EVENT)
+    {
+      g_warning ("component is not an event, rather of type %d",
+          e_cal_component_get_vtype (cal_comp));
+      continue ;
+    }
+    event_str = e_cal_component_get_as_string (cal_comp) ;
+    if (event_str)
+    {
+      g_message ("Got event '%s'", event_str) ;
+      g_free (event_str) ;
+    }
+    e_cal_component_get_categories (cal_comp, &categories) ;
+    if (categories)
+    {
+      g_message ("event's categs: '%s'\n", categories) ;
+      //g_free (categories) ;
+      categories = NULL ;
+    }
+    else
+    {
+      g_message ("no associated category") ;
+    }
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+    int            ret       = 0 ;
+    ECal           *cal      = NULL ;
+    char           *query    = NULL ;
+    GList          *objects  = NULL ;
+    GError         *error    = NULL ;
+
+    g_type_init () ;
+
+    if (argc != 1 && (!strcmp (argv[1], "--help") || !strcmp (argv[0], "-h"))) {
+        display_usage (argv[0]) ;
+        return -1 ;
+    }
+
+    cal = e_cal_new_system_calendar () ;
+    g_return_val_if_fail (cal, -1) ;
+    if (!e_cal_open (cal, TRUE, &error)) {
+        g_warning ("failed to open the calendar") ;
+        ret= -1 ;
+    }
+    if (error) {
+        ret = -1 ;
+        LOG_ERROR ;
+        FREE_ERROR ;
+    }
+    if (ret) {goto out ;}
+
+    /*
+    query = g_strdup_printf ("(occur-in-time-range? "
+                                 "(time-day-begin (time-now)) "
+                                 "(time-day-end   (time-now))"
+                             ")");
+
+    */
+    query = g_strdup_printf ("#t") ;
+
+    printf ("Issuing query: '%s'\n", query) ;
+    if (!e_cal_get_object_list (cal, query, &objects, &error)) {
+        g_message ("Querying system calendar failed\n") ;
+        ret = -1 ;
+    }
+    if (error) {
+        ret = -1 ;
+        LOG_ERROR ;
+        FREE_ERROR ;
+    }
+    if (ret) {goto out ;}
+    g_message ("Query succeded\n") ;
+    if (objects) {
+        display_events (objects) ;
+    }
+
+out:
+    /*
+    if (cal) {
+        g_object_unref (G_OBJECT (cal)) ;
+    }
+    */
+    if (objects) {
+        g_list_free (objects) ;
+    }
+    if (query) {
+        g_free (query) ;
+    }
+    return ret ;
+}
Index: /trunk/src/target/OM-2007.2/applications/openmoko-today2/configure.ac
===================================================================
--- /trunk/src/target/OM-2007.2/applications/openmoko-today2/configure.ac	(revision 2548)
+++ /trunk/src/target/OM-2007.2/applications/openmoko-today2/configure.ac	(revision 2548)
@@ -0,0 +1,39 @@
+AC_PREREQ(2.53)
+AC_INIT(today, 0.1, http://www.openedhand.com/)
+AM_INIT_AUTOMAKE()
+AC_CONFIG_SRCDIR(src/today-main.c)
+AM_MAINTAINER_MODE
+
+LIBEBOOK_VERSION=1.4.2
+LIBECAL_VERSION=1.4.2
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+AC_PROG_INTLTOOL
+
+dnl i18n support
+GETTEXT_PACKAGE=Today
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
+AC_SUBST(GETTEXT_PACKAGE)
+ALL_LINGUAS=""
+AM_GLIB_GNU_GETTEXT
+
+PKG_CHECK_MODULES(TODAY,
+                  openmoko-libs
+                  libstartup-notification-1.0
+                  libebook-1.2 >= $LIBEBOOK_VERSION
+                  libecal-1.2 >= $LIBEBOOK_VERSION)
+
+
+if test x$TODAY_DEVEL != x ; then
+    CFLAGS="-Wall -Wextra -Wshadow -Wpointer-arith -g"
+fi
+
+AC_OUTPUT([
+Makefile
+po/Makefile.in
+src/Makefile
+tests/Makefile
+])
