experimental: use wlr_xwayland_surface_offer_focus()

Offer focus by sending WM_TAKE_FOCUS to a client window supporting it.
The client may accept or ignore the offer. If it accepts, the surface will
emit a focus_in signal notifying the compositor that it has received focus.
The compositor should then call wlr_xwayland_surface_activate(surface, true).

This is a more compatible method of giving focus to windows using the
Globally Active input model (see wlr_xwayland_icccm_input_model()) than
calling wlr_xwayland_surface_activate() unconditionally, since there is no
reliable way to know in advance whether these windows want to be focused.
This commit is contained in:
John Lindgren 2023-10-09 23:25:53 -04:00
parent 179a030bbe
commit 22b193254c
5 changed files with 47 additions and 10 deletions

View file

@ -94,6 +94,7 @@ struct view_impl {
struct view_size_hints (*get_size_hints)(struct view *self);
/* if not implemented, VIEW_WANTS_FOCUS_ALWAYS is assumed */
enum view_wants_focus (*wants_focus)(struct view *self);
void (*offer_focus)(struct view *self);
};
struct view {
@ -320,6 +321,8 @@ view_is_focusable(struct view *view) {
return view_is_focusable_from(view, NULL);
}
void view_offer_focus(struct view *view);
void view_toggle_keybinds(struct view *view);
void view_set_activated(struct view *view, bool activated);

View file

@ -34,6 +34,7 @@ struct xwayland_view {
struct wl_listener set_decorations;
struct wl_listener set_override_redirect;
struct wl_listener set_strut_partial;
struct wl_listener focus_in;
/* Not (yet) implemented */
/* struct wl_listener set_role; */

View file

@ -67,16 +67,19 @@ desktop_focus_view(struct view *view, bool raise)
workspaces_switch_to(view->workspace, /*update_focus*/ false);
}
/*
* Give input focus, even if the view claims not to want it (see
* view->impl->wants_focus). This is a workaround for so-called
* "globally active" X11 views (MATLAB known to be one such)
* that expect to be able to control focus themselves, but can't
* under labwc since it's disallowed at the wlroots level.
*/
struct seat *seat = &view->server->seat;
if (view->surface != seat->seat->keyboard_state.focused_surface) {
seat_focus_surface(seat, view->surface);
switch (view_wants_focus(view)) {
case VIEW_WANTS_FOCUS_ALWAYS:
; /* works around "a label can only be part of a statement" */
struct seat *seat = &view->server->seat;
if (view->surface != seat->seat->keyboard_state.focused_surface) {
seat_focus_surface(seat, view->surface);
}
break;
case VIEW_WANTS_FOCUS_OFFER:
view_offer_focus(view);
break;
case VIEW_WANTS_FOCUS_NEVER:
break;
}
if (raise) {

View file

@ -178,6 +178,15 @@ view_is_focusable_from(struct view *view, struct wlr_surface *prev)
&& prev && view_is_related(view, prev)));
}
void
view_offer_focus(struct view *view)
{
assert(view);
if (view->impl->offer_focus) {
view->impl->offer_focus(view);
}
}
/**
* All view_apply_xxx_geometry() functions must *not* modify
* any state besides repositioning or resizing the view.

View file

@ -100,6 +100,12 @@ xwayland_view_wants_focus(struct view *view)
return VIEW_WANTS_FOCUS_NEVER;
}
static void
xwayland_view_offer_focus(struct view *view)
{
wlr_xwayland_surface_offer_focus(xwayland_surface_from_view(view));
}
static struct wlr_xwayland_surface *
top_parent_of(struct view *view)
{
@ -280,6 +286,7 @@ handle_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&xwayland_view->set_decorations.link);
wl_list_remove(&xwayland_view->set_override_redirect.link);
wl_list_remove(&xwayland_view->set_strut_partial.link);
wl_list_remove(&xwayland_view->focus_in.link);
view_destroy(view);
}
@ -467,6 +474,18 @@ handle_set_strut_partial(struct wl_listener *listener, void *data)
}
}
static void
handle_focus_in(struct wl_listener *listener, void *data)
{
struct xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, focus_in);
struct view *view = &xwayland_view->base;
struct seat *seat = &view->server->seat;
if (view->surface != seat->seat->keyboard_state.focused_surface) {
seat_focus_surface(seat, view->surface);
}
}
static void
set_initial_position(struct view *view,
struct wlr_xwayland_surface *xwayland_surface)
@ -790,6 +809,7 @@ static const struct view_impl xwayland_view_impl = {
.is_related = xwayland_view_is_related,
.get_size_hints = xwayland_view_get_size_hints,
.wants_focus = xwayland_view_wants_focus,
.offer_focus = xwayland_view_offer_focus,
};
void
@ -834,6 +854,7 @@ xwayland_view_create(struct server *server,
CONNECT_SIGNAL(xsurface, xwayland_view, set_decorations);
CONNECT_SIGNAL(xsurface, xwayland_view, set_override_redirect);
CONNECT_SIGNAL(xsurface, xwayland_view, set_strut_partial);
CONNECT_SIGNAL(xsurface, xwayland_view, focus_in);
wl_list_insert(&view->server->views, &view->link);