]> git.mdlowis.com Git - proto/labwc.git/commitdiff
seat: use focus_change event to update focused/active view
authorJohn Lindgren <john@jlindgren.net>
Wed, 27 Sep 2023 22:24:35 +0000 (18:24 -0400)
committerJohan Malm <johanmalm@users.noreply.github.com>
Thu, 28 Sep 2023 21:52:30 +0000 (22:52 +0100)
- Connect to wlr_seat_keyboard_state's focus_change event.
- Add view_from_wlr_surface(), which does what the name says.
- Use focus_change event along with view_from_wlr_surface() to update
  server->focused_view and set SSD states via view_set_activated().
- Eliminate desktop_focused_view() since server->focused_view should be
  reliably up-to-date now.
- Eliminate view_focus/defocus() since we can now just call
  seat_focus_surface() directly.

include/labwc.h
include/view.h
src/action.c
src/cursor.c
src/desktop.c
src/keyboard.c
src/seat.c
src/view.c
src/workspaces.c

index d7f5cbdecc04277e2582bc5a6c0a8cc7eabf7ece..78280b24968916eadb14d8380c2e59d888d7bcb8 100644 (file)
@@ -167,6 +167,7 @@ struct seat {
        struct wl_client *active_client_while_inhibited;
        struct wl_list inputs;
        struct wl_listener new_input;
+       struct wl_listener focus_change;
 
        struct wl_listener cursor_motion;
        struct wl_listener cursor_motion_absolute;
@@ -247,11 +248,8 @@ struct server {
 
        /* SSD state */
        /*
-        * Currently focused view (cached value). This pointer is used
-        * primarily to track which view is being drawn with "active"
-        * SSD coloring. We consider it a bug if this gets out of sync
-        * with the actual keyboard focus (according to wlroots). See
-        * also desktop_focused_view().
+        * Currently focused view. Updated with each "focus change"
+        * event. This view is drawn with "active" SSD coloring.
         */
        struct view *focused_view;
        struct ssd_hover_state *ssd_hover_state;
@@ -395,14 +393,6 @@ enum lab_cycle_dir {
  */
 struct view *desktop_cycle_view(struct server *server, struct view *start_view,
        enum lab_cycle_dir dir);
-/**
- * desktop_focused_view - return the view that is currently focused
- * (determined on-the-fly from the wlroots keyboard focus). The return
- * value should ideally match server->focused_view (we consider it a
- * bug otherwise) but is guaranteed to be up-to-date even if
- * server->focused_view gets out of sync.
- */
-struct view *desktop_focused_view(struct server *server);
 void desktop_focus_topmost_mapped_view(struct server *server);
 
 void keyboard_cancel_keybind_repeat(struct keyboard *keyboard);
index 7ff6901538fb9d1c592213c898144cfb4b833360..d5eb58380cd1789de0e64088f41b696ea8e51bbe 100644 (file)
@@ -186,6 +186,12 @@ enum lab_view_criteria {
        LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER = 1 << 2,
 };
 
+/**
+ * view_from_wlr_surface() - returns the view associated with a
+ * wlr_surface, or NULL if the surface has no associated view.
+ */
+struct view *view_from_wlr_surface(struct wlr_surface *surface);
+
 /**
  * for_each_view() - iterate over all views which match criteria
  * @view: Iterator.
@@ -257,8 +263,7 @@ bool view_isfocusable(struct view *view);
 bool view_inhibits_keybinds(struct view *view);
 void view_toggle_keybinds(struct view *view);
 
-void view_focus(struct view *view);
-void view_defocus(struct view *view);
+void view_set_activated(struct view *view, bool activated);
 void view_set_output(struct view *view, struct output *output);
 void view_close(struct view *view);
 
index cf8b4558121825de84780791176563ddd8c7b025..bdecf68d15d4e496bdab75303adb06542b20bde7 100644 (file)
@@ -503,7 +503,7 @@ view_for_action(struct view *activator, struct server *server,
                return ctx.view;
        }
        default:
-               return desktop_focused_view(server);
+               return server->focused_view;
        }
 }
 
index 16d9e8247e50130cb661ffe01cada9a4353e268d..773cd76a18e5dab6186fcb1c03ed77bbe6bee9d7 100644 (file)
@@ -602,7 +602,7 @@ create_constraint(struct wl_listener *listener, void *data)
        constraint->destroy.notify = destroy_constraint;
        wl_signal_add(&wlr_constraint->events.destroy, &constraint->destroy);
 
-       struct view *view = desktop_focused_view(server);
+       struct view *view = server->focused_view;
        if (view && view->surface == wlr_constraint->surface) {
                constrain_cursor(server, wlr_constraint);
        }
index cbaa0de6b3517a0876a3cd98292f27f4058f3197..4d2deba168ca68e31861f83c66d22f9d30debfd6 100644 (file)
@@ -74,7 +74,10 @@ desktop_focus_view(struct view *view, bool raise)
                workspaces_switch_to(view->workspace, /*update_focus*/ false);
        }
 
-       view_focus(view);
+       struct seat *seat = &server->seat;
+       if (view->surface != seat->seat->keyboard_state.focused_surface) {
+               seat_focus_surface(seat, view->surface);
+       }
 
        if (raise) {
                view_move_to_front(view);
@@ -147,7 +150,7 @@ desktop_cycle_view(struct server *server, struct view *start_view,
 
        if (!start_view) {
                start_view = first_view(server);
-               if (!start_view || start_view != desktop_focused_view(server)) {
+               if (!start_view || start_view != server->focused_view) {
                        return start_view;  /* may be NULL */
                }
        }
@@ -206,32 +209,6 @@ desktop_topmost_mapped_view(struct server *server)
        return NULL;
 }
 
-struct view *
-desktop_focused_view(struct server *server)
-{
-       struct seat *seat = &server->seat;
-       struct wlr_surface *focused_surface =
-               seat->seat->keyboard_state.focused_surface;
-       struct view *focused_view = NULL;
-
-       if (focused_surface) {
-               struct view *view;
-               wl_list_for_each(view, &server->views, link) {
-                       if (view->surface == focused_surface) {
-                               focused_view = view;
-                               break;
-                       }
-               }
-       }
-
-       /* warn so we can identify cases where this occurs */
-       if (focused_view != server->focused_view) {
-               wlr_log(WLR_ERROR, "server->focused_view is out of sync");
-       }
-
-       return focused_view;
-}
-
 void
 desktop_focus_topmost_mapped_view(struct server *server)
 {
@@ -242,12 +219,8 @@ desktop_focus_topmost_mapped_view(struct server *server)
                /*
                 * Defocus previous focused surface/view if no longer
                 * focusable (e.g. unmapped or on a different workspace).
-                * Note than a non-view surface may have been focused.
                 */
                seat_focus_surface(&server->seat, NULL);
-               if (server->focused_view) {
-                       view_defocus(server->focused_view);
-               }
        }
 }
 
index 3f954c7ccabaac2be3501439217d6453389505ad..e738afa33a39c0d2d23b2fef8f9b34f91b70b123 100644 (file)
@@ -94,7 +94,7 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym, x
                        continue;
                }
                if (server->seat.nr_inhibited_keybind_views
-                               && view_inhibits_keybinds(desktop_focused_view(server))
+                               && view_inhibits_keybinds(server->focused_view)
                                && !actions_contain_toggle_keybinds(&keybind->actions)) {
                        continue;
                }
index a38858a80c08612869b15076caff296f844efc06..c16f86dc365ccbdafda56a088f434529ab42b847 100644 (file)
@@ -11,6 +11,7 @@
 #include "common/mem.h"
 #include "key-state.h"
 #include "labwc.h"
+#include "view.h"
 
 static void
 input_device_destroy(struct wl_listener *listener, void *data)
@@ -335,6 +336,26 @@ new_virtual_keyboard(struct wl_listener *listener, void *data)
        seat_add_device(seat, input);
 }
 
