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
This commit is contained in:
parent
1d56d50fcd
commit
614d6bd0f8
5 changed files with 87 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue