[evolution] Bug #300567 - Calendar drawing optimizations



commit f093350819edeba7728af7f216d1429f8bcd5926
Author: Milan Crha <mcrha redhat com>
Date:   Thu Jul 30 11:22:59 2009 +0200

    Bug #300567 - Calendar drawing optimizations

 calendar/gui/calendar-config-keys.h   |    4 +
 calendar/gui/calendar-config.c        |   21 ++
 calendar/gui/calendar-config.h        |    4 +
 calendar/gui/comp-util.c              |   26 ++-
 calendar/gui/comp-util.h              |    2 +-
 calendar/gui/e-day-view-main-item.c   |  448 ++++++++++++++-------------------
 calendar/gui/e-day-view-top-item.c    |   13 +-
 calendar/gui/e-day-view.c             |    4 +-
 calendar/gui/e-week-view-event-item.c |  331 ++++++++++++-------------
 calendar/gui/e-week-view.c            |    2 +-
 e-util/e-categories-config.c          |   72 ++++--
 e-util/e-categories-config.h          |    4 +-
 12 files changed, 441 insertions(+), 490 deletions(-)
---
diff --git a/calendar/gui/calendar-config-keys.h b/calendar/gui/calendar-config-keys.h
index deac5d5..7210e83 100644
--- a/calendar/gui/calendar-config-keys.h
+++ b/calendar/gui/calendar-config-keys.h
@@ -103,6 +103,10 @@ G_BEGIN_DECLS
 
 #define CALENDAR_CONFIG_DEF_RECUR_COUNT CALENDAR_CONFIG_PREFIX "/other/def_recur_count"
 
+/* drawing of events */
+#define CALENDAR_CONFIG_DISPLAY_EVENTS_GRADIENT CALENDAR_CONFIG_PREFIX "/display/events_gradient"
+#define CALENDAR_CONFIG_DISPLAY_EVENTS_ALPHA CALENDAR_CONFIG_PREFIX "/display/events_transparency"
+
 G_END_DECLS
 
 #endif
diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c
index 86c771f..2bc7357 100644
--- a/calendar/gui/calendar-config.c
+++ b/calendar/gui/calendar-config.c
@@ -40,6 +40,8 @@
 #include "calendar-config.h"
 
 static GConfClient *config = NULL;
+static gboolean display_events_gradient = TRUE;
+static gfloat display_events_alpha = 1.0;
 
 static void
 do_cleanup (void)
@@ -58,6 +60,9 @@ calendar_config_init (void)
 	g_atexit ((GVoidFunc) do_cleanup);
 
 	gconf_client_add_dir (config, CALENDAR_CONFIG_PREFIX, GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+
+	display_events_gradient = gconf_client_get_bool (config, CALENDAR_CONFIG_DISPLAY_EVENTS_GRADIENT, NULL);
+	display_events_alpha = gconf_client_get_float (config, CALENDAR_CONFIG_DISPLAY_EVENTS_ALPHA, NULL);
 }
 
 void
@@ -1736,3 +1741,19 @@ calendar_config_get_default_count (void)
 
 	return res;
 }
+
+gboolean
+calendar_config_get_display_events_gradient (void)
+{
+	calendar_config_init ();
+
+	return display_events_gradient;
+}
+
+gfloat
+calendar_config_get_display_events_alpha (void)
+{
+	calendar_config_init ();
+
+	return display_events_alpha;
+}
diff --git a/calendar/gui/calendar-config.h b/calendar/gui/calendar-config.h
index bbee7e6..53d636f 100644
--- a/calendar/gui/calendar-config.h
+++ b/calendar/gui/calendar-config.h
@@ -280,4 +280,8 @@ guint calendar_config_add_notification_month_scroll_by_week (GConfClientNotifyFu
 /* default count for recurring events */
 gint calendar_config_get_default_count (void);
 
+/* event drawing customization, one-time read on start only */
+gboolean calendar_config_get_display_events_gradient (void);
+gfloat   calendar_config_get_display_events_alpha (void);
+
 #endif /* _CALENDAR_CONFIG_H_ */
diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c
index 30af43f..a745b61 100644
--- a/calendar/gui/comp-util.c
+++ b/calendar/gui/comp-util.c
@@ -428,13 +428,16 @@ cal_comp_memo_new_with_defaults (ECal *client)
 /**
  * cal_comp_util_get_n_icons:
  * @comp: A calendar component object.
+ * @pixbufs: List of pixbufs to use. Can be NULL.
  *
  * Get the number of icons owned by the component.
+ * Each member of pixmaps should be freed with g_object_unref
+ * and the list itself should be freed too.
  *
  * Returns: the number of icons owned by the component.
  **/
 gint
-cal_comp_util_get_n_icons (ECalComponent *comp)
+cal_comp_util_get_n_icons (ECalComponent *comp, GSList **pixbufs)
 {
 	GSList *categories_list, *elem;
 	gint num_icons = 0;
@@ -444,16 +447,21 @@ cal_comp_util_get_n_icons (ECalComponent *comp)
 
 	e_cal_component_get_categories_list (comp, &categories_list);
 	for (elem = categories_list; elem; elem = elem->next) {
-		gchar *category;
-		GdkPixmap *pixmap = NULL;
-		GdkBitmap *mask = NULL;
+		const gchar *category;
+		GdkPixbuf *pixbuf = NULL;
+
+		category = elem->data;
+		if (e_categories_config_get_icon_for (category, &pixbuf)) {
+			if (!pixbuf)
+				continue;
 
-		category = (gchar *) elem->data;
-		if (e_categories_config_get_icon_for (category, &pixmap, &mask)) {
 			num_icons++;
-			g_object_unref (pixmap);
-			if (mask)
-				g_object_unref (mask);
+
+			if (pixbufs) {
+				*pixbufs = g_slist_append (*pixbufs, pixbuf);
+			} else {
+				g_object_unref (pixbuf);
+			}
 		}
 	}
 	e_cal_component_free_categories_list (categories_list);
diff --git a/calendar/gui/comp-util.h b/calendar/gui/comp-util.h
index d46fcb7..2faea3e 100644
--- a/calendar/gui/comp-util.h
+++ b/calendar/gui/comp-util.h
@@ -39,7 +39,7 @@ gboolean cal_comp_util_compare_event_timezones (ECalComponent *comp,
 						icaltimezone *zone);
 
 /* Returns the number of icons owned by the ECalComponent */
-gint     cal_comp_util_get_n_icons (ECalComponent *comp);
+gint     cal_comp_util_get_n_icons (ECalComponent *comp, GSList **pixbufs);
 
 gboolean cal_comp_is_on_server (ECalComponent *comp,
 				ECal *client);
diff --git a/calendar/gui/e-day-view-main-item.c b/calendar/gui/e-day-view-main-item.c
index 2809140..3e19851 100644
--- a/calendar/gui/e-day-view-main-item.c
+++ b/calendar/gui/e-day-view-main-item.c
@@ -35,6 +35,7 @@
 #include "ea-calendar.h"
 #include "e-calendar-view.h"
 #include "comp-util.h"
+#include "calendar-config.h"
 #include <libecal/e-cal-time-util.h>
 #include <e-calendar-view.h>
 
@@ -61,22 +62,22 @@ static void e_day_view_main_item_draw_long_events_in_vbars (EDayViewMainItem *dv
 							    gint x,
 							    gint y,
 							    gint width,
-							    gint height);
+							    gint height, GdkRegion *draw_region);
 static void e_day_view_main_item_draw_events_in_vbars (EDayViewMainItem *dvmitem,
 						       GdkDrawable *drawable,
 						       gint x, gint y,
 						       gint width, gint height,
-						       gint day);
+						       gint day, GdkRegion *draw_region);
 static void e_day_view_main_item_draw_day_events (EDayViewMainItem *dvmitem,
 						  GdkDrawable *drawable,
 						  gint x, gint y,
 						  gint width, gint height,
-						  gint day);
+						  gint day, GdkRegion *draw_region);
 static void e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 						 GdkDrawable *drawable,
 						 gint x, gint y,
 						 gint width, gint height,
-						 gint day, gint event_num);
+						 gint day, gint event_num, GdkRegion *draw_region);
 
 /* The arguments we take */
 enum {
@@ -155,6 +156,36 @@ e_day_view_main_item_update (GnomeCanvasItem *item,
 	item->y2 = INT_MAX;
 }
 
+static gboolean
+can_draw_in_region (GdkRegion *draw_region, gint x, gint y, gint width, gint height)
+{
+	GdkRectangle rect;
+
+	g_return_val_if_fail (draw_region != NULL, FALSE);
+
+	rect.x = x;
+	rect.y = y;
+	rect.width = width;
+	rect.height = height;
+
+	return gdk_region_rect_in (draw_region, &rect) != GDK_OVERLAP_RECTANGLE_OUT;
+}
+
+static gboolean
+icalcomp_is_transparent (icalcomponent *icalcomp)
+{
+	icalproperty *transp_prop;
+	icalproperty_transp ical_transp = ICAL_TRANSP_NONE;
+
+	g_return_val_if_fail (icalcomp != NULL, TRUE);
+
+	transp_prop = icalcomponent_get_first_property (icalcomp, ICAL_TRANSP_PROPERTY);
+	if (transp_prop)
+		ical_transp = icalproperty_get_transp (transp_prop);
+
+	return transp_prop && (ical_transp == ICAL_TRANSP_TRANSPARENT || ical_transp == ICAL_TRANSP_TRANSPARENTNOCONFLICT);
+}
+
 /*
  * DRAWING ROUTINES - functions to paint the canvas item.
  */
@@ -175,6 +206,8 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 	gint weekday;
 	cairo_t *cr;
 	gboolean today = FALSE;
+	GdkRegion *draw_region;
+	GdkRectangle rect;
 
 	cr = gdk_cairo_create (drawable);
 
@@ -188,6 +221,11 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 	g_return_if_fail (day_view != NULL);
 
 	style = gtk_widget_get_style (GTK_WIDGET (day_view));
+	rect.x = 0;
+	rect.y = 0;
+	rect.width = width;
+	rect.height = height;
+	draw_region = gdk_region_rectangle (&rect);
 
 	/* Paint the background colors. */
 	work_day_start_y = e_day_view_convert_time_to_position (day_view, day_view->work_day_start_hour, day_view->work_day_start_minute) - y;
@@ -208,13 +246,13 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 		day_w = day_view->day_widths[day];
 
 		if (work_day) {
-			cairo_save (cr);
-			gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
-
-			cairo_rectangle (cr, day_x, 0 - y, day_w,
-					work_day_start_y - (0 - y));
-			cairo_fill (cr);
-			cairo_restore (cr);
+			if (can_draw_in_region (draw_region, day_x, 0 - y, day_w, work_day_start_y - (0 - y))) {
+				cairo_save (cr);
+				gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
+				cairo_rectangle (cr, day_x, 0 - y, day_w, work_day_start_y - (0 - y));
+				cairo_fill (cr);
+				cairo_restore (cr);
+			}
 
 			if (day_view->days_shown > 1) {
 				/* Check if we are drawing today */
@@ -225,25 +263,24 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 				today = FALSE;
 			}
 
-			cairo_save (cr);
-			gdk_cairo_set_source_color (cr, &day_view->colors[today ? E_DAY_VIEW_COLOR_BG_MULTIDAY_TODAY : E_DAY_VIEW_COLOR_BG_WORKING]);
-
-			cairo_rectangle (cr, day_x, work_day_start_y, day_w,
-					work_day_end_y - work_day_start_y);
-			cairo_fill (cr);
-			cairo_restore (cr);
-
-			cairo_save (cr);
-			gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
+			if (can_draw_in_region (draw_region, day_x, work_day_start_y, day_w, work_day_end_y - work_day_start_y)) {
+				cairo_save (cr);
+				gdk_cairo_set_source_color (cr, &day_view->colors[today ? E_DAY_VIEW_COLOR_BG_MULTIDAY_TODAY : E_DAY_VIEW_COLOR_BG_WORKING]);
+				cairo_rectangle (cr, day_x, work_day_start_y, day_w, work_day_end_y - work_day_start_y);
+				cairo_fill (cr);
+				cairo_restore (cr);
+			}
 
-			cairo_rectangle (cr, day_x, work_day_end_y, day_w,
-					height - work_day_end_y);
-			cairo_fill (cr);
-			cairo_restore (cr);
-		} else {
+			if (can_draw_in_region (draw_region, day_x, work_day_end_y, day_w, height - work_day_end_y)) {
+				cairo_save (cr);
+				gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
+				cairo_rectangle (cr, day_x, work_day_end_y, day_w, height - work_day_end_y);
+				cairo_fill (cr);
+				cairo_restore (cr);
+			}
+		} else if (can_draw_in_region (draw_region, day_x, 0, day_w, height)) {
 			cairo_save (cr);
 			gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_BG_NOT_WORKING]);
-
 			cairo_rectangle (cr, day_x, 0, day_w, height);
 			cairo_fill (cr);
 			cairo_restore (cr);
@@ -272,20 +309,10 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 			rect_y = start_row * day_view->row_height - y;
 			rect_height = (end_row - start_row + 1) * day_view->row_height;
 
-			if (GTK_WIDGET_HAS_FOCUS(day_view)) {
-				cairo_save (cr);
-				gdk_cairo_set_source_color (cr,
-					&day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED]);
-				cairo_rectangle (cr, rect_x, rect_y, rect_width,
-						rect_height);
-				cairo_fill (cr);
-				cairo_restore (cr);
-			} else {
+			if (can_draw_in_region (draw_region, rect_x, rect_y, rect_width, rect_height)) {
 				cairo_save (cr);
-				gdk_cairo_set_source_color (cr,
-					&day_view->colors[E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED]);
-				cairo_rectangle (cr, rect_x, rect_y, rect_width,
-					rect_height);
+				gdk_cairo_set_source_color (cr, &day_view->colors[GTK_WIDGET_HAS_FOCUS(day_view) ? E_DAY_VIEW_COLOR_BG_SELECTED : E_DAY_VIEW_COLOR_BG_SELECTED_UNFOCUSSED]);
+				cairo_rectangle (cr, rect_x, rect_y, rect_width, rect_height);
 				cairo_fill (cr);
 				cairo_restore (cr);
 			}
@@ -349,20 +376,20 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 		e_day_view_main_item_draw_events_in_vbars (dvmitem, drawable,
 							   x, y,
 							   width, height,
-							   day);
+							   day, draw_region);
 	}
 
 	/* Fill in the vertical bars corresponding to the busy times from the
 	   long events. */
 	e_day_view_main_item_draw_long_events_in_vbars (dvmitem, drawable,
-							x, y, width, height);
+							x, y, width, height, draw_region);
 
 	/* Draw the event borders and backgrounds, and the vertical bars
 	   down the left edges. */
 	for (day = 0; day < day_view->days_shown; day++) {
 		e_day_view_main_item_draw_day_events (dvmitem, drawable,
 						      x, y, width, height,
-						      day);
+						      day, draw_region);
 	}
 
 	if (e_day_view_get_show_marcus_bains (day_view)) {
@@ -404,6 +431,7 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable,
 		cairo_restore (cr);
 	}
 	cairo_destroy (cr);
+	gdk_region_destroy (draw_region);
 }
 
 static void
