[PATCH weston 13/14] compositor-x11: Attempt to track state without XKB

Daniel Stone daniel at fooishbar.org
Fri Jun 22 05:21:40 PDT 2012


This isn't very pleasant, but it's pretty much the best we can do in the
absence of either XCB XKB support, or XCB XI2 bindings (argh!).

We get a state mask with most significant X11 events (which inexplicably
includes EnterNotify but not FocusIn), but unfortunately it's only a
single flat set of effective modifiers rather than the more granular
sets we want, so we still update the state with every key, but then also
use the core X11 state as a mask to make sure we don't get any stuck
modifiers.

Ugh.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
 src/compositor-x11.c |   44 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 2dd1aec..a039269 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -610,7 +610,6 @@ x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
 	return NULL;
 }
 
-#ifdef HAVE_XCB_XKB
 static uint32_t
 get_xkb_mod_mask(struct x11_compositor *c, uint32_t in)
 {
@@ -637,6 +636,7 @@ get_xkb_mod_mask(struct x11_compositor *c, uint32_t in)
 	return ret;
 }
 
+#ifdef HAVE_XCB_XKB
 static void
 update_xkb_state(struct x11_compositor *c, xcb_xkb_state_notify_event_t *state)
 {
@@ -655,6 +655,34 @@ update_xkb_state(struct x11_compositor *c, xcb_xkb_state_notify_event_t *state)
 }
 #endif
 
+/**
+ * This is monumentally unpleasant.  If we don't have XCB-XKB bindings,
+ * the best we can do (given that XCB also lacks XI2 support), is to take
+ * the state from the core key events.  Unfortunately that only gives us
+ * the effective (i.e. union of depressed/latched/locked) state, and we
+ * need the granularity.
+ *
+ * So we still update the state with every key event we see, but also use
+ * the state field from X11 events as a mask so we don't get any stuck
+ * modifiers.
+ */
+static void
+update_xkb_state_from_core(struct x11_compositor *c, uint16_t x11_mask)
+{
+	uint32_t mask = get_xkb_mod_mask(c, x11_mask);
+	struct wl_keyboard *keyboard = &c->base.seat->keyboard;
+
+	xkb_state_update_mask(c->base.seat->xkb_state.state,
+			      keyboard->modifiers.mods_depressed & mask,
+			      keyboard->modifiers.mods_latched & mask,
+			      keyboard->modifiers.mods_locked & mask,
+			      0,
+			      0,
+			      (x11_mask >> 13) & 3);
+	notify_modifiers(&c->base.seat->seat,
+			 wl_display_next_serial(c->base.wl_display));
+}
+
 static void
 x11_compositor_deliver_button_event(struct x11_compositor *c,
 				    xcb_generic_event_t *event, int state)
@@ -663,6 +691,9 @@ x11_compositor_deliver_button_event(struct x11_compositor *c,
 		(xcb_button_press_event_t *) event;
 	uint32_t button;
 
+	if (!c->has_xkb)
+		update_xkb_state_from_core(c, button_event->state);
+
 	switch (button_event->detail) {
 	default:
 		button = button_event->detail + BTN_LEFT - 1;
@@ -767,6 +798,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 				/* Deliver the held key release now
 				 * and fall through and handle the new
 				 * event below. */
+				update_xkb_state_from_core(c, key_release->state);
 				notify_key(&c->base.seat->seat,
 					   weston_compositor_get_time(),
 					   key_release->detail - 8,
@@ -811,6 +843,8 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 		switch (event->response_type & ~0x80) {
 		case XCB_KEY_PRESS:
 			key_press = (xcb_key_press_event_t *) event;
+			if (!c->has_xkb)
+				update_xkb_state_from_core(c, key_press->state);
 			notify_key(&c->base.seat->seat,
 				   weston_compositor_get_time(),
 				   key_press->detail - 8,
@@ -840,6 +874,8 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 			break;
 		case XCB_MOTION_NOTIFY:
 			motion_notify = (xcb_motion_notify_event_t *) event;
+			if (!c->has_xkb)
+				update_xkb_state_from_core(c, motion_notify->state);
 			output = x11_compositor_find_output(c, motion_notify->event);
 			x = wl_fixed_from_int(output->base.x + motion_notify->event_x);
 			y = wl_fixed_from_int(output->base.y + motion_notify->event_y);
@@ -857,10 +893,11 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 			enter_notify = (xcb_enter_notify_event_t *) event;
 			if (enter_notify->state >= Button1Mask)
 				break;
+			if (!c->has_xkb)
+				update_xkb_state_from_core(c, enter_notify->state);
 			output = x11_compositor_find_output(c, enter_notify->event);
 			x = wl_fixed_from_int(output->base.x + enter_notify->event_x);
 			y = wl_fixed_from_int(output->base.y + enter_notify->event_y);
-			/* XXX notify_modifiers() */
 
 			notify_pointer_focus(&c->base.seat->seat,
 					     &output->base, x, y);
@@ -870,6 +907,8 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 			enter_notify = (xcb_enter_notify_event_t *) event;
 			if (enter_notify->state >= Button1Mask)
 				break;
+			if (!c->has_xkb)
+				update_xkb_state_from_core(c, enter_notify->state);
 			output = x11_compositor_find_output(c, enter_notify->event);
 			notify_pointer_focus(&c->base.seat->seat, NULL, 0, 0);
 			break;
@@ -919,6 +958,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 	switch (prev ? prev->response_type & ~0x80 : 0x80) {
 	case XCB_KEY_RELEASE:
 		key_release = (xcb_key_press_event_t *) prev;
+		update_xkb_state_from_core(c, key_release->state);
 		notify_key(&c->base.seat->seat,
 			   weston_compositor_get_time(),
 			   key_release->detail - 8,
-- 
1.7.10



More information about the wayland-devel mailing list