git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit648841863d261c731f46abc8b5d0a4f7d1588bd0
parent807e68473d
authorIsaac Freund <[email protected]>
date2024-12-30 16:33
WindowManager: remove unneeded lists

 river/Output.zig        |  5 -----
 river/OutputManager.zig | 36 +++++++++++++++++++++++++------
 river/Seat.zig          | 10 ---------
 river/Window.zig        | 57 +++++++++++--------------------------------------
 river/WindowManager.zig | 56 ++++++------------------------------------------
 river/XdgToplevel.zig   |  4 +++-
 6 files changed, 52 insertions(+), 116 deletions(-)

diff --git a/river/Output.zig b/river/Output.zig
index 0828ee0..1c46e98 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -160,7 +160,6 @@ link: wl.list.Link,
 
 /// Pending state to be sent to the wm in the next update sequence.
 pending: State = .{},
-link_pending: wl.list.Link,
 /// State sent to the wm in the latest update sequence.
 sent: State = .{},
 link_sent: wl.list.Link,
@@ -196,13 +195,11 @@ pub fn create(wlr_output: *wlr.Output) !void {
         .wlr_output = wlr_output,
         .scene_output = scene_output,
         .link = undefined,
-        .link_pending = undefined,
         .link_sent = undefined,
     };
     wlr_output.data = @intFromPtr(output);
 
     server.om.outputs.append(output);
-    server.wm.pending.outputs.append(output);
     output.link_sent.init();
 
     wlr_output.events.destroy.add(&output.destroy);
@@ -281,9 +278,7 @@ pub fn sendDirty(output: *Output) void {
                 output.object = null;
             }
 
-            output.link_pending.remove();
             output.link_sent.remove();