@@ -411,56 +439,24 @@ e_day_view_main_item_draw_events_in_vbars (EDayViewMainItem *dvmitem,
 					   GdkDrawable *drawable,
 					   gint x, gint y,
 					   gint width, gint height,
-					   gint day)
+					   gint day, GdkRegion *draw_region)
 {
 	EDayView *day_view;
 	EDayViewEvent *event;
 	gint grid_x, event_num, bar_y, bar_h;
-	ECalComponentTransparency transparency;
-	cairo_t *cr;
+	cairo_t *cr = NULL;
 	GdkColor bg_color;
 	day_view = dvmitem->day_view;
 
-	cr = gdk_cairo_create (drawable);
-	cairo_save (cr);
-
-	gdk_cairo_set_source_color (cr,
-			&day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND]);
-
 	grid_x = day_view->day_offsets[day] + 1 - x;
 
 	/* Draw the busy times corresponding to the events in the day. */
-	for (event_num = 0; event_num < day_view->events[day]->len;
-	     event_num++) {
-		ECalComponent *comp;
-
-		event = &g_array_index (day_view->events[day], EDayViewEvent,
-					event_num);
-		if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), event->comp_data),
-				     &bg_color)) {
-			GdkColormap *colormap;
-
-			colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
-			if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
-				gdk_cairo_set_source_color (cr,
-					&bg_color);
-				}
-		}
-
-		comp = e_cal_component_new ();
-		e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
-
-		/* If the event is TRANSPARENT, skip it. */
-		e_cal_component_get_transparency (comp, &transparency);
-		if (transparency == E_CAL_COMPONENT_TRANSP_TRANSPARENT) {
-			g_object_unref (comp);
-			continue;
-		}
+	for (event_num = 0; event_num < day_view->events[day]->len; event_num++) {
+		event = &g_array_index (day_view->events[day], EDayViewEvent, event_num);
 
 		/* We can skip the events in the first column since they will
 		   draw over this anyway. */
 		if (event->num_columns > 0 && event->start_row_or_col == 0) {
-			g_object_unref (comp);
 			continue;
 		}
 
@@ -469,66 +465,62 @@ e_day_view_main_item_draw_events_in_vbars (EDayViewMainItem *dvmitem,
 		bar_y -= y;
 
 		/* Skip it if it isn't visible. */
-		if (bar_y >= height || bar_y + bar_h <= 0) {
-			g_object_unref (comp);
+		if (bar_y >= height || bar_y + bar_h <= 0 || !can_draw_in_region (draw_region, grid_x, bar_y, E_DAY_VIEW_BAR_WIDTH - 2, bar_h)) {
+			continue;
+		}
+
+		/* If the event is TRANSPARENT, skip it. */
+		if (icalcomp_is_transparent (event->comp_data->icalcomp)) {
 			continue;
 		}
 
-		cairo_rectangle (cr, grid_x, bar_y,
-			       E_DAY_VIEW_BAR_WIDTH - 2, bar_h);
+		if (!cr) {
+			cr = gdk_cairo_create (drawable);
+			cairo_save (cr);
+
+			gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND]);
+		}
+
+		if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), event->comp_data), &bg_color)) {
+			GdkColormap *colormap;
+
+			colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
+			if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
+				gdk_cairo_set_source_color (cr, &bg_color);
+			}
+		}
+
+		cairo_rectangle (cr, grid_x, bar_y, E_DAY_VIEW_BAR_WIDTH - 2, bar_h);
 
 		cairo_fill (cr);
+	}
 
-		g_object_unref (comp);
+	if (cr) {
+		cairo_restore (cr);
+		cairo_destroy (cr);
 	}
-	cairo_restore (cr);
-	cairo_destroy (cr);
 }
 
 static void
 e_day_view_main_item_draw_long_events_in_vbars (EDayViewMainItem *dvmitem,
 						GdkDrawable *drawable,
 						gint x, gint y,
-						gint width, gint height)
+						gint width, gint height, GdkRegion *draw_region)
 {
 	EDayView *day_view;
 	EDayViewEvent *event;
 	gint event_num, start_day, end_day, day, bar_y1, bar_y2, grid_x;
-	ECalComponentTransparency transparency;
-	cairo_t *cr;
+	cairo_t *cr = NULL;
 	GdkColor bg_color;
 
 	day_view = dvmitem->day_view;
 
-	cr = gdk_cairo_create (drawable);
-	cairo_save (cr);
-
-	gdk_cairo_set_source_color (cr,
-			&day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND]);
-
-	for (event_num = 0; event_num < day_view->long_events->len;
-	     event_num++) {
-		ECalComponent *comp;
-
-		event = &g_array_index (day_view->long_events, EDayViewEvent,
-					event_num);
-		if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), event->comp_data),
-				     &bg_color)) {
-			GdkColormap *colormap;
-
-			colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
-			if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
-				gdk_cairo_set_source_color (cr, &bg_color);
-			}
-		}
-
-		comp = e_cal_component_new ();
-		e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (event->comp_data->icalcomp));
+	for (event_num = 0; event_num < day_view->long_events->len; event_num++) {
+		gboolean first = TRUE;
+		event = &g_array_index (day_view->long_events, EDayViewEvent, event_num);
 
 		/* If the event is TRANSPARENT, skip it. */
-		e_cal_component_get_transparency (comp, &transparency);
-		if (transparency == E_CAL_COMPONENT_TRANSP_TRANSPARENT) {
-			g_object_unref (comp);
+		if (icalcomp_is_transparent (event->comp_data->icalcomp)) {
 			continue;
 		}
 
@@ -536,7 +528,6 @@ e_day_view_main_item_draw_long_events_in_vbars (EDayViewMainItem *dvmitem,
 						      day_view->days_shown,
 						      day_view->day_starts,
 						      &start_day, &end_day)) {
-			g_object_unref (comp);
 			continue;
 		}
 
@@ -560,24 +551,43 @@ e_day_view_main_item_draw_long_events_in_vbars (EDayViewMainItem *dvmitem,
 				bar_y2 = event->end_minute * day_view->row_height / day_view->mins_per_row - y;
 			}
 
-			if (bar_y1 < height && bar_y2 > 0 && bar_y2 > bar_y1) {
-				cairo_rectangle (cr, grid_x, bar_y1,
-					       E_DAY_VIEW_BAR_WIDTH - 2, bar_y2 - bar_y1);
+			if (bar_y1 < height && bar_y2 > 0 && bar_y2 > bar_y1 && can_draw_in_region (draw_region, grid_x, bar_y1, E_DAY_VIEW_BAR_WIDTH - 2, bar_y2 - bar_y1)) {
+				if (!cr) {
+					cr = gdk_cairo_create (drawable);
+					cairo_save (cr);
+					gdk_cairo_set_source_color (cr, &day_view->colors[E_DAY_VIEW_COLOR_EVENT_BACKGROUND]);
+				}
 
+				if (first) {
+					first = FALSE;
+
+					if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (day_view)), event->comp_data), &bg_color)) {
+						GdkColormap *colormap;
+
+						colormap = gtk_widget_get_colormap (GTK_WIDGET (day_view));
+						if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
+							gdk_cairo_set_source_color (cr, &bg_color);
+						}
+					}
+				}
+
+				cairo_rectangle (cr, grid_x, bar_y1, E_DAY_VIEW_BAR_WIDTH - 2, bar_y2 - bar_y1);
 				cairo_fill (cr);
 			}
 		}
-		g_object_unref (comp);
 	}
-	cairo_restore (cr);
-	cairo_destroy (cr);
+
+	if (cr) {
+		cairo_restore (cr);
+		cairo_destroy (cr);
+	}
 }
 
 static void
 e_day_view_main_item_draw_day_events (EDayViewMainItem *dvmitem,
 				      GdkDrawable *drawable,
 				      gint x, gint y, gint width, gint height,
-				      gint day)
+				      gint day, GdkRegion *draw_region)
 {
 	EDayView *day_view;
 	gint event_num;
@@ -588,7 +598,7 @@ e_day_view_main_item_draw_day_events (EDayViewMainItem *dvmitem,
 	     event_num++) {
 		e_day_view_main_item_draw_day_event (dvmitem, drawable,
 						     x, y, width, height,
-						     day, event_num);
+						     day, event_num, draw_region);
 	}
 }
 
