From c5437b1153185ca7a6326b7eb2005683f26a96a4 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Wed, 1 Nov 2023 23:01:19 -0400 Subject: [PATCH] cursor: allow re-focusing xwayland-unmanaged surfaces We already allow some xwayland-unmanaged surfaces to take focus on map, if indicated by wlr_xwayland_or_surface_wants_focus(). But once these surfaces lose focus, they never regain it again. Add desktop_focus_view_or_surface() and call it in the appropriate places to allow these views to regain focus in the usual ways (e.g. clicking on them or focus-follows-mouse). --- include/labwc.h | 8 ++++++++ src/desktop.c | 23 +++++++++++++++++++++++ src/input/cursor.c | 21 ++++++++++++++++----- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 7ac4ad18..5701e9bb 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -382,6 +382,14 @@ void foreign_toplevel_update_outputs(struct view *view); * session is locked/input is inhibited; it will simply do nothing. */ void desktop_focus_view(struct view *view, bool raise); + +/** + * desktop_focus_view_or_surface() - like desktop_focus_view() but can + * also focus other (e.g. xwayland-unmanaged) surfaces + */ +void desktop_focus_view_or_surface(struct seat *seat, struct view *view, + struct wlr_surface *surface, bool raise); + void desktop_arrange_all_views(struct server *server); void desktop_focus_output(struct output *output); struct view *desktop_topmost_focusable_view(struct server *server); diff --git a/src/desktop.c b/src/desktop.c index ab057fbe..9eb54945 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -13,6 +13,10 @@ #include "workspaces.h" #include "xwayland.h" +#if HAVE_XWAYLAND +#include +#endif + void desktop_arrange_all_views(struct server *server) { @@ -84,6 +88,25 @@ desktop_focus_view(struct view *view, bool raise) } } +/* TODO: focus layer-shell surfaces also? */ +void +desktop_focus_view_or_surface(struct seat *seat, struct view *view, + struct wlr_surface *surface, bool raise) +{ + assert(view || surface); + if (view) { + desktop_focus_view(view, raise); +#if HAVE_XWAYLAND + } else if (wlr_surface_is_xwayland_surface(surface)) { + struct wlr_xwayland_surface *xsurface = + wlr_xwayland_surface_from_wlr_surface(surface); + if (xsurface && wlr_xwayland_or_surface_wants_focus(xsurface)) { + seat_focus_surface(seat, surface); + } +#endif + } +} + static struct wl_list * get_prev_item(struct wl_list *item) { diff --git a/src/input/cursor.c b/src/input/cursor.c index 97de12b4..58f55be1 100644 --- a/src/input/cursor.c +++ b/src/input/cursor.c @@ -479,8 +479,9 @@ process_cursor_motion(struct server *server, uint32_t time) dnd_icons_move(seat, seat->cursor->x, seat->cursor->y); } - if (ctx.view && rc.focus_follow_mouse) { - desktop_focus_view(ctx.view, rc.raise_on_focus); + if ((ctx.view || ctx.surface) && rc.focus_follow_mouse) { + desktop_focus_view_or_surface(seat, ctx.view, ctx.surface, + rc.raise_on_focus); } struct mousebind *mousebind; @@ -517,11 +518,12 @@ _cursor_update_focus(struct server *server) /* Focus surface under cursor if it isn't already focused */ struct cursor_context ctx = get_cursor_context(server); - if (ctx.view && rc.focus_follow_mouse + if ((ctx.view || ctx.surface) && rc.focus_follow_mouse && !rc.focus_follow_mouse_requires_movement && !server->osd_state.cycle_view) { /* Prevents changing keyboard focus during A-Tab */ - desktop_focus_view(ctx.view, rc.raise_on_focus); + desktop_focus_view_or_surface(&server->seat, ctx.view, + ctx.surface, rc.raise_on_focus); } cursor_update_common(server, &ctx, msec(&now), @@ -908,13 +910,22 @@ cursor_button_press(struct seat *seat, struct wlr_pointer_button_event *event) return; } - /* Handle _press_ on a layer surface */ + /* + * On press, set focus to a non-view surface that wants it. + * Action processing does not run for these surfaces and thus + * the Focus action (used for normal views) does not work. + */ if (ctx.type == LAB_SSD_LAYER_SURFACE) { struct wlr_layer_surface_v1 *layer = wlr_layer_surface_v1_from_wlr_surface(ctx.surface); if (layer && layer->current.keyboard_interactive) { seat_set_focus_layer(seat, layer); } +#ifdef HAVE_XWAYLAND + } else if (ctx.type == LAB_SSD_UNMANAGED) { + desktop_focus_view_or_surface(seat, NULL, ctx.surface, + /*raise*/ false); +#endif } /*