aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Cursor.zig18
-rw-r--r--river/Output.zig39
-rw-r--r--river/OutputStatus.zig13
-rw-r--r--river/Root.zig9
-rw-r--r--river/Seat.zig44
-rw-r--r--river/command/focus_view.zig18
-rw-r--r--river/command/zoom.zig22
-rw-r--r--river/render.zig34
-rw-r--r--river/view_stack.zig205
9 files changed, 185 insertions, 217 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig
index ab78137..abca096 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -548,16 +548,20 @@ fn layerSurfaceAt(
/// Find the topmost visible view surface (incl. popups) at ox,oy.
fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surface {
// Focused views are rendered on top, so look for them first.
- var it = ViewStack(View).iterator(output.views.first, output.current.tags);
- while (it.next()) |node| {
- if (node.view.current.focus == 0) continue;
- if (node.view.surfaceAt(ox, oy, sx, sy)) |found| return found;
+ var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
+ while (it.next()) |view| {
+ if (view.current.focus == 0) continue;
+ if (view.surfaceAt(ox, oy, sx, sy)) |found| return found;
}
- it = ViewStack(View).iterator(output.views.first, output.current.tags);
- while (it.next()) |node| {
- if (node.view.surfaceAt(ox, oy, sx, sy)) |found| return found;
+ it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
+ while (it.next()) |view| {
+ if (view.surfaceAt(ox, oy, sx, sy)) |found| return found;
}
return null;
}
+
+fn surfaceAtFilter(view: *View, filter_tags: u32) bool {
+ return !view.destroying and view.current.tags & filter_tags != 0;
+}
diff --git a/river/Output.zig b/river/Output.zig
index a05518b..794d833 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -97,7 +97,7 @@ pub fn init(self: *Self, root: *Root, wlr_output: *c.wlr_output) !void {
layer.* = std.TailQueue(LayerSurface).init();
}
- self.views.init();
+ self.views = ViewStack(View){};
self.current = .{
.tags = 1 << 0,
@@ -184,13 +184,10 @@ fn layoutFull(self: *Self, visible_count: u32) void {
.height = self.usable_box.height - (2 * xy_offset),
};
- var it = ViewStack(View).pendingIterator(self.views.first, self.pending.tags);
- while (it.next()) |node| {
- const view = &node.view;
- if (!view.pending.float and !view.pending.fullscreen) {
- view.pending.box = full_box;
- view.applyConstraints();
- }
+ var it = ViewStack(View).iter(self.views.first, .forward, self.pending.tags, arrangeFilter);
+ while (it.next()) |view| {
+ view.pending.box = full_box;
+ view.applyConstraints();
}
}
@@ -285,32 +282,28 @@ fn layoutExternal(self: *Self, visible_count: u32) !void {
// Apply window configuration to views
var i: u32 = 0;
- var view_it = ViewStack(View).pendingIterator(self.views.first, self.pending.tags);
- while (view_it.next()) |node| {
- const view = &node.view;
- if (!view.pending.float and !view.pending.fullscreen and !view.destroying) {
- view.pending.box = view_boxen.items[i];
- view.applyConstraints();
- i += 1;
- }
+ var view_it = ViewStack(View).iter(self.views.first, .forward, self.pending.tags, arrangeFilter);
+ while (view_it.next()) |view| : (i += 1) {
+ view.pending.box = view_boxen.items[i];
+ view.applyConstraints();
}
}
+fn arrangeFilter(view: *View, filter_tags: u32) bool {
+ return !view.destroying and !view.pending.float and
+ !view.pending.fullscreen and view.pending.tags & filter_tags != 0;
+}
+
/// Arrange all views on the output for the current layout. Modifies only
/// pending state, the changes are not appplied until a transaction is started
/// and completed.
pub fn arrangeViews(self: *Self) void {
if (self == &self.root.noop_output) return;
- const full_area = Box.fromWlrBox(c.wlr_output_layout_get_box(self.root.wlr_output_layout, self.wlr_output).*);
-
// Count up views that will be arranged by the layout
var layout_count: u32 = 0;
- var it = ViewStack(View).pendingIterator(self.views.first, self.pending.tags);
- while (it.next()) |node| {
- const view = &node.view;
- if (!view.pending.float and !view.pending.fullscreen and !view.destroying) layout_count += 1;
- }
+ var it = ViewStack(View).iter(self.views.first, .forward, self.pending.tags, arrangeFilter);
+ while (it.next() != null) layout_count += 1;
// If the usable area has a zero dimension, trying to arrange the layout
// would cause an underflow and is pointless anyway.
diff --git a/river/OutputStatus.zig b/river/OutputStatus.zig
index eac2bbd..af264d1 100644
--- a/river/OutputStatus.zig
+++ b/river/OutputStatus.zig
@@ -60,13 +60,14 @@ pub fn sendViewTags(self: Self) void {
var view_tags = std.ArrayList(u32).init(util.gpa);
defer view_tags.deinit();
- var it = ViewStack(View).iterator(self.output.views.first, std.math.maxInt(u32));
- while (it.next()) |node|
+ var it = self.output.views.first;
+ while (it) |node| : (it = node.next) {
view_tags.append(node.view.current.tags) catch {
- c.wl_resource_post_no_memory(self.wl_resource);
- log.crit(.river_status, "out of memory", .{});
- return;
- };
+ c.wl_resource_post_no_memory(self.wl_resource);
+ log.crit(.river_status, "out of memory", .{});
+ return;
+ };
+ }
var wl_array = c.wl_array{
.size = view_tags.items.len * @sizeOf(u32),
diff --git a/river/Root.zig b/river/Root.zig
index 6e7e99e..974bcee 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -125,12 +125,11 @@ pub fn startTransaction(self: *Self) void {
// to reset the pending count to 0 and clear serials from the views
self.pending_configures = 0;
- // Iterate over all layout views of all outputs
+ // Iterate over all views of all outputs
var output_it = self.outputs.first;
- while (output_it) |node| : (output_it = node.next) {
- const output = &node.data;
- var view_it = ViewStack(View).iterator(output.views.first, std.math.maxInt(u32));
- while (view_it.next()) |view_node| {
+ while (output_it) |output_node| : (output_it = output_node.next) {
+ var view_it = output_node.data.views.first;
+ while (view_it) |view_node| : (view_it = view_node.next) {
const view = &view_node.view;
if (view.destroying) {
diff --git a/river/Seat.zig b/river/Seat.zig
index 96d320b..a1825ed 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -88,7 +88,7 @@ pub fn init(self: *Self, input_manager: *InputManager, name: [*:0]const u8) !voi
self.focused = .none;
- self.focus_stack.init();
+ self.focus_stack = ViewStack(*View){};
self.status_trackers = std.SinglyLinkedList(SeatStatus).init();
@@ -111,41 +111,43 @@ pub fn deinit(self: *Self) void {
/// Set the current focus. If a visible view is passed it will be focused.
/// If null is passed, the first visible view in the focus stack will be focused.
-pub fn focus(self: *Self, _view: ?*View) void {
- var view = _view;
+pub fn focus(self: *Self, _target: ?*View) void {
+ var target = _target;
// While a layer surface is focused, views may not recieve focus
if (self.focused == .layer) return;
// If the view is not currently visible, behave as if null was passed
- if (view) |v| {
- if (v.output != self.focused_output or
- v.pending.tags & self.focused_output.pending.tags == 0) view = null;
+ if (target) |view| {
+ if (view.output != self.focused_output or
+ view.pending.tags & self.focused_output.pending.tags == 0) target = null;
}
// If the target view is not fullscreen or null, then a fullscreen view
// will grab focus if visible.
- if (if (view) |v| !v.pending.fullscreen else true) {
- var it = ViewStack(*View).pendingIterator(self.focus_stack.first, self.focused_output.pending.tags);
- view = while (it.next()) |node| {
- if (node.view.output == self.focused_output and node.view.pending.fullscreen) break node.view;
- } else view;
+ if (if (target) |v| !v.pending.fullscreen else true) {
+ const tags = self.focused_output.pending.tags;
+ var it = ViewStack(*View).iter(self.focus_stack.first, .forward, tags, pendingFilter);
+ target = while (it.next()) |view| {
+ if (view.output == self.focused_output and view.pending.fullscreen) break view;
+ } else target;
}
- if (view == null) {
+ if (target == null) {
// Set view to the first currently visible view in the focus stack if any
- var it = ViewStack(*View).pendingIterator(self.focus_stack.first, self.focused_output.pending.tags);
- view = while (it.next()) |node| {
- if (node.view.output == self.focused_output) break node.view;
+ const tags = self.focused_output.pending.tags;
+ var it = ViewStack(*View).iter(self.focus_stack.first, .forward, tags, pendingFilter);
+ target = while (it.next()) |view| {
+ if (view.output == self.focused_output) break view;
} else null;
}
- if (view) |view_to_focus| {
+ if (target) |view| {
// Find or allocate a new node in the focus stack for the target view
var it = self.focus_stack.first;
while (it) |node| : (it = node.next) {
// If the view is found, move it to the top of the stack
- if (node.view == view_to_focus) {
+ if (node.view == view) {
const new_focus_node = self.focus_stack.remove(node);
self.focus_stack.push(node);
break;
@@ -153,18 +155,22 @@ pub fn focus(self: *Self, _view: ?*View) void {
} else {
// The view is not in the stack, so allocate a new node and prepend it
const new_focus_node = util.gpa.create(ViewStack(*View).Node) catch return;
- new_focus_node.view = view_to_focus;
+ new_focus_node.view = view;
self.focus_stack.push(new_focus_node);
}
// Focus the target view
- self.setFocusRaw(.{ .view = view_to_focus });
+ self.setFocusRaw(.{ .view = view });
} else {
// Otherwise clear the focus
self.setFocusRaw(.{ .none = {} });
}
}
+fn pendingFilter(view: *View, filter_tags: u32) bool {
+ return !view.destroying and view.pending.tags & filter_tags != 0;
+}
+
/// Switch focus to the target, handling unfocus and input inhibition
/// properly. This should only be called directly if dealing with layers.
pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
diff --git a/river/command/focus_view.zig b/river/command/focus_view.zig
index 4e77665..3ac3b12 100644
--- a/river/command/focus_view.zig
+++ b/river/command/focus_view.zig
@@ -44,15 +44,15 @@ pub fn focusView(
// If there is a currently focused view, focus the next visible view in the stack.
const focused_node = @fieldParentPtr(ViewStack(View).Node, "view", seat.focused.view);
var it = switch (direction) {
- .next => ViewStack(View).iterator(focused_node, output.current.tags),
- .previous => ViewStack(View).reverseIterator(focused_node, output.current.tags),
+ .next => ViewStack(View).iter(focused_node, .forward, output.pending.tags, filter),
+ .previous => ViewStack(View).iter(focused_node, .reverse, output.pending.tags, filter),
};
// Skip past the focused node
_ = it.next();
// Focus the next visible node if there is one
- if (it.next()) |node| {
- seat.focus(&node.view);
+ if (it.next()) |view| {
+ seat.focus(view);
output.root.startTransaction();
return;
}
@@ -61,10 +61,14 @@ pub fn focusView(
// There is either no currently focused view or the last visible view in the
// stack is focused and we need to wrap.
var it = switch (direction) {
- .next => ViewStack(View).iterator(output.views.first, output.current.tags),
- .previous => ViewStack(View).reverseIterator(output.views.last, output.current.tags),
+ .next => ViewStack(View).iter(output.views.first, .forward, output.pending.tags, filter),
+ .previous => ViewStack(View).iter(output.views.last, .reverse, output.pending.tags, filter),
};
- seat.focus(if (it.next()) |node| &node.view else null);
+ seat.focus(it.next());
output.root.startTransaction();
}
+
+fn filter(view: *View, filter_tags: u32) bool {
+ return !view.destroying and view.pending.tags & filter_tags != 0;
+}
diff --git a/river/command/zoom.zig b/river/command/zoom.zig
index a701758..3efdc65 100644
--- a/river/command/zoom.zig
+++ b/river/command/zoom.zig
@@ -39,19 +39,14 @@ pub fn zoom(
// If the first view that is part of the layout is focused, zoom
// the next view in the layout. Otherwise zoom the focused view.
const output = seat.focused_output;
- var it = ViewStack(View).iterator(output.views.first, output.current.tags);
- const layout_first = while (it.next()) |node| {
- if (!node.view.pending.float and !node.view.pending.fullscreen) break node;
- } else unreachable;
+ var it = ViewStack(View).iter(output.views.first, .forward, output.pending.tags, filter);
+ const layout_first = @fieldParentPtr(ViewStack(View).Node, "view", it.next().?);
const focused_node = @fieldParentPtr(ViewStack(View).Node, "view", seat.focused.view);
- const zoom_node = if (focused_node == layout_first) blk: {
- while (it.next()) |node| {
- if (!node.view.pending.float and !node.view.pending.fullscreen) break :blk node;
- } else {
- break :blk null;
- }
- } else focused_node;
+ const zoom_node = if (focused_node == layout_first)
+ if (it.next()) |view| @fieldParentPtr(ViewStack(View).Node, "view", view) else null
+ else
+ focused_node;
if (zoom_node) |to_bump| {
output.views.remove(to_bump);
@@ -62,3 +57,8 @@ pub fn zoom(
}
}
}
+
+fn filter(view: *View, filter_tags: u32) bool {
+ return !view.destroying and !view.pending.float and
+ !view.pending.fullscreen and view.pending.tags & filter_tags != 0;
+}
diff --git a/river/render.zig b/river/render.zig
index 76492ab..9e3beaa 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -57,9 +57,9 @@ pub fn renderOutput(output: *Output) void {
c.wlr_renderer_begin(wlr_renderer, width, height);
// Find the first visible fullscreen view in the stack if there is one
- var it = ViewStack(View).iterator(output.views.first, output.current.tags);
- const fullscreen_view = while (it.next()) |node| {
- if (node.view.current.fullscreen) break &node.view;
+ var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, renderFilter);
+ const fullscreen_view = while (it.next()) |view| {
+ if (view.current.fullscreen) break view;
} else null;
// If we have a fullscreen view to render, render it.
@@ -76,14 +76,8 @@ pub fn renderOutput(output: *Output) void {
renderLayer(output.*, output.layers[c.ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now);
// The first view in the list is "on top" so iterate in reverse.
- it = ViewStack(View).reverseIterator(output.views.last, output.current.tags);
- while (it.next()) |node| {
- const view = &node.view;
-
- // This check prevents a race condition when a frame is requested
- // between mapping of a view and the first configure being handled.
- if (view.current.box.width == 0 or view.current.box.height == 0) continue;
-
+ it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
+ while (it.next()) |view| {
// Focused views are rendered on top of normal views, skip them for now
if (view.current.focus != 0) continue;
@@ -92,14 +86,8 @@ pub fn renderOutput(output: *Output) void {
}
// Render focused views
- it = ViewStack(View).reverseIterator(output.views.last, output.current.tags);
- while (it.next()) |node| {
- const view = &node.view;
-
- // This check prevents a race condition when a frame is requested
- // between mapping of a view and the first configure being handled.
- if (view.current.box.width == 0 or view.current.box.height == 0) continue;
-
+ it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
+ while (it.next()) |view| {
// Skip unfocused views since we already rendered them
if (view.current.focus == 0) continue;
@@ -130,6 +118,14 @@ pub fn renderOutput(output: *Output) void {
_ = c.wlr_output_commit(output.wlr_output);
}
+fn renderFilter(view: *View, filter_tags: u32) bool {
+ // This check prevents a race condition when a frame is requested
+ // between mapping of a view and the first configure being handled.
+ if (view.current.box.width == 0 or view.current.box.height == 0)
+ return false;
+ return view.current.tags & filter_tags != 0;
+}
+
/// Render all surfaces on the passed layer
fn renderLayer(output: Output, layer: std.TailQueue(LayerSurface), now: *c.timespec) void {
var it = layer.first;
diff --git a/river/view_stack.zig b/river/view_stack.zig
index eb69ebc..25f453e 100644
--- a/river/view_stack.zig
+++ b/river/view_stack.zig
@@ -41,14 +41,8 @@ pub fn ViewStack(comptime T: type) type {
};
/// Top/bottom nodes in the stack
- first: ?*Node,
- last: ?*Node,
-
- /// Initialize an undefined stack
- pub fn init(self: *Self) void {
- self.first = null;
- self.last = null;
- }
+ first: ?*Node = null,
+ last: ?*Node = null,
/// Add a node to the top of the stack.
pub fn push(self: *Self, new_node: *Node) void {
@@ -114,60 +108,42 @@ pub fn ViewStack(comptime T: type) type {
}
}
- const Iterator = struct {
- it: ?*Node,
- tags: u32,
- reverse: bool,
- pending: bool,
-
- /// Returns the next node in iteration order, or null if done.
- /// This function is horribly ugly, but it's well tested below.
- pub fn next(self: *Iterator) ?*Node {
- while (self.it) |node| : (self.it = if (self.reverse) node.prev else node.next) {
- if (if (self.pending)
- self.tags & node.view.pending.tags != 0
- else
- self.tags & node.view.current.tags != 0) {
- self.it = if (self.reverse) node.prev else node.next;
- return node;
- }
- }
- return null;
- }
+ const Direction = enum {
+ forward,
+ reverse,
};
- /// Returns an iterator starting at the passed node and filtered by
- /// checking the passed tags against the current tags of each view.
- pub fn iterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = false,
- .pending = false,
- };
- }
-
- /// Returns a reverse iterator starting at the passed node and filtered by
- /// checking the passed tags against the current tags of each view.
- pub fn reverseIterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = true,
- .pending = false,
+ fn Iter(comptime Context: type) type {
+ return struct {
+ it: ?*Node,
+ dir: Direction,
+ context: Context,
+ filter: fn (*View, Context) bool,
+
+ /// Returns the next node in iteration order which passes the
+ /// filter, or null if done.
+ pub fn next(self: *@This()) ?*View {
+ return while (self.it) |node| : (self.it = if (self.dir == .forward) node.next else node.prev) {
+ const view = if (T == View) &node.view else node.view;
+ if (self.filter(view, self.context)) {
+ self.it = if (self.dir == .forward) node.next else node.prev;
+ break view;
+ }
+ } else null;
+ }
};
}
- /// Returns an iterator starting at the passed node and filtered by
- /// checking the passed tags against the pending tags of each view.
- /// If a view has no pending tags, the current tags are used.
- pub fn pendingIterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = false,
- .pending = true,
- };
+ /// Return a filtered iterator over the stack given a start node,
+ /// iteration direction, and filter function. Views for which the
+ /// filter function returns false will be skipped.
+ pub fn iter(
+ start: ?*Node,
+ dir: Direction,
+ context: var,
+ filter: fn (*View, @TypeOf(context)) bool,
+ ) Iter(@TypeOf(context)) {
+ return .{ .it = start, .dir = dir, .context = context, .filter = filter };
}
};
}
@@ -177,8 +153,7 @@ test "push/remove (*View)" {
const allocator = testing.allocator;
- var views: ViewStack(*View) = undefined;
- views.init();
+ var views = ViewStack(*View){};
const one = try allocator.create(ViewStack(*View).Node);
defer allocator.destroy(one);
@@ -309,8 +284,21 @@ test "iteration (View)" {
const allocator = testing.allocator;
- var views: ViewStack(View) = undefined;
- views.init();
+ const filters = struct {
+ fn all(view: *View, context: void) bool {
+ return true;
+ }
+
+ fn none(view: *View, context: void) bool {
+ return false;
+ }
+
+ fn current(view: *View, filter_tags: u32) bool {
+ return view.current.tags & filter_tags != 0;
+ }
+ };
+
+ var views = ViewStack(View){};
const one_a_pb = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(one_a_pb);
@@ -343,94 +331,71 @@ test "iteration (View)" {
views.push(five_b); // {5, 4, 1, 3}
views.push(two_a); // {2, 5, 4, 1, 3}
- // Iteration over all tags
- {
- var it = ViewStack(View).iterator(views.first, std.math.maxInt(u32));
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over 'a' tags
- {
- var it = ViewStack(View).iterator(views.first, 1 << 0);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over 'b' tags
- {
- var it = ViewStack(View).iterator(views.first, 1 << 1);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect(it.next() == null);
- }
-
- // Iteration over tags that aren't present
+ // Iteration over all views
{
- var it = ViewStack(View).iterator(views.first, 1 << 2);
+ var it = ViewStack(View).iter(views.first, .forward, {}, filters.all);
+ testing.expect(it.next() == &two_a.view);
+ testing.expect(it.next() == &five_b.view);
+ testing.expect(it.next() == &four_b.view);
+ testing.expect(it.next() == &one_a_pb.view);
+ testing.expect(it.next() == &three_b_pa.view);
testing.expect(it.next() == null);
}
- // Reverse iteration over all tags
+ // Iteration over no views
{
- var it = ViewStack(View).reverseIterator(views.last, std.math.maxInt(u32));
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
+ var it = ViewStack(View).iter(views.first, .forward, {}, filters.none);
testing.expect(it.next() == null);
}
- // Reverse iteration over 'a' tags
+ // Iteration over 'a' tags
{
- var it = ViewStack(View).reverseIterator(views.last, 1 << 0);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
+ var it = ViewStack(View).iter(views.first, .forward, @as(u32, 1 << 0), filters.current);
+ testing.expect(it.next() == &two_a.view);
+ testing.expect(it.next() == &one_a_pb.view);
testing.expect(it.next() == null);
}
- // Reverse iteration over 'b' tags
+ // Iteration over 'b' tags
{
- var it = ViewStack(View).reverseIterator(views.last, 1 << 1);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
+ var it = ViewStack(View).iter(views.first, .forward, @as(u32, 1 << 1), filters.current);
+ testing.expect(it.next() == &five_b.view);
+ testing.expect(it.next() == &four_b.view);
+ testing.expect(it.next() == &three_b_pa.view);
testing.expect(it.next() == null);
}
- // Reverse iteration over tags that aren't present
+ // Reverse iteration over all views
{
- var it = ViewStack(View).reverseIterator(views.first, 1 << 2);
+ var it = ViewStack(View).iter(views.last, .reverse, {}, filters.all);
+ testing.expect(it.next() == &three_b_pa.view);
+ testing.expect(it.next() == &one_a_pb.view);
+ testing.expect(it.next() == &four_b.view);
+ testing.expect(it.next() == &five_b.view);
+ testing.expect(it.next() == &two_a.view);
testing.expect(it.next() == null);
}
- // Iteration over (pending) 'a' tags
+ // Reverse iteration over no views
{
- var it = ViewStack(View).pendingIterator(views.first, 1 << 0);
- testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
+ var it = ViewStack(View).iter(views.last, .reverse, {}, filters.none);
testing.expect(it.next() == null);
}
- // Iteration over (pending) 'b' tags
+ // Reverse iteration over 'a' tags
{
- var it = ViewStack(View).pendingIterator(views.first, 1 << 1);
- testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
- testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
+ var it = ViewStack(View).iter(views.last, .reverse, @as(u32, 1 << 0), filters.current);
+ testing.expect(it.next() == &one_a_pb.view);
+ testing.expect(it.next() == &two_a.view);
testing.expect(it.next() == null);
}
- // Iteration over (pending) tags that aren't present
+ // Reverse iteration over 'b' tags
{
- var it = ViewStack(View).pendingIterator(views.first, 1 << 2);
+ var it = ViewStack(View).iter(views.last, .reverse, @as(u32, 1 << 1), filters.current);
+ testing.expect(it.next() == &three_b_pa.view);
+ testing.expect(it.next() == &four_b.view);
+ testing.expect(it.next() == &five_b.view);
testing.expect(it.next() == null);
}
}