@@ -596,7 +606,7 @@ static void
 e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 				     GdkDrawable *drawable,
 				     gint x, gint y, gint width, gint height,
-				     gint day, gint event_num)
+				     gint day, gint event_num, GdkRegion *draw_region)
 {
 	EDayView *day_view;
 	EDayViewEvent *event;
@@ -608,7 +618,6 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 	gint max_icon_w, max_icon_h;
 	gboolean draw_reminder_icon, draw_recurrence_icon, draw_timezone_icon, draw_meeting_icon;
 	gboolean draw_attach_icon;
-	GSList *categories_list, *elem;
 	ECalComponentTransparency transparency;
 	cairo_t *cr;
 	cairo_pattern_t *pat;
@@ -632,34 +641,12 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 	gchar *text = NULL;
 	gint scroll_flag = 0;
 	gint row_y;
-	GConfClient *gconf;
 
 	day_view = dvmitem->day_view;
 
-	cr = gdk_cairo_create (drawable);
-	gdk_cairo_set_source_color (cr,
-			&day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR]);
-
-	gc = day_view->main_gc;
-
-	gconf = gconf_client_get_default ();
-
-	alpha = gconf_client_get_float (gconf,
-					 "/apps/evolution/calendar/display/events_transparency",
-					 NULL);
-
-	gradient = gconf_client_get_bool (gconf,
-					"/apps/evolution/calendar/display/events_gradient",
-					NULL);
-
-	g_object_unref (gconf);
-
-	font_options = get_font_options ();
-
 	/* If the event is currently being dragged, don't draw it. It will
 	   be drawn in the special drag items. */
-	if (day_view->drag_event_day == day
-	    && day_view->drag_event_num == event_num)
+	if (day_view->drag_event_day == day && day_view->drag_event_num == event_num)
 		return;
 
 	/* Get the position of the event. If it is not shown skip it.*/
@@ -671,6 +658,20 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 	item_x -= x;
 	item_y -= y;
 
+	if (!can_draw_in_region (draw_region, item_x, item_y, item_w, item_h))
+		return;
+
+	cr = gdk_cairo_create (drawable);
+	gdk_cairo_set_source_color (cr,
+			&day_view->colors[E_DAY_VIEW_COLOR_EVENT_VBAR]);
+
+	gc = day_view->main_gc;
+
+	gradient = calendar_config_get_display_events_gradient ();
+	alpha = calendar_config_get_display_events_alpha ();
+
+	font_options = get_font_options ();
+
 	event = &g_array_index (day_view->events[day], EDayViewEvent,
 				event_num);
 
@@ -1038,6 +1039,8 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 
 	/* Draw the reminder & recurrence icons, if needed. */
 	if (!resize_flag && (!is_editing || text_x_offset > E_DAY_VIEW_ICON_X_PAD)) {
+		GSList *categories_pixbufs = NULL, *pixbufs;
+
 		num_icons = 0;
 		draw_reminder_icon = FALSE;
 		draw_recurrence_icon = FALSE;
@@ -1073,8 +1076,7 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 			num_icons++;
 		}
 
-		num_icons += cal_comp_util_get_n_icons (comp);
-		e_cal_component_get_categories_list (comp, &categories_list);
+		num_icons += cal_comp_util_get_n_icons (comp, &categories_pixbufs);
 
 		if (num_icons != 0) {
 			if (item_h >= (E_DAY_VIEW_ICON_HEIGHT + E_DAY_VIEW_ICON_Y_PAD) * num_icons) {
@@ -1087,137 +1089,61 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem,
 				icon_y_inc = 0;
 			}
 
-			#define fit_in_event() icon_x + icon_x_inc < item_x + item_w && icon_y + icon_y_inc < item_y + item_h
+			#define fit_in_event() (icon_x + icon_x_inc < item_x + item_w && icon_y + icon_y_inc < item_y + item_h)
+			#define draw_pixbuf(pf)	\
+				max_icon_w = item_x + item_w - icon_x - E_DAY_VIEW_EVENT_BORDER_WIDTH;		\
+				max_icon_h = item_y + item_h - icon_y - E_DAY_VIEW_EVENT_BORDER_HEIGHT;		\
+														\
+				if (can_draw_in_region (draw_region, icon_x, icon_y, max_icon_w, max_icon_h)) {	\
+					cairo_save (cr);							\
+					cairo_rectangle (cr, icon_x, icon_y, max_icon_w, max_icon_h);		\
+					cairo_clip (cr);							\
+					cairo_new_path (cr);							\
+					gdk_cairo_set_source_pixbuf (cr, pf, icon_x, icon_y);			\
+					cairo_paint (cr);							\
+					cairo_close_path (cr);							\
+					cairo_restore (cr);							\
+				}										\
+														\
+				icon_x += icon_x_inc;								\
+				icon_y += icon_y_inc;
 
 			if (draw_reminder_icon && fit_in_event ()) {
-				max_icon_w = item_x + item_w - icon_x
-					- E_DAY_VIEW_EVENT_BORDER_WIDTH;
-				max_icon_h = item_y + item_h - icon_y
-					- E_DAY_VIEW_EVENT_BORDER_HEIGHT;
-
-				cairo_save (cr);
-				cairo_rectangle (cr, icon_x, icon_y, max_icon_w, max_icon_h);
-				cairo_clip (cr);
-				cairo_new_path (cr);
-				gdk_cairo_set_source_pixbuf (cr, day_view->reminder_icon, icon_x, icon_y);
-				cairo_paint (cr);
-				cairo_close_path (cr);
-				cairo_restore (cr);
-
-				icon_x += icon_x_inc;
-				icon_y += icon_y_inc;
+				draw_pixbuf (day_view->reminder_icon);
 			}
 
 			if (draw_recurrence_icon && fit_in_event ()) {
-				max_icon_w = item_x + item_w - icon_x
-					- E_DAY_VIEW_EVENT_BORDER_WIDTH;
-				max_icon_h = item_y + item_h - icon_y
-					- E_DAY_VIEW_EVENT_BORDER_HEIGHT;
-
-				cairo_save (cr);
-				cairo_rectangle (cr, icon_x, icon_y, max_icon_w, max_icon_h);
-				cairo_clip (cr);
-				cairo_new_path (cr);
-				gdk_cairo_set_source_pixbuf (cr, day_view->recurrence_icon, icon_x, icon_y);
-				cairo_paint (cr);
-				cairo_close_path (cr);
-				cairo_restore (cr);
-
-				icon_x += icon_x_inc;
-				icon_y += icon_y_inc;
+				draw_pixbuf (day_view->recurrence_icon);
 			}
 			if (draw_attach_icon && fit_in_event ()) {
-				max_icon_w = item_x + item_w - icon_x
-					- E_DAY_VIEW_EVENT_BORDER_WIDTH;
-				max_icon_h = item_y + item_h - icon_y
-					- E_DAY_VIEW_EVENT_BORDER_HEIGHT;
-
-				cairo_save (cr);
-				cairo_rectangle (cr, icon_x, icon_y, max_icon_w, max_icon_h);
-				cairo_clip (cr);
-				cairo_new_path (cr);
-				gdk_cairo_set_source_pixbuf (cr, day_view->attach_icon, icon_x, icon_y);
-				cairo_paint (cr);
-				cairo_close_path (cr);
-				cairo_restore (cr);
-				icon_x += icon_x_inc;
-				icon_y += icon_y_inc;
+				draw_pixbuf (day_view->attach_icon);
 			}
 			if (draw_timezone_icon && fit_in_event ()) {
-				max_icon_w = item_x + item_w - icon_x
-					- E_DAY_VIEW_EVENT_BORDER_WIDTH;
-				max_icon_h = item_y + item_h - icon_y
-					- E_DAY_VIEW_EVENT_BORDER_HEIGHT;
-
-				cairo_save (cr);
-				cairo_rectangle (cr, icon_x, icon_y, max_icon_w, max_icon_h);
-				cairo_clip (cr);
-				cairo_new_path (cr);
-				gdk_cairo_set_source_pixbuf (cr, day_view->timezone_icon, icon_x, icon_y);
-				cairo_paint (cr);
-				cairo_close_path (cr);
-				cairo_restore (cr);
-
-				icon_x += icon_x_inc;
-				icon_y += icon_y_inc;
+				draw_pixbuf (day_view->timezone_icon);
 			}
 
 			if (draw_meeting_icon && fit_in_event ()) {
-				max_icon_w = item_x + item_w - icon_x
-					- E_DAY_VIEW_EVENT_BORDER_WIDTH;
-				max_icon_h = item_y + item_h - icon_y
-					- E_DAY_VIEW_EVENT_BORDER_HEIGHT;
-
-				cairo_save (cr);
-				gdk_cairo_set_source_pixbuf (cr, day_view->meeting_icon, icon_x, icon_y);
-				cairo_paint (cr);
-				cairo_restore (cr);
-
-				icon_x += icon_x_inc;
-				icon_y += icon_y_inc;
+				draw_pixbuf (day_view->meeting_icon);
 			}
 
 			/* draw categories icons */
-			for (elem = categories_list; elem && fit_in_event (); elem = elem->next) {
-				gchar *category;
-				GdkPixmap *pixmap = NULL;
-				GdkBitmap *mask = NULL;
-
-				category = (gchar *) elem->data;
-				if (!e_categories_config_get_icon_for (category, &pixmap, &mask))
-					continue;
-
-				max_icon_w = item_x + item_w - icon_x
-					- E_DAY_VIEW_EVENT_BORDER_WIDTH;
-				max_icon_h = item_y + item_h - icon_y
-					- E_DAY_VIEW_EVENT_BORDER_HEIGHT;
-
-				gdk_gc_set_clip_origin (gc, icon_x, icon_y);
-				if (mask != NULL)
-					gdk_gc_set_clip_mask (gc, mask);
-				gdk_draw_drawable (drawable, gc,
-					 pixmap,
-					 0, 0, icon_x, icon_y,
-					 MIN (E_DAY_VIEW_ICON_WIDTH,
-					      max_icon_w),
-					 MIN (E_DAY_VIEW_ICON_HEIGHT,
-					      max_icon_h));
-
-				g_object_unref (pixmap);
-				if (mask != NULL)
-					g_object_unref (mask);
-
-				icon_x += icon_x_inc;
-				icon_y += icon_y_inc;
+			for (pixbufs = categories_pixbufs;
+			     pixbufs && fit_in_event ();
+			     pixbufs = pixbufs->next) {
+				GdkPixbuf *pixbuf = pixbufs->data;
+
+				draw_pixbuf (pixbuf);
 			}
 
-			#undef  fit_in_event
+			#undef draw_pixbuf
+			#undef fit_in_event
 
 			gdk_gc_set_clip_mask (gc, NULL);
 		}
 
 		/* free memory */
-		e_cal_component_free_categories_list (categories_list);
+		g_slist_foreach (categories_pixbufs, (GFunc)g_object_unref, NULL);
+		g_slist_free (categories_pixbufs);
 	}
 
 	if (!short_event)
