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
@ -40,6 +40,7 @@
|
|||||||
#include "meta-idle-monitor-xsync.h"
|
#include "meta-idle-monitor-xsync.h"
|
||||||
#include "meta-monitor-manager-xrandr.h"
|
#include "meta-monitor-manager-xrandr.h"
|
||||||
#include "backends/meta-monitor-manager-dummy.h"
|
#include "backends/meta-monitor-manager-dummy.h"
|
||||||
|
#include "wayland/meta-wayland.h"
|
||||||
#include "meta-cursor-renderer-x11.h"
|
#include "meta-cursor-renderer-x11.h"
|
||||||
|
|
||||||
#include <meta/util.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))
|
if (event->type == (priv->xsync_event_base + XSyncAlarmNotify))
|
||||||
handle_alarm_notify (backend, event);
|
handle_alarm_notify (backend, event);
|
||||||
|
|
||||||
@ -800,6 +816,20 @@ meta_backend_x11_select_stage_events (MetaBackend *backend)
|
|||||||
}
|
}
|
||||||
|
|
||||||
XISelectEvents (priv->xdisplay, xwin, &mask, 1);
|
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
|
static void
|
||||||
|
@ -477,6 +477,33 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
|||||||
return handled;
|
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
|
static void
|
||||||
move_resources (struct wl_list *destination, struct wl_list *source)
|
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,
|
gboolean meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||||
const ClutterKeyEvent *event);
|
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,
|
void meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
|
||||||
MetaWaylandSurface *surface);
|
MetaWaylandSurface *surface);
|
||||||
|
@ -207,6 +207,28 @@ meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
|||||||
return meta_wayland_seat_handle_event (compositor->seat, event);
|
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
|
void
|
||||||
meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
|
meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor,
|
||||||
MetaWaylandSurface *surface)
|
MetaWaylandSurface *surface)
|
||||||
|
@ -39,6 +39,10 @@ void meta_wayland_compositor_update (MetaWaylandComp
|
|||||||
const ClutterEvent *event);
|
const ClutterEvent *event);
|
||||||
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
gboolean meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
|
||||||
const ClutterEvent *event);
|
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_repick (MetaWaylandCompositor *compositor);
|
||||||
|
|
||||||
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
|
||||||
|
Loading…
Reference in New Issue
Block a user