Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/widgets/ChangeLog,v
retrieving revision 1.106
diff -u -r1.106 ChangeLog
--- ChangeLog	28 Aug 2003 14:27:45 -0000	1.106
+++ ChangeLog	22 Sep 2003 03:09:25 -0000
@@ -1,3 +1,23 @@
+2003-09-19  Bolian Yin <bolian.yin@sun.com>
+
+	Fixes #1245. ECalendar should be usable with the keyboard
+
+	*misc/e-calendar-item.c (e_calendar_item_focus): new func, focus handler.
+	(e_calendar_item_key_press_event): new func, key press event handler
+	(e_calendar_item_selection_add_days, e_calendar_item_stop_selecting): helpers.
+	(e_calendar_item_ensure_days_visible, e_calendar_item_set_selection_if_emission):
+	 add the flag to control if we should emit e-calendar signals.
+	(e_calendar_item_class_init): register focus handler.
+	(e_calendar_item_event): add code for GDK_FOCUS_CHANGE and GDK_KEY_PRESS.
+
+	*misc/e-calendar.c (e_calendar_focus): new func, focus handler
+	(e_calendar_button_has_focus): new func, if prev/next button has focus.
+	(e_calendar_on_next_clicked, e_calendar_on_prev_clicked): click signal handler
+ 	 for prev/next buttons.
+	(e_calendar_set_focusable): set if the e-calendar is focusable
+
+	*misc/e-dateedit.c (e_date_edit_show_date_popup, hide_date_popup): grab/ungrab gdk keyboard.
+
 2003-08-27  Hans Petter Jansson  <hpj@ximian.com>
 
 	Fixes #15638.
