[evolution/clutter-calendar-v2] Add Clutter texture to time line.



commit 45cd0eacf2586e19a1d1c9685ea1c032734435df
Author: Srinivasa Ragavan <sragavan gnome org>
Date:   Thu Aug 26 22:35:58 2010 +0530

    Add Clutter texture to time line.

 calendar/gui/Makefile.am                    |    4 +
 calendar/gui/e-day-view-clutter-time-item.c | 1147 +++++++++++++++++++++++++++
 calendar/gui/e-day-view-clutter-time-item.h |   90 +++
 calendar/gui/e-day-view.c                   |  107 +++-
 calendar/gui/e-day-view.h                   |   21 +-
 5 files changed, 1364 insertions(+), 5 deletions(-)
---
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index a168582..5631234 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -71,6 +71,7 @@ libevolution_calendar_la_CPPFLAGS =			\
 	-DPREFIX=\""$(prefix)"\"			\
 	$(GNOME_PLATFORM_CFLAGS)			\
 	$(LIBSOUP_CFLAGS)				\
+	$(CLUTTER_CFLAGS)				\
 	$(EVOLUTION_CALENDAR_CFLAGS)			\
 	$(CAMEL_CFLAGS)
 
@@ -85,6 +86,8 @@ etspec_DATA =				\
 	e-memo-table.etspec
 
 libevolution_calendar_la_SOURCES = \
+	e-day-view-clutter-time-item.c		\
+	e-day-view-clutter-time-item.h		\
 	cal-editor-utils.c			\
 	cal-editor-utils.h			\
 	calendar-config.c			\
@@ -227,6 +230,7 @@ libevolution_calendar_la_LIBADD =					\
 	$(top_builddir)/filter/libfilter.la				\
 	$(top_builddir)/e-util/libeutil.la				\
 	$(CAMEL_LIBS)							\
+	$(CLUTTER_LIBS)							\
 	$(LIBSOUP_LIBS)							\
 	$(EVOLUTION_CALENDAR_LIBS)					\
 	$(GNOME_PLATFORM_LIBS)
