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); struct view_size_hints (*get_size_hints)(struct view *self);
/* if not implemented, VIEW_WANTS_FOCUS_ALWAYS is assumed */ /* if not implemented, VIEW_WANTS_FOCUS_ALWAYS is assumed */
enum view_wants_focus (*wants_focus)(struct view *self); enum view_wants_focus (*wants_focus)(struct view *self);
void (*offer_focus)(struct view *self);
}; };
struct view { struct view {
@ -320,6 +321,8 @@ view_is_focusable(struct view *view) {
return view_is_focusable_from(view, NULL); return view_is_focusable_from(view, NULL);
} }
void view_offer_focus(struct view *view);
void view_toggle_keybinds(struct view *view); void view_toggle_keybinds(struct view *view);
void view_set_activated(struct view *view, bool activated); 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_decorations;
struct wl_listener set_override_redirect; struct wl_listener set_override_redirect;
struct wl_listener set_strut_partial; struct wl_listener set_strut_partial;
struct wl_listener focus_in;
/* Not (yet) implemented */ /* Not (yet) implemented */
/* struct wl_listener set_role; */ /* struct wl_listener set_role; */

View file

@ -67,17 +67,20 @@ desktop_focus_view(struct view *view, bool raise)
workspaces_switch_to(view->workspace, /*update_focus*/ false); workspaces_switch_to(view->workspace, /*update_focus*/ false);
} }
/* switch (view_wants_focus(view)) {
* Give input focus, even if the view claims not to want it (see case VIEW_WANTS_FOCUS_ALWAYS:
* view->impl->wants_focus). This is a workaround for so-called ; /* works around "a label can only be part of a statement" */
* "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; struct seat *seat = &view->server->seat;
if (view->surface != seat->seat->keyboard_state.focused_surface) { if (view->surface != seat->seat->keyboard_state.focused_surface) {
seat_focus_surface(seat, view->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) { if (raise) {
view_move_to_front(view); view_move_to_front(view);

View file

@ -178,6 +178,15 @@ view_is_focusable_from(struct view *view, struct wlr_surface *prev)
&& prev && view_is_related(view, 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 * All view_apply_xxx_geometry() functions must *not* modify
* any state besides repositioning or resizing the view. * 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; 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 * static struct wlr_xwayland_surface *
top_parent_of(struct view *view) 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_decorations.link);
wl_list_remove(&xwayland_view->set_override_redirect.link); wl_list_remove(&xwayland_view->set_override_redirect.link);
wl_list_remove(&xwayland_view->set_strut_partial.link); wl_list_remove(&xwayland_view->set_strut_partial.link);
wl_list_remove(&xwayland_view->focus_in.link);
view_destroy(view); 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 static void
set_initial_position(struct view *view, set_initial_position(struct view *view,
struct wlr_xwayland_surface *xwayland_surface) struct wlr_xwayland_surface *xwayland_surface)
@ -790,6 +809,7 @@ static const struct view_impl xwayland_view_impl = {
.is_related = xwayland_view_is_related, .is_related = xwayland_view_is_related,
.get_size_hints = xwayland_view_get_size_hints, .get_size_hints = xwayland_view_get_size_hints,
.wants_focus = xwayland_view_wants_focus, .wants_focus = xwayland_view_wants_focus,
.offer_focus = xwayland_view_offer_focus,
}; };
void void
@ -834,6 +854,7 @@ xwayland_view_create(struct server *server,
CONNECT_SIGNAL(xsurface, xwayland_view, set_decorations); CONNECT_SIGNAL(xsurface, xwayland_view, set_decorations);
CONNECT_SIGNAL(xsurface, xwayland_view, set_override_redirect); CONNECT_SIGNAL(xsurface, xwayland_view, set_override_redirect);
CONNECT_SIGNAL(xsurface, xwayland_view, set_strut_partial); CONNECT_SIGNAL(xsurface, xwayland_view, set_strut_partial);
CONNECT_SIGNAL(xsurface, xwayland_view, focus_in);
wl_list_insert(&view->server->views, &view->link); wl_list_insert(&view->server->views, &view->link);