Index: misc/e-calendar-item.c
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-calendar-item.c,v
retrieving revision 1.35
diff -u -r1.35 e-calendar-item.c
--- misc/e-calendar-item.c	27 Aug 2003 03:38:14 -0000	1.35
+++ misc/e-calendar-item.c	22 Sep 2003 03:09:28 -0000
@@ -3,6 +3,7 @@
 /* 
  * Author : 
  *  Damon Chaplin <damon@ximian.com>
+ *  Bolian Yin <bolian.yin@sun.com>
  *
  * Copyright 2000, Ximian, Inc.
  *
@@ -41,6 +42,7 @@
 #include <gtk/gtkmenuitem.h>
 #include <gtk/gtklabel.h>
 #include <gtk/gtksignal.h>
+#include <gdk/gdkkeysyms.h>
 #include <libgnome/gnome-i18n.h>
 #include <gal/util/e-util.h>
 
@@ -92,6 +94,8 @@
 static void e_calendar_item_set_arg	(GtkObject	 *o,
 					 GtkArg		 *arg,
 					 guint		  arg_id);
+static gboolean e_calendar_item_focus (GtkWidget *widget,
+				       GtkDirectionType direction);
 static void e_calendar_item_realize	(GnomeCanvasItem *item);
 static void e_calendar_item_unrealize	(GnomeCanvasItem *item);
 static void e_calendar_item_unmap	(GnomeCanvasItem *item);
@@ -130,6 +134,13 @@
 					 int		  cx,
 					 int		  cy,
 					 GnomeCanvasItem **actual_item);
+static void e_calendar_item_stop_selecting (ECalendarItem *calitem,
+					    guint32 time);
+static void e_calendar_item_selection_add_days (ECalendarItem *calitem,
+						gint n_days,
+						gboolean multi_selection);
+static gint e_calendar_item_key_press_event (ECalendarItem *item,
+					     GdkEvent *event);
 static gint e_calendar_item_event	(GnomeCanvasItem *item,
 					 GdkEvent	 *event);
 static void e_calendar_item_bounds (GnomeCanvasItem *item, double *x1, double *y1,
@@ -205,13 +216,14 @@
 static void e_calendar_item_ensure_valid_day	(ECalendarItem	*calitem,
 						 gint		*month_offset,
 						 gint		*day);
-static gboolean e_calendar_item_ensure_days_visible (ECalendarItem	*calitem,
-						     gint		 start_year,
-						     gint		 start_month,
-						     gint		 start_day,
-						     gint		 end_year,
-						     gint		 end_month,
-						     gint		 end_day);
+static gboolean e_calendar_item_ensure_days_visible (ECalendarItem *calitem,
+						     gint start_year,
+						     gint start_month,
+						     gint start_day,
+						     gint end_year,
+						     gint end_month,
+						     gint end_day,
+						     gboolean emission);
 static void e_calendar_item_show_popup_menu	(ECalendarItem	*calitem,
 						 GdkEventButton	*event,
 						 gint		 month_offset);
@@ -225,6 +237,10 @@
 static void e_calendar_item_date_range_changed	(ECalendarItem	*calitem);
 static void e_calendar_item_queue_signal_emission	(ECalendarItem	*calitem);
 static gboolean e_calendar_item_signal_emission_idle_cb	(gpointer data);
+static void e_calendar_item_set_selection_if_emission (ECalendarItem	*calitem,
+						       GDate		*start_date,
+						       GDate		*end_date,
+						       gboolean emission);
 
 /* Our arguments. */
 enum {
@@ -273,11 +289,13 @@
 e_calendar_item_class_init (ECalendarItemClass *class)
 {
 	GtkObjectClass  *object_class;
+	GtkWidgetClass *widget_class;
 	GnomeCanvasItemClass *item_class;
 
 	parent_class = g_type_class_ref(gnome_canvas_item_get_type());
 
 	object_class = (GtkObjectClass *) class;
+	widget_class = (GtkWidgetClass *) class;
 	item_class = (GnomeCanvasItemClass *) class;
 
 	gtk_object_add_arg_type ("ECalendarItem::year",
@@ -363,6 +381,7 @@
 	object_class->get_arg = e_calendar_item_get_arg;
 	object_class->set_arg = e_calendar_item_set_arg;
 
+	widget_class->focus = e_calendar_item_focus;
 	/* GnomeCanvasItem method overrides */
 	item_class->realize     = e_calendar_item_realize;
 	item_class->unrealize   = e_calendar_item_unrealize;
@@ -416,6 +435,9 @@
 	calitem->x2 = 0.0;
 	calitem->y2 = 0.0;
 
+	calitem->selecting = FALSE;
+	calitem->selecting_axis = NULL;
+
 	calitem->selection_set = FALSE;
 
 	calitem->selection_changed = FALSE;
@@ -467,6 +489,8 @@
 		calitem->week_number_font_desc = NULL;
 	}
 
+	if (calitem->selecting_axis)
+		g_free (calitem->selecting_axis);
 	if (GTK_OBJECT_CLASS (parent_class)->destroy)
 		(* GTK_OBJECT_CLASS (parent_class)->destroy) (o);
 }
@@ -693,6 +717,18 @@
 	}
 }
 
+static gboolean
+e_calendar_item_focus (GtkWidget *widget, GtkDirectionType direction)
+{
+	ECalendarItem *calitem;
+
+	g_return_val_if_fail (widget != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CALENDAR_ITEM (widget), FALSE);
+	calitem = E_CALENDAR_ITEM (widget);
+
+	GTK_WIDGET_CLASS (parent_class)->focus (widget, direction);
+	return TRUE;
+}
 
 static void
 e_calendar_item_realize		(GnomeCanvasItem *item)
@@ -717,6 +753,10 @@
 	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG].green = 65535;
 	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG].blue  = 65535;
 
+	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED].red   = 4700;
+	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED].green = 4700;
+	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED].blue  = 65535;
+
 	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].red   = 47000;
 	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].green = 47000;
 	calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG].blue  = 48000;
@@ -1254,7 +1294,7 @@
 	gint num_chars, digit;
 	gint week_num, mon, days_from_week_start;
 	gint years[3], months[3], days_in_month[3];
-	gboolean today, selected, has_focus = FALSE, drop_target = FALSE;
+	gboolean today, selected, has_focus, drop_target = FALSE;
 	gboolean bold, draw_day, finished = FALSE;
 	gint today_year, today_month, today_mday, month_offset;
 	gchar buffer[2];
@@ -1403,6 +1443,12 @@
 					day_style = calitem->styles[(month_offset + 1) * 32 + day_num];
 
 				/* Get the colors & style to use for the day.*/