diff --git a/calendar/gui/e-day-view-clutter-time-item.c b/calendar/gui/e-day-view-clutter-time-item.c
new file mode 100644
index 0000000..09179f9
--- /dev/null
+++ b/calendar/gui/e-day-view-clutter-time-item.c
@@ -0,0 +1,1147 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Authors:
+ *		Srinivasa Ragavan <sragavan gnome org>
+ *
+ * Copyright (C) 2010 Intel Corporation. (www.intel.com)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include "e-day-view-clutter-time-item.h"
+#include "calendar-config.h"
+#include <libecal/e-cal-time-util.h>
+#include <widgets/e-timezone-dialog/e-timezone-dialog.h>
+#include <libedataserver/e-data-server-util.h>
+
+/* The spacing between items in the time column. GRID_X_PAD is the space down
+   either side of the column, i.e. outside the main horizontal grid lines.
+   HOUR_L_PAD & HOUR_R_PAD are the spaces on the left & right side of the
+   big hour number (this is inside the horizontal grid lines).
+   MIN_X_PAD is the spacing either side of the minute number. The smaller
+   horizontal grid lines match with this.
+   60_MIN_X_PAD is the space either side of the HH:MM display used when
+   we are displaying 60 mins per row (inside the main grid lines).
+   LARGE_HOUR_Y_PAD is the offset of the large hour string from the top of the
+   row.
+   SMALL_FONT_Y_PAD is the offset of the small time/minute string from the top
+   of the row. */
+
+#define E_DVTMI_TIME_GRID_X_PAD		4
+#define E_DVTMI_HOUR_L_PAD		4
+#define E_DVTMI_HOUR_R_PAD		2
+#define E_DVTMI_MIN_X_PAD		2
+#define E_DVTMI_60_MIN_X_PAD		4
+#define E_DVTMI_LARGE_HOUR_Y_PAD	1
+#define E_DVTMI_SMALL_FONT_Y_PAD	1
+
+#define E_DAY_VIEW_CLUTTER_TIME_ITEM_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM, EDayViewClutterTimeItemPrivate))
+
+struct _EDayViewClutterTimeItemPrivate {
+	/* The parent EDayView widget. */
+	EDayView *day_view;
+
+	/* The width of the time column. */
+	gint column_width;
+
+	/* TRUE if we are currently dragging the selection times. */
+	gboolean dragging_selection;
+
+	/* The second timezone if shown, or else NULL. */
+	guint second_zone_changed_id;
+	icaltimezone *second_zone;
+
+	gdouble line_width;
+	ClutterActor *mb_line;
+	ClutterActor *mb_line_alt;
+};
+
+static void e_day_view_clutter_time_item_draw (ClutterActor *item);
+static double e_day_view_clutter_time_item_point (ClutterActor *item,
+					  double x, double y,
+					  gint cx, gint cy,
+					  ClutterActor **actual_item);
+static gint e_day_view_clutter_time_item_event (ClutterActor *item,
+					ClutterEvent *event);
+static void e_day_view_clutter_time_item_increment_time	(gint	*hour,
+						 gint	*minute,
+						 gint	 mins_per_row);
+static void e_day_view_clutter_time_item_show_popup_menu (EDayViewClutterTimeItem *time_item,
+						  ClutterEvent *event);
+static void e_day_view_clutter_time_item_on_set_divisions (GtkWidget *item,
+						   EDayViewClutterTimeItem *time_item);
+static void e_day_view_clutter_time_item_on_button_press (EDayViewClutterTimeItem *time_item,
+						  ClutterEvent *event);
+static void e_day_view_clutter_time_item_on_button_release (EDayViewClutterTimeItem *time_item,
+						    ClutterEvent *event);
+static void e_day_view_clutter_time_item_on_motion_notify (EDayViewClutterTimeItem *time_item,
+						   ClutterEvent *event);
+static gint e_day_view_clutter_time_item_convert_position_to_row (EDayViewClutterTimeItem *time_item,
+							  gint y);
+
+static void  edvti_second_zone_changed_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data);
+
+enum {
+	PROP_0,
+	PROP_DAY_VIEW
+};
+
+static gpointer parent_class;
+
+static void
+day_view_clutter_time_item_set_property (GObject *object,
+                                 guint property_id,
+                                 const GValue *value,
+                                 GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DAY_VIEW:
+			e_day_view_clutter_time_item_set_day_view (
+				E_DAY_VIEW_CLUTTER_TIME_ITEM (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+day_view_clutter_time_item_get_property (GObject *object,
+                                 guint property_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_DAY_VIEW:
+			g_value_set_object (
+				value, e_day_view_clutter_time_item_get_day_view (
+				E_DAY_VIEW_CLUTTER_TIME_ITEM (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+day_view_clutter_time_item_dispose (GObject *object)
+{
+	EDayViewClutterTimeItemPrivate *priv;
+
+	priv = E_DAY_VIEW_CLUTTER_TIME_ITEM_GET_PRIVATE (object);
+
+	if (priv->day_view != NULL) {
+		g_object_unref (priv->day_view);
+		priv->day_view = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+day_view_clutter_time_item_finalize (GObject *object)
+{
+	EDayViewClutterTimeItem *time_item;
+
+	time_item = E_DAY_VIEW_CLUTTER_TIME_ITEM (object);
+
+	if (time_item->priv->second_zone_changed_id)
+		calendar_config_remove_notification (time_item->priv->second_zone_changed_id);
+	time_item->priv->second_zone_changed_id = 0;
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+day_view_clutter_time_item_class_init (EDayViewClutterTimeItemClass *class)
+{
+	GObjectClass *object_class;
+	ClutterCairoTextureClass *item_class;
+	ClutterActorClass *actor_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EDayViewClutterTimeItemPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = day_view_clutter_time_item_set_property;
+	object_class->get_property = day_view_clutter_time_item_get_property;
+	object_class->dispose = day_view_clutter_time_item_dispose;
+	object_class->finalize = day_view_clutter_time_item_finalize;
+
+	item_class = CLUTTER_CAIRO_TEXTURE_CLASS (class);
+	actor_class = CLUTTER_ACTOR_CLASS (class);
+/*	item_class->update = e_day_view_clutter_time_item_update;
+	item_class->draw = e_day_view_clutter_time_item_draw;
+	item_class->point = e_day_view_clutter_time_item_point;
+*/
+	actor_class->event = e_day_view_clutter_time_item_event;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DAY_VIEW,
+		g_param_spec_object (
+			"day-view",
+			"Day View",
+			NULL,
+			E_TYPE_DAY_VIEW,
+			G_PARAM_READWRITE));
+}
+
+static void
+day_view_clutter_time_item_init (EDayViewClutterTimeItem *time_item)
+{
+	gchar *last;
+
+	time_item->priv = E_DAY_VIEW_CLUTTER_TIME_ITEM_GET_PRIVATE (time_item);
+
+	time_item->priv->dragging_selection = FALSE;
+	time_item->priv->second_zone = NULL;
+
+	last = calendar_config_get_day_second_zone ();
+
+	if (last) {
+		if (*last)
+			time_item->priv->second_zone = icaltimezone_get_builtin_timezone (last);
+		g_free (last);
+	}
+
+	time_item->priv->second_zone_changed_id = calendar_config_add_notification_day_second_zone (edvti_second_zone_changed_cb, time_item);
+}
+
+GType
+e_day_view_clutter_time_item_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		const GTypeInfo type_info = {
+			sizeof (EDayViewClutterTimeItemClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) day_view_clutter_time_item_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EDayViewClutterTimeItem),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) day_view_clutter_time_item_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			CLUTTER_TYPE_CAIRO_TEXTURE, "EDayViewClutterTimeItem",
+			&type_info, 0);
+	}
+
+	return type;
+}
+
+/* Draw Marcus Bains */
+static void
+edvti_draw_marcus_bains (ClutterActor *canvas_item,
+		gint		    x,
+		gint		    y,
+		gint		    width,
+		gint		    height,
+		gint		    x_offset,
+		icaltimezone       *use_zone)
+
+{
+	struct icaltimetype time_now;
+	gint marcus_bains_y;
+	EDayView *day_view;
+	EDayViewClutterTimeItem *time_item;
+	cairo_t *cr;
+	ClutterActor *mb;
+	gint long_line_x1, long_line_x2;
+	ClutterActor *stage;
+	GdkColor mb_color;
+
+	time_item = E_DAY_VIEW_CLUTTER_TIME_ITEM (canvas_item);
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+	
+	stage = time_item->stage;
+	long_line_x1 = (use_zone ? 0 : E_DVTMI_TIME_GRID_X_PAD) - x + x_offset;
+	long_line_x2 = time_item->priv->column_width - E_DVTMI_TIME_GRID_X_PAD - x - (use_zone ? E_DVTMI_TIME_GRID_X_PAD : 0) + x_offset;
+
+	if ((use_zone && !time_item->priv->mb_line_alt) ||
+			(!use_zone && !time_item->priv->mb_line)) {
+		mb = clutter_cairo_texture_new (long_line_x2-long_line_x1, (int)time_item->priv->line_width);
+		clutter_container_add_actor ((ClutterContainer *)stage, mb);
+		clutter_actor_show (mb);
+
+		if (use_zone)
+			time_item->priv->mb_line_alt = mb;
+		else
+			time_item->priv->mb_line  = mb;
+	} else {
+		if (use_zone)
+			mb = time_item->priv->mb_line_alt;
+		else
+			mb = time_item->priv->mb_line;
+	}
+
+	cr = clutter_cairo_texture_create ((ClutterCairoTexture *)mb);
+	cairo_save (cr);
+	gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE]);
+
+	if (day_view->marcus_bains_time_bar_color && gdk_color_parse (day_view->marcus_bains_time_bar_color, &mb_color)) {
+		GdkColormap *colormap;
+
+		colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
+		if (gdk_colormap_alloc_color (colormap, &mb_color, TRUE, TRUE)) {
+			gdk_cairo_set_source_color (cr, &mb_color);
+		}
+	} else
+		mb_color = day_view->colors[E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE];
+
+	time_now = icaltime_current_time_with_zone (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view)));
+	marcus_bains_y = (time_now.hour * 60 + time_now.minute) * day_view->row_height / day_view->mins_per_row - y;
+	cairo_set_line_width (cr, 1.5);
+	cairo_move_to (cr, long_line_x1 - (use_zone ? E_DVTMI_TIME_GRID_X_PAD : 0), 0);
+	cairo_line_to (cr, long_line_x2, 0);
+	cairo_stroke (cr);
+	cairo_restore (cr);
+
+	cairo_destroy (cr);
+
+	clutter_actor_set_position (mb, long_line_x1, y);
+}
+
+/*
+ * DRAWING ROUTINES - functions to paint the canvas item.
+ */
+static void
+edvti_draw_zone (ClutterActor   *canvas_item,
+		gint		    x,
+		gint		    y,
+		gint		    width,
+		gint		    height,
+		gint		    x_offset,
+		icaltimezone       *use_zone)
+{
+	EDayView *day_view;
+	EDayViewClutterTimeItem *time_item;
+	ECalModel *model;
+	GtkStyle *style;
+	const gchar *suffix;
+	gchar buffer[64], *midnight_day = NULL, *midnight_month = NULL;
+	gint hour, display_hour, minute, row;
+	gint row_y, start_y, large_hour_y_offset, small_font_y_offset;
+	gint long_line_x1, long_line_x2, short_line_x1;
+	gint large_hour_x2, minute_x2;
+	gint hour_width, minute_width, suffix_width;
+	gint max_suffix_width, max_minute_or_suffix_width;
+	PangoLayout *layout;
+	PangoContext *context;
+	PangoFontDescription *small_font_desc;
+	PangoFontMetrics *large_font_metrics, *small_font_metrics;
+	cairo_t *cr;
+	GdkColor fg, dark;
+	GdkColor mb_color;
+
+	cr = clutter_cairo_texture_create ((ClutterCairoTexture *)canvas_item);
+
+	time_item = E_DAY_VIEW_CLUTTER_TIME_ITEM (canvas_item);
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+
+	time_item->priv->line_width = cairo_get_line_width (cr);
+
+	model = e_calendar_view_get_model (E_CALENDAR_VIEW (day_view));
+
+	style = gtk_widget_get_style (GTK_WIDGET (day_view));
+	small_font_desc = style->font_desc;
+
+	context = gtk_widget_get_pango_context (GTK_WIDGET (day_view));
+	large_font_metrics = pango_context_get_metrics (context, day_view->large_font_desc,
+							pango_context_get_language (context));
+	small_font_metrics = pango_context_get_metrics (context, small_font_desc,
+							pango_context_get_language (context));
+
+	fg = style->fg[GTK_STATE_NORMAL];
+	dark = style->dark[GTK_STATE_NORMAL];
+
+	/* The start and end of the long horizontal line between hours. */
+	long_line_x1 = (use_zone ? 0 : E_DVTMI_TIME_GRID_X_PAD) - x + x_offset;
+	long_line_x2 = time_item->priv->column_width - E_DVTMI_TIME_GRID_X_PAD - x - (use_zone ? E_DVTMI_TIME_GRID_X_PAD : 0) + x_offset;
+
+	if (day_view->mins_per_row == 60) {
+		/* The right edge of the complete time string in 60-min
+		   divisions, e.g. "14:00" or "2 pm". */
+		minute_x2 = long_line_x2 - E_DVTMI_60_MIN_X_PAD;
+
+		/* These aren't used for 60-minute divisions, but we initialize
+		   them to keep gcc happy. */
+		short_line_x1 = 0;
+		large_hour_x2 = 0;
+	} else {
+		max_suffix_width = MAX (day_view->am_string_width,
+					day_view->pm_string_width);
+
+		max_minute_or_suffix_width = MAX (max_suffix_width,
+						  day_view->max_minute_width);
+
+		/* The start of the short horizontal line between the periods
+		   within each hour. */
+		short_line_x1 = long_line_x2 - E_DVTMI_MIN_X_PAD * 2
+			- max_minute_or_suffix_width;
+
+		/* The right edge of the large hour string. */
+		large_hour_x2 = short_line_x1 - E_DVTMI_HOUR_R_PAD;
+
+		/* The right edge of the minute part of the time. */
+		minute_x2 = long_line_x2 - E_DVTMI_MIN_X_PAD;
+	}
+
+	/* Start with the first hour & minute shown in the EDayView. */
+	hour = day_view->first_hour_shown;
+	minute = day_view->first_minute_shown;
+
+	if (use_zone) {
+		/* shift time with a difference between local time and the other timezone */
+		icaltimezone *cal_zone = e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view));
+		struct icaltimetype tt;
+		gint diff;
+		struct tm mn;
+
+		tt = icaltime_from_timet_with_zone (day_view->day_starts[0], 0, cal_zone);
+
+		/* diff is number of minutes */
+		diff = (icaltimezone_get_utc_offset (use_zone, &tt, NULL) -
+			icaltimezone_get_utc_offset (cal_zone, &tt, NULL)
+		       ) / 60;
+
+		tt = icaltime_from_timet_with_zone (day_view->day_starts[0], 0, cal_zone);
+		tt.is_date = FALSE;
+		icaltime_set_timezone (&tt, cal_zone);
+		tt = icaltime_convert_to_zone (tt, use_zone);
+
+		if (diff != 0) {
+			/* shows the next midnight */
+			icaltime_adjust (&tt, 1, 0, 0, 0);
+		}
+
+		mn = icaltimetype_to_tm (&tt);
+
+		/* up to two characters/numbers */
+		e_utf8_strftime (buffer, sizeof (buffer), "%d", &mn);
+		midnight_day = g_strdup (buffer);
+		/* up to three characters, abbreviated month name */
+		e_utf8_strftime (buffer, sizeof (buffer), "%b", &mn);
+		midnight_month = g_strdup (buffer);
+
+		minute += (diff % 60);
+		hour += (diff / 60) + (minute / 60);
+
+		minute = minute % 60;
+		if (minute < 0) {
+			hour--;
+			minute += 60;
+		}
+
+		hour = (hour + 48) % 24;
+	}
+
+	/* The offset of the large hour string from the top of the row. */
+	large_hour_y_offset = E_DVTMI_LARGE_HOUR_Y_PAD;
+
+	/* The offset of the small time/minute string from top of row. */
+	small_font_y_offset = E_DVTMI_SMALL_FONT_Y_PAD;
+
+	/* Calculate the minimum y position of the first row we need to draw.
+	   This is normally one row height above the 0 position, but if we
+	   are using the large font we may have to go back a bit further. */
+	start_y = 0 - MAX (day_view->row_height,
+			   (pango_font_metrics_get_ascent (large_font_metrics) +
+			    pango_font_metrics_get_descent (large_font_metrics)) / PANGO_SCALE +
+			   E_DVTMI_LARGE_HOUR_Y_PAD);
+
+	/* Draw the Marcus Bains Line first, so it appears under other elements. */
+	if (e_day_view_marcus_bains_get_show_line (day_view)) {
+		edvti_draw_marcus_bains (canvas_item,
+					x, y,
+					width, height,
+					x_offset, use_zone);
+	} else {
+		mb_color = day_view->colors[E_DAY_VIEW_COLOR_MARCUS_BAINS_LINE];
+
+		if (day_view->marcus_bains_time_bar_color && gdk_color_parse (day_view->marcus_bains_time_bar_color, &mb_color)) {
+			GdkColormap *colormap;
+
+			colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
+			if (gdk_colormap_alloc_color (colormap, &mb_color, TRUE, TRUE)) {
+				gdk_cairo_set_source_color (cr, &mb_color);
+			}
+		}
+	}
+
+	/* Step through each row, drawing the times and the horizontal lines
+	   between them. */
+	for (row = 0, row_y = 0 - y;
+	     row < day_view->rows && row_y < height;
+	     row++, row_y += day_view->row_height) {
+		gboolean show_midnight_date = use_zone && hour == 0 && (minute == 0 || day_view->mins_per_row == 60) && midnight_day && midnight_month;
+
+		/* If the row is above the first row we want to draw just
+		   increment the time and skip to the next row. */
+		if (row_y < start_y) {
+			e_day_view_clutter_time_item_increment_time (&hour, &minute,
+							     day_view->mins_per_row);
+			continue;
+		}
+
+		/* Calculate the actual hour number to display. For 12-hour
+		   format we convert 0-23 to 12-11am/12-11pm. */
+		e_day_view_convert_time_to_display (day_view, hour,
+						    &display_hour,
+						    &suffix, &suffix_width);
+
+		if (day_view->mins_per_row == 60) {
+			/* 60 minute intervals - draw a long horizontal line
+			   between hours and display as one long string,
+			   e.g. "14:00" or "2 pm". */
+			cairo_save (cr);
+			gdk_cairo_set_source_color (cr, &dark);
+			cairo_save (cr);
+			cairo_set_line_width (cr, 0.7);
+			cairo_move_to (cr, long_line_x1, row_y);
+			cairo_line_to (cr, long_line_x2, row_y);
+			cairo_stroke (cr);
+			cairo_restore (cr);
+
+			if (show_midnight_date) {
+				strcpy (buffer, midnight_day);
+				strcat (buffer, " ");
+				strcat (buffer, midnight_month);
+			} else if (e_cal_model_get_use_24_hour_format (model)) {
+				g_snprintf (buffer, sizeof (buffer), "%i:%02i",
+					    display_hour, minute);
+			} else {
+				g_snprintf (buffer, sizeof (buffer), "%i %s",
+					    display_hour, suffix);
+			}
+
+			cairo_save (cr);
+			if (show_midnight_date)
+				gdk_cairo_set_source_color (cr, &mb_color);
+			else
+				gdk_cairo_set_source_color (cr, &fg);
+			layout = pango_cairo_create_layout (cr);
+			pango_layout_set_text (layout, buffer, -1);
+			pango_layout_get_pixel_size (layout, &minute_width, NULL);
+			cairo_translate (cr, minute_x2 - minute_width, row_y + small_font_y_offset);
+			pango_cairo_update_layout (cr, layout);
+			pango_cairo_show_layout (cr, layout);
+			cairo_restore (cr);
+
+			g_object_unref (layout);
+		} else {
+			/* 5/10/15/30 minute intervals. */
+
+			if (minute == 0) {
+				/* On the hour - draw a long horizontal line
+				   before the hour and display the hour in the
+				   large font. */
+
+				cairo_save (cr);
+				gdk_cairo_set_source_color (cr, &dark);
+				if (show_midnight_date)
+					strcpy (buffer, midnight_day);
+				else
+					g_snprintf (buffer, sizeof (buffer), "%i",
+						    display_hour);
+
+				cairo_set_line_width (cr, 0.7);
+				cairo_move_to (cr, long_line_x1, row_y);
+				cairo_line_to (cr, long_line_x2, row_y);
+				cairo_stroke (cr);
+				cairo_restore (cr);
+
+				cairo_save (cr);
+				if (show_midnight_date)
+					gdk_cairo_set_source_color (cr, &mb_color);
+				else
+					gdk_cairo_set_source_color (cr, &fg);
+				layout = pango_cairo_create_layout (cr);
+				pango_layout_set_text (layout, buffer, -1);
+				pango_layout_set_font_description (layout, day_view->large_font_desc);
+				pango_layout_get_pixel_size (layout, &hour_width, NULL);
+				cairo_translate (cr, large_hour_x2 - hour_width, row_y + large_hour_y_offset);
+				pango_cairo_update_layout (cr, layout);
+				pango_cairo_show_layout (cr, layout);
+				cairo_restore (cr);
+
+				g_object_unref (layout);
+			} else {
+				/* Within the hour - draw a short line before
+				   the time. */
+				cairo_save (cr);
+				gdk_cairo_set_source_color (cr, &dark);
+				cairo_set_line_width (cr, 0.7);
+				cairo_move_to (cr, short_line_x1, row_y);
+				cairo_line_to (cr, long_line_x2, row_y);
+				cairo_stroke (cr);
+				cairo_restore (cr);
+			}
+
+			/* Normally we display the minute in each
+			   interval, but when using 30-minute intervals
+			   we don't display the '30'. */
+			if (day_view->mins_per_row != 30 || minute != 30) {
+				/* In 12-hour format we display 'am' or 'pm'
+				   instead of '00'. */
+				if (show_midnight_date)
+					strcpy (buffer, midnight_month);
+				else if (minute == 0
+				    && !e_cal_model_get_use_24_hour_format (model)) {
+					strcpy (buffer, suffix);
+				} else {
+					g_snprintf (buffer, sizeof (buffer),
+						    "%02i", minute);
+				}
+
+				cairo_save (cr);
+				if (show_midnight_date)
+					gdk_cairo_set_source_color (cr, &mb_color);
+				else
+					gdk_cairo_set_source_color (cr, &fg);
+				layout = pango_cairo_create_layout (cr);
+				pango_layout_set_text (layout, buffer, -1);
+				pango_layout_set_font_description (layout, day_view->small_font_desc);
+				pango_layout_get_pixel_size (layout, &minute_width, NULL);
+				cairo_translate (cr, minute_x2 - minute_width, row_y + small_font_y_offset);
+				pango_cairo_update_layout (cr, layout);
+				pango_cairo_show_layout (cr, layout);
+				cairo_restore (cr);
+
+				g_object_unref (layout);
+			}
+		}
+
+		e_day_view_clutter_time_item_increment_time (&hour, &minute,
+						     day_view->mins_per_row);
+	}
+
+	pango_font_metrics_unref (large_font_metrics);
+	pango_font_metrics_unref (small_font_metrics);
+	cairo_destroy (cr);
+
+	g_free (midnight_day);
+	g_free (midnight_month);
+}
+
+static void
+e_day_view_clutter_time_item_draw (ClutterActor *canvas_item)
+{
+	EDayViewClutterTimeItem *time_item;
+	gint x=0;
+	gint y=0;
+	guint width;
+	guint height;
+
+	time_item = E_DAY_VIEW_CLUTTER_TIME_ITEM (canvas_item);
+	g_return_if_fail (time_item != NULL);
+
+	clutter_cairo_texture_get_surface_size ((ClutterCairoTexture *)canvas_item, &width, &height);
+	
+	edvti_draw_zone (canvas_item, x, y, width, height, 0, NULL);
+
+	if (time_item->priv->second_zone)
+		edvti_draw_zone (canvas_item, x, y, width, height, time_item->priv->column_width, time_item->priv->second_zone);
+}
+
+void
+e_day_view_clutter_time_item_redraw (EDayViewClutterTimeItem *item)
+{
+	if (item->priv->mb_line)
+		clutter_cairo_texture_clear ((ClutterCairoTexture *)item->priv->mb_line);
+	if (item->priv->mb_line_alt)
+		clutter_cairo_texture_clear ((ClutterCairoTexture *)item->priv->mb_line_alt);
+	clutter_cairo_texture_clear ((ClutterCairoTexture *)item);
+	e_day_view_clutter_time_item_draw ((ClutterActor *)item);
+}
+
+void
+e_day_view_clutter_time_item_update (EDayViewClutterTimeItem *item)
+{
+	struct icaltimetype time_now;
+	gint marcus_bains_y;
+	int y = 0;
+	EDayView *day_view;
+	
+	day_view = e_day_view_clutter_time_item_get_day_view (item);
+	
+	time_now = icaltime_current_time_with_zone (e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view)));
+	marcus_bains_y = (time_now.hour * 60 + time_now.minute) * day_view->row_height / day_view->mins_per_row - y;
+
+	if (item->priv->mb_line) {
+		clutter_actor_animate (item->priv->mb_line,
+				CLUTTER_LINEAR, 200,
+				"y", (float) marcus_bains_y,
+				NULL);
+	}
+	if (item->priv->mb_line_alt) {
+		clutter_actor_animate (item->priv->mb_line_alt,
+				CLUTTER_LINEAR, 200,
+				"y", (float) marcus_bains_y,
+				NULL);
+	}
+}
+
+/* Increment the time by the 5/10/15/30/60 minute interval.
+   Note that mins_per_row is never > 60, so we never have to
+   worry about adding more than 60 minutes. */
+static void
+e_day_view_clutter_time_item_increment_time	(gint	*hour,
+					 gint	*minute,
+					 gint	 mins_per_row)
+{
+	*minute += mins_per_row;
+	if (*minute >= 60) {
+		*minute -= 60;
+		/* Currently we never wrap around to the next day, but
+		   we may do if we display extra timezones. */
+		*hour = (*hour + 1) % 24;
+	}
+}
+
+static double
+e_day_view_clutter_time_item_point (ClutterActor *item, double x, double y,
+			    gint cx, gint cy,
+			    ClutterActor **actual_item)
+{
+	*actual_item = item;
+	return 0.0;
+}
+
+static gint
+e_day_view_clutter_time_item_event (ClutterActor *item,
+			    ClutterEvent *event)
+{
+	EDayViewClutterTimeItem *time_item;
+
+	time_item = E_DAY_VIEW_CLUTTER_TIME_ITEM (item);
+
+	switch (event->type) {
+	case CLUTTER_BUTTON_PRESS:
+		if (event->button.button == 1) {
+			e_day_view_clutter_time_item_on_button_press (time_item, event);
+		} else if (event->button.button == 3) {
+			e_day_view_clutter_time_item_show_popup_menu (time_item, event);
+			return TRUE;
+		}
+		break;
+	case CLUTTER_BUTTON_RELEASE:
+		if (event->button.button == 1)
+			e_day_view_clutter_time_item_on_button_release (time_item,
+								event);
+		break;
+
+	case CLUTTER_MOTION:
+		e_day_view_clutter_time_item_on_motion_notify (time_item, event);
+		break;
+
+	default:
+		break;
+	}
+
+	return FALSE;
+}
+
+static void
+edvti_second_zone_changed_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data)
+{
+	EDayViewClutterTimeItem *time_item = user_data;
+	EDayView *day_view;
+	gchar *location;
+
+	g_return_if_fail (user_data != NULL);
+	g_return_if_fail (E_IS_DAY_VIEW_CLUTTER_TIME_ITEM (time_item));
+
+	location = calendar_config_get_day_second_zone ();
+	time_item->priv->second_zone = location ? icaltimezone_get_builtin_timezone (location) : NULL;
+	g_free (location);
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	gtk_widget_set_size_request (day_view->time_canvas, e_day_view_clutter_time_item_get_column_width (time_item), -1);
+	e_day_view_clutter_time_item_redraw (day_view->time_canvas_actor);
+}
+
+static void
+edvti_on_select_zone (GtkWidget *item, EDayViewClutterTimeItem *time_item)
+{
+	calendar_config_select_day_second_zone ();
+}
+
+static void
+edvti_on_set_zone (GtkWidget *item, EDayViewClutterTimeItem *time_item)
+{
+	if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
+		return;
+
+	calendar_config_set_day_second_zone (g_object_get_data (G_OBJECT (item), "timezone"));
+}
+
+static void
+e_day_view_clutter_time_item_show_popup_menu (EDayViewClutterTimeItem *time_item,
+				      ClutterEvent *event)
+{
+	static gint divisions[] = { 60, 30, 15, 10, 5 };
+	EDayView *day_view;
+	GtkWidget *menu, *item, *submenu;
+	gchar buffer[256];
+	GSList *group = NULL, *recent_zones, *s;
+	gint current_divisions, i;
+	icaltimezone *zone;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+
+	current_divisions = e_day_view_get_mins_per_row (day_view);
+
+	menu = gtk_menu_new ();
+
+	/* Make sure the menu is destroyed when it disappears. */
+	g_signal_connect (
+		menu, "selection-done",
+		G_CALLBACK (gtk_widget_destroy), NULL);
+
+	for (i = 0; i < G_N_ELEMENTS (divisions); i++) {
+		g_snprintf (buffer, sizeof (buffer),
+		/* TO TRANSLATORS: %02i is the number of minutes; this is a context menu entry
+		 * to change the length of the time division in the calendar day view, e.g.
+		 * a day is displayed in 24 "60 minute divisions" or 48 "30 minute divisions"
+		 */
+			    _("%02i minute divisions"), divisions[i]);
+		item = gtk_radio_menu_item_new_with_label (group, buffer);
+		group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+		gtk_widget_show (item);
+		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+		if (current_divisions == divisions[i])
+			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+
+		g_object_set_data (G_OBJECT (item), "divisions",
+				   GINT_TO_POINTER (divisions[i]));
+
+		g_signal_connect (item, "toggled",
+				  G_CALLBACK (e_day_view_clutter_time_item_on_set_divisions), time_item);
+	}
+
+	item = gtk_separator_menu_item_new ();
+	gtk_widget_show (item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+	submenu = gtk_menu_new ();
+	item = gtk_menu_item_new_with_label (_("Show the second time zone"));
+	gtk_widget_show (item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+	gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+
+	zone = e_calendar_view_get_timezone (E_CALENDAR_VIEW (day_view));
+	if (zone)
+		item = gtk_menu_item_new_with_label (icaltimezone_get_display_name (zone));
+	else
+		item = gtk_menu_item_new_with_label ("---");
+	gtk_widget_set_sensitive (item, FALSE);
+	gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+
+	item = gtk_separator_menu_item_new ();
+	gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+
+	group = NULL;
+	item = gtk_radio_menu_item_new_with_label (group, C_("cal-second-zone", "None"));
+	group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+	if (!time_item->priv->second_zone)
+		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+	gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+	g_signal_connect (item, "toggled", G_CALLBACK (edvti_on_set_zone), time_item);
+
+	recent_zones = calendar_config_get_day_second_zones ();
+	for (s = recent_zones; s != NULL; s = s->next) {
+		zone = icaltimezone_get_builtin_timezone (s->data);
+		if (!zone)
+			continue;
+
+		item = gtk_radio_menu_item_new_with_label (group, icaltimezone_get_display_name (zone));
+		group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+		/* both comes from builtin, thus no problem to compare pointers */
+		if (zone == time_item->priv->second_zone)
+			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+		gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+		g_object_set_data_full (G_OBJECT (item), "timezone", g_strdup (s->data), g_free);
+		g_signal_connect (item, "toggled", G_CALLBACK (edvti_on_set_zone), time_item);
+	}
+	calendar_config_free_day_second_zones (recent_zones);
+
+	item = gtk_separator_menu_item_new ();
+	gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+
+	item = gtk_menu_item_new_with_label (_("Select..."));
+	g_signal_connect (item, "activate", G_CALLBACK (edvti_on_select_zone), time_item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+
+	gtk_widget_show_all (submenu);
+
+	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
+			event->button.button, event->button.time);
+}
+
+static void
+e_day_view_clutter_time_item_on_set_divisions (GtkWidget *item,
+				       EDayViewClutterTimeItem *time_item)
+{
+	EDayView *day_view;
+	gint divisions;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+
+	if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
+		return;
+
+	divisions = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "divisions"));
+	e_day_view_set_mins_per_row (day_view, divisions);
+	calendar_config_set_time_divisions (divisions);
+}
+
+static void
+e_day_view_clutter_time_item_on_button_press (EDayViewClutterTimeItem *time_item,
+				      ClutterEvent *event)
+{
+	GdkWindow *window;	
+	EDayView *day_view;
+	gint row;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+
+	row = e_day_view_clutter_time_item_convert_position_to_row (time_item,
+							    event->button.y);
+
+	if (row == -1)
+		return;
+
+	if (!gtk_widget_has_focus (GTK_WIDGET (day_view)))
+		gtk_widget_grab_focus (GTK_WIDGET (day_view));
+
+	window = gtk_layout_get_bin_window ((GtkLayout *)day_view->time_canvas);
+
+	/* FIXME: This pointer grab seems unnecessary */
+	if (1 || gdk_pointer_grab (window, FALSE,
+			      GDK_POINTER_MOTION_MASK
+			      | GDK_BUTTON_RELEASE_MASK,
+			      NULL, NULL, event->button.time) == 0) {
+		e_day_view_start_selection (day_view, -1, row);
+		time_item->priv->dragging_selection = TRUE;
+	}
+}
+
+static void
+e_day_view_clutter_time_item_on_button_release (EDayViewClutterTimeItem *time_item,
+					ClutterEvent *event)
+{
+	EDayView *day_view;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+
+	if (time_item->priv->dragging_selection) {
+		/* gdk_pointer_ungrab (event->button.time); */
+		e_day_view_finish_selection (day_view);
+		e_day_view_stop_auto_scroll (day_view);
+	}
+
+	time_item->priv->dragging_selection = FALSE;
+}
+
+static void
+e_day_view_clutter_time_item_on_motion_notify (EDayViewClutterTimeItem *time_item,
+				       ClutterEvent *event)
+{
+	EDayView *day_view;
+	gint y, row;
+
+	if (!time_item->priv->dragging_selection)
+		return;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_if_fail (day_view != NULL);
+
+	y = (gint)event->motion.y;
+	row = e_day_view_clutter_time_item_convert_position_to_row (time_item, y);
+
+	if (row != -1) {
+		/* FIXME: Check if this works well */
+		e_day_view_update_selection (day_view, -1, row);
+		e_day_view_check_auto_scroll (day_view, -1, (gint) y);
+	}
+}
+
+/* Returns the row corresponding to the y position, or -1. */
+static gint
+e_day_view_clutter_time_item_convert_position_to_row (EDayViewClutterTimeItem *time_item,
+					      gint y)
+{
+	EDayView *day_view;
+	gint row;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_val_if_fail (day_view != NULL, -1);
+
+	if (y < 0)
+		return -1;
+
+	row = y / day_view->row_height;
+	if (row >= day_view->rows)
+		return -1;
+
+	return row;
+}
+
+EDayView *
+e_day_view_clutter_time_item_get_day_view (EDayViewClutterTimeItem *time_item)
+{
+	g_return_val_if_fail (E_IS_DAY_VIEW_CLUTTER_TIME_ITEM (time_item), NULL);
+
+	return time_item->priv->day_view;
+}
+
+void
+e_day_view_clutter_time_item_set_day_view (EDayViewClutterTimeItem *time_item,
+                                   EDayView *day_view)
+{
+	g_return_if_fail (E_IS_DAY_VIEW_CLUTTER_TIME_ITEM (time_item));
+	g_return_if_fail (E_IS_DAY_VIEW (day_view));
+
+	if (time_item->priv->day_view != NULL)
+		g_object_unref (time_item->priv->day_view);
+
+	time_item->priv->day_view = g_object_ref (day_view);
+
+	g_object_notify (G_OBJECT (time_item), "day-view");
+}
+
+/* Returns the minimum width needed for the column, by adding up all the
+   maximum widths of the strings. The string widths are all calculated in
+   the style_set handlers of EDayView and EDayViewClutterTimeCanvas. */
+gint
+e_day_view_clutter_time_item_get_column_width (EDayViewClutterTimeItem *time_item)
+{
+	EDayView *day_view;
+	GtkStyle *style;
+	gint digit, large_digit_width, max_large_digit_width = 0;
+	gint max_suffix_width, max_minute_or_suffix_width;
+	gint column_width_default, column_width_60_min_rows;
+
+	day_view = e_day_view_clutter_time_item_get_day_view (time_item);
+	g_return_val_if_fail (day_view != NULL, 0);
+
+	style = gtk_widget_get_style (GTK_WIDGET (day_view));
+	g_return_val_if_fail (style != NULL, 0);
+
+	/* Find the maximum width a digit can have. FIXME: We could use pango's
+	 * approximation function, but I worry it won't be precise enough. Also
+	 * it needs a language tag that I don't know where to get. */
+	for (digit = '0'; digit <= '9'; digit++) {
+		PangoLayout *layout;
+		gchar digit_str [2];
+
+		digit_str [0] = digit;
+		digit_str [1] = '\0';
+
+		layout = gtk_widget_create_pango_layout (GTK_WIDGET (day_view), digit_str);
+		pango_layout_set_font_description (layout, day_view->large_font_desc);
+		pango_layout_get_pixel_size (layout, &large_digit_width, NULL);
+
+		g_object_unref (layout);
+
+		max_large_digit_width = MAX (max_large_digit_width,
+					     large_digit_width);
+	}
+
+	/* Calculate the width of each time column, using the maximum of the
+	   default format with large hour numbers, and the 60-min divisions
+	   format which uses small text. */
+	max_suffix_width = MAX (day_view->am_string_width,
+				day_view->pm_string_width);
+
+	max_minute_or_suffix_width = MAX (max_suffix_width,
+					  day_view->max_minute_width);
+
+	column_width_default = max_large_digit_width * 2
+		+ max_minute_or_suffix_width
+		+ E_DVTMI_MIN_X_PAD * 2
+		+ E_DVTMI_HOUR_L_PAD
+		+ E_DVTMI_HOUR_R_PAD
+		+ E_DVTMI_TIME_GRID_X_PAD * 2;
+
+	column_width_60_min_rows = day_view->max_small_hour_width
+		+ day_view->colon_width
+		+ max_minute_or_suffix_width
+		+ E_DVTMI_60_MIN_X_PAD * 2
+		+ E_DVTMI_TIME_GRID_X_PAD * 2;
+
+	time_item->priv->column_width =
+		MAX (column_width_default, column_width_60_min_rows);
+
+	if (time_item->priv->second_zone)
+		return (2 * time_item->priv->column_width) -
+			E_DVTMI_TIME_GRID_X_PAD;
+
+	return time_item->priv->column_width;
+}
+
+icaltimezone *
+e_day_view_clutter_time_item_get_second_zone (EDayViewClutterTimeItem *time_item)
+{
+	g_return_val_if_fail (E_IS_DAY_VIEW_CLUTTER_TIME_ITEM (time_item), NULL);
+
+	return time_item->priv->second_zone;
+}
+
+EDayViewClutterTimeItem *
+e_day_view_clutter_time_item_new (EDayView *day_view, gint width, gint height)
+{
+	EDayViewClutterTimeItem *item;
+
+	item =  g_object_new (
+			E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM,
+			"EDayViewClutterTimeItem::day_view", day_view,
+                       "surface-width", 50,
+                       "surface-height", 300,			
+			NULL); 
+
+	e_day_view_clutter_time_item_draw ((ClutterActor *)item);
+
+	return item;
+}
+
+void
+e_day_view_clutter_time_item_set_size (EDayViewClutterTimeItem *item, int width, int height)
+{
+	clutter_cairo_texture_set_surface_size ((ClutterCairoTexture *)item, width, height);
+	e_day_view_clutter_time_item_redraw (item);
+}
+
diff --git a/calendar/gui/e-day-view-clutter-time-item.h b/calendar/gui/e-day-view-clutter-time-item.h
new file mode 100644
index 0000000..c246c44
--- /dev/null
+++ b/calendar/gui/e-day-view-clutter-time-item.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *		Srinivasa Ragavan <sragavan gnome org>
+ *
+ * Copyright (C) 2010 Intel Corporation. (www.intel.com)
+ *
+ */
+
+#ifndef E_DAY_VIEW_CLUTTER_TIME_ITEM_H
+#define E_DAY_VIEW_CLUTTER_TIME_ITEM_H
+
+#include "e-day-view.h"
+
+/* Standard GObject macros */
+#define E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM \
+	(e_day_view_clutter_time_item_get_type ())
+#define E_DAY_VIEW_CLUTTER_TIME_ITEM(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM, EDayViewClutterTimeItem))
+#define E_DAY_VIEW_CLUTTER_TIME_ITEM_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM, EDayViewClutterTimeItemClass))
+#define E_IS_DAY_VIEW_CLUTTER_TIME_ITEM(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM))
+#define E_IS_DAY_VIEW_CLUTTER_TIME_ITEM_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM))
+#define E_DAY_VIEW_CLUTTER_TIME_ITEM_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM, EDayViewClutterTimeItemClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EDayViewClutterTimeItem EDayViewClutterTimeItem;
+typedef struct _EDayViewClutterTimeItemClass EDayViewClutterTimeItemClass;
+typedef struct _EDayViewClutterTimeItemPrivate EDayViewClutterTimeItemPrivate;
+
+struct _EDayViewClutterTimeItem {
+	ClutterCairoTexture parent;
+	EDayViewClutterTimeItemPrivate *priv;
+	ClutterActor *stage;
+};
+
+struct _EDayViewClutterTimeItemClass {
+	ClutterCairoTextureClass parent_class;
+};
+
+GType		e_day_view_clutter_time_item_get_type	(void);
+EDayView *	e_day_view_clutter_time_item_get_day_view
+						(EDayViewClutterTimeItem *time_item);
+void		e_day_view_clutter_time_item_set_day_view
+						(EDayViewClutterTimeItem *time_item,
+						 EDayView *day_view);
+gint		e_day_view_clutter_time_item_get_column_width
+						(EDayViewClutterTimeItem *time_item);
+icaltimezone *	e_day_view_clutter_time_item_get_second_zone
+						(EDayViewClutterTimeItem *time_item);
+void		e_day_view_clutter_time_item_redraw 
+						(EDayViewClutterTimeItem *item);
+void		e_day_view_clutter_time_item_update 
+						(EDayViewClutterTimeItem *item);
+EDayViewClutterTimeItem *	
+		e_day_view_clutter_time_item_new(EDayView *day_view, 
+						 gint width, 
+						 gint height);
+void		e_day_view_clutter_time_item_set_size 
+						(EDayViewClutterTimeItem *item, 
+						 int width, 
+						 int height);
+						
+
+G_END_DECLS
+
+#endif /* E_DAY_VIEW_CLUTTER_TIME_ITEM_H */
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 95bd14b..cea0100 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -55,6 +55,9 @@
 #include "calendar-config.h"
 #include "goto.h"
 #include "e-cal-model-calendar.h"
