diff options
| author | Isaac Freund <ifreund@ifreund.xyz> | 2020-04-03 18:53:36 +0200 |
|---|---|---|
| committer | Isaac Freund <ifreund@ifreund.xyz> | 2020-04-04 16:51:02 +0200 |
| commit | 6cb9f6ac04e1fc7716bd69707c714ae89599cccc (patch) | |
| tree | d2b2e846a5f191b25e1853a0d60e5776f05b57c6 /src/root.zig | |
| parent | 9ba295f12673f201b5d70fa3918e270ef41be9f7 (diff) | |
| download | river-6cb9f6ac04e1fc7716bd69707c714ae89599cccc.tar.gz river-6cb9f6ac04e1fc7716bd69707c714ae89599cccc.tar.xz | |
Add a data structure to manage the view stack
Diffstat (limited to 'src/root.zig')
| -rw-r--r-- | src/root.zig | 142 |
1 files changed, 64 insertions, 78 deletions
diff --git a/src/root.zig b/src/root.zig index de2bba0..14935b2 100644 --- a/src/root.zig +++ b/src/root.zig @@ -7,6 +7,7 @@ const Output = @import("output.zig").Output; const Server = @import("server.zig").Server; const Seat = @import("seat.zig").Seat; const View = @import("view.zig").View; +const ViewStack = @import("view_stack.zig").ViewStack; /// Responsible for all windowing operations pub const Root = struct { @@ -17,10 +18,10 @@ pub const Root = struct { wlr_output_layout: *c.wlr_output_layout, outputs: std.TailQueue(Output), - // Must stay ordered, first N views in list are the masters - views: std.TailQueue(View), - unmapped_views: std.TailQueue(View), + /// The top of the stack is the "most important" view. + views: ViewStack, + /// The view that has seat focus, if any. focused_view: ?*View, /// A bit field of focused tags @@ -33,8 +34,8 @@ pub const Root = struct { /// Percentage of the total screen that the master section takes up. master_factor: f64, - // Number of pending configures sent in the current transaction. - // A value of 0 means there is no current transaction. + /// Number of pending configures sent in the current transaction. + /// A value of 0 means there is no current transaction. pending_configures: u32, /// Handles timeout of transactions @@ -51,8 +52,7 @@ pub const Root = struct { self.outputs = std.TailQueue(Output).init(); - self.views = std.TailQueue(View).init(); - self.unmapped_views = std.TailQueue(View).init(); + self.views.init(); self.focused_view = null; @@ -80,88 +80,83 @@ 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.current_focused_tags); - self.unmapped_views.prepend(node); + const node = self.server.allocator.create(ViewStack.Node) catch unreachable; + node.view.init(self, wlr_xdg_surface, self.current_focused_tags); + self.views.push(node); } /// Finds the topmost view under the output layout coordinates lx, ly /// returns the view if found, and a pointer to the wlr_surface as well as the surface coordinates pub fn viewAt(self: Self, lx: f64, ly: f64, surface: *?*c.wlr_surface, sx: *f64, sy: *f64) ?*View { - var it = self.views.last; - while (it) |node| : (it = node.prev) { - if (node.data.isAt(lx, ly, surface, sx, sy)) { - return &node.data; + var it = ViewStack.iterator(self.views.first, 0xFFFFFFFF); + while (it.next()) |view| { + if (view.isAt(lx, ly, surface, sx, sy)) { + return view; } } return null; } + /// Clear the current focus. + pub fn clearFocus(self: *Self) void { + if (self.focused_view) |view| { + _ = c.wlr_xdg_toplevel_set_activated(view.wlr_xdg_surface, false); + } + self.focused_view = null; + } + /// Focus the next visible view in the stack, wrapping if needed. Does /// nothing if there is only one view in the stack. - pub fn focusNextView(self: Self) void { + pub fn focusNextView(self: *Self) void { if (self.focused_view) |current_focus| { // If there is a currently focused view, focus the next visible view in the stack. - var it = @fieldParentPtr(std.TailQueue(View).Node, "data", current_focus).next; - while (it) |node| : (it = node.next) { - const view = &node.data; - if (view.current_tags & self.current_focused_tags != 0) { - view.focus(view.wlr_xdg_surface.surface); - return; - } + const current_node = @fieldParentPtr(ViewStack.Node, "view", current_focus); + var it = ViewStack.iterator(current_node, self.current_focused_tags); + // Skip past the current node + _ = it.next(); + // Focus the next visible node if there is one + if (it.next()) |view| { + view.focus(view.wlr_xdg_surface.surface); + return; } } // There is either no currently focused view or the last visible view in the // stack is focused and we need to wrap. - var it = self.views.first; - while (it) |node| : (it = node.next) { - const view = &node.data; - if (view.current_tags & self.current_focused_tags != 0) { - view.focus(view.wlr_xdg_surface.surface); - return; - } + var it = ViewStack.iterator(self.views.first, self.current_focused_tags); + if (it.next()) |view| { + view.focus(view.wlr_xdg_surface.surface); + } else { + // Otherwise clear the focus since there are no visible views + self.clearFocus(); } } /// Focus the previous view in the stack, wrapping if needed. Does nothing /// if there is only one view in the stack. - pub fn focusPrevView(self: Self) void { + pub fn focusPrevView(self: *Self) void { if (self.focused_view) |current_focus| { // If there is a currently focused view, focus the previous visible view in the stack. - var it = @fieldParentPtr(std.TailQueue(View).Node, "data", current_focus).prev; - while (it) |node| : (it = node.prev) { - const view = &node.data; - if (view.current_tags & self.current_focused_tags != 0) { - view.focus(view.wlr_xdg_surface.surface); - return; - } - } - } - - // There is either no currently focused view or the first visible view in the - // stack is focused and we need to wrap. - var it = self.views.last; - while (it) |node| : (it = node.prev) { - const view = &node.data; - if (view.current_tags & self.current_focused_tags != 0) { + const current_node = @fieldParentPtr(ViewStack.Node, "view", current_focus); + var it = ViewStack.reverseIterator(current_node, self.current_focused_tags); + // Skip past the current node + _ = it.next(); + // Focus the previous visible node if there is one + if (it.next()) |view| { view.focus(view.wlr_xdg_surface.surface); return; } } - } - // TODO: obsolete this function by using a better data structure - fn visibleCount(self: Self, tags: u32) u32 { - var count: u32 = 0; - var it = self.views.first; - while (it) |node| : (it = node.next) { - const view = &node.data; - if (view.current_tags & tags != 0) { - count += 1; - } + // There is either no currently focused view or the first visible view in the + // stack is focused and we need to wrap. + var it = ViewStack.reverseIterator(self.views.last, self.current_focused_tags); + if (it.next()) |view| { + view.focus(view.wlr_xdg_surface.surface); + } else { + // Otherwise clear the focus since there are no visible views + self.clearFocus(); } - return count; } pub fn arrange(self: *Self) void { @@ -170,7 +165,12 @@ pub const Root = struct { else self.current_focused_tags; - const visible_count = self.visibleCount(root_tags); + const visible_count = blk: { + var count: u32 = 0; + var it = ViewStack.pendingIterator(self.views.first, root_tags); + while (it.next() != null) count += 1; + break :blk count; + }; const master_count = util.min(u32, self.master_count, visible_count); const slave_count = if (master_count >= visible_count) 0 else visible_count - master_count; @@ -192,18 +192,8 @@ pub const Root = struct { } var i: u32 = 0; - var it = self.views.first; - while (it) |node| : (it = node.next) { - const view = &node.data; - - if (view.pending_tags) |tags| { - if (root_tags & tags == 0) { - continue; - } - } else if (view.current_tags & root_tags == 0) { - continue; - } - + var it = ViewStack.pendingIterator(self.views.first, root_tags); + while (it.next()) |view| { if (i < master_count) { // Add the remainder to the first master to ensure every pixel of height is used const master_height = @divTrunc(@intCast(u32, output_box.height), master_count); @@ -246,10 +236,8 @@ pub const Root = struct { // to reset the pending count to 0 and clear serials from the views self.pending_configures = 0; - var it = self.views.first; - while (it) |node| : (it = node.next) { - const view = &node.data; - + var it = ViewStack.iterator(self.views.first, 0xFFFFFFFF); + while (it.next()) |view| { // Clear the serial in case this transaction is interrupting a prior one. view.pending_serial = null; @@ -322,10 +310,8 @@ pub const Root = struct { self.pending_focused_tags = null; } - var it = self.views.first; - while (it) |node| : (it = node.next) { - const view = &node.data; - + var it = ViewStack.iterator(self.views.first, 0xFFFFFFFF); + while (it.next()) |view| { // Ensure that all pending state is cleared view.pending_serial = null; if (view.pending_box) |state| { |
