build: update to Zig 0.15
This commit is contained in:
@ -37,10 +37,10 @@ tasks:
|
||||
cd ..
|
||||
|
||||
# Eat Github's resources rather than the Zig Software Foundation's resources!
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz
|
||||
tar xf zig-linux-x86_64-0.14.0.tar.xz
|
||||
sudo mv zig-linux-x86_64-0.14.0/zig /usr/bin/
|
||||
sudo mv zig-linux-x86_64-0.14.0/lib /usr/lib/zig
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz
|
||||
tar xf zig-x86_64-linux-0.15.1.tar.xz
|
||||
sudo mv zig-x86_64-linux-0.15.1/zig /usr/bin/
|
||||
sudo mv zig-x86_64-linux-0.15.1/lib /usr/lib/zig
|
||||
- build: |
|
||||
cd river
|
||||
zig build --summary all
|
||||
|
@ -34,10 +34,10 @@ tasks:
|
||||
cd ..
|
||||
|
||||
# Eat Github's resources rather than the Zig Software Foundation's resources!
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz
|
||||
tar xf zig-linux-x86_64-0.14.0.tar.xz
|
||||
sudo mv zig-linux-x86_64-0.14.0/zig /usr/bin/
|
||||
sudo mv zig-linux-x86_64-0.14.0/lib /usr/lib/zig
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz
|
||||
tar xf zig-x86_64-linux-0.15.1.tar.xz
|
||||
sudo mv zig-x86_64-linux-0.15.1/zig /usr/bin/
|
||||
sudo mv zig-x86_64-linux-0.15.1/lib /usr/lib/zig
|
||||
- build: |
|
||||
cd river
|
||||
zig build --summary all
|
||||
|
@ -41,10 +41,10 @@ tasks:
|
||||
cd ..
|
||||
|
||||
# Eat Github's resources rather than the Zig Software Foundation's resources!
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.14.0/zig-freebsd-x86_64-0.14.0-unofficial.tar.xz
|
||||
tar xf zig-freebsd-x86_64-0.14.0-unofficial.tar.xz
|
||||
sudo mv zig-freebsd-x86_64-0.14.0-unofficial/zig /usr/bin/
|
||||
sudo mv zig-freebsd-x86_64-0.14.0-unofficial/lib /usr/lib/zig
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.15.1/zig-x86_64-freebsd-0.15.1.tar.xz
|
||||
tar xf zig-x86_64-freebsd-0.15.1.tar.xz
|
||||
sudo mv zig-x86_64-freebsd-0.15.1/zig /usr/bin/
|
||||
sudo mv zig-x86_64-freebsd-0.15.1/lib /usr/lib/zig
|
||||
- build: |
|
||||
cd river
|
||||
zig build --summary all
|
||||
|
@ -57,7 +57,7 @@ To compile river first ensure that you have the following dependencies
|
||||
installed. The "development" versions are required if applicable to your
|
||||
distribution.
|
||||
|
||||
- [zig](https://ziglang.org/download/) 0.14
|
||||
- [zig](https://ziglang.org/download/) 0.15
|
||||
- wayland
|
||||
- wayland-protocols
|
||||
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.19
|
||||
|
15
build.zig
15
build.zig
@ -12,7 +12,6 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
const strip = b.option(bool, "strip", "Omit debug information") orelse false;
|
||||
const pie = b.option(bool, "pie", "Build a Position Independent Executable") orelse false;
|
||||
const llvm = !(b.option(bool, "no-llvm", "(expirimental) Use non-LLVM x86 Zig backend") orelse false);
|
||||
|
||||
const omit_frame_pointer = switch (optimize) {
|
||||
.Debug, .ReleaseSafe => false,
|
||||
@ -150,12 +149,12 @@ pub fn build(b: *Build) !void {
|
||||
{
|
||||
const river = b.addExecutable(.{
|
||||
.name = "river",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("river/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
.use_llvm = llvm,
|
||||
.use_lld = llvm,
|
||||
}),
|
||||
});
|
||||
river.root_module.addOptions("build_options", options);
|
||||
|
||||
@ -188,12 +187,12 @@ pub fn build(b: *Build) !void {
|
||||
{
|
||||
const riverctl = b.addExecutable(.{
|
||||
.name = "riverctl",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("riverctl/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
.use_llvm = llvm,
|
||||
.use_lld = llvm,
|
||||
}),
|
||||
});
|
||||
riverctl.root_module.addOptions("build_options", options);
|
||||
|
||||
@ -211,12 +210,12 @@ pub fn build(b: *Build) !void {
|
||||
{
|
||||
const rivertile = b.addExecutable(.{
|
||||
.name = "rivertile",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("rivertile/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
.use_llvm = llvm,
|
||||
.use_lld = llvm,
|
||||
}),
|
||||
});
|
||||
rivertile.root_module.addOptions("build_options", options);
|
||||
|
||||
@ -275,9 +274,11 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
{
|
||||
const globber_test = b.addTest(.{
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("common/globber.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
const run_globber_test = b.addRunArtifact(globber_test);
|
||||
|
||||
|
@ -13,12 +13,12 @@
|
||||
.hash = "pixman-0.3.0-LClMnz2VAAAs7QSCGwLimV5VUYx0JFnX5xWU6HwtMuDX",
|
||||
},
|
||||
.wayland = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.3.0.tar.gz",
|
||||
.hash = "wayland-0.3.0-lQa1kjPIAQDmhGYpY-zxiRzQJFHQ2VqhJkQLbKKdt5wl",
|
||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.4.0.tar.gz",
|
||||
.hash = "wayland-0.4.0-lQa1khbMAQAsLS2eBR7M5lofyEGPIbu2iFDmoz8lPC27",
|
||||
},
|
||||
.wlroots = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/f92ba27133ecf702d85c9d3894f98a336389bbd9.tar.gz",
|
||||
.hash = "wlroots-0.19.3-dev-jmOlcr7_AwClfjFwW8oOkWoqAbt9oPLqgdvfFYEXqlOF",
|
||||
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.19.3.tar.gz",
|
||||
.hash = "wlroots-0.19.3-jmOlcuL_AwBHhLCwpFsXbTizE3q9BugFmGX-XIxqcPMc",
|
||||
},
|
||||
.xkbcommon = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-xkbcommon/archive/v0.3.0.tar.gz",
|
||||
|
@ -26,7 +26,7 @@ const wayland = @import("wayland");
|
||||
const wl = wayland.server.wl;
|
||||
const zwlr = wayland.server.zwlr;
|
||||
|
||||
const c = @import("c.zig");
|
||||
const c = @import("c.zig").c;
|
||||
const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
|
||||
@ -296,7 +296,7 @@ pub fn setTheme(cursor: *Cursor, theme: ?[*:0]const u8, _size: ?u32) !void {
|
||||
// If this cursor belongs to the default seat, set the xcursor environment
|
||||
// variables as well as the xwayland cursor theme.
|
||||
if (cursor.seat == server.input_manager.defaultSeat()) {
|
||||
const size_str = try std.fmt.allocPrintZ(util.gpa, "{}", .{size});
|
||||
const size_str = try std.fmt.allocPrintSentinel(util.gpa, "{}", .{size}, 0);
|
||||
defer util.gpa.free(size_str);
|
||||
if (c.setenv("XCURSOR_SIZE", size_str.ptr, 1) < 0) return error.OutOfMemory;
|
||||
if (theme) |t| if (c.setenv("XCURSOR_THEME", t, 1) < 0) return error.OutOfMemory;
|
||||
@ -378,8 +378,8 @@ fn handleAxis(listener: *wl.Listener(*wlr.Pointer.event.Axis), event: *wlr.Point
|
||||
// @intFromFloat() call safe due to the max/min i32 not being exactly representable
|
||||
// by an f32. Dividing by 2 is a low effort way to ensure the value is in bounds and
|
||||
// allow users to set their scroll-factor to inf without crashing river.
|
||||
math.minInt(i32) / 2,
|
||||
math.maxInt(i32) / 2,
|
||||
@as(f32, @floatFromInt(math.minInt(i32) / 2)),
|
||||
@as(f32, @floatFromInt(math.maxInt(i32) / 2)),
|
||||
)),
|
||||
event.source,
|
||||
event.relative_direction,
|
||||
|
@ -30,28 +30,29 @@ const View = @import("View.zig");
|
||||
wlr_manager: *wlr.IdleInhibitManagerV1,
|
||||
new_idle_inhibitor: wl.Listener(*wlr.IdleInhibitorV1) =
|
||||
wl.Listener(*wlr.IdleInhibitorV1).init(handleNewIdleInhibitor),
|
||||
inhibitors: std.DoublyLinkedList(IdleInhibitor) = .{},
|
||||
inhibitors: wl.list.Head(IdleInhibitor, .link),
|
||||
|
||||
pub fn init(inhibit_manager: *IdleInhibitManager) !void {
|
||||
inhibit_manager.* = .{
|
||||
.wlr_manager = try wlr.IdleInhibitManagerV1.create(server.wl_server),
|
||||
.inhibitors = undefined,
|
||||
};
|
||||
inhibit_manager.inhibitors.init();
|
||||
inhibit_manager.wlr_manager.events.new_inhibitor.add(&inhibit_manager.new_idle_inhibitor);
|
||||
}
|
||||
|
||||
pub fn deinit(inhibit_manager: *IdleInhibitManager) void {
|
||||
while (inhibit_manager.inhibitors.pop()) |inhibitor| {
|
||||
inhibitor.data.destroy.link.remove();
|
||||
util.gpa.destroy(inhibitor);
|
||||
while (inhibit_manager.inhibitors.first()) |inhibitor| {
|
||||
inhibitor.destroy();
|
||||
}
|
||||
inhibit_manager.new_idle_inhibitor.link.remove();
|
||||
}
|
||||
|
||||
pub fn checkActive(inhibit_manager: *IdleInhibitManager) void {
|
||||
var inhibited = false;
|
||||
var it = inhibit_manager.inhibitors.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const node_data = SceneNodeData.fromSurface(node.data.wlr_inhibitor.surface) orelse continue;
|
||||
var it = inhibit_manager.inhibitors.iterator(.forward);
|
||||
while (it.next()) |inhibitor| {
|
||||
const node_data = SceneNodeData.fromSurface(inhibitor.wlr_inhibitor.surface) orelse continue;
|
||||
switch (node_data.data) {
|
||||
.view => |view| {
|
||||
if (view.current.output != null and
|
||||
@ -79,13 +80,8 @@ pub fn checkActive(inhibit_manager: *IdleInhibitManager) void {
|
||||
|
||||
fn handleNewIdleInhibitor(listener: *wl.Listener(*wlr.IdleInhibitorV1), inhibitor: *wlr.IdleInhibitorV1) void {
|
||||
const inhibit_manager: *IdleInhibitManager = @fieldParentPtr("new_idle_inhibitor", listener);
|
||||
const inhibitor_node = util.gpa.create(std.DoublyLinkedList(IdleInhibitor).Node) catch return;
|
||||
inhibitor_node.data.init(inhibitor, inhibit_manager) catch {
|
||||
util.gpa.destroy(inhibitor_node);
|
||||
IdleInhibitor.create(inhibitor, inhibit_manager) catch {
|
||||
std.log.err("out of memory", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
inhibit_manager.inhibitors.append(inhibitor_node);
|
||||
|
||||
inhibit_manager.checkActive();
|
||||
}
|
||||
|
@ -28,31 +28,38 @@ const IdleInhibitManager = @import("IdleInhibitManager.zig");
|
||||
inhibit_manager: *IdleInhibitManager,
|
||||
wlr_inhibitor: *wlr.IdleInhibitorV1,
|
||||
|
||||
destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleDestroy),
|
||||
listen_destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleDestroy),
|
||||
|
||||
link: wl.list.Link,
|
||||
|
||||
pub fn create(wlr_inhibitor: *wlr.IdleInhibitorV1, inhibit_manager: *IdleInhibitManager) !void {
|
||||
const inhibitor = try util.gpa.create(IdleInhibitor);
|
||||
errdefer util.gpa.destroy(inhibitor);
|
||||
|
||||
pub fn init(
|
||||
inhibitor: *IdleInhibitor,
|
||||
wlr_inhibitor: *wlr.IdleInhibitorV1,
|
||||
inhibit_manager: *IdleInhibitManager,
|
||||
) !void {
|
||||
inhibitor.* = .{
|
||||
.inhibit_manager = inhibit_manager,
|
||||
.wlr_inhibitor = wlr_inhibitor,
|
||||
.link = undefined,
|
||||
};
|
||||
wlr_inhibitor.events.destroy.add(&inhibitor.destroy);
|
||||
wlr_inhibitor.events.destroy.add(&inhibitor.listen_destroy);
|
||||
|
||||
inhibit_manager.inhibitors.append(inhibitor);
|
||||
|
||||
inhibit_manager.checkActive();
|
||||
}
|
||||
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
const inhibitor: *IdleInhibitor = @fieldParentPtr("destroy", listener);
|
||||
pub fn destroy(inhibitor: *IdleInhibitor) void {
|
||||
inhibitor.listen_destroy.link.remove();
|
||||
|
||||
inhibitor.destroy.link.remove();
|
||||
|
||||
const node: *std.DoublyLinkedList(IdleInhibitor).Node = @fieldParentPtr("data", inhibitor);
|
||||
server.idle_inhibit_manager.inhibitors.remove(node);
|
||||
inhibitor.link.remove();
|
||||
|
||||
inhibitor.inhibit_manager.checkActive();
|
||||
|
||||
util.gpa.destroy(node);
|
||||
util.gpa.destroy(inhibitor);
|
||||
}
|
||||
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
const inhibitor: *IdleInhibitor = @fieldParentPtr("listen_destroy", listener);
|
||||
|
||||
inhibitor.destroy();
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ const wlr = @import("wlroots");
|
||||
|
||||
const log = std.log.scoped(.input_config);
|
||||
|
||||
const c = @import("c.zig");
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
@ -373,7 +373,7 @@ pub fn parse(config: *InputConfig, setting: []const u8, value: []const u8) !void
|
||||
return error.UnknownCommand;
|
||||
}
|
||||
|
||||
pub fn write(config: *InputConfig, writer: anytype) !void {
|
||||
pub fn write(config: *InputConfig, writer: *std.Io.Writer) !void {
|
||||
try writer.print("{s}\n", .{config.glob});
|
||||
|
||||
inline for (@typeInfo(InputConfig).@"struct".fields) |field| {
|
||||
|
@ -24,7 +24,7 @@ const wl = @import("wayland").server.wl;
|
||||
|
||||
const globber = @import("globber");
|
||||
|
||||
const c = @import("c.zig");
|
||||
const c = @import("c.zig").c;
|
||||
const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
|
||||
|
@ -55,10 +55,10 @@ tablet_manager: *wlr.TabletManagerV2,
|
||||
|
||||
/// List of input device configurations. Ordered by glob generality, with
|
||||
/// the most general towards the start and the most specific towards the end.
|
||||
configs: std.ArrayList(InputConfig),
|
||||
configs: std.ArrayList(InputConfig) = .{},
|
||||
|
||||
devices: wl.list.Head(InputDevice, .link),
|
||||
seats: std.DoublyLinkedList(Seat) = .{},
|
||||
seats: wl.list.Head(Seat, .link),
|
||||
|
||||
exclusive_client: ?*wl.Client = null,
|
||||
|
||||
@ -74,9 +74,6 @@ new_text_input: wl.Listener(*wlr.TextInputV3) =
|
||||
wl.Listener(*wlr.TextInputV3).init(handleNewTextInput),
|
||||
|
||||
pub fn init(input_manager: *InputManager) !void {
|
||||
const seat_node = try util.gpa.create(std.DoublyLinkedList(Seat).Node);
|
||||
errdefer util.gpa.destroy(seat_node);
|
||||
|
||||
input_manager.* = .{
|
||||
// These are automatically freed when the display is destroyed
|
||||
.idle_notifier = try wlr.IdleNotifierV1.create(server.wl_server),
|
||||
@ -88,14 +85,14 @@ pub fn init(input_manager: *InputManager) !void {
|
||||
.input_method_manager = try wlr.InputMethodManagerV2.create(server.wl_server),
|
||||
.text_input_manager = try wlr.TextInputManagerV3.create(server.wl_server),
|
||||
.tablet_manager = try wlr.TabletManagerV2.create(server.wl_server),
|
||||
.configs = std.ArrayList(InputConfig).init(util.gpa),
|
||||
|
||||
.seats = undefined,
|
||||
.devices = undefined,
|
||||
};
|
||||
input_manager.seats.init();
|
||||
input_manager.devices.init();
|
||||
|
||||
input_manager.seats.prepend(seat_node);
|
||||
try seat_node.data.init(default_seat_name);
|
||||
try Seat.create(default_seat_name);
|
||||
|
||||
if (build_options.xwayland) {
|
||||
if (server.xwayland) |xwayland| {
|
||||
@ -121,19 +118,18 @@ pub fn deinit(input_manager: *InputManager) void {
|
||||
input_manager.new_input_method.link.remove();
|
||||
input_manager.new_text_input.link.remove();
|
||||
|
||||
while (input_manager.seats.pop()) |seat_node| {
|
||||
seat_node.data.deinit();
|
||||
util.gpa.destroy(seat_node);
|
||||
while (input_manager.seats.first()) |seat| {
|
||||
seat.destroy();
|
||||
}
|
||||
|
||||
for (input_manager.configs.items) |*config| {
|
||||
config.deinit();
|
||||
}
|
||||
input_manager.configs.deinit();
|
||||
input_manager.configs.deinit(util.gpa);
|
||||
}
|
||||
|
||||
pub fn defaultSeat(input_manager: InputManager) *Seat {
|
||||
return &input_manager.seats.first.?.data;
|
||||
pub fn defaultSeat(input_manager: *InputManager) *Seat {
|
||||
return input_manager.seats.first().?;
|
||||
}
|
||||
|
||||
/// Returns true if input is currently allowed on the passed surface.
|
||||
|
@ -57,33 +57,52 @@ pub const Pressed = struct {
|
||||
assert(capacity == @typeInfo(std.meta.fieldInfo(wlr.Keyboard, .keycodes).type).array.len);
|
||||
}
|
||||
|
||||
keys: std.BoundedArray(Key, capacity) = .{},
|
||||
keys: [capacity]Key,
|
||||
len: usize,
|
||||
|
||||
const empty: Pressed = .{ .keys = undefined, .len = 0 };
|
||||
|
||||
pub fn slice(pressed: *Pressed) []Key {
|
||||
return pressed.keys[0..pressed.len];
|
||||
}
|
||||
|
||||
fn contains(pressed: *Pressed, code: u32) bool {
|
||||
for (pressed.keys.constSlice()) |item| {
|
||||
for (pressed.slice()) |item| {
|
||||
if (item.code == code) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn addAssumeCapacity(pressed: *Pressed, new: Key) void {
|
||||
assert(pressed.len < pressed.keys.len);
|
||||
assert(!pressed.contains(new.code));
|
||||
pressed.keys.appendAssumeCapacity(new);
|
||||
pressed.keys[pressed.len] = new;
|
||||
pressed.len += 1;
|
||||
}
|
||||
|
||||
fn remove(pressed: *Pressed, code: u32) ?KeyConsumer {
|
||||
for (pressed.keys.constSlice(), 0..) |item, idx| {
|
||||
if (item.code == code) return pressed.keys.swapRemove(idx).consumer;
|
||||
for (pressed.slice(), 0..) |item, idx| {
|
||||
if (item.code == code) return pressed.swapRemove(idx).consumer;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn swapRemove(pressed: *Pressed, index: usize) Key {
|
||||
defer pressed.len -= 1;
|
||||
if (index == pressed.len - 1) {
|
||||
return pressed.keys[index];
|
||||
}
|
||||
const ret = pressed.keys[index];
|
||||
pressed.keys[index] = pressed.keys[pressed.len - 1];
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
device: InputDevice,
|
||||
|
||||
/// Pressed keys along with where their press event has been sent
|
||||
pressed: Pressed = .{},
|
||||
pressed: Pressed = .empty,
|
||||
|
||||
key: wl.Listener(*wlr.Keyboard.event.Key) = wl.Listener(*wlr.Keyboard.event.Key).init(handleKey),
|
||||
modifiers: wl.Listener(*wlr.Keyboard) = wl.Listener(*wlr.Keyboard).init(handleModifiers),
|
||||
@ -203,7 +222,9 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
|
||||
// Ignore key presses beyond 32 simultaneously pressed keys (see comments in Pressed).
|
||||
// We must ensure capacity before calling handleMapping() to ensure that we either run
|
||||
// both the press and release mapping for certain key or neither mapping.
|
||||
keyboard.pressed.keys.ensureUnusedCapacity(1) catch return;
|
||||
if (keyboard.pressed.len >= keyboard.pressed.keys.len) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyboard.device.seat.handleMapping(keycode, modifiers, released, xkb_state)) {
|
||||
break :blk .mapping;
|
||||
|
@ -173,10 +173,8 @@ fn handleKeyboardInteractiveExclusive(output: *Output, consider: ?*LayerSurface)
|
||||
assert(s.wlr_layer_surface.current.keyboard_interactive != .none);
|
||||
}
|
||||
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const seat = &node.data;
|
||||
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
if (seat.focused_output == output) {
|
||||
if (to_focus) |s| {
|
||||
// If we found a surface on the output that requires focus, grab the focus of all
|
||||
|
@ -38,6 +38,9 @@ layout_v3: *river.LayoutV3,
|
||||
namespace: []const u8,
|
||||
output: *Output,
|
||||
|
||||
// Output.layouts
|
||||
link: wl.list.Link,
|
||||
|
||||
pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namespace: []const u8) !void {
|
||||
const layout_v3 = try river.LayoutV3.create(client, version, id);
|
||||
|
||||
@ -47,21 +50,22 @@ pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namesp
|
||||
return;
|
||||
}
|
||||
|
||||
const node = try util.gpa.create(std.DoublyLinkedList(Layout).Node);
|
||||
errdefer util.gpa.destroy(node);
|
||||
node.data = .{
|
||||
const layout = try util.gpa.create(Layout);
|
||||
errdefer util.gpa.destroy(layout);
|
||||
layout.* = .{
|
||||
.layout_v3 = layout_v3,
|
||||
.namespace = try util.gpa.dupe(u8, namespace),
|
||||
.output = output,
|
||||
.link = undefined,
|
||||
};
|
||||
output.layouts.append(node);
|
||||
output.layouts.append(layout);
|
||||
|
||||
layout_v3.setHandler(*Layout, handleRequest, handleDestroy, &node.data);
|
||||
layout_v3.setHandler(*Layout, handleRequest, handleDestroy, layout);
|
||||
|
||||
// If the namespace matches that of the output, set the layout as
|
||||
// the active one of the output and arrange it.
|
||||
if (mem.eql(u8, namespace, output.layoutNamespace())) {
|
||||
output.layout = &node.data;
|
||||
output.layout = layout;
|
||||
server.root.applyPending();
|
||||
}
|
||||
}
|
||||
@ -71,17 +75,17 @@ pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namesp
|
||||
fn namespaceInUse(namespace: []const u8, output: *Output, client: *wl.Client) bool {
|
||||
var output_it = server.root.active_outputs.iterator(.forward);
|
||||
while (output_it.next()) |o| {
|
||||
var layout_it = output.layouts.first;
|
||||
var layout_it = output.layouts.iterator(.forward);
|
||||
if (o == output) {
|
||||
// On this output, no other layout can have our namespace.
|
||||
while (layout_it) |layout_node| : (layout_it = layout_node.next) {
|
||||
if (mem.eql(u8, namespace, layout_node.data.namespace)) return true;
|
||||
while (layout_it.next()) |layout| {
|
||||
if (mem.eql(u8, namespace, layout.namespace)) return true;
|
||||
}
|
||||
} else {
|
||||
// Layouts on other outputs may share the namespace, if they come from the same client.
|
||||
while (layout_it) |layout_node| : (layout_it = layout_node.next) {
|
||||
if (mem.eql(u8, namespace, layout_node.data.namespace) and
|
||||
client != layout_node.data.layout_v3.getClient()) return true;
|
||||
while (layout_it.next()) |layout| {
|
||||
if (mem.eql(u8, namespace, layout.namespace) and
|
||||
client != layout.layout_v3.getClient()) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -185,9 +189,7 @@ pub fn destroy(layout: *Layout) void {
|
||||
.{ layout.namespace, layout.output.wlr_output.name },
|
||||
);
|
||||
|
||||
// Remove layout from the list
|
||||
const node: *std.DoublyLinkedList(Layout).Node = @fieldParentPtr("data", layout);
|
||||
layout.output.layouts.remove(node);
|
||||
layout.link.remove();
|
||||
|
||||
// If we are the currently active layout of an output, clean up.
|
||||
if (layout.output.layout == layout) {
|
||||
@ -208,5 +210,5 @@ pub fn destroy(layout: *Layout) void {
|
||||
layout.layout_v3.setHandler(?*anyopaque, handleRequestInert, null, null);
|
||||
|
||||
util.gpa.free(layout.namespace);
|
||||
util.gpa.destroy(node);
|
||||
util.gpa.destroy(layout);
|
||||
}
|
||||
|
@ -110,9 +110,8 @@ fn handleLock(listener: *wl.Listener(*wlr.SessionLockV1), lock: *wlr.SessionLock
|
||||
};
|
||||
|
||||
{
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const seat = &node.data;
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
seat.setFocusRaw(.none);
|
||||
|
||||
// Enter locked mode
|
||||
@ -213,9 +212,8 @@ fn handleUnlock(listener: *wl.Listener(void)) void {
|
||||
}
|
||||
|
||||
{
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const seat = &node.data;
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
seat.setFocusRaw(.none);
|
||||
|
||||
// Exit locked mode
|
||||
|
@ -68,9 +68,8 @@ pub fn destroy(lock_surface: *LockSurface) void {
|
||||
break .{ .lock_surface = @alignCast(@ptrCast(surface.data)) };
|
||||
} else .none;
|
||||
|
||||
var seat_it = server.input_manager.seats.first;
|
||||
while (seat_it) |node| : (seat_it = node.next) {
|
||||
const seat = &node.data;
|
||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
||||
while (seat_it.next()) |seat| {
|
||||
if (seat.focused == .lock_surface and seat.focused.lock_surface == lock_surface) {
|
||||
seat.setFocusRaw(new_focus);
|
||||
}
|
||||
@ -122,9 +121,8 @@ fn handleMap(listener: *wl.Listener(void)) void {
|
||||
}
|
||||
|
||||
fn updateFocus(lock_surface: *LockSurface) void {
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const seat = &node.data;
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
if (seat.focused != .lock_surface) {
|
||||
seat.setFocusRaw(.{ .lock_surface = lock_surface });
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ previous_tags: u32 = 1 << 0,
|
||||
attach_mode: ?Config.AttachMode = null,
|
||||
|
||||
/// List of all layouts
|
||||
layouts: std.DoublyLinkedList(Layout) = .{},
|
||||
layouts: wl.list.Head(Layout, .link),
|
||||
|
||||
/// The current layout namespace of the output. If null,
|
||||
/// config.default_layout_namespace should be used instead.
|
||||
@ -290,9 +290,12 @@ pub fn create(wlr_output: *wlr.Output) !void {
|
||||
.height = height,
|
||||
},
|
||||
.status = undefined,
|
||||
.layouts = undefined,
|
||||
};
|
||||
wlr_output.data = output;
|
||||
|
||||
output.layouts.init();
|
||||
|
||||
output.pending.focus_stack.init();
|
||||
output.pending.wm_stack.init();
|
||||
output.inflight.focus_stack.init();
|
||||
@ -416,7 +419,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
assert(output.inflight.focus_stack.empty());
|
||||
assert(output.inflight.wm_stack.empty());
|
||||
assert(output.inflight.layout_demand == null);
|
||||
assert(output.layouts.len == 0);
|
||||
assert(output.layouts.length() == 0);
|
||||
|
||||
output.all_link.remove();
|
||||
|
||||
@ -452,7 +455,7 @@ fn handleRequestState(listener: *wl.Listener(*wlr.Output.event.RequestState), ev
|
||||
// TODO double buffer output state changes for frame perfection and cleaner code.
|
||||
// Schedule a frame and commit in the frame handler.
|
||||
// Get rid of this function.
|
||||
pub fn applyState(output: *Output, state: *wlr.Output.State) error{CommitFailed}!void {
|
||||
pub fn applyState(output: *Output, state: *const wlr.Output.State) error{CommitFailed}!void {
|
||||
|
||||
// We need to be precise about this state change to make assertions
|
||||
// in updateLockRenderStateOnEnableDisable() possible.
|
||||
@ -619,7 +622,7 @@ fn handlePresent(
|
||||
}
|
||||
|
||||
fn setTitle(output: Output) void {
|
||||
const title = fmt.allocPrintZ(util.gpa, "river - {s}", .{output.wlr_output.name}) catch return;
|
||||
const title = fmt.allocPrintSentinel(util.gpa, "river - {s}", .{output.wlr_output.name}, 0) catch return;
|
||||
defer util.gpa.free(title);
|
||||
if (output.wlr_output.isWl()) {
|
||||
output.wlr_output.wlSetTitle(title);
|
||||
@ -631,9 +634,9 @@ fn setTitle(output: Output) void {
|
||||
pub fn handleLayoutNamespaceChange(output: *Output) void {
|
||||
// The user changed the layout namespace of this output. Try to find a
|
||||
// matching layout.
|
||||
var it = output.layouts.first;
|
||||
output.layout = while (it) |node| : (it = node.next) {
|
||||
if (mem.eql(u8, output.layoutNamespace(), node.data.namespace)) break &node.data;
|
||||
var it = output.layouts.iterator(.forward);
|
||||
output.layout = while (it.next()) |layout| {
|
||||
if (mem.eql(u8, output.layoutNamespace(), layout.namespace)) break layout;
|
||||
} else null;
|
||||
server.root.applyPending();
|
||||
}
|
||||
|
@ -337,9 +337,8 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
|
||||
}
|
||||
|
||||
// If any seat has the removed output focused, focus the fallback one
|
||||
var seat_it = server.input_manager.seats.first;
|
||||
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||
const seat = &seat_node.data;
|
||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
||||
while (seat_it.next()) |seat| {
|
||||
if (seat.focused_output == output) {
|
||||
seat.focusOutput(fallback_output);
|
||||
}
|
||||
@ -353,7 +352,7 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
|
||||
output.inflight.layout_demand = null;
|
||||
root.notifyLayoutDemandDone();
|
||||
}
|
||||
while (output.layouts.first) |node| node.data.destroy();
|
||||
while (output.layouts.first()) |layout| layout.destroy();
|
||||
|
||||
// We must call reconfigureDevices here to unmap devices that might be mapped to this output
|
||||
// in order to prevent a segfault in wlroots.
|
||||
@ -397,9 +396,8 @@ pub fn activateOutput(root: *Root, output: *Output) void {
|
||||
}
|
||||
{
|
||||
// Focus the new output with all seats
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |seat_node| : (it = seat_node.next) {
|
||||
const seat = &seat_node.data;
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
seat.focusOutput(output);
|
||||
}
|
||||
}
|
||||
@ -435,8 +433,8 @@ pub fn applyPending(root: *Root) void {
|
||||
// state consistent. Instead of having focus(null) calls spread all
|
||||
// around the codebase and risk forgetting one, always ensure focus
|
||||
// state is synchronized here.
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) node.data.focus(null);
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| seat.focus(null);
|
||||
}
|
||||
|
||||
// If there is already a transaction inflight, wait until it completes.
|
||||
@ -546,11 +544,9 @@ pub fn applyPending(root: *Root) void {
|
||||
}
|
||||
|
||||
{
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const cursor = &node.data.cursor;
|
||||
|
||||
switch (cursor.mode) {
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
switch (seat.cursor.mode) {
|
||||
.passthrough, .down => {},
|
||||
inline .move, .resize => |data| {
|
||||
if (data.view.inflight.output == null or
|
||||
@ -558,14 +554,14 @@ pub fn applyPending(root: *Root) void {
|
||||
(!data.view.inflight.float and data.view.inflight.output.?.layout != null) or
|
||||
data.view.inflight.fullscreen)
|
||||
{
|
||||
cursor.mode = .passthrough;
|
||||
seat.cursor.mode = .passthrough;
|
||||
data.view.pending.resizing = false;
|
||||
data.view.inflight.resizing = false;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
cursor.inflight_mode = cursor.mode;
|
||||
seat.cursor.inflight_mode = seat.cursor.mode;
|
||||
}
|
||||
}
|
||||
|
||||
@ -710,8 +706,8 @@ fn commitTransaction(root: *Root) void {
|
||||
}
|
||||
|
||||
{
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) node.data.cursor.updateState();
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| seat.cursor.updateState();
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ focused_output: ?*Output = null,
|
||||
focused: FocusTarget = .none,
|
||||
|
||||
/// List of status tracking objects relaying changes to this seat to clients.
|
||||
status_trackers: std.SinglyLinkedList(SeatStatus) = .{},
|
||||
status_trackers: wl.list.Head(SeatStatus, .link),
|
||||
|
||||
/// The currently in progress drag operation type.
|
||||
drag: enum {
|
||||
@ -109,7 +109,13 @@ drag_destroy: wl.Listener(*wlr.Drag) = wl.Listener(*wlr.Drag).init(handleDragDes
|
||||
request_set_primary_selection: wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection) =
|
||||
wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection).init(handleRequestSetPrimarySelection),
|
||||
|
||||
pub fn init(seat: *Seat, name: [*:0]const u8) !void {
|
||||
// InputManager.seats
|
||||
link: wl.list.Link = undefined,
|
||||
|
||||
pub fn create(name: [*:0]const u8) !void {
|
||||
const seat = try util.gpa.create(Seat);
|
||||
errdefer util.gpa.destroy(seat);
|
||||
|
||||
const event_loop = server.wl_server.getEventLoop();
|
||||
const mapping_repeat_timer = try event_loop.addTimer(*Seat, handleMappingRepeatTimeout, seat);
|
||||
errdefer mapping_repeat_timer.remove();
|
||||
@ -121,9 +127,14 @@ pub fn init(seat: *Seat, name: [*:0]const u8) !void {
|
||||
.relay = undefined,
|
||||
.mapping_repeat_timer = mapping_repeat_timer,
|
||||
.keyboard_group = try wlr.KeyboardGroup.create(),
|
||||
.status_trackers = undefined,
|
||||
.link = undefined,
|
||||
};
|
||||
seat.wlr_seat.data = seat;
|
||||
|
||||
server.input_manager.seats.append(seat);
|
||||
seat.status_trackers.init();
|
||||
|
||||
try seat.cursor.init(seat);
|
||||
seat.relay.init();
|
||||
|
||||
@ -135,7 +146,7 @@ pub fn init(seat: *Seat, name: [*:0]const u8) !void {
|
||||
seat.wlr_seat.events.request_set_primary_selection.add(&seat.request_set_primary_selection);
|
||||
}
|
||||
|
||||
pub fn deinit(seat: *Seat) void {
|
||||
pub fn destroy(seat: *Seat) void {
|
||||
{
|
||||
var it = server.input_manager.devices.iterator(.forward);
|
||||
while (it.next()) |device| assert(device.seat != seat);
|
||||
@ -151,6 +162,10 @@ pub fn deinit(seat: *Seat) void {
|
||||
seat.start_drag.link.remove();
|
||||
if (seat.drag != .none) seat.drag_destroy.link.remove();
|
||||
seat.request_set_primary_selection.link.remove();
|
||||
|
||||
seat.link.remove();
|
||||
|
||||
util.gpa.destroy(seat);
|
||||
}
|
||||
|
||||
/// Set the current focus. If a visible view is passed it will be focused.
|
||||
@ -295,8 +310,10 @@ pub fn setFocusRaw(seat: *Seat, new_focus: FocusTarget) void {
|
||||
seat.cursor.may_need_warp = true;
|
||||
|
||||
// Inform any clients tracking status of the change
|
||||
var it = seat.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendFocusedView();
|
||||
var it = seat.status_trackers.iterator(.forward);
|
||||
while (it.next()) |tracker| {
|
||||
tracker.sendFocusedView();
|
||||
}
|
||||
}
|
||||
|
||||
/// Send keyboard enter/leave events and handle pointer constraints
|
||||
@ -314,14 +331,15 @@ fn keyboardNotifyEnter(seat: *Seat, wlr_surface: *wlr.Surface) void {
|
||||
if (seat.wlr_seat.getKeyboard()) |wlr_keyboard| {
|
||||
const keyboard: *Keyboard = @alignCast(@ptrCast(wlr_keyboard.data));
|
||||
|
||||
var keycodes: std.BoundedArray(u32, Keyboard.Pressed.capacity) = .{};
|
||||
for (keyboard.pressed.keys.constSlice()) |item| {
|
||||
var buffer: [Keyboard.Pressed.capacity]u32 = undefined;
|
||||
var keycodes: std.ArrayList(u32) = .initBuffer(&buffer);
|
||||
for (keyboard.pressed.slice()) |item| {
|
||||
if (item.consumer == .focus) keycodes.appendAssumeCapacity(item.code);
|
||||
}
|
||||
|
||||
seat.wlr_seat.keyboardNotifyEnter(
|
||||
wlr_surface,
|
||||
keycodes.constSlice(),
|
||||
keycodes.items,
|
||||
&wlr_keyboard.modifiers,
|
||||
);
|
||||
} else {
|
||||
@ -334,15 +352,15 @@ pub fn focusOutput(seat: *Seat, output: ?*Output) void {
|
||||
if (seat.focused_output == output) return;
|
||||
|
||||
if (seat.focused_output) |old| {
|
||||
var it = seat.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendOutput(old, .unfocused);
|
||||
var it = seat.status_trackers.iterator(.forward);
|
||||
while (it.next()) |tracker| tracker.sendOutput(old, .unfocused);
|
||||
}
|
||||
|
||||
seat.focused_output = output;
|
||||
|
||||
if (seat.focused_output) |new| {
|
||||
var it = seat.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) node.data.sendOutput(new, .focused);
|
||||
var it = seat.status_trackers.iterator(.forward);
|
||||
while (it.next()) |tracker| tracker.sendOutput(new, .focused);
|
||||
}
|
||||
|
||||
// Depending on configuration and cursor position, changing output focus
|
||||
@ -357,9 +375,9 @@ pub fn handleActivity(seat: Seat) void {
|
||||
pub fn enterMode(seat: *Seat, mode_id: u32) void {
|
||||
seat.mode_id = mode_id;
|
||||
|
||||
var it = seat.status_trackers.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
node.data.sendMode(server.config.modes.items[mode_id].name);
|
||||
var it = seat.status_trackers.iterator(.forward);
|
||||
while (it.next()) |tracker| {
|
||||
tracker.sendMode(server.config.modes.items[mode_id].name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,8 +471,8 @@ pub fn runCommand(seat: *Seat, args: []const [:0]const u8) void {
|
||||
return;
|
||||
};
|
||||
if (out) |s| {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("{s}", .{s}) catch |err| {
|
||||
var stdout = std.fs.File.stdout().writer(&.{});
|
||||
stdout.interface.print("{s}", .{s}) catch |err| {
|
||||
std.log.scoped(.command).err("{s}: write to stdout failed {}", .{ args[0], err });
|
||||
};
|
||||
}
|
||||
|
@ -31,8 +31,19 @@ const View = @import("View.zig");
|
||||
seat: *Seat,
|
||||
seat_status_v1: *zriver.SeatStatusV1,
|
||||
|
||||
pub fn init(seat_status: *SeatStatus, seat: *Seat, seat_status_v1: *zriver.SeatStatusV1) void {
|
||||
seat_status.* = .{ .seat = seat, .seat_status_v1 = seat_status_v1 };
|
||||
link: wl.list.Link,
|
||||
|
||||
pub fn create(seat: *Seat, seat_status_v1: *zriver.SeatStatusV1) !void {
|
||||
const seat_status = try util.gpa.create(SeatStatus);
|
||||
errdefer util.gpa.destroy(seat_status);
|
||||
|
||||
seat_status.* = .{
|
||||
.seat = seat,
|
||||
.seat_status_v1 = seat_status_v1,
|
||||
.link = undefined,
|
||||
};
|
||||
seat.status_trackers.append(seat_status);
|
||||
errdefer comptime unreachable;
|
||||
|
||||
seat_status_v1.setHandler(*SeatStatus, handleRequest, handleDestroy, seat_status);
|
||||
|
||||
@ -49,9 +60,8 @@ fn handleRequest(seat_status_v1: *zriver.SeatStatusV1, request: zriver.SeatStatu
|
||||
}
|
||||
|
||||
fn handleDestroy(_: *zriver.SeatStatusV1, seat_status: *SeatStatus) void {
|
||||
const node: *std.SinglyLinkedList(SeatStatus).Node = @fieldParentPtr("data", seat_status);
|
||||
seat_status.seat.status_trackers.remove(node);
|
||||
util.gpa.destroy(node);
|
||||
seat_status.link.remove();
|
||||
util.gpa.destroy(seat_status);
|
||||
}
|
||||
|
||||
pub fn sendOutput(seat_status: SeatStatus, output: *Output, state: enum { focused, unfocused }) void {
|
||||
|
@ -24,7 +24,7 @@ const posix = std.posix;
|
||||
const wlr = @import("wlroots");
|
||||
const wl = @import("wayland").server.wl;
|
||||
|
||||
const c = @import("c.zig");
|
||||
const c = @import("c.zig").c;
|
||||
const util = @import("util.zig");
|
||||
|
||||
const Config = @import("Config.zig");
|
||||
|
@ -88,25 +88,21 @@ fn handleRequest(
|
||||
const wlr_seat = wlr.Seat.Client.fromWlSeat(req.seat) orelse return;
|
||||
const seat: *Seat = @alignCast(@ptrCast(wlr_seat.seat.data));
|
||||
|
||||
const node = util.gpa.create(std.SinglyLinkedList(SeatStatus).Node) catch {
|
||||
status_manager_v1.getClient().postNoMemory();
|
||||
log.err("out of memory", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
const seat_status = zriver.SeatStatusV1.create(
|
||||
status_manager_v1.getClient(),
|
||||
status_manager_v1.getVersion(),
|
||||
req.id,
|
||||
) catch {
|
||||
status_manager_v1.getClient().postNoMemory();
|
||||
util.gpa.destroy(node);
|
||||
log.err("out of memory", .{});
|
||||
return;
|
||||
};
|
||||
|
||||
node.data.init(seat, seat_status);
|
||||
seat.status_trackers.prepend(node);
|
||||
SeatStatus.create(seat, seat_status) catch {
|
||||
status_manager_v1.getClient().postNoMemory();
|
||||
log.err("out of memory", .{});
|
||||
return;
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -277,11 +277,12 @@ pub fn resizeUpdatePosition(view: *View, width: i32, height: i32) void {
|
||||
assert(view.inflight.resizing);
|
||||
|
||||
const data = blk: {
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const cursor = &node.data.cursor;
|
||||
if (cursor.inflight_mode == .resize and cursor.inflight_mode.resize.view == view) {
|
||||
break :blk cursor.inflight_mode.resize;
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| {
|
||||
if (seat.cursor.inflight_mode == .resize and
|
||||
seat.cursor.inflight_mode.resize.view == view)
|
||||
{
|
||||
break :blk seat.cursor.inflight_mode.resize;
|
||||
}
|
||||
} else {
|
||||
// The view resizing state should never be set when the view is
|
||||
@ -710,8 +711,8 @@ pub fn map(view: *View) !void {
|
||||
if (output) |o| {
|
||||
view.setPendingOutput(o);
|
||||
|
||||
var it = server.input_manager.seats.first;
|
||||
while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(view);
|
||||
var it = server.input_manager.seats.iterator(.forward);
|
||||
while (it.next()) |seat| seat.focus(view);
|
||||
} else {
|
||||
log.debug("no output available for newly mapped view, adding to fallback stacks", .{});
|
||||
|
||||
@ -778,12 +779,12 @@ pub fn notifyTitle(view: *const View) void {
|
||||
}
|
||||
|
||||
// Send title to all status listeners attached to a seat which focuses this view
|
||||
var seat_it = server.input_manager.seats.first;
|
||||
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||
if (seat_node.data.focused == .view and seat_node.data.focused.view == view) {
|
||||
var client_it = seat_node.data.status_trackers.first;
|
||||
while (client_it) |client_node| : (client_it = client_node.next) {
|
||||
client_node.data.sendFocusedView();
|
||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
||||
while (seat_it.next()) |seat| {
|
||||
if (seat.focused == .view and seat.focused.view == view) {
|
||||
var it = seat.status_trackers.iterator(.forward);
|
||||
while (it.next()) |tracker| {
|
||||
tracker.sendFocusedView();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,9 +165,8 @@ fn handleUnmap(listener: *wl.Listener(void)) void {
|
||||
|
||||
// If the unmapped surface is currently focused, pass keyboard focus
|
||||
// to the most appropriate surface.
|
||||
var seat_it = server.input_manager.seats.first;
|
||||
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||
const seat = &seat_node.data;
|
||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
||||
while (seat_it.next()) |seat| {
|
||||
if (seat.focused == .view and seat.focused.view.impl == .xwayland_view and
|
||||
seat.focused.view.impl.xwayland_view.xwayland_surface.pid == override_redirect.xwayland_surface.pid and
|
||||
seat.wlr_seat.keyboard_state.focused_surface == override_redirect.xwayland_surface.surface)
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
pub usingnamespace @cImport({
|
||||
pub const c = @cImport({
|
||||
@cDefine("_POSIX_C_SOURCE", "200809L");
|
||||
|
||||
@cInclude("stdlib.h");
|
||||
|
@ -122,6 +122,7 @@ pub const Error = error{
|
||||
CannotParseFile,
|
||||
UnknownOption,
|
||||
ConflictingOptions,
|
||||
WriteFailed,
|
||||
OutOfMemory,
|
||||
Other,
|
||||
};
|
||||
@ -165,7 +166,7 @@ pub fn errToMsg(err: Error) [:0]const u8 {
|
||||
Error.InvalidValue => "invalid value",
|
||||
Error.CannotReadFile => "cannot read file",
|
||||
Error.CannotParseFile => "cannot parse file",
|
||||
Error.OutOfMemory => "out of memory",
|
||||
Error.WriteFailed, Error.OutOfMemory => "out of memory",
|
||||
Error.Other => unreachable,
|
||||
};
|
||||
}
|
||||
|
@ -35,9 +35,8 @@ pub fn cursor(
|
||||
if (args.len < 3) return Error.NotEnoughArguments;
|
||||
if (args.len > 3) return Error.TooManyArguments;
|
||||
server.config.cursor_hide_timeout = try std.fmt.parseInt(u31, args[2], 10);
|
||||
var seat_it = server.input_manager.seats.first;
|
||||
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||
const seat = &seat_node.data;
|
||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
||||
while (seat_it.next()) |seat| {
|
||||
seat.cursor.unhide();
|
||||
}
|
||||
} else if (std.mem.eql(u8, "when-typing", args[1])) {
|
||||
|
@ -34,8 +34,8 @@ pub fn listInputs(
|
||||
) Error!void {
|
||||
if (args.len > 1) return error.TooManyArguments;
|
||||
|
||||
var input_list = std.ArrayList(u8).init(util.gpa);
|
||||
const writer = input_list.writer();
|
||||
var aw: std.Io.Writer.Allocating = .init(util.gpa);
|
||||
|
||||
var prev = false;
|
||||
|
||||
var it = server.input_manager.devices.iterator(.forward);
|
||||
@ -46,16 +46,16 @@ pub fn listInputs(
|
||||
}
|
||||
} else false;
|
||||
|
||||
if (prev) try input_list.appendSlice("\n");
|
||||
if (prev) try aw.writer.writeByte('\n');
|
||||
prev = true;
|
||||
|
||||
try writer.print("{s}\n\tconfigured: {}\n", .{
|
||||
try aw.writer.print("{s}\n\tconfigured: {}\n", .{
|
||||
device.identifier,
|
||||
configured,
|
||||
});
|
||||
}
|
||||
|
||||
out.* = try input_list.toOwnedSlice();
|
||||
out.* = try aw.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn listInputConfigs(
|
||||
@ -65,15 +65,14 @@ pub fn listInputConfigs(
|
||||
) Error!void {
|
||||
if (args.len > 1) return error.TooManyArguments;
|
||||
|
||||
var input_list = std.ArrayList(u8).init(util.gpa);
|
||||
const writer = input_list.writer();
|
||||
var aw: std.Io.Writer.Allocating = .init(util.gpa);
|
||||
|
||||
for (server.input_manager.configs.items, 0..) |*input_config, i| {
|
||||
if (i > 0) try writer.writeByte('\n');
|
||||
try input_config.write(writer);
|
||||
if (i > 0) try aw.writer.writeByte('\n');
|
||||
try input_config.write(&aw.writer);
|
||||
}
|
||||
|
||||
out.* = try input_list.toOwnedSlice();
|
||||
out.* = try aw.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn input(
|
||||
@ -99,7 +98,7 @@ pub fn input(
|
||||
};
|
||||
errdefer util.gpa.free(input_config.glob);
|
||||
|
||||
try server.input_manager.configs.ensureUnusedCapacity(1);
|
||||
try server.input_manager.configs.ensureUnusedCapacity(util.gpa, 1);
|
||||
|
||||
try input_config.parse(args[2], args[3]);
|
||||
|
||||
|
@ -71,9 +71,8 @@ pub fn sendLayoutCmd(
|
||||
const output = seat.focused_output orelse return;
|
||||
const target_namespace = args[1];
|
||||
|
||||
var it = output.layouts.first;
|
||||
const layout = while (it) |node| : (it = node.next) {
|
||||
const layout = &node.data;
|
||||
var it = output.layouts.iterator(.forward);
|
||||
const layout = while (it.next()) |layout| {
|
||||
if (mem.eql(u8, layout.namespace, target_namespace)) break layout;
|
||||
} else return;
|
||||
|
||||
|
@ -22,7 +22,7 @@ const wlr = @import("wlroots");
|
||||
const xkb = @import("xkbcommon");
|
||||
const flags = @import("flags");
|
||||
|
||||
const c = @import("../c.zig");
|
||||
const c = @import("../c.zig").c;
|
||||
const server = &@import("../main.zig").server;
|
||||
const util = @import("../util.zig");
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const fmt = std.fmt;
|
||||
|
||||
const globber = @import("globber");
|
||||
@ -217,6 +218,12 @@ fn apply_tearing_rules() void {
|
||||
}
|
||||
}
|
||||
|
||||
fn alignLeft(buf: []const u8, width: usize, writer: *std.io.Writer) Error!void {
|
||||
assert(buf.len <= width);
|
||||
try writer.writeAll(buf);
|
||||
try writer.splatByteAll(' ', width - buf.len);
|
||||
}
|
||||
|
||||
pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!void {
|
||||
if (args.len < 2) return error.NotEnoughArguments;
|
||||
if (args.len > 2) return error.TooManyArguments;
|
||||
@ -237,11 +244,12 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
||||
const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id);
|
||||
const title_column_max = 2 + @max("title".len, max_glob_len.title);
|
||||
|
||||
var buffer = std.ArrayList(u8).init(util.gpa);
|
||||
const writer = buffer.writer();
|
||||
var buffer = std.io.Writer.Allocating.init(util.gpa);
|
||||
defer buffer.deinit();
|
||||
const writer = &buffer.writer;
|
||||
|
||||
try fmt.formatBuf("title", .{ .width = title_column_max, .alignment = .left }, writer);
|
||||
try fmt.formatBuf("app-id", .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||
try alignLeft("title", title_column_max, writer);
|
||||
try alignLeft("app-id", app_id_column_max, writer);
|
||||
try writer.writeAll("action\n");
|
||||
|
||||
switch (rule_list) {
|
||||
@ -255,8 +263,8 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
||||
else => unreachable,
|
||||
};
|
||||
for (rules) |rule| {
|
||||
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
||||
try writer.print("{s}\n", .{switch (list) {
|
||||
.float => if (rule.value) "float" else "no-float",
|
||||
.ssd => if (rule.value) "ssd" else "csd",
|
||||
@ -269,22 +277,22 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
||||
},
|
||||
.tags => {
|
||||
for (server.config.rules.tags.rules.items) |rule| {
|
||||
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
||||
try writer.print("{b}\n", .{rule.value});
|
||||
}
|
||||
},
|
||||
.position => {
|
||||
for (server.config.rules.position.rules.items) |rule| {
|
||||
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
||||
try writer.print("{d},{d}\n", .{ rule.value.x, rule.value.y });
|
||||
}
|
||||
},
|
||||
.dimensions => {
|
||||
for (server.config.rules.dimensions.rules.items) |rule| {
|
||||
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
||||
try writer.print("{d}x{d}\n", .{ rule.value.width, rule.value.height });
|
||||
}
|
||||
},
|
||||
|
@ -17,7 +17,7 @@
|
||||
const std = @import("std");
|
||||
const posix = std.posix;
|
||||
|
||||
const c = @import("../c.zig");
|
||||
const c = @import("../c.zig").c;
|
||||
const util = @import("../util.zig");
|
||||
const process = @import("../process.zig");
|
||||
|
||||
|
@ -18,14 +18,13 @@ const build_options = @import("build_options");
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const fs = std.fs;
|
||||
const io = std.io;
|
||||
const log = std.log;
|
||||
const posix = std.posix;
|
||||
const builtin = @import("builtin");
|
||||
const wlr = @import("wlroots");
|
||||
const flags = @import("flags");
|
||||
|
||||
const c = @import("c.zig");
|
||||
const c = @import("c.zig").c;
|
||||
const util = @import("util.zig");
|
||||
const process = @import("process.zig");
|
||||
|
||||
@ -52,21 +51,21 @@ pub fn main() anyerror!void {
|
||||
.{ .name = "log-level", .kind = .arg },
|
||||
.{ .name = "no-xwayland", .kind = .boolean },
|
||||
}).parse(std.os.argv[1..]) catch {
|
||||
try io.getStdErr().writeAll(usage);
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
};
|
||||
if (result.flags.h) {
|
||||
try io.getStdOut().writeAll(usage);
|
||||
try fs.File.stdout().writeAll(usage);
|
||||
posix.exit(0);
|
||||
}
|
||||
if (result.args.len != 0) {
|
||||
log.err("unknown option '{s}'", .{result.args[0]});
|
||||
try io.getStdErr().writeAll(usage);
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
}
|
||||
|
||||
if (result.flags.version) {
|
||||
try io.getStdOut().writeAll(build_options.version ++ "\n");
|
||||
try fs.File.stdout().writeAll(build_options.version ++ "\n");
|
||||
posix.exit(0);
|
||||
}
|
||||
if (result.flags.@"log-level") |level| {
|
||||
@ -80,7 +79,7 @@ pub fn main() anyerror!void {
|
||||
runtime_log_level = .debug;
|
||||
} else {
|
||||
log.err("invalid log level '{s}'", .{level});
|
||||
try io.getStdErr().writeAll(usage);
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
}
|
||||
}
|
||||
@ -189,8 +188,8 @@ pub fn logFn(
|
||||
|
||||
const scope_prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
||||
|
||||
const stderr = io.getStdErr().writer();
|
||||
stderr.print(level.asText() ++ scope_prefix ++ format ++ "\n", args) catch {};
|
||||
var stderr = fs.File.stderr().writer(&.{});
|
||||
stderr.interface.print(level.asText() ++ scope_prefix ++ format ++ "\n", args) catch {};
|
||||
}
|
||||
|
||||
/// See wlroots_log_wrapper.c
|
||||
|
@ -17,7 +17,7 @@
|
||||
const std = @import("std");
|
||||
const posix = std.posix;
|
||||
|
||||
const c = @import("c.zig");
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
var original_rlimit: ?posix.rlimit = null;
|
||||
|
||||
@ -26,7 +26,7 @@ pub fn setup() void {
|
||||
// has had its read end closed by another process.
|
||||
const sig_ign = posix.Sigaction{
|
||||
.handler = .{ .handler = posix.SIG.IGN },
|
||||
.mask = posix.empty_sigset,
|
||||
.mask = posix.sigemptyset(),
|
||||
.flags = 0,
|
||||
};
|
||||
posix.sigaction(posix.SIG.PIPE, &sig_ign, null);
|
||||
@ -61,11 +61,11 @@ pub fn setup() void {
|
||||
|
||||
pub fn cleanupChild() void {
|
||||
if (c.setsid() < 0) unreachable;
|
||||
if (posix.system.sigprocmask(posix.SIG.SETMASK, &posix.empty_sigset, null) < 0) unreachable;
|
||||
if (posix.system.sigprocmask(posix.SIG.SETMASK, &posix.sigemptyset(), null) < 0) unreachable;
|
||||
|
||||
const sig_dfl = posix.Sigaction{
|
||||
.handler = .{ .handler = posix.SIG.DFL },
|
||||
.mask = posix.empty_sigset,
|
||||
.mask = posix.sigemptyset(),
|
||||
.flags = 0,
|
||||
};
|
||||
posix.sigaction(posix.SIG.PIPE, &sig_dfl, null);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const io = std.io;
|
||||
const fs = std.fs;
|
||||
const posix = std.posix;
|
||||
const assert = std.debug.assert;
|
||||
const builtin = @import("builtin");
|
||||
@ -73,15 +73,15 @@ fn _main() !void {
|
||||
.{ .name = "h", .kind = .boolean },
|
||||
.{ .name = "version", .kind = .boolean },
|
||||
}).parse(std.os.argv[1..]) catch {
|
||||
try io.getStdErr().writeAll(usage);
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
};
|
||||
if (result.flags.h) {
|
||||
try io.getStdOut().writeAll(usage);
|
||||
try fs.File.stdout().writeAll(usage);
|
||||
posix.exit(0);
|
||||
}
|
||||
if (result.flags.version) {
|
||||
try io.getStdOut().writeAll(@import("build_options").version ++ "\n");
|
||||
try fs.File.stdout().writeAll(@import("build_options").version ++ "\n");
|
||||
posix.exit(0);
|
||||
}
|
||||
|
||||
@ -125,8 +125,8 @@ fn callbackListener(_: *zriver.CommandCallbackV1, event: zriver.CommandCallbackV
|
||||
switch (event) {
|
||||
.success => |success| {
|
||||
if (mem.len(success.output) > 0) {
|
||||
const stdout = io.getStdOut().writer();
|
||||
stdout.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
|
||||
var stdout = fs.File.stdout().writer(&.{});
|
||||
stdout.interface.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
|
||||
}
|
||||
posix.exit(0);
|
||||
},
|
||||
@ -134,7 +134,7 @@ fn callbackListener(_: *zriver.CommandCallbackV1, event: zriver.CommandCallbackV
|
||||
// A small hack to provide usage text when river reports an unknown command.
|
||||
if (mem.orderZ(u8, failure.failure_message, "unknown command") == .eq) {
|
||||
std.log.err("unknown command", .{});
|
||||
io.getStdErr().writeAll(usage) catch {};
|
||||
fs.File.stderr().writeAll(usage) catch {};
|
||||
posix.exit(1);
|
||||
}
|
||||
fatal("{s}", .{failure.failure_message});
|
||||
|
@ -91,15 +91,12 @@ const gpa = std.heap.c_allocator;
|
||||
const Context = struct {
|
||||
initialized: bool = false,
|
||||
layout_manager: ?*river.LayoutManagerV3 = null,
|
||||
outputs: std.DoublyLinkedList(Output) = .{},
|
||||
outputs: wl.list.Head(Output, .link),
|
||||
|
||||
fn addOutput(context: *Context, registry: *wl.Registry, name: u32) !void {
|
||||
const wl_output = try registry.bind(name, wl.Output, 3);
|
||||
errdefer wl_output.release();
|
||||
const node = try gpa.create(std.DoublyLinkedList(Output).Node);
|
||||
errdefer gpa.destroy(node);
|
||||
try node.data.init(context, wl_output, name);
|
||||
context.outputs.append(node);
|
||||
try Output.create(context, wl_output, name);
|
||||
}
|
||||
};
|
||||
|
||||
@ -113,15 +110,21 @@ const Output = struct {
|
||||
|
||||
layout: *river.LayoutV3 = undefined,
|
||||
|
||||
fn init(output: *Output, context: *Context, wl_output: *wl.Output, name: u32) !void {
|
||||
link: wl.list.Link,
|
||||
|
||||
fn create(context: *Context, wl_output: *wl.Output, name: u32) !void {
|
||||
const output = try gpa.create(Output);
|
||||
errdefer gpa.destroy(output);
|
||||
output.* = .{
|
||||
.wl_output = wl_output,
|
||||
.name = name,
|
||||
.main_location = default_main_location,
|
||||
.main_count = default_main_count,
|
||||
.main_ratio = default_main_ratio,
|
||||
.link = undefined,
|
||||
};
|
||||
if (context.initialized) try output.getLayout(context);
|
||||
context.outputs.append(output);
|
||||
}
|
||||
|
||||
fn getLayout(output: *Output, context: *Context) !void {
|
||||
@ -130,9 +133,11 @@ const Output = struct {
|
||||
output.layout.setListener(*Output, layoutListener, output);
|
||||
}
|
||||
|
||||
fn deinit(output: *Output) void {
|
||||
fn destroy(output: *Output) void {
|
||||
output.wl_output.release();
|
||||
output.layout.destroy();
|
||||
output.link.remove();
|
||||
gpa.destroy(output);
|
||||
}
|
||||
|
||||
fn layoutListener(layout: *river.LayoutV3, event: river.LayoutV3.Event, output: *Output) void {
|
||||
@ -312,17 +317,17 @@ pub fn main() !void {
|
||||
.{ .name = "main-count", .kind = .arg },
|
||||
.{ .name = "main-ratio", .kind = .arg },
|
||||
}).parse(std.os.argv[1..]) catch {
|
||||
try std.io.getStdErr().writeAll(usage);
|
||||
try std.fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
};
|
||||
if (result.flags.h) {
|
||||
try std.io.getStdOut().writeAll(usage);
|
||||
try std.fs.File.stdout().writeAll(usage);
|
||||
posix.exit(0);
|
||||
}
|
||||
if (result.args.len != 0) fatalPrintUsage("unknown option '{s}'", .{result.args[0]});
|
||||
|
||||
if (result.flags.version) {
|
||||
try std.io.getStdOut().writeAll(@import("build_options").version ++ "\n");
|
||||
try std.fs.File.stdout().writeAll(@import("build_options").version ++ "\n");
|
||||
posix.exit(0);
|
||||
}
|
||||
if (result.flags.@"view-padding") |raw| {
|
||||
@ -356,7 +361,10 @@ pub fn main() !void {
|
||||
};
|
||||
defer display.disconnect();
|
||||
|
||||
var context: Context = .{};
|
||||
var context: Context = .{
|
||||
.outputs = undefined,
|
||||
};
|
||||
context.outputs.init();
|
||||
|
||||
const registry = try display.getRegistry();
|
||||
registry.setListener(*Context, registryListener, &context);
|
||||
@ -368,9 +376,8 @@ pub fn main() !void {
|
||||
|
||||
context.initialized = true;
|
||||
|
||||
var it = context.outputs.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const output = &node.data;
|
||||
var it = context.outputs.iterator(.forward);
|
||||
while (it.next()) |output| {
|
||||
try output.getLayout(&context);
|
||||
}
|
||||
|
||||
@ -389,13 +396,10 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *
|
||||
}
|
||||
},
|
||||
.global_remove => |ev| {
|
||||
var it = context.outputs.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
const output = &node.data;
|
||||
var it = context.outputs.safeIterator(.forward);
|
||||
while (it.next()) |output| {
|
||||
if (output.name == ev.name) {
|
||||
context.outputs.remove(node);
|
||||
output.deinit();
|
||||
gpa.destroy(node);
|
||||
output.destroy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -410,7 +414,7 @@ fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
|
||||
fn fatalPrintUsage(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.err(format, args);
|
||||
std.io.getStdErr().writeAll(usage) catch {};
|
||||
std.fs.File.stderr().writeAll(usage) catch {};
|
||||
posix.exit(1);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user