+#if HAVE_CLUTTER
+#include "e-day-view-clutter-time-item.h"
+#endif
 #include "e-day-view-time-item.h"
 #include "e-day-view-top-item.h"
 #include "e-day-view-layout.h"
@@ -97,6 +100,7 @@
    caption item and DnD space */
 #define E_DAY_VIEW_MAX_ROWS_AT_TOP     6
 
+#define WITHOUT_CLUTTER (g_getenv("WITHOUT_CLUTTER") != NULL)
 typedef struct {
 	EDayView *day_view;
 	ECalModelComponent *comp_data;
@@ -780,9 +784,19 @@ time_range_changed_cb (ECalModel *model, time_t start_time, time_t end_time, gpo
 		e_day_view_ensure_rows_visible (day_view, day_view->selection_start_row, day_view->selection_start_row);
 
 	/* update the time canvas to show proper date in it */
+#if HAVE_CLUTTER
+	if (WITHOUT_CLUTTER) {
+#endif
 	eti = E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item);
 	if (eti && e_day_view_time_item_get_second_zone (eti))
 		gtk_widget_queue_draw (day_view->time_canvas);
+#if HAVE_CLUTTER
+	} else {
+		
+	if (day_view->time_canvas_actor && e_day_view_clutter_time_item_get_second_zone (day_view->time_canvas_actor))
+		e_day_view_clutter_time_item_redraw (day_view->time_canvas_actor);
+	}
+#endif	
 }
 
 static void
