Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
river: fix issues with window destruction
river/Seat.zig | 2 +-
river/Window.zig | 41 +++++++++++++++++++++++++++++------------
rivercompat/Seat.zig | 1 +
rivercompat/Window.zig | 7 +++++++
4 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/river/Seat.zig b/river/Seat.zig
index 90a10dc..ee8b659 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -91,10 +91,10 @@ pub const WmFocus = union(enum) {
};
pub const Focus = union(enum) {
+ none,
window: *Window,
override_redirect: if (build_options.xwayland) *XwaylandOverrideRedirect else noreturn,
lock_surface: *LockSurface,
- none: void,
pub fn surface(target: Focus) ?*wlr.Surface {
return switch (target) {
diff --git a/river/Window.zig b/river/Window.zig
index cde2457..833fc7a 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -249,15 +249,28 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
/// mark this window for destruction when the transaction completes. Otherwise
/// destroy immediately.
pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
+ // We can't assert(window.wm_pending.state != .ready) since the client may
+ // have exited after making its empty initial commit but before the surface
+ // is mapped.
assert(window.impl == .none);
assert(!window.mapped);
- switch (window.wm_pending.state) {
- .init, .closing => {},
- .ready => unreachable,
- }
+
+ // We may need to send the closed event and make the window_v1/node_v1 objects
+ // inert here if the client exits after the empty initial commit but before
+ // the window is mapped.
+ window.makeInert();
window.destroying = true;
+ {
+ var it = server.input_manager.seats.iterator(.forward);
+ while (it.next()) |seat| {
+ if (seat.focused == .window and seat.focused.window == window) {
+ seat.focus(.none);
+ }
+ }
+ }
+
// If there are still saved buffers, then this window needs to be kept
// around until the current transaction completes. This function will be
// called again in WindowManager.commitTransaction()
@@ -351,14 +364,7 @@ pub fn sendDirty(window: *Window) void {
window.node.link_inflight.remove();
window.node.link_inflight.init();
- if (window.object) |window_v1| {
- window.object = null;
- window_v1.sendClosed();
- window_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
- window.node.makeInert();
- } else {
- assert(window.node.object == null);
- }
+ window.close();
},
.ready => {
const wm_v1 = server.wm.object orelse return;
@@ -435,6 +441,17 @@ pub fn sendDirty(window: *Window) void {
}
}
+pub fn makeInert(window: *Window) void {
+ if (window.object) |window_v1| {
+ window.object = null;
+ window_v1.sendClosed();
+ window_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
+ window.node.makeInert();
+ } else {
+ assert(window.node.object == null);
+ }
+}
+
fn handleRequestInert(
window_v1: *river.WindowV1,
request: river.WindowV1.Request,
diff --git a/rivercompat/Seat.zig b/rivercompat/Seat.zig
index 20094ee..dc48e96 100644
--- a/rivercompat/Seat.zig
+++ b/rivercompat/Seat.zig
@@ -50,6 +50,7 @@ pub fn create(wm: *WindowManager, seat_v1: *river.SeatV1) void {
XkbBinding.create(seat, xkb.Keysym.n, .{ .mod4 = true }, .focus_next);
XkbBinding.create(seat, xkb.Keysym.h, .{ .mod4 = true }, .hide_focused);
+ XkbBinding.create(seat, xkb.Keysym.k, .{ .mod4 = true }, .close_focused);
XkbBinding.create(seat, xkb.Keysym.s, .{ .mod4 = true }, .show_all);
PointerBinding.create(seat, c.BTN_LEFT, .{ .mod4 = true }, .move_start, .op_end);
PointerBinding.create(seat, c.BTN_RIGHT, .{ .mod4 = true }, .resize_start, .op_end);
diff --git a/rivercompat/Window.zig b/rivercompat/Window.zig
index 0d89f70..99f51b7 100644
--- a/rivercompat/Window.zig
+++ b/rivercompat/Window.zig
@@ -53,6 +53,13 @@ pub fn create(window_v1: *river.WindowV1, wm: *WindowManager) void {
@as(u32, (rgb >> 0) & 0xff) * (0xffff_ffff / 0xff),
0xffff_ffff,
);
+
+ {
+ var it = wm.seats.iterator(.forward);
+ while (it.next()) |seat| {
+ seat.focus(window);
+ }
+ }
}
fn handleEvent(window_v1: *river.WindowV1, event: river.WindowV1.Event, window: *Window) void {