From 450afbaf5112758bddecae3ae93f0aec8ff80aae Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Wed, 4 Sep 2013 15:01:11 +0200 Subject: [PATCH] wayland: reimplement keyboard state handling properly We can't rely on clutter's xkb_state, because that's updated when events are pulled from the kernel, not when we see them. Instead, use the new clutter API to get the full modifier state from the event (which, as a side effect, also works when clutter is using the X11 backend for running nested). https://bugzilla.gnome.org/show_bug.cgi?id=706963 --- src/wayland/meta-wayland-keyboard.c | 189 +++++++++++++--------------- src/wayland/meta-wayland-keyboard.h | 8 +- src/wayland/meta-wayland-seat.c | 9 +- src/wayland/meta-wayland-seat.h | 2 +- src/wayland/meta-wayland.c | 25 ++-- 5 files changed, 107 insertions(+), 126 deletions(-) diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c index 466b4386d..4a94e135e 100644 --- a/src/wayland/meta-wayland-keyboard.c +++ b/src/wayland/meta-wayland-keyboard.c @@ -202,7 +202,7 @@ lose_keyboard_focus (struct wl_listener *listener, void *data) keyboard->focus_resource = NULL; } -static void +static gboolean default_grab_key (MetaWaylandKeyboardGrab *grab, uint32_t time, uint32_t key, uint32_t state) { @@ -218,6 +218,8 @@ default_grab_key (MetaWaylandKeyboardGrab *grab, serial = wl_display_next_serial (display); wl_keyboard_send_key (resource, serial, time, key, state); } + + return resource != NULL; } static struct wl_resource * @@ -274,12 +276,14 @@ static const MetaWaylandKeyboardGrabInterface default_grab_modifiers, }; -static void +static gboolean modal_key (MetaWaylandKeyboardGrab *grab, uint32_t time, uint32_t key, uint32_t state) { + /* FALSE means: let the event through to clutter */ + return FALSE; } static void @@ -328,12 +332,6 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, manager = clutter_device_manager_get_default (); clutter_evdev_set_keyboard_map (manager, keyboard->xkb_info.keymap); - keyboard->xkb_state = clutter_evdev_get_keyboard_state (manager); - xkb_state_ref (keyboard->xkb_state); - } - else - { - keyboard->xkb_state = xkb_state_new (keyboard->xkb_info.keymap); } return TRUE; @@ -351,52 +349,6 @@ meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info) close (xkb_info->keymap_fd); } -static void -update_state_from_clutter (MetaWaylandKeyboard *keyboard, - ClutterModifierType modifier_state) -{ - uint32_t depressed_mods = 0; - uint32_t locked_mods = 0; - - if ((modifier_state & CLUTTER_SHIFT_MASK) && - keyboard->xkb_info.shift_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.shift_mod); - - if ((modifier_state & CLUTTER_LOCK_MASK) && - keyboard->xkb_info.caps_mod != XKB_MOD_INVALID) - locked_mods |= (1 << keyboard->xkb_info.caps_mod); - - if ((modifier_state & CLUTTER_CONTROL_MASK) && - keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod); - - if ((modifier_state & CLUTTER_MOD1_MASK) && - keyboard->xkb_info.alt_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.alt_mod); - - if ((modifier_state & CLUTTER_MOD2_MASK) && - keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.mod2_mod); - - if ((modifier_state & CLUTTER_MOD3_MASK) && - keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.mod3_mod); - - if ((modifier_state & CLUTTER_SUPER_MASK) && - keyboard->xkb_info.super_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.super_mod); - - if ((modifier_state & CLUTTER_MOD5_MASK) && - keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID) - depressed_mods |= (1 << keyboard->xkb_info.mod5_mod); - - xkb_state_update_mask (keyboard->xkb_state, - depressed_mods, - 0, - locked_mods, - 0, 0, 0); -} - static gboolean state_equal (MetaWaylandXkbState *one, MetaWaylandXkbState *two) @@ -409,25 +361,20 @@ state_equal (MetaWaylandXkbState *one, static void set_modifiers (MetaWaylandKeyboard *keyboard, - guint32 serial, - ClutterModifierType modifier_state) + guint32 serial, + ClutterEvent *event) { MetaWaylandKeyboardGrab *grab = keyboard->grab; MetaWaylandXkbState new_state; + guint effective_state; - /* In the evdev case, the state is shared with the clutter backend, so - we don't need to update it */ - if (!keyboard->is_evdev) - update_state_from_clutter (keyboard, modifier_state); - - new_state.mods_depressed = xkb_state_serialize_mods (keyboard->xkb_state, - XKB_STATE_MODS_DEPRESSED); - new_state.mods_latched = xkb_state_serialize_mods (keyboard->xkb_state, - XKB_STATE_MODS_LATCHED); - new_state.mods_locked = xkb_state_serialize_mods (keyboard->xkb_state, - XKB_STATE_MODS_LOCKED); - new_state.group = xkb_state_serialize_layout (keyboard->xkb_state, - XKB_STATE_LAYOUT_EFFECTIVE); + clutter_event_get_state_full (event, + NULL, + &new_state.mods_depressed, + &new_state.mods_latched, + &new_state.mods_locked, + &effective_state); + new_state.group = (effective_state >> 13) & 0x3; if (state_equal (&keyboard->modifier_state, &new_state)) return; @@ -442,36 +389,24 @@ set_modifiers (MetaWaylandKeyboard *keyboard, new_state.group); } -void -meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, - const ClutterKeyEvent *event) +static gboolean +update_pressed_keys (MetaWaylandKeyboard *keyboard, + uint32_t evdev_code, + gboolean is_press) { - gboolean state = event->type == CLUTTER_KEY_PRESS; - guint evdev_code; - uint32_t serial; - - /* We can't do anything with the event if we can't get an evdev - keycode for it */ - if (event->device == NULL || - !clutter_input_device_keycode_to_evdev (event->device, - event->hardware_keycode, - &evdev_code)) - return; - - /* We want to ignore events that are sent because of auto-repeat. In - the Clutter event stream these appear as a single key press - event. We can detect that because the key will already have been - pressed */ - if (state) + if (is_press) { uint32_t *end = (void *) ((char *) keyboard->keys.data + keyboard->keys.size); uint32_t *k; - /* Ignore the event if the key is already down */ + /* We want to ignore events that are sent because of auto-repeat. In + the Clutter event stream these appear as a single key press + event. We can detect that because the key will already have been + pressed */ for (k = keyboard->keys.data; k < end; k++) if (*k == evdev_code) - return; + return TRUE; /* Otherwise add the key to the list of pressed keys */ k = wl_array_add (&keyboard->keys, sizeof (*k)); @@ -494,19 +429,56 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, } g_warning ("unexpected key release event for key 0x%x", evdev_code); + return FALSE; found: (void) 0; } + return FALSE; +} + +gboolean +meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, + const ClutterKeyEvent *event) +{ + gboolean is_press = event->type == CLUTTER_KEY_PRESS; + guint xkb_keycode, evdev_code; + uint32_t serial; + gboolean autorepeat; + gboolean handled; + + xkb_keycode = event->hardware_keycode; + if (event->device == NULL || + !clutter_input_device_keycode_to_evdev (event->device, + xkb_keycode, &evdev_code)) + evdev_code = xkb_keycode - 8; /* What everyone is doing in practice... */ + + autorepeat = update_pressed_keys (keyboard, evdev_code, is_press); + + meta_verbose ("Handling key %s%s event code %d\n", + is_press ? "press" : "release", + autorepeat ? " (autorepeat)" : "", + xkb_keycode); + + if (autorepeat) + return FALSE; + serial = wl_display_next_serial (keyboard->display); - set_modifiers (keyboard, serial, event->modifier_state); + set_modifiers (keyboard, serial, (ClutterEvent*)event); - keyboard->grab->interface->key (keyboard->grab, - event->time, - evdev_code, - state); + handled = keyboard->grab->interface->key (keyboard->grab, + event->time, + evdev_code, + is_press); + + if (handled) + meta_verbose ("Sent event to wayland client\n"); + else + meta_verbose ("No wayland surface is focused, continuing normal operation\n"); + + return handled; } void @@ -597,7 +569,6 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard) meta_wayland_xkb_info_destroy (&keyboard->xkb_info); xkb_context_unref (keyboard->xkb_context); - xkb_state_unref (keyboard->xkb_state); /* XXX: What about keyboard->resource_list? */ if (keyboard->focus_resource) @@ -615,8 +586,10 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard, uint32_t *k; uint32_t serial; + meta_verbose ("Asked to acquire modal keyboard grab, timestamp %d\n", timestamp); + if (keyboard->grab != &keyboard->default_grab) - return FALSE; + return FALSE; if (keyboard->focus) { @@ -627,15 +600,19 @@ meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard, 0, 0, 0, 0); for (k = keyboard->keys.data; k < end; k++) - keyboard->grab->interface->key (keyboard->grab, - timestamp, - *k, 0); + { + keyboard->grab->interface->key (keyboard->grab, + timestamp, + *k, 0); + } } grab = g_slice_new0 (MetaWaylandKeyboardGrab); grab->interface = &modal_grab; meta_wayland_keyboard_start_grab (keyboard, grab); + meta_verbose ("Acquired modal keyboard grab, timestamp %d\n", timestamp); + return TRUE; } @@ -668,8 +645,12 @@ meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard, keyboard->modifier_state.group); for (k = keyboard->keys.data; k < end; k++) - keyboard->grab->interface->key (keyboard->grab, - timestamp, - *k, 1); + { + keyboard->grab->interface->key (keyboard->grab, + timestamp, + *k, 1); + } } + + meta_verbose ("Released modal keyboard grab, timestamp %d\n", timestamp); } diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h index 4ea124dc8..110363d78 100644 --- a/src/wayland/meta-wayland-keyboard.h +++ b/src/wayland/meta-wayland-keyboard.h @@ -50,8 +50,8 @@ struct _MetaWaylandKeyboardGrabInterface { - void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time, - uint32_t key, uint32_t state); + gboolean (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time, + uint32_t key, uint32_t state); void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group); @@ -111,9 +111,7 @@ struct _MetaWaylandKeyboard struct wl_display *display; struct xkb_context *xkb_context; - struct xkb_state *xkb_state; gboolean is_evdev; - MetaWaylandXkbInfo xkb_info; struct xkb_rule_names xkb_names; @@ -126,7 +124,7 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, struct wl_display *display, gboolean is_evdev); -void +gboolean meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard, const ClutterKeyEvent *event); diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c index 6f320787e..adf68fa5a 100644 --- a/src/wayland/meta-wayland-seat.c +++ b/src/wayland/meta-wayland-seat.c @@ -446,7 +446,7 @@ count_buttons (const ClutterEvent *event) return count; } -void +gboolean meta_wayland_seat_handle_event (MetaWaylandSeat *seat, const ClutterEvent *event) { @@ -467,9 +467,8 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat, case CLUTTER_KEY_PRESS: case CLUTTER_KEY_RELEASE: - meta_wayland_keyboard_handle_event (&seat->keyboard, - (const ClutterKeyEvent *) event); - break; + return meta_wayland_keyboard_handle_event (&seat->keyboard, + (const ClutterKeyEvent *) event); case CLUTTER_SCROLL: handle_scroll_event (seat, (const ClutterScrollEvent *) event); @@ -478,6 +477,8 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat, default: break; } + + return FALSE; } static void diff --git a/src/wayland/meta-wayland-seat.h b/src/wayland/meta-wayland-seat.h index a8e6d2e5c..09b9d7093 100644 --- a/src/wayland/meta-wayland-seat.h +++ b/src/wayland/meta-wayland-seat.h @@ -90,7 +90,7 @@ MetaWaylandSeat * meta_wayland_seat_new (struct wl_display *display, gboolean is_native); -void +gboolean meta_wayland_seat_handle_event (MetaWaylandSeat *seat, const ClutterEvent *event); diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 43c7d9569..adc2ef597 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -545,7 +545,7 @@ synthesize_motion_event (MetaWaylandCompositor *compositor, XIDeviceEvent device_event; unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 }; MetaDisplay *display = meta_get_display (); - ClutterModifierType state; + ClutterModifierType button_state; int i; generic_event.type = GenericEvent; @@ -618,10 +618,18 @@ synthesize_motion_event (MetaWaylandCompositor *compositor, device_event.root_x = wl_fixed_to_double (pointer->x); device_event.root_y = wl_fixed_to_double (pointer->y); - state = clutter_event_get_state (event); + clutter_event_get_state_full (event, + &button_state, + (ClutterModifierType*)&device_event.mods.base, + (ClutterModifierType*)&device_event.mods.latched, + (ClutterModifierType*)&device_event.mods.locked, + (ClutterModifierType*)&device_event.mods.effective); + device_event.mods.effective &= ~button_state; + memset (&device_event.group, 0, sizeof (device_event.group)); + device_event.group.effective = (device_event.mods.effective >> 13) & 0x3; for (i = 0; i < N_BUTTONS; i++) - if ((state & (CLUTTER_BUTTON1_MASK << i))) + if ((button_state & (CLUTTER_BUTTON1_MASK << i))) XISetMask (button_mask, i + 1); device_event.buttons.mask_len = N_BUTTONS + 1; device_event.buttons.mask = button_mask; @@ -630,14 +638,6 @@ synthesize_motion_event (MetaWaylandCompositor *compositor, device_event.valuators.mask = NULL; device_event.valuators.values = NULL; - memset (&device_event.mods, 0, sizeof (device_event.mods)); - device_event.mods.effective = - state & (CLUTTER_MODIFIER_MASK & - ~(((CLUTTER_BUTTON1_MASK << N_BUTTONS) - 1) ^ - (CLUTTER_BUTTON1_MASK - 1))); - - memset (&device_event.group, 0, sizeof (device_event.group)); - meta_display_handle_event (display, (XEvent *) &generic_event); } @@ -678,7 +678,8 @@ event_cb (ClutterActor *stage, reset_idletimes (event); - meta_wayland_seat_handle_event (compositor->seat, event); + if (meta_wayland_seat_handle_event (compositor->seat, event)) + return TRUE; /* HACK: for now, the surfaces from Wayland clients aren't integrated into Mutter's event handling and Mutter won't give them