+				if ((GTK_WIDGET_HAS_FOCUS(item->canvas)) &&
+				    item->canvas->focused_item == item)
+					has_focus = TRUE;
+				else
+					has_focus = FALSE;
+
 				if (calitem->style_callback)
 					(*calitem->style_callback)
 						(calitem,
@@ -1586,6 +1632,128 @@
 	return 0.0;
 }
 
+static void
+e_calendar_item_stop_selecting (ECalendarItem *calitem, guint32 time)
+{
+	if (!calitem->selecting)
+		return;
+
+	gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem), time);
+
+	calitem->selecting = FALSE;
+
+	/* If the user selects the grayed dates before the first month or
+	   after the last month, we move backwards or forwards one month.
+	   The set_month() call should take care of updating the selection. */
+	if (calitem->selection_end_month_offset == -1)
+		e_calendar_item_set_first_month (calitem, calitem->year,
+						 calitem->month - 1);
+	else if (calitem->selection_start_month_offset == calitem->rows * calitem->cols)
+		e_calendar_item_set_first_month (calitem, calitem->year,
+						 calitem->month + 1);
+
+	calitem->selection_changed = TRUE;
+	if (calitem->selecting_axis) {
+		g_free (calitem->selecting_axis);
+		calitem->selecting_axis = NULL;
+	}
+
+	e_calendar_item_queue_signal_emission (calitem);
+	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem));
+}
+
+static void
+e_calendar_item_selection_add_days (ECalendarItem *calitem, gint n_days,
+				    gboolean multi_selection)
+{
+	GDate gdate_start, gdate_end;
+
+	g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
+
+	if (!e_calendar_item_get_selection (calitem, &gdate_start, &gdate_end))
+		return;
+	if (multi_selection && calitem->max_days_selected > 1) {
+		gint days_between;
+
+		days_between = g_date_days_between (&gdate_start, &gdate_end);
+		if (!calitem->selecting_axis) {
+			calitem->selecting_axis = g_new (GDate, 1);
+			*(calitem->selecting_axis) = gdate_start;
+		}
+		if ((days_between != 0 &&
+		     g_date_compare (calitem->selecting_axis, &gdate_end) == 0) ||
+		    (days_between == 0 && n_days < 0)) {
+			if (days_between - n_days > calitem->max_days_selected - 1)
+				n_days =  days_between + 1 - calitem->max_days_selected;
+			g_date_add_days (&gdate_start, n_days);
+		}
+		else {
+			if (days_between + n_days > calitem->max_days_selected - 1)
+				n_days = calitem->max_days_selected - 1 - days_between;
+			g_date_add_days (&gdate_end, n_days);
+		}
+
+		if (g_date_compare (&gdate_end, &gdate_start) < 0) {
+			GDate tmp_date;
+			tmp_date = gdate_start;
+			gdate_start = gdate_end;
+			gdate_end = tmp_date;
+		}
+	}
+	else {
+		/* clear "selecting_axis", it is only for mulit-selecting */
+		if (calitem->selecting_axis) {
+			g_free (calitem->selecting_axis);
+			calitem->selecting_axis = NULL;
+		}
+		g_date_add_days (&gdate_start, n_days);
+		gdate_end = gdate_start;
+	}
+
+	calitem->selecting = TRUE;
+
+	e_calendar_item_set_selection_if_emission (calitem,
+						   &gdate_start, &gdate_end,
+						   FALSE);
+}
+
+static gint
+e_calendar_item_key_press_event (ECalendarItem *calitem, GdkEvent *event)
+{
+	guint keyval = event->key.keyval;
+	gboolean multi_selection = FALSE;
+
+	if (event->key.state & GDK_CONTROL_MASK ||
+	    event->key.state & GDK_MOD1_MASK)
+		return FALSE;
+
+	multi_selection = event->key.state & GDK_SHIFT_MASK;
+	switch (keyval) {
+	case GDK_Up:
+		e_calendar_item_selection_add_days (calitem, -7,
+						    multi_selection);
+		break;
+	case GDK_Down:
+		e_calendar_item_selection_add_days (calitem, 7,
+						    multi_selection);
+		break;
+	case GDK_Left:
+		e_calendar_item_selection_add_days (calitem, -1,
+						    multi_selection);
+		break;
+	case GDK_Right:
+		e_calendar_item_selection_add_days (calitem, 1,
+						    multi_selection);
+		break;
+	case GDK_space:
+	case GDK_Return:
+		e_calendar_item_stop_selecting (calitem, event->key.time);
+		break;
+	default:
+		return FALSE;
+	}
+	return TRUE;
+}
 
 static gint
 e_calendar_item_event (GnomeCanvasItem *item, GdkEvent *event)