-            output.link_pending.init();
             output.link_sent.init();
 
             if (output.pending.state == .destroying) {
diff --git a/river/OutputManager.zig b/river/OutputManager.zig
index 403a73b..f982af4 100644
--- a/river/OutputManager.zig
+++ b/river/OutputManager.zig
@@ -139,8 +139,6 @@ fn handleManagerApply(_: *wl.Listener(*wlr.OutputConfigurationV1), config: *wlr.
     while (it.next()) |head| {
         const output: *Output = @ptrFromInt(head.state.output.data);
 
-        const prev_state = output.pending.state;
-
         output.pending = .{
             .state = if (head.state.enabled) .enabled else .disabled_hard,
             .mode = blk: {
@@ -160,11 +158,6 @@ fn handleManagerApply(_: *wl.Listener(*wlr.OutputConfigurationV1), config: *wlr.
             .adaptive_sync = head.state.adaptive_sync_enabled,
             .auto_layout = false,
         };
-
-        if (output.pending.state == .enabled and prev_state != .enabled) {
-            output.link_pending.remove();
-            server.wm.pending.outputs.append(output);
-        }
     }
 
     if (server.wm.pending.output_config) |old| {
@@ -232,6 +225,35 @@ fn handleSetGamma(
     event.output.scheduleFrame();
 }
 
+pub fn autoLayout(om: *OutputManager) void {
+    // Find the right most edge of any non-autolayout output.
+    var rightmost_edge: i32 = 0;
+    var row_y: i32 = 0;
+    {
+        var it = om.outputs.iterator(.forward);
+        while (it.next()) |output| {
+            if (output.pending.auto_layout) continue;
+
+            const x = output.pending.x + output.pending.width();
+            if (x > rightmost_edge) {
+                rightmost_edge = x;
+                row_y = output.pending.y;
+            }
+        }
+    }
+    // Place autolayout outputs in a row starting at the rightmost edge.
+    {
+        var it = om.outputs.iterator(.forward);
+        while (it.next()) |output| {
+            if (!output.pending.auto_layout) continue;
+
+            output.pending.x = rightmost_edge;
+            output.pending.y = row_y;
+            rightmost_edge += output.pending.width();
+        }
+    }
+}
+
 pub fn commitOutputState(om: *OutputManager) void {
     const wm = &server.wm;
 
diff --git a/river/Seat.zig b/river/Seat.zig
index 36862f7..beee5af 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -123,7 +123,6 @@ pending: struct {
     /// The window clicked on, touched, etc.
     window_interaction: ?*Window = null,
 } = .{},
-link_pending: wl.list.Link,
 
 /// State sent to the window manager client in the latest update sequence.
 sent: struct {
@@ -173,7 +172,6 @@ pub fn create(name: [*:0]const u8) !void {
         // This will be automatically destroyed when the display is destroyed
         .wlr_seat = try wlr.Seat.create(server.wl_server, name),
         .link = undefined,
-        .link_pending = undefined,
         .link_sent = undefined,
         .xkb_bindings = undefined,
         .pointer_bindings = undefined,
@@ -183,7 +181,6 @@ pub fn create(name: [*:0]const u8) !void {
     seat.wlr_seat.data = @intFromPtr(seat);
 
     server.input_manager.seats.append(seat);
-    server.wm.pending.seats.append(seat);
     seat.link_sent.init();
     server.wm.dirtyPending();
 
@@ -206,7 +203,6 @@ pub fn destroy(seat: *Seat) void {
     }
 
     seat.link.remove();
-    seat.link_pending.remove();
     seat.link_sent.remove();
 
     seat.cursor.deinit();
@@ -273,12 +269,6 @@ pub fn sendDirty(seat: *Seat) void {
             seat_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
             seat.object = null;
         }
-
-        seat.link_pending.remove();
-        seat.link_sent.remove();
-        seat.link_pending.init();
-        seat.link_sent.init();
-
         seat.destroy();
         return;
     }
diff --git a/river/Window.zig b/river/Window.zig
index 1af33e3..46bcae4 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -112,11 +112,6 @@ node: WmNode,
 /// The implementation of this window
 impl: Impl,
 
-/// Link for WindowManager.windows
-link: wl.list.Link,
-/// Link for WindowManager.pending.dirty_windows
-link_dirty: wl.list.Link,
-
 tree: *wlr.SceneTree,
 surface_tree: *wlr.SceneTree,
 saved_surface_tree: *wlr.SceneTree,
@@ -132,6 +127,9 @@ mapped: bool = false,
 /// transaction completes. See Window.destroy()
 destroying: bool = false,
 
+/// WindowManager.windows
+link: wl.list.Link,
+
 /// State to be sent to the window manager client in the next update sequence.
 pending: struct {
     state: enum {
@@ -193,8 +191,6 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
     window.* = .{
         .node = undefined,
         .impl = impl,
-        .link = undefined,
-        .link_dirty = undefined,
         .tree = tree,
         .surface_tree = try tree.createSceneTree(),
         .saved_surface_tree = try tree.createSceneTree(),
@@ -205,12 +201,12 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
             try tree.createSceneRect(0, 0, &server.config.border_color),
         },
         .popup_tree = popup_tree,
+        .link = undefined,
     };
 
     window.node.init(.window);
 
-    server.wm.windows.prepend(window);
-    window.link_dirty.init();
+    server.wm.windows.append(window);
 
     window.tree.node.setEnabled(false);
     window.popup_tree.node.setEnabled(false);
@@ -243,7 +239,6 @@ pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
         window.popup_tree.node.destroy();
 
         window.link.remove();
-        window.link_dirty.remove();
 
         window.node.deinit();
 
@@ -256,33 +251,10 @@ pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
     }
 }
 
-fn dirtyPending(window: *Window) void {
-    switch (window.pending.state) {
-        .init => {},
-        .ready, .closing => {
-            window.link_dirty.remove();
-            server.wm.pending.dirty_windows.prepend(window);
-            server.wm.dirtyPending();
-        },
-    }
-}
-
-pub fn ready(window: *Window) void {
-    assert(window.pending.state != .ready);
-    window.pending.state = .ready;
-    window.dirtyPending();
-}
-
-pub fn closing(window: *Window) void {
-    assert(window.pending.state != .closing);
-    window.pending.state = .closing;
-    window.dirtyPending();
-}
-
 pub fn setDimensionsHint(window: *Window, hint: DimensionsHint) void {
     window.pending.dimensions_hint = hint;
     if (!meta.eql(window.sent.dimensions_hint, hint)) {
-        window.dirtyPending();
+        server.wm.dirtyPending();
     }
 }
 
@@ -294,14 +266,14 @@ pub fn setDimensions(window: *Window, width: i32, height: i32) void {
     window.inflight.box.height = height;
 
     if (width != window.sent.box.width or height != window.sent.box.height) {
-        window.dirtyPending();
+        server.wm.dirtyPending();
     }
 }
 
 pub fn setDecorationHint(window: *Window, hint: river.WindowV1.DecorationHint) void {
     window.pending.decoration_hint = hint;
     if (hint != window.sent.decoration_hint) {
-        window.dirtyPending();
+        server.wm.dirtyPending();
     }
 }
 
@@ -311,15 +283,13 @@ pub fn setFullscreenRequested(window: *Window, fullscreen_requested: bool) void
     } else {
         window.pending.fullscreen_requested = .exit;
     }
-    window.dirtyPending();
+    server.wm.dirtyPending();
 }
 
 /// Send dirty pending state as part of an in progress update sequence.
 pub fn sendDirty(window: *Window) void {
-    assert(window.pending.state != .init);
-
     switch (window.pending.state) {
-        .init => unreachable,
+        .init => {},
         .closing => {
             window.pending.state = .init;
             window.initialized = false;
@@ -392,9 +362,6 @@ pub fn sendDirty(window: *Window) void {
             pending.fullscreen_requested = .no_request;
         },
     }
-
-    window.link_dirty.remove();
-    window.link_dirty.init();
 }
 
 fn handleRequestInert(
@@ -815,7 +782,9 @@ pub fn unmap(window: *Window) void {
 
     window.foreign_toplevel_handle.unmap();
 
-    window.closing();
+    assert(window.pending.state != .closing);
+    window.pending.state = .closing;
+    server.wm.dirtyPending();
 }
 
 pub fn notifyTitle(window: *const Window) void {
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index 763ac3b..6502851 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -38,8 +38,6 @@ server_destroy: wl.Listener(*wl.Server) = wl.Listener(*wl.Server).init(handleSer
 /// The protocol object of the active window manager, if any.
 object: ?*river.WindowManagerV1 = null,
 
-windows: wl.list.Head(Window, .link),
-
 state: union(enum) {
     idle,
     /// An update event was sent to the window manager but has not yet been acked.
@@ -51,18 +49,15 @@ state: union(enum) {
     inflight_configures: u32,
 } = .idle,
 
+windows: wl.list.Head(Window, .link),
+
 /// Pending state to be sent to the wm in the next update sequence.
 pending: struct {
     /// Pending state has been modified since the last update event sent to the wm.
     dirty: bool = false,
 
-    dirty_windows: wl.list.Head(Window, .link_dirty),
-
-    outputs: wl.list.Head(Output, .link_pending),
     output_config: ?*wlr.OutputConfigurationV1 = null,
-
-    seats: wl.list.Head(Seat, .link_pending),
-},
+} = .{},
 
 /// State sent to the wm in the latest update sequence.
 sent: struct {
@@ -105,11 +100,6 @@ pub fn init(wm: *WindowManager) !void {
     wm.* = .{
         .global = try wl.Global.create(server.wl_server, river.WindowManagerV1, 1, *WindowManager, wm, bind),
         .windows = undefined,
-        .pending = .{
-            .dirty_windows = undefined,
-            .outputs = undefined,
-            .seats = undefined,
-        },
         .sent = .{
             .outputs = undefined,
             .seats = undefined,
@@ -126,9 +116,6 @@ pub fn init(wm: *WindowManager) !void {
         .timeout = timeout,
     };
     wm.windows.init();
-    wm.pending.dirty_windows.init();
-    wm.pending.outputs.init();
-    wm.pending.seats.init();
     wm.sent.outputs.init();
     wm.sent.seats.init();
     wm.uncommitted.render_list.init();
@@ -261,9 +248,9 @@ fn sendUpdate(wm: *WindowManager) void {
 
     log.debug("sending update to window manager", .{});
 
-    wm.autoLayoutOutputs();
+    server.om.autoLayout();
     {
-        var it = wm.pending.outputs.safeIterator(.forward);
+        var it = server.om.outputs.safeIterator(.forward);
         while (it.next()) |output| output.sendDirty();
     }
 
@@ -272,12 +259,12 @@ fn sendUpdate(wm: *WindowManager) void {
     wm.pending.output_config = null;
 
     {
-        var it = wm.pending.dirty_windows.safeIterator(.forward);
+        var it = wm.windows.safeIterator(.forward);
         while (it.next()) |window| window.sendDirty();
     }
 
     {
-        var it = wm.pending.seats.safeIterator(.forward);
+        var it = server.input_manager.seats.safeIterator(.forward);
         while (it.next()) |seat| seat.sendDirty();
     }
 
@@ -296,35 +283,6 @@ fn sendUpdate(wm: *WindowManager) void {
     }
 }
 
-fn autoLayoutOutputs(wm: *WindowManager) void {
-    // Find the right most edge of any non-autolayout output.
-    var rightmost_edge: i32 = 0;
-    var row_y: i32 = 0;
-    {
-        var it = wm.pending.outputs.iterator(.forward);
-        while (it.next()) |output| {
-            if (output.pending.auto_layout) continue;
-
-            const x = output.pending.x + output.pending.width();
-            if (x > rightmost_edge) {
-                rightmost_edge = x;
-                row_y = output.pending.y;
-            }
-        }
-    }
-    // Place autolayout outputs in a row starting at the rightmost edge.
-    {
-        var it = wm.pending.outputs.iterator(.forward);
-        while (it.next()) |output| {
-            if (!output.pending.auto_layout) continue;
-
-            output.pending.x = rightmost_edge;
-            output.pending.y = row_y;
-            rightmost_edge += output.pending.width();
-        }
-    }
-}
-
 fn sendConfigures(wm: *WindowManager) void {
     switch (wm.state) {
         .idle, .update_acked => {},
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 5466438..2f58450 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -307,7 +307,9 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
     });
 
     if (toplevel.wlr_toplevel.base.initial_commit) {
-        window.ready();
+        assert(window.pending.state != .ready);
+        window.pending.state = .ready;
+        server.wm.dirtyPending();
         return;
     }