Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
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;
}