Compare commits
65 Commits
main
...
track-old-
Author | SHA1 | Date | |
---|---|---|---|
8488cd9d97
|
|||
46f77f30dc | |||
8490558b8b | |||
14f63f3099
|
|||
543697847f | |||
c1fc15dbc6
|
|||
6abcc68a19 | |||
ab879e245c | |||
9f8b689f8a | |||
e575485f0d | |||
4fba7505f3 | |||
5ca829bd5a | |||
a2a5e8f463 | |||
33a69405c4
|
|||
5080f07724
|
|||
d66decb7c4
|
|||
eab34c7c03
|
|||
dbe2cb72f8
|
|||
1b5dd21ee6 | |||
3529463569 | |||
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.15.1/zig-x86_64-linux-0.15.1.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-x86_64-linux-0.15.1.tar.xz
|
tar xf zig-linux-x86_64-0.13.0.tar.xz
|
||||||
sudo mv zig-x86_64-linux-0.15.1/zig /usr/bin/
|
sudo mv zig-linux-x86_64-0.13.0/zig /usr/bin/
|
||||||
sudo mv zig-x86_64-linux-0.15.1/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.15.1/zig-x86_64-linux-0.15.1.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-x86_64-linux-0.15.1.tar.xz
|
tar xf zig-linux-x86_64-0.13.0.tar.xz
|
||||||
sudo mv zig-x86_64-linux-0.15.1/zig /usr/bin/
|
sudo mv zig-linux-x86_64-0.13.0/zig /usr/bin/
|
||||||
sudo mv zig-x86_64-linux-0.15.1/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.15.1/zig-x86_64-freebsd-0.15.1.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-x86_64-freebsd-0.15.1.tar.xz
|
tar xf zig-freebsd-x86_64-0.13.0.tar.xz
|
||||||
sudo mv zig-x86_64-freebsd-0.15.1/zig /usr/bin/
|
sudo mv zig-freebsd-x86_64-0.13.0/zig /usr/bin/
|
||||||
sudo mv zig-x86_64-freebsd-0.15.1/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.15
|
- [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
|
||||||
|
63
build.zig
63
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(.{});
|
||||||
@ -12,6 +18,7 @@ pub fn build(b: *Build) !void {
|
|||||||
|
|
||||||
const strip = b.option(bool, "strip", "Omit debug information") orelse false;
|
const strip = b.option(bool, "strip", "Omit debug information") orelse false;
|
||||||
const pie = b.option(bool, "pie", "Build a Position Independent Executable") orelse false;
|
const pie = b.option(bool, "pie", "Build a Position Independent Executable") orelse false;
|
||||||
|
const llvm = !(b.option(bool, "no-llvm", "(expirimental) Use non-LLVM x86 Zig backend") orelse false);
|
||||||
|
|
||||||
const omit_frame_pointer = switch (optimize) {
|
const omit_frame_pointer = switch (optimize) {
|
||||||
.Debug, .ReleaseSafe => false,
|
.Debug, .ReleaseSafe => false,
|
||||||
@ -64,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().?;
|
||||||
@ -129,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);
|
||||||
@ -141,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") });
|
||||||
@ -149,12 +156,12 @@ pub fn build(b: *Build) !void {
|
|||||||
{
|
{
|
||||||
const river = b.addExecutable(.{
|
const river = b.addExecutable(.{
|
||||||
.name = "river",
|
.name = "river",
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("river/main.zig"),
|
.root_source_file = b.path("river/main.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.strip = strip,
|
.strip = strip,
|
||||||
}),
|
.use_llvm = llvm,
|
||||||
|
.use_lld = llvm,
|
||||||
});
|
});
|
||||||
river.root_module.addOptions("build_options", options);
|
river.root_module.addOptions("build_options", options);
|
||||||
|
|
||||||
@ -162,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");
|
||||||
|
|
||||||
@ -187,12 +194,12 @@ pub fn build(b: *Build) !void {
|
|||||||
{
|
{
|
||||||
const riverctl = b.addExecutable(.{
|
const riverctl = b.addExecutable(.{
|
||||||
.name = "riverctl",
|
.name = "riverctl",
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("riverctl/main.zig"),
|
.root_source_file = b.path("riverctl/main.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.strip = strip,
|
.strip = strip,
|
||||||
}),
|
.use_llvm = llvm,
|
||||||
|
.use_lld = llvm,
|
||||||
});
|
});
|
||||||
riverctl.root_module.addOptions("build_options", options);
|
riverctl.root_module.addOptions("build_options", options);
|
||||||
|
|
||||||
@ -210,12 +217,12 @@ pub fn build(b: *Build) !void {
|
|||||||
{
|
{
|
||||||
const rivertile = b.addExecutable(.{
|
const rivertile = b.addExecutable(.{
|
||||||
.name = "rivertile",
|
.name = "rivertile",
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("rivertile/main.zig"),
|
.root_source_file = b.path("rivertile/main.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.strip = strip,
|
.strip = strip,
|
||||||
}),
|
.use_llvm = llvm,
|
||||||
|
.use_lld = llvm,
|
||||||
});
|
});
|
||||||
rivertile.root_module.addOptions("build_options", options);
|
rivertile.root_module.addOptions("build_options", options);
|
||||||
|
|
||||||
@ -274,11 +281,9 @@ pub fn build(b: *Build) !void {
|
|||||||
|
|
||||||
{
|
{
|
||||||
const globber_test = b.addTest(.{
|
const globber_test = b.addTest(.{
|
||||||
.root_module = b.createModule(.{
|
|
||||||
.root_source_file = b.path("common/globber.zig"),
|
.root_source_file = b.path("common/globber.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
const run_globber_test = b.addRunArtifact(globber_test);
|
const run_globber_test = b.addRunArtifact(globber_test);
|
||||||
|
|
||||||
@ -286,31 +291,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.12",
|
|
||||||
.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.4.0.tar.gz",
|
.url = "https://codeberg.org/ifreund/zig-wayland/archive/bd8afd256fb6beed7d72e3580b00f33dea7155a1.tar.gz",
|
||||||
.hash = "wayland-0.4.0-lQa1khbMAQAsLS2eBR7M5lofyEGPIbu2iFDmoz8lPC27",
|
.hash = "1220218a0e5c2cd63a2311417f4d3f2411dd17d75815f67c704ee657bd846ecbc3e0",
|
||||||
},
|
},
|
||||||
.wlroots = .{
|
.@"zig-wlroots" = .{
|
||||||
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.19.3.tar.gz",
|
.url = "https://codeberg.org/ifreund/zig-wlroots/archive/afbbbbe5579c750feed8de12b073fa50b0651137.tar.gz",
|
||||||
.hash = "wlroots-0.19.3-jmOlcuL_AwBHhLCwpFsXbTizE3q9BugFmGX-XIxqcPMc",
|
.hash = "122060ddef836b7872cb2088764a8bd2fb2e9254327673e8176b7f7a621ec897484f",
|
||||||
},
|
},
|
||||||
.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 = &.{},
|
||||||
|
@ -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 = @ptrCast(@alignCast(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(),
|
||||||
|
@ -26,7 +26,7 @@ const wayland = @import("wayland");
|
|||||||
const wl = wayland.server.wl;
|
const wl = wayland.server.wl;
|
||||||
const zwlr = wayland.server.zwlr;
|
const zwlr = wayland.server.zwlr;
|
||||||
|
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig");
|
||||||
const server = &@import("main.zig").server;
|
const server = &@import("main.zig").server;
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ 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,
|
image: Image = .none,
|
||||||
image_surface_destroy: wl.Listener(*wlr.Surface) = .init(handleImageSurfaceDestroy),
|
image_surface_destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleImageSurfaceDestroy),
|
||||||
|
|
||||||
/// Number of distinct buttons currently pressed
|
/// Number of distinct buttons currently pressed
|
||||||
pressed_count: u32 = 0,
|
pressed_count: u32 = 0,
|
||||||
@ -255,30 +255,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();
|
||||||
@ -296,7 +272,7 @@ pub fn setTheme(cursor: *Cursor, theme: ?[*:0]const u8, _size: ?u32) !void {
|
|||||||
// If this cursor belongs to the default seat, set the xcursor environment
|
// If this cursor belongs to the default seat, set the xcursor environment
|
||||||
// variables as well as the xwayland cursor theme.
|
// variables as well as the xwayland cursor theme.
|
||||||
if (cursor.seat == server.input_manager.defaultSeat()) {
|
if (cursor.seat == server.input_manager.defaultSeat()) {
|
||||||
const size_str = try std.fmt.allocPrintSentinel(util.gpa, "{}", .{size}, 0);
|
const size_str = try std.fmt.allocPrintZ(util.gpa, "{}", .{size});
|
||||||
defer util.gpa.free(size_str);
|
defer util.gpa.free(size_str);
|
||||||
if (c.setenv("XCURSOR_SIZE", size_str.ptr, 1) < 0) return error.OutOfMemory;
|
if (c.setenv("XCURSOR_SIZE", size_str.ptr, 1) < 0) return error.OutOfMemory;
|
||||||
if (theme) |t| if (c.setenv("XCURSOR_THEME", t, 1) < 0) return error.OutOfMemory;
|
if (theme) |t| if (c.setenv("XCURSOR_THEME", t, 1) < 0) return error.OutOfMemory;
|
||||||
@ -362,7 +338,7 @@ fn clearFocus(cursor: *Cursor) void {
|
|||||||
/// 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 = @ptrCast(@alignCast(event.device.data));
|
const device: *InputDevice = @ptrFromInt(event.device.data);
|
||||||
|
|
||||||
cursor.seat.handleActivity();
|
cursor.seat.handleActivity();
|
||||||
cursor.unhide();
|
cursor.unhide();
|
||||||
@ -378,8 +354,8 @@ fn handleAxis(listener: *wl.Listener(*wlr.Pointer.event.Axis), event: *wlr.Point
|
|||||||
// @intFromFloat() call safe due to the max/min i32 not being exactly representable
|
// @intFromFloat() call safe due to the max/min i32 not being exactly representable
|
||||||
// by an f32. Dividing by 2 is a low effort way to ensure the value is in bounds and
|
// by an f32. Dividing by 2 is a low effort way to ensure the value is in bounds and
|
||||||
// allow users to set their scroll-factor to inf without crashing river.
|
// allow users to set their scroll-factor to inf without crashing river.
|
||||||
@as(f32, @floatFromInt(math.minInt(i32) / 2)),
|
math.minInt(i32) / 2,
|
||||||
@as(f32, @floatFromInt(math.maxInt(i32) / 2)),
|
math.maxInt(i32) / 2,
|
||||||
)),
|
)),
|
||||||
event.source,
|
event.source,
|
||||||
event.relative_direction,
|
event.relative_direction,
|
||||||
@ -482,7 +458,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 = @ptrCast(@alignCast(wlr_output.data));
|
const output: *Output = @ptrFromInt(wlr_output.data);
|
||||||
cursor.seat.focusOutput(output);
|
cursor.seat.focusOutput(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -659,7 +635,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 = @ptrCast(@alignCast(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 +649,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 = @ptrCast(@alignCast(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 +663,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 = @ptrCast(@alignCast(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 +677,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 = @ptrCast(@alignCast(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();
|
||||||
@ -822,7 +798,6 @@ pub fn hide(cursor: *Cursor) void {
|
|||||||
|
|
||||||
cursor.hidden = true;
|
cursor.hidden = true;
|
||||||
cursor.wlr_cursor.unsetImage();
|
cursor.wlr_cursor.unsetImage();
|
||||||
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", .{});
|
||||||
};
|
};
|
||||||
@ -1154,12 +1129,13 @@ 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;
|
||||||
|
posix.clock_gettime(posix.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
|
||||||
// 2^32-1 milliseconds is ~50 days, which is a realistic uptime.
|
// 2^32-1 milliseconds is ~50 days, which is a realistic uptime.
|
||||||
// This means that we must wrap if the monotonic time is greater than
|
// This means that we must wrap if the monotonic time is greater than
|
||||||
// 2^32-1 milliseconds and hope that clients don't get too confused.
|
// 2^32-1 milliseconds and hope that clients don't get too confused.
|
||||||
const msec: u32 = @intCast(@rem(
|
const msec: u32 = @intCast(@rem(
|
||||||
now.sec *% std.time.ms_per_s +% @divTrunc(now.nsec, std.time.ns_per_ms),
|
now.tv_sec *% std.time.ms_per_s +% @divTrunc(now.tv_nsec, std.time.ns_per_ms),
|
||||||
math.maxInt(u32),
|
math.maxInt(u32),
|
||||||
));
|
));
|
||||||
cursor.passthrough(msec);
|
cursor.passthrough(msec);
|
||||||
@ -1301,7 +1277,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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(event.seat.data));
|
const seat: *Seat = @ptrFromInt(event.seat.data);
|
||||||
|
|
||||||
seat.focus(view);
|
seat.focus(view);
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
|
@ -30,29 +30,28 @@ 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: wl.list.Head(IdleInhibitor, .link),
|
inhibitors: std.TailQueue(IdleInhibitor) = .{},
|
||||||
|
|
||||||
pub fn init(inhibit_manager: *IdleInhibitManager) !void {
|
pub fn init(inhibit_manager: *IdleInhibitManager) !void {
|
||||||
inhibit_manager.* = .{
|
inhibit_manager.* = .{
|
||||||
.wlr_manager = try wlr.IdleInhibitManagerV1.create(server.wl_server),
|
.wlr_manager = try wlr.IdleInhibitManagerV1.create(server.wl_server),
|
||||||
.inhibitors = undefined,
|
|
||||||
};
|
};
|
||||||
inhibit_manager.inhibitors.init();
|
|
||||||
inhibit_manager.wlr_manager.events.new_inhibitor.add(&inhibit_manager.new_idle_inhibitor);
|
inhibit_manager.wlr_manager.events.new_inhibitor.add(&inhibit_manager.new_idle_inhibitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(inhibit_manager: *IdleInhibitManager) void {
|
pub fn deinit(inhibit_manager: *IdleInhibitManager) void {
|
||||||
while (inhibit_manager.inhibitors.first()) |inhibitor| {
|
while (inhibit_manager.inhibitors.pop()) |inhibitor| {
|
||||||
inhibitor.destroy();
|
inhibitor.data.destroy.link.remove();
|
||||||
|
util.gpa.destroy(inhibitor);
|
||||||
}
|
}
|
||||||
inhibit_manager.new_idle_inhibitor.link.remove();
|
inhibit_manager.new_idle_inhibitor.link.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkActive(inhibit_manager: *IdleInhibitManager) void {
|
pub fn checkActive(inhibit_manager: *IdleInhibitManager) void {
|
||||||
var inhibited = false;
|
var inhibited = false;
|
||||||
var it = inhibit_manager.inhibitors.iterator(.forward);
|
var it = inhibit_manager.inhibitors.first;
|
||||||
while (it.next()) |inhibitor| {
|
while (it) |node| : (it = node.next) {
|
||||||
const node_data = SceneNodeData.fromSurface(inhibitor.wlr_inhibitor.surface) orelse continue;
|
const node_data = SceneNodeData.fromSurface(node.data.wlr_inhibitor.surface) orelse continue;
|
||||||
switch (node_data.data) {
|
switch (node_data.data) {
|
||||||
.view => |view| {
|
.view => |view| {
|
||||||
if (view.current.output != null and
|
if (view.current.output != null and
|
||||||
@ -80,8 +79,13 @@ 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);
|
||||||
IdleInhibitor.create(inhibitor, inhibit_manager) catch {
|
const inhibitor_node = util.gpa.create(std.TailQueue(IdleInhibitor).Node) catch return;
|
||||||
std.log.err("out of memory", .{});
|
inhibitor_node.data.init(inhibitor, inhibit_manager) catch {
|
||||||
|
util.gpa.destroy(inhibitor_node);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inhibit_manager.inhibitors.append(inhibitor_node);
|
||||||
|
|
||||||
|
inhibit_manager.checkActive();
|
||||||
}
|
}
|
||||||
|
@ -28,38 +28,31 @@ const IdleInhibitManager = @import("IdleInhibitManager.zig");
|
|||||||
inhibit_manager: *IdleInhibitManager,
|
inhibit_manager: *IdleInhibitManager,
|
||||||
wlr_inhibitor: *wlr.IdleInhibitorV1,
|
wlr_inhibitor: *wlr.IdleInhibitorV1,
|
||||||
|
|
||||||
listen_destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleDestroy),
|
destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleDestroy),
|
||||||
|
|
||||||
link: wl.list.Link,
|
|
||||||
|
|
||||||
pub fn create(wlr_inhibitor: *wlr.IdleInhibitorV1, inhibit_manager: *IdleInhibitManager) !void {
|
|
||||||
const inhibitor = try util.gpa.create(IdleInhibitor);
|
|
||||||
errdefer util.gpa.destroy(inhibitor);
|
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
inhibitor: *IdleInhibitor,
|
||||||
|
wlr_inhibitor: *wlr.IdleInhibitorV1,
|
||||||
|
inhibit_manager: *IdleInhibitManager,
|
||||||
|
) !void {
|
||||||
inhibitor.* = .{
|
inhibitor.* = .{
|
||||||
.inhibit_manager = inhibit_manager,
|
.inhibit_manager = inhibit_manager,
|
||||||
.wlr_inhibitor = wlr_inhibitor,
|
.wlr_inhibitor = wlr_inhibitor,
|
||||||
.link = undefined,
|
|
||||||
};
|
};
|
||||||
wlr_inhibitor.events.destroy.add(&inhibitor.listen_destroy);
|
wlr_inhibitor.events.destroy.add(&inhibitor.destroy);
|
||||||
|
|
||||||
inhibit_manager.inhibitors.append(inhibitor);
|
|
||||||
|
|
||||||
inhibit_manager.checkActive();
|
inhibit_manager.checkActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(inhibitor: *IdleInhibitor) void {
|
fn handleDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||||
inhibitor.listen_destroy.link.remove();
|
const inhibitor: *IdleInhibitor = @fieldParentPtr("destroy", listener);
|
||||||
|
|
||||||
inhibitor.link.remove();
|
inhibitor.destroy.link.remove();
|
||||||
|
|
||||||
|
const node: *std.TailQueue(IdleInhibitor).Node = @fieldParentPtr("data", inhibitor);
|
||||||
|
server.idle_inhibit_manager.inhibitors.remove(node);
|
||||||
|
|
||||||
inhibitor.inhibit_manager.checkActive();
|
inhibitor.inhibit_manager.checkActive();
|
||||||
|
|
||||||
util.gpa.destroy(inhibitor);
|
util.gpa.destroy(node);
|
||||||
}
|
|
||||||
|
|
||||||
fn handleDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
|
||||||
const inhibitor: *IdleInhibitor = @fieldParentPtr("listen_destroy", listener);
|
|
||||||
|
|
||||||
inhibitor.destroy();
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ const wlr = @import("wlroots");
|
|||||||
|
|
||||||
const log = std.log.scoped(.input_config);
|
const log = std.log.scoped(.input_config);
|
||||||
|
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig");
|
||||||
|
|
||||||
const server = &@import("main.zig").server;
|
const server = &@import("main.zig").server;
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
@ -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
|
||||||
@ -373,10 +373,10 @@ pub fn parse(config: *InputConfig, setting: []const u8, value: []const u8) !void
|
|||||||
return error.UnknownCommand;
|
return error.UnknownCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(config: *InputConfig, writer: *std.Io.Writer) !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: *std.Io.Writer) !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) });
|
||||||
|
@ -24,7 +24,7 @@ const wl = @import("wayland").server.wl;
|
|||||||
|
|
||||||
const globber = @import("globber");
|
const globber = @import("globber");
|
||||||
|
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig");
|
||||||
const server = &@import("main.zig").server;
|
const server = &@import("main.zig").server;
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -55,10 +55,10 @@ tablet_manager: *wlr.TabletManagerV2,
|
|||||||
|
|
||||||
/// List of input device configurations. Ordered by glob generality, with
|
/// List of input device configurations. Ordered by glob generality, with
|
||||||
/// the most general towards the start and the most specific towards the end.
|
/// the most general towards the start and the most specific towards the end.
|
||||||
configs: std.ArrayList(InputConfig) = .{},
|
configs: std.ArrayList(InputConfig),
|
||||||
|
|
||||||
devices: wl.list.Head(InputDevice, .link),
|
devices: wl.list.Head(InputDevice, .link),
|
||||||
seats: wl.list.Head(Seat, .link),
|
seats: std.TailQueue(Seat) = .{},
|
||||||
|
|
||||||
exclusive_client: ?*wl.Client = null,
|
exclusive_client: ?*wl.Client = null,
|
||||||
|
|
||||||
@ -74,6 +74,9 @@ 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.TailQueue(Seat).Node);
|
||||||
|
errdefer util.gpa.destroy(seat_node);
|
||||||
|
|
||||||
input_manager.* = .{
|
input_manager.* = .{
|
||||||
// These are automatically freed when the display is destroyed
|
// These are automatically freed when the display is destroyed
|
||||||
.idle_notifier = try wlr.IdleNotifierV1.create(server.wl_server),
|
.idle_notifier = try wlr.IdleNotifierV1.create(server.wl_server),
|
||||||
@ -85,14 +88,14 @@ pub fn init(input_manager: *InputManager) !void {
|
|||||||
.input_method_manager = try wlr.InputMethodManagerV2.create(server.wl_server),
|
.input_method_manager = try wlr.InputMethodManagerV2.create(server.wl_server),
|
||||||
.text_input_manager = try wlr.TextInputManagerV3.create(server.wl_server),
|
.text_input_manager = try wlr.TextInputManagerV3.create(server.wl_server),
|
||||||
.tablet_manager = try wlr.TabletManagerV2.create(server.wl_server),
|
.tablet_manager = try wlr.TabletManagerV2.create(server.wl_server),
|
||||||
|
.configs = std.ArrayList(InputConfig).init(util.gpa),
|
||||||
|
|
||||||
.seats = undefined,
|
|
||||||
.devices = undefined,
|
.devices = undefined,
|
||||||
};
|
};
|
||||||
input_manager.seats.init();
|
|
||||||
input_manager.devices.init();
|
input_manager.devices.init();
|
||||||
|
|
||||||
try Seat.create(default_seat_name);
|
input_manager.seats.prepend(seat_node);
|
||||||
|
try seat_node.data.init(default_seat_name);
|
||||||
|
|
||||||
if (build_options.xwayland) {
|
if (build_options.xwayland) {
|
||||||
if (server.xwayland) |xwayland| {
|
if (server.xwayland) |xwayland| {
|
||||||
@ -118,18 +121,19 @@ pub fn deinit(input_manager: *InputManager) void {
|
|||||||
input_manager.new_input_method.link.remove();
|
input_manager.new_input_method.link.remove();
|
||||||
input_manager.new_text_input.link.remove();
|
input_manager.new_text_input.link.remove();
|
||||||
|
|
||||||
while (input_manager.seats.first()) |seat| {
|
while (input_manager.seats.pop()) |seat_node| {
|
||||||
seat.destroy();
|
seat_node.data.deinit();
|
||||||
|
util.gpa.destroy(seat_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (input_manager.configs.items) |*config| {
|
for (input_manager.configs.items) |*config| {
|
||||||
config.deinit();
|
config.deinit();
|
||||||
}
|
}
|
||||||
input_manager.configs.deinit(util.gpa);
|
input_manager.configs.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn defaultSeat(input_manager: *InputManager) *Seat {
|
pub fn defaultSeat(input_manager: InputManager) *Seat {
|
||||||
return input_manager.seats.first().?;
|
return &input_manager.seats.first.?.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if input is currently allowed on the passed surface.
|
/// Returns true if input is currently allowed on the passed surface.
|
||||||
@ -156,7 +160,7 @@ pub fn reconfigureDevices(input_manager: *InputManager) void {
|
|||||||
fn handleNewInput(listener: *wl.Listener(*wlr.InputDevice), wlr_device: *wlr.InputDevice) void {
|
fn handleNewInput(listener: *wl.Listener(*wlr.InputDevice), wlr_device: *wlr.InputDevice) void {
|
||||||
const input_manager: *InputManager = @fieldParentPtr("new_input", listener);
|
const input_manager: *InputManager = @fieldParentPtr("new_input", listener);
|
||||||
|
|
||||||
input_manager.defaultSeat().addDevice(wlr_device, false);
|
input_manager.defaultSeat().addDevice(wlr_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleNewVirtualPointer(
|
fn handleNewVirtualPointer(
|
||||||
@ -174,53 +178,17 @@ fn handleNewVirtualPointer(
|
|||||||
log.debug("Ignoring output suggestion from virtual pointer", .{});
|
log.debug("Ignoring output suggestion from virtual pointer", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
input_manager.defaultSeat().addDevice(&event.new_pointer.pointer.base, true);
|
input_manager.defaultSeat().addDevice(&event.new_pointer.pointer.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleNewVirtualKeyboard(
|
fn handleNewVirtualKeyboard(
|
||||||
_: *wl.Listener(*wlr.VirtualKeyboardV1),
|
_: *wl.Listener(*wlr.VirtualKeyboardV1),
|
||||||
virtual_keyboard: *wlr.VirtualKeyboardV1,
|
virtual_keyboard: *wlr.VirtualKeyboardV1,
|
||||||
) void {
|
) void {
|
||||||
const no_keymap = util.gpa.create(NoKeymapVirtKeyboard) catch {
|
const seat: *Seat = @ptrFromInt(virtual_keyboard.seat.data);
|
||||||
log.err("out of memory", .{});
|
seat.addDevice(&virtual_keyboard.keyboard.base);
|
||||||
return;
|
|
||||||
};
|
|
||||||
errdefer util.gpa.destroy(no_keymap);
|
|
||||||
|
|
||||||
no_keymap.* = .{
|
|
||||||
.virtual_keyboard = virtual_keyboard,
|
|
||||||
};
|
|
||||||
virtual_keyboard.keyboard.base.events.destroy.add(&no_keymap.destroy);
|
|
||||||
virtual_keyboard.keyboard.events.keymap.add(&no_keymap.keymap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ignore virtual keyboards completely until the client sets a keymap
|
|
||||||
/// Yes, wlroots should probably do this for us.
|
|
||||||
const NoKeymapVirtKeyboard = struct {
|
|
||||||
virtual_keyboard: *wlr.VirtualKeyboardV1,
|
|
||||||
destroy: wl.Listener(*wlr.InputDevice) = .init(handleDestroy),
|
|
||||||
keymap: wl.Listener(*wlr.Keyboard) = .init(handleKeymap),
|
|
||||||
|
|
||||||
fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void {
|
|
||||||
const no_keymap: *NoKeymapVirtKeyboard = @fieldParentPtr("destroy", listener);
|
|
||||||
|
|
||||||
no_keymap.destroy.link.remove();
|
|
||||||
no_keymap.keymap.link.remove();
|
|
||||||
|
|
||||||
util.gpa.destroy(no_keymap);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handleKeymap(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
|
|
||||||
const no_keymap: *NoKeymapVirtKeyboard = @fieldParentPtr("keymap", listener);
|
|
||||||
const virtual_keyboard = no_keymap.virtual_keyboard;
|
|
||||||
|
|
||||||
handleDestroy(&no_keymap.destroy, &virtual_keyboard.keyboard.base);
|
|
||||||
|
|
||||||
const seat: *Seat = @ptrCast(@alignCast(virtual_keyboard.seat.data));
|
|
||||||
seat.addDevice(&virtual_keyboard.keyboard.base, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fn handleNewConstraint(
|
fn handleNewConstraint(
|
||||||
_: *wl.Listener(*wlr.PointerConstraintV1),
|
_: *wl.Listener(*wlr.PointerConstraintV1),
|
||||||
wlr_constraint: *wlr.PointerConstraintV1,
|
wlr_constraint: *wlr.PointerConstraintV1,
|
||||||
@ -232,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 = @ptrCast(@alignCast(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,60 +54,41 @@ 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: [capacity]Key,
|
keys: std.BoundedArray(Key, capacity) = .{},
|
||||||
len: usize,
|
|
||||||
|
|
||||||
const empty: Pressed = .{ .keys = undefined, .len = 0 };
|
|
||||||
|
|
||||||
pub fn slice(pressed: *Pressed) []Key {
|
|
||||||
return pressed.keys[0..pressed.len];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains(pressed: *Pressed, code: u32) bool {
|
fn contains(pressed: *Pressed, code: u32) bool {
|
||||||
for (pressed.slice()) |item| {
|
for (pressed.keys.constSlice()) |item| {
|
||||||
if (item.code == code) return true;
|
if (item.code == code) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addAssumeCapacity(pressed: *Pressed, new: Key) void {
|
fn addAssumeCapacity(pressed: *Pressed, new: Key) void {
|
||||||
assert(pressed.len < pressed.keys.len);
|
|
||||||
assert(!pressed.contains(new.code));
|
assert(!pressed.contains(new.code));
|
||||||
pressed.keys[pressed.len] = new;
|
pressed.keys.appendAssumeCapacity(new);
|
||||||
pressed.len += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(pressed: *Pressed, code: u32) ?KeyConsumer {
|
fn remove(pressed: *Pressed, code: u32) ?KeyConsumer {
|
||||||
for (pressed.slice(), 0..) |item, idx| {
|
for (pressed.keys.constSlice(), 0..) |item, idx| {
|
||||||
if (item.code == code) return pressed.swapRemove(idx).consumer;
|
if (item.code == code) return pressed.keys.swapRemove(idx).consumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn swapRemove(pressed: *Pressed, index: usize) Key {
|
|
||||||
defer pressed.len -= 1;
|
|
||||||
if (index == pressed.len - 1) {
|
|
||||||
return pressed.keys[index];
|
|
||||||
}
|
|
||||||
const ret = pressed.keys[index];
|
|
||||||
pressed.keys[index] = pressed.keys[pressed.len - 1];
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
device: InputDevice,
|
device: InputDevice,
|
||||||
|
|
||||||
/// Pressed keys along with where their press event has been sent
|
/// Pressed keys along with where their press event has been sent
|
||||||
pressed: Pressed = .empty,
|
pressed: Pressed = .{},
|
||||||
|
|
||||||
key: wl.Listener(*wlr.Keyboard.event.Key) = wl.Listener(*wlr.Keyboard.event.Key).init(handleKey),
|
key: wl.Listener(*wlr.Keyboard.event.Key) = wl.Listener(*wlr.Keyboard.event.Key).init(handleKey),
|
||||||
modifiers: wl.Listener(*wlr.Keyboard) = wl.Listener(*wlr.Keyboard).init(handleModifiers),
|
modifiers: wl.Listener(*wlr.Keyboard) = wl.Listener(*wlr.Keyboard).init(handleModifiers),
|
||||||
|
|
||||||
pub fn init(keyboard: *Keyboard, seat: *Seat, wlr_device: *wlr.InputDevice, virtual: bool) !void {
|
pub fn init(keyboard: *Keyboard, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
|
||||||
keyboard.* = .{
|
keyboard.* = .{
|
||||||
.device = undefined,
|
.device = undefined,
|
||||||
};
|
};
|
||||||
@ -115,9 +96,8 @@ pub fn init(keyboard: *Keyboard, seat: *Seat, wlr_device: *wlr.InputDevice, virt
|
|||||||
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);
|
||||||
|
|
||||||
if (!virtual) {
|
|
||||||
// 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;
|
||||||
|
|
||||||
@ -125,7 +105,6 @@ pub fn init(keyboard: *Keyboard, seat: *Seat, wlr_device: *wlr.InputDevice, virt
|
|||||||
// wlroots will log an error on failure
|
// wlroots will log an error on failure
|
||||||
_ = seat.keyboard_group.addKeyboard(wlr_keyboard);
|
_ = seat.keyboard_group.addKeyboard(wlr_keyboard);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
|
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
|
||||||
|
|
||||||
@ -222,9 +201,7 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
|
|||||||
// Ignore key presses beyond 32 simultaneously pressed keys (see comments in Pressed).
|
// Ignore key presses beyond 32 simultaneously pressed keys (see comments in Pressed).
|
||||||
// We must ensure capacity before calling handleMapping() to ensure that we either run
|
// We must ensure capacity before calling handleMapping() to ensure that we either run
|
||||||
// both the press and release mapping for certain key or neither mapping.
|
// both the press and release mapping for certain key or neither mapping.
|
||||||
if (keyboard.pressed.len >= keyboard.pressed.keys.len) {
|
keyboard.pressed.keys.ensureUnusedCapacity(1) catch return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyboard.device.seat.handleMapping(keycode, modifiers, released, xkb_state)) {
|
if (keyboard.device.seat.handleMapping(keycode, modifiers, released, xkb_state)) {
|
||||||
break :blk .mapping;
|
break :blk .mapping;
|
||||||
|
@ -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 = @ptrCast(@alignCast(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, @ptrCast(@alignCast(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
|
||||||
@ -173,8 +172,10 @@ fn handleKeyboardInteractiveExclusive(output: *Output, consider: ?*LayerSurface)
|
|||||||
assert(s.wlr_layer_surface.current.keyboard_interactive != .none);
|
assert(s.wlr_layer_surface.current.keyboard_interactive != .none);
|
||||||
}
|
}
|
||||||
|
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |node| : (it = node.next) {
|
||||||
|
const seat = &node.data;
|
||||||
|
|
||||||
if (seat.focused_output == output) {
|
if (seat.focused_output == output) {
|
||||||
if (to_focus) |s| {
|
if (to_focus) |s| {
|
||||||
// If we found a surface on the output that requires focus, grab the focus of all
|
// If we found a surface on the output that requires focus, grab the focus of all
|
||||||
|
@ -38,9 +38,6 @@ layout_v3: *river.LayoutV3,
|
|||||||
namespace: []const u8,
|
namespace: []const u8,
|
||||||
output: *Output,
|
output: *Output,
|
||||||
|
|
||||||
// Output.layouts
|
|
||||||
link: wl.list.Link,
|
|
||||||
|
|
||||||
pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namespace: []const u8) !void {
|
pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namespace: []const u8) !void {
|
||||||
const layout_v3 = try river.LayoutV3.create(client, version, id);
|
const layout_v3 = try river.LayoutV3.create(client, version, id);
|
||||||
|
|
||||||
@ -50,22 +47,21 @@ pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namesp
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const layout = try util.gpa.create(Layout);
|
const node = try util.gpa.create(std.TailQueue(Layout).Node);
|
||||||
errdefer util.gpa.destroy(layout);
|
errdefer util.gpa.destroy(node);
|
||||||
layout.* = .{
|
node.data = .{
|
||||||
.layout_v3 = layout_v3,
|
.layout_v3 = layout_v3,
|
||||||
.namespace = try util.gpa.dupe(u8, namespace),
|
.namespace = try util.gpa.dupe(u8, namespace),
|
||||||
.output = output,
|
.output = output,
|
||||||
.link = undefined,
|
|
||||||
};
|
};
|
||||||
output.layouts.append(layout);
|
output.layouts.append(node);
|
||||||
|
|
||||||
layout_v3.setHandler(*Layout, handleRequest, handleDestroy, layout);
|
layout_v3.setHandler(*Layout, handleRequest, handleDestroy, &node.data);
|
||||||
|
|
||||||
// If the namespace matches that of the output, set the layout as
|
// If the namespace matches that of the output, set the layout as
|
||||||
// the active one of the output and arrange it.
|
// the active one of the output and arrange it.
|
||||||
if (mem.eql(u8, namespace, output.layoutNamespace())) {
|
if (mem.eql(u8, namespace, output.layoutNamespace())) {
|
||||||
output.layout = layout;
|
output.layout = &node.data;
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,17 +71,17 @@ pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namesp
|
|||||||
fn namespaceInUse(namespace: []const u8, output: *Output, client: *wl.Client) bool {
|
fn namespaceInUse(namespace: []const u8, output: *Output, client: *wl.Client) bool {
|
||||||
var output_it = server.root.active_outputs.iterator(.forward);
|
var output_it = server.root.active_outputs.iterator(.forward);
|
||||||
while (output_it.next()) |o| {
|
while (output_it.next()) |o| {
|
||||||
var layout_it = output.layouts.iterator(.forward);
|
var layout_it = output.layouts.first;
|
||||||
if (o == output) {
|
if (o == output) {
|
||||||
// On this output, no other layout can have our namespace.
|
// On this output, no other layout can have our namespace.
|
||||||
while (layout_it.next()) |layout| {
|
while (layout_it) |layout_node| : (layout_it = layout_node.next) {
|
||||||
if (mem.eql(u8, namespace, layout.namespace)) return true;
|
if (mem.eql(u8, namespace, layout_node.data.namespace)) return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Layouts on other outputs may share the namespace, if they come from the same client.
|
// Layouts on other outputs may share the namespace, if they come from the same client.
|
||||||
while (layout_it.next()) |layout| {
|
while (layout_it) |layout_node| : (layout_it = layout_node.next) {
|
||||||
if (mem.eql(u8, namespace, layout.namespace) and
|
if (mem.eql(u8, namespace, layout_node.data.namespace) and
|
||||||
client != layout.layout_v3.getClient()) return true;
|
client != layout_node.data.layout_v3.getClient()) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +185,9 @@ pub fn destroy(layout: *Layout) void {
|
|||||||
.{ layout.namespace, layout.output.wlr_output.name },
|
.{ layout.namespace, layout.output.wlr_output.name },
|
||||||
);
|
);
|
||||||
|
|
||||||
layout.link.remove();
|
// Remove layout from the list
|
||||||
|
const node: *std.TailQueue(Layout).Node = @fieldParentPtr("data", layout);
|
||||||
|
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.
|
||||||
if (layout.output.layout == layout) {
|
if (layout.output.layout == layout) {
|
||||||
@ -210,5 +208,5 @@ pub fn destroy(layout: *Layout) void {
|
|||||||
layout.layout_v3.setHandler(?*anyopaque, handleRequestInert, null, null);
|
layout.layout_v3.setHandler(?*anyopaque, handleRequestInert, null, null);
|
||||||
|
|
||||||
util.gpa.free(layout.namespace);
|
util.gpa.free(layout.namespace);
|
||||||
util.gpa.destroy(layout);
|
util.gpa.destroy(node);
|
||||||
}
|
}
|
||||||
|
@ -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 = @ptrCast(@alignCast(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 });
|
||||||
|
|
||||||
|
@ -110,8 +110,9 @@ fn handleLock(listener: *wl.Listener(*wlr.SessionLockV1), lock: *wlr.SessionLock
|
|||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |node| : (it = node.next) {
|
||||||
|
const seat = &node.data;
|
||||||
seat.setFocusRaw(.none);
|
seat.setFocusRaw(.none);
|
||||||
|
|
||||||
// Enter locked mode
|
// Enter locked mode
|
||||||
@ -212,8 +213,9 @@ fn handleUnlock(listener: *wl.Listener(void)) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |node| : (it = node.next) {
|
||||||
|
const seat = &node.data;
|
||||||
seat.setFocusRaw(.none);
|
seat.setFocusRaw(.none);
|
||||||
|
|
||||||
// Exit locked mode
|
// Exit locked mode
|
||||||
@ -264,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 = @ptrCast(@alignCast(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,11 +65,12 @@ 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 = @ptrCast(@alignCast(surface.data)) };
|
break .{ .lock_surface = @ptrFromInt(surface.data) };
|
||||||
} else .none;
|
} else .none;
|
||||||
|
|
||||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
var seat_it = server.input_manager.seats.first;
|
||||||
while (seat_it.next()) |seat| {
|
while (seat_it) |node| : (seat_it = node.next) {
|
||||||
|
const seat = &node.data;
|
||||||
if (seat.focused == .lock_surface and seat.focused.lock_surface == lock_surface) {
|
if (seat.focused == .lock_surface and seat.focused.lock_surface == lock_surface) {
|
||||||
seat.setFocusRaw(new_focus);
|
seat.setFocusRaw(new_focus);
|
||||||
}
|
}
|
||||||
@ -85,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 @ptrCast(@alignCast(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 {
|
||||||
@ -121,8 +122,9 @@ fn handleMap(listener: *wl.Listener(void)) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn updateFocus(lock_surface: *LockSurface) void {
|
fn updateFocus(lock_surface: *LockSurface) void {
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |node| : (it = node.next) {
|
||||||
|
const seat = &node.data;
|
||||||
if (seat.focused != .lock_surface) {
|
if (seat.focused != .lock_surface) {
|
||||||
seat.setFocusRaw(.{ .lock_surface = lock_surface });
|
seat.setFocusRaw(.{ .lock_surface = lock_surface });
|
||||||
}
|
}
|
||||||
|
@ -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: wl.list.Head(Layout, .link),
|
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.
|
||||||
@ -290,11 +294,8 @@ pub fn create(wlr_output: *wlr.Output) !void {
|
|||||||
.height = height,
|
.height = height,
|
||||||
},
|
},
|
||||||
.status = undefined,
|
.status = undefined,
|
||||||
.layouts = undefined,
|
|
||||||
};
|
};
|
||||||
wlr_output.data = output;
|
wlr_output.data = @intFromPtr(output);
|
||||||
|
|
||||||
output.layouts.init();
|
|
||||||
|
|
||||||
output.pending.focus_stack.init();
|
output.pending.focus_stack.init();
|
||||||
output.pending.wm_stack.init();
|
output.pending.wm_stack.init();
|
||||||
@ -363,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, @ptrCast(@alignCast(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;
|
||||||
@ -419,7 +420,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
|
|||||||
assert(output.inflight.focus_stack.empty());
|
assert(output.inflight.focus_stack.empty());
|
||||||
assert(output.inflight.wm_stack.empty());
|
assert(output.inflight.wm_stack.empty());
|
||||||
assert(output.inflight.layout_demand == null);
|
assert(output.inflight.layout_demand == null);
|
||||||
assert(output.layouts.length() == 0);
|
assert(output.layouts.len == 0);
|
||||||
|
|
||||||
output.all_link.remove();
|
output.all_link.remove();
|
||||||
|
|
||||||
@ -432,7 +433,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);
|
||||||
|
|
||||||
@ -455,7 +456,7 @@ fn handleRequestState(listener: *wl.Listener(*wlr.Output.event.RequestState), ev
|
|||||||
// TODO double buffer output state changes for frame perfection and cleaner code.
|
// TODO double buffer output state changes for frame perfection and cleaner code.
|
||||||
// Schedule a frame and commit in the frame handler.
|
// Schedule a frame and commit in the frame handler.
|
||||||
// Get rid of this function.
|
// Get rid of this function.
|
||||||
pub fn applyState(output: *Output, state: *const wlr.Output.State) error{CommitFailed}!void {
|
pub fn applyState(output: *Output, state: *wlr.Output.State) error{CommitFailed}!void {
|
||||||
|
|
||||||
// We need to be precise about this state change to make assertions
|
// We need to be precise about this state change to make assertions
|
||||||
// in updateLockRenderStateOnEnableDisable() possible.
|
// in updateLockRenderStateOnEnableDisable() possible.
|
||||||
@ -479,6 +480,7 @@ pub fn applyState(output: *Output, state: *const wlr.Output.State) error{CommitF
|
|||||||
|
|
||||||
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
|
||||||
@ -530,21 +532,44 @@ 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;
|
// TODO(wlroots): replace this with wlr_scene_output_needs_frame()
|
||||||
|
if (!output.wlr_output.needs_frame and !output.gamma_dirty and
|
||||||
|
!scene_output.pending_commit_damage.notEmpty())
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
// TODO(wlroots): remove this isHeadless() workaround after upstream fix is available
|
||||||
|
// in a release: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4868
|
||||||
|
if (!output.wlr_output.testState(&state) or output.wlr_output.isHeadless()) {
|
||||||
|
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;
|
||||||
@ -559,6 +584,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)
|
||||||
@ -622,7 +649,7 @@ fn handlePresent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setTitle(output: Output) void {
|
fn setTitle(output: Output) void {
|
||||||
const title = fmt.allocPrintSentinel(util.gpa, "river - {s}", .{output.wlr_output.name}, 0) catch return;
|
const title = fmt.allocPrintZ(util.gpa, "river - {s}", .{output.wlr_output.name}) catch return;
|
||||||
defer util.gpa.free(title);
|
defer util.gpa.free(title);
|
||||||
if (output.wlr_output.isWl()) {
|
if (output.wlr_output.isWl()) {
|
||||||
output.wlr_output.wlSetTitle(title);
|
output.wlr_output.wlSetTitle(title);
|
||||||
@ -634,9 +661,9 @@ fn setTitle(output: Output) void {
|
|||||||
pub fn handleLayoutNamespaceChange(output: *Output) void {
|
pub fn handleLayoutNamespaceChange(output: *Output) void {
|
||||||
// The user changed the layout namespace of this output. Try to find a
|
// The user changed the layout namespace of this output. Try to find a
|
||||||
// matching layout.
|
// matching layout.
|
||||||
var it = output.layouts.iterator(.forward);
|
var it = output.layouts.first;
|
||||||
output.layout = while (it.next()) |layout| {
|
output.layout = while (it) |node| : (it = node.next) {
|
||||||
if (mem.eql(u8, output.layoutNamespace(), layout.namespace)) break layout;
|
if (mem.eql(u8, output.layoutNamespace(), node.data.namespace)) break &node.data;
|
||||||
} else null;
|
} else null;
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
}
|
}
|
||||||
|
@ -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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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,15 +323,16 @@ 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, @ptrCast(@alignCast(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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any seat has the removed output focused, focus the fallback one
|
// If any seat has the removed output focused, focus the fallback one
|
||||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
var seat_it = server.input_manager.seats.first;
|
||||||
while (seat_it.next()) |seat| {
|
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||||
|
const seat = &seat_node.data;
|
||||||
if (seat.focused_output == output) {
|
if (seat.focused_output == output) {
|
||||||
seat.focusOutput(fallback_output);
|
seat.focusOutput(fallback_output);
|
||||||
}
|
}
|
||||||
@ -352,7 +346,7 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
|
|||||||
output.inflight.layout_demand = null;
|
output.inflight.layout_demand = null;
|
||||||
root.notifyLayoutDemandDone();
|
root.notifyLayoutDemandDone();
|
||||||
}
|
}
|
||||||
while (output.layouts.first()) |layout| layout.destroy();
|
while (output.layouts.first) |node| node.data.destroy();
|
||||||
|
|
||||||
// We must call reconfigureDevices here to unmap devices that might be mapped to this output
|
// We must call reconfigureDevices here to unmap devices that might be mapped to this output
|
||||||
// in order to prevent a segfault in wlroots.
|
// in order to prevent a segfault in wlroots.
|
||||||
@ -396,8 +390,9 @@ pub fn activateOutput(root: *Root, output: *Output) void {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Focus the new output with all seats
|
// Focus the new output with all seats
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |seat_node| : (it = seat_node.next) {
|
||||||
|
const seat = &seat_node.data;
|
||||||
seat.focusOutput(output);
|
seat.focusOutput(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -433,8 +428,8 @@ pub fn applyPending(root: *Root) void {
|
|||||||
// state consistent. Instead of having focus(null) calls spread all
|
// state consistent. Instead of having focus(null) calls spread all
|
||||||
// around the codebase and risk forgetting one, always ensure focus
|
// around the codebase and risk forgetting one, always ensure focus
|
||||||
// state is synchronized here.
|
// state is synchronized here.
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| seat.focus(null);
|
while (it) |node| : (it = node.next) node.data.focus(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is already a transaction inflight, wait until it completes.
|
// If there is already a transaction inflight, wait until it completes.
|
||||||
@ -544,9 +539,11 @@ pub fn applyPending(root: *Root) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |node| : (it = node.next) {
|
||||||
switch (seat.cursor.mode) {
|
const cursor = &node.data.cursor;
|
||||||
|
|
||||||
|
switch (cursor.mode) {
|
||||||
.passthrough, .down => {},
|
.passthrough, .down => {},
|
||||||
inline .move, .resize => |data| {
|
inline .move, .resize => |data| {
|
||||||
if (data.view.inflight.output == null or
|
if (data.view.inflight.output == null or
|
||||||
@ -554,14 +551,14 @@ pub fn applyPending(root: *Root) void {
|
|||||||
(!data.view.inflight.float and data.view.inflight.output.?.layout != null) or
|
(!data.view.inflight.float and data.view.inflight.output.?.layout != null) or
|
||||||
data.view.inflight.fullscreen)
|
data.view.inflight.fullscreen)
|
||||||
{
|
{
|
||||||
seat.cursor.mode = .passthrough;
|
cursor.mode = .passthrough;
|
||||||
data.view.pending.resizing = false;
|
data.view.pending.resizing = false;
|
||||||
data.view.inflight.resizing = false;
|
data.view.inflight.resizing = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
seat.cursor.inflight_mode = seat.cursor.mode;
|
cursor.inflight_mode = cursor.mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,8 +703,11 @@ fn commitTransaction(root: *Root) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| seat.cursor.updateState();
|
while (it) |node| : (it = node.next) {
|
||||||
|
node.data.cursor.updateState();
|
||||||
|
node.data.sendFocusedView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -798,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 = @ptrCast(@alignCast(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);
|
||||||
@ -850,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 = @ptrCast(@alignCast(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),
|
||||||
@ -880,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, @ptrCast(@alignCast(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, @ptrCast(@alignCast(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);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ focused_output: ?*Output = null,
|
|||||||
focused: FocusTarget = .none,
|
focused: FocusTarget = .none,
|
||||||
|
|
||||||
/// List of status tracking objects relaying changes to this seat to clients.
|
/// List of status tracking objects relaying changes to this seat to clients.
|
||||||
status_trackers: wl.list.Head(SeatStatus, .link),
|
status_trackers: std.SinglyLinkedList(SeatStatus) = .{},
|
||||||
|
|
||||||
/// The currently in progress drag operation type.
|
/// The currently in progress drag operation type.
|
||||||
drag: enum {
|
drag: enum {
|
||||||
@ -109,13 +109,7 @@ drag_destroy: wl.Listener(*wlr.Drag) = wl.Listener(*wlr.Drag).init(handleDragDes
|
|||||||
request_set_primary_selection: wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection) =
|
request_set_primary_selection: wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection) =
|
||||||
wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection).init(handleRequestSetPrimarySelection),
|
wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection).init(handleRequestSetPrimarySelection),
|
||||||
|
|
||||||
// InputManager.seats
|
pub fn init(seat: *Seat, name: [*:0]const u8) !void {
|
||||||
link: wl.list.Link = undefined,
|
|
||||||
|
|
||||||
pub fn create(name: [*:0]const u8) !void {
|
|
||||||
const seat = try util.gpa.create(Seat);
|
|
||||||
errdefer util.gpa.destroy(seat);
|
|
||||||
|
|
||||||
const event_loop = server.wl_server.getEventLoop();
|
const event_loop = server.wl_server.getEventLoop();
|
||||||
const mapping_repeat_timer = try event_loop.addTimer(*Seat, handleMappingRepeatTimeout, seat);
|
const mapping_repeat_timer = try event_loop.addTimer(*Seat, handleMappingRepeatTimeout, seat);
|
||||||
errdefer mapping_repeat_timer.remove();
|
errdefer mapping_repeat_timer.remove();
|
||||||
@ -127,18 +121,13 @@ pub fn create(name: [*:0]const u8) !void {
|
|||||||
.relay = undefined,
|
.relay = undefined,
|
||||||
.mapping_repeat_timer = mapping_repeat_timer,
|
.mapping_repeat_timer = mapping_repeat_timer,
|
||||||
.keyboard_group = try wlr.KeyboardGroup.create(),
|
.keyboard_group = try wlr.KeyboardGroup.create(),
|
||||||
.status_trackers = undefined,
|
|
||||||
.link = undefined,
|
|
||||||
};
|
};
|
||||||
seat.wlr_seat.data = seat;
|
seat.wlr_seat.data = @intFromPtr(seat);
|
||||||
|
|
||||||
server.input_manager.seats.append(seat);
|
|
||||||
seat.status_trackers.init();
|
|
||||||
|
|
||||||
try seat.cursor.init(seat);
|
try seat.cursor.init(seat);
|
||||||
seat.relay.init();
|
seat.relay.init();
|
||||||
|
|
||||||
try seat.tryAddDevice(&seat.keyboard_group.keyboard.base, false);
|
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);
|
||||||
@ -146,7 +135,7 @@ pub fn create(name: [*:0]const u8) !void {
|
|||||||
seat.wlr_seat.events.request_set_primary_selection.add(&seat.request_set_primary_selection);
|
seat.wlr_seat.events.request_set_primary_selection.add(&seat.request_set_primary_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(seat: *Seat) void {
|
pub fn deinit(seat: *Seat) void {
|
||||||
{
|
{
|
||||||
var it = server.input_manager.devices.iterator(.forward);
|
var it = server.input_manager.devices.iterator(.forward);
|
||||||
while (it.next()) |device| assert(device.seat != seat);
|
while (it.next()) |device| assert(device.seat != seat);
|
||||||
@ -162,10 +151,6 @@ pub fn destroy(seat: *Seat) void {
|
|||||||
seat.start_drag.link.remove();
|
seat.start_drag.link.remove();
|
||||||
if (seat.drag != .none) seat.drag_destroy.link.remove();
|
if (seat.drag != .none) seat.drag_destroy.link.remove();
|
||||||
seat.request_set_primary_selection.link.remove();
|
seat.request_set_primary_selection.link.remove();
|
||||||
|
|
||||||
seat.link.remove();
|
|
||||||
|
|
||||||
util.gpa.destroy(seat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the current focus. If a visible view is passed it will be focused.
|
/// Set the current focus. If a visible view is passed it will be focused.
|
||||||
@ -304,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 = @ptrCast(@alignCast(wlr_constraint.data));
|
seat.cursor.constraint = @ptrFromInt(wlr_constraint.data);
|
||||||
assert(seat.cursor.constraint != null);
|
assert(seat.cursor.constraint != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,10 +300,7 @@ pub fn setFocusRaw(seat: *Seat, new_focus: FocusTarget) void {
|
|||||||
seat.cursor.may_need_warp = true;
|
seat.cursor.may_need_warp = true;
|
||||||
|
|
||||||
// Inform any clients tracking status of the change
|
// Inform any clients tracking status of the change
|
||||||
var it = seat.status_trackers.iterator(.forward);
|
seat.sendFocusedView();
|
||||||
while (it.next()) |tracker| {
|
|
||||||
tracker.sendFocusedView();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send keyboard enter/leave events and handle pointer constraints
|
/// Send keyboard enter/leave events and handle pointer constraints
|
||||||
@ -334,17 +316,16 @@ 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 = @ptrCast(@alignCast(wlr_keyboard.data));
|
const keyboard: *Keyboard = @ptrFromInt(wlr_keyboard.data);
|
||||||
|
|
||||||
var buffer: [Keyboard.Pressed.capacity]u32 = undefined;
|
var keycodes: std.BoundedArray(u32, Keyboard.Pressed.capacity) = .{};
|
||||||
var keycodes: std.ArrayList(u32) = .initBuffer(&buffer);
|
for (keyboard.pressed.keys.constSlice()) |item| {
|
||||||
for (keyboard.pressed.slice()) |item| {
|
|
||||||
if (item.consumer == .focus) keycodes.appendAssumeCapacity(item.code);
|
if (item.consumer == .focus) keycodes.appendAssumeCapacity(item.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
seat.wlr_seat.keyboardNotifyEnter(
|
seat.wlr_seat.keyboardNotifyEnter(
|
||||||
wlr_surface,
|
wlr_surface,
|
||||||
keycodes.items,
|
keycodes.constSlice(),
|
||||||
&wlr_keyboard.modifiers,
|
&wlr_keyboard.modifiers,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -357,15 +338,15 @@ pub fn focusOutput(seat: *Seat, output: ?*Output) void {
|
|||||||
if (seat.focused_output == output) return;
|
if (seat.focused_output == output) return;
|
||||||
|
|
||||||
if (seat.focused_output) |old| {
|
if (seat.focused_output) |old| {
|
||||||
var it = seat.status_trackers.iterator(.forward);
|
var it = seat.status_trackers.first;
|
||||||
while (it.next()) |tracker| tracker.sendOutput(old, .unfocused);
|
while (it) |node| : (it = node.next) node.data.sendOutput(old, .unfocused);
|
||||||
}
|
}
|
||||||
|
|
||||||
seat.focused_output = output;
|
seat.focused_output = output;
|
||||||
|
|
||||||
if (seat.focused_output) |new| {
|
if (seat.focused_output) |new| {
|
||||||
var it = seat.status_trackers.iterator(.forward);
|
var it = seat.status_trackers.first;
|
||||||
while (it.next()) |tracker| tracker.sendOutput(new, .focused);
|
while (it) |node| : (it = node.next) node.data.sendOutput(new, .focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depending on configuration and cursor position, changing output focus
|
// Depending on configuration and cursor position, changing output focus
|
||||||
@ -380,9 +361,9 @@ pub fn handleActivity(seat: Seat) void {
|
|||||||
pub fn enterMode(seat: *Seat, mode_id: u32) void {
|
pub fn enterMode(seat: *Seat, mode_id: u32) void {
|
||||||
seat.mode_id = mode_id;
|
seat.mode_id = mode_id;
|
||||||
|
|
||||||
var it = seat.status_trackers.iterator(.forward);
|
var it = seat.status_trackers.first;
|
||||||
while (it.next()) |tracker| {
|
while (it) |node| : (it = node.next) {
|
||||||
tracker.sendMode(server.config.modes.items[mode_id].name);
|
node.data.sendMode(server.config.modes.items[mode_id].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,8 +457,8 @@ pub fn runCommand(seat: *Seat, args: []const [:0]const u8) void {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (out) |s| {
|
if (out) |s| {
|
||||||
var stdout = std.fs.File.stdout().writer(&.{});
|
const stdout = std.io.getStdOut().writer();
|
||||||
stdout.interface.print("{s}", .{s}) catch |err| {
|
stdout.print("{s}", .{s}) catch |err| {
|
||||||
std.log.scoped(.command).err("{s}: write to stdout failed {}", .{ args[0], err });
|
std.log.scoped(.command).err("{s}: write to stdout failed {}", .{ args[0], err });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -503,19 +484,19 @@ fn handleMappingRepeatTimeout(seat: *Seat) c_int {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addDevice(seat: *Seat, wlr_device: *wlr.InputDevice, virtual: bool) void {
|
pub fn addDevice(seat: *Seat, wlr_device: *wlr.InputDevice) void {
|
||||||
seat.tryAddDevice(wlr_device, virtual) catch |err| switch (err) {
|
seat.tryAddDevice(wlr_device) catch |err| switch (err) {
|
||||||
error.OutOfMemory => log.err("out of memory", .{}),
|
error.OutOfMemory => log.err("out of memory", .{}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tryAddDevice(seat: *Seat, wlr_device: *wlr.InputDevice, virtual: bool) !void {
|
fn tryAddDevice(seat: *Seat, wlr_device: *wlr.InputDevice) !void {
|
||||||
switch (wlr_device.type) {
|
switch (wlr_device.type) {
|
||||||
.keyboard => {
|
.keyboard => {
|
||||||
const keyboard = try util.gpa.create(Keyboard);
|
const keyboard = try util.gpa.create(Keyboard);
|
||||||
errdefer util.gpa.destroy(keyboard);
|
errdefer util.gpa.destroy(keyboard);
|
||||||
|
|
||||||
try keyboard.init(seat, wlr_device, virtual);
|
try keyboard.init(seat, wlr_device);
|
||||||
|
|
||||||
seat.wlr_seat.setKeyboard(keyboard.device.wlr_device.toKeyboard());
|
seat.wlr_seat.setKeyboard(keyboard.device.wlr_device.toKeyboard());
|
||||||
if (seat.wlr_seat.keyboard_state.focused_surface) |wlr_surface| {
|
if (seat.wlr_seat.keyboard_state.focused_surface) |wlr_surface| {
|
||||||
|
@ -33,19 +33,8 @@ const View = @import("View.zig");
|
|||||||
seat: *Seat,
|
seat: *Seat,
|
||||||
seat_status_v1: *zriver.SeatStatusV1,
|
seat_status_v1: *zriver.SeatStatusV1,
|
||||||
|
|
||||||
link: wl.list.Link,
|
pub fn init(seat_status: *SeatStatus, seat: *Seat, seat_status_v1: *zriver.SeatStatusV1) void {
|
||||||
|
seat_status.* = .{ .seat = seat, .seat_status_v1 = seat_status_v1 };
|
||||||
pub fn create(seat: *Seat, seat_status_v1: *zriver.SeatStatusV1) !void {
|
|
||||||
const seat_status = try util.gpa.create(SeatStatus);
|
|
||||||
errdefer util.gpa.destroy(seat_status);
|
|
||||||
|
|
||||||
seat_status.* = .{
|
|
||||||
.seat = seat,
|
|
||||||
.seat_status_v1 = seat_status_v1,
|
|
||||||
.link = undefined,
|
|
||||||
};
|
|
||||||
seat.status_trackers.append(seat_status);
|
|
||||||
errdefer comptime unreachable;
|
|
||||||
|
|
||||||
seat_status_v1.setHandler(*SeatStatus, handleRequest, handleDestroy, seat_status);
|
seat_status_v1.setHandler(*SeatStatus, handleRequest, handleDestroy, seat_status);
|
||||||
|
|
||||||
@ -62,8 +51,9 @@ fn handleRequest(seat_status_v1: *zriver.SeatStatusV1, request: zriver.SeatStatu
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleDestroy(_: *zriver.SeatStatusV1, seat_status: *SeatStatus) void {
|
fn handleDestroy(_: *zriver.SeatStatusV1, seat_status: *SeatStatus) void {
|
||||||
seat_status.link.remove();
|
const node: *std.SinglyLinkedList(SeatStatus).Node = @fieldParentPtr("data", seat_status);
|
||||||
util.gpa.destroy(seat_status);
|
seat_status.seat.status_trackers.remove(node);
|
||||||
|
util.gpa.destroy(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendOutput(seat_status: SeatStatus, output: *Output, state: enum { focused, unfocused }) void {
|
pub fn sendOutput(seat_status: SeatStatus, output: *Output, state: enum { focused, unfocused }) void {
|
||||||
|
@ -24,7 +24,7 @@ const posix = std.posix;
|
|||||||
const wlr = @import("wlroots");
|
const wlr = @import("wlroots");
|
||||||
const wl = @import("wayland").server.wl;
|
const wl = @import("wayland").server.wl;
|
||||||
|
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
const Config = @import("Config.zig");
|
const Config = @import("Config.zig");
|
||||||
@ -61,8 +61,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,
|
||||||
@ -85,8 +85,6 @@ screencopy_manager: *wlr.ScreencopyManagerV1,
|
|||||||
|
|
||||||
foreign_toplevel_manager: *wlr.ForeignToplevelManagerV1,
|
foreign_toplevel_manager: *wlr.ForeignToplevelManagerV1,
|
||||||
|
|
||||||
foreign_toplevel_list: *wlr.ExtForeignToplevelListV1,
|
|
||||||
|
|
||||||
tearing_control_manager: *wlr.TearingControlManagerV1,
|
tearing_control_manager: *wlr.TearingControlManagerV1,
|
||||||
|
|
||||||
alpha_modifier: *wlr.AlphaModifierV1,
|
alpha_modifier: *wlr.AlphaModifierV1,
|
||||||
@ -166,8 +164,6 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
|
|||||||
|
|
||||||
.foreign_toplevel_manager = try wlr.ForeignToplevelManagerV1.create(wl_server),
|
.foreign_toplevel_manager = try wlr.ForeignToplevelManagerV1.create(wl_server),
|
||||||
|
|
||||||
.foreign_toplevel_list = try wlr.ExtForeignToplevelListV1.create(wl_server, 1),
|
|
||||||
|
|
||||||
.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),
|
.alpha_modifier = try wlr.AlphaModifierV1.create(wl_server),
|
||||||
@ -184,14 +180,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);
|
||||||
@ -237,8 +233,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
|
||||||
@ -299,12 +293,8 @@ 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
|
||||||
@ -348,7 +338,6 @@ fn blocklist(server: *Server, global: *const wl.Global) bool {
|
|||||||
return global == server.security_context_manager.global or
|
return global == server.security_context_manager.global or
|
||||||
global == server.layer_shell.global or
|
global == server.layer_shell.global or
|
||||||
global == server.foreign_toplevel_manager.global or
|
global == server.foreign_toplevel_manager.global or
|
||||||
global == server.foreign_toplevel_list.global or
|
|
||||||
global == server.screencopy_manager.global or
|
global == server.screencopy_manager.global or
|
||||||
global == server.export_dmabuf_manager.global or
|
global == server.export_dmabuf_manager.global or
|
||||||
global == server.data_control_manager.global or
|
global == server.data_control_manager.global or
|
||||||
@ -510,7 +499,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 = @ptrCast(@alignCast(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);
|
||||||
|
@ -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 = @ptrCast(@alignCast(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,13 @@ 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 = @ptrCast(@alignCast(wlr_seat.seat.data));
|
const seat: *Seat = @ptrFromInt(wlr_seat.seat.data);
|
||||||
|
|
||||||
|
const node = util.gpa.create(std.SinglyLinkedList(SeatStatus).Node) catch {
|
||||||
|
status_manager_v1.getClient().postNoMemory();
|
||||||
|
log.err("out of memory", .{});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
const seat_status = zriver.SeatStatusV1.create(
|
const seat_status = zriver.SeatStatusV1.create(
|
||||||
status_manager_v1.getClient(),
|
status_manager_v1.getClient(),
|
||||||
@ -94,15 +100,13 @@ fn handleRequest(
|
|||||||
req.id,
|
req.id,
|
||||||
) catch {
|
) catch {
|
||||||
status_manager_v1.getClient().postNoMemory();
|
status_manager_v1.getClient().postNoMemory();
|
||||||
|
util.gpa.destroy(node);
|
||||||
log.err("out of memory", .{});
|
log.err("out of memory", .{});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
SeatStatus.create(seat, seat_status) catch {
|
node.data.init(seat, seat_status);
|
||||||
status_manager_v1.getClient().postNoMemory();
|
seat.status_trackers.prepend(node);
|
||||||
log.err("out of memory", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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, @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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();
|
||||||
|
@ -181,8 +181,6 @@ post_fullscreen_box: wlr.Box = undefined,
|
|||||||
|
|
||||||
foreign_toplevel_handle: ForeignToplevelHandle = .{},
|
foreign_toplevel_handle: ForeignToplevelHandle = .{},
|
||||||
|
|
||||||
ext_foreign_toplevel_handle: ?*wlr.ExtForeignToplevelHandleV1 = null,
|
|
||||||
|
|
||||||
/// Connector name of the output this view occupied before an evacuation.
|
/// Connector name of the output this view occupied before an evacuation.
|
||||||
output_before_evac: ?[]const u8 = null,
|
output_before_evac: ?[]const u8 = null,
|
||||||
|
|
||||||
@ -277,12 +275,11 @@ pub fn resizeUpdatePosition(view: *View, width: i32, height: i32) void {
|
|||||||
assert(view.inflight.resizing);
|
assert(view.inflight.resizing);
|
||||||
|
|
||||||
const data = blk: {
|
const data = blk: {
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| {
|
while (it) |node| : (it = node.next) {
|
||||||
if (seat.cursor.inflight_mode == .resize and
|
const cursor = &node.data.cursor;
|
||||||
seat.cursor.inflight_mode.resize.view == view)
|
if (cursor.inflight_mode == .resize and cursor.inflight_mode.resize.view == view) {
|
||||||
{
|
break :blk cursor.inflight_mode.resize;
|
||||||
break :blk seat.cursor.inflight_mode.resize;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The view resizing state should never be set when the view is
|
// The view resizing state should never be set when the view is
|
||||||
@ -449,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;
|
||||||
|
|
||||||
@ -489,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +589,7 @@ pub fn allowTearing(view: *View) bool {
|
|||||||
.window_hint => {
|
.window_hint => {
|
||||||
if (server.config.allow_tearing) {
|
if (server.config.allow_tearing) {
|
||||||
if (view.rootSurface()) |root_surface| {
|
if (view.rootSurface()) |root_surface| {
|
||||||
return server.tearing_control_manager.hintFromSurface(root_surface) == .async;
|
return server.tearing_control_manager.hintFromSurface(root_surface) == .@"async";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -659,15 +653,6 @@ pub fn map(view: *View) !void {
|
|||||||
assert(!view.mapped and !view.destroying);
|
assert(!view.mapped and !view.destroying);
|
||||||
view.mapped = true;
|
view.mapped = true;
|
||||||
|
|
||||||
if (wlr.ExtForeignToplevelHandleV1.create(server.foreign_toplevel_list, &.{
|
|
||||||
.title = view.getTitle(),
|
|
||||||
.app_id = view.getAppId(),
|
|
||||||
})) |handle| {
|
|
||||||
view.ext_foreign_toplevel_handle = handle;
|
|
||||||
} else |_| {
|
|
||||||
log.err("failed to create ext foreign toplevel handle", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
view.foreign_toplevel_handle.map();
|
view.foreign_toplevel_handle.map();
|
||||||
|
|
||||||
if (server.config.rules.float.match(view)) |float| {
|
if (server.config.rules.float.match(view)) |float| {
|
||||||
@ -721,8 +706,8 @@ pub fn map(view: *View) !void {
|
|||||||
if (output) |o| {
|
if (output) |o| {
|
||||||
view.setPendingOutput(o);
|
view.setPendingOutput(o);
|
||||||
|
|
||||||
var it = server.input_manager.seats.iterator(.forward);
|
var it = server.input_manager.seats.first;
|
||||||
while (it.next()) |seat| seat.focus(view);
|
while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(view);
|
||||||
} else {
|
} else {
|
||||||
log.debug("no output available for newly mapped view, adding to fallback stacks", .{});
|
log.debug("no output available for newly mapped view, adding to fallback stacks", .{});
|
||||||
|
|
||||||
@ -767,10 +752,6 @@ pub fn unmap(view: *View) void {
|
|||||||
assert(view.mapped and !view.destroying);
|
assert(view.mapped and !view.destroying);
|
||||||
view.mapped = false;
|
view.mapped = false;
|
||||||
|
|
||||||
if (view.ext_foreign_toplevel_handle) |handle| {
|
|
||||||
handle.destroy();
|
|
||||||
view.ext_foreign_toplevel_handle = null;
|
|
||||||
}
|
|
||||||
view.foreign_toplevel_handle.unmap();
|
view.foreign_toplevel_handle.unmap();
|
||||||
|
|
||||||
server.root.applyPending();
|
server.root.applyPending();
|
||||||
@ -781,19 +762,12 @@ pub fn notifyState(view: *const View) void {
|
|||||||
if (view.getTitle()) |title| wlr_handle.setTitle(title);
|
if (view.getTitle()) |title| wlr_handle.setTitle(title);
|
||||||
}
|
}
|
||||||
// Send title and tags to all status listeners attached to a seat which focuses this view
|
// Send title and tags to all status listeners attached to a seat which focuses this view
|
||||||
if (view.ext_foreign_toplevel_handle) |handle| {
|
var seat_it = server.input_manager.seats.first;
|
||||||
handle.updateState(&.{
|
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||||
.title = view.getTitle(),
|
if (seat_node.data.focused == .view and seat_node.data.focused.view == view) {
|
||||||
.app_id = view.getAppId(),
|
var client_it = seat_node.data.status_trackers.first;
|
||||||
});
|
while (client_it) |client_node| : (client_it = client_node.next) {
|
||||||
}
|
client_node.data.sendFocusedView();
|
||||||
// Send title to all status listeners attached to a seat which focuses this view
|
|
||||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
|
||||||
while (seat_it.next()) |seat| {
|
|
||||||
if (seat.focused == .view and seat.focused.view == view) {
|
|
||||||
var it = seat.status_trackers.iterator(.forward);
|
|
||||||
while (it.next()) |tracker| {
|
|
||||||
tracker.sendFocusedView();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -803,11 +777,4 @@ pub fn notifyAppId(view: View) void {
|
|||||||
if (view.foreign_toplevel_handle.wlr_handle) |wlr_handle| {
|
if (view.foreign_toplevel_handle.wlr_handle) |wlr_handle| {
|
||||||
if (view.getAppId()) |app_id| wlr_handle.setAppId(app_id);
|
if (view.getAppId()) |app_id| wlr_handle.setAppId(app_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view.ext_foreign_toplevel_handle) |handle| {
|
|
||||||
handle.updateState(&.{
|
|
||||||
.title = view.getTitle(),
|
|
||||||
.app_id = view.getAppId(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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 = @ptrCast(@alignCast(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,14 +159,15 @@ 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;
|
||||||
|
|
||||||
// If the unmapped surface is currently focused, pass keyboard focus
|
// If the unmapped surface is currently focused, pass keyboard focus
|
||||||
// to the most appropriate surface.
|
// to the most appropriate surface.
|
||||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
var seat_it = server.input_manager.seats.first;
|
||||||
while (seat_it.next()) |seat| {
|
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||||
|
const seat = &seat_node.data;
|
||||||
if (seat.focused == .view and seat.focused.view.impl == .xwayland_view and
|
if (seat.focused == .view and seat.focused.view.impl == .xwayland_view and
|
||||||
seat.focused.view.impl.xwayland_view.xwayland_surface.pid == override_redirect.xwayland_surface.pid and
|
seat.focused.view.impl.xwayland_view.xwayland_surface.pid == override_redirect.xwayland_surface.pid and
|
||||||
seat.wlr_seat.keyboard_state.focused_surface == override_redirect.xwayland_surface.surface)
|
seat.wlr_seat.keyboard_state.focused_surface == override_redirect.xwayland_surface.surface)
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub const c = @cImport({
|
pub usingnamespace @cImport({
|
||||||
@cDefine("_POSIX_C_SOURCE", "200809L");
|
@cDefine("_POSIX_C_SOURCE", "200809L");
|
||||||
|
|
||||||
@cInclude("stdlib.h");
|
@cInclude("stdlib.h");
|
||||||
|
@ -122,7 +122,6 @@ pub const Error = error{
|
|||||||
CannotParseFile,
|
CannotParseFile,
|
||||||
UnknownOption,
|
UnknownOption,
|
||||||
ConflictingOptions,
|
ConflictingOptions,
|
||||||
WriteFailed,
|
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
Other,
|
Other,
|
||||||
};
|
};
|
||||||
@ -166,7 +165,7 @@ pub fn errToMsg(err: Error) [:0]const u8 {
|
|||||||
Error.InvalidValue => "invalid value",
|
Error.InvalidValue => "invalid value",
|
||||||
Error.CannotReadFile => "cannot read file",
|
Error.CannotReadFile => "cannot read file",
|
||||||
Error.CannotParseFile => "cannot parse file",
|
Error.CannotParseFile => "cannot parse file",
|
||||||
Error.WriteFailed, Error.OutOfMemory => "out of memory",
|
Error.OutOfMemory => "out of memory",
|
||||||
Error.Other => unreachable,
|
Error.Other => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,9 @@ pub fn cursor(
|
|||||||
if (args.len < 3) return Error.NotEnoughArguments;
|
if (args.len < 3) return Error.NotEnoughArguments;
|
||||||
if (args.len > 3) return Error.TooManyArguments;
|
if (args.len > 3) return Error.TooManyArguments;
|
||||||
server.config.cursor_hide_timeout = try std.fmt.parseInt(u31, args[2], 10);
|
server.config.cursor_hide_timeout = try std.fmt.parseInt(u31, args[2], 10);
|
||||||
var seat_it = server.input_manager.seats.iterator(.forward);
|
var seat_it = server.input_manager.seats.first;
|
||||||
while (seat_it.next()) |seat| {
|
while (seat_it) |seat_node| : (seat_it = seat_node.next) {
|
||||||
|
const seat = &seat_node.data;
|
||||||
seat.cursor.unhide();
|
seat.cursor.unhide();
|
||||||
}
|
}
|
||||||
} else if (std.mem.eql(u8, "when-typing", args[1])) {
|
} else if (std.mem.eql(u8, "when-typing", args[1])) {
|
||||||
|
@ -34,8 +34,8 @@ pub fn listInputs(
|
|||||||
) Error!void {
|
) Error!void {
|
||||||
if (args.len > 1) return error.TooManyArguments;
|
if (args.len > 1) return error.TooManyArguments;
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(util.gpa);
|
var input_list = std.ArrayList(u8).init(util.gpa);
|
||||||
|
const writer = input_list.writer();
|
||||||
var prev = false;
|
var prev = false;
|
||||||
|
|
||||||
var it = server.input_manager.devices.iterator(.forward);
|
var it = server.input_manager.devices.iterator(.forward);
|
||||||
@ -46,16 +46,16 @@ pub fn listInputs(
|
|||||||
}
|
}
|
||||||
} else false;
|
} else false;
|
||||||
|
|
||||||
if (prev) try aw.writer.writeByte('\n');
|
if (prev) try input_list.appendSlice("\n");
|
||||||
prev = true;
|
prev = true;
|
||||||
|
|
||||||
try aw.writer.print("{s}\n\tconfigured: {}\n", .{
|
try writer.print("{s}\n\tconfigured: {}\n", .{
|
||||||
device.identifier,
|
device.identifier,
|
||||||
configured,
|
configured,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
out.* = try aw.toOwnedSlice();
|
out.* = try input_list.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listInputConfigs(
|
pub fn listInputConfigs(
|
||||||
@ -65,14 +65,15 @@ pub fn listInputConfigs(
|
|||||||
) Error!void {
|
) Error!void {
|
||||||
if (args.len > 1) return error.TooManyArguments;
|
if (args.len > 1) return error.TooManyArguments;
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(util.gpa);
|
var input_list = std.ArrayList(u8).init(util.gpa);
|
||||||
|
const writer = input_list.writer();
|
||||||
|
|
||||||
for (server.input_manager.configs.items, 0..) |*input_config, i| {
|
for (server.input_manager.configs.items, 0..) |*input_config, i| {
|
||||||
if (i > 0) try aw.writer.writeByte('\n');
|
if (i > 0) try writer.writeByte('\n');
|
||||||
try input_config.write(&aw.writer);
|
try input_config.write(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
out.* = try aw.toOwnedSlice();
|
out.* = try input_list.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(
|
pub fn input(
|
||||||
@ -98,7 +99,7 @@ pub fn input(
|
|||||||
};
|
};
|
||||||
errdefer util.gpa.free(input_config.glob);
|
errdefer util.gpa.free(input_config.glob);
|
||||||
|
|
||||||
try server.input_manager.configs.ensureUnusedCapacity(util.gpa, 1);
|
try server.input_manager.configs.ensureUnusedCapacity(1);
|
||||||
|
|
||||||
try input_config.parse(args[2], args[3]);
|
try input_config.parse(args[2], args[3]);
|
||||||
|
|
||||||
|
@ -71,8 +71,9 @@ pub fn sendLayoutCmd(
|
|||||||
const output = seat.focused_output orelse return;
|
const output = seat.focused_output orelse return;
|
||||||
const target_namespace = args[1];
|
const target_namespace = args[1];
|
||||||
|
|
||||||
var it = output.layouts.iterator(.forward);
|
var it = output.layouts.first;
|
||||||
const layout = while (it.next()) |layout| {
|
const layout = while (it) |node| : (it = node.next) {
|
||||||
|
const layout = &node.data;
|
||||||
if (mem.eql(u8, layout.namespace, target_namespace)) break layout;
|
if (mem.eql(u8, layout.namespace, target_namespace)) break layout;
|
||||||
} else return;
|
} else return;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ const wlr = @import("wlroots");
|
|||||||
const xkb = @import("xkbcommon");
|
const xkb = @import("xkbcommon");
|
||||||
const flags = @import("flags");
|
const flags = @import("flags");
|
||||||
|
|
||||||
const c = @import("../c.zig").c;
|
const c = @import("../c.zig");
|
||||||
const server = &@import("../main.zig").server;
|
const server = &@import("../main.zig").server;
|
||||||
const util = @import("../util.zig");
|
const util = @import("../util.zig");
|
||||||
|
|
||||||
@ -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 @ptrCast(@alignCast(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);
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
|
|
||||||
const globber = @import("globber");
|
const globber = @import("globber");
|
||||||
@ -28,7 +27,6 @@ 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 Anchor = @import("../Config.zig").Anchor;
|
||||||
const RuleGlobs = @import("../rule_list.zig").RuleGlobs;
|
|
||||||
|
|
||||||
const Action = enum {
|
const Action = enum {
|
||||||
float,
|
float,
|
||||||
@ -189,7 +187,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 "*",
|
||||||
};
|
};
|
||||||
@ -251,12 +249,6 @@ fn apply_tearing_rules() void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alignLeft(buf: []const u8, width: usize, writer: *std.io.Writer) Error!void {
|
|
||||||
assert(buf.len <= width);
|
|
||||||
try writer.writeAll(buf);
|
|
||||||
try writer.splatByteAll(' ', width - buf.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!void {
|
pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!void {
|
||||||
if (args.len < 2) return error.NotEnoughArguments;
|
if (args.len < 2) return error.NotEnoughArguments;
|
||||||
if (args.len > 2) return error.TooManyArguments;
|
if (args.len > 2) return error.TooManyArguments;
|
||||||
@ -278,12 +270,11 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id);
|
const app_id_column_max = 2 + @max("app-id".len, max_glob_len.app_id);
|
||||||
const title_column_max = 2 + @max("title".len, max_glob_len.title);
|
const title_column_max = 2 + @max("title".len, max_glob_len.title);
|
||||||
|
|
||||||
var buffer = std.io.Writer.Allocating.init(util.gpa);
|
var buffer = std.ArrayList(u8).init(util.gpa);
|
||||||
defer buffer.deinit();
|
const writer = buffer.writer();
|
||||||
const writer = &buffer.writer;
|
|
||||||
|
|
||||||
try alignLeft("title", title_column_max, writer);
|
try fmt.formatBuf("title", .{ .width = title_column_max, .alignment = .left }, writer);
|
||||||
try alignLeft("app-id", app_id_column_max, writer);
|
try fmt.formatBuf("app-id", .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
try writer.writeAll("action\n");
|
try writer.writeAll("action\n");
|
||||||
|
|
||||||
switch (rule_list) {
|
switch (rule_list) {
|
||||||
@ -298,8 +289,8 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
for (rules) |rule| {
|
for (rules) |rule| {
|
||||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
try writer.print("{s}\n", .{switch (list) {
|
try writer.print("{s}\n", .{switch (list) {
|
||||||
.float => if (rule.value) "float" else "no-float",
|
.float => if (rule.value) "float" else "no-float",
|
||||||
.ssd => if (rule.value) "ssd" else "csd",
|
.ssd => if (rule.value) "ssd" else "csd",
|
||||||
@ -313,22 +304,22 @@ pub fn listRules(_: *Seat, args: []const [:0]const u8, out: *?[]const u8) Error!
|
|||||||
},
|
},
|
||||||
.tags => {
|
.tags => {
|
||||||
for (server.config.rules.tags.rules.items) |rule| {
|
for (server.config.rules.tags.rules.items) |rule| {
|
||||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
try writer.print("{b}\n", .{rule.value});
|
try writer.print("{b}\n", .{rule.value});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.position => {
|
.position => {
|
||||||
for (server.config.rules.position.rules.items) |rule| {
|
for (server.config.rules.position.rules.items) |rule| {
|
||||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
try writer.print("{s},{d},{d}\n", .{ @tagName(rule.value.anchor), rule.value.x, rule.value.y });
|
try writer.print("{s},{d},{d}", .{ @tagName(rule.value.anchor), rule.value.x, rule.value.y });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.dimensions => {
|
.dimensions => {
|
||||||
for (server.config.rules.dimensions.rules.items) |rule| {
|
for (server.config.rules.dimensions.rules.items) |rule| {
|
||||||
try alignLeft(rule.title_glob, title_column_max, writer);
|
try fmt.formatBuf(rule.title_glob, .{ .width = title_column_max, .alignment = .left }, writer);
|
||||||
try alignLeft(rule.app_id_glob, app_id_column_max, writer);
|
try fmt.formatBuf(rule.app_id_glob, .{ .width = app_id_column_max, .alignment = .left }, writer);
|
||||||
try writer.print("{d}x{d}\n", .{ rule.value.width, rule.value.height });
|
try writer.print("{d}x{d}\n", .{ rule.value.width, rule.value.height });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
|
|
||||||
const c = @import("../c.zig").c;
|
const c = @import("../c.zig");
|
||||||
const util = @import("../util.zig");
|
const util = @import("../util.zig");
|
||||||
const process = @import("../process.zig");
|
const process = @import("../process.zig");
|
||||||
|
|
||||||
|
@ -18,13 +18,14 @@ const build_options = @import("build_options");
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
|
const io = std.io;
|
||||||
const log = std.log;
|
const log = std.log;
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const wlr = @import("wlroots");
|
const wlr = @import("wlroots");
|
||||||
const flags = @import("flags");
|
const flags = @import("flags");
|
||||||
|
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
const process = @import("process.zig");
|
const process = @import("process.zig");
|
||||||
|
|
||||||
@ -51,21 +52,21 @@ pub fn main() anyerror!void {
|
|||||||
.{ .name = "log-level", .kind = .arg },
|
.{ .name = "log-level", .kind = .arg },
|
||||||
.{ .name = "no-xwayland", .kind = .boolean },
|
.{ .name = "no-xwayland", .kind = .boolean },
|
||||||
}).parse(std.os.argv[1..]) catch {
|
}).parse(std.os.argv[1..]) catch {
|
||||||
try fs.File.stderr().writeAll(usage);
|
try io.getStdErr().writeAll(usage);
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
};
|
};
|
||||||
if (result.flags.h) {
|
if (result.flags.h) {
|
||||||
try fs.File.stdout().writeAll(usage);
|
try io.getStdOut().writeAll(usage);
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
}
|
}
|
||||||
if (result.args.len != 0) {
|
if (result.args.len != 0) {
|
||||||
log.err("unknown option '{s}'", .{result.args[0]});
|
log.err("unknown option '{s}'", .{result.args[0]});
|
||||||
try fs.File.stderr().writeAll(usage);
|
try io.getStdErr().writeAll(usage);
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.flags.version) {
|
if (result.flags.version) {
|
||||||
try fs.File.stdout().writeAll(build_options.version ++ "\n");
|
try io.getStdOut().writeAll(build_options.version ++ "\n");
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
}
|
}
|
||||||
if (result.flags.@"log-level") |level| {
|
if (result.flags.@"log-level") |level| {
|
||||||
@ -79,7 +80,7 @@ pub fn main() anyerror!void {
|
|||||||
runtime_log_level = .debug;
|
runtime_log_level = .debug;
|
||||||
} else {
|
} else {
|
||||||
log.err("invalid log level '{s}'", .{level});
|
log.err("invalid log level '{s}'", .{level});
|
||||||
try fs.File.stderr().writeAll(usage);
|
try io.getStdErr().writeAll(usage);
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,8 +189,8 @@ pub fn logFn(
|
|||||||
|
|
||||||
const scope_prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
const scope_prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
||||||
|
|
||||||
var stderr = fs.File.stderr().writer(&.{});
|
const stderr = io.getStdErr().writer();
|
||||||
stderr.interface.print(level.asText() ++ scope_prefix ++ format ++ "\n", args) catch {};
|
stderr.print(level.asText() ++ scope_prefix ++ format ++ "\n", args) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See wlroots_log_wrapper.c
|
/// See wlroots_log_wrapper.c
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
|
|
||||||
const c = @import("c.zig").c;
|
const c = @import("c.zig");
|
||||||
|
|
||||||
var original_rlimit: ?posix.rlimit = null;
|
var original_rlimit: ?posix.rlimit = null;
|
||||||
|
|
||||||
@ -26,10 +26,10 @@ pub fn setup() void {
|
|||||||
// has had its read end closed by another process.
|
// has had its read end closed by another process.
|
||||||
const sig_ign = posix.Sigaction{
|
const sig_ign = posix.Sigaction{
|
||||||
.handler = .{ .handler = posix.SIG.IGN },
|
.handler = .{ .handler = posix.SIG.IGN },
|
||||||
.mask = posix.sigemptyset(),
|
.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
|
||||||
@ -61,14 +61,14 @@ pub fn setup() void {
|
|||||||
|
|
||||||
pub fn cleanupChild() void {
|
pub fn cleanupChild() void {
|
||||||
if (c.setsid() < 0) unreachable;
|
if (c.setsid() < 0) unreachable;
|
||||||
if (posix.system.sigprocmask(posix.SIG.SETMASK, &posix.sigemptyset(), null) < 0) unreachable;
|
if (posix.system.sigprocmask(posix.SIG.SETMASK, &posix.empty_sigset, null) < 0) unreachable;
|
||||||
|
|
||||||
const sig_dfl = posix.Sigaction{
|
const sig_dfl = posix.Sigaction{
|
||||||
.handler = .{ .handler = posix.SIG.DFL },
|
.handler = .{ .handler = posix.SIG.DFL },
|
||||||
.mask = posix.sigemptyset(),
|
.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))
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const fs = std.fs;
|
const io = std.io;
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
@ -73,15 +73,15 @@ fn _main() !void {
|
|||||||
.{ .name = "h", .kind = .boolean },
|
.{ .name = "h", .kind = .boolean },
|
||||||
.{ .name = "version", .kind = .boolean },
|
.{ .name = "version", .kind = .boolean },
|
||||||
}).parse(std.os.argv[1..]) catch {
|
}).parse(std.os.argv[1..]) catch {
|
||||||
try fs.File.stderr().writeAll(usage);
|
try io.getStdErr().writeAll(usage);
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
};
|
};
|
||||||
if (result.flags.h) {
|
if (result.flags.h) {
|
||||||
try fs.File.stdout().writeAll(usage);
|
try io.getStdOut().writeAll(usage);
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
}
|
}
|
||||||
if (result.flags.version) {
|
if (result.flags.version) {
|
||||||
try fs.File.stdout().writeAll(@import("build_options").version ++ "\n");
|
try io.getStdOut().writeAll(@import("build_options").version ++ "\n");
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +125,8 @@ fn callbackListener(_: *zriver.CommandCallbackV1, event: zriver.CommandCallbackV
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
.success => |success| {
|
.success => |success| {
|
||||||
if (mem.len(success.output) > 0) {
|
if (mem.len(success.output) > 0) {
|
||||||
var stdout = fs.File.stdout().writer(&.{});
|
const stdout = io.getStdOut().writer();
|
||||||
stdout.interface.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
|
stdout.print("{s}\n", .{success.output}) catch @panic("failed to write to stdout");
|
||||||
}
|
}
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
},
|
},
|
||||||
@ -134,7 +134,7 @@ fn callbackListener(_: *zriver.CommandCallbackV1, event: zriver.CommandCallbackV
|
|||||||
// A small hack to provide usage text when river reports an unknown command.
|
// A small hack to provide usage text when river reports an unknown command.
|
||||||
if (mem.orderZ(u8, failure.failure_message, "unknown command") == .eq) {
|
if (mem.orderZ(u8, failure.failure_message, "unknown command") == .eq) {
|
||||||
std.log.err("unknown command", .{});
|
std.log.err("unknown command", .{});
|
||||||
fs.File.stderr().writeAll(usage) catch {};
|
io.getStdErr().writeAll(usage) catch {};
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
fatal("{s}", .{failure.failure_message});
|
fatal("{s}", .{failure.failure_message});
|
||||||
|
@ -91,12 +91,15 @@ 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: wl.list.Head(Output, .link),
|
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();
|
||||||
try Output.create(context, wl_output, name);
|
const node = try gpa.create(std.TailQueue(Output).Node);
|
||||||
|
errdefer gpa.destroy(node);
|
||||||
|
try node.data.init(context, wl_output, name);
|
||||||
|
context.outputs.append(node);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -110,21 +113,15 @@ const Output = struct {
|
|||||||
|
|
||||||
layout: *river.LayoutV3 = undefined,
|
layout: *river.LayoutV3 = undefined,
|
||||||
|
|
||||||
link: wl.list.Link,
|
fn init(output: *Output, context: *Context, wl_output: *wl.Output, name: u32) !void {
|
||||||
|
|
||||||
fn create(context: *Context, wl_output: *wl.Output, name: u32) !void {
|
|
||||||
const output = try gpa.create(Output);
|
|
||||||
errdefer gpa.destroy(output);
|
|
||||||
output.* = .{
|
output.* = .{
|
||||||
.wl_output = wl_output,
|
.wl_output = wl_output,
|
||||||
.name = name,
|
.name = name,
|
||||||
.main_location = default_main_location,
|
.main_location = default_main_location,
|
||||||
.main_count = default_main_count,
|
.main_count = default_main_count,
|
||||||
.main_ratio = default_main_ratio,
|
.main_ratio = default_main_ratio,
|
||||||
.link = undefined,
|
|
||||||
};
|
};
|
||||||
if (context.initialized) try output.getLayout(context);
|
if (context.initialized) try output.getLayout(context);
|
||||||
context.outputs.append(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getLayout(output: *Output, context: *Context) !void {
|
fn getLayout(output: *Output, context: *Context) !void {
|
||||||
@ -133,11 +130,9 @@ const Output = struct {
|
|||||||
output.layout.setListener(*Output, layoutListener, output);
|
output.layout.setListener(*Output, layoutListener, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy(output: *Output) void {
|
fn deinit(output: *Output) void {
|
||||||
output.wl_output.release();
|
output.wl_output.release();
|
||||||
output.layout.destroy();
|
output.layout.destroy();
|
||||||
output.link.remove();
|
|
||||||
gpa.destroy(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layoutListener(layout: *river.LayoutV3, event: river.LayoutV3.Event, output: *Output) void {
|
fn layoutListener(layout: *river.LayoutV3, event: river.LayoutV3.Event, output: *Output) void {
|
||||||
@ -145,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;
|
||||||
@ -317,17 +312,17 @@ pub fn main() !void {
|
|||||||
.{ .name = "main-count", .kind = .arg },
|
.{ .name = "main-count", .kind = .arg },
|
||||||
.{ .name = "main-ratio", .kind = .arg },
|
.{ .name = "main-ratio", .kind = .arg },
|
||||||
}).parse(std.os.argv[1..]) catch {
|
}).parse(std.os.argv[1..]) catch {
|
||||||
try std.fs.File.stderr().writeAll(usage);
|
try std.io.getStdErr().writeAll(usage);
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
};
|
};
|
||||||
if (result.flags.h) {
|
if (result.flags.h) {
|
||||||
try std.fs.File.stdout().writeAll(usage);
|
try std.io.getStdOut().writeAll(usage);
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
}
|
}
|
||||||
if (result.args.len != 0) fatalPrintUsage("unknown option '{s}'", .{result.args[0]});
|
if (result.args.len != 0) fatalPrintUsage("unknown option '{s}'", .{result.args[0]});
|
||||||
|
|
||||||
if (result.flags.version) {
|
if (result.flags.version) {
|
||||||
try std.fs.File.stdout().writeAll(@import("build_options").version ++ "\n");
|
try std.io.getStdOut().writeAll(@import("build_options").version ++ "\n");
|
||||||
posix.exit(0);
|
posix.exit(0);
|
||||||
}
|
}
|
||||||
if (result.flags.@"view-padding") |raw| {
|
if (result.flags.@"view-padding") |raw| {
|
||||||
@ -361,10 +356,7 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
defer display.disconnect();
|
defer display.disconnect();
|
||||||
|
|
||||||
var context: Context = .{
|
var context: Context = .{};
|
||||||
.outputs = undefined,
|
|
||||||
};
|
|
||||||
context.outputs.init();
|
|
||||||
|
|
||||||
const registry = try display.getRegistry();
|
const registry = try display.getRegistry();
|
||||||
registry.setListener(*Context, registryListener, &context);
|
registry.setListener(*Context, registryListener, &context);
|
||||||
@ -376,8 +368,9 @@ pub fn main() !void {
|
|||||||
|
|
||||||
context.initialized = true;
|
context.initialized = true;
|
||||||
|
|
||||||
var it = context.outputs.iterator(.forward);
|
var it = context.outputs.first;
|
||||||
while (it.next()) |output| {
|
while (it) |node| : (it = node.next) {
|
||||||
|
const output = &node.data;
|
||||||
try output.getLayout(&context);
|
try output.getLayout(&context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,10 +389,13 @@ fn registryListener(registry: *wl.Registry, event: wl.Registry.Event, context: *
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.global_remove => |ev| {
|
.global_remove => |ev| {
|
||||||
var it = context.outputs.safeIterator(.forward);
|
var it = context.outputs.first;
|
||||||
while (it.next()) |output| {
|
while (it) |node| : (it = node.next) {
|
||||||
|
const output = &node.data;
|
||||||
if (output.name == ev.name) {
|
if (output.name == ev.name) {
|
||||||
output.destroy();
|
context.outputs.remove(node);
|
||||||
|
output.deinit();
|
||||||
|
gpa.destroy(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,7 +410,7 @@ fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
|||||||
|
|
||||||
fn fatalPrintUsage(comptime format: []const u8, args: anytype) noreturn {
|
fn fatalPrintUsage(comptime format: []const u8, args: anytype) noreturn {
|
||||||
std.log.err(format, args);
|
std.log.err(format, args);
|
||||||
std.fs.File.stderr().writeAll(usage) catch {};
|
std.io.getStdErr().writeAll(usage) catch {};
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user