mirror of
https://github.com/brl/mutter.git
synced 2025-02-16 13:24:09 +00:00
wayland: implement global and window keybindings
Synthetize XInput events from ClutterEvents in MetaWaylandKeyboard, and pass them to the keybindings infrastructure for early handling, so that we can activate them even if the currently focused window is not an X11 one (or if there is no focused window, or we're modal) https://bugzilla.gnome.org/show_bug.cgi?id=706963
This commit is contained in:
parent
9cff36bf30
commit
67457dc25c
@ -3186,7 +3186,9 @@ event_callback (XEvent *event,
|
||||
translation altogether by directly using the Clutter events */
|
||||
if (meta_is_wayland_compositor () &&
|
||||
event->type == GenericEvent &&
|
||||
event->xcookie.evtype == XI_Motion)
|
||||
(event->xcookie.evtype == XI_Motion ||
|
||||
event->xcookie.evtype == XI_KeyPress ||
|
||||
event->xcookie.evtype == XI_KeyRelease))
|
||||
return FALSE;
|
||||
|
||||
return meta_display_handle_event (display, event);
|
||||
|
@ -2065,22 +2065,22 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
gboolean handled;
|
||||
const char *str;
|
||||
MetaScreen *screen;
|
||||
gboolean was_current_time;
|
||||
|
||||
/* if key event was on root window, we have a shortcut */
|
||||
screen = meta_display_screen_for_root (display, event->event);
|
||||
|
||||
/* else round-trip to server */
|
||||
if (screen == NULL)
|
||||
screen = meta_display_screen_for_xwindow (display, event->event);
|
||||
|
||||
if (screen == NULL)
|
||||
return FALSE; /* event window is destroyed */
|
||||
/* We only ever have one screen */
|
||||
screen = display->screens->data;
|
||||
|
||||
/* ignore key events on popup menus and such. */
|
||||
if (meta_ui_window_is_widget (screen->ui, event->event))
|
||||
return FALSE;
|
||||
|
||||
/* window may be NULL */
|
||||
if (display->current_time == CurrentTime)
|
||||
{
|
||||
display->current_time = event->time;
|
||||
was_current_time = TRUE;
|
||||
}
|
||||
else
|
||||
was_current_time = FALSE;
|
||||
|
||||
keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0);
|
||||
|
||||
@ -2098,11 +2098,11 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
{
|
||||
handled = process_overlay_key (display, screen, event, keysym);
|
||||
if (handled)
|
||||
return TRUE;
|
||||
goto out;
|
||||
|
||||
handled = process_iso_next_group (display, screen, event, keysym);
|
||||
if (handled)
|
||||
return TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
XIAllowEvents (display->xdisplay, event->deviceid,
|
||||
@ -2112,7 +2112,11 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
if (all_keys_grabbed)
|
||||
{
|
||||
if (display->grab_op == META_GRAB_OP_NONE)
|
||||
return TRUE;
|
||||
{
|
||||
handled = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we get here we have a global grab, because
|
||||
* we're in some special keyboard mode such as window move
|
||||
* mode.
|
||||
@ -2191,14 +2195,20 @@ meta_display_process_key_event (MetaDisplay *display,
|
||||
meta_display_end_grab_op (display, event->time);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
handled = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Do the normal keybindings */
|
||||
return process_event (display->key_bindings,
|
||||
display->n_key_bindings,
|
||||
display, screen, window, event, keysym,
|
||||
!all_keys_grabbed && window);
|
||||
handled = process_event (display->key_bindings,
|
||||
display->n_key_bindings,
|
||||
display, screen, window, event, keysym,
|
||||
!all_keys_grabbed && window);
|
||||
|
||||
out:
|
||||
if (was_current_time)
|
||||
display->current_time = CurrentTime;
|
||||
return handled;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -442,7 +442,86 @@ set_modifiers (MetaWaylandKeyboard *keyboard,
|
||||
new_state.group);
|
||||
}
|
||||
|
||||
void
|
||||
#define N_BUTTONS 5
|
||||
|
||||
static gboolean
|
||||
process_keybinding (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaWaylandSurface *surface;
|
||||
XGenericEventCookie generic_event;
|
||||
XIDeviceEvent device_event;
|
||||
unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
ClutterModifierType state;
|
||||
int i;
|
||||
|
||||
if (!display) /* not initialized yet */
|
||||
return FALSE;
|
||||
|
||||
generic_event.type = GenericEvent;
|
||||
generic_event.serial = 0;
|
||||
generic_event.send_event = False;
|
||||
generic_event.display = display->xdisplay;
|
||||
generic_event.extension = display->xinput_opcode;
|
||||
if (clutter_event_type (event) == CLUTTER_KEY_PRESS)
|
||||
generic_event.evtype = XI_KeyPress;
|
||||
else
|
||||
generic_event.evtype = XI_KeyRelease;
|
||||
/* Mutter assumes the data for the event is already retrieved by GDK
|
||||
* so we don't need the cookie */
|
||||
generic_event.cookie = 0;
|
||||
generic_event.data = &device_event;
|
||||
|
||||
memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
|
||||
|
||||
/* Can't use clutter_event_get_time() here, because evdev timestamps
|
||||
have nothing to do with X timestamps */
|
||||
device_event.time = meta_display_get_current_time_roundtrip (display);
|
||||
device_event.deviceid = clutter_event_get_device_id (event);
|
||||
device_event.sourceid = 0; /* not used, not sure what this should be */
|
||||
device_event.detail = clutter_event_get_key_code (event);
|
||||
device_event.root = DefaultRootWindow (display->xdisplay);
|
||||
device_event.flags = 0;
|
||||
|
||||
surface = keyboard->focus;
|
||||
if (surface)
|
||||
device_event.event = surface->window ? surface->window->xwindow : device_event.root;
|
||||
else
|
||||
device_event.event = device_event.root;
|
||||
|
||||
/* Mutter doesn't really know about the sub-windows. This assumes it
|
||||
doesn't care either */
|
||||
device_event.child = device_event.event;
|
||||
device_event.root_x = 0;
|
||||
device_event.root_y = 0;
|
||||
|
||||
state = clutter_event_get_state (event);
|
||||
|
||||
for (i = 0; i < N_BUTTONS; i++)
|
||||
if ((state & (CLUTTER_BUTTON1_MASK << i)))
|
||||
XISetMask (button_mask, i + 1);
|
||||
device_event.buttons.mask_len = N_BUTTONS + 1;
|
||||
device_event.buttons.mask = button_mask;
|
||||
|
||||
device_event.valuators.mask_len = 0;
|
||||
device_event.valuators.mask = NULL;
|
||||
device_event.valuators.values = NULL;
|
||||
|
||||
device_event.mods.base = xkb_state_serialize_mods (keyboard->xkb_state,
|
||||
XKB_STATE_MODS_DEPRESSED);
|
||||
device_event.mods.latched = xkb_state_serialize_mods (keyboard->xkb_state,
|
||||
XKB_STATE_MODS_LATCHED);
|
||||
device_event.mods.locked = xkb_state_serialize_mods (keyboard->xkb_state,
|
||||
XKB_STATE_MODS_LOCKED);
|
||||
device_event.mods.effective = xkb_state_serialize_mods (keyboard->xkb_state,
|
||||
XKB_STATE_MODS_EFFECTIVE);
|
||||
memset (&device_event.group, 0, sizeof (device_event.group));
|
||||
|
||||
return meta_display_process_key_event (display, surface ? surface->window : NULL, &device_event);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
const ClutterKeyEvent *event)
|
||||
{
|
||||
@ -456,7 +535,11 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
!clutter_input_device_keycode_to_evdev (event->device,
|
||||
event->hardware_keycode,
|
||||
&evdev_code))
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
/* Give a chance to process keybindings */
|
||||
if (process_keybinding (keyboard, (ClutterEvent*) event))
|
||||
return TRUE;
|
||||
|
||||
/* We want to ignore events that are sent because of auto-repeat. In
|
||||
the Clutter event stream these appear as a single key press
|
||||
@ -471,7 +554,7 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
/* Ignore the event if the key is already down */
|
||||
for (k = keyboard->keys.data; k < end; k++)
|
||||
if (*k == evdev_code)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
/* Otherwise add the key to the list of pressed keys */
|
||||
k = wl_array_add (&keyboard->keys, sizeof (*k));
|
||||
@ -507,6 +590,7 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
event->time,
|
||||
evdev_code,
|
||||
state);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -126,7 +126,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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -681,7 +681,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
|
||||
|
Loading…
x
Reference in New Issue
Block a user