[mutter] Nested X11: use KeymapNotify events to fix key state on FocusIn
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] Nested X11: use KeymapNotify events to fix key state on FocusIn
- Date: Thu, 3 Sep 2015 20:03:24 +0000 (UTC)
commit 614d6bd0f80ce336df7dca64e04746b057753f3b
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Fri Aug 21 16:25:53 2015 -0400
Nested X11: use KeymapNotify events to fix key state on FocusIn
If the user Alt-Tabs out of the window, we will be left thinking
the Alt key is still pressed since we don't see a release for it.
Solve this and other related issues for the nested X11 compositor
by selecting for KeymapStateMask which causes a KeymapNotify event
to be sent after each FocusIn, and when we get these events, update
the internal XKB state and send any necessary modifiers events to
clients.
https://bugzilla.gnome.org/show_bug.cgi?id=753948
src/backends/x11/meta-backend-x11.c | 30 ++++++++++++++++++++++++++++++
src/wayland/meta-wayland-keyboard.c | 27 +++++++++++++++++++++++++++
src/wayland/meta-wayland-keyboard.h | 4 ++++
src/wayland/meta-wayland.c | 22 ++++++++++++++++++++++
src/wayland/meta-wayland.h | 4 ++++
5 files changed, 87 insertions(+), 0 deletions(-)
---
diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c
index a76dbc5..641fb8e 100644
--- a/src/backends/x11/meta-backend-x11.c
+++ b/src/backends/x11/meta-backend-x11.c
@@ -40,6 +40,7 @@
#include "meta-idle-monitor-xsync.h"
#include "meta-monitor-manager-xrandr.h"
#include "backends/meta-monitor-manager-dummy.h"
+#include "wayland/meta-wayland.h"
#include "meta-cursor-renderer-x11.h"
#include <meta/util.h>
@@ -269,6 +270,21 @@ handle_host_xevent (MetaBackend *backend,
}
}
+ if (priv->mode == META_BACKEND_X11_MODE_NESTED && event->type == FocusIn)
+ {
+ Window xwin = meta_backend_x11_get_xwindow(x11);
+ XEvent xev;
+
+ if (event->xfocus.window == xwin)
+ {
+ /* Since we've selected for KeymapStateMask, every FocusIn is followed immediately
+ * by a KeymapNotify event */
+ XMaskEvent(priv->xdisplay, KeymapStateMask, &xev);
+ MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+ meta_wayland_compositor_update_key_state (compositor, xev.xkeymap.key_vector, 32, 8);
+ }
+ }
+
if (event->type == (priv->xsync_event_base + XSyncAlarmNotify))
handle_alarm_notify (backend, event);
@@ -800,6 +816,20 @@ meta_backend_x11_select_stage_events (MetaBackend *backend)
}
XISelectEvents (priv->xdisplay, xwin, &mask, 1);
+
+ if (priv->mode == META_BACKEND_X11_MODE_NESTED)
+ {
+ /* We have no way of tracking key changes when the stage doesn't have
+ * focus, so we select for KeymapStateMask so that we get a complete
+ * dump of the keyboard state in a KeymapNotify event that immediately
+ * follows each FocusIn (and EnterNotify, but we ignore that.)
+ */
+ XWindowAttributes xwa;
+
+ XGetWindowAttributes(priv->xdisplay, xwin, &xwa);
+ XSelectInput(priv->xdisplay, xwin,
+ xwa.your_event_mask | FocusChangeMask | KeymapStateMask);
+ }
}
static void
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
index e4d4f22..8d136c9 100644
--- a/src/wayland/meta-wayland-keyboard.c
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -477,6 +477,33 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
return handled;
}
+void
+meta_wayland_keyboard_update_key_state (MetaWaylandKeyboard *keyboard,
+ char *key_vector,
+ int key_vector_len,
+ int offset)
+{
+ gboolean mods_changed = FALSE;
+
+ for (gint i = offset; i < key_vector_len * 8; i++)
+ {
+ gboolean set = (key_vector[i/8] & (1 << (i % 8))) != 0;
+
+ /* The 'offset' parameter allows the caller to have the indices
+ * into key_vector to either be X-style (base 8) or evdev (base 0), or
+ * something else (unlikely). We subtract 'offset' to convert to evdev
+ * style, then add 8 to convert the "evdev" style keycode back to
+ * the X-style that xkbcommon expects.
+ */
+ mods_changed |= xkb_state_update_key (keyboard->xkb_info.state,
+ i - offset + 8,
+ set ? XKB_KEY_DOWN : XKB_KEY_UP);
+ }
+
+ if (mods_changed)
+ notify_modifiers (keyboard);
+}
+
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
index b4a8c52..ea9db32 100644
--- a/src/wayland/meta-wayland-keyboard.h
+++ b/src/wayland/meta-wayland-keyboard.h
@@ -85,6 +85,10 @@ void meta_wayland_keyboard_update (MetaWaylandKeyboard *keyboard,
gboolean meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
const ClutterKeyEvent *event);
+void meta_wayland_keyboard_update_key_state (MetaWaylandKeyboard *compositor,
+ char *key_vector,
+ int key_vector_len,
+ int offset);
void meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
MetaWaylandSurface *surface);
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 13709f1..65e05f6 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -207,6 +207,28 @@ meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
return meta_wayland_seat_handle_event (compositor->seat, event);
}
+/* meta_wayland_compositor_update_key_state:
+ * @compositor: the #MetaWaylandCompositor
+ * @key_vector: bit vector of key states
+ * @key_vector_len: length of @key_vector
+ * @offset: the key for the first evdev keycode is found at this offset in @key_vector
+ *
+ * This function is used to resynchronize the key state that Mutter
+ * is tracking with the actual keyboard state. This is useful, for example,
+ * to handle changes in key state when a nested compositor doesn't
+ * have focus. We need to fix up the XKB modifier tracking and deliver
+ * any modifier changes to clients.
+ */
+void
+meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
+ char *key_vector,
+ int key_vector_len,
+ int offset)
+{
+ meta_wayland_keyboard_update_key_state (&compositor->seat->keyboard,
+ key_vector, key_vector_len, offset);
+}
+
void
meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
MetaWaylandSurface *surface)
diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h
index ec12e06..7db5ca1 100644
--- a/src/wayland/meta-wayland.h
+++ b/src/wayland/meta-wayland.h
@@ -39,6 +39,10 @@ void meta_wayland_compositor_update (MetaWaylandComp
const ClutterEvent *event);
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event);
+void meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor,
+ char *key_vector,
+ int key_vector_len,
+ int offset);
void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]