Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
WindowManager: make all objects inert on wm destroy
This avoids strange/broken behavior if the active window manager
destroys the river_window_manager_v1 object but continues running and
keeps its seat/output/window objects for example.
river/Output.zig | 16 ++++++++++------
river/Seat.zig | 28 ++++++++++++++++++----------
river/Window.zig | 2 +-
river/WindowManager.zig | 12 ++++++++++++
river/XkbBindings.zig | 6 ++++++
5 files changed, 47 insertions(+), 17 deletions(-)
diff --git a/river/Output.zig b/river/Output.zig
index 75bb410..9d56930 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -338,12 +338,7 @@ pub fn manageStart(output: *Output) void {
server.wm.sent.outputs.append(output);
},
.disabled_hard, .destroying => {
- if (output.object) |output_v1| {
- output_v1.sendRemoved();
- output_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
- output.layer_shell.makeInert();
- handleObjectDestroy(output_v1, output);
- }
+ output.makeInert();
output.sent = output.scheduled;
@@ -374,6 +369,15 @@ pub fn manageStart(output: *Output) void {
}
}
+pub fn makeInert(output: *Output) void {
+ if (output.object) |output_v1| {
+ output_v1.sendRemoved();
+ output_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
+ output.layer_shell.makeInert();
+ handleObjectDestroy(output_v1, output);
+ }
+}
+
fn handleRequestInert(
output_v1: *river.OutputV1,
request: river.OutputV1.Request,
diff --git a/river/Seat.zig b/river/Seat.zig
index 57b7123..9bc6eda 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -277,6 +277,8 @@ pub fn create(name: [*:0]const u8) !void {
}
pub fn destroy(seat: *Seat) void {
+ seat.makeInert();
+
while (seat.event_queue.popFront()) |event| {
switch (event) {
.keyboard_key => |data| data.keyboard.dropEvent(),
@@ -299,6 +301,7 @@ pub fn destroy(seat: *Seat) void {
=> {},
}
}
+
{
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
@@ -313,9 +316,6 @@ pub fn destroy(seat: *Seat) void {
}
assert(seat.keyboard_groups.empty());
- while (seat.xkb_bindings.first()) |binding| binding.destroy();
- while (seat.pointer_bindings.first()) |binding| binding.destroy();
-
seat.link.remove();
seat.link_sent.remove();
@@ -381,13 +381,6 @@ pub fn processEvents(seat: *Seat) void {
pub fn manageStart(seat: *Seat) void {
if (seat.destroying) {
- if (seat.object) |seat_v1| {
- seat_v1.sendRemoved();
- seat_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
- seat.layer_shell.makeInert();
- seat.xkb_bindings_seat.makeInert();
- seat.object = null;
- }
seat.destroy();
return;
}
@@ -526,6 +519,21 @@ pub fn manageStart(seat: *Seat) void {
seat.wm_scheduled.interaction = .none;
}
+pub fn makeInert(seat: *Seat) void {
+ if (seat.object) |seat_v1| {
+ seat_v1.sendRemoved();
+ seat_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
+
+ seat.layer_shell.makeInert();
+ seat.xkb_bindings_seat.makeInert();
+
+ while (seat.xkb_bindings.first()) |binding| binding.destroy();
+ while (seat.pointer_bindings.first()) |binding| binding.destroy();
+
+ seat.object = null;
+ }
+}
+
fn handleRequestInert(
seat_v1: *river.SeatV1,
request: river.SeatV1.Request,
diff --git a/river/Window.zig b/river/Window.zig
index 8ecb8a1..408e70d 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -521,7 +521,7 @@ pub fn manageStart(window: *Window) void {
}
}
-fn makeInert(window: *Window) void {
+pub fn makeInert(window: *Window) void {
if (window.object) |window_v1| {
window_v1.sendClosed();
window_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 56ac5bf..868d10a 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -137,6 +137,18 @@ fn handleRequestInert(
fn handleDestroy(_: *river.WindowManagerV1, wm: *WindowManager) void {
log.debug("active river_window_manager_v1 destroyed", .{});
wm.object = null;
+ {
+ var it = server.om.outputs.iterator(.forward);
+ while (it.next()) |output| output.makeInert();
+ }
+ {
+ var it = server.input_manager.seats.iterator(.forward);
+ while (it.next()) |seat| seat.makeInert();
+ }
+ {
+ var it = wm.windows.iterator();
+ while (it.next()) |window| window.makeInert();
+ }
switch (wm.state) {
.idle => {},
.inflight_configures => {},
diff --git a/river/XkbBindings.zig b/river/XkbBindings.zig
index 8f8a558..f6f18ef 100644
--- a/river/XkbBindings.zig
+++ b/river/XkbBindings.zig
@@ -51,6 +51,9 @@ fn handleRequest(
switch (request) {
.destroy => object.destroy(),
.get_xkb_binding => |args| {
+ // Since we make all river_seat_v1 objects inert when the active
+ // window manager is destroyed, this check means that only the
+ // active window manager can create bindings.
const seat_data = args.seat.getUserData() orelse return;
const seat: *Seat = @ptrCast(@alignCast(seat_data));
XkbBinding.create(
@@ -67,6 +70,9 @@ fn handleRequest(
};
},
.get_seat => |args| {
+ // Since we make all river_seat_v1 objects inert when the active
+ // window manager is destroyed, this check means that only the
+ // active window manager can create a bindings seat.
const seat_data = args.seat.getUserData() orelse return;
const seat: *Seat = @ptrCast(@alignCast(seat_data));
if (seat.xkb_bindings_seat.object != null) {