+static void
+focus_change_notify(struct wl_listener *listener, void *data)
+{
+       struct seat *seat = wl_container_of(listener, seat, focus_change);
+       struct wlr_seat_keyboard_focus_change_event *event = data;
+       struct server *server = seat->server;
+       struct view *view = event->new_surface ?
+               view_from_wlr_surface(event->new_surface) : NULL;
+
+       if (view != server->focused_view) {
+               if (server->focused_view) {
+                       view_set_activated(server->focused_view, false);
+               }
+               if (view) {
+                       view_set_activated(view, true);
+               }
+               server->focused_view = view;
+       }
+}
+
 void
 seat_init(struct server *server)
 {
@@ -353,6 +374,10 @@ seat_init(struct server *server)
        seat->new_input.notify = new_input_notify;
        wl_signal_add(&server->backend->events.new_input, &seat->new_input);
 
+       seat->focus_change.notify = focus_change_notify;
+       wl_signal_add(&seat->seat->keyboard_state.events.focus_change,
+               &seat->focus_change);
+
        seat->virtual_pointer = wlr_virtual_pointer_manager_v1_create(
                server->wl_display);
        wl_signal_add(&seat->virtual_pointer->events.new_virtual_pointer,
@@ -382,6 +407,7 @@ seat_finish(struct server *server)
 {
        struct seat *seat = &server->seat;
        wl_list_remove(&seat->new_input.link);
+       wl_list_remove(&seat->focus_change.link);
 
        struct input *input, *next;
        wl_list_for_each_safe(input, next, &seat->inputs, link) {
index ed88739ab19f696bf93ed523d76573bcb3c2afc0..23b345fe3c8c9d85c8f0ab8a44d7a0d2db4731ea 100644 (file)
@@ -2,6 +2,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <strings.h>
+#include <wlr/xwayland.h>
 #include "common/mem.h"
 #include "common/scene-helpers.h"
 #include "labwc.h"
 #define LAB_FALLBACK_WIDTH  640
 #define LAB_FALLBACK_HEIGHT 480
 
+struct view *
+view_from_wlr_surface(struct wlr_surface *surface)
+{
+       assert(surface);
+       /*
+        * TODO:
+        * - find a way to get rid of xdg/xwayland-specific stuff
+        * - look up root/toplevel surface if passed a subsurface?
+        */
+       if (wlr_surface_is_xdg_surface(surface)) {
+               struct wlr_xdg_surface *xdg_surface =
+                       wlr_xdg_surface_from_wlr_surface(surface);
+               if (xdg_surface) {
+                       return xdg_surface->data;
+               }
+       }
+#if HAVE_XWAYLAND
+       if (wlr_surface_is_xwayland_surface(surface)) {
+               struct wlr_xwayland_surface *xsurface =
+                       wlr_xwayland_surface_from_wlr_surface(surface);
+               if (xsurface) {
+                       return xsurface->data;
+               }
+       }
+#endif
+       return NULL;
+}
+
 static bool
 matches_criteria(struct view *view, enum lab_view_criteria criteria)
 {
@@ -174,9 +203,10 @@ view_discover_output(struct view *view)
                view->current.y + view->current.height / 2);
 }
 
-static void
-_view_set_activated(struct view *view, bool activated)
+void
+view_set_activated(struct view *view, bool activated)
 {
+       assert(view);
        ssd_set_active(view->ssd, activated);
        if (view->impl->set_activated) {
                view->impl->set_activated(view, activated);
@@ -187,52 +217,6 @@ _view_set_activated(struct view *view, bool activated)
        }
 }
 
-/*
- * Give the view keyboard focus and mark it active. This function should
- * only be called by desktop_focus_view(), which contains additional
- * checks to make sure it's okay to give focus.
- */
-void
-view_focus(struct view *view)
-{
-       assert(view);
-       /* Update seat focus */
-       struct seat *seat = &view->server->seat;
-       if (view->surface != seat->seat->keyboard_state.focused_surface) {
-               seat_focus_surface(seat, view->surface);
-       }
-       /* Update active view */
-       if (view != view->server->focused_view) {
-               if (view->server->focused_view) {
-                       _view_set_activated(view->server->focused_view, false);
-               }
-               _view_set_activated(view, true);
-               view->server->focused_view = view;
-       }
-}
-
-/*
- * Take keyboard focus from the view and mark it inactive. It's rarely
- * necessary to call this function directly; usually it's better to
- * focus a different view instead by calling something like
- * desktop_focus_topmost_mapped_view().
- */
-void
-view_defocus(struct view *view)
-{
-       assert(view);
-       /* Update seat focus */
-       struct seat *seat = &view->server->seat;
-       if (view->surface == seat->seat->keyboard_state.focused_surface) {
-               seat_focus_surface(seat, NULL);
-       }
-       /* Update active view */
-       if (view == view->server->focused_view) {
-               _view_set_activated(view, false);
-               view->server->focused_view = NULL;
-       }
-}
-
 void
 view_set_output(struct view *view, struct output *output)
 {
@@ -408,7 +392,6 @@ _minimize(struct view *view, bool minimized)
        view->minimized = minimized;
        if (minimized) {
                view->impl->unmap(view, /* client_request */ false);
-               view_defocus(view);
        } else {
                view->impl->map(view);
        }
index 48be68f363da1ca3b8f6e46c5c1b20ba51f687a0..19606ffabf06f337ec678ac5e67c4c068def5d64 100644 (file)
@@ -287,7 +287,7 @@ workspaces_switch_to(struct workspace *target, bool update_focus)
         * Only refocus if the focus is not already on an always-on-top view.
         */
        if (update_focus) {
-               struct view *view = desktop_focused_view(server);
+               struct view *view = server->focused_view;
                if (!view || !view_is_always_on_top(view)) {
                        desktop_focus_topmost_mapped_view(server);
                }