@@ -1601,6 +1769,10 @@
 		return e_calendar_item_button_release (calitem, event);
 	case GDK_MOTION_NOTIFY:
 		return e_calendar_item_motion (calitem, event);
+	case GDK_FOCUS_CHANGE:
+		gnome_canvas_item_request_update (item);
+	case GDK_KEY_PRESS:
+		return e_calendar_item_key_press_event (calitem, event);
 	default:
 		break;
 	}
@@ -1752,7 +1924,11 @@
 
 	if (selected) {
 		*fg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_FG];
-		*bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG];
+		if (has_focus)
+			*bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED];
+		else
+			*bg_color = &calitem->colors[E_CALENDAR_ITEM_COLOR_SELECTION_BG];
+
 	}
 }
 
@@ -1840,33 +2016,11 @@
 	return TRUE;
 }
 
-
 static gboolean
 e_calendar_item_button_release	(ECalendarItem	*calitem,
 				 GdkEvent	*event)
 {
-	if (!calitem->selecting)
-		return FALSE;
-
-	gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem),
-				  event->button.time);
-
-	calitem->selecting = FALSE;
-
-	/* If the user selects the grayed dates before the first month or
-	   after the last month, we move backwards or forwards one month.
-	   The set_month() call should take care of updating the selection. */
-	if (calitem->selection_end_month_offset == -1)
-		e_calendar_item_set_first_month (calitem, calitem->year,
-						 calitem->month - 1);
-	else if (calitem->selection_start_month_offset == calitem->rows * calitem->cols)
-		e_calendar_item_set_first_month (calitem, calitem->year,
-						 calitem->month + 1);
-
-	calitem->selection_changed = TRUE;
-	e_calendar_item_queue_signal_emission (calitem);
-	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem));
-
+	e_calendar_item_stop_selecting (calitem, event->button.time);
 	return FALSE;
 }
 
@@ -2727,10 +2881,11 @@
 }
 
 
-void
-e_calendar_item_set_selection	(ECalendarItem	*calitem,
-				 GDate		*start_date,
-				 GDate		*end_date)
+static void
+e_calendar_item_set_selection_if_emission (ECalendarItem	*calitem,
+					   GDate		*start_date,
+					   GDate		*end_date,
+					   gboolean emission)
 {
 	gint start_year, start_month, start_day;
 	gint end_year, end_month, end_day;
@@ -2740,13 +2895,6 @@
 
 	g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
 
-	/* If the user is in the middle of a selection, we must abort it. */
-	if (calitem->selecting) {
-		gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem),
-					  GDK_CURRENT_TIME);
-		calitem->selecting = FALSE;
-	}
-
 	/* If start_date is NULL, we clear the selection without changing the
 	   month shown. */
 	if (start_date == NULL) {
@@ -2759,9 +2907,9 @@
 
 	if (end_date == NULL)
 		end_date = start_date;
-	
+
 	g_return_if_fail (g_date_compare (start_date, end_date) <= 0);
-	
+
 	start_year = g_date_get_year (start_date);
 	start_month = g_date_get_month (start_date) - 1;
 	start_day = g_date_get_day (start_date);
@@ -2775,7 +2923,8 @@
 							   start_day,
 							   end_year,
 							   end_month,
-							   end_day);
+							   end_day,
+							   emission);
 
 	new_start_month_offset = (start_year - calitem->year) * 12
 		+ start_month - calitem->month;
@@ -2794,7 +2943,8 @@
 	    || calitem->selection_end_day != new_end_day) {
 		need_update = TRUE;
 		calitem->selection_changed = TRUE;
-		e_calendar_item_queue_signal_emission (calitem);
+		if (emission)
+			e_calendar_item_queue_signal_emission (calitem);
 		calitem->selection_set = TRUE;
 		calitem->selection_start_month_offset = new_start_month_offset;
 		calitem->selection_start_day = new_start_day;
@@ -2810,6 +2960,22 @@
 		gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (calitem));
 }
 
