From 10df80762c650cf4cfb19a3860d97b7cb072769c Mon Sep 17 00:00:00 2001 From: Rui Matos Date: Fri, 29 Mar 2013 02:38:43 +0100 Subject: [PATCH] keybindings: Add API to freeze/unfreeze the keyboard We'll use this in gnome-shell to freeze the keyboard right before switching input source and unfreeze it after that's finished so that we don't lose any key events to the wrong input source. https://bugzilla.gnome.org/show_bug.cgi?id=697001 --- src/core/keybindings.c | 44 ++++++++++++++++++++++++++++++++++++++---- src/meta/display.h | 7 +++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/core/keybindings.c b/src/core/keybindings.c index b1681c7ee..94f86dc58 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -1264,7 +1264,8 @@ grab_status_to_string (int status) static gboolean grab_keyboard (MetaDisplay *display, Window xwindow, - guint32 timestamp) + guint32 timestamp, + int grab_mode) { int result; int grab_status; @@ -1280,12 +1281,21 @@ grab_keyboard (MetaDisplay *display, */ meta_error_trap_push_with_return (display); + /* Strictly, we only need to set grab_mode on the keyboard device + * while the pointer should always be XIGrabModeAsync. Unfortunately + * there is a bug in the X server, only fixed (link below) in 1.15, + * which swaps these arguments for keyboard devices. As such, we set + * both the device and the paired device mode which works around + * that bug and also works on fixed X servers. + * + * http://cgit.freedesktop.org/xorg/xserver/commit/?id=9003399708936481083424b4ff8f18a16b88b7b3 + */ grab_status = XIGrabDevice (display->xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID, xwindow, timestamp, None, - XIGrabModeAsync, XIGrabModeAsync, + grab_mode, grab_mode, True, /* owner_events */ &mask); @@ -1339,7 +1349,7 @@ meta_screen_grab_all_keys (MetaScreen *screen, guint32 timestamp) meta_topic (META_DEBUG_KEYBINDINGS, "Grabbing all keys on RootWindow\n"); - retval = grab_keyboard (screen->display, screen->xroot, timestamp); + retval = grab_keyboard (screen->display, screen->xroot, timestamp, XIGrabModeAsync); if (retval) { screen->all_keys_grabbed = TRUE; @@ -1392,7 +1402,7 @@ meta_window_grab_all_keys (MetaWindow *window, meta_topic (META_DEBUG_KEYBINDINGS, "Grabbing all keys on window %s\n", window->desc); - retval = grab_keyboard (window->display, grabwindow, timestamp); + retval = grab_keyboard (window->display, grabwindow, timestamp, XIGrabModeAsync); if (retval) { window->keys_grabbed = FALSE; @@ -1419,6 +1429,32 @@ meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp) } } +void +meta_display_freeze_keyboard (MetaDisplay *display, Window window, guint32 timestamp) +{ + grab_keyboard (display, window, timestamp, XIGrabModeSync); +} + +void +meta_display_ungrab_keyboard (MetaDisplay *display, guint32 timestamp) +{ + ungrab_keyboard (display, timestamp); +} + +void +meta_display_unfreeze_keyboard (MetaDisplay *display, guint32 timestamp) +{ + meta_error_trap_push (display); + XIAllowEvents (display->xdisplay, META_VIRTUAL_CORE_KEYBOARD_ID, + XIAsyncDevice, timestamp); + /* We shouldn't need to unfreeze the pointer device here, however we + * have to, due to the workaround we do in grab_keyboard(). + */ + XIAllowEvents (display->xdisplay, META_VIRTUAL_CORE_POINTER_ID, + XIAsyncDevice, timestamp); + meta_error_trap_pop (display); +} + static gboolean is_modifier (MetaDisplay *display, unsigned int keycode) diff --git a/src/meta/display.h b/src/meta/display.h index 7ace85806..09f95e9cc 100644 --- a/src/meta/display.h +++ b/src/meta/display.h @@ -191,4 +191,11 @@ void meta_display_unmanage_screen (MetaDisplay *display, void meta_display_clear_mouse_mode (MetaDisplay *display); +void meta_display_freeze_keyboard (MetaDisplay *display, + Window window, + guint32 timestamp); +void meta_display_ungrab_keyboard (MetaDisplay *display, + guint32 timestamp); +void meta_display_unfreeze_keyboard (MetaDisplay *display, + guint32 timestamp); #endif