aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/misc')
-rw-r--r--widgets/misc/e-calendar-item.c265
-rw-r--r--widgets/misc/e-calendar-item.h2
-rw-r--r--widgets/misc/e-calendar.c125
-rw-r--r--widgets/misc/e-calendar.h1
-rw-r--r--widgets/misc/e-dateedit.c2
5 files changed, 342 insertions, 53 deletions
diff --git a/widgets/misc/e-calendar-item.c b/widgets/misc/e-calendar-item.c
index 1f430124d9..883ec6e0d6 100644
--- a/widgets/misc/e-calendar-item.c
+++ b/widgets/misc/e-calendar-item.c
@@ -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_get_arg (GtkObject *o,
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 @@ static double e_calendar_item_point (GnomeCanvasItem *item,
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 gint e_calendar_item_get_inclusive_days (ECalendarItem *calitem,
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_position_menu (GtkMenu *menu,
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 @@ static void
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 @@ e_calendar_item_class_init (ECalendarItemClass *class)
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 @@ e_calendar_item_init (ECalendarItem *calitem)
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 @@ e_calendar_item_destroy (GtkObject *o)
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 @@ e_calendar_item_set_arg (GtkObject *o, GtkArg *arg, guint arg_id)
}
}
+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 @@ e_calendar_item_realize (GnomeCanvasItem *item)
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 @@ e_calendar_item_draw_day_numbers (ECalendarItem *calitem,
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 @@ e_calendar_item_draw_day_numbers (ECalendarItem *calitem,
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 @@ e_calendar_item_point (GnomeCanvasItem *item, double x, double y,
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 @@ e_calendar_item_event (GnomeCanvasItem *item, GdkEvent *event)
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 @@ e_calendar_item_get_day_style (ECalendarItem *calitem,
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 @@ e_calendar_item_button_press (ECalendarItem *calitem,
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 @@ e_calendar_item_get_selection (ECalendarItem *calitem,
}
-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 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
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 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
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 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
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 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
|| 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 @@ e_calendar_item_set_selection (ECalendarItem *calitem,
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 @@ e_calendar_item_ensure_days_visible (ECalendarItem *calitem,
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 @@ e_calendar_item_ensure_days_visible (ECalendarItem *calitem,
}
}
- if (need_update)
+ if (need_update && emission)
e_calendar_item_date_range_changed (calitem);
return need_update;
diff --git a/widgets/misc/e-calendar-item.h b/widgets/misc/e-calendar-item.h
index a6fe161e5d..218095f741 100644
--- a/widgets/misc/e-calendar-item.h
+++ b/widgets/misc/e-calendar-item.h
@@ -45,6 +45,7 @@ typedef enum
{
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 @@ struct _ECalendarItem
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;
diff --git a/widgets/misc/e-calendar.c b/widgets/misc/e-calendar.c
index ec720e9047..b2eb17cf2e 100644
--- a/widgets/misc/e-calendar.c
+++ b/widgets/misc/e-calendar.c
@@ -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 gint e_calendar_drag_motion (GtkWidget *widget,
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 @@ e_calendar_class_init (ECalendarClass *class)
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 @@ e_calendar_init (ECalendar *cal)
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 @@ e_calendar_init (ECalendar *cal)
/* 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 @@ e_calendar_init (ECalendar *cal)
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 @@ e_calendar_init (ECalendar *cal)
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 @@ e_calendar_init (ECalendar *cal)
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_on_prev_pressed (ECalendar *cal)
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_on_next_pressed (ECalendar *cal)
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 @@ e_calendar_drag_leave (GtkWidget *widget,
#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);
+ }
+}
diff --git a/widgets/misc/e-calendar.h b/widgets/misc/e-calendar.h
index aadde962f4..1fe6d2500c 100644
--- a/widgets/misc/e-calendar.h
+++ b/widgets/misc/e-calendar.h
@@ -93,6 +93,7 @@ void e_calendar_get_border_size (ECalendar *cal,
gint *left,
gint *right);
+void e_calendar_set_focusable (ECalendar *cal, gboolean focusable);
#ifdef __cplusplus
}
diff --git a/widgets/misc/e-dateedit.c b/widgets/misc/e-dateedit.c
index 31b070a2e8..c6c2ad9bc7 100644
--- a/widgets/misc/e-dateedit.c
+++ b/widgets/misc/e-dateedit.c
@@ -1180,6 +1180,7 @@ e_date_edit_show_date_popup (EDateEdit *dedit)
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 @@ hide_date_popup (EDateEdit *dedit)
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);
}