+void
+e_calendar_item_set_selection (ECalendarItem	*calitem,
+			       GDate		*start_date,
+			       GDate		*end_date)
+{
+	/* If the user is in the middle of a selection, we must abort it. */
+	if (calitem->selecting) {
+		gnome_canvas_item_ungrab (GNOME_CANVAS_ITEM (calitem),
+					  GDK_CURRENT_TIME);
+		calitem->selecting = FALSE;
+	}
+
+	e_calendar_item_set_selection_if_emission (calitem,
+						   start_date, end_date,
+						   TRUE);
+}
 
 /* This tries to ensure that the given time range is visible. If the range
    given is longer than we can show, only the start of it will be visible.
@@ -2822,7 +2988,8 @@
 					 gint		 start_day,
 					 gint		 end_year,
 					 gint		 end_month,
-					 gint		 end_day)
+					 gint		 end_day,
+					 gboolean emission)
 {
 	gint current_end_year, current_end_month;
 	gint months_shown, months;
@@ -2903,7 +3070,7 @@
 		}
 	}
 
-	if (need_update)
+	if (need_update && emission)
 		e_calendar_item_date_range_changed (calitem);
 
 	return need_update;
Index: misc/e-calendar-item.h
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-calendar-item.h,v
retrieving revision 1.15
diff -u -r1.15 e-calendar-item.h
--- misc/e-calendar-item.h	2 Apr 2003 05:38:19 -0000	1.15
+++ misc/e-calendar-item.h	22 Sep 2003 03:09:28 -0000
@@ -45,6 +45,7 @@
 {
 	E_CALENDAR_ITEM_COLOR_TODAY_BOX,
 	E_CALENDAR_ITEM_COLOR_SELECTION_FG,
+	E_CALENDAR_ITEM_COLOR_SELECTION_BG_FOCUSED,
 	E_CALENDAR_ITEM_COLOR_SELECTION_BG,
 	E_CALENDAR_ITEM_COLOR_PREV_OR_NEXT_MONTH_FG,
 	
@@ -174,6 +175,7 @@
 	   top-left calendar month view. Note that -1 is used for the last days
 	   from the previous month. The days are real month days. */
 	gboolean selecting;
+	GDate *selecting_axis;
 	gboolean selection_dragging_end;
 	gboolean selection_from_full_week;
 	gboolean selection_set;
Index: misc/e-calendar.c
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-calendar.c,v
retrieving revision 1.20
diff -u -r1.20 e-calendar.c
--- misc/e-calendar.c	15 Apr 2003 21:43:05 -0000	1.20
+++ misc/e-calendar.c	22 Sep 2003 03:09:28 -0000
@@ -3,6 +3,7 @@
 /*
  * Author :
  *  Damon Chaplin <damon@ximian.com>
+ *  Bolian Yin <bolian.yin@sun.com>
  *
  * Copyright 2000, Ximian, Inc.
  *
@@ -86,11 +87,16 @@
 static void e_calendar_drag_leave	(GtkWidget      *widget,
 					 GdkDragContext *context,
 					 guint           time);
+static gboolean e_calendar_button_has_focus (ECalendar	*cal);
+static gboolean e_calendar_focus (GtkWidget *widget,
+ 				  GtkDirectionType direction);
 
 static void e_calendar_on_prev_pressed	(ECalendar	*cal);
 static void e_calendar_on_prev_released	(ECalendar	*cal);
+static void e_calendar_on_prev_clicked	(ECalendar	*cal);
 static void e_calendar_on_next_pressed	(ECalendar	*cal);
 static void e_calendar_on_next_released	(ECalendar	*cal);
+static void e_calendar_on_next_clicked	(ECalendar	*cal);
 
 static void e_calendar_start_auto_move	(ECalendar	*cal,
 					 gboolean	 moving_forward);
@@ -124,6 +130,7 @@
  	widget_class->size_allocate	   = e_calendar_size_allocate;
 	widget_class->drag_motion	   = e_calendar_drag_motion;
 	widget_class->drag_leave	   = e_calendar_drag_leave;
+ 	widget_class->focus                = e_calendar_focus;
 }
 
 
@@ -134,8 +141,6 @@
 	PangoFontDescription *small_font_desc;
 	GtkWidget *button, *pixmap;
 
-	GTK_WIDGET_UNSET_FLAGS (cal, GTK_CAN_FOCUS);
-
 	/* Create the small font. */
 
 	small_font_desc =
