Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
session-lock: unbreak implementation
This has been broken for a while due to river-window-management related
refactoring.
Still needs more testing, but I need to fix disabling outputs before
complete testing is possible.
river/LockManager.zig | 15 ++++++----
river/LockSurface.zig | 13 +++++----
river/Output.zig | 78 ++++++++++++++++++++++++-------------------------
river/OutputManager.zig | 22 +++++++++++---
river/Scene.zig | 1 +
5 files changed, 75 insertions(+), 54 deletions(-)
diff --git a/river/LockManager.zig b/river/LockManager.zig
index 3e12242..a4be23e 100644
--- a/river/LockManager.zig
+++ b/river/LockManager.zig
@@ -86,6 +86,8 @@ pub fn deinit(manager: *LockManager) void {
fn handleLock(listener: *wl.Listener(*wlr.SessionLockV1), lock: *wlr.SessionLockV1) void {
const manager: *LockManager = @fieldParentPtr("new_lock", listener);
+ log.debug("session lock client made lock request", .{});
+
if (manager.lock != null) {
log.info("denying new session lock client, an active one already exists", .{});
lock.destroy();
@@ -97,9 +99,8 @@ fn handleLock(listener: *wl.Listener(*wlr.SessionLockV1), lock: *wlr.SessionLock
if (manager.state == .unlocked) {
manager.state = .waiting_for_lock_surfaces;
- if (build_options.xwayland) {
- server.scene.layers.override_redirect.node.setEnabled(false);
- }
+ assert(!server.scene.locked_tree.node.enabled);
+ server.scene.locked_tree.node.setEnabled(true);
manager.lock_surfaces_timer.timerUpdate(200) catch {
log.err("error setting lock surfaces timer, imperfect frames may be shown", .{});
@@ -133,7 +134,7 @@ fn handleLockSurfacesTimeout(manager: *LockManager) c_int {
assert(manager.state == .waiting_for_lock_surfaces);
manager.state = .waiting_for_blank;
- if (true) @panic("XXX blank all outputs");
+ server.scene.normal_tree.node.setEnabled(false);
// This call is necessary in the case that all outputs in the layout are disabled.
manager.maybeLock();
@@ -147,7 +148,8 @@ pub fn maybeLock(manager: *LockManager) void {
{
var it = server.om.outputs.iterator(.forward);
while (it.next()) |output| {
- if (!output.wlr_output.?.enabled) continue;
+ const wlr_output = output.wlr_output orelse continue;
+ if (!wlr_output.enabled) continue;
switch (output.lock_render_state) {
.pending_unlock, .unlocked, .pending_blank, .pending_lock_surface => {
@@ -168,6 +170,7 @@ pub fn maybeLock(manager: *LockManager) void {
// The lock client may have been destroyed, for example due to a protocol error.
if (manager.lock) |lock| lock.sendLocked();
manager.state = .locked;
+ server.scene.normal_tree.node.setEnabled(false);
manager.lock_surfaces_timer.timerUpdate(0) catch {};
},
.waiting_for_blank => if (all_outputs_blanked) {
@@ -191,7 +194,7 @@ fn handleUnlock(listener: *wl.Listener(void)) void {
server.scene.normal_tree.node.setEnabled(true);
assert(server.scene.locked_tree.node.enabled);
- server.scene.locked_tree.node.setEnabled(true);
+ server.scene.locked_tree.node.setEnabled(false);
{
var it = server.input_manager.seats.iterator(.forward);
diff --git a/river/LockSurface.zig b/river/LockSurface.zig
index e453de2..a3a0ca2 100644
--- a/river/LockSurface.zig
+++ b/river/LockSurface.zig
@@ -30,6 +30,7 @@ const SceneNodeData = @import("SceneNodeData.zig");
wlr_lock_surface: *wlr.SessionLockSurfaceV1,
lock: *wlr.SessionLockV1,
+tree: *wlr.SceneTree,
idle_update_focus: ?*wl.EventSource = null,
@@ -40,17 +41,17 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
const lock_surface = try util.gpa.create(LockSurface);
errdefer util.gpa.destroy(lock_surface);
+ const tree = try server.scene.locked_tree.createSceneSubsurfaceTree(wlr_lock_surface.surface);
+ errdefer tree.node.destroy();
+
lock_surface.* = .{
.wlr_lock_surface = wlr_lock_surface,
.lock = lock,
+ .tree = tree,
};
wlr_lock_surface.data = lock_surface;
- const tree = try server.scene.locked_tree.createSceneSubsurfaceTree(wlr_lock_surface.surface);
- errdefer tree.node.destroy();
-
try SceneNodeData.attach(&tree.node, .{ .lock_surface = lock_surface });
-
wlr_lock_surface.surface.data = &tree.node;
wlr_lock_surface.surface.events.map.add(&lock_surface.map);
@@ -59,7 +60,7 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
lock_surface.configure();
}
-pub fn destroy(lock_surface: *LockSurface) void {
+fn destroy(lock_surface: *LockSurface) void {
{
var surface_it = lock_surface.lock.surfaces.iterator(.forward);
const new_focus: Seat.Focus = while (surface_it.next()) |surface| {
@@ -102,6 +103,8 @@ pub fn configure(lock_surface: *LockSurface) void {
fn handleMap(listener: *wl.Listener(void)) void {
const lock_surface: *LockSurface = @fieldParentPtr("map", listener);
+ const output = lock_surface.getOutput();
+ lock_surface.tree.node.setPosition(output.sent.x, output.sent.y);
// Unfortunately the surface commit handlers for the scene subsurface tree corresponding to
// this lock surface won't be called until after this function returns, which means that we cannot
diff --git a/river/Output.zig b/river/Output.zig
index bffff9b..dba4d3e 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -400,42 +400,43 @@ fn renderAndCommit(output: *Output) !void {
if (!wlr_output.commitState(&state)) return error.CommitFailed;
- const lock_surface_mapped = blk: {
- if (server.lock_manager.lockSurfaceFromOutput(output)) |lock_surface| {
- break :blk lock_surface.wlr_lock_surface.surface.mapped;
- } else {
- break :blk false;
- }
- };
-
- if (server.lock_manager.state == .locked or
- (server.lock_manager.state == .waiting_for_lock_surfaces and lock_surface_mapped) or
- server.lock_manager.state == .waiting_for_blank)
- {
- assert(!server.scene.normal_tree.node.enabled);
- assert(server.scene.locked_tree.node.enabled);
-
- switch (server.lock_manager.state) {
- .unlocked => unreachable,
- .locked => switch (output.lock_render_state) {
+ switch (server.lock_manager.state) {
+ .unlocked => {
+ if (output.lock_render_state != .unlocked) {
+ output.lock_render_state = .pending_unlock;
+ }
+ },
+ .locked => {
+ assert(!server.scene.normal_tree.node.enabled);
+ switch (output.lock_render_state) {
.pending_unlock, .unlocked, .pending_blank, .pending_lock_surface => unreachable,
.blanked, .lock_surface => {},
- },
- .waiting_for_blank => {
- if (output.lock_render_state != .blanked) {
- output.lock_render_state = .pending_blank;
+ }
+ },
+ .waiting_for_blank => {
+ assert(!server.scene.normal_tree.node.enabled);
+ if (output.lock_render_state != .blanked) {
+ output.lock_render_state = .pending_blank;
+ }
+ },
+ .waiting_for_lock_surfaces => {
+ const lock_surface_mapped = blk: {
+ if (server.lock_manager.lockSurfaceFromOutput(output)) |lock_surface| {
+ break :blk lock_surface.wlr_lock_surface.surface.mapped;
+ } else {
+ break :blk false;
}
- },
- .waiting_for_lock_surfaces => {
+ };
+ if (lock_surface_mapped) {
if (output.lock_render_state != .lock_surface) {
output.lock_render_state = .pending_lock_surface;
}
- },
- }
- } else {
- if (output.lock_render_state != .unlocked) {
- output.lock_render_state = .pending_unlock;
- }
+ } else {
+ if (output.lock_render_state != .unlocked) {
+ output.lock_render_state = .pending_unlock;
+ }
+ }
+ },
}
}
@@ -444,24 +445,23 @@ fn handlePresent(
event: *wlr.Output.event.Present,
) void {
const output: *Output = @fieldParentPtr("present", listener);
-
if (!event.presented) {
return;
}
-
switch (output.lock_render_state) {
.pending_unlock => {
assert(server.lock_manager.state != .locked);
output.lock_render_state = .unlocked;
},
.unlocked => assert(server.lock_manager.state != .locked),
- .pending_blank, .pending_lock_surface => {
- output.lock_render_state = switch (output.lock_render_state) {
- .pending_blank => .blanked,
- .pending_lock_surface => .lock_surface,
- .pending_unlock, .unlocked, .blanked, .lock_surface => unreachable,
- };
-
+ .pending_blank => {
+ output.lock_render_state = .blanked;
+ if (server.lock_manager.state != .locked) {
+ server.lock_manager.maybeLock();
+ }
+ },
+ .pending_lock_surface => {
+ output.lock_render_state = .lock_surface;
if (server.lock_manager.state != .locked) {
server.lock_manager.maybeLock();
}
diff --git a/river/OutputManager.zig b/river/OutputManager.zig
index bd037d1..ff2ff27 100644
--- a/river/OutputManager.zig
+++ b/river/OutputManager.zig
@@ -264,6 +264,9 @@ pub fn commitOutputState(om: *OutputManager) void {
log.err("out of memory", .{});
continue; // Try again next time
};
+ if (server.lock_manager.lockSurfaceFromOutput(output)) |lock_surface| {
+ lock_surface.tree.node.setPosition(output.sent.x, output.sent.y);
+ }
},
.disabled_hard, .destroying => {
om.output_layout.remove(wlr_output);
@@ -279,12 +282,14 @@ pub fn commitOutputState(om: *OutputManager) void {
var it = wm.wm_sent.outputs.iterator(.forward);
while (it.next()) |output| {
const wlr_output = output.wlr_output orelse continue;
-
switch (output.sent.state) {
.enabled => if (!wlr_output.enabled) break :blk true,
- .disabled_soft, .disabled_hard, .destroying => continue,
+ // Technically disabling an output does not require a modeset,
+ // but handling both enabled and disable here simplifies
+ // lock_render_state tracking.
+ .disabled_soft, .disabled_hard => if (wlr_output.enabled) break :blk true,
+ .destroying => unreachable, // output.wlr_output must be null.
}
-
switch (output.sent.mode) {
.standard => |mode| {
if (mode != wlr_output.current_mode) break :blk true;
@@ -300,7 +305,6 @@ pub fn commitOutputState(om: *OutputManager) void {
break :blk true;
}
}
-
break :blk false;
};
@@ -382,6 +386,16 @@ pub fn commitOutputState(om: *OutputManager) void {
}
swapchain_manager.apply();
+
+ {
+ var it = wm.wm_sent.outputs.iterator(.forward);
+ while (it.next()) |output| {
+ const wlr_output = output.wlr_output orelse continue;
+ if (!wlr_output.enabled) {
+ output.lock_render_state = .blanked;
+ }
+ }
+ }
}
if (wm.wm_sent.output_config) |config| {
diff --git a/river/Scene.zig b/river/Scene.zig
index 33eb69e..6e23c83 100644
--- a/river/Scene.zig
+++ b/river/Scene.zig
@@ -73,6 +73,7 @@ pub fn init(scene: *Scene) !void {
const normal_tree = try interactive_tree.createSceneTree();
const locked_tree = try interactive_tree.createSceneTree();
+ locked_tree.node.setEnabled(false);
scene.* = .{
.wlr_scene = wlr_scene,