@@ -979,6 +993,25 @@ timezone_changed_cb (ECalModel *cal_model, icaltimezone *old_zone,
 	e_day_view_update_query (day_view);
 }
 
+static void                
+time_canvas_set_canvas_size (GtkWidget     *widget,
+		 GtkAllocation *allocation,
+		  EDayView *day_view)
+{
+	ClutterActor *stage = day_view->time_canvas_stage;
+	GtkWidget *embed = day_view->time_canvas_embed;
+	guint w,h;
+
+	gtk_layout_get_size ((GtkLayout *)day_view->main_canvas, &w, &h);
+
+	gtk_widget_set_size_request (embed, allocation->width, h);
+	gtk_layout_set_size ((GtkLayout *)widget, allocation->width, h);
+	
+	clutter_actor_set_size (stage, allocation->width, h);
+	clutter_actor_set_size ((ClutterActor *)day_view->time_canvas_actor, allocation->width, h);
+	e_day_view_clutter_time_item_set_size ((EDayViewClutterTimeItem *)day_view->time_canvas_actor, allocation->width, h);
+}
+
 static void
 e_day_view_init (EDayView *day_view)
 {
@@ -1243,11 +1276,26 @@ e_day_view_init (EDayView *day_view)
 	/*
 	 * Times Canvas
 	 */
+#if HAVE_CLUTTER
+	if (WITHOUT_CLUTTER) {
+#endif
 	day_view->time_canvas = e_canvas_new ();
 	layout = GTK_LAYOUT (day_view->main_canvas);
 	adjustment = gtk_layout_get_vadjustment (layout);
 	layout = GTK_LAYOUT (day_view->time_canvas);
 	gtk_layout_set_vadjustment (layout, adjustment);
+#if HAVE_CLUTTER
+	} else {
+	layout = GTK_LAYOUT (day_view->main_canvas);
+	adjustment = gtk_layout_get_vadjustment (layout);		
+	day_view->time_canvas = gtk_layout_new (NULL, adjustment);
+	day_view->time_canvas_embed = gtk_clutter_embed_new ();
+	gtk_widget_show (day_view->time_canvas_embed);
+	gtk_container_add ((GtkContainer *)day_view->time_canvas, day_view->time_canvas_embed);
+	day_view->time_canvas_stage = gtk_clutter_embed_get_stage ((GtkClutterEmbed *) day_view->time_canvas_embed);
+	g_signal_connect (day_view->time_canvas, "size-allocate", G_CALLBACK(time_canvas_set_canvas_size), day_view);
+	}
+#endif	
 	gtk_table_attach (GTK_TABLE (day_view), day_view->time_canvas,
 			  0, 1, 1, 2,
 			  GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
@@ -1255,14 +1303,29 @@ e_day_view_init (EDayView *day_view)
 	g_signal_connect_after (day_view->time_canvas, "scroll_event",
 				G_CALLBACK (e_day_view_on_time_canvas_scroll), day_view);
 
+#if HAVE_CLUTTER	
+	if (WITHOUT_CLUTTER) {	
+#endif		
 	canvas_group = GNOME_CANVAS_GROUP (GNOME_CANVAS (day_view->time_canvas)->root);
-
 	day_view->time_canvas_item =
 		gnome_canvas_item_new (canvas_group,
 				       e_day_view_time_item_get_type (),
 				       "EDayViewTimeItem::day_view", day_view,
 				       NULL);
-
+#if HAVE_CLUTTER
+	} else {
+	day_view->time_canvas_actor = g_object_new (
+			E_TYPE_DAY_VIEW_CLUTTER_TIME_ITEM,
+			"EDayViewClutterTimeItem::day_view", day_view,
+                       "surface-width", 64,
+                       "surface-height", 600,			
+			NULL);
+	clutter_actor_set_reactive ((ClutterActor *)day_view->time_canvas_actor, TRUE);
+	((EDayViewClutterTimeItem *)day_view->time_canvas_actor)->stage = day_view->time_canvas_stage;
+	clutter_container_add_actor ((ClutterContainer *)day_view->time_canvas_stage, (ClutterActor *)day_view->time_canvas_actor);
+	clutter_actor_show ((ClutterActor *)day_view->time_canvas_actor);
+	}
+#endif	
 	/*
 	 * Scrollbar.
 	 */
@@ -1764,7 +1827,15 @@ e_day_view_style_set (GtkWidget *widget,
 	pango_layout_get_pixel_size (layout, &day_view->pm_string_width, NULL);
 
 	/* Calculate the width of the time column. */
+#if HAVE_CLUTTER
+	if(WITHOUT_CLUTTER) {
+#endif		
 	times_width = e_day_view_time_item_get_column_width (E_DAY_VIEW_TIME_ITEM (day_view->time_canvas_item));
+#if HAVE_CLUTTER
+	} else {
+	times_width = e_day_view_clutter_time_item_get_column_width (E_DAY_VIEW_CLUTTER_TIME_ITEM (day_view->time_canvas_actor));
+	}
+#endif	
 	gtk_widget_set_size_request (day_view->time_canvas, times_width, -1);
 
 	g_object_unref (layout);
@@ -2751,10 +2822,32 @@ e_day_view_set_mins_per_row (EDayView *day_view,
 	/* We must layout the events before updating the scroll region, since
 	   that will result in a redraw which would crash otherwise. */
 	e_day_view_check_layout (day_view);
-	gtk_widget_queue_draw (day_view->time_canvas);
+
 	gtk_widget_queue_draw (day_view->main_canvas);
 
 	e_day_view_update_scroll_regions (day_view);
+#if HAVE_CLUTTER
+	if (WITHOUT_CLUTTER) {
+#endif		
+	gtk_widget_queue_draw (day_view->time_canvas);
+#if HAVE_CLUTTER
+	} else {
+		ClutterActor *stage = day_view->time_canvas_stage;
+		GtkWidget *embed = day_view->time_canvas_embed;
+		guint w,h;
+		guint cw, ch;
+
+		gtk_layout_get_size ((GtkLayout *)day_view->main_canvas, &w, &h);
+		gtk_layout_get_size ((GtkLayout *)day_view->time_canvas, &cw, &ch);
+
+		gtk_widget_set_size_request (embed, cw, h);
+		gtk_layout_set_size ((GtkLayout *)day_view->time_canvas, cw, h);
+	
+		clutter_actor_set_size (stage, cw, h);
+		clutter_actor_set_size ((ClutterActor *)day_view->time_canvas_actor, cw, h);
+		e_day_view_clutter_time_item_set_size ((EDayViewClutterTimeItem *)day_view->time_canvas_actor, cw, h);
+	}
+#endif	
 }
 
 /* This specifies the working days in the week. The value is a bitwise
@@ -2920,7 +3013,15 @@ e_day_view_marcus_bains_update (EDayView *day_view)
 {
 	g_return_if_fail (E_IS_DAY_VIEW (day_view));
 	gtk_widget_queue_draw (day_view->main_canvas);
+#if HAVE_CLUTTER
+	if (WITHOUT_CLUTTER) {
+#endif		
 	gtk_widget_queue_draw (day_view->time_canvas);
+#if HAVE_CLUTTER
+	} else {
+	e_day_view_clutter_time_item_update (day_view->time_canvas_actor);
+	}
+#endif	
 }
 
 gboolean
diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h
index aee8be0..dc9fc3a 100644
--- a/calendar/gui/e-day-view.h
+++ b/calendar/gui/e-day-view.h
@@ -31,6 +31,12 @@
 #include "e-calendar-view.h"
 #include "gnome-cal.h"
 
+#if HAVE_CLUTTER
+#include <clutter/clutter.h>
+#include <mx/mx.h>
+#include <clutter-gtk/clutter-gtk.h>
+#endif
+
 G_BEGIN_DECLS
 
 /*
@@ -215,7 +221,9 @@ struct _EDayView {
 	/* The top canvas where the dates and long appointments are shown. */
 	GtkWidget *top_canvas;
 	GnomeCanvasItem *top_canvas_item;
-
+#if HAVE_CLUTTER
+	ClutterActor *top_canvas_actor;
+#endif
 	/* scrollbar for top_canvas */
 	GtkWidget *tc_vscrollbar;
 
@@ -225,10 +233,19 @@ struct _EDayView {
 	/* The main canvas where the rest of the appointments are shown. */
 	GtkWidget *main_canvas;
 	GnomeCanvasItem *main_canvas_item;
-
+#if HAVE_CLUTTER
+	ClutterActor *main_canvas_actor;
+	GtkWidget *main_canvas_embed;
+	ClutterActor *main_canvas_stage;
+#endif
 	/* The canvas displaying the times of the day. */
 	GtkWidget *time_canvas;
 	GnomeCanvasItem *time_canvas_item;
+#if HAVE_CLUTTER
+	GtkWidget *time_canvas_embed;
+	ClutterActor *time_canvas_stage;
+	ClutterActor *time_canvas_actor;
+#endif
 
 	GtkWidget *vscrollbar;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]