diff --git a/calendar/gui/e-day-view-top-item.c b/calendar/gui/e-day-view-top-item.c
index 09ed59e..67f6d00 100644
--- a/calendar/gui/e-day-view-top-item.c
+++ b/calendar/gui/e-day-view-top-item.c
@@ -34,6 +34,7 @@
 #include <libecal/e-cal-time-util.h>
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-categories.h>
+#include "calendar-config.h"
 #include "e-calendar-view.h"
 #include "e-day-view-top-item.h"
 
@@ -363,7 +364,6 @@ e_day_view_top_item_draw_long_event (EDayViewTopItem *dvtitem,
 {
 	EDayView *day_view;
 	EDayViewEvent *event;
-	GConfClient *gconf_client;
 	GtkStyle *style;
 	GdkGC *gc, *fg_gc;
 	gint start_day, end_day;
@@ -391,15 +391,8 @@ e_day_view_top_item_draw_long_event (EDayViewTopItem *dvtitem,
 	day_view = dvtitem->day_view;
 	cr = gdk_cairo_create (drawable);
 
-	gconf_client = gconf_client_get_default ();
-	alpha = gconf_client_get_float (gconf_client,
-					 "/apps/evolution/calendar/display/events_transparency",
-					NULL);
-
-	gradient = gconf_client_get_bool (gconf_client,
-					"/apps/evolution/calendar/display/events_gradient",
-					NULL);
-	g_object_unref (gconf_client);
+	gradient = calendar_config_get_display_events_gradient ();
+	alpha = calendar_config_get_display_events_alpha ();
 
 	/* If the event is currently being dragged, don't draw it. It will
 	   be drawn in the special drag items. */
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 209196c..1ed1a49 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -4457,7 +4457,7 @@ e_day_view_reshape_long_event (EDayView *day_view,
 			num_icons++;
 		if (e_cal_component_has_attachments (comp))
 			num_icons++;
-		num_icons += cal_comp_util_get_n_icons (comp);
+		num_icons += cal_comp_util_get_n_icons (comp, NULL);
 	}
 
 	if (!event->canvas_item) {
@@ -4627,7 +4627,7 @@ e_day_view_reshape_day_event (EDayView *day_view,
 			if (e_cal_component_has_organizer (comp))
 				num_icons++;
 
-			num_icons += cal_comp_util_get_n_icons (comp);
+			num_icons += cal_comp_util_get_n_icons (comp, NULL);
 			g_object_unref(comp);
 		}
 
diff --git a/calendar/gui/e-week-view-event-item.c b/calendar/gui/e-week-view-event-item.c
index 66c1bed..9896382 100644
--- a/calendar/gui/e-week-view-event-item.c
+++ b/calendar/gui/e-week-view-event-item.c
@@ -35,6 +35,7 @@
 
 #include <gtk/gtk.h>
 #include "e-calendar-view.h"
+#include "calendar-config.h"
 #include "comp-util.h"
 
 #include <text/e-text.h>
@@ -64,13 +65,16 @@ static void e_week_view_event_item_draw_icons	(EWeekViewEventItem *wveitem,
 						 gint		     icon_x,
 						 gint		     icon_y,
 						 gint		     x2,
-						 gboolean	     right_align);
+						 gboolean	     right_align,
+						 GdkRegion          *draw_region);
 static void e_week_view_event_item_draw_triangle (EWeekViewEventItem *wveitem,
 						  GdkDrawable	     *drawable,
+						  GdkColor            bg_color,
 						  gint		      x,
 						  gint		      y,
 						  gint		      w,
-						  gint		      h);
+						  gint		      h,
+						  GdkRegion          *draw_region);
 static double e_week_view_event_item_point	(GnomeCanvasItem *item,
 						 double		  x,
 						 double		  y,
@@ -216,6 +220,21 @@ e_week_view_event_item_update (GnomeCanvasItem *item,
 	}
 }
 
+static gboolean
+can_draw_in_region (GdkRegion *draw_region, gint x, gint y, gint width, gint height)
+{
+	GdkRectangle rect;
+
+	g_return_val_if_fail (draw_region != NULL, FALSE);
+
+	rect.x = x;
+	rect.y = y;
+	rect.width = width;
+	rect.height = height;
+
+	return gdk_region_rect_in (draw_region, &rect) != GDK_OVERLAP_RECTANGLE_OUT;
+}
+
 /*
  * DRAWING ROUTINES - functions to paint the canvas item.
  */
@@ -231,7 +250,6 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 	EWeekView *week_view;
 	EWeekViewEvent *event;
 	EWeekViewEventSpan *span;
-	GConfClient *gconf_client;
 	GdkGC *gc;
 	gint x1, y1, x2, y2, time_x, time_y;
 	gint icon_x, icon_y, time_width, min_end_time_x, max_icon_x;
@@ -248,6 +266,8 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 	gdouble radius, cx0, cy0, rect_height, rect_width;
 	gboolean gradient;
 	gdouble cc = 65535.0;
+	GdkRegion *draw_region;
+	GdkRectangle rect;
 
 #if 0
 	g_print ("In e_week_view_event_item_draw %i,%i %ix%i\n",
@@ -258,23 +278,15 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 	week_view = E_WEEK_VIEW (GTK_WIDGET (canvas_item->canvas)->parent);
 	g_return_if_fail (E_IS_WEEK_VIEW (week_view));
 
-	cr = gdk_cairo_create (drawable);
-
 	if (wveitem->event_num == -1 || wveitem->span_num == -1)
 		return;
 
-	g_return_if_fail(wveitem->event_num < week_view->events->len);
-
-	gconf_client = gconf_client_get_default ();
-	gradient = gconf_client_get_bool (gconf_client,
-					"/apps/evolution/calendar/display/events_gradient",
-					NULL);
-	g_object_unref (gconf_client);
+	g_return_if_fail (wveitem->event_num < week_view->events->len);
 
 	event = &g_array_index (week_view->events, EWeekViewEvent,
 				wveitem->event_num);
 
-	g_return_if_fail(event->spans_index + wveitem->span_num < week_view->spans->len);
+	g_return_if_fail (event->spans_index + wveitem->span_num < week_view->spans->len);
 
 	span = &g_array_index (week_view->spans, EWeekViewEventSpan,
 			       event->spans_index + wveitem->span_num);
@@ -289,6 +301,20 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 	if (x1 == x2 || y1 == y2)
 		return;
 
+	rect.x = 0;
+	rect.y = 0;
+	rect.width = width;
+	rect.height = height;
+	draw_region = gdk_region_rectangle (&rect);
+
+	if (!can_draw_in_region (draw_region, x1, y1, x2 - x1, y2 - y1)) {
+		gdk_region_destroy (draw_region);
+		return;
+	}
+	
+	cr = gdk_cairo_create (drawable);
+	gradient = calendar_config_get_display_events_gradient ();
+
 	icon_x = 0;
 	icon_y = y1 + E_WEEK_VIEW_EVENT_BORDER_HEIGHT + E_WEEK_VIEW_ICON_Y_PAD;
 
@@ -305,37 +331,28 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 
 	time_width = e_week_view_get_time_string_width (week_view);
 
-	one_day_event = e_week_view_is_one_day_event (week_view,
-						      wveitem->event_num);
+	one_day_event = e_week_view_is_one_day_event (week_view, wveitem->event_num);
+
+	bg_color = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND];
+	if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)), event->comp_data), &bg_color)) {
+		GdkColormap *colormap;
+
+		colormap = gtk_widget_get_colormap (GTK_WIDGET (week_view));
+		if (!gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
+			bg_color = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND];
+		}
+	}
+
+	red = bg_color.red;
+	green = bg_color.green;
+	blue = bg_color.blue;
+
 	if (one_day_event) {
 		time_x = x1 + E_WEEK_VIEW_EVENT_L_PAD + 1;
 		rect_x = x1 + E_WEEK_VIEW_EVENT_L_PAD;
 		rect_w = x2 - x1 - E_WEEK_VIEW_EVENT_L_PAD - E_WEEK_VIEW_EVENT_R_PAD + 1;
 
-		if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)),
-									  event->comp_data),
-				     &bg_color)) {
-			GdkColormap *colormap;
-
-			colormap = gtk_widget_get_colormap (GTK_WIDGET (week_view));
-			if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
-				red = bg_color.red;
-				green = bg_color.green;
-				blue = bg_color.blue;
-			} else {
-				red = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red;
-				green = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-				blue = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue;
-			}
-		} else {
-			red = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-			green = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-			blue = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-		}
-
 		/* Here we draw the border around the event*/
