From f27bbf03f1173c9f148c5343dc0fc168c4fcb982 Mon Sep 17 00:00:00 2001 From: tiosgz Date: Tue, 16 Jul 2024 21:11:55 +0000 Subject: [PATCH] LayerSurface: focus on_demand-interactive surfaces on map This is done specifically for lxqt-runner and qterminal to work as expected, consistently among (almost) all compositors with layer-shell. The most prominent drawback of this is that top- and overlay-layer status bars with on_demand interactivity also get focus on map. See https://codeberg.org/river/river/issues/1111 for more details. --- river/LayerSurface.zig | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/river/LayerSurface.zig b/river/LayerSurface.zig index 004a6c2..156ef1b 100644 --- a/river/LayerSurface.zig +++ b/river/LayerSurface.zig @@ -95,11 +95,17 @@ fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurfa fn handleMap(listener: *wl.Listener(void)) void { const layer_surface: *LayerSurface = @fieldParentPtr("map", listener); + const wlr_surface = layer_surface.wlr_layer_surface; - log.debug("layer surface '{s}' mapped", .{layer_surface.wlr_layer_surface.namespace}); + log.debug("layer surface '{s}' mapped", .{wlr_surface.namespace}); layer_surface.output.arrangeLayers(); - handleKeyboardInteractiveExclusive(layer_surface.output); + const consider = (wlr_surface.current.keyboard_interactive != .none and + (wlr_surface.current.layer == .top or wlr_surface.current.layer == .overlay)); + handleKeyboardInteractiveExclusive( + layer_surface.output, + if (consider) layer_surface else null, + ); server.root.applyPending(); } @@ -109,7 +115,7 @@ fn handleUnmap(listener: *wl.Listener(void)) void { log.debug("layer surface '{s}' unmapped", .{layer_surface.wlr_layer_surface.namespace}); layer_surface.output.arrangeLayers(); - handleKeyboardInteractiveExclusive(layer_surface.output); + handleKeyboardInteractiveExclusive(layer_surface.output, null); server.root.applyPending(); } @@ -129,17 +135,19 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void { @as(u32, @bitCast(wlr_layer_surface.current.committed)) != 0) { layer_surface.output.arrangeLayers(); - handleKeyboardInteractiveExclusive(layer_surface.output); + handleKeyboardInteractiveExclusive(layer_surface.output, null); server.root.applyPending(); } } +/// Focus topmost keyboard-interactivity-exclusive layer surface above normal +/// content, or if none found, focus that given as `consider`. /// Requires a call to Root.applyPending() -fn handleKeyboardInteractiveExclusive(output: *Output) void { +fn handleKeyboardInteractiveExclusive(output: *Output, consider: ?*LayerSurface) void { if (server.lock_manager.state != .unlocked) return; - // Find the topmost layer surface in the top or overlay layers which - // requests keyboard interactivity if any. + // Find the topmost layer surface (if any) in the top or overlay layers which + // requests exclusive keyboard interactivity. const topmost_surface = outer: for ([_]zwlr.LayerShellV1.Layer{ .overlay, .top }) |layer| { const tree = output.layerSurfaceTree(layer); // Iterate in reverse to match rendering order. @@ -156,7 +164,11 @@ fn handleKeyboardInteractiveExclusive(output: *Output) void { } } } - } else null; + } else consider; + + if (topmost_surface) |surface| { + assert(surface.wlr_layer_surface.current.keyboard_interactive != .none); + } var it = server.input_manager.seats.first; while (it) |node| : (it = node.next) {