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
|
|
@ -14,13 +14,16 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
const scanner = Scanner.create(b, .{});
|
||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||
const xkbcommon = b.dependency("xkbcommon", .{}).module("xkbcommon");
|
||||
|
||||
scanner.addCustomProtocol(b.path("protocol/river-window-management-v1.xml"));
|
||||
scanner.addCustomProtocol(b.path("protocol/river-xkb-bindings-v1.xml"));
|
||||
|
||||
scanner.generate("wl_compositor", 4);
|
||||
scanner.generate("wl_shm", 1);
|
||||
scanner.generate("wl_output", 4);
|
||||
scanner.generate("river_window_manager_v1", 1);
|
||||
scanner.generate("river_window_manager_v1", 3);
|
||||
scanner.generate("river_xkb_bindings_v1", 2);
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "beansprout",
|
||||
|
|
@ -34,6 +37,7 @@ pub fn build(b: *std.Build) void {
|
|||
exe.pie = pie;
|
||||
|
||||
exe.root_module.addImport("wayland", wayland);
|
||||
exe.root_module.addImport("xkbcommon", xkbcommon);
|
||||
|
||||
exe.linkLibC();
|
||||
exe.linkSystemLibrary("wayland-client");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.4.0.tar.gz",
|
||||
.hash = "wayland-0.4.0-lQa1khbMAQAsLS2eBR7M5lofyEGPIbu2iFDmoz8lPC27",
|
||||
},
|
||||
.xkbcommon = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-xkbcommon/archive/v0.3.0.tar.gz",
|
||||
.hash = "xkbcommon-0.3.0-VDqIe3K9AQB2fG5ZeRcMC9i7kfrp5m2rWgLrmdNn9azr",
|
||||
},
|
||||
},
|
||||
|
||||
.paths = .{
|
||||
|
|
|
|||
273
protocol/river-xkb-bindings-v1.xml
Normal file
273
protocol/river-xkb-bindings-v1.xml
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="river_xkb_bindings_v1">
|
||||
<copyright>
|
||||
SPDX-FileCopyrightText: © 2025 Isaac Freund
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<description summary="define xkbcommon-based key bindings">
|
||||
This protocol allows the river-window-management-v1 window manager to
|
||||
define key bindings in terms of xkbcommon keysyms and other configurable
|
||||
properties.
|
||||
|
||||
The key words "must", "must not", "required", "shall", "shall not",
|
||||
"should", "should not", "recommended", "may", and "optional" in this
|
||||
document are to be interpreted as described in IETF RFC 2119.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can only
|
||||
be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<interface name="river_xkb_bindings_v1" version="2">
|
||||
<description summary="xkbcommon bindings global interface">
|
||||
This global interface should only be advertised to the client if the
|
||||
river_window_manager_v1 global is also advertised.
|
||||
</description>
|
||||
|
||||
<enum name="error" since="2">
|
||||
<entry name="object_already_created" value="0" since="2"/>
|
||||
</enum>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the river_xkb_bindings_v1 object">
|
||||
This request indicates that the client will no longer use the
|
||||
river_xkb_bindings_v1 object.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_xkb_binding">
|
||||
<description summary="define a new xkbcommon key binding">
|
||||
Define a key binding for the given seat in terms of an xkbcommon keysym
|
||||
and other configurable properties.
|
||||
|
||||
The new key binding is not enabled until initial configuration is
|
||||
completed and the enable request is made during a manage sequence.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="river_seat_v1"/>
|
||||
<arg name="id" type="new_id" interface="river_xkb_binding_v1"/>
|
||||
<arg name="keysym" type="uint" summary="an xkbcommon keysym"/>
|
||||
<arg name="modifiers" type="uint" enum="river_seat_v1.modifiers"/>
|
||||
</request>
|
||||
|
||||
<request name="get_seat" since="2">
|
||||
<description summary="manage seat-specific state">
|
||||
Create an object to manage seat-specific xkb bindings state.
|
||||
|
||||
It is a protocol error to make this request more than once for a given
|
||||
river_seat_v1 object.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="river_xkb_bindings_seat_v1"/>
|
||||
<arg name="seat" type="object" interface="river_seat_v1"/>
|
||||
</request>
|
||||
</interface>
|
||||
|
||||
<interface name="river_xkb_binding_v1" version="2">
|
||||
<description summary="configure a xkb key binding, receive trigger events">
|
||||
This object allows the window manager to configure a xkbcommon key binding
|
||||
and receive events when the key binding is triggered.
|
||||
|
||||
The new key binding is not enabled until the enable request is made during
|
||||
a manage sequence.
|
||||
|
||||
Normally, all key events are sent to the surface with keyboard focus by
|
||||
the compositor. Key events that trigger a key binding are not sent to the
|
||||
surface with keyboard focus.
|
||||
|
||||
If multiple key bindings would be triggered by a single physical key event
|
||||
on the compositor side, it is compositor policy which key binding(s) will
|
||||
receive press/release events or if all of the matched key bindings receive
|
||||
press/release events.
|
||||
|
||||
Key bindings might be matched by the same physical key event due to shared
|
||||
keysym and modifiers. The layout override feature may also cause the same
|
||||
physical key event to trigger two key bindings with different keysyms and
|
||||
different layout overrides configured.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the xkb binding object">
|
||||
This request indicates that the client will no longer use the xkb key
|
||||
binding object and that it may be safely destroyed.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_layout_override">
|
||||
<description summary="override currently active xkb layout">
|
||||
Specify an xkb layout that should be used to translate key events for
|
||||
the purpose of triggering this key binding irrespective of the currently
|
||||
active xkb layout.
|
||||
|
||||
The layout argument is a 0-indexed xkbcommon layout number for the
|
||||
keyboard that generated the key event.
|
||||
|
||||
If this request is never made, the currently active xkb layout of the
|
||||
keyboard that generated the key event will be used.
|
||||
|
||||
This request modifies window management state and may only be made as
|
||||
part of a manage sequence, see the river_window_manager_v1 description.
|
||||
</description>
|
||||
<arg name="layout" type="uint" summary="0-indexed xkbcommon layout"/>
|
||||
</request>
|
||||
|
||||
<request name="enable">
|
||||
<description summary="enable the key binding">
|
||||
This request should be made after all initial configuration has been
|
||||
completed and the window manager wishes the key binding to be able to be
|
||||
triggered.
|
||||
|
||||
This request modifies window management state and may only be made as
|
||||
part of a manage sequence, see the river_window_manager_v1 description.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="disable">
|
||||
<description summary="disable the key binding">
|
||||
This request may be used to temporarily disable the key binding. It may
|
||||
be later re-enabled with the enable request.
|
||||
|
||||
This request modifies window management state and may only be made as
|
||||
part of a manage sequence, see the river_window_manager_v1 description.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="pressed">
|
||||
<description summary="the key triggering the binding has been pressed">
|
||||
This event indicates that the physical key triggering the binding has
|
||||
been pressed.
|
||||
|
||||
This event will be followed by a manage_start event after all other new
|
||||
state has been sent by the server.
|
||||
|
||||
The compositor should wait for the manage sequence to complete before
|
||||
processing further input events. This allows the window manager client
|
||||
to, for example, modify key bindings and keyboard focus without racing
|
||||
against future input events. The window manager should of course respond
|
||||
as soon as possible as the capacity of the compositor to buffer incoming
|
||||
input events is finite.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="released">
|
||||
<description summary="the key triggering the binding has been released">
|
||||
This event indicates that the physical key triggering the binding has
|
||||
been released.
|
||||
|
||||
Releasing the modifiers for the binding without releasing the "main"
|
||||
physical key that produces the bound keysym does not trigger the release
|
||||
event. This event is sent when the "main" key is released, even if the
|
||||
modifiers have changed since the pressed event.
|
||||
|
||||
This event will be followed by a manage_start event after all other new
|
||||
state has been sent by the server.
|
||||
|
||||
The compositor should wait for the manage sequence to complete before
|
||||
processing further input events. This allows the window manager client
|
||||
to, for example, modify key bindings and keyboard focus without racing
|
||||
against future input events. The window manager should of course respond
|
||||
as soon as possible as the capacity of the compositor to buffer incoming
|
||||
input events is finite.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="stop_repeat" since="2">
|
||||
<description summary="repeating should be stopped">
|
||||
This event indicates that repeating should be stopped for the binding if
|
||||
the window manager has been repeating some action since the pressed
|
||||
event.
|
||||
|
||||
This event is generally sent when some other (possible unbound) key is
|
||||
pressed after the pressed event is sent and before the released event
|
||||
is sent for this binding.
|
||||
|
||||
This event will be followed by a manage_start event after all other new
|
||||
state has been sent by the server.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="river_xkb_bindings_seat_v1" version="2">
|
||||
<description summary="xkb bindings seat">
|
||||
This object manages xkb bindings state associated with a specific seat.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor" since="2">
|
||||
<description summary="destroy the object">
|
||||
This request indicates that the client will no longer use the object and
|
||||
that it may be safely destroyed.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="ensure_next_key_eaten" since="2">
|
||||
<description summary="ensure the next key press event is eaten">
|
||||
Ensure that the next non-modifier key press and corresponding release
|
||||
events for this seat are not sent to the currently focused surface.
|
||||
|
||||
If the next non-modifier key press triggers a binding, the
|
||||
pressed/released events are sent to the river_xkb_binding_v1 object as
|
||||
usual.
|
||||
|
||||
If the next non-modifier key press does not trigger a binding, the
|
||||
ate_unbound_key event is sent instead.
|
||||
|
||||
Rationale: the window manager may wish to implement "chorded"
|
||||
keybindings where triggering a binding activates a "submap" with a
|
||||
different set of keybindings. Without a way to eat the next key
|
||||
press event, there is no good way for the window manager to know that it
|
||||
should error out and exit the submap when a key not bound in the submap
|
||||
is pressed.
|
||||
|
||||
This request modifies window management state and may only be made as
|
||||
part of a manage sequence, see the river_window_manager_v1 description.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="cancel_ensure_next_key_eaten" since="2">
|
||||
<description summary="cancel an ensure_next_key_eaten request">
|
||||
This requests cancels the effect of the latest ensure_next_key_eaten
|
||||
request if no key has been eaten due to the request yet. This request
|
||||
has no effect if a key has already been eaten or no
|
||||
ensure_next_key_eaten was made.
|
||||
|
||||
Rationale: the window manager may wish cancel an uncompleted "chorded"
|
||||
keybinding after a timeout of a few seconds. Note that since this
|
||||
timeout use-case requires the window manager to trigger a manage sequence
|
||||
with the river_window_manager_v1.manage_dirty request it is possible that
|
||||
the ate_unbound_key key event may be sent before the window manager has
|
||||
a chance to make the cancel_ensure_next_key_eaten request.
|
||||
|
||||
This request modifies window management state and may only be made as
|
||||
part of a manage sequence, see the river_window_manager_v1 description.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="ate_unbound_key" since="2">
|
||||
<description summary="an unbound key press event was eaten">
|
||||
An unbound key press event was eaten due to the ensure_next_key_eaten
|
||||
request.
|
||||
|
||||
This event will be followed by a manage_start event after all other new
|
||||
state has been sent by the server.
|
||||
</description>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
||||
|
|
@ -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