]> git.mdlowis.com Git - proto/labwc.git/commitdiff
view/xwayland: avoid focusing views that don't want focus
authorJohn Lindgren <john@jlindgren.net>
Sat, 23 Sep 2023 15:51:47 +0000 (11:51 -0400)
committerJohan Malm <johanmalm@users.noreply.github.com>
Fri, 29 Sep 2023 17:04:32 +0000 (18:04 +0100)
XWayland views can self-declare that they don't want keyboard focus via
the ICCCM WM_HINTS property. Most of the logic is already in place to
avoid giving focus to such views (e.g. taskbars).

Add a couple of missing pieces to make this work:

- Hook up view_isfocusable() to look at WM_HINTS for XWayland views
- Adjust desktop_focus_topmost_mapped_view() to skip unfocusable views

include/labwc.h
include/view.h
src/desktop.c
src/seat.c
src/session-lock.c
src/view.c
src/workspaces.c
src/xdg.c
src/xwayland-unmanaged.c
src/xwayland.c

index 78280b24968916eadb14d8380c2e59d888d7bcb8..41c9a6682c90eab99c856f718c9cc1021aecda7b 100644 (file)
@@ -378,7 +378,7 @@ void foreign_toplevel_update_outputs(struct view *view);
 void desktop_focus_view(struct view *view, bool raise);
 void desktop_arrange_all_views(struct server *server);
 void desktop_focus_output(struct output *output);
