Actually use focus_follows_pointer and pointer_warp_on_focus_change

This commit is contained in:
Ben Buhse 2026-01-27 15:30:30 -06:00
commit 676ca40891
No known key found for this signature in database
GPG key ID: 7916ACFCD38FD0B4
5 changed files with 37 additions and 26 deletions

View file

@ -1,15 +1,18 @@
<!--
SPDX-FileCopyrightText: 2025 Ben Buhse <me@benbuhse.email>
SPDX-License-Identifier: EUPL-1.2
SPDX-License-Identifier: GPL-3.0-or-later
-->
# beansprout wm
## TODOs
[ ] Support multiple outputs
[ ] Support multiple seats
[ ] Support floating windows
[ ] Support wallpapers
[ ] Support a bar
[ ] Support starting programs at WM launch
[ ] Support changeable primary ratio
[ ] Support changeable primary count
[ ] Support overriding config location

10
examples/config.kdl Normal file
View file

@ -0,0 +1,10 @@
attach_mode top
focus_follows_pointer true
pointer_warp_on_focus_change true
borders {
width 2
color_focused 0x89b4fa
color_unfocused 0x1e1e2e
}

View file

@ -1,6 +0,0 @@
#! /bin/sh
./zig-out/bin/beansprout &
/usr/bin/foot &
/usr/bin/foot &

View file

@ -193,7 +193,7 @@ fn loadBordersChildBlock(config: *Config, parser: *kdl.Parser) !void {
}
}
/// Skips an entire child block in KDL
/// Skips an entire child block including any nested child blocks
fn skipChildBlock(_: *Config, parser: *kdl.Parser) !void {
log.warn("Unexpected child block. Skipping it", .{});
@ -216,10 +216,11 @@ fn skipChildBlock(_: *Config, parser: *kdl.Parser) !void {
}
}
/// Convert a KDL argument into a bool or null if the string is not a bool
/// "#true" and "true" => true
/// "#false" and "false" => false
/// else => null
/// Convert a KDL argument into a bool
///
/// if arg_str in ["#true", "true"], return true
/// if arg_str in ["#false", "false"], return false
/// else, return null
fn boolFromKdlStr(_: Config, arg_str: []const u8) ?bool {
if (mem.eql(u8, arg_str, "#true") or
mem.eql(u8, arg_str, "true"))

View file

@ -53,7 +53,9 @@ fn seatListener(river_seat_v1: *river.SeatV1, event: river.SeatV1.Event, seat: *
.wl_seat => |ev| {
log.debug("initializing new river_seat_v1 corresponding to wl_seat: {d}", .{ev.name});
},
.pointer_enter => |ev| seat.setWindowFocus(ev.window),
.pointer_enter => |ev| if (seat.context.config.focus_follows_pointer) {
seat.setWindowFocus(ev.window);
},
.window_interaction => |ev| seat.setWindowFocus(ev.window),
else => |ev| {
log.debug("unhandled event: {s}", .{@tagName(ev)});
@ -95,12 +97,12 @@ pub fn manage(seat: *Seat) void {
}
}
if (seat.pending_manage.should_warp_pointer) {
if (seat.pending_manage.should_warp_pointer) blk: {
if (seat.context.config.pointer_warp_on_focus_change) {
const window = seat.focused orelse {
log.err("Trying to warp-on-focus-change without a focused window.", .{});
return;
break :blk;
};
// TODO - CONFIG: Allow disabling this behaviour
// Warp pointer to center of focused window;
// because the x and y coords are set during render, we need to check if
// there are new coordinates in window.pending_render.
@ -108,6 +110,7 @@ pub fn manage(seat: *Seat) void {
const pointer_y: i32 = (window.pending_render.y orelse window.y) + @divTrunc(window.height, 2);
seat.river_seat_v1.pointerWarp(pointer_x, pointer_y);
}
}
}
pub fn render(seat: *Seat) void {