Compare commits
10 Commits
main
...
050b9976f1
| Author | SHA1 | Date | |
|---|---|---|---|
|
050b9976f1
|
|||
| 273f31016a | |||
| 53405ec4df | |||
| 0d31ec658a | |||
| 6962fe20be | |||
| 3456deeed4 | |||
| 2089f84b21 | |||
| 5d8a493057 | |||
| 49721c5641 | |||
| a955ae21e5 |
+4
-4
@@ -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.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
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz
|
||||
tar xf zig-x86_64-linux-0.16.0.tar.xz
|
||||
sudo mv zig-x86_64-linux-0.16.0/zig /usr/bin/
|
||||
sudo mv zig-x86_64-linux-0.16.0/lib /usr/lib/zig
|
||||
- build: |
|
||||
cd river-classic
|
||||
zig build --summary all
|
||||
|
||||
@@ -34,16 +34,18 @@ 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.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
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.16.0/zig-x86_64-linux-0.16.0.tar.xz
|
||||
tar xf zig-x86_64-linux-0.16.0.tar.xz
|
||||
sudo mv zig-x86_64-linux-0.16.0/zig /usr/bin/
|
||||
sudo mv zig-x86_64-linux-0.16.0/lib /usr/lib/zig
|
||||
- build: |
|
||||
cd river-classic
|
||||
zig build --summary all
|
||||
# Arch's glibc version has SFrame sections in crt objects, force llvm/lld usage as a workaround
|
||||
# https://codeberg.org/ziglang/zig/issues/31272
|
||||
zig build -Dllvm --summary all
|
||||
- build_xwayland: |
|
||||
cd river-classic
|
||||
zig build --summary all -Dxwayland
|
||||
zig build -Dllvm --summary all -Dxwayland
|
||||
- fmt: |
|
||||
cd river-classic
|
||||
zig fmt --check river/
|
||||
|
||||
+4
-4
@@ -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.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
|
||||
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.16.0/zig-x86_64-freebsd-0.16.0.tar.xz
|
||||
tar xf zig-x86_64-freebsd-0.16.0.tar.xz
|
||||
sudo mv zig-x86_64-freebsd-0.16.0/zig /usr/bin/
|
||||
sudo mv zig-x86_64-freebsd-0.16.0/lib /usr/lib/zig
|
||||
- build: |
|
||||
cd river-classic
|
||||
zig build --summary all
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
zig-pkg/
|
||||
|
||||
@@ -50,7 +50,7 @@ To compile river-classic 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.15
|
||||
- [zig](https://ziglang.org/download/) 0.16
|
||||
- wayland
|
||||
- wayland-protocols
|
||||
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.20
|
||||
|
||||
@@ -4,7 +4,11 @@ const Build = std.Build;
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
|
||||
const manifest = @import("build.zig.zon");
|
||||
const version = manifest.version;
|
||||
|
||||
const Scanner = @import("wayland").Scanner;
|
||||
const Translator = @import("translate_c").Translator;
|
||||
|
||||
pub fn build(b: *Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
@@ -12,6 +16,7 @@ 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 use_llvm = b.option(bool, "llvm", "Force use of Zig's LLVM backend and the lld linker") orelse false;
|
||||
|
||||
const omit_frame_pointer = switch (optimize) {
|
||||
.Debug, .ReleaseSafe => false,
|
||||
@@ -25,7 +30,6 @@ pub fn build(b: *Build) !void {
|
||||
) orelse scdoc_found: {
|
||||
_ = b.findProgram(&.{"scdoc"}, &.{}) catch |err| switch (err) {
|
||||
error.FileNotFound => break :scdoc_found false,
|
||||
else => return err,
|
||||
};
|
||||
break :scdoc_found true;
|
||||
};
|
||||
@@ -61,7 +65,7 @@ pub fn build(b: *Build) !void {
|
||||
const git_describe_long = b.runAllowFail(
|
||||
&.{ "git", "-C", b.build_root.path orelse ".", "describe", "--long" },
|
||||
&ret,
|
||||
.Inherit,
|
||||
.inherit,
|
||||
) catch break :blk version;
|
||||
|
||||
var it = mem.splitScalar(u8, mem.trim(u8, git_describe_long, &std.ascii.whitespace), '-');
|
||||
@@ -154,6 +158,15 @@ pub fn build(b: *Build) !void {
|
||||
const flags = b.createModule(.{ .root_source_file = b.path("common/flags.zig") });
|
||||
const globber = b.createModule(.{ .root_source_file = b.path("common/globber.zig") });
|
||||
|
||||
const translate_c: Translator = .init(b.dependency("translate_c", .{}), .{
|
||||
.name = "c",
|
||||
.c_source_file = b.path("river/c.h"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
translate_c.linkSystemLibrary("libevdev", .{});
|
||||
translate_c.linkSystemLibrary("libinput", .{});
|
||||
|
||||
{
|
||||
const river = b.addExecutable(.{
|
||||
.name = "river",
|
||||
@@ -162,17 +175,19 @@ pub fn build(b: *Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.use_llvm = use_llvm,
|
||||
.use_lld = use_llvm,
|
||||
});
|
||||
river.root_module.addOptions("build_options", options);
|
||||
|
||||
river.linkLibC();
|
||||
river.linkSystemLibrary("libevdev");
|
||||
river.linkSystemLibrary("libinput");
|
||||
river.linkSystemLibrary("wayland-server");
|
||||
river.linkSystemLibrary("wlroots-0.20");
|
||||
river.linkSystemLibrary("xkbcommon");
|
||||
river.linkSystemLibrary("pixman-1");
|
||||
river.root_module.linkSystemLibrary("libevdev", .{});
|
||||
river.root_module.linkSystemLibrary("libinput", .{});
|
||||
river.root_module.linkSystemLibrary("wayland-server", .{});
|
||||
river.root_module.linkSystemLibrary("wlroots-0.20", .{});
|
||||
river.root_module.linkSystemLibrary("xkbcommon", .{});
|
||||
river.root_module.linkSystemLibrary("pixman-1", .{});
|
||||
|
||||
river.root_module.addImport("wayland", wayland);
|
||||
river.root_module.addImport("xkbcommon", xkbcommon);
|
||||
@@ -180,8 +195,9 @@ pub fn build(b: *Build) !void {
|
||||
river.root_module.addImport("wlroots", wlroots);
|
||||
river.root_module.addImport("flags", flags);
|
||||
river.root_module.addImport("globber", globber);
|
||||
river.root_module.addImport("c", translate_c.mod);
|
||||
|
||||
river.addCSourceFile(.{
|
||||
river.root_module.addCSourceFile(.{
|
||||
.file = b.path("river/wlroots_log_wrapper.c"),
|
||||
.flags = &.{ "-std=c99", "-O2" },
|
||||
});
|
||||
@@ -200,14 +216,16 @@ pub fn build(b: *Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.use_llvm = use_llvm,
|
||||
.use_lld = use_llvm,
|
||||
});
|
||||
riverctl.root_module.addOptions("build_options", options);
|
||||
|
||||
riverctl.root_module.addImport("flags", flags);
|
||||
riverctl.root_module.addImport("wayland", wayland);
|
||||
riverctl.linkLibC();
|
||||
riverctl.linkSystemLibrary("wayland-client");
|
||||
riverctl.root_module.linkSystemLibrary("wayland-client", .{});
|
||||
|
||||
riverctl.pie = pie;
|
||||
riverctl.root_module.omit_frame_pointer = omit_frame_pointer;
|
||||
@@ -223,14 +241,16 @@ pub fn build(b: *Build) !void {
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
.link_libc = true,
|
||||
}),
|
||||
.use_llvm = use_llvm,
|
||||
.use_lld = use_llvm,
|
||||
});
|
||||
rivertile.root_module.addOptions("build_options", options);
|
||||
|
||||
rivertile.root_module.addImport("flags", flags);
|
||||
rivertile.root_module.addImport("wayland", wayland);
|
||||
rivertile.linkLibC();
|
||||
rivertile.linkSystemLibrary("wayland-client");
|
||||
rivertile.root_module.linkSystemLibrary("wayland-client", .{});
|
||||
|
||||
rivertile.pie = pie;
|
||||
rivertile.root_module.omit_frame_pointer = omit_frame_pointer;
|
||||
@@ -263,7 +283,7 @@ pub fn build(b: *Build) !void {
|
||||
// This makes the caching work for the Workaround, and the extra argument is ignored by /bin/sh.
|
||||
scdoc.addFileArg(b.path("doc/" ++ page ++ ".1.scd"));
|
||||
|
||||
const stdout = scdoc.captureStdOut();
|
||||
const stdout = scdoc.captureStdOut(.{});
|
||||
b.getInstallStep().dependOn(&b.addInstallFile(stdout, "share/man/man1/" ++ page ++ ".1").step);
|
||||
}
|
||||
}
|
||||
@@ -294,31 +314,3 @@ pub fn build(b: *Build) !void {
|
||||
test_step.dependOn(&run_globber_test.step);
|
||||
}
|
||||
}
|
||||
|
||||
const version = manifest.version;
|
||||
/// Getting rid of this wart requires upstream zig improvements.
|
||||
/// See: https://github.com/ziglang/zig/issues/22775
|
||||
const manifest: struct {
|
||||
name: @Type(.enum_literal),
|
||||
version: []const u8,
|
||||
paths: []const []const u8,
|
||||
dependencies: struct {
|
||||
pixman: struct {
|
||||
url: []const u8,
|
||||
hash: []const u8,
|
||||
},
|
||||
wayland: struct {
|
||||
url: []const u8,
|
||||
hash: []const u8,
|
||||
},
|
||||
wlroots: struct {
|
||||
url: []const u8,
|
||||
hash: []const u8,
|
||||
},
|
||||
xkbcommon: struct {
|
||||
url: []const u8,
|
||||
hash: []const u8,
|
||||
},
|
||||
},
|
||||
fingerprint: u64,
|
||||
} = @import("build.zig.zon");
|
||||
|
||||
+9
-5
@@ -5,7 +5,7 @@
|
||||
// When a release is tagged, the "-dev" suffix should be removed for the
|
||||
// commit that gets tagged. Directly after the tagged commit, the version
|
||||
// should be bumped and the "-dev" suffix added.
|
||||
.version = "0.3.16-dev",
|
||||
.version = "0.3.18-dev",
|
||||
.paths = .{""},
|
||||
.dependencies = .{
|
||||
.pixman = .{
|
||||
@@ -13,17 +13,21 @@
|
||||
.hash = "pixman-0.3.0-LClMnz2VAAAs7QSCGwLimV5VUYx0JFnX5xWU6HwtMuDX",
|
||||
},
|
||||
.wayland = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.4.0.tar.gz",
|
||||
.hash = "wayland-0.4.0-lQa1khbMAQAsLS2eBR7M5lofyEGPIbu2iFDmoz8lPC27",
|
||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.6.0.tar.gz",
|
||||
.hash = "wayland-0.6.0-lQa1kqz8AQADQmdNJsNhLoNHcnEGEUjrOaPV-dtEnEmX",
|
||||
},
|
||||
.wlroots = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.20.0.tar.gz",
|
||||
.hash = "wlroots-0.20.0-jmOlcmtCBADS6eoJ6mkeiSNZkibrhD-c5Qwn-LiM86r1",
|
||||
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.20.1.tar.gz",
|
||||
.hash = "wlroots-0.20.1-jmOlcqNVBAB3uB5oqBTzpRlwu-FmMyyZMVAWCe5kmcSt",
|
||||
},
|
||||
.xkbcommon = .{
|
||||
.url = "https://codeberg.org/ifreund/zig-xkbcommon/archive/v0.3.0.tar.gz",
|
||||
.hash = "xkbcommon-0.3.0-VDqIe3K9AQB2fG5ZeRcMC9i7kfrp5m2rWgLrmdNn9azr",
|
||||
},
|
||||
.translate_c = .{
|
||||
.url = "git+https://codeberg.org/ziglang/translate-c/#7a1a9fdc4ab00835748a6657ecbb835e3d5d45f7",
|
||||
.hash = "translate_c-0.0.0-Q_BUWvP1BgCjAk6PWv5286tOlvzD9-X-NkuTzh0KxY0Q",
|
||||
},
|
||||
},
|
||||
.fingerprint = 0x3dae7aba2ea52a3b,
|
||||
}
|
||||
|
||||
+23
-58
@@ -1,82 +1,51 @@
|
||||
// Zero allocation argument parsing for unix-like systems.
|
||||
// Released under the Zero Clause BSD (0BSD) license:
|
||||
//
|
||||
// Copyright 2023 Isaac Freund
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
// SPDX-FileCopyrightText: © 2023 Isaac Freund
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
|
||||
pub const Flag = struct {
|
||||
name: [:0]const u8,
|
||||
name: []const u8,
|
||||
kind: enum { boolean, arg },
|
||||
};
|
||||
|
||||
pub fn parser(comptime Arg: type, comptime flags: []const Flag) type {
|
||||
switch (Arg) {
|
||||
// TODO consider allowing []const u8
|
||||
[:0]const u8, [*:0]const u8 => {}, // ok
|
||||
else => @compileError("invalid argument type: " ++ @typeName(Arg)),
|
||||
}
|
||||
pub fn parser(comptime flags: []const Flag) type {
|
||||
return struct {
|
||||
pub const Result = struct {
|
||||
/// Remaining args after the recognized flags
|
||||
args: []const Arg,
|
||||
args: []const [:0]const u8,
|
||||
/// Data obtained from parsed flags
|
||||
flags: Flags,
|
||||
|
||||
pub const Flags = flags_type: {
|
||||
var fields: []const std.builtin.Type.StructField = &.{};
|
||||
for (flags) |flag| {
|
||||
const field: std.builtin.Type.StructField = switch (flag.kind) {
|
||||
.boolean => .{
|
||||
.name = flag.name,
|
||||
.type = bool,
|
||||
.default_value_ptr = &false,
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(bool),
|
||||
const Attributes = std.builtin.Type.StructField.Attributes;
|
||||
var names: [flags.len][]const u8 = undefined;
|
||||
var types: [flags.len]type = undefined;
|
||||
var attrs: [flags.len]Attributes = undefined;
|
||||
for (flags, &names, &types, &attrs) |flag, *name, *ty, *attr| {
|
||||
name.* = flag.name;
|
||||
switch (flag.kind) {
|
||||
.boolean => {
|
||||
ty.* = bool;
|
||||
attr.* = .{ .default_value_ptr = &false };
|
||||
},
|
||||
.arg => .{
|
||||
.name = flag.name,
|
||||
.type = ?[:0]const u8,
|
||||
.default_value_ptr = &@as(?[:0]const u8, null),
|
||||
.is_comptime = false,
|
||||
.alignment = @alignOf(?[:0]const u8),
|
||||
.arg => {
|
||||
ty.* = ?[:0]const u8;
|
||||
attr.* = .{ .default_value_ptr = &@as(ty.*, null) };
|
||||
},
|
||||
};
|
||||
fields = fields ++ [_]std.builtin.Type.StructField{field};
|
||||
}
|
||||
}
|
||||
break :flags_type @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = fields,
|
||||
.decls = &.{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
break :flags_type @Struct(.auto, null, &names, &types, &attrs);
|
||||
};
|
||||
};
|
||||
|
||||
pub fn parse(args: []const Arg) !Result {
|
||||
pub fn parse(args: []const [:0]const u8) error{MissingFlagArgument}!Result {
|
||||
var result_flags: Result.Flags = .{};
|
||||
|
||||
var i: usize = 0;
|
||||
outer: while (i < args.len) : (i += 1) {
|
||||
const arg = switch (Arg) {
|
||||
[*:0]const u8 => mem.sliceTo(args[i], 0),
|
||||
[:0]const u8 => args[i],
|
||||
else => unreachable,
|
||||
};
|
||||
inline for (flags) |flag| {
|
||||
if (mem.eql(u8, "-" ++ flag.name, arg)) {
|
||||
if (mem.eql(u8, "-" ++ flag.name, args[i])) {
|
||||
switch (flag.kind) {
|
||||
.boolean => @field(result_flags, flag.name) = true,
|
||||
.arg => {
|
||||
@@ -86,11 +55,7 @@ pub fn parser(comptime Arg: type, comptime flags: []const Flag) type {
|
||||
"' requires an argument but none was provided!", .{});
|
||||
return error.MissingFlagArgument;
|
||||
}
|
||||
@field(result_flags, flag.name) = switch (Arg) {
|
||||
[*:0]const u8 => mem.sliceTo(args[i], 0),
|
||||
[:0]const u8 => args[i],
|
||||
else => unreachable,
|
||||
};
|
||||
@field(result_flags, flag.name) = args[i];
|
||||
},
|
||||
}
|
||||
continue :outer;
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ fn bind(client: *wl.Client, control: *Control, version: u32, id: u32) void {
|
||||
client.postNoMemory();
|
||||
return;
|
||||
};
|
||||
control.args_map.putNoClobber(.{ .client = client, .id = id }, .{}) catch {
|
||||
control.args_map.putNoClobber(.{ .client = client, .id = id }, .empty) catch {
|
||||
control_v1.destroy();
|
||||
client.postNoMemory();
|
||||
return;
|
||||
|
||||
+3
-11
@@ -26,7 +26,7 @@ const wayland = @import("wayland");
|
||||
const wl = wayland.server.wl;
|
||||
const zwlr = wayland.server.zwlr;
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("c");
|
||||
const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
|
||||
@@ -158,7 +158,7 @@ focus_follows_cursor_target: ?*View = null,
|
||||
|
||||
/// Keeps track of the last known location of all touch points in layout coordinates.
|
||||
/// This information is necessary for proper touch dnd support if there are multiple touch points.
|
||||
touch_points: std.AutoHashMapUnmanaged(i32, LayoutPoint) = .{},
|
||||
touch_points: std.AutoHashMapUnmanaged(i32, LayoutPoint) = .empty,
|
||||
|
||||
axis: wl.Listener(*wlr.Pointer.event.Axis) = wl.Listener(*wlr.Pointer.event.Axis).init(handleAxis),
|
||||
frame: wl.Listener(*wlr.Cursor) = wl.Listener(*wlr.Cursor).init(handleFrame),
|
||||
@@ -1151,15 +1151,7 @@ pub fn updateState(cursor: *Cursor) void {
|
||||
.passthrough => {
|
||||
cursor.updateFocusFollowsCursorTarget();
|
||||
if (!cursor.hidden) {
|
||||
const now = posix.clock_gettime(.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
||||
// 2^32-1 milliseconds is ~50 days, which is a realistic uptime.
|
||||
// This means that we must wrap if the monotonic time is greater than
|
||||
// 2^32-1 milliseconds and hope that clients don't get too confused.
|
||||
const msec: u32 = @intCast(@rem(
|
||||
now.sec *% std.time.ms_per_s +% @divTrunc(now.nsec, std.time.ns_per_ms),
|
||||
math.maxInt(u32),
|
||||
));
|
||||
cursor.passthrough(msec);
|
||||
cursor.passthrough(util.msecTimestamp());
|
||||
}
|
||||
},
|
||||
// TODO: Leave down mode if the target surface is no longer visible.
|
||||
|
||||
@@ -25,7 +25,7 @@ const wlr = @import("wlroots");
|
||||
|
||||
const log = std.log.scoped(.input_config);
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("c");
|
||||
|
||||
const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
|
||||
@@ -24,7 +24,7 @@ const wl = @import("wayland").server.wl;
|
||||
|
||||
const globber = @import("globber");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("c");
|
||||
const server = &@import("main.zig").server;
|
||||
const util = @import("util.zig");
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ 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) = .empty,
|
||||
|
||||
devices: wl.list.Head(InputDevice, .link),
|
||||
seats: wl.list.Head(Seat, .link),
|
||||
|
||||
+3
-3
@@ -24,9 +24,9 @@ const PointerMapping = @import("PointerMapping.zig");
|
||||
const SwitchMapping = @import("SwitchMapping.zig");
|
||||
|
||||
name: [:0]const u8,
|
||||
mappings: std.ArrayListUnmanaged(Mapping) = .{},
|
||||
pointer_mappings: std.ArrayListUnmanaged(PointerMapping) = .{},
|
||||
switch_mappings: std.ArrayListUnmanaged(SwitchMapping) = .{},
|
||||
mappings: std.ArrayList(Mapping) = .empty,
|
||||
pointer_mappings: std.ArrayList(PointerMapping) = .empty,
|
||||
switch_mappings: std.ArrayList(SwitchMapping) = .empty,
|
||||
|
||||
pub fn deinit(mode: *Mode) void {
|
||||
util.gpa.free(mode.name);
|
||||
|
||||
+1
-1
@@ -537,7 +537,7 @@ fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
||||
error.CommitFailed => log.err("output commit failed for {s}", .{output.wlr_output.name}),
|
||||
};
|
||||
|
||||
var now = posix.clock_gettime(.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
||||
var now = util.timestamp();
|
||||
scene_output.sendFrameDone(&now);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ const View = @import("View.zig");
|
||||
const log = std.log.scoped(.river_status);
|
||||
|
||||
resources: wl.list.Head(zriver.OutputStatusV1, null),
|
||||
view_tags: std.ArrayListUnmanaged(u32) = .{},
|
||||
view_tags: std.ArrayList(u32) = .empty,
|
||||
focused_tags: u32 = 0,
|
||||
urgent_tags: u32 = 0,
|
||||
|
||||
|
||||
+1
-4
@@ -476,10 +476,7 @@ pub fn runCommand(seat: *Seat, args: []const [:0]const u8) void {
|
||||
return;
|
||||
};
|
||||
if (out) |s| {
|
||||
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 });
|
||||
};
|
||||
std.log.scoped(.command).info("mapped command output: {s}", .{s});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -26,7 +26,7 @@ const wayland = @import("wayland");
|
||||
const wl = wayland.server.wl;
|
||||
const wp = wayland.server.wp;
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const c = @import("c");
|
||||
const util = @import("util.zig");
|
||||
|
||||
const Config = @import("Config.zig");
|
||||
@@ -148,8 +148,8 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
|
||||
|
||||
server.* = .{
|
||||
.wl_server = wl_server,
|
||||
.sigint_source = try loop.addSignal(*wl.Server, posix.SIG.INT, terminate, wl_server),
|
||||
.sigterm_source = try loop.addSignal(*wl.Server, posix.SIG.TERM, terminate, wl_server),
|
||||
.sigint_source = try loop.addSignal(*wl.Server, @intFromEnum(posix.SIG.INT), terminate, wl_server),
|
||||
.sigterm_source = try loop.addSignal(*wl.Server, @intFromEnum(posix.SIG.TERM), terminate, wl_server),
|
||||
|
||||
.fixes = try wlr.Fixes.create(wl_server, 1),
|
||||
|
||||
|
||||
+1
-1
@@ -498,7 +498,7 @@ pub fn rootSurface(view: View) ?*wlr.Surface {
|
||||
pub fn sendFrameDone(view: View) void {
|
||||
assert(view.mapped and !view.destroying);
|
||||
|
||||
const now = posix.clock_gettime(.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
||||
const now = util.timestamp();
|
||||
view.rootSurface().?.sendFrameDone(&now);
|
||||
}
|
||||
|
||||
|
||||
@@ -314,6 +314,9 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||
const toplevel: *XdgToplevel = @fieldParentPtr("commit", listener);
|
||||
const view = toplevel.view;
|
||||
|
||||
// NB: the subsurface tree is never empty here
|
||||
view.image_capture_scene.tree.node.subsurfaceTreeSetClip(&toplevel.wlr_toplevel.base.geometry);
|
||||
|
||||
if (toplevel.wlr_toplevel.base.initial_commit) {
|
||||
_ = toplevel.wlr_toplevel.setWmCapabilities(.{ .fullscreen = true });
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <libinput.h>
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
// This file is part of river, a dynamic tiling wayland compositor.
|
||||
//
|
||||
// Copyright 2020 The River Developers
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// 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 const c = @cImport({
|
||||
@cDefine("_POSIX_C_SOURCE", "200809L");
|
||||
|
||||
@cInclude("stdlib.h");
|
||||
@cInclude("unistd.h");
|
||||
|
||||
@cInclude("linux/input-event-codes.h");
|
||||
@cInclude("libevdev/libevdev.h");
|
||||
|
||||
@cInclude("libinput.h");
|
||||
});
|
||||
@@ -124,6 +124,7 @@ pub const Error = error{
|
||||
ConflictingOptions,
|
||||
WriteFailed,
|
||||
OutOfMemory,
|
||||
Unexpected,
|
||||
Other,
|
||||
};
|
||||
|
||||
@@ -167,6 +168,7 @@ pub fn errToMsg(err: Error) [:0]const u8 {
|
||||
Error.CannotReadFile => "cannot read file",
|
||||
Error.CannotParseFile => "cannot parse file",
|
||||
Error.WriteFailed, Error.OutOfMemory => "out of memory",
|
||||
Error.Unexpected => "unexpected error",
|
||||
Error.Other => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn keyboardLayout(
|
||||
args: []const [:0]const u8,
|
||||
_: *?[]const u8,
|
||||
) Error!void {
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "rules", .kind = .arg },
|
||||
.{ .name = "model", .kind = .arg },
|
||||
.{ .name = "variant", .kind = .arg },
|
||||
@@ -69,13 +69,15 @@ pub fn keyboardLayoutFile(
|
||||
if (args.len < 2) return Error.NotEnoughArguments;
|
||||
if (args.len > 2) return Error.TooManyArguments;
|
||||
|
||||
const file = std.fs.cwd().openFile(args[1], .{}) catch return error.CannotReadFile;
|
||||
defer file.close();
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
const file = std.Io.Dir.cwd().openFile(io, args[1], .{}) catch return error.CannotReadFile;
|
||||
defer file.close(io);
|
||||
var reader = file.reader(io, &.{});
|
||||
|
||||
// 1 GiB is arbitrarily chosen as an exceedingly large but not infinite upper bound.
|
||||
const file_bytes = file.readToEndAlloc(util.gpa, 1024 * 1024 * 1024) catch |err| {
|
||||
const file_bytes = reader.interface.allocRemaining(util.gpa, .limited(1024 * 1024 * 1024)) catch |err| {
|
||||
switch (err) {
|
||||
error.FileTooBig, error.OutOfMemory => return error.OutOfMemory,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => return error.CannotReadFile,
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ const wlr = @import("wlroots");
|
||||
const xkb = @import("xkbcommon");
|
||||
const flags = @import("flags");
|
||||
|
||||
const c = @import("../c.zig").c;
|
||||
const c = @import("c");
|
||||
const server = &@import("../main.zig").server;
|
||||
const util = @import("../util.zig");
|
||||
|
||||
@@ -42,7 +42,7 @@ pub fn map(
|
||||
args: []const [:0]const u8,
|
||||
out: *?[]const u8,
|
||||
) Error!void {
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "release", .kind = .boolean },
|
||||
.{ .name = "repeat", .kind = .boolean },
|
||||
.{ .name = "layout", .kind = .arg },
|
||||
@@ -366,7 +366,7 @@ fn parseSwitchState(
|
||||
/// Example:
|
||||
/// unmap normal Mod4+Shift Return
|
||||
pub fn unmap(seat: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!void {
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "release", .kind = .boolean },
|
||||
}).parse(args[1..]) catch {
|
||||
return error.InvalidValue;
|
||||
|
||||
@@ -54,10 +54,10 @@ pub fn sendToOutput(
|
||||
_: *?[]const u8,
|
||||
) Error!void {
|
||||
if (args.len < 2) return Error.NotEnoughArguments;
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "current-tags", .kind = .boolean },
|
||||
}).parse(args[1..]) catch {
|
||||
return error.InvalidOption;
|
||||
return error.InvalidValue;
|
||||
};
|
||||
if (result.args.len < 1) return Error.NotEnoughArguments;
|
||||
if (result.args.len > 1) return Error.TooManyArguments;
|
||||
|
||||
@@ -49,7 +49,7 @@ const Action = enum {
|
||||
};
|
||||
|
||||
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "app-id", .kind = .arg },
|
||||
.{ .name = "title", .kind = .arg },
|
||||
}).parse(args[1..]) catch {
|
||||
@@ -177,7 +177,7 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
||||
}
|
||||
|
||||
pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "app-id", .kind = .arg },
|
||||
.{ .name = "title", .kind = .arg },
|
||||
}).parse(args[1..]) catch {
|
||||
@@ -251,7 +251,7 @@ fn apply_tearing_rules() void {
|
||||
}
|
||||
}
|
||||
|
||||
fn alignLeft(buf: []const u8, width: usize, writer: *std.io.Writer) Error!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);
|
||||
@@ -278,7 +278,7 @@ 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.io.Writer.Allocating.init(util.gpa);
|
||||
var buffer = std.Io.Writer.Allocating.init(util.gpa);
|
||||
defer buffer.deinit();
|
||||
const writer = &buffer.writer;
|
||||
|
||||
|
||||
+29
-10
@@ -15,9 +15,8 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const posix = std.posix;
|
||||
const c = std.c;
|
||||
|
||||
const c = @import("../c.zig").c;
|
||||
const util = @import("../util.zig");
|
||||
const process = @import("../process.zig");
|
||||
|
||||
@@ -35,26 +34,46 @@ pub fn spawn(
|
||||
|
||||
const child_args = [_:null]?[*:0]const u8{ "/bin/sh", "-c", args[1], null };
|
||||
|
||||
const pid = posix.fork() catch {
|
||||
out.* = try std.fmt.allocPrint(util.gpa, "fork/execve failed", .{});
|
||||
return Error.Other;
|
||||
const pid: c.pid_t = blk: {
|
||||
const rc = c.fork();
|
||||
if (c.errno(rc) != .SUCCESS) {
|
||||
out.* = try std.fmt.allocPrint(util.gpa, "fork/execve failed", .{});
|
||||
return Error.Other;
|
||||
}
|
||||
break :blk @intCast(rc);
|
||||
};
|
||||
|
||||
if (pid == 0) {
|
||||
process.cleanupChild();
|
||||
|
||||
const pid2 = posix.fork() catch c._exit(1);
|
||||
const pid2: c.pid_t = blk: {
|
||||
const rc = c.fork();
|
||||
if (c.errno(rc) != .SUCCESS) {
|
||||
c._exit(1);
|
||||
}
|
||||
break :blk @intCast(rc);
|
||||
};
|
||||
|
||||
if (pid2 == 0) {
|
||||
posix.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
|
||||
_ = c.execve("/bin/sh", &child_args, c.environ);
|
||||
c._exit(1); // only reachable if execve fails
|
||||
}
|
||||
|
||||
c._exit(0);
|
||||
}
|
||||
|
||||
// Wait the intermediate child.
|
||||
const ret = posix.waitpid(pid, 0);
|
||||
if (!posix.W.IFEXITED(ret.status) or
|
||||
(posix.W.IFEXITED(ret.status) and posix.W.EXITSTATUS(ret.status) != 0))
|
||||
const status: u32 = while (true) {
|
||||
var status: c_int = 0;
|
||||
switch (c.errno(c.waitpid(pid, &status, 0))) {
|
||||
.SUCCESS => break @bitCast(status),
|
||||
.INTR => continue,
|
||||
else => return Error.Unexpected, // should never happen, but don't trust the kernel
|
||||
}
|
||||
};
|
||||
|
||||
if (!c.W.IFEXITED(status) or
|
||||
(c.W.IFEXITED(status) and c.W.EXITSTATUS(status) != 0))
|
||||
{
|
||||
out.* = try std.fmt.allocPrint(util.gpa, "fork/execve failed", .{});
|
||||
return Error.Other;
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn focusView(
|
||||
args: []const [:0]const u8,
|
||||
_: *?[]const u8,
|
||||
) Error!void {
|
||||
const result = flags.parser([:0]const u8, &.{
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "skip-floating", .kind = .boolean },
|
||||
}).parse(args[1..]) catch {
|
||||
return error.InvalidValue;
|
||||
|
||||
+57
-32
@@ -16,15 +16,19 @@
|
||||
|
||||
const build_options = @import("build_options");
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Io = std.Io;
|
||||
const fs = std.fs;
|
||||
const log = std.log;
|
||||
const mem = std.mem;
|
||||
const posix = std.posix;
|
||||
const exit = std.process.exit;
|
||||
const fatal = std.process.fatal;
|
||||
const c = std.c;
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const wlr = @import("wlroots");
|
||||
const flags = @import("flags");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const util = @import("util.zig");
|
||||
const process = @import("process.zig");
|
||||
|
||||
@@ -43,30 +47,47 @@ const usage: []const u8 =
|
||||
|
||||
pub var server: Server = undefined;
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
const result = flags.parser([*:0]const u8, &.{
|
||||
pub fn main(init: std.process.Init.Minimal) anyerror!void {
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
|
||||
var stdout_buffer: [64]u8 = undefined;
|
||||
var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
|
||||
const stdout = &stdout_writer.interface;
|
||||
|
||||
var stderr_buffer: [64]u8 = undefined;
|
||||
var stderr_writer = Io.File.stderr().writer(io, &stderr_buffer);
|
||||
const stderr = &stderr_writer.interface;
|
||||
|
||||
const args = try init.args.toSlice(util.gpa);
|
||||
defer util.gpa.free(args);
|
||||
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "h", .kind = .boolean },
|
||||
.{ .name = "version", .kind = .boolean },
|
||||
.{ .name = "c", .kind = .arg },
|
||||
.{ .name = "log-level", .kind = .arg },
|
||||
.{ .name = "no-xwayland", .kind = .boolean },
|
||||
}).parse(std.os.argv[1..]) catch {
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
}).parse(args[1..]) catch {
|
||||
try stderr.writeAll(usage);
|
||||
try stderr.flush();
|
||||
exit(1);
|
||||
};
|
||||
if (result.flags.h) {
|
||||
try fs.File.stdout().writeAll(usage);
|
||||
posix.exit(0);
|
||||
try stdout.writeAll(usage);
|
||||
try stdout.flush();
|
||||
exit(0);
|
||||
}
|
||||
if (result.args.len != 0) {
|
||||
log.err("unknown option '{s}'", .{result.args[0]});
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
try stderr.writeAll(usage);
|
||||
try stderr.flush();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (result.flags.version) {
|
||||
try fs.File.stdout().writeAll(build_options.version ++ "\n");
|
||||
posix.exit(0);
|
||||
try stdout.writeAll(build_options.version ++ "\n");
|
||||
try stdout.flush();
|
||||
exit(0);
|
||||
}
|
||||
if (result.flags.@"log-level") |level| {
|
||||
if (mem.eql(u8, level, "error")) {
|
||||
@@ -79,8 +100,9 @@ pub fn main() anyerror!void {
|
||||
runtime_log_level = .debug;
|
||||
} else {
|
||||
log.err("invalid log level '{s}'", .{level});
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
try stderr.writeAll(usage);
|
||||
try stderr.flush();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
const runtime_xwayland = !result.flags.@"no-xwayland";
|
||||
@@ -88,7 +110,7 @@ pub fn main() anyerror!void {
|
||||
if (result.flags.c) |command| {
|
||||
break :blk try util.gpa.dupeZ(u8, command);
|
||||
} else {
|
||||
break :blk try defaultInitPath();
|
||||
break :blk try defaultInitPath(io, init.environ);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -120,10 +142,20 @@ pub fn main() anyerror!void {
|
||||
const child_pgid = if (startup_command) |cmd| blk: {
|
||||
log.info("running init executable '{s}'", .{cmd});
|
||||
const child_args = [_:null]?[*:0]const u8{ "/bin/sh", "-c", cmd, null };
|
||||
const pid = try posix.fork();
|
||||
|
||||
const pid: c.pid_t = pid: {
|
||||
const rc = c.fork();
|
||||
switch (c.errno(rc)) {
|
||||
.SUCCESS => {},
|
||||
else => |err| fatal("failed to start init process: {}", .{err}),
|
||||
}
|
||||
break :pid @intCast(rc);
|
||||
};
|
||||
|
||||
if (pid == 0) {
|
||||
process.cleanupChild();
|
||||
posix.execveZ("/bin/sh", &child_args, std.c.environ) catch c._exit(1);
|
||||
_ = c.execve("/bin/sh", &child_args, c.environ);
|
||||
c._exit(1); // only reachable if execve fails
|
||||
}
|
||||
util.gpa.free(cmd);
|
||||
// Since the child has called setsid, the pid is the pgid
|
||||
@@ -140,22 +172,21 @@ pub fn main() anyerror!void {
|
||||
log.info("shutting down", .{});
|
||||
}
|
||||
|
||||
fn defaultInitPath() !?[:0]const u8 {
|
||||
fn defaultInitPath(io: Io, environ: std.process.Environ) !?[:0]const u8 {
|
||||
const path = blk: {
|
||||
if (posix.getenv("XDG_CONFIG_HOME")) |xdg_config_home| {
|
||||
if (environ.getPosix("XDG_CONFIG_HOME")) |xdg_config_home| {
|
||||
break :blk try fs.path.joinZ(util.gpa, &[_][]const u8{ xdg_config_home, "river/init" });
|
||||
} else if (posix.getenv("HOME")) |home| {
|
||||
} else if (environ.getPosix("HOME")) |home| {
|
||||
break :blk try fs.path.joinZ(util.gpa, &[_][]const u8{ home, ".config/river/init" });
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
posix.accessZ(path, posix.X_OK) catch |err| {
|
||||
Io.Dir.cwd().access(io, path, .{ .execute = true }) catch |err| {
|
||||
if (err == error.PermissionDenied) {
|
||||
if (posix.accessZ(path, posix.R_OK)) {
|
||||
log.err("failed to run init executable {s}: the file is not executable", .{path});
|
||||
posix.exit(1);
|
||||
if (Io.Dir.cwd().access(io, path, .{})) {
|
||||
fatal("failed to run init executable {s}: the file is not executable", .{path});
|
||||
} else |_| {}
|
||||
}
|
||||
log.err("failed to run init executable {s}: {s}", .{ path, @errorName(err) });
|
||||
@@ -186,13 +217,7 @@ pub fn logFn(
|
||||
) void {
|
||||
if (@intFromEnum(level) > @intFromEnum(runtime_log_level)) return;
|
||||
|
||||
const scope_prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
||||
|
||||
var buffer: [256]u8 = undefined;
|
||||
const stderr = std.debug.lockStderrWriter(&buffer);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
|
||||
stderr.print(level.asText() ++ scope_prefix ++ format ++ "\n", args) catch {};
|
||||
std.log.defaultLog(level, scope, format, args);
|
||||
}
|
||||
|
||||
/// See wlroots_log_wrapper.c
|
||||
|
||||
+1
-3
@@ -17,8 +17,6 @@
|
||||
const std = @import("std");
|
||||
const posix = std.posix;
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
var original_rlimit: ?posix.rlimit = null;
|
||||
|
||||
pub fn setup() void {
|
||||
@@ -60,7 +58,7 @@ pub fn setup() void {
|
||||
}
|
||||
|
||||
pub fn cleanupChild() void {
|
||||
if (c.setsid() < 0) unreachable;
|
||||
if (std.c.setsid() < 0) unreachable;
|
||||
if (posix.system.sigprocmask(posix.SIG.SETMASK, &posix.sigemptyset(), null) < 0) unreachable;
|
||||
|
||||
const sig_dfl = posix.Sigaction{
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ pub fn RuleList(comptime T: type) type {
|
||||
|
||||
/// Ordered from most specific to most general.
|
||||
/// Ordered first by app-id generality then by title generality.
|
||||
rules: std.ArrayListUnmanaged(Rule) = .{},
|
||||
rules: std.ArrayList(Rule) = .empty,
|
||||
|
||||
pub fn deinit(list: *List) void {
|
||||
for (list.rules.items) |rule| {
|
||||
|
||||
@@ -18,3 +18,22 @@ const std = @import("std");
|
||||
|
||||
/// The global general-purpose allocator used throughout river's code
|
||||
pub const gpa = std.heap.c_allocator;
|
||||
|
||||
pub fn timestamp() std.c.timespec {
|
||||
var timespec: std.c.timespec = undefined;
|
||||
switch (std.c.errno(std.c.clock_gettime(std.c.CLOCK.MONOTONIC, ×pec))) {
|
||||
.SUCCESS => return timespec,
|
||||
else => @panic("CLOCK_MONOTONIC not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn msecTimestamp() u32 {
|
||||
const now = timestamp();
|
||||
// 2^32-1 milliseconds is ~50 days, which is a realistic uptime.
|
||||
// This means that we must wrap if the monotonic time is greater than
|
||||
// 2^32-1 milliseconds and hope that clients don't get too confused.
|
||||
return @intCast(@rem(
|
||||
now.sec *% std.time.ms_per_s +% @divTrunc(now.nsec, std.time.ns_per_ms),
|
||||
std.math.maxInt(u32),
|
||||
));
|
||||
}
|
||||
|
||||
+35
-22
@@ -17,8 +17,11 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const fs = std.fs;
|
||||
const Io = std.Io;
|
||||
const posix = std.posix;
|
||||
const assert = std.debug.assert;
|
||||
const process = std.process;
|
||||
const fatal = process.fatal;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const wayland = @import("wayland");
|
||||
@@ -38,6 +41,15 @@ const usage =
|
||||
\\
|
||||
;
|
||||
|
||||
const io = Io.Threaded.global_single_threaded.io();
|
||||
var stdout_buffer: [64]u8 = undefined;
|
||||
var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
|
||||
const stdout = &stdout_writer.interface;
|
||||
|
||||
var stderr_buffer: [64]u8 = undefined;
|
||||
var stderr_writer = Io.File.stderr().writer(io, &stderr_buffer);
|
||||
const stderr = &stderr_writer.interface;
|
||||
|
||||
const gpa = std.heap.c_allocator;
|
||||
|
||||
pub const Globals = struct {
|
||||
@@ -45,8 +57,8 @@ pub const Globals = struct {
|
||||
seat: ?*wl.Seat = null,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
_main() catch |err| {
|
||||
pub fn main(init: std.process.Init.Minimal) !void {
|
||||
_main(init) catch |err| {
|
||||
switch (err) {
|
||||
error.RiverControlNotAdvertised => fatal(
|
||||
\\The Wayland server does not support river-control-unstable-v1.
|
||||
@@ -57,7 +69,7 @@ pub fn main() !void {
|
||||
, .{}),
|
||||
error.ConnectFailed => {
|
||||
std.log.err("Unable to connect to the Wayland server.", .{});
|
||||
if (posix.getenvZ("WAYLAND_DISPLAY") == null) {
|
||||
if (init.environ.getPosix("WAYLAND_DISPLAY") == null) {
|
||||
fatal("WAYLAND_DISPLAY is not set.", .{});
|
||||
} else {
|
||||
fatal("Does WAYLAND_DISPLAY contain the socket name of a running server?", .{});
|
||||
@@ -68,21 +80,27 @@ pub fn main() !void {
|
||||
};
|
||||
}
|
||||
|
||||
fn _main() !void {
|
||||
const result = flags.parser([*:0]const u8, &.{
|
||||
fn _main(init: std.process.Init.Minimal) !void {
|
||||
const args = try init.args.toSlice(gpa);
|
||||
defer gpa.free(args);
|
||||
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "h", .kind = .boolean },
|
||||
.{ .name = "version", .kind = .boolean },
|
||||
}).parse(std.os.argv[1..]) catch {
|
||||
try fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
}).parse(args[1..]) catch {
|
||||
try stderr.writeAll(usage);
|
||||
try stderr.flush();
|
||||
process.exit(1);
|
||||
};
|
||||
if (result.flags.h) {
|
||||
try fs.File.stdout().writeAll(usage);
|
||||
posix.exit(0);
|
||||
try stdout.writeAll(usage);
|
||||
try stdout.flush();
|
||||
process.exit(0);
|
||||
}
|
||||
if (result.flags.version) {
|
||||
try fs.File.stdout().writeAll(@import("build_options").version ++ "\n");
|
||||
posix.exit(0);
|
||||
try stdout.writeAll(@import("build_options").version ++ "\n");
|
||||
try stdout.flush();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const display = try wl.Display.connect(null);
|
||||
@@ -125,24 +143,19 @@ fn callbackListener(_: *zriver.CommandCallbackV1, event: zriver.CommandCallbackV
|
||||
switch (event) {
|
||||
.success => |success| {
|
||||
if (mem.len(success.output) > 0) {
|
||||
var stdout = fs.File.stdout().writer(&.{});
|
||||
stdout.interface.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
|
||||
stdout.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
|
||||
}
|
||||
posix.exit(0);
|
||||
process.exit(0);
|
||||
},
|
||||
.failure => |failure| {
|
||||
// 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", .{});
|
||||
fs.File.stderr().writeAll(usage) catch {};
|
||||
posix.exit(1);
|
||||
stderr.writeAll(usage) catch {};
|
||||
stderr.flush() catch {};
|
||||
process.exit(1);
|
||||
}
|
||||
fatal("{s}", .{failure.failure_message});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.err(format, args);
|
||||
posix.exit(1);
|
||||
}
|
||||
|
||||
+29
-18
@@ -40,6 +40,8 @@ const fmt = std.fmt;
|
||||
const mem = std.mem;
|
||||
const math = std.math;
|
||||
const posix = std.posix;
|
||||
const process = std.process;
|
||||
const fatal = std.process.fatal;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const wayland = @import("wayland");
|
||||
@@ -307,8 +309,20 @@ const Output = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
const result = flags.parser([*:0]const u8, &[_]flags.Flag{
|
||||
pub fn main(init: std.process.Init.Minimal) !void {
|
||||
const args = try init.args.toSlice(gpa);
|
||||
defer gpa.free(args);
|
||||
|
||||
const io = std.Io.Threaded.global_single_threaded.io();
|
||||
var stdout_buffer: [64]u8 = undefined;
|
||||
var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer);
|
||||
const stdout = &stdout_writer.interface;
|
||||
|
||||
var stderr_buffer: [64]u8 = undefined;
|
||||
var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer);
|
||||
const stderr = &stderr_writer.interface;
|
||||
|
||||
const result = flags.parser(&.{
|
||||
.{ .name = "h", .kind = .boolean },
|
||||
.{ .name = "version", .kind = .boolean },
|
||||
.{ .name = "view-padding", .kind = .arg },
|
||||
@@ -316,19 +330,22 @@ pub fn main() !void {
|
||||
.{ .name = "main-location", .kind = .arg },
|
||||
.{ .name = "main-count", .kind = .arg },
|
||||
.{ .name = "main-ratio", .kind = .arg },
|
||||
}).parse(std.os.argv[1..]) catch {
|
||||
try std.fs.File.stderr().writeAll(usage);
|
||||
posix.exit(1);
|
||||
}).parse(args[1..]) catch {
|
||||
try stderr.writeAll(usage);
|
||||
try stderr.flush();
|
||||
process.exit(1);
|
||||
};
|
||||
if (result.flags.h) {
|
||||
try std.fs.File.stdout().writeAll(usage);
|
||||
posix.exit(0);
|
||||
try stdout.writeAll(usage);
|
||||
try stdout.flush();
|
||||
process.exit(0);
|
||||
}
|
||||
if (result.args.len != 0) fatalPrintUsage("unknown option '{s}'", .{result.args[0]});
|
||||
|
||||
if (result.flags.version) {
|
||||
try std.fs.File.stdout().writeAll(@import("build_options").version ++ "\n");
|
||||
posix.exit(0);
|
||||
try stdout.writeAll(@import("build_options").version ++ "\n");
|
||||
try stdout.flush();
|
||||
process.exit(0);
|
||||
}
|
||||
if (result.flags.@"view-padding") |raw| {
|
||||
view_padding = fmt.parseUnsigned(u31, raw, 10) catch
|
||||
@@ -356,8 +373,7 @@ pub fn main() !void {
|
||||
}
|
||||
|
||||
const display = wl.Display.connect(null) catch {
|
||||
std.debug.print("Unable to connect to Wayland server.\n", .{});
|
||||
posix.exit(1);
|
||||
fatal("Unable to connect to Wayland server.\n", .{});
|
||||
};
|
||||
defer display.disconnect();
|
||||
|
||||
@@ -407,15 +423,10 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *
|
||||
}
|
||||
}
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.err(format, args);
|
||||
posix.exit(1);
|
||||
}
|
||||
|
||||
fn fatalPrintUsage(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.err(format, args);
|
||||
std.fs.File.stderr().writeAll(usage) catch {};
|
||||
posix.exit(1);
|
||||
std.debug.print(usage, .{});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
fn saturatingCast(comptime T: type, x: anytype) T {
|
||||
|
||||
Reference in New Issue
Block a user