[evolution] Avoid gdk_keyboard_grab/ungrab() and gdk_pointer_grab/ungrab().



commit 2ce2f8c27698e6122c6a2687f710a18bb4ca602b
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Nov 30 10:39:03 2012 -0500

    Avoid gdk_keyboard_grab/ungrab() and gdk_pointer_grab/ungrab().
    
    Use gdk_device_grab() and gdk_device_ungrab() instead.
    
    In some cases this requires stashing the grabbed device so it can be
    ungrabbed outside of an GdkEvent handler.

 calendar/gui/e-calendar-view.c      |   71 ++++++++++++-
 calendar/gui/e-day-view-time-item.c |   29 ++++-
 calendar/gui/e-day-view.c           |   44 +++++++-
 calendar/gui/e-day-view.h           |    3 +
 widgets/misc/e-dateedit.c           |  199 ++++++++++++++++++++++++++---------
 widgets/misc/e-map.c                |    2 +-
 widgets/table/e-cell-combo.c        |  167 +++++++++++++++++++++++------
 widgets/table/e-cell-combo.h        |    3 +
 8 files changed, 417 insertions(+), 101 deletions(-)
---
diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c
index bbf890a..9c21a18 100644
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@ -76,6 +76,10 @@ struct _ECalendarViewPrivate {
 
 	GtkTargetList *copy_target_list;
 	GtkTargetList *paste_target_list;
+
+	/* All keyboard devices are grabbed
+	 * while a tooltip window is shown. */
+	GQueue grabbed_keyboards;
 };
 
 enum {
@@ -353,6 +357,13 @@ calendar_view_dispose (GObject *object)
 		priv->selected_cut_list = NULL;
 	}
 
+	while (!g_queue_is_empty (&priv->grabbed_keyboards)) {
+		GdkDevice *keyboard;
+		keyboard = g_queue_pop_head (&priv->grabbed_keyboards);
+		gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
+		g_object_unref (keyboard);
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_calendar_view_parent_class)->dispose (object);
 }