-		cairo_save (cr);
-
 		cx0	   = rect_x;
 		cy0	   = y1 + 1;
 		rect_width  = rect_w;
@@ -343,17 +360,17 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 
 		radius = 12;
 
-		draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
-
-		cairo_set_line_width (cr, 2.0);
-		cairo_set_source_rgb (cr, red/cc, green/cc, blue/cc);
-		cairo_stroke (cr);
-		cairo_restore (cr);
+		if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) {
+			cairo_save (cr);
+			draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
+			cairo_set_line_width (cr, 2.0);
+			cairo_set_source_rgb (cr, red/cc, green/cc, blue/cc);
+			cairo_stroke (cr);
+			cairo_restore (cr);
+		}
 
 		/* Fill it in the Event */
 
-		cairo_save (cr);
-
 		cx0	   = rect_x + 1.5;
 		cy0	   = y1 + 2.75;
 		rect_width  = rect_w - 3.;
@@ -361,24 +378,26 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 
 		radius = 8;
 
-		draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
-
-		if (gradient) {
-			pat = cairo_pattern_create_linear (rect_x + 2, y1 + 1,
-							rect_x + 2, y2 - 7.25);
-			cairo_pattern_add_color_stop_rgba (pat, 1, red/cc, green/cc, blue/cc, 0.8);
-			cairo_pattern_add_color_stop_rgba (pat, 0, red/cc, green/cc, blue/cc, 0.4);
-			cairo_set_source (cr, pat);
-			cairo_fill_preserve (cr);
-			cairo_pattern_destroy (pat);
-		} else {
-			cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.8);
-			cairo_fill_preserve (cr);
+		if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) {
+			cairo_save (cr);
+			draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
+
+			if (gradient) {
+				pat = cairo_pattern_create_linear (rect_x + 2, y1 + 1, rect_x + 2, y2 - 7.25);
+				cairo_pattern_add_color_stop_rgba (pat, 1, red/cc, green/cc, blue/cc, 0.8);
+				cairo_pattern_add_color_stop_rgba (pat, 0, red/cc, green/cc, blue/cc, 0.4);
+				cairo_set_source (cr, pat);
+				cairo_fill_preserve (cr);
+				cairo_pattern_destroy (pat);
+			} else {
+				cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.8);
+				cairo_fill_preserve (cr);
+			}
+			cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.2);
+			cairo_set_line_width (cr, 0.5);
+			cairo_stroke (cr);
+			cairo_restore (cr);
 		}
-		cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.2);
-		cairo_set_line_width (cr, 0.5);
-		cairo_stroke (cr);
-		cairo_restore (cr);
 
 		/* Draw the start and end times, as required. */
 		switch (week_view->time_format) {
@@ -427,7 +446,7 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 		/* Draw the icons. */
 		e_week_view_event_item_draw_icons (wveitem, drawable,
 						   icon_x, icon_y,
-						   x2, FALSE);
+						   x2, FALSE, draw_region);
 
 	} else {
 		rect_x = x1 + E_WEEK_VIEW_EVENT_L_PAD;
@@ -450,28 +469,7 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 			rect_w -= 2;
 		}
 
-		cairo_save (cr);
-		if (gdk_color_parse (e_cal_model_get_color_for_component (e_calendar_view_get_model (E_CALENDAR_VIEW (week_view)),
-									  event->comp_data),
-				     &bg_color)) {
-			GdkColormap *colormap;
-
-			colormap = gtk_widget_get_colormap (GTK_WIDGET (week_view));
-			if (gdk_colormap_alloc_color (colormap, &bg_color, TRUE, TRUE)) {
-				red = bg_color.red;
-				green = bg_color.green;
-				blue = bg_color.blue;
-			} else {
-				red = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].red;
-				green = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-				blue = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].blue;
-			}
-		} else {
-			red = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-			green = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-			blue = week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BACKGROUND].green;
-		}
-
+		
 		/* Here we draw the border around the event */
 
 		cx0	   = rect_x;
