Commit 2ce2f8c2 authored by Matthew Barnes's avatar Matthew Barnes
Browse files

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.
parent ab3f65a1
......@@ -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);
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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);