]> git.mdlowis.com Git - proto/labwc.git/commitdiff
xwayland: better support for keyboard focus grabs
authorJohn Lindgren <john@jlindgren.net>
Wed, 14 Feb 2024 03:25:20 +0000 (22:25 -0500)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Wed, 21 May 2025 18:30:19 +0000 (20:30 +0200)
Use the new grab_focus signal as a more reliable way to tell when an
unmanaged (override-redirect) surface wants focus.

include/xwayland.h
src/xwayland-unmanaged.c

index 0a5f7c105610ce925a7b55033251dc263b772c12..3afea406ce963e7f7e58728781be0c995e06778f 100644 (file)
@@ -47,12 +47,20 @@ struct xwayland_unmanaged {
 
        struct wl_listener associate;
        struct wl_listener dissociate;
+       struct wl_listener grab_focus;
        struct wl_listener request_activate;
        struct wl_listener request_configure;
 /*     struct wl_listener request_fullscreen; */
        struct wl_listener set_geometry;
        struct wl_listener destroy;
        struct wl_listener set_override_redirect;
+
+       /*
+        * True if the surface has performed a keyboard grab. labwc
+        * honors keyboard grabs and will give the surface focus when
+        * it's mapped (which may occur slightly later) and on top.
+        */
+       bool ever_grabbed_focus;
 };
 
 struct xwayland_view {
index 0a7880cafbeb4bdca4c2bfdff66a7e284455648a..d45937e48f0aa6a85c550b9d8626f31d28687d81 100644 (file)
@@ -7,6 +7,20 @@
 #include "labwc.h"
 #include "xwayland.h"
 
+static void
+handle_grab_focus(struct wl_listener *listener, void *data)
+{
+       struct xwayland_unmanaged *unmanaged =
+               wl_container_of(listener, unmanaged, grab_focus);
+
+       unmanaged->ever_grabbed_focus = true;
+       if (unmanaged->node) {
+               assert(unmanaged->xwayland_surface->surface);
+               seat_focus_surface(&unmanaged->server->seat,
+                       unmanaged->xwayland_surface->surface);
+       }
+}
+
 static void
 handle_request_configure(struct wl_listener *listener, void *data)
 {
@@ -46,7 +60,8 @@ handle_map(struct wl_listener *listener, void *data)
 
        CONNECT_SIGNAL(xsurface, unmanaged, set_geometry);
 
-       if (wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
+       if (wlr_xwayland_surface_override_redirect_wants_focus(xsurface)
+                       || unmanaged->ever_grabbed_focus) {
                seat_focus_surface(&unmanaged->server->seat, xsurface->surface);
        }
 
@@ -66,7 +81,8 @@ focus_next_surface(struct server *server, struct wlr_xwayland_surface *xsurface)
        struct wl_list *list = &server->unmanaged_surfaces;
        wl_list_for_each_reverse(u, list, link) {
                struct wlr_xwayland_surface *prev = u->xwayland_surface;
-               if (wlr_xwayland_surface_override_redirect_wants_focus(prev)) {
+               if (wlr_xwayland_surface_override_redirect_wants_focus(prev)
+                               || u->ever_grabbed_focus) {
                        seat_focus_surface(&server->seat, prev->surface);
                        return;
                }
@@ -152,9 +168,10 @@ handle_destroy(struct wl_listener *listener, void *data)
 
        wl_list_remove(&unmanaged->associate.link);
        wl_list_remove(&unmanaged->dissociate.link);
+       wl_list_remove(&unmanaged->grab_focus.link);
+       wl_list_remove(&unmanaged->request_activate.link);
        wl_list_remove(&unmanaged->request_configure.link);
        wl_list_remove(&unmanaged->set_override_redirect.link);
-       wl_list_remove(&unmanaged->request_activate.link);
        wl_list_remove(&unmanaged->destroy.link);
        free(unmanaged);
 }
@@ -223,6 +240,7 @@ xwayland_unmanaged_create(struct server *server,
        CONNECT_SIGNAL(xsurface, unmanaged, associate);
        CONNECT_SIGNAL(xsurface, unmanaged, dissociate);
        CONNECT_SIGNAL(xsurface, unmanaged, destroy);
+       CONNECT_SIGNAL(xsurface, unmanaged, grab_focus);
        CONNECT_SIGNAL(xsurface, unmanaged, request_activate);
        CONNECT_SIGNAL(xsurface, unmanaged, request_configure);
        CONNECT_SIGNAL(xsurface, unmanaged, set_override_redirect);