xwayland: add focus_in and grab_focus events

Allows the compositor to know when the XWayland focus changes.
This commit is contained in:
John Lindgren 2024-02-14 05:53:46 -05:00 committed by Kirill Primak
parent aa1163e640
commit eb5312022a
2 changed files with 20 additions and 6 deletions

View File

@ -186,6 +186,8 @@ struct wlr_xwayland_surface {
struct wl_signal set_strut_partial; struct wl_signal set_strut_partial;
struct wl_signal set_override_redirect; struct wl_signal set_override_redirect;
struct wl_signal set_geometry; struct wl_signal set_geometry;
struct wl_signal focus_in;
struct wl_signal grab_focus;
/* can be used to set initial maximized/fullscreen geometry */ /* can be used to set initial maximized/fullscreen geometry */
struct wl_signal map_request; struct wl_signal map_request;
struct wl_signal ping_timeout; struct wl_signal ping_timeout;

View File

@ -219,6 +219,8 @@ static struct wlr_xwayland_surface *xwayland_surface_create(
wl_signal_init(&surface->events.set_strut_partial); wl_signal_init(&surface->events.set_strut_partial);
wl_signal_init(&surface->events.set_override_redirect); wl_signal_init(&surface->events.set_override_redirect);
wl_signal_init(&surface->events.set_geometry); wl_signal_init(&surface->events.set_geometry);
wl_signal_init(&surface->events.focus_in);
wl_signal_init(&surface->events.grab_focus);
wl_signal_init(&surface->events.map_request); wl_signal_init(&surface->events.map_request);
wl_signal_init(&surface->events.ping_timeout); wl_signal_init(&surface->events.ping_timeout);
@ -1591,16 +1593,26 @@ static bool validate_focus_serial(uint16_t last_focus_seq, uint16_t event_seq) {
static void xwm_handle_focus_in(struct wlr_xwm *xwm, static void xwm_handle_focus_in(struct wlr_xwm *xwm,
xcb_focus_in_event_t *ev) { xcb_focus_in_event_t *ev) {
// Do not interfere with grabs
if (ev->mode == XCB_NOTIFY_MODE_GRAB ||
ev->mode == XCB_NOTIFY_MODE_UNGRAB) {
return;
}
// Ignore pointer focus change events // Ignore pointer focus change events
if (ev->detail == XCB_NOTIFY_DETAIL_POINTER) { if (ev->detail == XCB_NOTIFY_DETAIL_POINTER) {
return; return;
} }
// Do not interfere with keyboard grabs, but notify the
// compositor. Note that many legitimate X11 applications use
// keyboard grabs to "steal" focus for e.g. popup menus.
struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->event);
if (ev->mode == XCB_NOTIFY_MODE_GRAB) {
if (xsurface) {
wl_signal_emit_mutable(&xsurface->events.grab_focus, NULL);
}
return;
}
if (ev->mode == XCB_NOTIFY_MODE_UNGRAB) {
/* Do we need an ungrab_focus event? */
return;
}
// Ignore any out-of-date FocusIn event (older than the last // Ignore any out-of-date FocusIn event (older than the last
// known WM-initiated focus change) to avoid race conditions. // known WM-initiated focus change) to avoid race conditions.
// https://github.com/swaywm/wlroots/issues/2324 // https://github.com/swaywm/wlroots/issues/2324
@ -1611,9 +1623,9 @@ static void xwm_handle_focus_in(struct wlr_xwm *xwm,
// Allow focus changes between surfaces belonging to the same // Allow focus changes between surfaces belonging to the same
// application. Steam for example relies on this: // application. Steam for example relies on this:
// https://github.com/swaywm/sway/issues/1865 // https://github.com/swaywm/sway/issues/1865
struct wlr_xwayland_surface *xsurface = lookup_surface(xwm, ev->event);
if (xsurface && xwm->focus_surface && xsurface->pid == xwm->focus_surface->pid) { if (xsurface && xwm->focus_surface && xsurface->pid == xwm->focus_surface->pid) {
xwm_set_focused_window(xwm, xsurface); xwm_set_focused_window(xwm, xsurface);
wl_signal_emit_mutable(&xsurface->events.focus_in, NULL);
} else { } else {
// Try to prevent clients from changing focus between // Try to prevent clients from changing focus between
// applications, by refocusing the previous surface. // applications, by refocusing the previous surface.