-struct view *desktop_topmost_mapped_view(struct server *server);
+struct view *desktop_topmost_focusable_view(struct server *server);
 
 enum lab_cycle_dir {
        LAB_CYCLE_DIR_NONE,
@@ -393,7 +393,7 @@ enum lab_cycle_dir {
  */
 struct view *desktop_cycle_view(struct server *server, struct view *start_view,
        enum lab_cycle_dir dir);
-void desktop_focus_topmost_mapped_view(struct server *server);
+void desktop_focus_topmost_view(struct server *server);
 
 void keyboard_cancel_keybind_repeat(struct keyboard *keyboard);
 void keyboard_key_notify(struct wl_listener *listener, void *data);
index d5eb58380cd1789de0e64088f41b696ea8e51bbe..4a408a84fcb737ec92ccf1a68f72bd2ad1a7750c 100644 (file)
@@ -69,6 +69,8 @@ struct view_impl {
        struct view *(*get_root)(struct view *self);
        void (*append_children)(struct view *self, struct wl_array *children);
        struct view_size_hints (*get_size_hints)(struct view *self);
+       /* if not implemented, view is assumed to want focus */
+       bool (*wants_focus)(struct view *self);
 };
 
 struct view {
index 4d2deba168ca68e31861f83c66d22f9d30debfd6..7376555eed79e321246dff940aee425d4f2e7a03 100644 (file)
@@ -190,7 +190,7 @@ desktop_cycle_view(struct server *server, struct view *start_view,
 }
 
 struct view *
-desktop_topmost_mapped_view(struct server *server)
+desktop_topmost_focusable_view(struct server *server)
 {
        struct view *view;
        struct wl_list *node_list;
@@ -202,7 +202,7 @@ desktop_topmost_mapped_view(struct server *server)
                        continue;
                }
                view = node_view_from_node(node);
-               if (view->mapped) {
+               if (view->mapped && view_isfocusable(view)) {
                        return view;
                }
        }
@@ -210,9 +210,9 @@ desktop_topmost_mapped_view(struct server *server)
 }
 
 void
-desktop_focus_topmost_mapped_view(struct server *server)
+desktop_focus_topmost_view(struct server *server)
 {
-       struct view *view = desktop_topmost_mapped_view(server);
+       struct view *view = desktop_topmost_focusable_view(server);
        if (view) {
                desktop_focus_view(view, /*raise*/ true);
        } else {
index c16f86dc365ccbdafda56a088f434529ab42b847..bb6729a096f1f592581b5dffb97d83d6b8c3cdc5 100644 (file)
@@ -496,7 +496,7 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
 {
        if (!layer) {
                seat->focused_layer = NULL;
-               desktop_focus_topmost_mapped_view(seat->server);
+               desktop_focus_topmost_view(seat->server);
                return;
        }
        seat_focus(seat, layer->surface);
index 4e09e1eee893bd253a8f1b858e6066926d9103b8..fe920f413a8c5855c75d7a8a3bc4395ded7f53e9 100644 (file)
@@ -227,7 +227,7 @@ handle_unlock(struct wl_listener *listener, void *data)
 {
        struct session_lock *lock = wl_container_of(listener, lock, unlock);
        session_lock_destroy(lock);
-       desktop_focus_topmost_mapped_view(g_server);
+       desktop_focus_topmost_view(g_server);
 }
 
 static void
index 6e41f382b45375030b213e5877fcf9ef57f18e88..743c9290dd9128e6ff1dc58e1841142648ff5d68 100644 (file)
@@ -118,6 +118,9 @@ view_isfocusable(struct view *view)
        if (!view->surface) {
                return false;
        }
+       if (view->impl->wants_focus && !view->impl->wants_focus(view)) {
+               return false;
+       }
        return (view->mapped || view->minimized);
 }
 
index 19606ffabf06f337ec678ac5e67c4c068def5d64..bd9bdab04cb73d3880acbabb9f53861022e47920 100644 (file)
@@ -289,7 +289,7 @@ workspaces_switch_to(struct workspace *target, bool update_focus)
        if (update_focus) {
                struct view *view = server->focused_view;
                if (!view || !view_is_always_on_top(view)) {
-                       desktop_focus_topmost_mapped_view(server);
+                       desktop_focus_topmost_view(server);
                }
        }
 
index 65f164d313d5aba51dbdefa7601bea019b41cbbb..f916087d708a84017401812175890d766d49d852 100644 (file)
--- a/src/xdg.c
+++ b/src/xdg.c
@@ -554,7 +554,7 @@ xdg_toplevel_view_unmap(struct view *view, bool client_request)
                view->mapped = false;
                wlr_scene_node_set_enabled(&view->scene_tree->node, false);
                wl_list_remove(&view->commit.link);
-               desktop_focus_topmost_mapped_view(view->server);
+               desktop_focus_topmost_view(view->server);
        }
 }
 
index 7f7454a2779274f26e2eb3d8635d802adbb229c0..8f8faf7939bd2e882cc234a761b233811443d131 100644 (file)
@@ -88,7 +88,7 @@ focus_next_surface(struct server *server, struct wlr_xwayland_surface *xsurface)
         * to the topmost mapped view. This fixes dmenu
         * not giving focus back when closed with ESC.
         */
-       desktop_focus_topmost_mapped_view(server);
+       desktop_focus_topmost_view(server);
 }
 
 static void
@@ -166,7 +166,7 @@ unmanaged_handle_request_activate(struct wl_listener *listener, void *data)
         * Validate that the unmanaged surface trying to grab focus is actually
         * a child of the topmost mapped view before granting the request.
         */
-       struct view *view = desktop_topmost_mapped_view(server);
+       struct view *view = desktop_topmost_focusable_view(server);
        if (view && view->type == LAB_XWAYLAND_VIEW) {
                struct wlr_xwayland_surface *surf =
                        wlr_xwayland_surface_from_wlr_surface(view->surface);
index 4423345bdc4329801777f529f984072aee802879..57094d7fbcdc362c1dc7429933ef2f946e24b8b4 100644 (file)
@@ -30,6 +30,16 @@ xwayland_view_get_size_hints(struct view *view)
        };
 }
 
+static bool
+xwayland_view_wants_focus(struct view *view)
+{
+       xcb_icccm_wm_hints_t *hints = xwayland_surface_from_view(view)->hints;
+       if (!hints) {
+               return true;
+       }
+       return (bool)hints->input;
+}
+
 static struct wlr_xwayland_surface *
 top_parent_of(struct view *view)
 {
@@ -505,7 +515,7 @@ xwayland_view_unmap(struct view *view, bool client_request)
        view->mapped = false;
        wl_list_remove(&view->commit.link);
        wlr_scene_node_set_enabled(&view->scene_tree->node, false);
-       desktop_focus_topmost_mapped_view(view->server);
+       desktop_focus_topmost_view(view->server);
 
        /*
         * If the view was explicitly unmapped by the client (rather
@@ -634,6 +644,7 @@ static const struct view_impl xwayland_view_impl = {
        .get_root = xwayland_view_get_root,
        .append_children = xwayland_view_append_children,
        .get_size_hints = xwayland_view_get_size_hints,
+       .wants_focus = xwayland_view_wants_focus,
 };
 
 void