@@ -154,7 +159,6 @@
 
 	/* Create the arrow buttons to move to the previous/next month. */
 	button = gtk_button_new ();
-	GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
 	gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
 	gtk_widget_show (button);
 	gtk_signal_connect_object (GTK_OBJECT (button), "pressed",
@@ -163,6 +167,9 @@
 	gtk_signal_connect_object (GTK_OBJECT (button), "released",
 				   G_CALLBACK (e_calendar_on_prev_released),
 				   GTK_OBJECT (cal));
+	gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+				   G_CALLBACK (e_calendar_on_prev_clicked),
+				   GTK_OBJECT (cal));
 
 	pixmap = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
 	gtk_widget_show (pixmap);
@@ -174,7 +181,6 @@
 						NULL);
 
 	button = gtk_button_new ();
-	GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
 	gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
 	gtk_widget_show (button);
 	gtk_signal_connect_object (GTK_OBJECT (button), "pressed",
@@ -183,6 +189,9 @@
 	gtk_signal_connect_object (GTK_OBJECT (button), "released",
 				   G_CALLBACK (e_calendar_on_next_released),
 				   GTK_OBJECT (cal));
+	gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+				   G_CALLBACK (e_calendar_on_next_clicked),
+				   GTK_OBJECT (cal));
 
 	pixmap = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
 	gtk_widget_show (pixmap);
@@ -431,6 +440,12 @@
 	e_calendar_start_auto_move (cal, FALSE);
 }
 
+static void
+e_calendar_on_prev_clicked	(ECalendar	*cal)
+{
+	e_calendar_item_set_first_month (cal->calitem, cal->calitem->year,
+					 cal->calitem->month - 1);
+}
 
 static void
 e_calendar_on_next_pressed	(ECalendar	*cal)
@@ -438,6 +453,12 @@
 	e_calendar_start_auto_move (cal, TRUE);
 }
 
+static void
+e_calendar_on_next_clicked	(ECalendar	*cal)
+{
+	e_calendar_item_set_first_month (cal->calitem, cal->calitem->year,
+					 cal->calitem->month + 1);
+}
 
 static void
 e_calendar_start_auto_move	(ECalendar	*cal,
@@ -549,3 +570,99 @@
 #endif
 }
 
