Compare commits
46 Commits
main
...
dbe2cb72f8
Author | SHA1 | Date | |
---|---|---|---|
dbe2cb72f8
|
|||
2061ae2c4c
|
|||
fd55f51ba1 | |||
26f599b56b | |||
fbb9cc0f76 | |||
55974987b6 | |||
f82b2f5816 | |||
066baa5753 | |||
db7de8151c | |||
f5d37f9b4d | |||
93863b132e | |||
85a1673a9e | |||
2cc1d1cef3 | |||
f27bbf03f1 | |||
99ef96a389 | |||
ccd676e5a9 | |||
a7411ef2a6 | |||
1f5bf1d972 | |||
14a5609dae
|
|||
4232d6b99f | |||
ec16f1c375 | |||
a80e0f7322 | |||
0997fde28e | |||
ae7f4b8fcb | |||
2e09b66963 | |||
ffb24267b8
|
|||
de3035563c | |||
28a14c6794 | |||
e2f3cd8252 | |||
f9201ae7cd | |||
16c938111d | |||
68dda1a48a
|
|||
fac47ffb5d
|
|||
8da69699e9 | |||
c5b1d1de4e | |||
4d44ca6d5d | |||
7fdba05b82 | |||
958f8798b6 | |||
045ee7bd25 | |||
033cad47bf | |||
680cb8ef69 | |||
5d1fc034bc | |||
c75d32c88b | |||
b35a40b9df | |||
ba6023e38a | |||
74baf7225a |
@ -14,7 +14,6 @@ packages:
|
|||||||
- xcb-util-wm-dev
|
- xcb-util-wm-dev
|
||||||
- pixman-dev
|
- pixman-dev
|
||||||
- libevdev-dev
|
- libevdev-dev
|
||||||
- wayland-dev
|
|
||||||
- wayland-protocols
|
- wayland-protocols
|
||||||
- xwayland-dev
|
- xwayland-dev
|
||||||
- meson
|
- meson
|
||||||
@ -24,11 +23,18 @@ packages:
|
|||||||
- xz
|
- xz
|
||||||
sources:
|
sources:
|
||||||
- https://codeberg.org/river/river
|
- https://codeberg.org/river/river
|
||||||
|
- https://gitlab.freedesktop.org/wayland/wayland.git
|
||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||||
tasks:
|
tasks:
|
||||||
- install_deps: |
|
- install_deps: |
|
||||||
|
cd wayland
|
||||||
|
git checkout 1.23.0
|
||||||
|
meson setup build -Ddocumentation=false -Dtests=false --prefix /usr
|
||||||
|
sudo ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
cd wlroots
|
cd wlroots
|
||||||
git checkout 0.19.0
|
git checkout 0.18.0
|
||||||
meson setup build --auto-features=enabled -Drenderers=gles2 \
|
meson setup build --auto-features=enabled -Drenderers=gles2 \
|
||||||
-Dcolor-management=disabled -Dlibliftoff=disabled \
|
-Dcolor-management=disabled -Dlibliftoff=disabled \
|
||||||
-Dexamples=false -Dwerror=false -Db_ndebug=false \
|
-Dexamples=false -Dwerror=false -Db_ndebug=false \
|
||||||
@ -37,10 +43,10 @@ tasks:
|
|||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# Eat Github's resources rather than the Zig Software Foundation's resources!
|
# 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
|
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.13.0/zig-linux-x86_64-0.13.0.tar.xz
|
||||||
tar xf zig-linux-x86_64-0.14.0.tar.xz
|
tar xf zig-linux-x86_64-0.13.0.tar.xz
|
||||||
sudo mv zig-linux-x86_64-0.14.0/zig /usr/bin/
|
sudo mv zig-linux-x86_64-0.13.0/zig /usr/bin/
|
||||||
sudo mv zig-linux-x86_64-0.14.0/lib /usr/lib/zig
|
sudo mv zig-linux-x86_64-0.13.0/lib /usr/lib/zig
|
||||||
- build: |
|
- build: |
|
||||||
cd river
|
cd river
|
||||||
zig build --summary all
|
zig build --summary all
|
||||||
@ -53,3 +59,4 @@ tasks:
|
|||||||
zig fmt --check riverctl/
|
zig fmt --check riverctl/
|
||||||
zig fmt --check rivertile/
|
zig fmt --check rivertile/
|
||||||
zig fmt --check build.zig
|
zig fmt --check build.zig
|
||||||
|
zig fmt --check build.zig.zon
|
||||||
|
@ -21,11 +21,18 @@ packages:
|
|||||||
- xz
|
- xz
|
||||||
sources:
|
sources:
|
||||||
- https://codeberg.org/river/river
|
- https://codeberg.org/river/river
|
||||||
|
- https://gitlab.freedesktop.org/wayland/wayland.git
|
||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||||
tasks:
|
tasks:
|
||||||
- install_deps: |
|
- install_deps: |
|
||||||
|
cd wayland
|
||||||
|
git checkout 1.23.0
|
||||||
|
meson setup build -Ddocumentation=false -Dtests=false --prefix /usr
|
||||||
|
sudo ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
cd wlroots
|
cd wlroots
|
||||||
git checkout 0.19.0
|
git checkout 0.18.0
|
||||||
meson setup build --auto-features=enabled -Drenderers=gles2 \
|
meson setup build --auto-features=enabled -Drenderers=gles2 \
|
||||||
-Dcolor-management=disabled -Dlibliftoff=disabled \
|
-Dcolor-management=disabled -Dlibliftoff=disabled \
|
||||||
-Dexamples=false -Dwerror=false -Db_ndebug=false \
|
-Dexamples=false -Dwerror=false -Db_ndebug=false \
|
||||||
@ -34,10 +41,10 @@ tasks:
|
|||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# Eat Github's resources rather than the Zig Software Foundation's resources!
|
# 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
|
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.13.0/zig-linux-x86_64-0.13.0.tar.xz
|
||||||
tar xf zig-linux-x86_64-0.14.0.tar.xz
|
tar xf zig-linux-x86_64-0.13.0.tar.xz
|
||||||
sudo mv zig-linux-x86_64-0.14.0/zig /usr/bin/
|
sudo mv zig-linux-x86_64-0.13.0/zig /usr/bin/
|
||||||
sudo mv zig-linux-x86_64-0.14.0/lib /usr/lib/zig
|
sudo mv zig-linux-x86_64-0.13.0/lib /usr/lib/zig
|
||||||
- build: |
|
- build: |
|
||||||
cd river
|
cd river
|
||||||
zig build --summary all
|
zig build --summary all
|
||||||
@ -50,3 +57,4 @@ tasks:
|
|||||||
zig fmt --check riverctl/
|
zig fmt --check riverctl/
|
||||||
zig fmt --check rivertile/
|
zig fmt --check rivertile/
|
||||||
zig fmt --check build.zig
|
zig fmt --check build.zig
|
||||||
|
zig fmt --check build.zig.zon
|
||||||
|
@ -7,7 +7,6 @@ packages:
|
|||||||
- devel/meson
|
- devel/meson
|
||||||
- devel/pkgconf
|
- devel/pkgconf
|
||||||
- graphics/mesa-libs
|
- graphics/mesa-libs
|
||||||
- graphics/wayland
|
|
||||||
- graphics/wayland-protocols
|
- graphics/wayland-protocols
|
||||||
- misc/hwdata
|
- misc/hwdata
|
||||||
- x11/libX11
|
- x11/libX11
|
||||||
@ -27,13 +26,19 @@ packages:
|
|||||||
- wget
|
- wget
|
||||||
sources:
|
sources:
|
||||||
- https://codeberg.org/river/river
|
- https://codeberg.org/river/river
|
||||||
|
- https://gitlab.freedesktop.org/wayland/wayland.git
|
||||||
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
- https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||||
tasks:
|
tasks:
|
||||||
- install_deps: |
|
- install_deps: |
|
||||||
|
cd wayland
|
||||||
|
git checkout 1.23.0
|
||||||
|
meson setup build -Ddocumentation=false -Dtests=false --prefix /usr
|
||||||
|
sudo ninja -C build install
|
||||||
|
cd ..
|
||||||
|
|
||||||
cd wlroots
|
cd wlroots
|
||||||
git checkout 0.19.0
|
git checkout 0.18.0
|
||||||
meson setup build --auto-features=enabled -Drenderers=gles2 \
|
meson setup build --auto-features=enabled -Drenderers=gles2 \
|
||||||
-Dallocators=gbm \
|
|
||||||
-Dcolor-management=disabled -Dlibliftoff=disabled \
|
-Dcolor-management=disabled -Dlibliftoff=disabled \
|
||||||
-Dexamples=false -Dwerror=false -Db_ndebug=false \
|
-Dexamples=false -Dwerror=false -Db_ndebug=false \
|
||||||
-Dxcb-errors=disabled --prefix /usr
|
-Dxcb-errors=disabled --prefix /usr
|
||||||
@ -41,10 +46,10 @@ tasks:
|
|||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
# Eat Github's resources rather than the Zig Software Foundation's resources!
|
# 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
|
wget -nv https://github.com/ifreund/zig-tarball-mirror/releases/download/0.13.0/zig-freebsd-x86_64-0.13.0.tar.xz
|
||||||
tar xf zig-freebsd-x86_64-0.14.0-unofficial.tar.xz
|
tar xf zig-freebsd-x86_64-0.13.0.tar.xz
|
||||||
sudo mv zig-freebsd-x86_64-0.14.0-unofficial/zig /usr/bin/
|
sudo mv zig-freebsd-x86_64-0.13.0/zig /usr/bin/
|
||||||
sudo mv zig-freebsd-x86_64-0.14.0-unofficial/lib /usr/lib/zig
|
sudo mv zig-freebsd-x86_64-0.13.0/lib /usr/lib/zig
|
||||||
- build: |
|
- build: |
|
||||||
cd river
|
cd river
|
||||||
zig build --summary all
|
zig build --summary all
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
.zig-cache/
|
.zig-cache/
|
||||||
|
zig-cache/
|
||||||
zig-out/
|
zig-out/
|
||||||
|
deps/
|
||||||
|
@ -57,10 +57,10 @@ To compile river first ensure that you have the following dependencies
|
|||||||
installed. The "development" versions are required if applicable to your
|
installed. The "development" versions are required if applicable to your
|
||||||
distribution.
|
distribution.
|
||||||
|
|
||||||
- [zig](https://ziglang.org/download/) 0.14
|
- [zig](https://ziglang.org/download/) 0.13
|
||||||
- wayland
|
- wayland
|
||||||
- wayland-protocols
|
- wayland-protocols
|
||||||
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.19
|
- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.18
|
||||||
- xkbcommon
|
- xkbcommon
|
||||||
- libevdev
|
- libevdev
|
||||||
- pixman
|
- pixman
|
||||||
|
65
build.zig
65
build.zig
@ -4,7 +4,13 @@ const Build = std.Build;
|
|||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
const Scanner = @import("wayland").Scanner;
|
const Scanner = @import("zig-wayland").Scanner;
|
||||||
|
|
||||||
|
/// While a river release is in development, this string should contain the version in development
|
||||||
|
/// with the "-dev" suffix.
|
||||||
|
/// 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.
|
||||||
|
const version = "0.4.0-dev";
|
||||||
|
|
||||||
pub fn build(b: *Build) !void {
|
pub fn build(b: *Build) !void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
@ -65,7 +71,7 @@ pub fn build(b: *Build) !void {
|
|||||||
.Inherit,
|
.Inherit,
|
||||||
) catch break :blk version;
|
) catch break :blk version;
|
||||||
|
|
||||||
var it = mem.splitScalar(u8, mem.trim(u8, git_describe_long, &std.ascii.whitespace), '-');
|
var it = mem.split(u8, mem.trim(u8, git_describe_long, &std.ascii.whitespace), "-");
|
||||||
_ = it.next().?; // previous tag
|
_ = it.next().?; // previous tag
|
||||||
const commit_count = it.next().?;
|
const commit_count = it.next().?;
|
||||||
const commit_hash = it.next().?;
|
const commit_hash = it.next().?;
|
||||||
@ -94,11 +100,11 @@ pub fn build(b: *Build) !void {
|
|||||||
scanner.addSystemProtocol("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml");
|
scanner.addSystemProtocol("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml");
|
||||||
scanner.addSystemProtocol("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml");
|
scanner.addSystemProtocol("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml");
|
||||||
|
|
||||||
scanner.addCustomProtocol(b.path("protocol/river-control-unstable-v1.xml"));
|
scanner.addCustomProtocol("protocol/river-control-unstable-v1.xml");
|
||||||
scanner.addCustomProtocol(b.path("protocol/river-status-unstable-v1.xml"));
|
scanner.addCustomProtocol("protocol/river-status-unstable-v1.xml");
|
||||||
scanner.addCustomProtocol(b.path("protocol/river-layout-v3.xml"));
|
scanner.addCustomProtocol("protocol/river-layout-v3.xml");
|
||||||
scanner.addCustomProtocol(b.path("protocol/wlr-layer-shell-unstable-v1.xml"));
|
scanner.addCustomProtocol("protocol/wlr-layer-shell-unstable-v1.xml");
|
||||||
scanner.addCustomProtocol(b.path("protocol/wlr-output-power-management-unstable-v1.xml"));
|
scanner.addCustomProtocol("protocol/wlr-output-power-management-unstable-v1.xml");
|
||||||
|
|
||||||
// Some of these versions may be out of date with what wlroots implements.
|
// Some of these versions may be out of date with what wlroots implements.
|
||||||
// This is not a problem in practice though as long as river successfully compiles.
|
// This is not a problem in practice though as long as river successfully compiles.
|
||||||
@ -130,10 +136,10 @@ pub fn build(b: *Build) !void {
|
|||||||
|
|
||||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||||
|
|
||||||
const xkbcommon = b.dependency("xkbcommon", .{}).module("xkbcommon");
|
const xkbcommon = b.dependency("zig-xkbcommon", .{}).module("xkbcommon");
|
||||||
const pixman = b.dependency("pixman", .{}).module("pixman");
|
const pixman = b.dependency("zig-pixman", .{}).module("pixman");
|
||||||
|
|
||||||
const wlroots = b.dependency("wlroots", .{}).module("wlroots");
|
const wlroots = b.dependency("zig-wlroots", .{}).module("wlroots");
|
||||||
wlroots.addImport("wayland", wayland);
|
wlroots.addImport("wayland", wayland);
|
||||||
wlroots.addImport("xkbcommon", xkbcommon);
|
wlroots.addImport("xkbcommon", xkbcommon);
|
||||||
wlroots.addImport("pixman", pixman);
|
wlroots.addImport("pixman", pixman);
|
||||||
@ -142,7 +148,7 @@ pub fn build(b: *Build) !void {
|
|||||||
// exposed to the wlroots module for @cImport() to work. This seems to be
|
// exposed to the wlroots module for @cImport() to work. This seems to be
|
||||||
// the best way to do so with the current std.Build API.
|
// the best way to do so with the current std.Build API.
|
||||||
wlroots.resolved_target = target;
|
wlroots.resolved_target = target;
|
||||||
wlroots.linkSystemLibrary("wlroots-0.19", .{});
|
wlroots.linkSystemLibrary("wlroots-0.18", .{});
|
||||||
|
|
||||||
const flags = b.createModule(.{ .root_source_file = b.path("common/flags.zig") });
|
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 globber = b.createModule(.{ .root_source_file = b.path("common/globber.zig") });
|
||||||
@ -163,7 +169,7 @@ pub fn build(b: *Build) !void {
|
|||||||
river.linkSystemLibrary("libevdev");
|
river.linkSystemLibrary("libevdev");
|
||||||
river.linkSystemLibrary("libinput");
|
river.linkSystemLibrary("libinput");
|
||||||
river.linkSystemLibrary("wayland-server");
|
river.linkSystemLibrary("wayland-server");
|
||||||
river.linkSystemLibrary("wlroots-0.19");
|
river.linkSystemLibrary("wlroots-0.18");
|
||||||
river.linkSystemLibrary("xkbcommon");
|
river.linkSystemLibrary("xkbcommon");
|
||||||
river.linkSystemLibrary("pixman-1");
|
river.linkSystemLibrary("pixman-1");
|
||||||
|
|
||||||
@ -179,6 +185,9 @@ pub fn build(b: *Build) !void {
|
|||||||
.flags = &.{ "-std=c99", "-O2" },
|
.flags = &.{ "-std=c99", "-O2" },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: remove when zig issue #131 is implemented
|
||||||
|
scanner.addCSource(river);
|
||||||
|
|
||||||
river.pie = pie;
|
river.pie = pie;
|
||||||
river.root_module.omit_frame_pointer = omit_frame_pointer;
|
river.root_module.omit_frame_pointer = omit_frame_pointer;
|
||||||
|
|
||||||
@ -202,6 +211,8 @@ pub fn build(b: *Build) !void {
|
|||||||
riverctl.linkLibC();
|
riverctl.linkLibC();
|
||||||
riverctl.linkSystemLibrary("wayland-client");
|
riverctl.linkSystemLibrary("wayland-client");
|
||||||
|
|
||||||
|
scanner.addCSource(riverctl);
|
||||||
|
|
||||||
riverctl.pie = pie;
|
riverctl.pie = pie;
|
||||||
riverctl.root_module.omit_frame_pointer = omit_frame_pointer;
|
riverctl.root_module.omit_frame_pointer = omit_frame_pointer;
|
||||||
|
|
||||||
@ -225,6 +236,8 @@ pub fn build(b: *Build) !void {
|
|||||||
rivertile.linkLibC();
|
rivertile.linkLibC();
|
||||||
rivertile.linkSystemLibrary("wayland-client");
|
rivertile.linkSystemLibrary("wayland-client");
|
||||||
|
|
||||||
|
scanner.addCSource(rivertile);
|
||||||
|
|
||||||
rivertile.pie = pie;
|
rivertile.pie = pie;
|
||||||
rivertile.root_module.omit_frame_pointer = omit_frame_pointer;
|
rivertile.root_module.omit_frame_pointer = omit_frame_pointer;
|
||||||
|
|
||||||
@ -285,31 +298,3 @@ pub fn build(b: *Build) !void {
|
|||||||
test_step.dependOn(&run_globber_test.step);
|
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");
|
|
||||||
|
@ -1,29 +1,23 @@
|
|||||||
.{
|
.{
|
||||||
.name = .river,
|
.name = "river",
|
||||||
// While a river release is in development, this string should contain
|
.version = "0.4.0-dev",
|
||||||
// the version in development with the "-dev" suffix.
|
|
||||||
// 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.11-dev",
|
|
||||||
.paths = .{""},
|
.paths = .{""},
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.pixman = .{
|
.@"zig-pixman" = .{
|
||||||
.url = "https://codeberg.org/ifreund/zig-pixman/archive/v0.3.0.tar.gz",
|
.url = "https://codeberg.org/ifreund/zig-pixman/archive/v0.2.0.tar.gz",
|
||||||
.hash = "pixman-0.3.0-LClMnz2VAAAs7QSCGwLimV5VUYx0JFnX5xWU6HwtMuDX",
|
.hash = "12209db20ce873af176138b76632931def33a10539387cba745db72933c43d274d56",
|
||||||
},
|
},
|
||||||
.wayland = .{
|
.@"zig-wayland" = .{
|
||||||
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.3.0.tar.gz",
|
.url = "https://codeberg.org/ifreund/zig-wayland/archive/v0.2.0.tar.gz",
|
||||||
.hash = "wayland-0.3.0-lQa1kjPIAQDmhGYpY-zxiRzQJFHQ2VqhJkQLbKKdt5wl",
|
.hash = "1220687c8c47a48ba285d26a05600f8700d37fc637e223ced3aa8324f3650bf52242",
|
||||||
},
|
},
|
||||||
.wlroots = .{
|
.@"zig-wlroots" = .{
|
||||||
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.19.1.tar.gz",
|
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/e486223799648d27e8b91c5fe0ea4c088b74b707.tar.gz",
|
||||||
.hash = "wlroots-0.19.1-jmOlcs7dAwCajnVWlQZIc-ySYjRlbLxy0F5FvTQqYA3P",
|
.hash = "1220aeb3317e16c38583839961c9d695fa60d23a3d506c8275fb0e8fa9849844f2f7",
|
||||||
},
|
},
|
||||||
.xkbcommon = .{
|
.@"zig-xkbcommon" = .{
|
||||||
.url = "https://codeberg.org/ifreund/zig-xkbcommon/archive/v0.3.0.tar.gz",
|
.url = "https://codeberg.org/ifreund/zig-xkbcommon/archive/v0.2.0.tar.gz",
|
||||||
.hash = "xkbcommon-0.3.0-VDqIe3K9AQB2fG5ZeRcMC9i7kfrp5m2rWgLrmdNn9azr",
|
.hash = "1220c90b2228d65fd8427a837d31b0add83e9fade1dcfa539bb56fd06f1f8461605f",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.fingerprint = 0xf5e3672b8e8d6efc,
|
|
||||||
}
|
}
|
||||||
|
@ -42,21 +42,21 @@ pub fn parser(comptime Arg: type, comptime flags: []const Flag) type {
|
|||||||
.boolean => .{
|
.boolean => .{
|
||||||
.name = flag.name,
|
.name = flag.name,
|
||||||
.type = bool,
|
.type = bool,
|
||||||
.default_value_ptr = &false,
|
.default_value = &false,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(bool),
|
.alignment = @alignOf(bool),
|
||||||
},
|
},
|
||||||
.arg => .{
|
.arg => .{
|
||||||
.name = flag.name,
|
.name = flag.name,
|
||||||
.type = ?[:0]const u8,
|
.type = ?[:0]const u8,
|
||||||
.default_value_ptr = &@as(?[:0]const u8, null),
|
.default_value = &@as(?[:0]const u8, null),
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(?[:0]const u8),
|
.alignment = @alignOf(?[:0]const u8),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
fields = fields ++ [_]std.builtin.Type.StructField{field};
|
fields = fields ++ [_]std.builtin.Type.StructField{field};
|
||||||
}
|
}
|
||||||
break :flags_type @Type(.{ .@"struct" = .{
|
break :flags_type @Type(.{ .Struct = .{
|
||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.fields = fields,
|
.fields = fields,
|
||||||
.decls = &.{},
|
.decls = &.{},
|
||||||
|
@ -18,11 +18,12 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
/// Validate a glob, returning error.InvalidGlob if is "**" or has a '*'
|
/// Validate a glob, returning error.InvalidGlob if it is empty, "**" or has a
|
||||||
/// at any position other than the first and/or last byte.
|
/// '*' at any position other than the first and/or last byte.
|
||||||
pub fn validate(glob: []const u8) error{InvalidGlob}!void {
|
pub fn validate(glob: []const u8) error{InvalidGlob}!void {
|
||||||
switch (glob.len) {
|
switch (glob.len) {
|
||||||
0, 1 => {},
|
0 => return error.InvalidGlob,
|
||||||
|
1 => {},
|
||||||
2 => if (glob[0] == '*' and glob[1] == '*') return error.InvalidGlob,
|
2 => if (glob[0] == '*' and glob[1] == '*') return error.InvalidGlob,
|
||||||
else => if (mem.indexOfScalar(u8, glob[1 .. glob.len - 1], '*') != null) {
|
else => if (mem.indexOfScalar(u8, glob[1 .. glob.len - 1], '*') != null) {
|
||||||
return error.InvalidGlob;
|
return error.InvalidGlob;
|
||||||
@ -33,7 +34,6 @@ pub fn validate(glob: []const u8) error{InvalidGlob}!void {
|
|||||||
test validate {
|
test validate {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
try validate("");
|
|
||||||
try validate("*");
|
try validate("*");
|
||||||
try validate("a");
|
try validate("a");
|
||||||
try validate("*a");
|
try validate("*a");
|
||||||
@ -48,6 +48,7 @@ test validate {
|
|||||||
try validate("abc*");
|
try validate("abc*");
|
||||||
try validate("*abc*");
|
try validate("*abc*");
|
||||||
|
|
||||||
|
try testing.expectError(error.InvalidGlob, validate(""));
|
||||||
try testing.expectError(error.InvalidGlob, validate("**"));
|
try testing.expectError(error.InvalidGlob, validate("**"));
|
||||||
try testing.expectError(error.InvalidGlob, validate("***"));
|
try testing.expectError(error.InvalidGlob, validate("***"));
|
||||||
try testing.expectError(error.InvalidGlob, validate("a*c"));
|
try testing.expectError(error.InvalidGlob, validate("a*c"));
|
||||||
@ -66,9 +67,7 @@ pub fn match(s: []const u8, glob: []const u8) bool {
|
|||||||
validate(glob) catch unreachable;
|
validate(glob) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glob.len == 0) {
|
if (glob.len == 1) {
|
||||||
return s.len == 0;
|
|
||||||
} else if (glob.len == 1) {
|
|
||||||
return glob[0] == '*' or mem.eql(u8, s, glob);
|
return glob[0] == '*' or mem.eql(u8, s, glob);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,9 +89,6 @@ test match {
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
||||||
try testing.expect(match("", "*"));
|
try testing.expect(match("", "*"));
|
||||||
try testing.expect(match("", ""));
|
|
||||||
try testing.expect(!match("a", ""));
|
|
||||||
try testing.expect(!match("", "a"));
|
|
||||||
|
|
||||||
try testing.expect(match("a", "*"));
|
try testing.expect(match("a", "*"));
|
||||||
try testing.expect(match("a", "*a*"));
|
try testing.expect(match("a", "*a*"));
|
||||||
@ -169,10 +165,8 @@ pub fn order(a: []const u8, b: []const u8) std.math.Order {
|
|||||||
return .lt;
|
return .lt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const count_a = if (a.len != 0) @as(u2, @intFromBool(a[0] == '*')) +
|
const count_a = @as(u2, @intFromBool(a[0] == '*')) + @intFromBool(a[a.len - 1] == '*');
|
||||||
@intFromBool(a[a.len - 1] == '*') else 0;
|
const count_b = @as(u2, @intFromBool(b[0] == '*')) + @intFromBool(b[b.len - 1] == '*');
|
||||||
const count_b = if (b.len != 0) @as(u2, @intFromBool(b[0] == '*')) +
|
|
||||||
@intFromBool(b[b.len - 1] == '*') else 0;
|
|
||||||
|
|
||||||
if (count_a == 0 and count_b == 0) {
|
if (count_a == 0 and count_b == 0) {
|
||||||
return .eq;
|
return .eq;
|
||||||
@ -188,7 +182,6 @@ test order {
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const Order = std.math.Order;
|
const Order = std.math.Order;
|
||||||
|
|
||||||
try testing.expectEqual(Order.eq, order("", ""));
|
|
||||||
try testing.expectEqual(Order.eq, order("*", "*"));
|
try testing.expectEqual(Order.eq, order("*", "*"));
|
||||||
try testing.expectEqual(Order.eq, order("*a*", "*b*"));
|
try testing.expectEqual(Order.eq, order("*a*", "*b*"));
|
||||||
try testing.expectEqual(Order.eq, order("a*", "*b"));
|
try testing.expectEqual(Order.eq, order("a*", "*b"));
|
||||||
@ -211,7 +204,6 @@ test order {
|
|||||||
"bababab",
|
"bababab",
|
||||||
"b",
|
"b",
|
||||||
"a",
|
"a",
|
||||||
"",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (descending, 0..) |a, i| {
|
for (descending, 0..) |a, i| {
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
function __riverctl_completion ()
|
function __riverctl_completion ()
|
||||||
{
|
{
|
||||||
local rule_actions="float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen warp no-warp"
|
local rule_actions="float no-float ssd csd tags output position dimensions fullscreen no-fullscreen"
|
||||||
if [ "${COMP_CWORD}" -eq 1 ]
|
if [ "${COMP_CWORD}" -eq 1 ]
|
||||||
then
|
then
|
||||||
OPTS=" \
|
OPTS=" \
|
||||||
|
keyboard-group-create \
|
||||||
|
keyboard-group-destroy \
|
||||||
|
keyboard-group-add \
|
||||||
|
keyboard-group-remove \
|
||||||
keyboard-layout \
|
keyboard-layout \
|
||||||
keyboard-layout-file \
|
keyboard-layout-file \
|
||||||
close \
|
close \
|
||||||
|
@ -72,6 +72,11 @@ complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'hide-cursor'
|
|||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-repeat' -d 'Set the keyboard repeat rate and repeat delay'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-repeat' -d 'Set the keyboard repeat rate and repeat delay'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-cursor-warp' -d 'Set the cursor warp mode'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'set-cursor-warp' -d 'Set the cursor warp mode'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'xcursor-theme' -d 'Set the xcursor theme'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'xcursor-theme' -d 'Set the xcursor theme'
|
||||||
|
# Keyboardgroups
|
||||||
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-create' -d 'Create a keyboard group'
|
||||||
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-destroy' -d 'Destroy a keyboard group'
|
||||||
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-add' -d 'Add a keyboard to a keyboard group'
|
||||||
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-remove' -d 'Remove a keyboard from a keyboard group'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout' -d 'Set the keyboard layout'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout' -d 'Set the keyboard layout'
|
||||||
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout-file' -d 'Set the keyboard layout from a file.'
|
complete -c riverctl -n '__fish_riverctl_complete_arg 1' -a 'keyboard-layout-file' -d 'Set the keyboard layout from a file.'
|
||||||
|
|
||||||
@ -86,10 +91,10 @@ complete -c riverctl -n '__fish_seen_subcommand_from default-attach-mode'
|
|||||||
complete -c riverctl -n '__fish_seen_subcommand_from output-attach-mode' -n '__fish_riverctl_complete_arg 2' -a 'top bottom above below after'
|
complete -c riverctl -n '__fish_seen_subcommand_from output-attach-mode' -n '__fish_riverctl_complete_arg 2' -a 'top bottom above below after'
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from focus-follows-cursor' -n '__fish_riverctl_complete_arg 2' -a 'disabled normal always'
|
complete -c riverctl -n '__fish_seen_subcommand_from focus-follows-cursor' -n '__fish_riverctl_complete_arg 2' -a 'disabled normal always'
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from set-cursor-warp' -n '__fish_riverctl_complete_arg 2' -a 'disabled on-output-change on-focus-change'
|
complete -c riverctl -n '__fish_seen_subcommand_from set-cursor-warp' -n '__fish_riverctl_complete_arg 2' -a 'disabled on-output-change on-focus-change'
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from list-rules' -n '__fish_riverctl_complete_arg 2' -a 'float ssd tags output position dimensions fullscreen warp'
|
complete -c riverctl -n '__fish_seen_subcommand_from list-rules' -n '__fish_riverctl_complete_arg 2' -a 'float ssd tags output position dimensions fullscreen'
|
||||||
|
|
||||||
# Options and subcommands for 'rule-add' and 'rule-del'
|
# Options and subcommands for 'rule-add' and 'rule-del'
|
||||||
set -l rule_actions float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen warp no-warp
|
set -l rule_actions float no-float ssd csd tags output position dimensions fullscreen no-fullscreen
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o app-id' -o 'app-id' -r
|
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o app-id' -o 'app-id' -r
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o title' -o 'title' -r
|
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'not __fish_seen_argument -o title' -o 'title' -r
|
||||||
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'test (math (count (commandline -opc)) % 2) -eq 0' -a "$rule_actions"
|
complete -c riverctl -n '__fish_seen_subcommand_from rule-add rule-del' -n "not __fish_seen_subcommand_from $rule_actions" -n 'test (math (count (commandline -opc)) % 2) -eq 0' -a "$rule_actions"
|
||||||
|
@ -62,6 +62,11 @@ _riverctl_commands()
|
|||||||
'set-repeat:Set the keyboard repeat rate and repeat delay'
|
'set-repeat:Set the keyboard repeat rate and repeat delay'
|
||||||
'set-cursor-warp:Set the cursor warp mode.'
|
'set-cursor-warp:Set the cursor warp mode.'
|
||||||
'xcursor-theme:Set the xcursor theme'
|
'xcursor-theme:Set the xcursor theme'
|
||||||
|
# Keyboard groups
|
||||||
|
'keyboard-group-create:Create a keyboard group'
|
||||||
|
'keyboard-group-destroy:Destroy a keyboard group'
|
||||||
|
'keyboard-group-add:Add a keyboard to a keyboard group'
|
||||||
|
'keyboard-group-remove:Remove a keyboard from a keyboard group'
|
||||||
'keyboard-layout:Set the keyboard layout'
|
'keyboard-layout:Set the keyboard layout'
|
||||||
'keyboard-layout-file:Set the keyboard layout from a file'
|
'keyboard-layout-file:Set the keyboard layout from a file'
|
||||||
# Input
|
# Input
|
||||||
@ -202,9 +207,9 @@ _riverctl()
|
|||||||
# In case of a new rule added in river, we just need
|
# In case of a new rule added in river, we just need
|
||||||
# to add it to the third option between '()',
|
# to add it to the third option between '()',
|
||||||
# i.e (float no-float <new-option>)
|
# i.e (float no-float <new-option>)
|
||||||
_arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tags output position relative-position dimensions fullscreen no-fullscreen warp no-warp)'
|
_arguments '1: :(-app-id -title)' '2: : ' ':: :(float no-float ssd csd tags output position dimensions fullscreen no-fullscreen)'
|
||||||
;;
|
;;
|
||||||
list-rules) _alternative 'arguments:args:(float ssd tags output position dimensions fullscreen warp)' ;;
|
list-rules) _alternative 'arguments:args:(float ssd tags output position dimensions fullscreen)' ;;
|
||||||
*) return 0 ;;
|
*) return 0 ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
@ -300,11 +300,9 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
serial is unknown, the word "Unknown" is used instead.
|
serial is unknown, the word "Unknown" is used instead.
|
||||||
- *position*: Set the initial position of the view, clamping to the bounds
|
- *position*: Set the initial position of the view, clamping to the bounds
|
||||||
of the output. Requires x and y coordinates of the view as arguments, both
|
of the output. Requires x and y coordinates of the view as arguments, both
|
||||||
of which must be non-negative. Applies only to new views.
|
of which must be non-negative. Optionally, the string "mouse" can appear
|
||||||
- *relative-position*: Set the position of the view relative to
|
as the only argument. In this case, the view will appear at the mouse's
|
||||||
something. Requires the anchor and the x and y coordinates of the
|
position. Applies only to new views.
|
||||||
view. The coordinates are either positive or negative numbers that are
|
|
||||||
relative to the anchor. Applies only to new views.
|
|
||||||
- *dimensions*: Set the initial dimensions of the view, clamping to the
|
- *dimensions*: Set the initial dimensions of the view, clamping to the
|
||||||
constraints of the view. Requires width and height of the view as
|
constraints of the view. Requires width and height of the view as
|
||||||
arguments, both of which must be non-negative. Applies only to new views.
|
arguments, both of which must be non-negative. Applies only to new views.
|
||||||
@ -315,16 +313,12 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
view's preference. Applies to new and existing views.
|
view's preference. Applies to new and existing views.
|
||||||
- *no-tearing*: Disable tearing for the view regardless of the view's
|
- *no-tearing*: Disable tearing for the view regardless of the view's
|
||||||
preference. Applies to new and existing views.
|
preference. Applies to new and existing views.
|
||||||
- *warp*: Always warp the cursor when switching to this view, regardless of
|
|
||||||
the _set-cursor-warp_ setting. Applies to new and existing views.
|
|
||||||
- *no-warp*: Never warp the cursor when switching to this view, regardless
|
|
||||||
of the _set-cursor-warp_ setting. Applies to new and existing views.
|
|
||||||
|
|
||||||
Both *float* and *no-float* rules are added to the same list,
|
Both *float* and *no-float* rules are added to the same list,
|
||||||
which means that adding a *no-float* rule with the same arguments
|
which means that adding a *no-float* rule with the same arguments
|
||||||
as a *float* rule will overwrite it. The same holds for *ssd* and
|
as a *float* rule will overwrite it. The same holds for *ssd* and
|
||||||
*csd*, *fullscreen* and *no-fullscreen*, *tearing* and
|
*csd*, *fullscreen* and *no-fullscreen*, *tearing* and
|
||||||
*no-tearing*, *warp* and *no-warp* rules.
|
*no-tearing* rules.
|
||||||
|
|
||||||
If multiple rules in a list match a given view the most specific
|
If multiple rules in a list match a given view the most specific
|
||||||
rule will be applied. For example with the following rules
|
rule will be applied. For example with the following rules
|
||||||
@ -352,7 +346,7 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
*rule-del* [*-app-id* _glob_|*-title* _glob_] _action_
|
*rule-del* [*-app-id* _glob_|*-title* _glob_] _action_
|
||||||
Delete a rule created using *rule-add* with the given arguments.
|
Delete a rule created using *rule-add* with the given arguments.
|
||||||
|
|
||||||
*list-rules* *float*|*ssd*|*tags*|*position*|*dimensions*|*fullscreen*|*warp*
|
*list-rules* *float*|*ssd*|*tags*|*position*|*dimensions*|*fullscreen*
|
||||||
Print the specified rule list. The output is ordered from most specific
|
Print the specified rule list. The output is ordered from most specific
|
||||||
to least specific, the same order in which views are checked against
|
to least specific, the same order in which views are checked against
|
||||||
when searching for a match. Only the first matching rule in the list
|
when searching for a match. Only the first matching rule in the list
|
||||||
@ -430,8 +424,7 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
|
|
||||||
*set-repeat* _rate_ _delay_
|
*set-repeat* _rate_ _delay_
|
||||||
Set the keyboard repeat rate to _rate_ key repeats per second and
|
Set the keyboard repeat rate to _rate_ key repeats per second and
|
||||||
repeat delay to _delay_ milliseconds. The default is a rate of 25
|
repeat delay to _delay_ milliseconds.
|
||||||
repeats per second and a delay of 600ms.
|
|
||||||
|
|
||||||
*xcursor-theme* _theme_name_ [_size_]
|
*xcursor-theme* _theme_name_ [_size_]
|
||||||
Set the xcursor theme to _theme_name_ and optionally set the _size_.
|
Set the xcursor theme to _theme_name_ and optionally set the _size_.
|
||||||
@ -462,6 +455,25 @@ matches everything while _\*\*_ and the empty string are invalid.
|
|||||||
following URL:
|
following URL:
|
||||||
https://xkbcommon.org/doc/current/keymap-text-format-v1.html
|
https://xkbcommon.org/doc/current/keymap-text-format-v1.html
|
||||||
|
|
||||||
|
*keyboard-group-create* _group_name_
|
||||||
|
Create a keyboard group. A keyboard group collects multiple keyboards in
|
||||||
|
a single logical keyboard. This means that all state, like the active
|
||||||
|
modifiers, is shared between the keyboards in a group.
|
||||||
|
|
||||||
|
*keyboard-group-destroy* _group_name_
|
||||||
|
Destroy the keyboard group with the given name. All attached keyboards
|
||||||
|
will be released, making them act as separate devices again.
|
||||||
|
|
||||||
|
*keyboard-group-add* _group_name_ _input_device_name_
|
||||||
|
Add a keyboard to a keyboard group, identified by the keyboard's
|
||||||
|
input device name. Any currently connected and future keyboards with
|
||||||
|
the given name will be added to the group. Simple globbing patterns are
|
||||||
|
supported, see the rules section for further information on globs.
|
||||||
|
|
||||||
|
*keyboard-group-remove* _group_name_ _input_device_name_
|
||||||
|
Remove a keyboard from a keyboard group, identified by the keyboard's
|
||||||
|
input device name.
|
||||||
|
|
||||||
The _input_ command can be used to create a configuration rule for an input
|
The _input_ command can be used to create a configuration rule for an input
|
||||||
device identified by its _name_.
|
device identified by its _name_.
|
||||||
The _name_ of an input device consists of its type, its decimal vendor id,
|
The _name_ of an input device consists of its type, its decimal vendor id,
|
||||||
|
@ -58,15 +58,19 @@ pub const HideCursorWhenTypingMode = enum {
|
|||||||
enabled,
|
enabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Anchor = enum {
|
pub const PositionType = enum {
|
||||||
absolute,
|
absolute,
|
||||||
mouse,
|
at_mouse,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Position = struct {
|
pub const Position = struct {
|
||||||
anchor: Anchor,
|
x: u31,
|
||||||
x: i31,
|
y: u31,
|
||||||
y: i31,
|
};
|
||||||
|
|
||||||
|
pub const FloatPosition = union(PositionType) {
|
||||||
|
absolute: Position,
|
||||||
|
at_mouse,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Dimensions = struct {
|
pub const Dimensions = struct {
|
||||||
@ -104,11 +108,10 @@ rules: struct {
|
|||||||
ssd: RuleList(bool) = .{},
|
ssd: RuleList(bool) = .{},
|
||||||
tags: RuleList(u32) = .{},
|
tags: RuleList(u32) = .{},
|
||||||
output: RuleList([]const u8) = .{},
|
output: RuleList([]const u8) = .{},
|
||||||
position: RuleList(Position) = .{},
|
position: RuleList(FloatPosition) = .{},
|
||||||
dimensions: RuleList(Dimensions) = .{},
|
dimensions: RuleList(Dimensions) = .{},
|
||||||
fullscreen: RuleList(bool) = .{},
|
fullscreen: RuleList(bool) = .{},
|
||||||
tearing: RuleList(bool) = .{},
|
tearing: RuleList(bool) = .{},
|
||||||
warp: RuleList(bool) = .{},
|
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
/// The selected focus_follows_cursor mode
|
/// The selected focus_follows_cursor mode
|
||||||
@ -193,7 +196,6 @@ pub fn deinit(config: *Config) void {
|
|||||||
config.rules.position.deinit();
|
config.rules.position.deinit();
|
||||||
config.rules.dimensions.deinit();
|
config.rules.dimensions.deinit();
|
||||||
config.rules.fullscreen.deinit();
|
config.rules.fullscreen.deinit();
|
||||||
config.rules.warp.deinit();
|
|
||||||
|
|
||||||
util.gpa.free(config.default_layout_namespace);
|
util.gpa.free(config.default_layout_namespace);
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ fn handleRequest(control_v1: *zriver.ControlV1, request: zriver.ControlV1.Reques
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
.run_command => |run_command| {
|
.run_command => |run_command| {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(wlr.Seat.Client.fromWlSeat(run_command.seat).?.seat.data));
|
const seat: *Seat = @ptrFromInt(wlr.Seat.Client.fromWlSeat(run_command.seat).?.seat.data);
|
||||||
|
|
||||||
const callback = zriver.CommandCallbackV1.create(
|
const callback = zriver.CommandCallbackV1.create(
|
||||||
control_v1.getClient(),
|
control_v1.getClient(),
|
||||||
|
132
river/Cursor.zig
132
river/Cursor.zig
@ -108,19 +108,6 @@ const LayoutPoint = struct {
|
|||||||
ly: f64,
|
ly: f64,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Image = union(enum) {
|
|
||||||
/// No cursor image
|
|
||||||
none,
|
|
||||||
/// Name of the current Xcursor shape
|
|
||||||
xcursor: [*:0]const u8,
|
|
||||||
/// Cursor surface configured by a client
|
|
||||||
client: struct {
|
|
||||||
surface: *wlr.Surface,
|
|
||||||
hotspot_x: i32,
|
|
||||||
hotspot_y: i32,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const log = std.log.scoped(.cursor);
|
const log = std.log.scoped(.cursor);
|
||||||
|
|
||||||
/// Current cursor mode as well as any state needed to implement that mode
|
/// Current cursor mode as well as any state needed to implement that mode
|
||||||
@ -137,8 +124,9 @@ wlr_cursor: *wlr.Cursor,
|
|||||||
|
|
||||||
/// Xcursor manager for the currently configured Xcursor theme.
|
/// Xcursor manager for the currently configured Xcursor theme.
|
||||||
xcursor_manager: *wlr.XcursorManager,
|
xcursor_manager: *wlr.XcursorManager,
|
||||||
image: Image = .none,
|
/// Name of the current Xcursor shape, or null if a client has configured a
|
||||||
image_surface_destroy: wl.Listener(*wlr.Surface) = .init(handleImageSurfaceDestroy),
|
/// surface to be used as the cursor shape instead.
|
||||||
|
xcursor_name: ?[*:0]const u8 = null,
|
||||||
|
|
||||||
/// Number of distinct buttons currently pressed
|
/// Number of distinct buttons currently pressed
|
||||||
pressed_count: u32 = 0,
|
pressed_count: u32 = 0,
|
||||||
@ -255,30 +243,6 @@ pub fn init(cursor: *Cursor, seat: *Seat) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(cursor: *Cursor) void {
|
pub fn deinit(cursor: *Cursor) void {
|
||||||
cursor.axis.link.remove();
|
|
||||||
cursor.button.link.remove();
|
|
||||||
cursor.frame.link.remove();
|
|
||||||
cursor.motion_absolute.link.remove();
|
|
||||||
cursor.motion.link.remove();
|
|
||||||
cursor.swipe_begin.link.remove();
|
|
||||||
cursor.swipe_update.link.remove();
|
|
||||||
cursor.swipe_end.link.remove();
|
|
||||||
cursor.pinch_begin.link.remove();
|
|
||||||
cursor.pinch_update.link.remove();
|
|
||||||
cursor.pinch_end.link.remove();
|
|
||||||
cursor.request_set_cursor.link.remove();
|
|
||||||
|
|
||||||
cursor.touch_down.link.remove();
|
|
||||||
cursor.touch_motion.link.remove();
|
|
||||||
cursor.touch_up.link.remove();
|
|
||||||
cursor.touch_cancel.link.remove();
|
|
||||||
cursor.touch_frame.link.remove();
|
|
||||||
|
|
||||||
cursor.tablet_tool_axis.link.remove();
|
|
||||||
cursor.tablet_tool_proximity.link.remove();
|
|
||||||
cursor.tablet_tool_tip.link.remove();
|
|
||||||
cursor.tablet_tool_button.link.remove();
|
|
||||||
|
|
||||||
cursor.hide_cursor_timer.remove();
|
cursor.hide_cursor_timer.remove();
|
||||||
cursor.xcursor_manager.destroy();
|
cursor.xcursor_manager.destroy();
|
||||||
cursor.wlr_cursor.destroy();
|
cursor.wlr_cursor.destroy();
|
||||||
@ -322,47 +286,25 @@ pub fn setTheme(cursor: *Cursor, theme: ?[*:0]const u8, _size: ?u32) !void {
|
|||||||
cursor.xcursor_manager.destroy();
|
cursor.xcursor_manager.destroy();
|
||||||
cursor.xcursor_manager = xcursor_manager;
|
cursor.xcursor_manager = xcursor_manager;
|
||||||
|
|
||||||
switch (cursor.image) {
|
if (cursor.xcursor_name) |name| {
|
||||||
.none, .client => {},
|
cursor.setXcursor(name);
|
||||||
.xcursor => |name| cursor.wlr_cursor.setXcursor(xcursor_manager, name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setImage(cursor: *Cursor, image: Image) void {
|
pub fn setXcursor(cursor: *Cursor, name: [*:0]const u8) void {
|
||||||
switch (cursor.image) {
|
cursor.wlr_cursor.setXcursor(cursor.xcursor_manager, name);
|
||||||
.none, .xcursor => {},
|
cursor.xcursor_name = name;
|
||||||
.client => {
|
|
||||||
cursor.image_surface_destroy.link.remove();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cursor.image = image;
|
|
||||||
switch (cursor.image) {
|
|
||||||
.none => cursor.wlr_cursor.unsetImage(),
|
|
||||||
.xcursor => |name| cursor.wlr_cursor.setXcursor(cursor.xcursor_manager, name),
|
|
||||||
.client => |client| {
|
|
||||||
cursor.wlr_cursor.setSurface(client.surface, client.hotspot_x, client.hotspot_y);
|
|
||||||
client.surface.events.destroy.add(&cursor.image_surface_destroy);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handleImageSurfaceDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
|
||||||
const cursor: *Cursor = @fieldParentPtr("image_surface_destroy", listener);
|
|
||||||
// wlroots calls wlr_cursor_unset_image() automatically
|
|
||||||
// when the cursor surface is destroyed.
|
|
||||||
cursor.image = .none;
|
|
||||||
cursor.image_surface_destroy.link.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clearFocus(cursor: *Cursor) void {
|
fn clearFocus(cursor: *Cursor) void {
|
||||||
cursor.setImage(.{ .xcursor = "default" });
|
cursor.setXcursor("default");
|
||||||
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Axis event is a scroll wheel or similiar
|
/// Axis event is a scroll wheel or similiar
|
||||||
fn handleAxis(listener: *wl.Listener(*wlr.Pointer.event.Axis), event: *wlr.Pointer.event.Axis) void {
|
fn handleAxis(listener: *wl.Listener(*wlr.Pointer.event.Axis), event: *wlr.Pointer.event.Axis) void {
|
||||||
const cursor: *Cursor = @fieldParentPtr("axis", listener);
|
const cursor: *Cursor = @fieldParentPtr("axis", listener);
|
||||||
const device: *InputDevice = @alignCast(@ptrCast(event.device.data));
|
const device: *InputDevice = @ptrFromInt(event.device.data);
|
||||||
|
|
||||||
cursor.seat.handleActivity();
|
cursor.seat.handleActivity();
|
||||||
cursor.unhide();
|
cursor.unhide();
|
||||||
@ -482,7 +424,7 @@ fn updateKeyboardFocus(cursor: Cursor, result: Root.AtResult) void {
|
|||||||
/// Requires a call to Root.applyPending()
|
/// Requires a call to Root.applyPending()
|
||||||
fn updateOutputFocus(cursor: Cursor, lx: f64, ly: f64) void {
|
fn updateOutputFocus(cursor: Cursor, lx: f64, ly: f64) void {
|
||||||
if (server.root.output_layout.outputAt(lx, ly)) |wlr_output| {
|
if (server.root.output_layout.outputAt(lx, ly)) |wlr_output| {
|
||||||
const output: *Output = @alignCast(@ptrCast(wlr_output.data));
|
const output: *Output = @ptrFromInt(wlr_output.data);
|
||||||
cursor.seat.focusOutput(output);
|
cursor.seat.focusOutput(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -659,7 +601,7 @@ fn handleTabletToolAxis(
|
|||||||
_: *wl.Listener(*wlr.Tablet.event.Axis),
|
_: *wl.Listener(*wlr.Tablet.event.Axis),
|
||||||
event: *wlr.Tablet.event.Axis,
|
event: *wlr.Tablet.event.Axis,
|
||||||
) void {
|
) void {
|
||||||
const device: *InputDevice = @alignCast(@ptrCast(event.device.data));
|
const device: *InputDevice = @ptrFromInt(event.device.data);
|
||||||
const tablet: *Tablet = @fieldParentPtr("device", device);
|
const tablet: *Tablet = @fieldParentPtr("device", device);
|
||||||
|
|
||||||
device.seat.handleActivity();
|
device.seat.handleActivity();
|
||||||
@ -673,7 +615,7 @@ fn handleTabletToolProximity(
|
|||||||
_: *wl.Listener(*wlr.Tablet.event.Proximity),
|
_: *wl.Listener(*wlr.Tablet.event.Proximity),
|
||||||
event: *wlr.Tablet.event.Proximity,
|
event: *wlr.Tablet.event.Proximity,
|
||||||
) void {
|
) void {
|
||||||
const device: *InputDevice = @alignCast(@ptrCast(event.device.data));
|
const device: *InputDevice = @ptrFromInt(event.device.data);
|
||||||
const tablet: *Tablet = @fieldParentPtr("device", device);
|
const tablet: *Tablet = @fieldParentPtr("device", device);
|
||||||
|
|
||||||
device.seat.handleActivity();
|
device.seat.handleActivity();
|
||||||
@ -687,7 +629,7 @@ fn handleTabletToolTip(
|
|||||||
_: *wl.Listener(*wlr.Tablet.event.Tip),
|
_: *wl.Listener(*wlr.Tablet.event.Tip),
|
||||||
event: *wlr.Tablet.event.Tip,
|
event: *wlr.Tablet.event.Tip,
|
||||||
) void {
|
) void {
|
||||||
const device: *InputDevice = @alignCast(@ptrCast(event.device.data));
|
const device: *InputDevice = @ptrFromInt(event.device.data);
|
||||||
const tablet: *Tablet = @fieldParentPtr("device", device);
|
const tablet: *Tablet = @fieldParentPtr("device", device);
|
||||||
|
|
||||||
device.seat.handleActivity();
|
device.seat.handleActivity();
|
||||||
@ -701,7 +643,7 @@ fn handleTabletToolButton(
|
|||||||
_: *wl.Listener(*wlr.Tablet.event.Button),
|
_: *wl.Listener(*wlr.Tablet.event.Button),
|
||||||
event: *wlr.Tablet.event.Button,
|
event: *wlr.Tablet.event.Button,
|
||||||
) void {
|
) void {
|
||||||
const device: *InputDevice = @alignCast(@ptrCast(event.device.data));
|
const device: *InputDevice = @ptrFromInt(event.device.data);
|
||||||
const tablet: *Tablet = @fieldParentPtr("device", device);
|
const tablet: *Tablet = @fieldParentPtr("device", device);
|
||||||
|
|
||||||
device.seat.handleActivity();
|
device.seat.handleActivity();
|
||||||
@ -798,15 +740,8 @@ fn handleRequestSetCursor(
|
|||||||
// on the output that it's currently on and continue to do so as the
|
// on the output that it's currently on and continue to do so as the
|
||||||
// cursor moves between outputs.
|
// cursor moves between outputs.
|
||||||
log.debug("focused client set cursor", .{});
|
log.debug("focused client set cursor", .{});
|
||||||
if (event.surface) |surface| {
|
cursor.wlr_cursor.setSurface(event.surface, event.hotspot_x, event.hotspot_y);
|
||||||
cursor.setImage(.{ .client = .{
|
cursor.xcursor_name = null;
|
||||||
.surface = surface,
|
|
||||||
.hotspot_x = event.hotspot_x,
|
|
||||||
.hotspot_y = event.hotspot_y,
|
|
||||||
} });
|
|
||||||
} else {
|
|
||||||
cursor.setImage(.none);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,6 +757,8 @@ pub fn hide(cursor: *Cursor) void {
|
|||||||
|
|
||||||
cursor.hidden = true;
|
cursor.hidden = true;
|
||||||
cursor.wlr_cursor.unsetImage();
|
cursor.wlr_cursor.unsetImage();
|
||||||
|
cursor.xcursor_name = null;
|
||||||
|
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
||||||
cursor.hide_cursor_timer.timerUpdate(0) catch {
|
cursor.hide_cursor_timer.timerUpdate(0) catch {
|
||||||
log.err("failed to update cursor hide timeout", .{});
|
log.err("failed to update cursor hide timeout", .{});
|
||||||
};
|
};
|
||||||
@ -833,7 +770,6 @@ pub fn unhide(cursor: *Cursor) void {
|
|||||||
};
|
};
|
||||||
if (!cursor.hidden) return;
|
if (!cursor.hidden) return;
|
||||||
cursor.hidden = false;
|
cursor.hidden = false;
|
||||||
cursor.setImage(cursor.image);
|
|
||||||
cursor.updateState();
|
cursor.updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,7 +868,7 @@ fn computeEdges(cursor: *const Cursor, view: *const View) wlr.Edges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor: [*:0]const u8) void {
|
fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor_name: [*:0]const u8) void {
|
||||||
assert(cursor.mode == .passthrough or cursor.mode == .down);
|
assert(cursor.mode == .passthrough or cursor.mode == .down);
|
||||||
assert(mode == .move or mode == .resize);
|
assert(mode == .move or mode == .resize);
|
||||||
|
|
||||||
@ -948,7 +884,7 @@ fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor: [*:0]const u8) v
|
|||||||
}
|
}
|
||||||
|
|
||||||
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
cursor.seat.wlr_seat.pointerNotifyClearFocus();
|
||||||
cursor.setImage(.{ .xcursor = xcursor });
|
cursor.setXcursor(xcursor_name);
|
||||||
|
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
}
|
}
|
||||||
@ -1153,14 +1089,10 @@ pub fn updateState(cursor: *Cursor) void {
|
|||||||
.passthrough => {
|
.passthrough => {
|
||||||
cursor.updateFocusFollowsCursorTarget();
|
cursor.updateFocusFollowsCursorTarget();
|
||||||
if (!cursor.hidden) {
|
if (!cursor.hidden) {
|
||||||
const now = posix.clock_gettime(.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
var now: posix.timespec = undefined;
|
||||||
// 2^32-1 milliseconds is ~50 days, which is a realistic uptime.
|
posix.clock_gettime(posix.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
|
||||||
// This means that we must wrap if the monotonic time is greater than
|
const msec: u32 = @intCast(now.tv_sec * std.time.ms_per_s +
|
||||||
// 2^32-1 milliseconds and hope that clients don't get too confused.
|
@divTrunc(now.tv_nsec, std.time.ns_per_ms));
|
||||||
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(msec);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1246,18 +1178,10 @@ fn warp(cursor: *Cursor) void {
|
|||||||
|
|
||||||
const focused_output = cursor.seat.focused_output orelse return;
|
const focused_output = cursor.seat.focused_output orelse return;
|
||||||
|
|
||||||
var mode = server.config.warp_cursor;
|
|
||||||
if (cursor.seat.focused == .view) {
|
|
||||||
const view = cursor.seat.focused.view;
|
|
||||||
if (server.config.rules.warp.match(view)) |w| {
|
|
||||||
mode = if (w) .@"on-focus-change" else .disabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warp pointer to center of the focused view/output (In layout coordinates) if enabled.
|
// Warp pointer to center of the focused view/output (In layout coordinates) if enabled.
|
||||||
var output_layout_box: wlr.Box = undefined;
|
var output_layout_box: wlr.Box = undefined;
|
||||||
server.root.output_layout.getBox(focused_output.wlr_output, &output_layout_box);
|
server.root.output_layout.getBox(focused_output.wlr_output, &output_layout_box);
|
||||||
const target_box = switch (mode) {
|
const target_box = switch (server.config.warp_cursor) {
|
||||||
.disabled => return,
|
.disabled => return,
|
||||||
.@"on-output-change" => output_layout_box,
|
.@"on-output-change" => output_layout_box,
|
||||||
.@"on-focus-change" => switch (cursor.seat.focused) {
|
.@"on-focus-change" => switch (cursor.seat.focused) {
|
||||||
@ -1287,7 +1211,7 @@ fn warp(cursor: *Cursor) void {
|
|||||||
};
|
};
|
||||||
if (!output_layout_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y) or
|
if (!output_layout_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y) or
|
||||||
(usable_layout_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y) and
|
(usable_layout_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y) and
|
||||||
!target_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y)))
|
!target_box.containsPoint(cursor.wlr_cursor.x, cursor.wlr_cursor.y)))
|
||||||
{
|
{
|
||||||
const lx: f64 = @floatFromInt(target_box.x + @divTrunc(target_box.width, 2));
|
const lx: f64 = @floatFromInt(target_box.x + @divTrunc(target_box.width, 2));
|
||||||
const ly: f64 = @floatFromInt(target_box.y + @divTrunc(target_box.height, 2));
|
const ly: f64 = @floatFromInt(target_box.y + @divTrunc(target_box.height, 2));
|
||||||
@ -1300,7 +1224,7 @@ fn warp(cursor: *Cursor) void {
|
|||||||
fn updateDragIcons(cursor: *Cursor) void {
|
fn updateDragIcons(cursor: *Cursor) void {
|
||||||
var it = server.root.drag_icons.children.iterator(.forward);
|
var it = server.root.drag_icons.children.iterator(.forward);
|
||||||
while (it.next()) |node| {
|
while (it.next()) |node| {
|
||||||
const icon: *DragIcon = @alignCast(@ptrCast(node.data));
|
const icon = @as(*DragIcon, @ptrFromInt(node.data));
|
||||||
|
|
||||||
if (icon.wlr_drag_icon.drag.seat == cursor.seat.wlr_seat) {
|
if (icon.wlr_drag_icon.drag.seat == cursor.seat.wlr_seat) {
|
||||||
icon.updatePosition(cursor);
|
icon.updatePosition(cursor);
|
||||||
|
@ -42,7 +42,7 @@ pub fn create(wlr_drag_icon: *wlr.Drag.Icon, cursor: *Cursor) error{OutOfMemory}
|
|||||||
.wlr_drag_icon = wlr_drag_icon,
|
.wlr_drag_icon = wlr_drag_icon,
|
||||||
.scene_drag_icon = scene_drag_icon,
|
.scene_drag_icon = scene_drag_icon,
|
||||||
};
|
};
|
||||||
scene_drag_icon.node.data = drag_icon;
|
scene_drag_icon.node.data = @intFromPtr(drag_icon);
|
||||||
|
|
||||||
drag_icon.updatePosition(cursor);
|
drag_icon.updatePosition(cursor);
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ fn handleForeignActivate(
|
|||||||
) void {
|
) void {
|
||||||
const handle: *ForeignToplevelHandle = @fieldParentPtr("foreign_activate", listener);
|
const handle: *ForeignToplevelHandle = @fieldParentPtr("foreign_activate", listener);
|
||||||
const view: *View = @fieldParentPtr("foreign_toplevel_handle", handle);
|
const view: *View = @fieldParentPtr("foreign_toplevel_handle", handle);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(event.seat.data));
|
const seat: *Seat = @ptrFromInt(event.seat.data);
|
||||||
|
|
||||||
seat.focus(view);
|
seat.focus(view);
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
|
@ -30,7 +30,7 @@ const View = @import("View.zig");
|
|||||||
wlr_manager: *wlr.IdleInhibitManagerV1,
|
wlr_manager: *wlr.IdleInhibitManagerV1,
|
||||||
new_idle_inhibitor: wl.Listener(*wlr.IdleInhibitorV1) =
|
new_idle_inhibitor: wl.Listener(*wlr.IdleInhibitorV1) =
|
||||||
wl.Listener(*wlr.IdleInhibitorV1).init(handleNewIdleInhibitor),
|
wl.Listener(*wlr.IdleInhibitorV1).init(handleNewIdleInhibitor),
|
||||||
inhibitors: std.DoublyLinkedList(IdleInhibitor) = .{},
|
inhibitors: std.TailQueue(IdleInhibitor) = .{},
|
||||||
|
|
||||||
pub fn init(inhibit_manager: *IdleInhibitManager) !void {
|
pub fn init(inhibit_manager: *IdleInhibitManager) !void {
|
||||||
inhibit_manager.* = .{
|
inhibit_manager.* = .{
|
||||||
@ -79,7 +79,7 @@ pub fn checkActive(inhibit_manager: *IdleInhibitManager) void {
|
|||||||
|
|
||||||
fn handleNewIdleInhibitor(listener: *wl.Listener(*wlr.IdleInhibitorV1), inhibitor: *wlr.IdleInhibitorV1) void {
|
fn handleNewIdleInhibitor(listener: *wl.Listener(*wlr.IdleInhibitorV1), inhibitor: *wlr.IdleInhibitorV1) void {
|
||||||
const inhibit_manager: *IdleInhibitManager = @fieldParentPtr("new_idle_inhibitor", listener);
|
const inhibit_manager: *IdleInhibitManager = @fieldParentPtr("new_idle_inhibitor", listener);
|
||||||
const inhibitor_node = util.gpa.create(std.DoublyLinkedList(IdleInhibitor).Node) catch return;
|
const inhibitor_node = util.gpa.create(std.TailQueue(IdleInhibitor).Node) catch return;
|
||||||
inhibitor_node.data.init(inhibitor, inhibit_manager) catch {
|
inhibitor_node.data.init(inhibitor, inhibit_manager) catch {
|
||||||
util.gpa.destroy(inhibitor_node);
|
util.gpa.destroy(inhibitor_node);
|
||||||
return;
|
return;
|
||||||
|
@ -49,7 +49,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
|||||||
|
|
||||||
inhibitor.destroy.link.remove();
|
inhibitor.destroy.link.remove();
|
||||||
|
|
||||||
const node: *std.DoublyLinkedList(IdleInhibitor).Node = @fieldParentPtr("data", inhibitor);
|
const node: *std.TailQueue(IdleInhibitor).Node = @fieldParentPtr("data", inhibitor);
|
||||||
server.idle_inhibit_manager.inhibitors.remove(node);
|
server.idle_inhibit_manager.inhibitors.remove(node);
|
||||||
|
|
||||||
inhibitor.inhibit_manager.checkActive();
|
inhibitor.inhibit_manager.checkActive();
|
||||||
|
@ -307,7 +307,7 @@ pub fn apply(config: *const InputConfig, device: *InputDevice) void {
|
|||||||
const libinput_device: *c.libinput_device = @ptrCast(device.wlr_device.getLibinputDevice() orelse return);
|
const libinput_device: *c.libinput_device = @ptrCast(device.wlr_device.getLibinputDevice() orelse return);
|
||||||
log.debug("applying input configuration '{s}' to device '{s}'.", .{ config.glob, device.identifier });
|
log.debug("applying input configuration '{s}' to device '{s}'.", .{ config.glob, device.identifier });
|
||||||
|
|
||||||
inline for (@typeInfo(InputConfig).@"struct".fields) |field| {
|
inline for (@typeInfo(InputConfig).Struct.fields) |field| {
|
||||||
if (comptime mem.eql(u8, field.name, "glob")) continue;
|
if (comptime mem.eql(u8, field.name, "glob")) continue;
|
||||||
|
|
||||||
if (@field(config, field.name)) |setting| {
|
if (@field(config, field.name)) |setting| {
|
||||||
@ -324,7 +324,7 @@ pub fn apply(config: *const InputConfig, device: *InputDevice) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(config: *InputConfig, setting: []const u8, value: []const u8) !void {
|
pub fn parse(config: *InputConfig, setting: []const u8, value: []const u8) !void {
|
||||||
inline for (@typeInfo(InputConfig).@"struct".fields) |field| {
|
inline for (@typeInfo(InputConfig).Struct.fields) |field| {
|
||||||
if (comptime mem.eql(u8, field.name, "glob")) continue;
|
if (comptime mem.eql(u8, field.name, "glob")) continue;
|
||||||
|
|
||||||
if (mem.eql(u8, setting, field.name)) {
|
if (mem.eql(u8, setting, field.name)) {
|
||||||
@ -358,8 +358,8 @@ pub fn parse(config: *InputConfig, setting: []const u8, value: []const u8) !void
|
|||||||
}
|
}
|
||||||
config.@"map-to-output" = .{ .output_name = output_name_owned };
|
config.@"map-to-output" = .{ .output_name = output_name_owned };
|
||||||
} else {
|
} else {
|
||||||
const T = @typeInfo(field.type).optional.child;
|
const T = @typeInfo(field.type).Optional.child;
|
||||||
if (@typeInfo(T) != .@"enum") {
|
if (@typeInfo(T) != .Enum) {
|
||||||
@compileError("You forgot to implement parsing for an input configuration setting.");
|
@compileError("You forgot to implement parsing for an input configuration setting.");
|
||||||
}
|
}
|
||||||
@field(config, field.name) = meta.stringToEnum(T, value) orelse
|
@field(config, field.name) = meta.stringToEnum(T, value) orelse
|
||||||
@ -376,7 +376,7 @@ pub fn parse(config: *InputConfig, setting: []const u8, value: []const u8) !void
|
|||||||
pub fn write(config: *InputConfig, writer: anytype) !void {
|
pub fn write(config: *InputConfig, writer: anytype) !void {
|
||||||
try writer.print("{s}\n", .{config.glob});
|
try writer.print("{s}\n", .{config.glob});
|
||||||
|
|
||||||
inline for (@typeInfo(InputConfig).@"struct".fields) |field| {
|
inline for (@typeInfo(InputConfig).Struct.fields) |field| {
|
||||||
if (comptime mem.eql(u8, field.name, "glob")) continue;
|
if (comptime mem.eql(u8, field.name, "glob")) continue;
|
||||||
|
|
||||||
if (comptime mem.eql(u8, field.name, "map-to-output")) {
|
if (comptime mem.eql(u8, field.name, "map-to-output")) {
|
||||||
@ -396,8 +396,8 @@ pub fn write(config: *InputConfig, writer: anytype) !void {
|
|||||||
mem.sliceTo(c.libevdev_event_code_get_name(c.EV_KEY, setting.button), 0),
|
mem.sliceTo(c.libevdev_event_code_get_name(c.EV_KEY, setting.button), 0),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const T = @typeInfo(field.type).optional.child;
|
const T = @typeInfo(field.type).Optional.child;
|
||||||
if (@typeInfo(T) != .@"enum") {
|
if (@typeInfo(T) != .Enum) {
|
||||||
@compileError("You forgot to implement listing for an input configuration setting.");
|
@compileError("You forgot to implement listing for an input configuration setting.");
|
||||||
}
|
}
|
||||||
try writer.print("\t{s}: {s}\n", .{ field.name, @tagName(setting) });
|
try writer.print("\t{s}: {s}\n", .{ field.name, @tagName(setting) });
|
||||||
|
@ -86,7 +86,7 @@ pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !vo
|
|||||||
.link = undefined,
|
.link = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
wlr_device.data = device;
|
wlr_device.data = @intFromPtr(device);
|
||||||
|
|
||||||
wlr_device.events.destroy.add(&device.destroy);
|
wlr_device.events.destroy.add(&device.destroy);
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ pub fn deinit(device: *InputDevice) void {
|
|||||||
device.seat.updateCapabilities();
|
device.seat.updateCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
device.wlr_device.data = null;
|
device.wlr_device.data = 0;
|
||||||
|
|
||||||
device.* = undefined;
|
device.* = undefined;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ tablet_manager: *wlr.TabletManagerV2,
|
|||||||
configs: std.ArrayList(InputConfig),
|
configs: std.ArrayList(InputConfig),
|
||||||
|
|
||||||
devices: wl.list.Head(InputDevice, .link),
|
devices: wl.list.Head(InputDevice, .link),
|
||||||
seats: std.DoublyLinkedList(Seat) = .{},
|
seats: std.TailQueue(Seat) = .{},
|
||||||
|
|
||||||
exclusive_client: ?*wl.Client = null,
|
exclusive_client: ?*wl.Client = null,
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ new_text_input: wl.Listener(*wlr.TextInputV3) =
|
|||||||
wl.Listener(*wlr.TextInputV3).init(handleNewTextInput),
|
wl.Listener(*wlr.TextInputV3).init(handleNewTextInput),
|
||||||
|
|
||||||
pub fn init(input_manager: *InputManager) !void {
|
pub fn init(input_manager: *InputManager) !void {
|
||||||
const seat_node = try util.gpa.create(std.DoublyLinkedList(Seat).Node);
|
const seat_node = try util.gpa.create(std.TailQueue(Seat).Node);
|
||||||
errdefer util.gpa.destroy(seat_node);
|
errdefer util.gpa.destroy(seat_node);
|
||||||
|
|
||||||
input_manager.* = .{
|
input_manager.* = .{
|
||||||
@ -185,7 +185,7 @@ fn handleNewVirtualKeyboard(
|
|||||||
_: *wl.Listener(*wlr.VirtualKeyboardV1),
|
_: *wl.Listener(*wlr.VirtualKeyboardV1),
|
||||||
virtual_keyboard: *wlr.VirtualKeyboardV1,
|
virtual_keyboard: *wlr.VirtualKeyboardV1,
|
||||||
) void {
|
) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(virtual_keyboard.seat.data));
|
const seat: *Seat = @ptrFromInt(virtual_keyboard.seat.data);
|
||||||
seat.addDevice(&virtual_keyboard.keyboard.base);
|
seat.addDevice(&virtual_keyboard.keyboard.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ fn handleNewConstraint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleNewInputMethod(_: *wl.Listener(*wlr.InputMethodV2), input_method: *wlr.InputMethodV2) void {
|
fn handleNewInputMethod(_: *wl.Listener(*wlr.InputMethodV2), input_method: *wlr.InputMethodV2) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(input_method.seat.data));
|
const seat: *Seat = @ptrFromInt(input_method.seat.data);
|
||||||
|
|
||||||
log.debug("new input method on seat {s}", .{seat.wlr_seat.name});
|
log.debug("new input method on seat {s}", .{seat.wlr_seat.name});
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ pub const Pressed = struct {
|
|||||||
// Furthermore, wlroots will continue to forward key press/release events to river if more
|
// Furthermore, wlroots will continue to forward key press/release events to river if more
|
||||||
// than 32 keys are pressed. Therefore river chooses to ignore keypresses that would take
|
// than 32 keys are pressed. Therefore river chooses to ignore keypresses that would take
|
||||||
// the keyboard beyond 32 simultaneously pressed keys.
|
// the keyboard beyond 32 simultaneously pressed keys.
|
||||||
assert(capacity == @typeInfo(std.meta.fieldInfo(wlr.Keyboard, .keycodes).type).array.len);
|
assert(capacity == @typeInfo(std.meta.fieldInfo(wlr.Keyboard, .keycodes).type).Array.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
keys: std.BoundedArray(Key, capacity) = .{},
|
keys: std.BoundedArray(Key, capacity) = .{},
|
||||||
@ -96,14 +96,21 @@ pub fn init(keyboard: *Keyboard, seat: *Seat, wlr_device: *wlr.InputDevice) !voi
|
|||||||
errdefer keyboard.device.deinit();
|
errdefer keyboard.device.deinit();
|
||||||
|
|
||||||
const wlr_keyboard = keyboard.device.wlr_device.toKeyboard();
|
const wlr_keyboard = keyboard.device.wlr_device.toKeyboard();
|
||||||
wlr_keyboard.data = keyboard;
|
wlr_keyboard.data = @intFromPtr(keyboard);
|
||||||
|
|
||||||
// wlroots will log a more detailed error if this fails.
|
// wlroots will log a more detailed error if this fails.
|
||||||
if (!wlr_keyboard.setKeymap(server.config.keymap)) return error.OutOfMemory;
|
if (!wlr_keyboard.setKeymap(server.config.keymap)) return error.OutOfMemory;
|
||||||
|
|
||||||
if (wlr.KeyboardGroup.fromKeyboard(wlr_keyboard) == null) {
|
// Add to keyboard-group, if applicable.
|
||||||
// wlroots will log an error on failure
|
var group_it = seat.keyboard_groups.first;
|
||||||
_ = seat.keyboard_group.addKeyboard(wlr_keyboard);
|
outer: while (group_it) |group_node| : (group_it = group_node.next) {
|
||||||
|
for (group_node.data.globs.items) |glob| {
|
||||||
|
if (globber.match(glob, keyboard.device.identifier)) {
|
||||||
|
// wlroots will log an error if this fails explaining the reason.
|
||||||
|
_ = group_node.data.wlr_group.addKeyboard(wlr_keyboard);
|
||||||
|
break :outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
|
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
|
||||||
|
141
river/KeyboardGroup.zig
Normal file
141
river/KeyboardGroup.zig
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// This file is part of river, a dynamic tiling wayland compositor.
|
||||||
|
//
|
||||||
|
// Copyright 2022 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/>.
|
||||||
|
|
||||||
|
const KeyboardGroup = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
const globber = @import("globber");
|
||||||
|
const wlr = @import("wlroots");
|
||||||
|
const wl = @import("wayland").server.wl;
|
||||||
|
const xkb = @import("xkbcommon");
|
||||||
|
|
||||||
|
const log = std.log.scoped(.keyboard_group);
|
||||||
|
|
||||||
|
const server = &@import("main.zig").server;
|
||||||
|
const util = @import("util.zig");
|
||||||
|
|
||||||
|
const Seat = @import("Seat.zig");
|
||||||
|
const Keyboard = @import("Keyboard.zig");
|
||||||
|
|
||||||
|
seat: *Seat,
|
||||||
|
wlr_group: *wlr.KeyboardGroup,
|
||||||
|
name: []const u8,
|
||||||
|
globs: std.ArrayListUnmanaged([]const u8) = .{},
|
||||||
|
|
||||||
|
pub fn create(seat: *Seat, name: []const u8) !void {
|
||||||
|
log.debug("new keyboard group: '{s}'", .{name});
|
||||||
|
|
||||||
|
const node = try util.gpa.create(std.TailQueue(KeyboardGroup).Node);
|
||||||
|
errdefer util.gpa.destroy(node);
|
||||||
|
|
||||||
|
const wlr_group = try wlr.KeyboardGroup.create();
|
||||||
|
errdefer wlr_group.destroy();
|
||||||
|
|
||||||
|
const owned_name = try util.gpa.dupe(u8, name);
|
||||||
|
errdefer util.gpa.free(owned_name);
|
||||||
|
|
||||||
|
node.data = .{
|
||||||
|
.wlr_group = wlr_group,
|
||||||
|
.name = owned_name,
|
||||||
|
.seat = seat,
|
||||||
|
};
|
||||||
|
|
||||||
|
seat.addDevice(&wlr_group.keyboard.base);
|
||||||
|
seat.keyboard_groups.append(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(group: *KeyboardGroup) void {
|
||||||
|
log.debug("destroying keyboard group: '{s}'", .{group.name});
|
||||||
|
|
||||||
|
util.gpa.free(group.name);
|
||||||
|
|
||||||
|
for (group.globs.items) |glob| {
|
||||||
|
util.gpa.free(glob);
|
||||||
|
}
|
||||||
|
group.globs.deinit(util.gpa);
|
||||||
|
|
||||||
|
group.wlr_group.destroy();
|
||||||
|
|
||||||
|
const node: *std.TailQueue(KeyboardGroup).Node = @fieldParentPtr("data", group);
|
||||||
|
group.seat.keyboard_groups.remove(node);
|
||||||
|
util.gpa.destroy(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void {
|
||||||
|
for (group.globs.items) |glob| {
|
||||||
|
if (mem.eql(u8, glob, new_id)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("keyboard group '{s}' adding identifier: '{s}'", .{ group.name, new_id });
|
||||||
|
|
||||||
|
const owned_id = try util.gpa.dupe(u8, new_id);
|
||||||
|
errdefer util.gpa.free(owned_id);
|
||||||
|
|
||||||
|
// Glob is validated in the command handler.
|
||||||
|
try group.globs.append(util.gpa, owned_id);
|
||||||
|
errdefer {
|
||||||
|
// Not used now, but if at any point this function is modified to that
|
||||||
|
// it may return an error after the glob pattern is added to the list,
|
||||||
|
// the list will have a pointer to freed memory in its last position.
|
||||||
|
_ = group.globs.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any existing matching keyboards to the group.
|
||||||
|
var it = server.input_manager.devices.iterator(.forward);
|
||||||
|
while (it.next()) |device| {
|
||||||
|
if (device.seat != group.seat) continue;
|
||||||
|
if (device.wlr_device.type != .keyboard) continue;
|
||||||
|
|
||||||
|
if (globber.match(device.identifier, new_id)) {
|
||||||
|
log.debug("found existing matching keyboard; adding to group", .{});
|
||||||
|
|
||||||
|
if (!group.wlr_group.addKeyboard(device.wlr_device.toKeyboard())) {
|
||||||
|
// wlroots logs an error message to explain why this failed.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue, because we may have more than one device with the exact
|
||||||
|
// same identifier. That is in fact one reason for the keyboard group
|
||||||
|
// feature to exist in the first place.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn removeIdentifier(group: *KeyboardGroup, id: []const u8) !void {
|
||||||
|
for (group.globs.items, 0..) |glob, index| {
|
||||||
|
if (mem.eql(u8, glob, id)) {
|
||||||
|
_ = group.globs.orderedRemove(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = server.input_manager.devices.iterator(.forward);
|
||||||
|
while (it.next()) |device| {
|
||||||
|
if (device.seat != group.seat) continue;
|
||||||
|
if (device.wlr_device.type != .keyboard) continue;
|
||||||
|
|
||||||
|
if (globber.match(device.identifier, id)) {
|
||||||
|
const wlr_keyboard = device.wlr_device.toKeyboard();
|
||||||
|
assert(wlr_keyboard.group == group.wlr_group);
|
||||||
|
group.wlr_group.removeKeyboard(wlr_keyboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -43,7 +43,7 @@ commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit)
|
|||||||
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
|
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
|
||||||
|
|
||||||
pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
|
pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
|
||||||
const output: *Output = @alignCast(@ptrCast(wlr_layer_surface.output.?.data));
|
const output: *Output = @ptrFromInt(wlr_layer_surface.output.?.data);
|
||||||
const layer_surface = try util.gpa.create(LayerSurface);
|
const layer_surface = try util.gpa.create(LayerSurface);
|
||||||
errdefer util.gpa.destroy(layer_surface);
|
errdefer util.gpa.destroy(layer_surface);
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
|
|||||||
try SceneNodeData.attach(&layer_surface.scene_layer_surface.tree.node, .{ .layer_surface = layer_surface });
|
try SceneNodeData.attach(&layer_surface.scene_layer_surface.tree.node, .{ .layer_surface = layer_surface });
|
||||||
try SceneNodeData.attach(&layer_surface.popup_tree.node, .{ .layer_surface = layer_surface });
|
try SceneNodeData.attach(&layer_surface.popup_tree.node, .{ .layer_surface = layer_surface });
|
||||||
|
|
||||||
wlr_layer_surface.surface.data = &layer_surface.scene_layer_surface.tree.node;
|
wlr_layer_surface.surface.data = @intFromPtr(&layer_surface.scene_layer_surface.tree.node);
|
||||||
|
|
||||||
wlr_layer_surface.events.destroy.add(&layer_surface.destroy);
|
wlr_layer_surface.events.destroy.add(&layer_surface.destroy);
|
||||||
wlr_layer_surface.surface.events.map.add(&layer_surface.map);
|
wlr_layer_surface.surface.events.map.add(&layer_surface.map);
|
||||||
@ -82,14 +82,13 @@ fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurfa
|
|||||||
layer_surface.map.link.remove();
|
layer_surface.map.link.remove();
|
||||||
layer_surface.unmap.link.remove();
|
layer_surface.unmap.link.remove();
|
||||||
layer_surface.commit.link.remove();
|
layer_surface.commit.link.remove();
|
||||||
layer_surface.new_popup.link.remove();
|
|
||||||
|
|
||||||
layer_surface.destroyPopups();
|
layer_surface.destroyPopups();
|
||||||
|
|
||||||
layer_surface.popup_tree.node.destroy();
|
layer_surface.popup_tree.node.destroy();
|
||||||
|
|
||||||
// The wlr_surface may outlive the wlr_layer_surface so we must clean up the user data.
|
// The wlr_surface may outlive the wlr_layer_surface so we must clean up the user data.
|
||||||
layer_surface.wlr_layer_surface.surface.data = null;
|
layer_surface.wlr_layer_surface.surface.data = 0;
|
||||||
|
|
||||||
util.gpa.destroy(layer_surface);
|
util.gpa.destroy(layer_surface);
|
||||||
}
|
}
|
||||||
@ -157,7 +156,7 @@ fn handleKeyboardInteractiveExclusive(output: *Output, consider: ?*LayerSurface)
|
|||||||
var it = tree.children.iterator(.reverse);
|
var it = tree.children.iterator(.reverse);
|
||||||
while (it.next()) |node| {
|
while (it.next()) |node| {
|
||||||
assert(node.type == .tree);
|
assert(node.type == .tree);
|
||||||
if (@as(?*SceneNodeData, @alignCast(@ptrCast(node.data)))) |node_data| {
|
if (@as(?*SceneNodeData, @ptrFromInt(node.data))) |node_data| {
|
||||||
const layer_surface = node_data.data.layer_surface;
|
const layer_surface = node_data.data.layer_surface;
|
||||||
const wlr_layer_surface = layer_surface.wlr_layer_surface;
|
const wlr_layer_surface = layer_surface.wlr_layer_surface;
|
||||||
if (wlr_layer_surface.surface.mapped and
|
if (wlr_layer_surface.surface.mapped and
|
||||||
|
@ -47,7 +47,7 @@ pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namesp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = try util.gpa.create(std.DoublyLinkedList(Layout).Node);
|
const node = try util.gpa.create(std.TailQueue(Layout).Node);
|
||||||
errdefer util.gpa.destroy(node);
|
errdefer util.gpa.destroy(node);
|
||||||
node.data = .{
|
node.data = .{
|
||||||
.layout_v3 = layout_v3,
|
.layout_v3 = layout_v3,
|
||||||
@ -186,7 +186,7 @@ pub fn destroy(layout: *Layout) void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Remove layout from the list
|
// Remove layout from the list
|
||||||
const node: *std.DoublyLinkedList(Layout).Node = @fieldParentPtr("data", layout);
|
const node: *std.TailQueue(Layout).Node = @fieldParentPtr("data", layout);
|
||||||
layout.output.layouts.remove(node);
|
layout.output.layouts.remove(node);
|
||||||
|
|
||||||
// If we are the currently active layout of an output, clean up.
|
// If we are the currently active layout of an output, clean up.
|
||||||
|
@ -68,7 +68,7 @@ fn handleRequest(
|
|||||||
.get_layout => |req| {
|
.get_layout => |req| {
|
||||||
// Ignore if the output is inert
|
// Ignore if the output is inert
|
||||||
const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return;
|
const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return;
|
||||||
const output: *Output = @alignCast(@ptrCast(wlr_output.data));
|
const output: *Output = @ptrFromInt(wlr_output.data);
|
||||||
|
|
||||||
log.debug("bind layout '{s}' on output '{s}'", .{ req.namespace, output.wlr_output.name });
|
log.debug("bind layout '{s}' on output '{s}'", .{ req.namespace, output.wlr_output.name });
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ pub fn updateLockSurfaceSize(manager: *LockManager, output: *Output) void {
|
|||||||
|
|
||||||
var it = lock.surfaces.iterator(.forward);
|
var it = lock.surfaces.iterator(.forward);
|
||||||
while (it.next()) |wlr_lock_surface| {
|
while (it.next()) |wlr_lock_surface| {
|
||||||
const lock_surface: *LockSurface = @alignCast(@ptrCast(wlr_lock_surface.data));
|
const lock_surface: *LockSurface = @ptrFromInt(wlr_lock_surface.data);
|
||||||
if (output == lock_surface.getOutput()) {
|
if (output == lock_surface.getOutput()) {
|
||||||
lock_surface.configure();
|
lock_surface.configure();
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
|
|||||||
.wlr_lock_surface = wlr_lock_surface,
|
.wlr_lock_surface = wlr_lock_surface,
|
||||||
.lock = lock,
|
.lock = lock,
|
||||||
};
|
};
|
||||||
wlr_lock_surface.data = lock_surface;
|
wlr_lock_surface.data = @intFromPtr(lock_surface);
|
||||||
|
|
||||||
const output = lock_surface.getOutput();
|
const output = lock_surface.getOutput();
|
||||||
const tree = try output.locked_content.createSceneSubsurfaceTree(wlr_lock_surface.surface);
|
const tree = try output.locked_content.createSceneSubsurfaceTree(wlr_lock_surface.surface);
|
||||||
@ -52,7 +52,7 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
|
|||||||
|
|
||||||
try SceneNodeData.attach(&tree.node, .{ .lock_surface = lock_surface });
|
try SceneNodeData.attach(&tree.node, .{ .lock_surface = lock_surface });
|
||||||
|
|
||||||
wlr_lock_surface.surface.data = &tree.node;
|
wlr_lock_surface.surface.data = @intFromPtr(&tree.node);
|
||||||
|
|
||||||
wlr_lock_surface.surface.events.map.add(&lock_surface.map);
|
wlr_lock_surface.surface.events.map.add(&lock_surface.map);
|
||||||
wlr_lock_surface.events.destroy.add(&lock_surface.surface_destroy);
|
wlr_lock_surface.events.destroy.add(&lock_surface.surface_destroy);
|
||||||
@ -65,7 +65,7 @@ pub fn destroy(lock_surface: *LockSurface) void {
|
|||||||
var surface_it = lock_surface.lock.surfaces.iterator(.forward);
|
var surface_it = lock_surface.lock.surfaces.iterator(.forward);
|
||||||
const new_focus: Seat.FocusTarget = while (surface_it.next()) |surface| {
|
const new_focus: Seat.FocusTarget = while (surface_it.next()) |surface| {
|
||||||
if (surface != lock_surface.wlr_lock_surface)
|
if (surface != lock_surface.wlr_lock_surface)
|
||||||
break .{ .lock_surface = @alignCast(@ptrCast(surface.data)) };
|
break .{ .lock_surface = @ptrFromInt(surface.data) };
|
||||||
} else .none;
|
} else .none;
|
||||||
|
|
||||||
var seat_it = server.input_manager.seats.first;
|
var seat_it = server.input_manager.seats.first;
|
||||||
@ -86,13 +86,13 @@ pub fn destroy(lock_surface: *LockSurface) void {
|
|||||||
lock_surface.surface_destroy.link.remove();
|
lock_surface.surface_destroy.link.remove();
|
||||||
|
|
||||||
// The wlr_surface may outlive the wlr_lock_surface so we must clean up the user data.
|
// The wlr_surface may outlive the wlr_lock_surface so we must clean up the user data.
|
||||||
lock_surface.wlr_lock_surface.surface.data = null;
|
lock_surface.wlr_lock_surface.surface.data = 0;
|
||||||
|
|
||||||
util.gpa.destroy(lock_surface);
|
util.gpa.destroy(lock_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOutput(lock_surface: *LockSurface) *Output {
|
pub fn getOutput(lock_surface: *LockSurface) *Output {
|
||||||
return @alignCast(@ptrCast(lock_surface.wlr_lock_surface.output.data));
|
return @ptrFromInt(lock_surface.wlr_lock_surface.output.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure(lock_surface: *LockSurface) void {
|
pub fn configure(lock_surface: *LockSurface) void {
|
||||||
|
@ -125,6 +125,10 @@ lock_render_state: enum {
|
|||||||
lock_surface,
|
lock_surface,
|
||||||
} = .blanked,
|
} = .blanked,
|
||||||
|
|
||||||
|
/// Set to true if a gamma control client makes a set gamma request.
|
||||||
|
/// This request is handled while rendering the next frame in handleFrame().
|
||||||
|
gamma_dirty: bool = false,
|
||||||
|
|
||||||
/// The state of the output that is directly acted upon/modified through user input.
|
/// The state of the output that is directly acted upon/modified through user input.
|
||||||
///
|
///
|
||||||
/// Pending state will be copied to the inflight state and communicated to clients
|
/// Pending state will be copied to the inflight state and communicated to clients
|
||||||
@ -167,7 +171,7 @@ previous_tags: u32 = 1 << 0,
|
|||||||
attach_mode: ?Config.AttachMode = null,
|
attach_mode: ?Config.AttachMode = null,
|
||||||
|
|
||||||
/// List of all layouts
|
/// List of all layouts
|
||||||
layouts: std.DoublyLinkedList(Layout) = .{},
|
layouts: std.TailQueue(Layout) = .{},
|
||||||
|
|
||||||
/// The current layout namespace of the output. If null,
|
/// The current layout namespace of the output. If null,
|
||||||
/// config.default_layout_namespace should be used instead.
|
/// config.default_layout_namespace should be used instead.
|
||||||
@ -291,7 +295,7 @@ pub fn create(wlr_output: *wlr.Output) !void {
|
|||||||
},
|
},
|
||||||
.status = undefined,
|
.status = undefined,
|
||||||
};
|
};
|
||||||
wlr_output.data = output;
|
wlr_output.data = @intFromPtr(output);
|
||||||
|
|
||||||
output.pending.focus_stack.init();
|
output.pending.focus_stack.init();
|
||||||
output.pending.wm_stack.init();
|
output.pending.wm_stack.init();
|
||||||
@ -360,7 +364,7 @@ fn sendLayerConfigures(
|
|||||||
var it = tree.children.safeIterator(.forward);
|
var it = tree.children.safeIterator(.forward);
|
||||||
while (it.next()) |node| {
|
while (it.next()) |node| {
|
||||||
assert(node.type == .tree);
|
assert(node.type == .tree);
|
||||||
if (@as(?*SceneNodeData, @alignCast(@ptrCast(node.data)))) |node_data| {
|
if (@as(?*SceneNodeData, @ptrFromInt(node.data))) |node_data| {
|
||||||
const layer_surface = node_data.data.layer_surface;
|
const layer_surface = node_data.data.layer_surface;
|
||||||
|
|
||||||
if (!layer_surface.wlr_layer_surface.initialized) continue;
|
if (!layer_surface.wlr_layer_surface.initialized) continue;
|
||||||
@ -389,15 +393,11 @@ fn sendLayerConfigures(
|
|||||||
usable_box.* = new_usable_box;
|
usable_box.* = new_usable_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
const x = layer_surface.scene_layer_surface.tree.node.x;
|
layer_surface.popup_tree.node.setPosition(
|
||||||
const y = layer_surface.scene_layer_surface.tree.node.y;
|
layer_surface.scene_layer_surface.tree.node.x,
|
||||||
layer_surface.popup_tree.node.setPosition(x, y);
|
layer_surface.scene_layer_surface.tree.node.y,
|
||||||
layer_surface.scene_layer_surface.tree.node.subsurfaceTreeSetClip(&.{
|
);
|
||||||
.x = -x,
|
layer_surface.scene_layer_surface.tree.node.subsurfaceTreeSetClip(&full_box);
|
||||||
.y = -y,
|
|
||||||
.width = full_box.width,
|
|
||||||
.height = full_box.height,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,7 +429,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
|||||||
|
|
||||||
if (output.layout_namespace) |namespace| util.gpa.free(namespace);
|
if (output.layout_namespace) |namespace| util.gpa.free(namespace);
|
||||||
|
|
||||||
output.wlr_output.data = null;
|
output.wlr_output.data = 0;
|
||||||
|
|
||||||
util.gpa.destroy(output);
|
util.gpa.destroy(output);
|
||||||
|
|
||||||
@ -476,6 +476,7 @@ pub fn applyState(output: *Output, state: *wlr.Output.State) error{CommitFailed}
|
|||||||
|
|
||||||
fn handleEnableDisable(output: *Output) void {
|
fn handleEnableDisable(output: *Output) void {
|
||||||
output.updateLockRenderStateOnEnableDisable();
|
output.updateLockRenderStateOnEnableDisable();
|
||||||
|
output.gamma_dirty = true;
|
||||||
|
|
||||||
if (output.wlr_output.enabled) {
|
if (output.wlr_output.enabled) {
|
||||||
// Add the output to root.active_outputs and the output layout if it has not
|
// Add the output to root.active_outputs and the output layout if it has not
|
||||||
@ -527,21 +528,35 @@ fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
|||||||
|
|
||||||
// TODO this should probably be retried on failure
|
// TODO this should probably be retried on failure
|
||||||
output.renderAndCommit(scene_output) catch |err| switch (err) {
|
output.renderAndCommit(scene_output) catch |err| switch (err) {
|
||||||
|
error.OutOfMemory => log.err("out of memory", .{}),
|
||||||
error.CommitFailed => log.err("output commit failed for {s}", .{output.wlr_output.name}),
|
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: posix.timespec = undefined;
|
||||||
|
posix.clock_gettime(posix.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
|
||||||
scene_output.sendFrameDone(&now);
|
scene_output.sendFrameDone(&now);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderAndCommit(output: *Output, scene_output: *wlr.SceneOutput) !void {
|
fn renderAndCommit(output: *Output, scene_output: *wlr.SceneOutput) !void {
|
||||||
if (!scene_output.needsFrame()) return;
|
|
||||||
|
|
||||||
var state = wlr.Output.State.init();
|
var state = wlr.Output.State.init();
|
||||||
defer state.finish();
|
defer state.finish();
|
||||||
|
|
||||||
if (!scene_output.buildState(&state, null)) return error.CommitFailed;
|
if (!scene_output.buildState(&state, null)) return error.CommitFailed;
|
||||||
|
|
||||||
|
if (output.gamma_dirty) {
|
||||||
|
const control = server.root.gamma_control_manager.getControl(output.wlr_output);
|
||||||
|
if (!wlr.GammaControlV1.apply(control, &state)) return error.OutOfMemory;
|
||||||
|
|
||||||
|
if (!output.wlr_output.testState(&state)) {
|
||||||
|
wlr.GammaControlV1.sendFailedAndDestroy(control);
|
||||||
|
state.clearGammaLut();
|
||||||
|
// If the backend does not support gamma LUTs it will reject any
|
||||||
|
// state with the gamma LUT committed bit set even if the state
|
||||||
|
// has a null LUT. The wayland backend for example has this behavior.
|
||||||
|
state.committed.gamma_lut = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (output.current.fullscreen) |fullscreen| {
|
if (output.current.fullscreen) |fullscreen| {
|
||||||
if (fullscreen.allowTearing()) {
|
if (fullscreen.allowTearing()) {
|
||||||
state.tearing_page_flip = true;
|
state.tearing_page_flip = true;
|
||||||
@ -556,6 +571,8 @@ fn renderAndCommit(output: *Output, scene_output: *wlr.SceneOutput) !void {
|
|||||||
|
|
||||||
if (!output.wlr_output.commitState(&state)) return error.CommitFailed;
|
if (!output.wlr_output.commitState(&state)) return error.CommitFailed;
|
||||||
|
|
||||||
|
output.gamma_dirty = false;
|
||||||
|
|
||||||
if (server.lock_manager.state == .locked or
|
if (server.lock_manager.state == .locked or
|
||||||
(server.lock_manager.state == .waiting_for_lock_surfaces and output.locked_content.node.enabled) or
|
(server.lock_manager.state == .waiting_for_lock_surfaces and output.locked_content.node.enabled) or
|
||||||
server.lock_manager.state == .waiting_for_blank)
|
server.lock_manager.state == .waiting_for_blank)
|
||||||
|
@ -47,7 +47,7 @@ commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit)
|
|||||||
node_destroy: wl.Listener(void) = wl.Listener(void).init(handleNodeDestroy),
|
node_destroy: wl.Listener(void) = wl.Listener(void).init(handleNodeDestroy),
|
||||||
|
|
||||||
pub fn create(wlr_constraint: *wlr.PointerConstraintV1) error{OutOfMemory}!void {
|
pub fn create(wlr_constraint: *wlr.PointerConstraintV1) error{OutOfMemory}!void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(wlr_constraint.seat.data);
|
||||||
|
|
||||||
const constraint = try util.gpa.create(PointerConstraint);
|
const constraint = try util.gpa.create(PointerConstraint);
|
||||||
errdefer util.gpa.destroy(constraint);
|
errdefer util.gpa.destroy(constraint);
|
||||||
@ -55,7 +55,7 @@ pub fn create(wlr_constraint: *wlr.PointerConstraintV1) error{OutOfMemory}!void
|
|||||||
constraint.* = .{
|
constraint.* = .{
|
||||||
.wlr_constraint = wlr_constraint,
|
.wlr_constraint = wlr_constraint,
|
||||||
};
|
};
|
||||||
wlr_constraint.data = constraint;
|
wlr_constraint.data = @intFromPtr(constraint);
|
||||||
|
|
||||||
wlr_constraint.events.destroy.add(&constraint.destroy);
|
wlr_constraint.events.destroy.add(&constraint.destroy);
|
||||||
wlr_constraint.surface.events.commit.add(&constraint.commit);
|
wlr_constraint.surface.events.commit.add(&constraint.commit);
|
||||||
@ -70,7 +70,7 @@ pub fn create(wlr_constraint: *wlr.PointerConstraintV1) error{OutOfMemory}!void
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybeActivate(constraint: *PointerConstraint) void {
|
pub fn maybeActivate(constraint: *PointerConstraint) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(constraint.wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(constraint.wlr_constraint.seat.data);
|
||||||
|
|
||||||
assert(seat.cursor.constraint == constraint);
|
assert(seat.cursor.constraint == constraint);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ pub fn maybeActivate(constraint: *PointerConstraint) void {
|
|||||||
|
|
||||||
/// Called when the cursor position or content in the scene graph changes
|
/// Called when the cursor position or content in the scene graph changes
|
||||||
pub fn updateState(constraint: *PointerConstraint) void {
|
pub fn updateState(constraint: *PointerConstraint) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(constraint.wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(constraint.wlr_constraint.seat.data);
|
||||||
|
|
||||||
constraint.maybeActivate();
|
constraint.maybeActivate();
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ pub fn confine(constraint: *PointerConstraint, dx: *f64, dy: *f64) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate(constraint: *PointerConstraint) void {
|
pub fn deactivate(constraint: *PointerConstraint) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(constraint.wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(constraint.wlr_constraint.seat.data);
|
||||||
|
|
||||||
assert(seat.cursor.constraint == constraint);
|
assert(seat.cursor.constraint == constraint);
|
||||||
assert(constraint.state == .active);
|
assert(constraint.state == .active);
|
||||||
@ -167,7 +167,7 @@ pub fn deactivate(constraint: *PointerConstraint) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn warpToHintIfSet(constraint: *PointerConstraint) void {
|
fn warpToHintIfSet(constraint: *PointerConstraint) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(constraint.wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(constraint.wlr_constraint.seat.data);
|
||||||
|
|
||||||
if (constraint.wlr_constraint.current.cursor_hint.enabled) {
|
if (constraint.wlr_constraint.current.cursor_hint.enabled) {
|
||||||
var lx: i32 = undefined;
|
var lx: i32 = undefined;
|
||||||
@ -190,7 +190,7 @@ fn handleNodeDestroy(listener: *wl.Listener(void)) void {
|
|||||||
|
|
||||||
fn handleDestroy(listener: *wl.Listener(*wlr.PointerConstraintV1), _: *wlr.PointerConstraintV1) void {
|
fn handleDestroy(listener: *wl.Listener(*wlr.PointerConstraintV1), _: *wlr.PointerConstraintV1) void {
|
||||||
const constraint: *PointerConstraint = @fieldParentPtr("destroy", listener);
|
const constraint: *PointerConstraint = @fieldParentPtr("destroy", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(constraint.wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(constraint.wlr_constraint.seat.data);
|
||||||
|
|
||||||
if (constraint.state == .active) {
|
if (constraint.state == .active) {
|
||||||
// We can't simply call deactivate() here as it calls sendDeactivated(),
|
// We can't simply call deactivate() here as it calls sendDeactivated(),
|
||||||
@ -215,7 +215,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.PointerConstraintV1), _: *wlr.Point
|
|||||||
// the surface changes.
|
// the surface changes.
|
||||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||||
const constraint: *PointerConstraint = @fieldParentPtr("commit", listener);
|
const constraint: *PointerConstraint = @fieldParentPtr("commit", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(constraint.wlr_constraint.seat.data));
|
const seat: *Seat = @ptrFromInt(constraint.wlr_constraint.seat.data);
|
||||||
|
|
||||||
switch (constraint.state) {
|
switch (constraint.state) {
|
||||||
.active => |state| {
|
.active => |state| {
|
||||||
|
@ -97,6 +97,8 @@ power_manager_set_mode: wl.Listener(*wlr.OutputPowerManagerV1.event.SetMode) =
|
|||||||
wl.Listener(*wlr.OutputPowerManagerV1.event.SetMode).init(handlePowerManagerSetMode),
|
wl.Listener(*wlr.OutputPowerManagerV1.event.SetMode).init(handlePowerManagerSetMode),
|
||||||
|
|
||||||
gamma_control_manager: *wlr.GammaControlManagerV1,
|
gamma_control_manager: *wlr.GammaControlManagerV1,
|
||||||
|
gamma_control_set_gamma: wl.Listener(*wlr.GammaControlManagerV1.event.SetGamma) =
|
||||||
|
wl.Listener(*wlr.GammaControlManagerV1.event.SetGamma).init(handleSetGamma),
|
||||||
|
|
||||||
/// A list of all outputs
|
/// A list of all outputs
|
||||||
all_outputs: wl.list.Head(Output, .all_link),
|
all_outputs: wl.list.Head(Output, .all_link),
|
||||||
@ -121,11 +123,6 @@ pub fn init(root: *Root) !void {
|
|||||||
const scene = try wlr.Scene.create();
|
const scene = try wlr.Scene.create();
|
||||||
errdefer scene.tree.node.destroy();
|
errdefer scene.tree.node.destroy();
|
||||||
|
|
||||||
const gamma_control_manager = try wlr.GammaControlManagerV1.create(server.wl_server);
|
|
||||||
scene.setGammaControlManagerV1(gamma_control_manager);
|
|
||||||
|
|
||||||
if (server.linux_dmabuf) |linux_dmabuf| scene.setLinuxDmabufV1(linux_dmabuf);
|
|
||||||
|
|
||||||
const interactive_content = try scene.tree.createSceneTree();
|
const interactive_content = try scene.tree.createSceneTree();
|
||||||
const drag_icons = try scene.tree.createSceneTree();
|
const drag_icons = try scene.tree.createSceneTree();
|
||||||
const hidden_tree = try scene.tree.createSceneTree();
|
const hidden_tree = try scene.tree.createSceneTree();
|
||||||
@ -166,11 +163,11 @@ pub fn init(root: *Root) !void {
|
|||||||
.all_outputs = undefined,
|
.all_outputs = undefined,
|
||||||
.active_outputs = undefined,
|
.active_outputs = undefined,
|
||||||
|
|
||||||
.presentation = try wlr.Presentation.create(server.wl_server, server.backend, 2),
|
.presentation = try wlr.Presentation.create(server.wl_server, server.backend),
|
||||||
.xdg_output_manager = try wlr.XdgOutputManagerV1.create(server.wl_server, output_layout),
|
.xdg_output_manager = try wlr.XdgOutputManagerV1.create(server.wl_server, output_layout),
|
||||||
.output_manager = try wlr.OutputManagerV1.create(server.wl_server),
|
.output_manager = try wlr.OutputManagerV1.create(server.wl_server),
|
||||||
.power_manager = try wlr.OutputPowerManagerV1.create(server.wl_server),
|
.power_manager = try wlr.OutputPowerManagerV1.create(server.wl_server),
|
||||||
.gamma_control_manager = gamma_control_manager,
|
.gamma_control_manager = try wlr.GammaControlManagerV1.create(server.wl_server),
|
||||||
.transaction_timeout = transaction_timeout,
|
.transaction_timeout = transaction_timeout,
|
||||||
};
|
};
|
||||||
root.hidden.pending.focus_stack.init();
|
root.hidden.pending.focus_stack.init();
|
||||||
@ -190,14 +187,10 @@ pub fn init(root: *Root) !void {
|
|||||||
root.output_manager.events.@"test".add(&root.manager_test);
|
root.output_manager.events.@"test".add(&root.manager_test);
|
||||||
root.output_layout.events.change.add(&root.layout_change);
|
root.output_layout.events.change.add(&root.layout_change);
|
||||||
root.power_manager.events.set_mode.add(&root.power_manager_set_mode);
|
root.power_manager.events.set_mode.add(&root.power_manager_set_mode);
|
||||||
|
root.gamma_control_manager.events.set_gamma.add(&root.gamma_control_set_gamma);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(root: *Root) void {
|
pub fn deinit(root: *Root) void {
|
||||||
root.manager_apply.link.remove();
|
|
||||||
root.manager_test.link.remove();
|
|
||||||
root.layout_change.link.remove();
|
|
||||||
root.power_manager_set_mode.link.remove();
|
|
||||||
|
|
||||||
root.output_layout.destroy();
|
root.output_layout.destroy();
|
||||||
root.transaction_timeout.remove();
|
root.transaction_timeout.remove();
|
||||||
}
|
}
|
||||||
@ -330,7 +323,7 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
|
|||||||
var it = tree.children.safeIterator(.forward);
|
var it = tree.children.safeIterator(.forward);
|
||||||
while (it.next()) |scene_node| {
|
while (it.next()) |scene_node| {
|
||||||
assert(scene_node.type == .tree);
|
assert(scene_node.type == .tree);
|
||||||
if (@as(?*SceneNodeData, @alignCast(@ptrCast(scene_node.data)))) |node_data| {
|
if (@as(?*SceneNodeData, @ptrFromInt(scene_node.data))) |node_data| {
|
||||||
node_data.data.layer_surface.wlr_layer_surface.destroy();
|
node_data.data.layer_surface.wlr_layer_surface.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -805,7 +798,7 @@ fn processOutputConfig(
|
|||||||
var it = config.heads.iterator(.forward);
|
var it = config.heads.iterator(.forward);
|
||||||
while (it.next()) |head| {
|
while (it.next()) |head| {
|
||||||
const wlr_output = head.state.output;
|
const wlr_output = head.state.output;
|
||||||
const output: *Output = @alignCast(@ptrCast(wlr_output.data));
|
const output: *Output = @ptrFromInt(wlr_output.data);
|
||||||
|
|
||||||
var proposed_state = wlr.Output.State.init();
|
var proposed_state = wlr.Output.State.init();
|
||||||
head.state.apply(&proposed_state);
|
head.state.apply(&proposed_state);
|
||||||
@ -857,7 +850,7 @@ fn handlePowerManagerSetMode(
|
|||||||
event: *wlr.OutputPowerManagerV1.event.SetMode,
|
event: *wlr.OutputPowerManagerV1.event.SetMode,
|
||||||
) void {
|
) void {
|
||||||
// The output may have been destroyed, in which case there is nothing to do
|
// The output may have been destroyed, in which case there is nothing to do
|
||||||
const output: *Output = @alignCast(@ptrCast(event.output.data orelse return));
|
const output = @as(?*Output, @ptrFromInt(event.output.data)) orelse return;
|
||||||
|
|
||||||
std.log.debug("client requested dpms {s} for output {s}", .{
|
std.log.debug("client requested dpms {s} for output {s}", .{
|
||||||
@tagName(event.mode),
|
@tagName(event.mode),
|
||||||
@ -887,4 +880,18 @@ fn handlePowerManagerSetMode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
output.updateLockRenderStateOnEnableDisable();
|
output.updateLockRenderStateOnEnableDisable();
|
||||||
|
output.gamma_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleSetGamma(
|
||||||
|
_: *wl.Listener(*wlr.GammaControlManagerV1.event.SetGamma),
|
||||||
|
event: *wlr.GammaControlManagerV1.event.SetGamma,
|
||||||
|
) void {
|
||||||
|
// The output may have been destroyed, in which case there is nothing to do
|
||||||
|
const output = @as(?*Output, @ptrFromInt(event.output.data)) orelse return;
|
||||||
|
|
||||||
|
std.log.debug("client requested to set gamma", .{});
|
||||||
|
|
||||||
|
output.gamma_dirty = true;
|
||||||
|
output.wlr_output.scheduleFrame();
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ pub fn attach(node: *wlr.SceneNode, data: Data) error{OutOfMemory}!void {
|
|||||||
.node = node,
|
.node = node,
|
||||||
.data = data,
|
.data = data,
|
||||||
};
|
};
|
||||||
node.data = scene_node_data;
|
node.data = @intFromPtr(scene_node_data);
|
||||||
|
|
||||||
node.events.destroy.add(&scene_node_data.destroy);
|
node.events.destroy.add(&scene_node_data.destroy);
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ pub fn attach(node: *wlr.SceneNode, data: Data) error{OutOfMemory}!void {
|
|||||||
pub fn fromNode(node: *wlr.SceneNode) ?*SceneNodeData {
|
pub fn fromNode(node: *wlr.SceneNode) ?*SceneNodeData {
|
||||||
var n = node;
|
var n = node;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (@as(?*SceneNodeData, @alignCast(@ptrCast(n.data)))) |scene_node_data| {
|
if (@as(?*SceneNodeData, @ptrFromInt(n.data))) |scene_node_data| {
|
||||||
return scene_node_data;
|
return scene_node_data;
|
||||||
}
|
}
|
||||||
if (n.parent) |parent_tree| {
|
if (n.parent) |parent_tree| {
|
||||||
@ -66,7 +66,7 @@ pub fn fromNode(node: *wlr.SceneNode) ?*SceneNodeData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromSurface(surface: *wlr.Surface) ?*SceneNodeData {
|
pub fn fromSurface(surface: *wlr.Surface) ?*SceneNodeData {
|
||||||
if (@as(?*wlr.SceneNode, @alignCast(@ptrCast(surface.getRootSurface().data)))) |node| {
|
if (@as(?*wlr.SceneNode, @ptrFromInt(surface.getRootSurface().data))) |node| {
|
||||||
return fromNode(node);
|
return fromNode(node);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -76,7 +76,7 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
|
|||||||
const scene_node_data: *SceneNodeData = @fieldParentPtr("destroy", listener);
|
const scene_node_data: *SceneNodeData = @fieldParentPtr("destroy", listener);
|
||||||
|
|
||||||
scene_node_data.destroy.link.remove();
|
scene_node_data.destroy.link.remove();
|
||||||
scene_node_data.node.data = null;
|
scene_node_data.node.data = 0;
|
||||||
|
|
||||||
util.gpa.destroy(scene_node_data);
|
util.gpa.destroy(scene_node_data);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ const InputDevice = @import("InputDevice.zig");
|
|||||||
const InputManager = @import("InputManager.zig");
|
const InputManager = @import("InputManager.zig");
|
||||||
const InputRelay = @import("InputRelay.zig");
|
const InputRelay = @import("InputRelay.zig");
|
||||||
const Keyboard = @import("Keyboard.zig");
|
const Keyboard = @import("Keyboard.zig");
|
||||||
|
const KeyboardGroup = @import("KeyboardGroup.zig");
|
||||||
const LayerSurface = @import("LayerSurface.zig");
|
const LayerSurface = @import("LayerSurface.zig");
|
||||||
const LockSurface = @import("LockSurface.zig");
|
const LockSurface = @import("LockSurface.zig");
|
||||||
const Mapping = @import("Mapping.zig");
|
const Mapping = @import("Mapping.zig");
|
||||||
@ -83,7 +84,7 @@ mapping_repeat_timer: *wl.EventSource,
|
|||||||
/// Currently repeating mapping, if any
|
/// Currently repeating mapping, if any
|
||||||
repeating_mapping: ?*const Mapping = null,
|
repeating_mapping: ?*const Mapping = null,
|
||||||
|
|
||||||
keyboard_group: *wlr.KeyboardGroup,
|
keyboard_groups: std.TailQueue(KeyboardGroup) = .{},
|
||||||
|
|
||||||
/// Currently focused output. Null only when there are no outputs at all.
|
/// Currently focused output. Null only when there are no outputs at all.
|
||||||
focused_output: ?*Output = null,
|
focused_output: ?*Output = null,
|
||||||
@ -120,15 +121,12 @@ pub fn init(seat: *Seat, name: [*:0]const u8) !void {
|
|||||||
.cursor = undefined,
|
.cursor = undefined,
|
||||||
.relay = undefined,
|
.relay = undefined,
|
||||||
.mapping_repeat_timer = mapping_repeat_timer,
|
.mapping_repeat_timer = mapping_repeat_timer,
|
||||||
.keyboard_group = try wlr.KeyboardGroup.create(),
|
|
||||||
};
|
};
|
||||||
seat.wlr_seat.data = seat;
|
seat.wlr_seat.data = @intFromPtr(seat);
|
||||||
|
|
||||||
try seat.cursor.init(seat);
|
try seat.cursor.init(seat);
|
||||||
seat.relay.init();
|
seat.relay.init();
|
||||||
|
|
||||||
try seat.tryAddDevice(&seat.keyboard_group.keyboard.base);
|
|
||||||
|
|
||||||
seat.wlr_seat.events.request_set_selection.add(&seat.request_set_selection);
|
seat.wlr_seat.events.request_set_selection.add(&seat.request_set_selection);
|
||||||
seat.wlr_seat.events.request_start_drag.add(&seat.request_start_drag);
|
seat.wlr_seat.events.request_start_drag.add(&seat.request_start_drag);
|
||||||
seat.wlr_seat.events.start_drag.add(&seat.start_drag);
|
seat.wlr_seat.events.start_drag.add(&seat.start_drag);
|
||||||
@ -144,7 +142,9 @@ pub fn deinit(seat: *Seat) void {
|
|||||||
seat.cursor.deinit();
|
seat.cursor.deinit();
|
||||||
seat.mapping_repeat_timer.remove();
|
seat.mapping_repeat_timer.remove();
|
||||||
|
|
||||||
seat.keyboard_group.destroy();
|
while (seat.keyboard_groups.first) |node| {
|
||||||
|
node.data.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
seat.request_set_selection.link.remove();
|
seat.request_set_selection.link.remove();
|
||||||
seat.request_start_drag.link.remove();
|
seat.request_start_drag.link.remove();
|
||||||
@ -289,7 +289,7 @@ pub fn setFocusRaw(seat: *Seat, new_focus: FocusTarget) void {
|
|||||||
if (seat.cursor.constraint) |constraint| {
|
if (seat.cursor.constraint) |constraint| {
|
||||||
assert(constraint.wlr_constraint == wlr_constraint);
|
assert(constraint.wlr_constraint == wlr_constraint);
|
||||||
} else {
|
} else {
|
||||||
seat.cursor.constraint = @alignCast(@ptrCast(wlr_constraint.data));
|
seat.cursor.constraint = @ptrFromInt(wlr_constraint.data);
|
||||||
assert(seat.cursor.constraint != null);
|
assert(seat.cursor.constraint != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ pub fn keyboardEnterOrLeave(seat: *Seat, target_surface: ?*wlr.Surface) void {
|
|||||||
|
|
||||||
fn keyboardNotifyEnter(seat: *Seat, wlr_surface: *wlr.Surface) void {
|
fn keyboardNotifyEnter(seat: *Seat, wlr_surface: *wlr.Surface) void {
|
||||||
if (seat.wlr_seat.getKeyboard()) |wlr_keyboard| {
|
if (seat.wlr_seat.getKeyboard()) |wlr_keyboard| {
|
||||||
const keyboard: *Keyboard = @alignCast(@ptrCast(wlr_keyboard.data));
|
const keyboard: *Keyboard = @ptrFromInt(wlr_keyboard.data);
|
||||||
|
|
||||||
var keycodes: std.BoundedArray(u32, Keyboard.Pressed.capacity) = .{};
|
var keycodes: std.BoundedArray(u32, Keyboard.Pressed.capacity) = .{};
|
||||||
for (keyboard.pressed.keys.constSlice()) |item| {
|
for (keyboard.pressed.keys.constSlice()) |item| {
|
||||||
|
@ -19,7 +19,6 @@ const Server = @This();
|
|||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const mem = std.mem;
|
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
const wlr = @import("wlroots");
|
const wlr = @import("wlroots");
|
||||||
const wl = @import("wayland").server.wl;
|
const wl = @import("wayland").server.wl;
|
||||||
@ -61,8 +60,8 @@ allocator: *wlr.Allocator,
|
|||||||
security_context_manager: *wlr.SecurityContextManagerV1,
|
security_context_manager: *wlr.SecurityContextManagerV1,
|
||||||
|
|
||||||
shm: *wlr.Shm,
|
shm: *wlr.Shm,
|
||||||
|
drm: ?*wlr.Drm = null,
|
||||||
linux_dmabuf: ?*wlr.LinuxDmabufV1 = null,
|
linux_dmabuf: ?*wlr.LinuxDmabufV1 = null,
|
||||||
linux_drm_syncobj_manager: ?*wlr.LinuxDrmSyncobjManagerV1 = null,
|
|
||||||
single_pixel_buffer_manager: *wlr.SinglePixelBufferManagerV1,
|
single_pixel_buffer_manager: *wlr.SinglePixelBufferManagerV1,
|
||||||
|
|
||||||
viewporter: *wlr.Viewporter,
|
viewporter: *wlr.Viewporter,
|
||||||
@ -87,8 +86,6 @@ foreign_toplevel_manager: *wlr.ForeignToplevelManagerV1,
|
|||||||
|
|
||||||
tearing_control_manager: *wlr.TearingControlManagerV1,
|
tearing_control_manager: *wlr.TearingControlManagerV1,
|
||||||
|
|
||||||
alpha_modifier: *wlr.AlphaModifierV1,
|
|
||||||
|
|
||||||
input_manager: InputManager,
|
input_manager: InputManager,
|
||||||
root: Root,
|
root: Root,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -166,8 +163,6 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
|
|||||||
|
|
||||||
.tearing_control_manager = try wlr.TearingControlManagerV1.create(wl_server, 1),
|
.tearing_control_manager = try wlr.TearingControlManagerV1.create(wl_server, 1),
|
||||||
|
|
||||||
.alpha_modifier = try wlr.AlphaModifierV1.create(wl_server),
|
|
||||||
|
|
||||||
.config = try Config.init(),
|
.config = try Config.init(),
|
||||||
|
|
||||||
.root = undefined,
|
.root = undefined,
|
||||||
@ -180,14 +175,14 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (renderer.getTextureFormats(@intFromEnum(wlr.BufferCap.dmabuf)) != null) {
|
if (renderer.getTextureFormats(@intFromEnum(wlr.BufferCap.dmabuf)) != null) {
|
||||||
|
// wl_drm is a legacy interface and all clients should switch to linux_dmabuf.
|
||||||
|
// However, enough widely used clients still rely on wl_drm that the pragmatic option
|
||||||
|
// is to keep it around for the near future.
|
||||||
|
// TODO remove wl_drm support
|
||||||
|
server.drm = try wlr.Drm.create(wl_server, renderer);
|
||||||
|
|
||||||
server.linux_dmabuf = try wlr.LinuxDmabufV1.createWithRenderer(wl_server, 4, renderer);
|
server.linux_dmabuf = try wlr.LinuxDmabufV1.createWithRenderer(wl_server, 4, renderer);
|
||||||
}
|
}
|
||||||
if (renderer.features.timeline and backend.features.timeline) {
|
|
||||||
const drm_fd = renderer.getDrmFd();
|
|
||||||
if (drm_fd >= 0) {
|
|
||||||
server.linux_drm_syncobj_manager = wlr.LinuxDrmSyncobjManagerV1.create(wl_server, 1, drm_fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (build_options.xwayland and runtime_xwayland) {
|
if (build_options.xwayland and runtime_xwayland) {
|
||||||
server.xwayland = try wlr.Xwayland.create(wl_server, compositor, false);
|
server.xwayland = try wlr.Xwayland.create(wl_server, compositor, false);
|
||||||
@ -233,8 +228,6 @@ pub fn deinit(server: *Server) void {
|
|||||||
|
|
||||||
server.wl_server.destroyClients();
|
server.wl_server.destroyClients();
|
||||||
|
|
||||||
server.input_manager.new_input.link.remove();
|
|
||||||
server.root.new_output.link.remove();
|
|
||||||
server.backend.destroy();
|
server.backend.destroy();
|
||||||
|
|
||||||
// The scene graph needs to be destroyed after the backend but before the renderer
|
// The scene graph needs to be destroyed after the backend but before the renderer
|
||||||
@ -295,27 +288,20 @@ fn globalFilter(client: *const wl.Client, global: *const wl.Global, server: *Ser
|
|||||||
|
|
||||||
/// Returns true if the global is allowlisted for security contexts
|
/// Returns true if the global is allowlisted for security contexts
|
||||||
fn allowlist(server: *Server, global: *const wl.Global) bool {
|
fn allowlist(server: *Server, global: *const wl.Global) bool {
|
||||||
if (server.linux_dmabuf) |linux_dmabuf| {
|
if (server.drm) |drm| if (global == drm.global) return true;
|
||||||
if (global == linux_dmabuf.global) return true;
|
if (server.linux_dmabuf) |linux_dmabuf| if (global == linux_dmabuf.global) return true;
|
||||||
}
|
|
||||||
if (server.linux_drm_syncobj_manager) |linux_drm_syncobj_manager| {
|
|
||||||
if (global == linux_drm_syncobj_manager.global) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We must use the getInterface() approach for dynamically created globals
|
// We must use the getInterface() approach for dynamically created globals
|
||||||
// such as wl_output and wl_seat since the wl_global_create() function will
|
// such as wl_output and wl_seat since the wl_global_create() function will
|
||||||
// advertise the global to clients and invoke this filter before returning
|
// advertise the global to clients and invoke this filter before returning
|
||||||
// the new global pointer.
|
// the new global pointer.
|
||||||
if ((mem.orderZ(u8, global.getInterface().name, "wl_output") == .eq) or
|
//
|
||||||
(mem.orderZ(u8, global.getInterface().name, "wl_seat") == .eq))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For other globals I like the current pointer comparison approach as it
|
// For other globals I like the current pointer comparison approach as it
|
||||||
// should catch river accidentally exposing multiple copies of e.g. wl_shm
|
// should catch river accidentally exposing multiple copies of e.g. wl_shm
|
||||||
// with an assertion failure.
|
// with an assertion failure.
|
||||||
return global == server.shm.global or
|
return global.getInterface() == wl.Output.getInterface() or
|
||||||
|
global.getInterface() == wl.Seat.getInterface() or
|
||||||
|
global == server.shm.global or
|
||||||
global == server.single_pixel_buffer_manager.global or
|
global == server.single_pixel_buffer_manager.global or
|
||||||
global == server.viewporter.global or
|
global == server.viewporter.global or
|
||||||
global == server.fractional_scale_manager.global or
|
global == server.fractional_scale_manager.global or
|
||||||
@ -335,8 +321,7 @@ fn allowlist(server: *Server, global: *const wl.Global) bool {
|
|||||||
global == server.input_manager.tablet_manager.global or
|
global == server.input_manager.tablet_manager.global or
|
||||||
global == server.input_manager.pointer_gestures.global or
|
global == server.input_manager.pointer_gestures.global or
|
||||||
global == server.idle_inhibit_manager.wlr_manager.global or
|
global == server.idle_inhibit_manager.wlr_manager.global or
|
||||||
global == server.tearing_control_manager.global or
|
global == server.tearing_control_manager.global;
|
||||||
global == server.alpha_modifier.global;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the global is blocked for security contexts
|
/// Returns true if the global is blocked for security contexts
|
||||||
@ -505,7 +490,7 @@ fn handleRequestSetCursorShape(
|
|||||||
_: *wl.Listener(*wlr.CursorShapeManagerV1.event.RequestSetShape),
|
_: *wl.Listener(*wlr.CursorShapeManagerV1.event.RequestSetShape),
|
||||||
event: *wlr.CursorShapeManagerV1.event.RequestSetShape,
|
event: *wlr.CursorShapeManagerV1.event.RequestSetShape,
|
||||||
) void {
|
) void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(event.seat_client.seat.data));
|
const seat: *Seat = @ptrFromInt(event.seat_client.seat.data);
|
||||||
|
|
||||||
if (event.tablet_tool) |wp_tool| {
|
if (event.tablet_tool) |wp_tool| {
|
||||||
assert(event.device_type == .tablet_tool);
|
assert(event.device_type == .tablet_tool);
|
||||||
@ -525,7 +510,7 @@ fn handleRequestSetCursorShape(
|
|||||||
// actually has pointer focus first.
|
// actually has pointer focus first.
|
||||||
if (focused_client == event.seat_client) {
|
if (focused_client == event.seat_client) {
|
||||||
const name = wlr.CursorShapeManagerV1.shapeName(event.shape);
|
const name = wlr.CursorShapeManagerV1.shapeName(event.shape);
|
||||||
seat.cursor.setImage(.{ .xcursor = name });
|
seat.cursor.setXcursor(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ fn handleRequest(
|
|||||||
.get_river_output_status => |req| {
|
.get_river_output_status => |req| {
|
||||||
// ignore if the output is inert
|
// ignore if the output is inert
|
||||||
const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return;
|
const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return;
|
||||||
const output: *Output = @alignCast(@ptrCast(wlr_output.data));
|
const output: *Output = @ptrFromInt(wlr_output.data);
|
||||||
|
|
||||||
const resource = zriver.OutputStatusV1.create(
|
const resource = zriver.OutputStatusV1.create(
|
||||||
status_manager_v1.getClient(),
|
status_manager_v1.getClient(),
|
||||||
@ -86,7 +86,7 @@ fn handleRequest(
|
|||||||
.get_river_seat_status => |req| {
|
.get_river_seat_status => |req| {
|
||||||
// ignore if the seat is inert
|
// ignore if the seat is inert
|
||||||
const wlr_seat = wlr.Seat.Client.fromWlSeat(req.seat) orelse return;
|
const wlr_seat = wlr.Seat.Client.fromWlSeat(req.seat) orelse return;
|
||||||
const seat: *Seat = @alignCast(@ptrCast(wlr_seat.seat.data));
|
const seat: *Seat = @ptrFromInt(wlr_seat.seat.data);
|
||||||
|
|
||||||
const node = util.gpa.create(std.SinglyLinkedList(SeatStatus).Node) catch {
|
const node = util.gpa.create(std.SinglyLinkedList(SeatStatus).Node) catch {
|
||||||
status_manager_v1.getClient().postNoMemory();
|
status_manager_v1.getClient().postNoMemory();
|
||||||
|
@ -59,7 +59,7 @@ set_cursor: wl.Listener(*wlr.TabletV2TabletTool.event.SetCursor) =
|
|||||||
wl.Listener(*wlr.TabletV2TabletTool.event.SetCursor).init(handleSetCursor),
|
wl.Listener(*wlr.TabletV2TabletTool.event.SetCursor).init(handleSetCursor),
|
||||||
|
|
||||||
pub fn get(wlr_seat: *wlr.Seat, wlr_tool: *wlr.TabletTool) error{OutOfMemory}!*TabletTool {
|
pub fn get(wlr_seat: *wlr.Seat, wlr_tool: *wlr.TabletTool) error{OutOfMemory}!*TabletTool {
|
||||||
if (@as(?*TabletTool, @alignCast(@ptrCast(wlr_tool.data)))) |tool| {
|
if (@as(?*TabletTool, @ptrFromInt(wlr_tool.data))) |tool| {
|
||||||
return tool;
|
return tool;
|
||||||
} else {
|
} else {
|
||||||
return TabletTool.create(wlr_seat, wlr_tool);
|
return TabletTool.create(wlr_seat, wlr_tool);
|
||||||
@ -81,7 +81,7 @@ fn create(wlr_seat: *wlr.Seat, wlr_tool: *wlr.TabletTool) error{OutOfMemory}!*Ta
|
|||||||
.wlr_cursor = wlr_cursor,
|
.wlr_cursor = wlr_cursor,
|
||||||
};
|
};
|
||||||
|
|
||||||
wlr_tool.data = tool;
|
wlr_tool.data = @intFromPtr(tool);
|
||||||
|
|
||||||
wlr_tool.events.destroy.add(&tool.destroy);
|
wlr_tool.events.destroy.add(&tool.destroy);
|
||||||
tool.wp_tool.events.set_cursor.add(&tool.set_cursor);
|
tool.wp_tool.events.set_cursor.add(&tool.set_cursor);
|
||||||
@ -92,7 +92,7 @@ fn create(wlr_seat: *wlr.Seat, wlr_tool: *wlr.TabletTool) error{OutOfMemory}!*Ta
|
|||||||
fn handleDestroy(listener: *wl.Listener(*wlr.TabletTool), _: *wlr.TabletTool) void {
|
fn handleDestroy(listener: *wl.Listener(*wlr.TabletTool), _: *wlr.TabletTool) void {
|
||||||
const tool: *TabletTool = @fieldParentPtr("destroy", listener);
|
const tool: *TabletTool = @fieldParentPtr("destroy", listener);
|
||||||
|
|
||||||
tool.wp_tool.wlr_tool.data = null;
|
tool.wp_tool.wlr_tool.data = 0;
|
||||||
|
|
||||||
tool.wlr_cursor.destroy();
|
tool.wlr_cursor.destroy();
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ destroy: wl.Listener(*wlr.TextInputV3) =
|
|||||||
wl.Listener(*wlr.TextInputV3).init(handleDestroy),
|
wl.Listener(*wlr.TextInputV3).init(handleDestroy),
|
||||||
|
|
||||||
pub fn create(wlr_text_input: *wlr.TextInputV3) !void {
|
pub fn create(wlr_text_input: *wlr.TextInputV3) !void {
|
||||||
const seat: *Seat = @alignCast(@ptrCast(wlr_text_input.seat.data));
|
const seat: *Seat = @ptrFromInt(wlr_text_input.seat.data);
|
||||||
|
|
||||||
const text_input = try util.gpa.create(TextInput);
|
const text_input = try util.gpa.create(TextInput);
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ pub fn create(wlr_text_input: *wlr.TextInputV3) !void {
|
|||||||
|
|
||||||
fn handleEnable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
fn handleEnable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
||||||
const text_input: *TextInput = @fieldParentPtr("enable", listener);
|
const text_input: *TextInput = @fieldParentPtr("enable", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(text_input.wlr_text_input.seat.data));
|
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
|
||||||
|
|
||||||
if (text_input.wlr_text_input.focused_surface == null) {
|
if (text_input.wlr_text_input.focused_surface == null) {
|
||||||
log.err("client requested to enable text input without focus, ignoring request", .{});
|
log.err("client requested to enable text input without focus, ignoring request", .{});
|
||||||
@ -91,7 +91,7 @@ fn handleEnable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) v
|
|||||||
|
|
||||||
fn handleCommit(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
fn handleCommit(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
||||||
const text_input: *TextInput = @fieldParentPtr("commit", listener);
|
const text_input: *TextInput = @fieldParentPtr("commit", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(text_input.wlr_text_input.seat.data));
|
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
|
||||||
|
|
||||||
if (seat.relay.text_input != text_input) {
|
if (seat.relay.text_input != text_input) {
|
||||||
log.err("inactive text input tried to commit an update, client bug?", .{});
|
log.err("inactive text input tried to commit an update, client bug?", .{});
|
||||||
@ -105,7 +105,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) v
|
|||||||
|
|
||||||
fn handleDisable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
fn handleDisable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
||||||
const text_input: *TextInput = @fieldParentPtr("disable", listener);
|
const text_input: *TextInput = @fieldParentPtr("disable", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(text_input.wlr_text_input.seat.data));
|
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
|
||||||
|
|
||||||
if (seat.relay.text_input == text_input) {
|
if (seat.relay.text_input == text_input) {
|
||||||
seat.relay.disableTextInput();
|
seat.relay.disableTextInput();
|
||||||
@ -114,7 +114,7 @@ fn handleDisable(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3)
|
|||||||
|
|
||||||
fn handleDestroy(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
fn handleDestroy(listener: *wl.Listener(*wlr.TextInputV3), _: *wlr.TextInputV3) void {
|
||||||
const text_input: *TextInput = @fieldParentPtr("destroy", listener);
|
const text_input: *TextInput = @fieldParentPtr("destroy", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(text_input.wlr_text_input.seat.data));
|
const seat: *Seat = @ptrFromInt(text_input.wlr_text_input.seat.data);
|
||||||
|
|
||||||
if (seat.relay.text_input == text_input) {
|
if (seat.relay.text_input == text_input) {
|
||||||
seat.relay.disableTextInput();
|
seat.relay.disableTextInput();
|
||||||
|
@ -446,11 +446,7 @@ pub fn updateSceneState(view: *View) void {
|
|||||||
for (&view.borders, &border_boxes) |border, *border_box| {
|
for (&view.borders, &border_boxes) |border, *border_box| {
|
||||||
border_box.x += box.x;
|
border_box.x += box.x;
|
||||||
border_box.y += box.y;
|
border_box.y += box.y;
|
||||||
if (!border_box.intersection(border_box, &output_box)) {
|
_ = border_box.intersection(border_box, &output_box);
|
||||||
// TODO(wlroots): remove this redundant code after fixed upstream
|
|
||||||
// https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5084
|
|
||||||
border_box.* = .{ .x = 0, .y = 0, .width = 0, .height = 0 };
|
|
||||||
}
|
|
||||||
border_box.x -= box.x;
|
border_box.x -= box.x;
|
||||||
border_box.y -= box.y;
|
border_box.y -= box.y;
|
||||||
|
|
||||||
@ -486,7 +482,8 @@ pub fn rootSurface(view: View) ?*wlr.Surface {
|
|||||||
pub fn sendFrameDone(view: View) void {
|
pub fn sendFrameDone(view: View) void {
|
||||||
assert(view.mapped and !view.destroying);
|
assert(view.mapped and !view.destroying);
|
||||||
|
|
||||||
const now = posix.clock_gettime(.MONOTONIC) catch @panic("CLOCK_MONOTONIC not supported");
|
var now: posix.timespec = undefined;
|
||||||
|
posix.clock_gettime(posix.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
|
||||||
view.rootSurface().?.sendFrameDone(&now);
|
view.rootSurface().?.sendFrameDone(&now);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,18 +678,17 @@ pub fn map(view: *View) !void {
|
|||||||
server.input_manager.defaultSeat().focused_output;
|
server.input_manager.defaultSeat().focused_output;
|
||||||
|
|
||||||
if (server.config.rules.position.match(view)) |position| {
|
if (server.config.rules.position.match(view)) |position| {
|
||||||
var base_x: i31 = 0;
|
switch (position) {
|
||||||
var base_y: i31 = 0;
|
.absolute => |pos| {
|
||||||
switch (position.anchor) {
|
view.pending.box.x = pos.x;
|
||||||
.absolute => {},
|
view.pending.box.y = pos.y;
|
||||||
.mouse => {
|
},
|
||||||
const cursor = server.input_manager.defaultSeat().wlr_seat.pointer_state;
|
.at_mouse => {
|
||||||
base_x = @intCast(@as(i31, @intFromFloat(cursor.sx)));
|
const cursor = server.input_manager.defaultSeat().cursor.wlr_cursor;
|
||||||
base_y = @intCast(@as(i31, @intFromFloat(cursor.sy)));
|
view.pending.box.x = @as(c_int, @intFromFloat(cursor.x));
|
||||||
|
view.pending.box.y = @as(c_int, @intFromFloat(cursor.y));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
view.pending.box.x = base_x + position.x;
|
|
||||||
view.pending.box.y = base_y + position.y;
|
|
||||||
} else if (output) |o| {
|
} else if (output) |o| {
|
||||||
// Center the initial pending box on the output
|
// Center the initial pending box on the output
|
||||||
view.pending.box.x = @divTrunc(@max(0, o.usable_box.width - view.pending.box.width), 2);
|
view.pending.box.x = @divTrunc(@max(0, o.usable_box.width - view.pending.box.width), 2);
|
||||||
|
@ -34,7 +34,7 @@ request_mode: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
|||||||
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleRequestMode),
|
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleRequestMode),
|
||||||
|
|
||||||
pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
|
pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
|
||||||
const toplevel: *XdgToplevel = @alignCast(@ptrCast(wlr_decoration.toplevel.base.data));
|
const toplevel: *XdgToplevel = @ptrFromInt(wlr_decoration.toplevel.base.data);
|
||||||
|
|
||||||
toplevel.decoration = .{ .wlr_decoration = wlr_decoration };
|
toplevel.decoration = .{ .wlr_decoration = wlr_decoration };
|
||||||
const decoration = &toplevel.decoration.?;
|
const decoration = &toplevel.decoration.?;
|
||||||
@ -48,7 +48,7 @@ pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(decoration: *XdgDecoration) void {
|
pub fn deinit(decoration: *XdgDecoration) void {
|
||||||
const toplevel: *XdgToplevel = @alignCast(@ptrCast(decoration.wlr_decoration.toplevel.base.data));
|
const toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.toplevel.base.data);
|
||||||
|
|
||||||
decoration.destroy.link.remove();
|
decoration.destroy.link.remove();
|
||||||
decoration.request_mode.link.remove();
|
decoration.request_mode.link.remove();
|
||||||
@ -72,7 +72,7 @@ fn handleRequestMode(
|
|||||||
) void {
|
) void {
|
||||||
const decoration: *XdgDecoration = @fieldParentPtr("request_mode", listener);
|
const decoration: *XdgDecoration = @fieldParentPtr("request_mode", listener);
|
||||||
|
|
||||||
const toplevel: *XdgToplevel = @alignCast(@ptrCast(decoration.wlr_decoration.toplevel.base.data));
|
const toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.toplevel.base.data);
|
||||||
const view = toplevel.view;
|
const view = toplevel.view;
|
||||||
|
|
||||||
const ssd = server.config.rules.ssd.match(toplevel.view) orelse
|
const ssd = server.config.rules.ssd.match(toplevel.view) orelse
|
||||||
|
@ -100,8 +100,8 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
|
|||||||
|
|
||||||
toplevel.view = view;
|
toplevel.view = view;
|
||||||
|
|
||||||
wlr_toplevel.base.data = toplevel;
|
wlr_toplevel.base.data = @intFromPtr(toplevel);
|
||||||
wlr_toplevel.base.surface.data = &view.tree.node;
|
wlr_toplevel.base.surface.data = @intFromPtr(&view.tree.node);
|
||||||
|
|
||||||
// Add listeners that are active over the toplevel's entire lifetime
|
// Add listeners that are active over the toplevel's entire lifetime
|
||||||
wlr_toplevel.events.destroy.add(&toplevel.destroy);
|
wlr_toplevel.events.destroy.add(&toplevel.destroy);
|
||||||
@ -216,7 +216,7 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
|
|||||||
toplevel.new_popup.link.remove();
|
toplevel.new_popup.link.remove();
|
||||||
|
|
||||||
// The wlr_surface may outlive the wlr_xdg_toplevel so we must clean up the user data.
|
// The wlr_surface may outlive the wlr_xdg_toplevel so we must clean up the user data.
|
||||||
toplevel.wlr_toplevel.base.surface.data = null;
|
toplevel.wlr_toplevel.base.surface.data = 0;
|
||||||
|
|
||||||
const view = toplevel.view;
|
const view = toplevel.view;
|
||||||
view.impl = .none;
|
view.impl = .none;
|
||||||
@ -235,7 +235,7 @@ fn handleMap(listener: *wl.Listener(void)) void {
|
|||||||
toplevel.wlr_toplevel.events.set_title.add(&toplevel.set_title);
|
toplevel.wlr_toplevel.events.set_title.add(&toplevel.set_title);
|
||||||
toplevel.wlr_toplevel.events.set_app_id.add(&toplevel.set_app_id);
|
toplevel.wlr_toplevel.events.set_app_id.add(&toplevel.set_app_id);
|
||||||
|
|
||||||
toplevel.geometry = toplevel.wlr_toplevel.base.geometry;
|
toplevel.wlr_toplevel.base.getGeometry(&toplevel.geometry);
|
||||||
|
|
||||||
view.pending.box = .{
|
view.pending.box = .{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
@ -338,7 +338,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
|||||||
switch (toplevel.configure_state) {
|
switch (toplevel.configure_state) {
|
||||||
.idle, .committed, .timed_out => {
|
.idle, .committed, .timed_out => {
|
||||||
const old_geometry = toplevel.geometry;
|
const old_geometry = toplevel.geometry;
|
||||||
toplevel.geometry = toplevel.wlr_toplevel.base.geometry;
|
toplevel.wlr_toplevel.base.getGeometry(&toplevel.geometry);
|
||||||
|
|
||||||
const size_changed = toplevel.geometry.width != old_geometry.width or
|
const size_changed = toplevel.geometry.width != old_geometry.width or
|
||||||
toplevel.geometry.height != old_geometry.height;
|
toplevel.geometry.height != old_geometry.height;
|
||||||
@ -381,7 +381,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
|||||||
// stashed buffer from when the transaction started.
|
// stashed buffer from when the transaction started.
|
||||||
.inflight => view.sendFrameDone(),
|
.inflight => view.sendFrameDone(),
|
||||||
.acked, .timed_out_acked => {
|
.acked, .timed_out_acked => {
|
||||||
toplevel.geometry = toplevel.wlr_toplevel.base.geometry;
|
toplevel.wlr_toplevel.base.getGeometry(&toplevel.geometry);
|
||||||
|
|
||||||
if (view.inflight.resizing) {
|
if (view.inflight.resizing) {
|
||||||
view.resizeUpdatePosition(toplevel.geometry.width, toplevel.geometry.height);
|
view.resizeUpdatePosition(toplevel.geometry.width, toplevel.geometry.height);
|
||||||
@ -423,7 +423,7 @@ fn handleRequestMove(
|
|||||||
event: *wlr.XdgToplevel.event.Move,
|
event: *wlr.XdgToplevel.event.Move,
|
||||||
) void {
|
) void {
|
||||||
const toplevel: *XdgToplevel = @fieldParentPtr("request_move", listener);
|
const toplevel: *XdgToplevel = @fieldParentPtr("request_move", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(event.seat.seat.data));
|
const seat: *Seat = @ptrFromInt(event.seat.seat.data);
|
||||||
const view = toplevel.view;
|
const view = toplevel.view;
|
||||||
|
|
||||||
if (view.pending.fullscreen) return;
|
if (view.pending.fullscreen) return;
|
||||||
@ -446,7 +446,7 @@ fn handleRequestMove(
|
|||||||
|
|
||||||
fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), event: *wlr.XdgToplevel.event.Resize) void {
|
fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), event: *wlr.XdgToplevel.event.Resize) void {
|
||||||
const toplevel: *XdgToplevel = @fieldParentPtr("request_resize", listener);
|
const toplevel: *XdgToplevel = @fieldParentPtr("request_resize", listener);
|
||||||
const seat: *Seat = @alignCast(@ptrCast(event.seat.seat.data));
|
const seat: *Seat = @ptrFromInt(event.seat.seat.data);
|
||||||
const view = toplevel.view;
|
const view = toplevel.view;
|
||||||
|
|
||||||
if (view.pending.fullscreen) return;
|
if (view.pending.fullscreen) return;
|
||||||
|
@ -120,7 +120,7 @@ fn mapImpl(override_redirect: *XwaylandOverrideRedirect) error{OutOfMemory}!void
|
|||||||
.override_redirect = override_redirect,
|
.override_redirect = override_redirect,
|
||||||
});
|
});
|
||||||
|
|
||||||
surface.data = &override_redirect.surface_tree.?.node;
|
surface.data = @intFromPtr(&override_redirect.surface_tree.?.node);
|
||||||
|
|
||||||
override_redirect.surface_tree.?.node.setPosition(
|
override_redirect.surface_tree.?.node.setPosition(
|
||||||
override_redirect.xwayland_surface.x,
|
override_redirect.xwayland_surface.x,
|
||||||
@ -159,7 +159,7 @@ fn handleUnmap(listener: *wl.Listener(void)) void {
|
|||||||
|
|
||||||
override_redirect.set_geometry.link.remove();
|
override_redirect.set_geometry.link.remove();
|
||||||
|
|
||||||
override_redirect.xwayland_surface.surface.?.data = null;
|
override_redirect.xwayland_surface.surface.?.data = 0;
|
||||||
override_redirect.surface_tree.?.node.destroy();
|
override_redirect.surface_tree.?.node.destroy();
|
||||||
override_redirect.surface_tree = null;
|
override_redirect.surface_tree = null;
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ pub fn configure(xwayland_view: XwaylandView) bool {
|
|||||||
xwayland_view.xwayland_surface.height == inflight.box.height and
|
xwayland_view.xwayland_surface.height == inflight.box.height and
|
||||||
(inflight.focus != 0) == (current.focus != 0) and
|
(inflight.focus != 0) == (current.focus != 0) and
|
||||||
(output.inflight.fullscreen == xwayland_view.view) ==
|
(output.inflight.fullscreen == xwayland_view.view) ==
|
||||||
(current.output != null and current.output.?.current.fullscreen == xwayland_view.view))
|
(current.output != null and current.output.?.current.fullscreen == xwayland_view.view))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ pub fn handleMap(listener: *wl.Listener(void)) void {
|
|||||||
|
|
||||||
const xwayland_surface = xwayland_view.xwayland_surface;
|
const xwayland_surface = xwayland_view.xwayland_surface;
|
||||||
const surface = xwayland_surface.surface.?;
|
const surface = xwayland_surface.surface.?;
|
||||||
surface.data = &view.tree.node;
|
surface.data = @intFromPtr(&view.tree.node);
|
||||||
|
|
||||||
// Add listeners that are only active while mapped
|
// Add listeners that are only active while mapped
|
||||||
xwayland_surface.events.set_title.add(&xwayland_view.set_title);
|
xwayland_surface.events.set_title.add(&xwayland_view.set_title);
|
||||||
@ -215,12 +215,11 @@ pub fn handleMap(listener: *wl.Listener(void)) void {
|
|||||||
fn handleUnmap(listener: *wl.Listener(void)) void {
|
fn handleUnmap(listener: *wl.Listener(void)) void {
|
||||||
const xwayland_view: *XwaylandView = @fieldParentPtr("unmap", listener);
|
const xwayland_view: *XwaylandView = @fieldParentPtr("unmap", listener);
|
||||||
|
|
||||||
xwayland_view.xwayland_surface.surface.?.data = null;
|
xwayland_view.xwayland_surface.surface.?.data = 0;
|
||||||
|
|
||||||
// Remove listeners that are only active while mapped
|
// Remove listeners that are only active while mapped
|
||||||
xwayland_view.set_title.link.remove();
|
xwayland_view.set_title.link.remove();
|
||||||
xwayland_view.set_class.link.remove();
|
xwayland_view.set_class.link.remove();
|
||||||
xwayland_view.set_decorations.link.remove();
|
|
||||||
xwayland_view.request_fullscreen.link.remove();
|
xwayland_view.request_fullscreen.link.remove();
|
||||||
xwayland_view.request_minimize.link.remove();
|
xwayland_view.request_minimize.link.remove();
|
||||||
|
|
||||||
|
@ -24,13 +24,77 @@ const util = @import("../util.zig");
|
|||||||
|
|
||||||
const Error = @import("../command.zig").Error;
|
const Error = @import("../command.zig").Error;
|
||||||
const Seat = @import("../Seat.zig");
|
const Seat = @import("../Seat.zig");
|
||||||
|
const KeyboardGroup = @import("../KeyboardGroup.zig");
|
||||||
|
|
||||||
pub const keyboardGroupCreate = keyboardGroupDeprecated;
|
pub fn keyboardGroupCreate(
|
||||||
pub const keyboardGroupDestroy = keyboardGroupDeprecated;
|
seat: *Seat,
|
||||||
pub const keyboardGroupAdd = keyboardGroupDeprecated;
|
args: []const [:0]const u8,
|
||||||
pub const keyboardGroupRemove = keyboardGroupDeprecated;
|
out: *?[]const u8,
|
||||||
|
) Error!void {
|
||||||
|
if (args.len < 2) return Error.NotEnoughArguments;
|
||||||
|
if (args.len > 2) return Error.TooManyArguments;
|
||||||
|
|
||||||
fn keyboardGroupDeprecated(_: *Seat, _: []const [:0]const u8, out: *?[]const u8) Error!void {
|
if (keyboardGroupFromName(seat, args[1]) != null) {
|
||||||
out.* = try util.gpa.dupe(u8, "warning: explicit keyboard groups are deprecated, " ++
|
const msg = try util.gpa.dupe(u8, "error: failed to create keybaord group: group of same name already exists\n");
|
||||||
"all keyboards are now automatically added to a single group\n");
|
out.* = msg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try KeyboardGroup.create(seat, args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keyboardGroupDestroy(
|
||||||
|
seat: *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;
|
||||||
|
const group = keyboardGroupFromName(seat, args[1]) orelse {
|
||||||
|
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
|
||||||
|
out.* = msg;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
group.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keyboardGroupAdd(
|
||||||
|
seat: *Seat,
|
||||||
|
args: []const [:0]const u8,
|
||||||
|
out: *?[]const u8,
|
||||||
|
) Error!void {
|
||||||
|
if (args.len < 3) return Error.NotEnoughArguments;
|
||||||
|
if (args.len > 3) return Error.TooManyArguments;
|
||||||
|
|
||||||
|
const group = keyboardGroupFromName(seat, args[1]) orelse {
|
||||||
|
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
|
||||||
|
out.* = msg;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
try globber.validate(args[2]);
|
||||||
|
try group.addIdentifier(args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keyboardGroupRemove(
|
||||||
|
seat: *Seat,
|
||||||
|
args: []const [:0]const u8,
|
||||||
|
out: *?[]const u8,
|
||||||
|
) Error!void {
|
||||||
|
if (args.len < 3) return Error.NotEnoughArguments;
|
||||||
|
if (args.len > 3) return Error.TooManyArguments;
|
||||||
|
|
||||||
|
const group = keyboardGroupFromName(seat, args[1]) orelse {
|
||||||
|
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
|
||||||
|
out.* = msg;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
try group.removeIdentifier(args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn keyboardGroupFromName(seat: *Seat, name: []const u8) ?*KeyboardGroup {
|
||||||
|
var it = seat.keyboard_groups.first;
|
||||||
|
while (it) |node| : (it = node.next) {
|
||||||
|
if (mem.eql(u8, node.data.name, name)) return &node.data;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ fn parseKeysym(name: [:0]const u8, out: *?[]const u8) !xkb.Keysym {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseModifiers(modifiers_str: []const u8, out: *?[]const u8) !wlr.Keyboard.ModifierMask {
|
fn parseModifiers(modifiers_str: []const u8, out: *?[]const u8) !wlr.Keyboard.ModifierMask {
|
||||||
var it = mem.splitScalar(u8, modifiers_str, '+');
|
var it = mem.split(u8, modifiers_str, "+");
|
||||||
var modifiers = wlr.Keyboard.ModifierMask{};
|
var modifiers = wlr.Keyboard.ModifierMask{};
|
||||||
outer: while (it.next()) |mod_name| {
|
outer: while (it.next()) |mod_name| {
|
||||||
if (mem.eql(u8, mod_name, "None")) continue;
|
if (mem.eql(u8, mod_name, "None")) continue;
|
||||||
|
@ -109,7 +109,7 @@ fn getOutput(seat: *Seat, str: []const u8) !?*Output {
|
|||||||
.previous => link.prev.?,
|
.previous => link.prev.?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return @fieldParentPtr("active_link", link);
|
return @as(*Output, @fieldParentPtr("active_link", link));
|
||||||
} else if (std.meta.stringToEnum(wlr.OutputLayout.Direction, str)) |direction| { // Spacial direction
|
} else if (std.meta.stringToEnum(wlr.OutputLayout.Direction, str)) |direction| { // Spacial direction
|
||||||
var focus_box: wlr.Box = undefined;
|
var focus_box: wlr.Box = undefined;
|
||||||
server.root.output_layout.getBox(seat.focused_output.?.wlr_output, &focus_box);
|
server.root.output_layout.getBox(seat.focused_output.?.wlr_output, &focus_box);
|
||||||
@ -121,7 +121,7 @@ fn getOutput(seat: *Seat, str: []const u8) !?*Output {
|
|||||||
@floatFromInt(focus_box.x + @divTrunc(focus_box.width, 2)),
|
@floatFromInt(focus_box.x + @divTrunc(focus_box.width, 2)),
|
||||||
@floatFromInt(focus_box.y + @divTrunc(focus_box.height, 2)),
|
@floatFromInt(focus_box.y + @divTrunc(focus_box.height, 2)),
|
||||||
) orelse return null;
|
) orelse return null;
|
||||||
return @alignCast(@ptrCast(wlr_output.data));
|
return @as(*Output, @ptrFromInt(wlr_output.data));
|
||||||
} else {
|
} else {
|
||||||
// Check if an output matches by name
|
// Check if an output matches by name
|
||||||
var it = server.root.active_outputs.iterator(.forward);
|
var it = server.root.active_outputs.iterator(.forward);
|
||||||
|
@ -26,8 +26,6 @@ const util = @import("../util.zig");
|
|||||||
const Error = @import("../command.zig").Error;
|
const Error = @import("../command.zig").Error;
|
||||||
const Seat = @import("../Seat.zig");
|
const Seat = @import("../Seat.zig");
|
||||||
const View = @import("../View.zig");
|
const View = @import("../View.zig");
|
||||||
const Anchor = @import("../Config.zig").Anchor;
|
|
||||||
const RuleGlobs = @import("../rule_list.zig").RuleGlobs;
|
|
||||||
|
|
||||||
const Action = enum {
|
const Action = enum {
|
||||||
float,
|
float,
|
||||||
@ -37,14 +35,11 @@ const Action = enum {
|
|||||||
tags,
|
tags,
|
||||||
output,
|
output,
|
||||||
position,
|
position,
|
||||||
@"relative-position",
|
|
||||||
dimensions,
|
dimensions,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
@"no-fullscreen",
|
@"no-fullscreen",
|
||||||
tearing,
|
tearing,
|
||||||
@"no-tearing",
|
@"no-tearing",
|
||||||
warp,
|
|
||||||
@"no-warp",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void {
|
||||||
@ -59,11 +54,17 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
|
|
||||||
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
||||||
|
|
||||||
|
var pos_is_mouse = false;
|
||||||
const positional_arguments_count: u8 = switch (action) {
|
const positional_arguments_count: u8 = switch (action) {
|
||||||
.float, .@"no-float", .ssd, .csd, .fullscreen, .@"no-fullscreen", .tearing, .@"no-tearing", .warp, .@"no-warp" => 1,
|
.float, .@"no-float", .ssd, .csd, .fullscreen, .@"no-fullscreen", .tearing, .@"no-tearing" => 1,
|
||||||
.tags, .output => 2,
|
.tags, .output => 2,
|
||||||
.position, .dimensions => 3,
|
.dimensions => 3,
|
||||||
.@"relative-position" => 4,
|
.position => blk: {
|
||||||
|
if (result.args.len >= 2 and std.mem.eql(u8, result.args[1], "mouse")) {
|
||||||
|
pos_is_mouse = true;
|
||||||
|
break :blk 2;
|
||||||
|
} else break :blk 3;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
if (result.args.len > positional_arguments_count) return Error.TooManyArguments;
|
if (result.args.len > positional_arguments_count) return Error.TooManyArguments;
|
||||||
if (result.args.len < positional_arguments_count) return Error.NotEnoughArguments;
|
if (result.args.len < positional_arguments_count) return Error.NotEnoughArguments;
|
||||||
@ -117,34 +118,24 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
.position => {
|
.position => {
|
||||||
const x = try fmt.parseInt(i31, result.args[1], 10);
|
if (pos_is_mouse) {
|
||||||
const y = try fmt.parseInt(i31, result.args[2], 10);
|
try server.config.rules.position.add(.{
|
||||||
if (x < 0 or y < 0) return Error.OutOfBounds;
|
.app_id_glob = app_id_glob,
|
||||||
try server.config.rules.position.add(.{
|
.title_glob = title_glob,
|
||||||
.app_id_glob = app_id_glob,
|
.value = .at_mouse,
|
||||||
.title_glob = title_glob,
|
});
|
||||||
.value = .{
|
} else {
|
||||||
.anchor = .absolute,
|
const x = try fmt.parseInt(u31, result.args[1], 10);
|
||||||
.x = @intCast(x),
|
const y = try fmt.parseInt(u31, result.args[2], 10);
|
||||||
.y = @intCast(y),
|
try server.config.rules.position.add(.{
|
||||||
},
|
.app_id_glob = app_id_glob,
|
||||||
});
|
.title_glob = title_glob,
|
||||||
},
|
.value = .{ .absolute = .{
|
||||||
.@"relative-position" => {
|
.x = x,
|
||||||
const anchor = std.meta.stringToEnum(Anchor, result.args[1]) orelse return Error.UnknownOption;
|
.y = y,
|
||||||
// force the use of the normal position command for absolute positions
|
} },
|
||||||
if (anchor == .absolute) return Error.UnknownOption;
|
});
|
||||||
const x_off = try fmt.parseInt(i31, result.args[2], 10);
|
}
|
||||||
const y_off = try fmt.parseInt(i31, result.args[3], 10);
|
|
||||||
try server.config.rules.position.add(.{
|
|
||||||
.app_id_glob = app_id_glob,
|
|
||||||
.title_glob = title_glob,
|
|
||||||
.value = .{
|
|
||||||
.anchor = anchor,
|
|
||||||
.x = x_off,
|
|
||||||
.y = y_off,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
.dimensions => {
|
.dimensions => {
|
||||||
const width = try fmt.parseInt(u31, result.args[1], 10);
|
const width = try fmt.parseInt(u31, result.args[1], 10);
|
||||||
@ -165,13 +156,6 @@ pub fn ruleAdd(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
.value = (action == .fullscreen),
|
.value = (action == .fullscreen),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.warp, .@"no-warp" => {
|
|
||||||
try server.config.rules.warp.add(.{
|
|
||||||
.app_id_glob = app_id_glob,
|
|
||||||
.title_glob = title_glob,
|
|
||||||
.value = (action == .warp),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +172,7 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
|
|
||||||
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
const action = std.meta.stringToEnum(Action, result.args[0]) orelse return Error.UnknownOption;
|
||||||
|
|
||||||
const rule: RuleGlobs = .{
|
const rule = .{
|
||||||
.app_id_glob = result.flags.@"app-id" orelse "*",
|
.app_id_glob = result.flags.@"app-id" orelse "*",
|
||||||
.title_glob = result.flags.title orelse "*",
|
.title_glob = result.flags.title orelse "*",
|
||||||
};
|
};
|
||||||
@ -209,7 +193,7 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
util.gpa.free(output_rule);
|
util.gpa.free(output_rule);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.position, .@"relative-position" => {
|
.position => {
|
||||||
_ = server.config.rules.position.del(rule);
|
_ = server.config.rules.position.del(rule);
|
||||||
},
|
},
|
||||||
.dimensions => {
|
.dimensions => {
|
||||||
@ -222,9 +206,6 @@ pub fn ruleDel(_: *Seat, args: []const [:0]const u8, _: *?[]const u8) Error!void
|
|||||||
_ = server.config.rules.tearing.del(rule);
|
_ = server.config.rules.tearing.del(rule);
|
||||||
apply_tearing_rules();
|
apply_tearing_rules();
|
||||||
},
|
},
|
||||||
.warp, .@"no-warp" => {
|
|
||||||
_ = server.config.rules.warp.del(rule);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +244,6 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
dimensions,
|
dimensions,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
tearing,
|
tearing,
|
||||||
warp,
|
|
||||||
}, args[1]) orelse return Error.UnknownOption;
|
}, args[1]) orelse return Error.UnknownOption;
|
||||||
const max_glob_len = switch (rule_list) {
|
const max_glob_len = switch (rule_list) {
|
||||||
inline else => |list| @field(server.config.rules, @tagName(list)).getMaxGlobLen(),
|
inline else => |list| @field(server.config.rules, @tagName(list)).getMaxGlobLen(),
|
||||||
@ -279,14 +259,13 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
try writer.writeAll("action\n");
|
try writer.writeAll("action\n");
|
||||||
|
|
||||||
switch (rule_list) {
|
switch (rule_list) {
|
||||||
inline .float, .ssd, .output, .fullscreen, .tearing, .warp => |list| {
|
inline .float, .ssd, .output, .fullscreen, .tearing => |list| {
|
||||||
const rules = switch (list) {
|
const rules = switch (list) {
|
||||||
.float => server.config.rules.float.rules.items,
|
.float => server.config.rules.float.rules.items,
|
||||||
.ssd => server.config.rules.ssd.rules.items,
|
.ssd => server.config.rules.ssd.rules.items,
|
||||||
.output => server.config.rules.output.rules.items,
|
.output => server.config.rules.output.rules.items,
|
||||||
.fullscreen => server.config.rules.fullscreen.rules.items,
|
.fullscreen => server.config.rules.fullscreen.rules.items,
|
||||||
.tearing => server.config.rules.tearing.rules.items,
|
.tearing => server.config.rules.tearing.rules.items,
|
||||||
.warp => server.config.rules.warp.rules.items,
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
for (rules) |rule| {
|
for (rules) |rule| {
|
||||||
@ -298,7 +277,6 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
.output => rule.value,
|
.output => rule.value,
|
||||||
.fullscreen => if (rule.value) "fullscreen" else "no-fullscreen",
|
.fullscreen => if (rule.value) "fullscreen" else "no-fullscreen",
|
||||||
.tearing => if (rule.value) "tearing" else "no-tearing",
|
.tearing => if (rule.value) "tearing" else "no-tearing",
|
||||||
.warp => if (rule.value) "warp" else "no-warp",
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
@ -314,7 +292,10 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
for (server.config.rules.position.rules.items) |rule| {
|
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.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 fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
try writer.print("{s},{d},{d}", .{ @tagName(rule.value.anchor), rule.value.x, rule.value.y });
|
switch (rule.value) {
|
||||||
|
.absolute => |pos| try writer.print("{d},{d}\n", .{ pos.x, pos.y }),
|
||||||
|
.at_mouse => try writer.print("mouse\n", .{}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.dimensions => {
|
.dimensions => {
|
||||||
|
@ -84,7 +84,7 @@ pub fn main() anyerror!void {
|
|||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const runtime_xwayland = !result.flags.@"no-xwayland";
|
const enable_xwayland = !result.flags.@"no-xwayland";
|
||||||
const startup_command = blk: {
|
const startup_command = blk: {
|
||||||
if (result.flags.c) |command| {
|
if (result.flags.c) |command| {
|
||||||
break :blk try util.gpa.dupeZ(u8, command);
|
break :blk try util.gpa.dupeZ(u8, command);
|
||||||
@ -95,25 +95,17 @@ pub fn main() anyerror!void {
|
|||||||
|
|
||||||
log.info("river version {s}, initializing server", .{build_options.version});
|
log.info("river version {s}, initializing server", .{build_options.version});
|
||||||
|
|
||||||
|
process.setup();
|
||||||
|
|
||||||
river_init_wlroots_log(switch (runtime_log_level) {
|
river_init_wlroots_log(switch (runtime_log_level) {
|
||||||
.debug => .debug,
|
.debug => .debug,
|
||||||
.info => .info,
|
.info => .info,
|
||||||
.warn, .err => .err,
|
.warn, .err => .err,
|
||||||
});
|
});
|
||||||
|
|
||||||
try server.init(runtime_xwayland);
|
try server.init(enable_xwayland);
|
||||||
defer server.deinit();
|
defer server.deinit();
|
||||||
|
|
||||||
// wlroots starts the Xwayland process from an idle event source, the reasoning being that
|
|
||||||
// this gives the compositor time to set up event listeners before Xwayland is actually
|
|
||||||
// started. We want Xwayland to be started by wlroots before we modify our rlimits in
|
|
||||||
// process.setup() since wlroots does not offer a way for us to reset the rlimit post-fork.
|
|
||||||
if (build_options.xwayland and runtime_xwayland) {
|
|
||||||
server.wl_server.getEventLoop().dispatchIdle();
|
|
||||||
}
|
|
||||||
|
|
||||||
process.setup();
|
|
||||||
|
|
||||||
try server.start();
|
try server.start();
|
||||||
|
|
||||||
// Run the child in a new process group so that we can send SIGTERM to all
|
// Run the child in a new process group so that we can send SIGTERM to all
|
||||||
|
@ -29,7 +29,7 @@ pub fn setup() void {
|
|||||||
.mask = posix.empty_sigset,
|
.mask = posix.empty_sigset,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
posix.sigaction(posix.SIG.PIPE, &sig_ign, null);
|
posix.sigaction(posix.SIG.PIPE, &sig_ign, null) catch unreachable;
|
||||||
|
|
||||||
// Most unix systems have a default limit of 1024 file descriptors and it
|
// Most unix systems have a default limit of 1024 file descriptors and it
|
||||||
// seems unlikely for this default to be universally raised due to the
|
// seems unlikely for this default to be universally raised due to the
|
||||||
@ -68,7 +68,7 @@ pub fn cleanupChild() void {
|
|||||||
.mask = posix.empty_sigset,
|
.mask = posix.empty_sigset,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
posix.sigaction(posix.SIG.PIPE, &sig_dfl, null);
|
posix.sigaction(posix.SIG.PIPE, &sig_dfl, null) catch unreachable;
|
||||||
|
|
||||||
if (original_rlimit) |original| {
|
if (original_rlimit) |original| {
|
||||||
posix.setrlimit(.NOFILE, original) catch {
|
posix.setrlimit(.NOFILE, original) catch {
|
||||||
|
@ -23,11 +23,6 @@ const util = @import("util.zig");
|
|||||||
|
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
|
|
||||||
pub const RuleGlobs = struct {
|
|
||||||
app_id_glob: []const u8,
|
|
||||||
title_glob: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const MaxGlobLen = struct {
|
pub const MaxGlobLen = struct {
|
||||||
app_id: usize,
|
app_id: usize,
|
||||||
title: usize,
|
title: usize,
|
||||||
@ -88,7 +83,7 @@ pub fn RuleList(comptime T: type) type {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn del(list: *List, rule: RuleGlobs) ?T {
|
pub fn del(list: *List, rule: struct { app_id_glob: []const u8, title_glob: []const u8 }) ?T {
|
||||||
for (list.rules.items, 0..) |existing, i| {
|
for (list.rules.items, 0..) |existing, i| {
|
||||||
if (mem.eql(u8, rule.app_id_glob, existing.app_id_glob) and
|
if (mem.eql(u8, rule.app_id_glob, existing.app_id_glob) and
|
||||||
mem.eql(u8, rule.title_glob, existing.title_glob))
|
mem.eql(u8, rule.title_glob, existing.title_glob))
|
||||||
|
@ -110,10 +110,10 @@ fn _main() !void {
|
|||||||
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *Globals) void {
|
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, globals: *Globals) void {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.global => |global| {
|
.global => |global| {
|
||||||
if (mem.orderZ(u8, global.interface, wl.Seat.interface.name) == .eq) {
|
if (mem.orderZ(u8, global.interface, wl.Seat.getInterface().name) == .eq) {
|
||||||
assert(globals.seat == null); // TODO: support multiple seats
|
assert(globals.seat == null); // TODO: support multiple seats
|
||||||
globals.seat = registry.bind(global.name, wl.Seat, 1) catch @panic("out of memory");
|
globals.seat = registry.bind(global.name, wl.Seat, 1) catch @panic("out of memory");
|
||||||
} else if (mem.orderZ(u8, global.interface, zriver.ControlV1.interface.name) == .eq) {
|
} else if (mem.orderZ(u8, global.interface, zriver.ControlV1.getInterface().name) == .eq) {
|
||||||
globals.control = registry.bind(global.name, zriver.ControlV1, 1) catch @panic("out of memory");
|
globals.control = registry.bind(global.name, zriver.ControlV1, 1) catch @panic("out of memory");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -91,12 +91,12 @@ const gpa = std.heap.c_allocator;
|
|||||||
const Context = struct {
|
const Context = struct {
|
||||||
initialized: bool = false,
|
initialized: bool = false,
|
||||||
layout_manager: ?*river.LayoutManagerV3 = null,
|
layout_manager: ?*river.LayoutManagerV3 = null,
|
||||||
outputs: std.DoublyLinkedList(Output) = .{},
|
outputs: std.TailQueue(Output) = .{},
|
||||||
|
|
||||||
fn addOutput(context: *Context, registry: *wl.Registry, name: u32) !void {
|
fn addOutput(context: *Context, registry: *wl.Registry, name: u32) !void {
|
||||||
const wl_output = try registry.bind(name, wl.Output, 3);
|
const wl_output = try registry.bind(name, wl.Output, 3);
|
||||||
errdefer wl_output.release();
|
errdefer wl_output.release();
|
||||||
const node = try gpa.create(std.DoublyLinkedList(Output).Node);
|
const node = try gpa.create(std.TailQueue(Output).Node);
|
||||||
errdefer gpa.destroy(node);
|
errdefer gpa.destroy(node);
|
||||||
try node.data.init(context, wl_output, name);
|
try node.data.init(context, wl_output, name);
|
||||||
context.outputs.append(node);
|
context.outputs.append(node);
|
||||||
@ -140,7 +140,7 @@ const Output = struct {
|
|||||||
.namespace_in_use => fatal("namespace 'rivertile' already in use.", .{}),
|
.namespace_in_use => fatal("namespace 'rivertile' already in use.", .{}),
|
||||||
|
|
||||||
.user_command => |ev| {
|
.user_command => |ev| {
|
||||||
var it = mem.tokenizeScalar(u8, mem.span(ev.command), ' ');
|
var it = mem.tokenize(u8, mem.span(ev.command), " ");
|
||||||
const raw_cmd = it.next() orelse {
|
const raw_cmd = it.next() orelse {
|
||||||
std.log.err("not enough arguments", .{});
|
std.log.err("not enough arguments", .{});
|
||||||
return;
|
return;
|
||||||
@ -382,9 +382,9 @@ pub fn main() !void {
|
|||||||
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *Context) void {
|
fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *Context) void {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.global => |global| {
|
.global => |global| {
|
||||||
if (mem.orderZ(u8, global.interface, river.LayoutManagerV3.interface.name) == .eq) {
|
if (mem.orderZ(u8, global.interface, river.LayoutManagerV3.getInterface().name) == .eq) {
|
||||||
context.layout_manager = registry.bind(global.name, river.LayoutManagerV3, 1) catch return;
|
context.layout_manager = registry.bind(global.name, river.LayoutManagerV3, 1) catch return;
|
||||||
} else if (mem.orderZ(u8, global.interface, wl.Output.interface.name) == .eq) {
|
} else if (mem.orderZ(u8, global.interface, wl.Output.getInterface().name) == .eq) {
|
||||||
context.addOutput(registry, global.name) catch |err| fatal("failed to bind output: {}", .{err});
|
context.addOutput(registry, global.name) catch |err| fatal("failed to bind output: {}", .{err});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user