@@ -481,17 +479,17 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 
 		radius = 12;
 
-		draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
-
-		cairo_set_line_width (cr, 2.0);
-		cairo_set_source_rgb (cr, red/cc, green/cc, blue/cc);
-		cairo_stroke (cr);
-		cairo_restore (cr);
+		if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) {
+			cairo_save (cr);
+			draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
+			cairo_set_line_width (cr, 2.0);
+			cairo_set_source_rgb (cr, red/cc, green/cc, blue/cc);
+			cairo_stroke (cr);
+			cairo_restore (cr);
+		}
 
 		/* Here we fill it in the event*/
 
-		cairo_save (cr);
-
 		cx0	   = rect_x + 1.5;
 		cy0	   = y1 + 2.75;
 		rect_width  = rect_w - 3.;
@@ -499,28 +497,30 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 
 		radius = 8;
 
-		draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
-
-		if (gradient) {
-			pat = cairo_pattern_create_linear (rect_x + 2, y1 + 1,
-						rect_x + 2, y2 - 7.25);
-			cairo_pattern_add_color_stop_rgba (pat, 1, red/cc, green/cc, blue/cc, 0.8);
-			cairo_pattern_add_color_stop_rgba (pat, 0, red/cc, green/cc, blue/cc, 0.4);
-			cairo_set_source (cr, pat);
-			cairo_fill_preserve (cr);
-			cairo_pattern_destroy (pat);
-		} else {
-			cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.8);
-			cairo_fill_preserve (cr);
+		if (can_draw_in_region (draw_region, cx0, cy0, rect_width, rect_height)) {
+			cairo_save (cr);
+			draw_curved_rectangle (cr, cx0, cy0, rect_width, rect_height, radius);
+
+			if (gradient){
+				pat = cairo_pattern_create_linear (rect_x + 2, y1 + 1, rect_x + 2, y2 - 7.25);
+				cairo_pattern_add_color_stop_rgba (pat, 1, red/cc, green/cc, blue/cc, 0.8);
+				cairo_pattern_add_color_stop_rgba (pat, 0, red/cc, green/cc, blue/cc, 0.4);
+				cairo_set_source (cr, pat);
+				cairo_fill_preserve (cr);
+				cairo_pattern_destroy (pat);
+			} else {
+				cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.8);
+				cairo_fill_preserve (cr);
+			}
+			cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.2);
+			cairo_set_line_width (cr, 0.5);
+			cairo_stroke (cr);
+			cairo_restore (cr);
 		}
-		cairo_set_source_rgba (cr, red/cc, green/cc, blue/cc, 0.2);
-		cairo_set_line_width (cr, 0.5);
-		cairo_stroke (cr);
-		cairo_restore (cr);
 
 		if (draw_start_triangle) {
-			e_week_view_event_item_draw_triangle (wveitem, drawable, x1 + E_WEEK_VIEW_EVENT_L_PAD + 2, y1, -3, y2 - y1 + 1);
-		} else {
+			e_week_view_event_item_draw_triangle (wveitem, drawable, bg_color, x1 + E_WEEK_VIEW_EVENT_L_PAD + 2, y1, -3, y2 - y1 + 1, draw_region);
+		} else if (can_draw_in_region (draw_region, rect_x, y1, 1, y2 - y1)) {
 			cairo_save (cr);
 			gdk_cairo_set_source_color (cr,  &week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER]);
 			cairo_set_line_width (cr, 0.7);
@@ -531,8 +531,8 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 		}
 
 		if (draw_end_triangle) {
-			e_week_view_event_item_draw_triangle (wveitem, drawable, x2 - E_WEEK_VIEW_EVENT_R_PAD - 2, y1, 3, y2 - y1 + 1);
-		} else {
+			e_week_view_event_item_draw_triangle (wveitem, drawable, bg_color, x2 - E_WEEK_VIEW_EVENT_R_PAD - 2, y1, 3, y2 - y1 + 1, draw_region);
+		} else if (can_draw_in_region (draw_region, rect_x2, y2, 1, 1)) {
 			cairo_save (cr);
 			gdk_cairo_set_source_color (cr,  &week_view->colors[E_WEEK_VIEW_COLOR_EVENT_BORDER]);
 			cairo_set_line_width (cr, 0.7);
@@ -614,10 +614,12 @@ e_week_view_event_item_draw (GnomeCanvasItem  *canvas_item,
 			icon_x = span->text_item->x1 - E_WEEK_VIEW_ICON_R_PAD - x;
 			e_week_view_event_item_draw_icons (wveitem, drawable,
 							   icon_x, icon_y,
-							   max_icon_x, TRUE);
+							   max_icon_x, TRUE, draw_region);
 		}
 	}
 	cairo_destroy (cr);
+
+	gdk_region_destroy (draw_region);
 }
 
 static void
@@ -722,7 +724,8 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
 				   gint		       icon_x,
 				   gint		       icon_y,
 				   gint		       x2,
-				   gboolean	       right_align)
+				   gboolean	       right_align,
+				   GdkRegion          *draw_region)
 {
 	EWeekView *week_view;
 	EWeekViewEvent *event;
@@ -732,7 +735,7 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
 	gboolean draw_reminder_icon = FALSE, draw_recurrence_icon = FALSE;
 	gboolean draw_timezone_icon = FALSE, draw_attach_icon = FALSE;
 	gboolean draw_meeting_icon = FALSE;
-	GSList *categories_list, *elem;
+	GSList *categories_pixbufs = NULL, *pixbufs;
 	cairo_t *cr;
 
 	week_view = E_WEEK_VIEW (GTK_WIDGET (GNOME_CANVAS_ITEM (wveitem)->canvas)->parent);
@@ -770,87 +773,61 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
 		num_icons++;
 	}
 
-	num_icons += cal_comp_util_get_n_icons (comp);
-
-	e_cal_component_get_categories_list (comp, &categories_list);
+	num_icons += cal_comp_util_get_n_icons (comp, &categories_pixbufs);
 
 	icon_x_inc = E_WEEK_VIEW_ICON_WIDTH + E_WEEK_VIEW_ICON_X_PAD;
 
 	if (right_align)
 		icon_x -= icon_x_inc * num_icons;
 