@@ -1833,15 +1844,25 @@ e_calendar_view_modify_and_send (ECalendarView *cal_view,
 
 static gboolean
 tooltip_grab (GtkWidget *tooltip,
-              GdkEventKey *event,
+              GdkEvent *key_event,
               ECalendarView *view)
 {
-	GtkWidget *widget = (GtkWidget *) g_object_get_data (G_OBJECT (view), "tooltip-window");
+	GtkWidget *widget;
+	GdkDevice *keyboard;
+	guint32 event_time;
 
-	if (!widget)
+	widget = g_object_get_data (G_OBJECT (view), "tooltip-window");
+	if (widget == NULL)
 		return TRUE;
 
-	gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+	event_time = gdk_event_get_time (key_event);
+
+	while (!g_queue_is_empty (&view->priv->grabbed_keyboards)) {
+		keyboard = g_queue_pop_head (&view->priv->grabbed_keyboards);
+		gdk_device_ungrab (keyboard, event_time);
+		g_object_unref (keyboard);
+	}
+
 	gtk_widget_destroy (widget);
 	g_object_set_data (G_OBJECT (view), "tooltip-window", NULL);
 
@@ -1927,10 +1948,14 @@ e_calendar_view_get_tooltips (const ECalendarViewEventData *data)
 	GtkStyle *style = gtk_widget_get_default_style ();
 	GtkWidget *widget;
 	GdkWindow *window;
+	GdkDisplay *display;
+	GdkDeviceManager *device_manager;
+	GQueue *grabbed_keyboards;
 	ECalComponent *newcomp = e_cal_component_new ();
 	icaltimezone *zone, *default_zone;
 	ECalModel *model;
 	ECalClient *client = NULL;
+	GList *list, *link;
 	gboolean free_text = FALSE;
 
 	/* This function is a timeout callback. */
@@ -2099,8 +2124,44 @@ e_calendar_view_get_tooltips (const ECalendarViewEventData *data)
 
 	e_calendar_view_move_tip (pevent->tooltip, pevent->x +16, pevent->y + 16);
 
+	/* Grab all keyboard devices.  A key press from
+	 * any of them will dismiss the tooltip window. */
+
 	window = gtk_widget_get_window (pevent->tooltip);
-	gdk_keyboard_grab (window, FALSE, GDK_CURRENT_TIME);
+	display = gdk_window_get_display (window);
+	device_manager = gdk_display_get_device_manager (display);
+
+	grabbed_keyboards = &data->cal_view->priv->grabbed_keyboards;
+	g_warn_if_fail (g_queue_is_empty (grabbed_keyboards));
+
+	list = gdk_device_manager_list_devices (
+		device_manager, GDK_DEVICE_TYPE_MASTER);
+
+	for (link = list; link != NULL; link = g_list_next (link)) {
+		GdkDevice *device = GDK_DEVICE (link->data);
+		GdkGrabStatus grab_status;
+
+		if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+			continue;
+
+		grab_status = gdk_device_grab (
+			device,
+			window,
+			GDK_OWNERSHIP_NONE,
+			FALSE,
+			GDK_KEY_PRESS_MASK |
+			GDK_KEY_RELEASE_MASK,
+			NULL,
+			GDK_CURRENT_TIME);
+
+		if (grab_status == GDK_GRAB_SUCCESS)
+			g_queue_push_tail (
+				grabbed_keyboards,
+				g_object_ref (device));
+	}
+
+	g_list_free (list);
+
 	g_signal_connect (
 		pevent->tooltip, "key-press-event",
 		G_CALLBACK (tooltip_grab), data->cal_view);
diff --git a/calendar/gui/e-day-view-time-item.c b/calendar/gui/e-day-view-time-item.c
index 3a8284b..f337aa0 100644
--- a/calendar/gui/e-day-view-time-item.c
+++ b/calendar/gui/e-day-view-time-item.c
@@ -908,6 +908,9 @@ e_day_view_time_item_on_button_press (EDayViewTimeItem *time_item,
 	GdkWindow *window;
 	EDayView *day_view;
 	GnomeCanvas *canvas;
+	GdkGrabStatus grab_status;
+	GdkDevice *event_device;
+	guint32 event_time;
 	gint row;
 
 	day_view = e_day_view_time_item_get_day_view (time_item);
@@ -927,10 +930,20 @@ e_day_view_time_item_on_button_press (EDayViewTimeItem *time_item,
 
 	window = gtk_layout_get_bin_window (GTK_LAYOUT (canvas));
 
-	if (gdk_pointer_grab (window, FALSE,
-			      GDK_POINTER_MOTION_MASK
-			      | GDK_BUTTON_RELEASE_MASK,
-			      NULL, NULL, event->button.time) == 0) {
+	event_device = gdk_event_get_device (event);
+	event_time = gdk_event_get_time (event);
+
+	grab_status = gdk_device_grab (
+		event_device,
+		window,
+		GDK_OWNERSHIP_NONE,
+		FALSE,
+		GDK_POINTER_MOTION_MASK |
+		GDK_BUTTON_RELEASE_MASK,
+		NULL,
+		event_time);
+
+	if (grab_status == GDK_GRAB_SUCCESS) {
 		e_day_view_start_selection (day_view, -1, row);
 		time_item->priv->dragging_selection = TRUE;
 	}
@@ -946,7 +959,13 @@ e_day_view_time_item_on_button_release (EDayViewTimeItem *time_item,
 	g_return_if_fail (day_view != NULL);
 
 	if (time_item->priv->dragging_selection) {
-		gdk_pointer_ungrab (event->button.time);
+		GdkDevice *event_device;
+		guint32 event_time;
+
+		event_device = gdk_event_get_device (event);
+		event_time = gdk_event_get_time (event);
+		gdk_device_ungrab (event_device, event_time);
+
 		e_day_view_finish_selection (day_view);
 		e_day_view_stop_auto_scroll (day_view);
 	}
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 0f0448d..db4557c 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -1394,6 +1394,14 @@ e_day_view_dispose (GObject *object)
 		}
 	}
 
+	if (day_view->grabbed_pointer != NULL) {
+		gdk_device_ungrab (
+			day_view->grabbed_pointer,
+			GDK_CURRENT_TIME);
+		g_object_unref (day_view->grabbed_pointer);
+		day_view->grabbed_pointer = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_day_view_parent_class)->dispose (object);
 }
@@ -3184,6 +3192,9 @@ e_day_view_on_top_canvas_button_press (GtkWidget *widget,
 			event_time);
 
 		if (grab_status == GDK_GRAB_SUCCESS) {
+			g_warn_if_fail (day_view->grabbed_pointer == NULL);
+			day_view->grabbed_pointer = g_object_ref (event_device);
+
 			if (event_time - day_view->bc_event_time > 250)
 				e_day_view_get_selected_time_range (
 					E_CALENDAR_VIEW (day_view),
@@ -3345,6 +3356,9 @@ e_day_view_on_main_canvas_button_press (GtkWidget *widget,
 			event_time);
 
 		if (grab_status == GDK_GRAB_SUCCESS) {
+			g_warn_if_fail (day_view->grabbed_pointer == NULL);
+			day_view->grabbed_pointer = g_object_ref (event_device);
+
 			if (event_time - day_view->bc_event_time > 250)
 				e_day_view_get_selected_time_range (
 					E_CALENDAR_VIEW (day_view),
@@ -3618,6 +3632,9 @@ e_day_view_on_long_event_click (EDayView *day_view,
 			event_time);
 
 		if (grab_status == GDK_GRAB_SUCCESS) {
+			g_warn_if_fail (day_view->grabbed_pointer == NULL);
+			day_view->grabbed_pointer = g_object_ref (event_device);
+
 			day_view->resize_event_day = E_DAY_VIEW_LONG_EVENT;
 			day_view->resize_event_num = event_num;
 			day_view->resize_drag_pos = pos;
@@ -3717,6 +3734,9 @@ e_day_view_on_event_click (EDayView *day_view,
 			event_time);
 
 		if (grab_status == GDK_GRAB_SUCCESS) {
+			g_warn_if_fail (day_view->grabbed_pointer == NULL);
+			day_view->grabbed_pointer = g_object_ref (event_device);
+
 			day_view->resize_event_day = day;
 			day_view->resize_event_num = event_num;
 			day_view->resize_drag_pos = pos;
@@ -3907,11 +3927,15 @@ e_day_view_on_top_canvas_button_release (GtkWidget *widget,
 	event_device = gdk_event_get_device (button_event);
 	event_time = gdk_event_get_time (button_event);
 
+	if (day_view->grabbed_pointer == event_device) {
+		gdk_device_ungrab (day_view->grabbed_pointer, event_time);
+		g_object_unref (day_view->grabbed_pointer);
+		day_view->grabbed_pointer = NULL;
+	}
+
 	if (day_view->selection_is_being_dragged) {
-		gdk_device_ungrab (event_device, event_time);
 		e_day_view_finish_selection (day_view);
 	} else if (day_view->resize_drag_pos != E_CALENDAR_VIEW_POS_NONE) {
-		gdk_device_ungrab (event_device, event_time);
 		e_day_view_finish_long_event_resize (day_view);
 	} else if (day_view->pressed_event_day != -1) {
 		e_day_view_start_editing_event (
@@ -3937,12 +3961,16 @@ e_day_view_on_main_canvas_button_release (GtkWidget *widget,
 	event_device = gdk_event_get_device (button_event);
 	event_time = gdk_event_get_time (button_event);
 
+	if (day_view->grabbed_pointer == event_device) {
+		gdk_device_ungrab (day_view->grabbed_pointer, event_time);
+		g_object_unref (day_view->grabbed_pointer);
+		day_view->grabbed_pointer = NULL;
+	}
+
 	if (day_view->selection_is_being_dragged) {
-		gdk_device_ungrab (event_device, event_time);
 		e_day_view_finish_selection (day_view);
 		e_day_view_stop_auto_scroll (day_view);
 	} else if (day_view->resize_drag_pos != E_CALENDAR_VIEW_POS_NONE) {
-		gdk_device_ungrab (event_device, event_time);
 		e_day_view_finish_resize (day_view);
 		e_day_view_stop_auto_scroll (day_view);
 	} else if (day_view->pressed_event_day != -1) {
@@ -5403,7 +5431,13 @@ e_day_view_do_key_press (GtkWidget *widget,
 	/* The Escape key aborts a resize operation. */
 	if (day_view->resize_drag_pos != E_CALENDAR_VIEW_POS_NONE) {
 		if (keyval == GDK_KEY_Escape) {
-			gdk_pointer_ungrab (event->time);
+			if (day_view->grabbed_pointer != NULL) {
+				gdk_device_ungrab (
+					day_view->grabbed_pointer,
+					event->time);
+				g_object_unref (day_view->grabbed_pointer);
+				day_view->grabbed_pointer = NULL;
+			}
 			e_day_view_abort_resize (day_view);
 		}
 		return FALSE;
diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h
index 9f43a1a..5bf8974 100644
--- a/calendar/gui/e-day-view.h
+++ b/calendar/gui/e-day-view.h
@@ -459,6 +459,9 @@ struct _EDayView {
 	GnomeCanvasItem *drag_bar_item;
 	GnomeCanvasItem *drag_item;
 
+	/* Grabbed pointer device while dragging. */
+	GdkDevice *grabbed_pointer;
+
 	/* "am" and "pm" in the current locale, and their widths. */
 	gchar *am_string;
 	gchar *pm_string;
diff --git a/widgets/misc/e-dateedit.c b/widgets/misc/e-dateedit.c
index e24d413..dce571b 100644
--- a/widgets/misc/e-dateedit.c
+++ b/widgets/misc/e-dateedit.c
@@ -62,6 +62,9 @@ struct _EDateEditPrivate {
 	GtkWidget *none_button;		/* This will only be visible if a
 					 * 'None' date/time is permitted. */
 
+	GdkDevice *grabbed_keyboard;
+	GdkDevice *grabbed_pointer;
+
 	gboolean show_date;
 	gboolean show_time;
 	gboolean use_24_hour_format;
@@ -140,14 +143,15 @@ static gboolean e_date_edit_mnemonic_activate	(GtkWidget	*widget,
 static void e_date_edit_grab_focus		(GtkWidget	*widget);
 
 static gint on_date_entry_key_press		(GtkWidget	*widget,
-						 GdkEventKey	*event,
+						 GdkEvent	*key_event,
 						 EDateEdit	*dedit);
 static gint on_date_entry_key_release		(GtkWidget	*widget,
-						 GdkEventKey	*event,
+						 GdkEvent	*key_event,
 						 EDateEdit	*dedit);
 static void on_date_button_clicked		(GtkWidget	*widget,
 						 EDateEdit	*dedit);
-static void e_date_edit_show_date_popup		(EDateEdit	*dedit);
+static void e_date_edit_show_date_popup		(EDateEdit	*dedit,
+						 GdkEvent	*event);
 static void position_date_popup			(EDateEdit	*dedit);
 static void on_date_popup_none_button_clicked	(GtkWidget	*button,
 						 EDateEdit	*dedit);
@@ -177,10 +181,10 @@ static gboolean e_date_edit_parse_time		(EDateEdit	*dedit,
 static void on_date_edit_time_selected		(GtkComboBox	*combo,
 						 EDateEdit	*dedit);
 static gint on_time_entry_key_press		(GtkWidget	*widget,
-						 GdkEventKey	*event,
+						 GdkEvent	*key_event,
 						 EDateEdit	*dedit);
 static gint on_time_entry_key_release		(GtkWidget	*widget,
-						 GdkEventKey	*event,
+						 GdkEvent	*key_event,
 						 EDateEdit	*dedit);
 static gint on_date_entry_focus_out		(GtkEntry	*entry,
 						 GdkEventFocus  *event,
@@ -339,6 +343,22 @@ date_edit_dispose (GObject *object)
 		dedit->priv->cal_popup = NULL;
 	}
 
+	if (dedit->priv->grabbed_keyboard != NULL) {
+		gdk_device_ungrab (
+			dedit->priv->grabbed_keyboard,
+			GDK_CURRENT_TIME);
+		g_object_unref (dedit->priv->grabbed_keyboard);
+		dedit->priv->grabbed_keyboard = NULL;
+	}
+
+	if (dedit->priv->grabbed_pointer != NULL) {
+		gdk_device_ungrab (
+			dedit->priv->grabbed_pointer,
+			GDK_CURRENT_TIME);
+		g_object_unref (dedit->priv->grabbed_pointer);
+		dedit->priv->grabbed_pointer = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_date_edit_parent_class)->dispose (object);
 }
@@ -1354,19 +1374,31 @@ static void
 on_date_button_clicked (GtkWidget *widget,
                         EDateEdit *dedit)
 {
-	e_date_edit_show_date_popup (dedit);
+	GdkEvent *event;
+
+	/* Obtain the GdkEvent that triggered
+	 * the date button's "clicked" signal. */
+	event = gtk_get_current_event ();
+	e_date_edit_show_date_popup (dedit, event);
 }
 
 static void
-e_date_edit_show_date_popup (EDateEdit *dedit)
+e_date_edit_show_date_popup (EDateEdit *dedit,
+                             GdkEvent *event)
 {
 	EDateEditPrivate *priv;
 	ECalendar *calendar;
+	GdkDevice *event_device;
+	GdkDevice *assoc_device;
+	GdkDevice *keyboard_device;
+	GdkDevice *pointer_device;
 	GdkWindow *window;
+	GdkGrabStatus grab_status;
 	struct tm mtm;
 	const gchar *date_text;
 	GDate selected_day;
 	gboolean clear_selection = FALSE;
+	guint event_time;
 
 	priv = dedit->priv;
 	calendar = E_CALENDAR (priv->calendar);
@@ -1398,14 +1430,63 @@ e_date_edit_show_date_popup (EDateEdit *dedit)
 	gtk_grab_add (priv->cal_popup);
 
 	window = gtk_widget_get_window (priv->cal_popup);
-	gdk_pointer_grab (
-		window, TRUE,
-		GDK_BUTTON_PRESS_MASK |
-		GDK_BUTTON_RELEASE_MASK |
-		GDK_POINTER_MOTION_MASK,
-		NULL, NULL, GDK_CURRENT_TIME);
-	gdk_keyboard_grab (window, TRUE, GDK_CURRENT_TIME);
-	gdk_window_focus (window, GDK_CURRENT_TIME);
+
+	g_return_if_fail (priv->grabbed_keyboard == NULL);
+	g_return_if_fail (priv->grabbed_pointer == NULL);
+
+	event_device = gdk_event_get_device (event);
+	assoc_device = gdk_device_get_associated_device (event_device);
+
+	event_time = gdk_event_get_time (event);
+
+	if (gdk_device_get_source (event_device) == GDK_SOURCE_KEYBOARD) {
+		keyboard_device = event_device;
+		pointer_device = assoc_device;
+	} else {
+		keyboard_device = assoc_device;
+		pointer_device = event_device;
+	}
+
+	if (keyboard_device != NULL) {
+		grab_status = gdk_device_grab (
+			keyboard_device,
+			window,
+			GDK_OWNERSHIP_WINDOW,
+			TRUE,
+			GDK_KEY_PRESS_MASK |
+			GDK_KEY_RELEASE_MASK,
+			NULL,
+			event_time);
+		if (grab_status == GDK_GRAB_SUCCESS) {
+			priv->grabbed_keyboard =
+				g_object_ref (keyboard_device);
+		}
+	}
+
+	if (pointer_device != NULL) {
+		grab_status = gdk_device_grab (
+			pointer_device,
+			window,
+			GDK_OWNERSHIP_WINDOW,
+			TRUE,
+			GDK_BUTTON_PRESS_MASK |
+			GDK_BUTTON_RELEASE_MASK |
+			GDK_POINTER_MOTION_MASK,
+			NULL,
+			event_time);
+		if (grab_status == GDK_GRAB_SUCCESS) {
+			priv->grabbed_pointer =
+				g_object_ref (pointer_device);
+		} else if (priv->grabbed_keyboard != NULL) {
+			gdk_device_ungrab (
+				priv->grabbed_keyboard,
+				event_time);
+			g_object_unref (priv->grabbed_keyboard);
+			priv->grabbed_keyboard = NULL;
+		}
+	}
+
+	gdk_window_focus (window, event_time);
 }
 
 /* This positions the date popup below and to the left of the arrow button,
@@ -1516,19 +1597,13 @@ on_date_popup_key_press (GtkWidget *widget,
                          GdkEventKey *event,
                          EDateEdit *dedit)
 {
-	GdkWindow *window;
-
-	window = gtk_widget_get_window (dedit->priv->cal_popup);
-
-	if (event->keyval != GDK_KEY_Escape) {
-		gdk_keyboard_grab (window, TRUE, GDK_CURRENT_TIME);
-		return FALSE;
+	if (event->keyval == GDK_KEY_Escape) {
+		g_signal_stop_emission_by_name (widget, "key_press_event");
+		hide_date_popup (dedit);
+		return TRUE;
 	}
 
-	g_signal_stop_emission_by_name (widget, "key_press_event");
-	hide_date_popup (dedit);
-
-	return TRUE;
+	return FALSE;
 }
 
 /* A mouse button has been pressed while the date popup is showing.
@@ -1583,8 +1658,22 @@ 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);
+
+	if (dedit->priv->grabbed_keyboard != NULL) {
+		gdk_device_ungrab (
+			dedit->priv->grabbed_keyboard,
+			GDK_CURRENT_TIME);
+		g_object_unref (dedit->priv->grabbed_keyboard);
+		dedit->priv->grabbed_keyboard = NULL;
+	}
+
+	if (dedit->priv->grabbed_pointer != NULL) {
+		gdk_device_ungrab (
+			dedit->priv->grabbed_pointer,
+			GDK_CURRENT_TIME);
+		g_object_unref (dedit->priv->grabbed_pointer);
+		dedit->priv->grabbed_pointer = NULL;
+	}
 }
 
 /* Clears the time popup and rebuilds it using the lower_hour, upper_hour
@@ -1737,21 +1826,26 @@ on_date_edit_time_selected (GtkComboBox *combo,
 
 static gint
 on_date_entry_key_press (GtkWidget *widget,
-                         GdkEventKey *event,
+                         GdkEvent *key_event,
                          EDateEdit *dedit)
 {
-	if (event->state & GDK_MOD1_MASK
-	    && (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down
-		|| event->keyval == GDK_KEY_Return)) {
-		g_signal_stop_emission_by_name (
-			widget, "key_press_event");
-		e_date_edit_show_date_popup (dedit);
+	GdkModifierType event_state = 0;
+	guint event_keyval = 0;
+
+	gdk_event_get_keyval (key_event, &event_keyval);
+	gdk_event_get_state (key_event, &event_state);
+
+	if (event_state & GDK_MOD1_MASK
+	    && (event_keyval == GDK_KEY_Up || event_keyval == GDK_KEY_Down
+		|| event_keyval == GDK_KEY_Return)) {
+		g_signal_stop_emission_by_name (widget, "key_press_event");
+		e_date_edit_show_date_popup (dedit, key_event);
 		return TRUE;
 	}
 
 	/* If the user hits the return key emit a "date_changed" signal if
 	 * needed. But let the signal carry on. */
-	if (event->keyval == GDK_KEY_Return) {
+	if (event_keyval == GDK_KEY_Return) {
 		e_date_edit_check_date_changed (dedit);
 		return FALSE;
 	}
@@ -1761,20 +1855,25 @@ on_date_entry_key_press (GtkWidget *widget,
 
 static gint
 on_time_entry_key_press (GtkWidget *widget,
-                         GdkEventKey *event,
+                         GdkEvent *key_event,
                          EDateEdit *dedit)
 {
 	GtkWidget *child;
+	GdkModifierType event_state = 0;
+	guint event_keyval = 0;
+
+	gdk_event_get_keyval (key_event, &event_keyval);
+	gdk_event_get_state (key_event, &event_state);
 
 	child = gtk_bin_get_child (GTK_BIN (dedit->priv->time_combo));
 
 	/* I'd like to use Alt+Up/Down for popping up the list, like Win32,
 	 * but the combo steals any Up/Down keys, so we use Alt + Return. */
 #if 0
-	if (event->state & GDK_MOD1_MASK
-	    && (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down)) {
+	if (event_state & GDK_MOD1_MASK
+	    && (event_keyval == GDK_KEY_Up || event_keyval == GDK_KEY_Down)) {
 #else
-	if (event->state & GDK_MOD1_MASK && event->keyval == GDK_KEY_Return) {
+	if (event_state & GDK_MOD1_MASK && event_keyval == GDK_KEY_Return) {
 #endif
 		g_signal_stop_emission_by_name (widget, "key_press_event");
 		g_signal_emit_by_name (child, "activate", 0);
@@ -1783,10 +1882,8 @@ on_time_entry_key_press (GtkWidget *widget,
 
 	/* Stop the return key from emitting the activate signal, and check
 	 * if we need to emit a "time_changed" signal. */
-	if (event->keyval == GDK_KEY_Return) {
-		g_signal_stop_emission_by_name (
-			widget,
-						"key_press_event");
+	if (event_keyval == GDK_KEY_Return) {
+		g_signal_stop_emission_by_name (widget, "key_press_event");
 		e_date_edit_check_time_changed (dedit);
 		return TRUE;
 	}
@@ -1796,7 +1893,7 @@ on_time_entry_key_press (GtkWidget *widget,
 
 static gint
 on_date_entry_key_release (GtkWidget *widget,
-                           GdkEventKey *event,
+                           GdkEvent *key_event,
                            EDateEdit *dedit)
 {
 	e_date_edit_check_date_changed (dedit);
@@ -1805,13 +1902,15 @@ on_date_entry_key_release (GtkWidget *widget,
 
 static gint
 on_time_entry_key_release (GtkWidget *widget,
-                           GdkEventKey *event,
+                           GdkEvent *key_event,
                            EDateEdit *dedit)
 {
-	if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down) {
-		g_signal_stop_emission_by_name (
-			widget,
-						"key_release_event");
+	guint event_keyval = 0;
+
+	gdk_event_get_keyval (key_event, &event_keyval);
+
+	if (event_keyval == GDK_KEY_Up || event_keyval == GDK_KEY_Down) {
+		g_signal_stop_emission_by_name (widget, "key_release_event");
 		e_date_edit_check_time_changed (dedit);
 		return TRUE;
 	}
diff --git a/widgets/misc/e-map.c b/widgets/misc/e-map.c
index ebccf38..b90c4f2 100644
--- a/widgets/misc/e-map.c
+++ b/widgets/misc/e-map.c
@@ -735,7 +735,7 @@ e_map_button_release (GtkWidget *widget,
 	if (event->button != 1)
 		return FALSE;
 
-	gdk_pointer_ungrab (event->time);
+	gdk_device_ungrab (event->device, event->time);
 	return TRUE;
 }
 
diff --git a/widgets/table/e-cell-combo.c b/widgets/table/e-cell-combo.c
index cc72e90..b3e1c52 100644
--- a/widgets/table/e-cell-combo.c
+++ b/widgets/table/e-cell-combo.c
@@ -101,7 +101,7 @@ static gint	e_cell_combo_button_release	(GtkWidget *popup_window,
 						 GdkEvent *button_event,
 						 ECellCombo *ecc);
 static gint	e_cell_combo_key_press		(GtkWidget *popup_window,
-						 GdkEventKey *event,
+						 GdkEvent *key_event,
 						 ECellCombo *ecc);
 static void	e_cell_combo_update_cell	(ECellCombo *ecc);
 static void	e_cell_combo_restart_edit	(ECellCombo *ecc);
@@ -221,9 +221,22 @@ e_cell_combo_dispose (GObject *object)
 {
 	ECellCombo *ecc = E_CELL_COMBO (object);
 
-	if (ecc->popup_window)
+	if (ecc->popup_window != NULL) {
 		gtk_widget_destroy (ecc->popup_window);
-	ecc->popup_window = NULL;
+		ecc->popup_window = NULL;
+	}
+
+	if (ecc->grabbed_keyboard != NULL) {
+		gdk_device_ungrab (ecc->grabbed_keyboard, GDK_CURRENT_TIME);
+		g_object_unref (ecc->grabbed_keyboard);
+		ecc->grabbed_keyboard = NULL;
+	}
+
+	if (ecc->grabbed_pointer != NULL) {
+		gdk_device_ungrab (ecc->grabbed_pointer, GDK_CURRENT_TIME);
+		g_object_unref (ecc->grabbed_pointer);
+		ecc->grabbed_pointer = NULL;
+	}
 
 	G_OBJECT_CLASS (e_cell_combo_parent_class)->dispose (object);
 }
@@ -260,9 +273,15 @@ e_cell_combo_do_popup (ECellPopup *ecp,
 {
 	ECellCombo *ecc = E_CELL_COMBO (ecp);
 	GtkTreeSelection *selection;
+	GdkGrabStatus grab_status;
 	GdkWindow *window;
-	guint32 time;
-	gint error_code;
+	GdkDevice *keyboard;
+	GdkDevice *pointer;
+	GdkDevice *event_device;
+	guint32 event_time;
+
+	g_return_val_if_fail (ecc->grabbed_keyboard == NULL, FALSE);
+	g_return_val_if_fail (ecc->grabbed_pointer == NULL, FALSE);
 
 	selection = gtk_tree_view_get_selection (
 		GTK_TREE_VIEW (ecc->popup_tree_view));
@@ -276,27 +295,65 @@ e_cell_combo_do_popup (ECellPopup *ecp,
 	g_signal_handlers_unblock_by_func (
 		selection, e_cell_combo_selection_changed, ecc);
 
-	if (event->type == GDK_BUTTON_PRESS)
-		time = event->button.time;
-	else
-		time = event->key.time;
-
 	window = gtk_widget_get_window (ecc->popup_tree_view);
 
-	error_code = gdk_pointer_grab (
-		window, TRUE,
-		GDK_ENTER_NOTIFY_MASK |
-		GDK_BUTTON_PRESS_MASK |
-		GDK_BUTTON_RELEASE_MASK |
-		GDK_POINTER_MOTION_HINT_MASK |
-		GDK_BUTTON1_MOTION_MASK,
-		NULL, NULL, time);
+	event_device = gdk_event_get_device (event);
+	event_time = gdk_event_get_time (event);
 
-	if (error_code != 0)
-		g_warning ("Failed to get pointer grab (%i)", error_code);
+	if (gdk_device_get_source (event_device) == GDK_SOURCE_KEYBOARD) {
+		keyboard = event_device;
+		pointer = gdk_device_get_associated_device (event_device);
+	} else {
+		keyboard = gdk_device_get_associated_device (event_device);
+		pointer = event_device;
+	}
+
+	if (pointer != NULL) {
+		grab_status = gdk_device_grab (
+			pointer,
+			window,
+			GDK_OWNERSHIP_NONE,
+			TRUE,
+			GDK_ENTER_NOTIFY_MASK |
+			GDK_BUTTON_PRESS_MASK |
+			GDK_BUTTON_RELEASE_MASK |
+			GDK_POINTER_MOTION_HINT_MASK |
+			GDK_BUTTON1_MOTION_MASK,
+			NULL,
+			event_time);
+
+		if (grab_status != GDK_GRAB_SUCCESS)
+			return FALSE;
+
+		ecc->grabbed_pointer = g_object_ref (pointer);
+	}
 
 	gtk_grab_add (ecc->popup_window);
-	gdk_keyboard_grab (window, TRUE, time);
+
+	if (keyboard != NULL) {
+		grab_status = gdk_device_grab (
+			keyboard,
+			window,
+			GDK_OWNERSHIP_NONE,
+			TRUE,
+			GDK_KEY_PRESS_MASK |
+			GDK_KEY_RELEASE_MASK,
+			NULL,
+			event_time);
+
+		if (grab_status != GDK_GRAB_SUCCESS) {
+			if (ecc->grabbed_pointer != NULL) {
+				gdk_device_ungrab (
+					ecc->grabbed_pointer,
+					event_time);
+				g_object_unref (ecc->grabbed_pointer);
+				ecc->grabbed_pointer = NULL;
+			}
+			return FALSE;
+		}
+
+		ecc->grabbed_keyboard = g_object_ref (keyboard);
+	}
 
 	return TRUE;
 }
@@ -597,8 +654,19 @@ e_cell_combo_button_press (GtkWidget *popup_window,
 	}
 
 	gtk_grab_remove (ecc->popup_window);
-	gdk_pointer_ungrab (event_time);
-	gdk_keyboard_ungrab (event_time);
+
+	if (ecc->grabbed_keyboard != NULL) {
+		gdk_device_ungrab (ecc->grabbed_keyboard, event_time);
+		g_object_unref (ecc->grabbed_keyboard);
+		ecc->grabbed_keyboard = NULL;
+	}
+
+	if (ecc->grabbed_pointer != NULL) {
+		gdk_device_ungrab (ecc->grabbed_pointer, event_time);
+		g_object_unref (ecc->grabbed_pointer);
+		ecc->grabbed_pointer = NULL;
+	}
+
 	gtk_widget_hide (ecc->popup_window);
 
 	e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
@@ -639,9 +707,21 @@ e_cell_combo_button_release (GtkWidget *popup_window,
 
 	/* The button was released inside the list, so we hide the popup and
 	 * update the cell to reflect the new selection. */
+
 	gtk_grab_remove (ecc->popup_window);
-	gdk_pointer_ungrab (event_time);
-	gdk_keyboard_ungrab (event_time);
+
+	if (ecc->grabbed_keyboard != NULL) {
+		gdk_device_ungrab (ecc->grabbed_keyboard, event_time);
+		g_object_unref (ecc->grabbed_keyboard);
+		ecc->grabbed_keyboard = NULL;
+	}
+
+	if (ecc->grabbed_pointer != NULL) {
+		gdk_device_ungrab (ecc->grabbed_pointer, event_time);
+		g_object_unref (ecc->grabbed_pointer);
+		ecc->grabbed_pointer = NULL;
+	}
+
 	gtk_widget_hide (ecc->popup_window);
 
 	e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
@@ -657,30 +737,47 @@ e_cell_combo_button_release (GtkWidget *popup_window,
  * pressed we hide the popup, and do not change the cell contents. */
 static gint
 e_cell_combo_key_press (GtkWidget *popup_window,
-                        GdkEventKey *event,
+                        GdkEvent *key_event,
                         ECellCombo *ecc)
 {
+	guint event_keyval = 0;
+	guint32 event_time;
+
+	gdk_event_get_keyval (key_event, &event_keyval);
+	event_time = gdk_event_get_time (key_event);
+
 	/* If the Escape key is pressed we hide the popup. */
-	if (event->keyval != GDK_KEY_Escape
-	    && event->keyval != GDK_KEY_Return
-	    && event->keyval != GDK_KEY_KP_Enter
-	    && event->keyval != GDK_KEY_ISO_Enter
-	    && event->keyval != GDK_KEY_3270_Enter)
+	if (event_keyval != GDK_KEY_Escape
+	    && event_keyval != GDK_KEY_Return
+	    && event_keyval != GDK_KEY_KP_Enter
+	    && event_keyval != GDK_KEY_ISO_Enter
+	    && event_keyval != GDK_KEY_3270_Enter)
 		return FALSE;
 
-	if (event->keyval == GDK_KEY_Escape &&
+	if (event_keyval == GDK_KEY_Escape &&
 	   (!ecc->popup_window || !gtk_widget_get_visible (ecc->popup_window)))
 		return FALSE;
 
 	gtk_grab_remove (ecc->popup_window);
-	gdk_pointer_ungrab (event->time);
-	gdk_keyboard_ungrab (event->time);
+
+	if (ecc->grabbed_keyboard != NULL) {
+		gdk_device_ungrab (ecc->grabbed_keyboard, event_time);
+		g_object_unref (ecc->grabbed_keyboard);
+		ecc->grabbed_keyboard = NULL;
+	}
+
+	if (ecc->grabbed_pointer != NULL) {
+		gdk_device_ungrab (ecc->grabbed_pointer, event_time);
+		g_object_unref (ecc->grabbed_pointer);
+		ecc->grabbed_pointer = NULL;
+	}
+
 	gtk_widget_hide (ecc->popup_window);
 
 	e_cell_popup_set_shown (E_CELL_POPUP (ecc), FALSE);
 	d (g_print ("%s: popup_shown = FALSE\n", __FUNCTION__));
 
-	if (event->keyval != GDK_KEY_Escape)
+	if (event_keyval != GDK_KEY_Escape)
 		e_cell_combo_update_cell (ecc);
 
 	e_cell_combo_restart_edit (ecc);
diff --git a/widgets/table/e-cell-combo.h b/widgets/table/e-cell-combo.h
index ec77dcd..3d2fb33 100644
--- a/widgets/table/e-cell-combo.h
+++ b/widgets/table/e-cell-combo.h
@@ -63,6 +63,9 @@ struct _ECellCombo {
 	GtkWidget *popup_window;
 	GtkWidget *popup_scrolled_window;
 	GtkWidget *popup_tree_view;
+
+	GdkDevice *grabbed_keyboard;
+	GdkDevice *grabbed_pointer;
 };
 
 struct _ECellComboClass {



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