Add river-xkb-bindings and implement Alt+T to open foot
This is the only keybind for now.
This commit is contained in:
parent
a69d647f0c
commit
2c18946703
7 changed files with 402 additions and 9 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2025 Ben Buhse <me@benbuhse.email>
|
||||
// SPDX-FileCopyrightText: 2025-2026 Ben Buhse <me@benbuhse.email>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
|
@ -19,6 +19,7 @@ new_x: i32 = 0,
|
|||
new_y: i32 = 0,
|
||||
|
||||
link: wl.list.Link,
|
||||
is_head: bool = false,
|
||||
|
||||
pub fn init(window: *Window, context: *Context, river_window_v1: *river.WindowV1) void {
|
||||
window.* = .{
|
||||
|
|
@ -47,7 +48,7 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event,
|
|||
window.context.allocator.destroy(window);
|
||||
},
|
||||
.dimensions => |ev| {
|
||||
// Part of the protocol requires these are strictly greater-than zero
|
||||
// The protocol requires these are strictly greather than zero.
|
||||
assert(ev.width > 0 and ev.height > 0);
|
||||
window.width = @intCast(ev.width);
|
||||
window.height = @intCast(ev.height);
|
||||
|
|
@ -69,13 +70,16 @@ pub fn manage(window: *Window) void {
|
|||
window.new_y = 0;
|
||||
}
|
||||
|
||||
// TODO: Support multiple primaries
|
||||
// TODO: Is this a valid way to check for the window's index?
|
||||
|
||||
// TODO: Remove this -- just fullscreen for now
|
||||
if (window.width != window.context.wm.outputs.first().?.width or
|
||||
window.height != window.context.wm.outputs.first().?.height)
|
||||
{
|
||||
window.width = @intCast(window.context.wm.outputs.first().?.width);
|
||||
window.height = @intCast(window.context.wm.outputs.first().?.height);
|
||||
log.debug("setting window width={d} and height={d}", .{ window.width, window.height });
|
||||
log.debug("setting window width={d} and height={d} {}", .{ window.width, window.height, window.is_head });
|
||||
}
|
||||
window.window_v1.proposeDimensions(window.width, window.height);
|
||||
// window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true });
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2025 Ben Buhse <me@benbuhse.email>
|
||||
// SPDX-FileCopyrightText: 2025-2026 Ben Buhse <me@benbuhse.email>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
|
@ -12,6 +12,8 @@ seats: wl.list.Head(Seat, .link),
|
|||
outputs: wl.list.Head(Output, .link),
|
||||
windows: wl.list.Head(Window, .link),
|
||||
|
||||
window_count: u8 = 0,
|
||||
|
||||
pub fn init(wm: *WindowManager, context: *Context, window_manager_v1: *river.WindowManagerV1) void {
|
||||
assert(wm == &context.wm);
|
||||
wm.* = .{
|
||||
|
|
@ -38,6 +40,10 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
|
|||
std.posix.exit(1);
|
||||
},
|
||||
.manage_start => {
|
||||
if (!context.initialized) {
|
||||
context.initialized = true;
|
||||
context.xkb_bindings.addBinding(xkbcommon.Keysym.t, .{ .mod1 = true });
|
||||
}
|
||||
{
|
||||
var it = wm.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
|
|
@ -96,6 +102,11 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
|
|||
var window = context.allocator.create(Window) catch @panic("out-of-memory; exiting.");
|
||||
window.init(context, ev.id);
|
||||
wm.windows.append(window);
|
||||
wm.window_count += 1;
|
||||
if (wm.window_count == 1) {
|
||||
window.is_head = true;
|
||||
}
|
||||
log.debug("window_count = {d}", .{wm.window_count});
|
||||
},
|
||||
else => |ev| {
|
||||
log.debug("unhandled event: {s}", .{@tagName(ev)});
|
||||
|
|
@ -110,10 +121,11 @@ const wayland = @import("wayland");
|
|||
const wl = wayland.client.wl;
|
||||
const river = wayland.client.river;
|
||||
|
||||
const xkbcommon = @import("xkbcommon");
|
||||
|
||||
const Context = @import("main.zig").Context;
|
||||
const Output = @import("Output.zig");
|
||||
const Seat = @import("Seat.zig");
|
||||
const Window = @import("Window.zig");
|
||||
|
||||
const log = std.log.scoped(.WindowManager);
|
||||
|
||||
const Seat = @import("Seat.zig");
|
||||
|
|
|
|||
87
src/XkbBindings.zig
Normal file
87
src/XkbBindings.zig
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// SPDX-FileCopyrightText: 2025-2026 Ben Buhse <me@benbuhse.email>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
const XkbBindings = @This();
|
||||
|
||||
const XkbBinding = struct {
|
||||
xkb_binding_v1: *river.XkbBindingV1,
|
||||
link: wl.list.Link,
|
||||
|
||||
fn init(xkb_binding: *XkbBinding, xkb_binding_v1: *river.XkbBindingV1) void {
|
||||
xkb_binding.* = .{
|
||||
.xkb_binding_v1 = xkb_binding_v1,
|
||||
.link = undefined, // Handled by the wl.list
|
||||
};
|
||||
|
||||
xkb_binding.xkb_binding_v1.setListener(*XkbBinding, xkbBindingListener, xkb_binding);
|
||||
}
|
||||
|
||||
fn xkbBindingListener(xkb_binding_v1: *river.XkbBindingV1, event: river.XkbBindingV1.Event, xkb_binding: *XkbBinding) void {
|
||||
assert(xkb_binding.xkb_binding_v1 == xkb_binding_v1);
|
||||
switch (event) {
|
||||
.pressed => {
|
||||
var child = std.process.Child.init(&.{"foot"}, std.heap.c_allocator);
|
||||
_ = child.spawn() catch |err| {
|
||||
log.err("Failed to spawn foot: {}", .{err});
|
||||
};
|
||||
},
|
||||
.released => {},
|
||||
else => |ev| {
|
||||
log.debug("unhandled event: {s}", .{@tagName(ev)});
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
context: *Context,
|
||||
|
||||
xkb_bindings_v1: *river.XkbBindingsV1,
|
||||
|
||||
bindings: wl.list.Head(XkbBinding, .link),
|
||||
|
||||
xkb_bindings_seat_v1: ?*river.XkbBindingsSeatV1 = null,
|
||||
|
||||
pub fn init(xkb_bindings: *XkbBindings, context: *Context, xkb_bindings_v1: *river.XkbBindingsV1) void {
|
||||
assert(xkb_bindings == &context.xkb_bindings);
|
||||
xkb_bindings.* = .{
|
||||
.context = context,
|
||||
.xkb_bindings_v1 = xkb_bindings_v1,
|
||||
.bindings = undefined, // we will initialize this shortly
|
||||
};
|
||||
|
||||
xkb_bindings.bindings.init();
|
||||
}
|
||||
|
||||
pub fn getSeat(xkb_bindings: *XkbBindings) *river.SeatV1 {
|
||||
const seat = xkb_bindings.context.wm.seats.first() orelse @panic("No seat available");
|
||||
return seat.seat_v1;
|
||||
}
|
||||
|
||||
pub fn addBinding(xkb_bindings: *XkbBindings, keysym: u32, modifiers: river.SeatV1.Modifiers) void {
|
||||
const seat_v1 = xkb_bindings.getSeat();
|
||||
const xkb_binding_v1 = xkb_bindings.xkb_bindings_v1.getXkbBinding(seat_v1, keysym, modifiers) catch |err| {
|
||||
log.err("Failed to get xkb binding: {}", .{err});
|
||||
return;
|
||||
};
|
||||
|
||||
const xkb_binding = xkb_bindings.context.allocator.create(XkbBinding) catch @panic("out-of-memory");
|
||||
xkb_binding.init(xkb_binding_v1);
|
||||
xkb_bindings.bindings.append(xkb_binding);
|
||||
|
||||
xkb_binding_v1.enable();
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const wayland = @import("wayland");
|
||||
const wl = wayland.client.wl;
|
||||
const river = wayland.client.river;
|
||||
|
||||
const xkbcommon = @import("xkbcommon");
|
||||
|
||||
const Context = @import("main.zig").Context;
|
||||
const Seat = @import("Seat.zig");
|
||||
|
||||
const log = std.log.scoped(.XkbBindings);
|
||||
13
src/main.zig
13
src/main.zig
|
|
@ -15,6 +15,7 @@ pub const Context = struct {
|
|||
shm: ?*wl.Shm = null,
|
||||
|
||||
wm: WindowManager,
|
||||
xkb_bindings: XkbBindings,
|
||||
|
||||
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *Context) void {
|
||||
switch (event) {
|
||||
|
|
@ -31,11 +32,17 @@ pub const Context = struct {
|
|||
std.posix.exit(1);
|
||||
};
|
||||
} else if (mem.orderZ(u8, ev.interface, river.WindowManagerV1.interface.name) == .eq) {
|
||||
const window_manager_v1 = registry.bind(ev.name, river.WindowManagerV1, 1) catch |e| {
|
||||
log.err("Failed to bind to window_manager_v: {any}", .{@errorName(e)});
|
||||
const window_manager_v1 = registry.bind(ev.name, river.WindowManagerV1, 3) catch |e| {
|
||||
log.err("Failed to bind to window_manager_v1: {any}", .{@errorName(e)});
|
||||
std.posix.exit(1);
|
||||
};
|
||||
context.wm.init(context, window_manager_v1);
|
||||
} else if (mem.orderZ(u8, ev.interface, river.XkbBindingsV1.interface.name) == .eq) {
|
||||
const xkb_bindings_v1 = registry.bind(ev.name, river.XkbBindingsV1, 2) catch |e| {
|
||||
log.err("Failed to bind to xkb_bindings_v1: {any}", .{@errorName(e)});
|
||||
std.posix.exit(1);
|
||||
};
|
||||
context.xkb_bindings.init(context, xkb_bindings_v1);
|
||||
}
|
||||
},
|
||||
// We don't need .global_remove
|
||||
|
|
@ -69,6 +76,7 @@ pub fn main() !void {
|
|||
.display = wl_display,
|
||||
.registry = registry,
|
||||
.wm = undefined,
|
||||
.xkb_bindings = undefined,
|
||||
};
|
||||
|
||||
registry.setListener(*Context, Context.registryListener, &context);
|
||||
|
|
@ -107,5 +115,6 @@ const river = wayland.client.river;
|
|||
const wl = wayland.client.wl;
|
||||
|
||||
const WindowManager = @import("WindowManager.zig");
|
||||
const XkbBindings = @import("XkbBindings.zig");
|
||||
|
||||
const log = std.log.scoped(.main);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue