aboutsummaryrefslogtreecommitdiff
path: root/src/root.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/root.zig')
-rw-r--r--src/root.zig84
1 files changed, 83 insertions, 1 deletions
diff --git a/src/root.zig b/src/root.zig
index fca4591..e31d2e1 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -17,9 +17,15 @@ pub const Root = struct {
// Must stay ordered, first N views in list are the masters
views: std.TailQueue(View),
+ unmapped_views: std.TailQueue(View),
+
+ // Number of pending configures sent in the current transaction.
+ // A value of 0 means there is no current transaction.
+ pending_count: u32,
pub fn init(self: *Self, server: *Server) !void {
self.server = server;
+ self.pending_count = 0;
// Create an output layout, which a wlroots utility for working with an
// arrangement of screens in a physical layout.
@@ -29,6 +35,7 @@ pub const Root = struct {
self.outputs = std.TailQueue(Output).init();
self.views = std.TailQueue(View).init();
+ self.unmapped_views = std.TailQueue(View).init();
}
pub fn destroy(self: *Self) void {
@@ -45,7 +52,7 @@ pub const Root = struct {
pub fn addView(self: *Self, wlr_xdg_surface: *c.wlr_xdg_surface) void {
const node = self.views.allocateNode(self.server.allocator) catch unreachable;
node.data.init(self, wlr_xdg_surface);
- self.views.append(node);
+ self.unmapped_views.append(node);
}
/// Finds the top most view under the output layout coordinates lx, ly
@@ -59,4 +66,79 @@ pub const Root = struct {
}
return null;
}
+
+ pub fn arrange(self: *Self) void {
+ if (self.views.len == 0) {
+ return;
+ }
+ // Super basic vertical layout for now, no master/slave stuff
+ // This can't return null if pass null as the reference
+ const output_box: *c.wlr_box = c.wlr_output_layout_get_box(self.wlr_output_layout, null);
+ const new_height = output_box.height;
+ // Allow for a 10px gap
+ const num_views = @intCast(c_int, self.views.len);
+ const new_width = @divTrunc(output_box.width, num_views) - (num_views - 1) * 10;
+
+ var x: c_int = 0;
+ var y: c_int = 0;
+
+ var it = self.views.first;
+ while (it) |node| : (it = node.next) {
+ const view = &node.data;
+ view.pending_state.x = x;
+ view.pending_state.y = y;
+ view.pending_state.width = @intCast(u32, new_width);
+ view.pending_state.height = @intCast(u32, new_height);
+
+ x += new_width + 10;
+ }
+
+ self.startTransaction();
+ }
+
+ /// Initiate an atomic change to the layout. This change will not be
+ /// applied until all affected clients ack a configure and commit a buffer.
+ fn startTransaction(self: *Self) void {
+ std.debug.assert(self.pending_count == 0);
+
+ var it = self.views.first;
+ while (it) |node| : (it = node.next) {
+ const view = &node.data;
+ if (view.needsConfigure()) {
+ view.configurePending();
+ self.pending_count += 1;
+
+ // We save the current buffer, so we can send an early
+ // frame done event to give the client a head start on
+ // redrawing.
+ view.sendFrameDone();
+ }
+ view.stashBuffer();
+ }
+
+ // TODO: start a timer and handle timeout waiting for all clients to ack
+ }
+
+ pub fn notifyConfigured(self: *Self) void {
+ self.pending_count -= 1;
+ if (self.pending_count == 0) {
+ self.commitTransaction();
+ }
+ }
+
+ /// Apply the pending state and drop stashed buffers. This means that
+ /// the next frame drawn will be the post-transaction state of the
+ /// layout. Must only be called after all clients have configured for
+ /// the new layout.
+ fn commitTransaction(self: *Self) void {
+ // TODO: apply damage properly
+ var it = self.views.first;
+ while (it) |node| : (it = node.next) {
+ const view = &node.data;
+
+ // TODO: handle views that timed out
+ view.current_state = view.pending_state;
+ view.dropStashedBuffer();
+ }
+ }
};