]> git.mdlowis.com Git - proto/labwc.git/commitdiff
desktop: allow re-focus between "globally active" views of the same PID
authorJohn Lindgren <john@jlindgren.net>
Sat, 14 Oct 2023 20:29:13 +0000 (16:29 -0400)
committerJohan Malm <johanmalm@users.noreply.github.com>
Mon, 16 Oct 2023 19:28:18 +0000 (20:28 +0100)
Commit 7e72bf975fb6 changed behavior to not automatically focus xwayland
views using the "Globally Active" input model (WM_HINTS.inputs = false
but WM_TAKE_FOCUS listed in WM_PROTOCOLS).

One undesired side effect of this change is that when a dialog is
closed, the parent window is not re-focused if "Globally Active". This
issue is seen for example with JDownloader. It can be solved taking a
similar approach to what is done for unmanaged xwayland views: allow
automatic re-focus between views sharing the same PID.

Note that it's difficult to completely solve all of the focus issues
with Globally Active views without proper WM_TAKE_FOCUS support.
Implementing proper support is difficult since it requires wlroots
changes and would also mean waiting for a message round-trip in
desktop_focus_topmost_view().

Fixes (partially): 7e72bf975fb65c8290b398d21b2ad9d87a22880f
("view/xwayland: avoid focusing views that don't want focus")

include/view.h
src/desktop.c
src/view.c

index 12b5d1093d7a62f57ac569aac3e758fac9618f01..b3cc0368dce785b5eb4963545ef2c2eee28b0390 100644 (file)
@@ -290,6 +290,14 @@ void view_array_append(struct server *server, struct wl_array *views,
 
 enum view_wants_focus view_wants_focus(struct view *view);
 
+/**
+ * view_is_focusable_from() - variant of view_is_focusable()
+ * that takes into account the previously focused surface
+ * @view: view to be checked
+ * @prev_surface: previously focused surface
+ */
+bool view_is_focusable_from(struct view *view, struct wlr_surface *prev);
+
 /**
  * view_is_focusable() - Check whether or not a view can be focused
  * @view: view to be checked
@@ -302,7 +310,10 @@ enum view_wants_focus view_wants_focus(struct view *view);
  * The only views that are allowed to be focusd are those that have a surface
  * and have been mapped at some point since creation.
  */
-bool view_is_focusable(struct view *view);
+static inline bool
+view_is_focusable(struct view *view) {
+       return view_is_focusable_from(view, NULL);
+}
 
 void view_toggle_keybinds(struct view *view);
 
index 607da49c8194734ba23dafb03644eec2d8a80612..ab057fbeac497ec9bdc45e38a68588c5f8983b96 100644 (file)
@@ -192,6 +192,8 @@ desktop_cycle_view(struct server *server, struct view *start_view,
 struct view *
 desktop_topmost_focusable_view(struct server *server)
 {
+       struct wlr_surface *prev =
+               server->seat.seat->keyboard_state.focused_surface;
        struct view *view;
        struct wl_list *node_list;
        struct wlr_scene_node *node;
@@ -202,7 +204,7 @@ desktop_topmost_focusable_view(struct server *server)
                        continue;
                }
                view = node_view_from_node(node);
-               if (view->mapped && view_is_focusable(view)) {
+               if (view->mapped && view_is_focusable_from(view, prev)) {
                        return view;
                }
        }
index dcca4bcdc08bde9e1e5f876c634531f10c4460e2..813566bdccfbd987d3eedb0761cfe5118cd75af2 100644 (file)
@@ -154,16 +154,28 @@ view_wants_focus(struct view *view)
 }
 
 bool
-view_is_focusable(struct view *view)
+view_is_focusable_from(struct view *view, struct wlr_surface *prev)
 {
        assert(view);
        if (!view->surface) {
                return false;
        }
-       if (view_wants_focus(view) != VIEW_WANTS_FOCUS_ALWAYS) {
+       if (!view->mapped && !view->minimized) {
                return false;
        }
-       return (view->mapped || view->minimized);
+       enum view_wants_focus wants_focus = view_wants_focus(view);
+       /*
+        * Consider "offer focus" (Globally Active) views as focusable
+        * only if another surface from the same application already had
+        * focus. The goal is to allow focusing a parent window when a
+        * dialog/popup is closed, but still avoid focusing standalone
+        * panels/toolbars/notifications. Note that we are basically
+        * guessing whether Globally Active views want focus, and will
+        * probably be wrong some of the time.
+        */
+       return (wants_focus == VIEW_WANTS_FOCUS_ALWAYS
+               || (wants_focus == VIEW_WANTS_FOCUS_OFFER
+                       && prev && view_is_related(view, prev)));
 }
 
 /**