+static gboolean
+e_calendar_button_has_focus (ECalendar	*cal)
+{
+	GtkWidget *prev_widget, *next_widget;
+	gboolean ret_val;
+
+	g_return_val_if_fail (E_IS_CALENDAR (cal), FALSE);
+
+	prev_widget = GNOME_CANVAS_WIDGET(cal->prev_item)->widget;
+	next_widget = GNOME_CANVAS_WIDGET(cal->next_item)->widget;
+	ret_val = GTK_WIDGET_HAS_FOCUS (prev_widget) ||
+		GTK_WIDGET_HAS_FOCUS (next_widget);
+	return ret_val;
+}
+
+static gboolean
+e_calendar_focus (GtkWidget *widget, GtkDirectionType direction)
+{
+#define E_CALENDAR_FOCUS_CHILDREN_NUM 3
+	ECalendar *cal;
+	GnomeCanvas *canvas;
+	GnomeCanvasItem *children[E_CALENDAR_FOCUS_CHILDREN_NUM];
+	gint focused_index = -1;
+	gint index;
+
+	g_return_val_if_fail (widget != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CALENDAR (widget), FALSE);
+	cal = E_CALENDAR (widget);
+	canvas = GNOME_CANVAS (widget);
+
+	if (!GTK_WIDGET_CAN_FOCUS (widget))
+		return FALSE;
+
+	children[0] = GNOME_CANVAS_ITEM (cal->calitem);
+	children[1] = cal->prev_item;
+	children[2] = cal->next_item;
+
+	/* get current focused item, if e-calendar has had focus */
+	if (GTK_WIDGET_HAS_FOCUS (widget) || e_calendar_button_has_focus (cal))
+		for (index = 0; canvas->focused_item && index < E_CALENDAR_FOCUS_CHILDREN_NUM; ++index) {
+			if (children[index] == canvas->focused_item) {
+				focused_index = index;
+				break;
+			}
+		}
+
+	if (focused_index == -1)
+		if (direction == GTK_DIR_TAB_FORWARD)
+			focused_index = 0;
+		else
+			focused_index = E_CALENDAR_FOCUS_CHILDREN_NUM - 1;
+	else
+		if (direction == GTK_DIR_TAB_FORWARD)
+			++focused_index;
+		else
+			--focused_index;
+
+	if (focused_index < 0 ||
+	    focused_index >= E_CALENDAR_FOCUS_CHILDREN_NUM)
+		/* move out of e-calendar */
+		return FALSE;
+	gnome_canvas_item_grab_focus (children[focused_index]);
+	if (GNOME_IS_CANVAS_WIDGET (children[focused_index])) {
+		GtkWidget *widget;
+		widget = GNOME_CANVAS_WIDGET (children[focused_index])->widget;
+		gtk_widget_grab_focus (widget);
+	}
+	return TRUE;
+}
+
+void
+e_calendar_set_focusable (ECalendar *cal, gboolean focusable)
+{
+	GtkWidget *prev_widget, *next_widget;
+
+	g_return_if_fail (E_IS_CALENDAR (cal));
+
+	prev_widget = GNOME_CANVAS_WIDGET(cal->prev_item)->widget;
+	next_widget = GNOME_CANVAS_WIDGET(cal->next_item)->widget;
+
+	if (focusable) {
+		GTK_WIDGET_SET_FLAGS (cal, GTK_CAN_FOCUS);
+		GTK_WIDGET_SET_FLAGS (prev_widget, GTK_CAN_FOCUS);
+		GTK_WIDGET_SET_FLAGS (next_widget, GTK_CAN_FOCUS);
+	}
+	else {
+		if (GTK_WIDGET_HAS_FOCUS (cal) || e_calendar_button_has_focus (cal)) {
+			GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (cal));
+			if (toplevel)
+				gtk_widget_grab_focus (toplevel);
+		}
+		GTK_WIDGET_UNSET_FLAGS (cal, GTK_CAN_FOCUS);
+		GTK_WIDGET_UNSET_FLAGS (prev_widget, GTK_CAN_FOCUS);
+		GTK_WIDGET_UNSET_FLAGS (next_widget, GTK_CAN_FOCUS);
+	}
+}
Index: misc/e-calendar.h
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-calendar.h,v
retrieving revision 1.8
diff -u -r1.8 e-calendar.h
--- misc/e-calendar.h	2 Dec 2002 03:28:22 -0000	1.8
+++ misc/e-calendar.h	22 Sep 2003 03:09:29 -0000
@@ -93,6 +93,7 @@
 					 gint		*left,
 					 gint		*right);
 
+void       e_calendar_set_focusable (ECalendar *cal, gboolean focusable);
 
 #ifdef __cplusplus
 }
Index: misc/e-dateedit.c
===================================================================
RCS file: /cvs/gnome/evolution/widgets/misc/e-dateedit.c,v
retrieving revision 1.36
diff -u -r1.36 e-dateedit.c
--- misc/e-dateedit.c	28 Aug 2003 14:27:46 -0000	1.36
+++ misc/e-dateedit.c	22 Sep 2003 03:09:30 -0000
@@ -1180,6 +1180,7 @@
 
         position_date_popup (dedit);
 	gtk_widget_show (priv->cal_popup);
+	gdk_keyboard_grab (priv->cal_popup->window, TRUE, GDK_CURRENT_TIME);
 	gtk_widget_grab_focus (priv->cal_popup);
 	gtk_grab_add (priv->cal_popup);
 	gdk_pointer_grab (priv->cal_popup->window, TRUE,
@@ -1365,6 +1366,7 @@
 	gtk_widget_hide (dedit->priv->cal_popup);
 	gtk_grab_remove (dedit->priv->cal_popup);
 	gdk_pointer_ungrab (GDK_CURRENT_TIME);
+	gdk_keyboard_ungrab (GDK_CURRENT_TIME);
 }
 
 