-	if (draw_reminder_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
-		cairo_save (cr);
-		gdk_cairo_set_source_pixbuf (cr, week_view->reminder_icon, icon_x, icon_y);
-		cairo_paint (cr);
-		cairo_restore (cr);
-
+	#define draw_pixbuf(pf)							\
+		if (can_draw_in_region (draw_region, icon_x, icon_y, 		\
+		    E_WEEK_VIEW_ICON_WIDTH, E_WEEK_VIEW_ICON_HEIGHT)) {		\
+			cairo_save (cr);					\
+			gdk_cairo_set_source_pixbuf (cr, pf, icon_x, icon_y);	\
+			cairo_paint (cr);					\
+			cairo_restore (cr);					\
+		}								\
+										\
 		icon_x += icon_x_inc;
+
+
+	if (draw_reminder_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
+		draw_pixbuf (week_view->reminder_icon);
 	}
 
 	if (draw_attach_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
-		cairo_save (cr);
-		gdk_cairo_set_source_pixbuf (cr, week_view->attach_icon, icon_x, icon_y);
-		cairo_paint (cr);
-		cairo_restore (cr);
-
-		icon_x += icon_x_inc;
+		draw_pixbuf (week_view->attach_icon);
 	}
 
 	if (draw_recurrence_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
-		cairo_save (cr);
-		gdk_cairo_set_source_pixbuf (cr, week_view->recurrence_icon, icon_x, icon_y);
-		cairo_paint (cr);
-		cairo_restore (cr);
-		icon_x += icon_x_inc;
+		draw_pixbuf (week_view->recurrence_icon);
 	}
 
 	if (draw_timezone_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
-		cairo_save (cr);
-		gdk_cairo_set_source_pixbuf (cr, week_view->timezone_icon, icon_x, icon_y);
-		cairo_paint (cr);
-		cairo_restore (cr);
-		icon_x += icon_x_inc;
+		draw_pixbuf (week_view->timezone_icon);
 	}
 
 	if (draw_meeting_icon && icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
-		cairo_save (cr);
-		gdk_cairo_set_source_pixbuf (cr, week_view->meeting_icon, icon_x, icon_y);
-		cairo_paint (cr);
-		cairo_restore (cr);
-		icon_x += icon_x_inc;
+		draw_pixbuf (week_view->meeting_icon);
 	}
 
 	/* draw categories icons */
-	for (elem = categories_list; elem; elem = elem->next) {
-		gchar *category;
-		GdkPixmap *pixmap = NULL;
-		GdkBitmap *mask = NULL;
-
-		category = (gchar *) elem->data;
-		if (!e_categories_config_get_icon_for (category, &pixmap, &mask))
-			continue;
-
-		if (icon_x + E_WEEK_VIEW_ICON_WIDTH <= x2) {
-			gdk_gc_set_clip_origin (gc, icon_x, icon_y);
-			if (mask != NULL)
-				gdk_gc_set_clip_mask (gc, mask);
-			gdk_draw_drawable (drawable, gc,
-					 pixmap,
-					 0, 0, icon_x, icon_y,
-					 E_WEEK_VIEW_ICON_WIDTH,
-					 E_WEEK_VIEW_ICON_HEIGHT);
-			icon_x += icon_x_inc;
-		}
-		g_object_unref (pixmap);
-		if (mask != NULL)
-			g_object_unref (mask);
+	for (pixbufs = categories_pixbufs;
+	     pixbufs;
+	     pixbufs = pixbufs->next) {
+		GdkPixbuf *pixbuf = pixbufs->data;
+
+		draw_pixbuf (pixbuf);
 	}
 
+	#undef draw_pixbuf
+
+	g_slist_foreach (categories_pixbufs, (GFunc)g_object_unref, NULL);
+	g_slist_free (categories_pixbufs);
+
 	cairo_destroy (cr);
-	e_cal_component_free_categories_list (categories_list);
 	g_object_unref(comp);
-
 	gdk_gc_set_clip_mask (gc, NULL);
 }
 
@@ -859,19 +836,23 @@ e_week_view_event_item_draw_icons (EWeekViewEventItem *wveitem,
 static void
 e_week_view_event_item_draw_triangle (EWeekViewEventItem *wveitem,
 				      GdkDrawable	 *drawable,
+				      GdkColor            bg_color,
 				      gint		  x,
 				      gint		  y,
 				      gint		  w,
-				      gint		  h)
+				      gint		  h,
+				      GdkRegion          *draw_region)
 {
 	EWeekView *week_view;
 	EWeekViewEvent *event;
 	GdkGC *gc;
-	GdkColor bg_color;
 	GdkPoint points[3];
 	gint c1, c2;
 	cairo_t *cr;
 
+	if (!can_draw_in_region (draw_region, x, y, w, h))
+		return;
+
 	week_view = E_WEEK_VIEW (GTK_WIDGET (GNOME_CANVAS_ITEM (wveitem)->canvas)->parent);
 
 	event = &g_array_index (week_view->events, EWeekViewEvent,
diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c
index abf18cc..f3c3100 100644
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@ -2817,7 +2817,7 @@ e_week_view_reshape_event_span (EWeekView *week_view,
 			num_icons++;
 		if (event->different_timezone)
 			num_icons++;
-		num_icons += cal_comp_util_get_n_icons (comp);
+		num_icons += cal_comp_util_get_n_icons (comp, NULL);
 	}
 
 	/* Create the background canvas item if necessary. */
diff --git a/e-util/e-categories-config.c b/e-util/e-categories-config.c
index 14c8eae..3dc3558 100644
--- a/e-util/e-categories-config.c
+++ b/e-util/e-categories-config.c
@@ -27,48 +27,64 @@
 #include <libedataserverui/e-categories-dialog.h>
 #include "e-categories-config.h"
 
+static GHashTable *pixbufs_cache = NULL;
+
+static void
+categories_changed_cb (gpointer object, gpointer user_data)
+{
+	if (pixbufs_cache)
+		g_hash_table_remove_all (pixbufs_cache);
+}
+
+static void
+free_pixbuf_cb (gpointer ptr)
+{
+	GdkPixbuf *pixbuf = ptr;
+
+	if (pixbuf)
+		g_object_unref (pixbuf);
+}
+
 /**
  * e_categories_config_get_icon_for:
  * @category: Category for which to get the icon.
- * @icon: A pointer to where the pixmap will be returned.
- * @mask: A pointer to where the mask will be returned.
+ * @pixbuf: A pointer to where the pixbuf will be returned.
  *
- * Returns the icon (and associated mask) configured for the
- * given category.
+ * Returns the icon configured for the given category.
  */
 gboolean
-e_categories_config_get_icon_for (const gchar *category, GdkPixmap **pixmap, GdkBitmap **mask)
+e_categories_config_get_icon_for (const gchar *category, GdkPixbuf **pixbuf)
 {
-	gchar *icon_file;
-	GdkPixbuf *pixbuf;
-	GdkBitmap *tmp_mask;
+	const gchar *icon_file;
 
-	g_return_val_if_fail (pixmap != NULL, FALSE);
+	g_return_val_if_fail (pixbuf != NULL, FALSE);
+	g_return_val_if_fail (category != NULL, FALSE);
 
-	icon_file = (gchar *) e_categories_get_icon_file_for (category);
-	if (!icon_file) {
-		*pixmap = NULL;
-		if (mask != NULL)
-			*mask = NULL;
-		return FALSE;
+	if (!pixbufs_cache) {
+		pixbufs_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_pixbuf_cb);
+		e_categories_register_change_listener (G_CALLBACK (categories_changed_cb), NULL);
+	} else {
+		gpointer key = NULL, value = NULL;
+
+		if (g_hash_table_lookup_extended (pixbufs_cache, category, &key, &value)) {
+			*pixbuf = value;
+			if (*pixbuf)
+				g_object_ref (*pixbuf);
+			return *pixbuf != NULL;
+		}
 	}
 
-	/* load the icon in our list */
-	pixbuf = gdk_pixbuf_new_from_file (icon_file, NULL);
-	if (!pixbuf) {
-		*pixmap = NULL;
-		if (mask != NULL)
-			*mask = NULL;
-		return FALSE;
+	icon_file = e_categories_get_icon_file_for (category);
+	if (!icon_file) {
+		*pixbuf = NULL;
+	} else {
+		/* load the icon in our list */
+		*pixbuf = gdk_pixbuf_new_from_file (icon_file, NULL);
 	}
 
-	/* render the pixbuf to the pixmap and mask passed */
-	gdk_pixbuf_render_pixmap_and_mask (pixbuf, pixmap, &tmp_mask, 1);
-	if (mask != NULL)
-		*mask = tmp_mask;
+	g_hash_table_insert (pixbufs_cache, g_strdup (category), *pixbuf == NULL ? NULL : g_object_ref (*pixbuf));
 
-	g_object_unref (pixbuf);
-	return TRUE;
+	return *pixbuf != NULL;
 }
 
 /**
diff --git a/e-util/e-categories-config.h b/e-util/e-categories-config.h
index 81ae016..82294ae 100644
--- a/e-util/e-categories-config.h
+++ b/e-util/e-categories-config.h
@@ -30,9 +30,7 @@
 
 G_BEGIN_DECLS
 
-gboolean e_categories_config_get_icon_for (const gchar *category,
-					   GdkPixmap **icon,
-					   GdkBitmap **mask);
+gboolean e_categories_config_get_icon_for (const gchar *category, GdkPixbuf **pixbuf);
 void     e_categories_config_open_dialog_for_entry (GtkEntry *entry);
 
 G_END_DECLS



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