aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/command.zig3
-rw-r--r--src/output.zig12
-rw-r--r--src/render.zig5
-rw-r--r--src/root.zig46
-rw-r--r--src/view.zig2
-rw-r--r--src/view_stack.zig318
6 files changed, 198 insertions, 188 deletions
diff --git a/src/command.zig b/src/command.zig
index 1f2b483..b5c237a 100644
--- a/src/command.zig
+++ b/src/command.zig
@@ -3,6 +3,7 @@ const c = @import("c.zig");
const Log = @import("log.zig").Log;
const Server = @import("server.zig").Server;
+const View = @import("view.zig").View;
const ViewStack = @import("view_stack.zig").ViewStack;
pub const Arg = union {
@@ -60,7 +61,7 @@ pub fn modifyMasterFactor(server: *Server, arg: Arg) void {
pub fn zoom(server: *Server, arg: Arg) void {
if (server.root.focused_view) |current_focus| {
const output = server.root.focusedOutput();
- const node = @fieldParentPtr(ViewStack.Node, "view", current_focus);
+ const node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus);
if (node != output.views.first) {
output.views.remove(node);
output.views.push(node);
diff --git a/src/output.zig b/src/output.zig
index 3aa1ae8..23e9e88 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -6,6 +6,7 @@ const Box = @import("box.zig").Box;
const LayerSurface = @import("layer_surface.zig").LayerSurface;
const Log = @import("log.zig").Log;
const Root = @import("root.zig").Root;
+const View = @import("view.zig").View;
const ViewStack = @import("view_stack.zig").ViewStack;
pub const Output = struct {
@@ -22,7 +23,7 @@ pub const Output = struct {
usable_box: Box,
/// The top of the stack is the "most important" view.
- views: ViewStack,
+ views: ViewStack(View),
/// A bit field of focused tags
current_focused_tags: u32,
@@ -100,7 +101,7 @@ pub const Output = struct {
/// Add a new view to the output. arrangeViews() will be called by the view
/// when it is mapped.
pub fn addView(self: *Self, wlr_xdg_surface: *c.wlr_xdg_surface) void {
- const node = self.root.server.allocator.create(ViewStack.Node) catch unreachable;
+ const node = self.root.server.allocator.create(ViewStack(View).Node) catch unreachable;
node.view.init(self, wlr_xdg_surface, self.current_focused_tags);
self.views.push(node);
}
@@ -129,7 +130,7 @@ pub const Output = struct {
const visible_count = blk: {
var count: u32 = 0;
- var it = ViewStack.pendingIterator(self.views.first, output_tags);
+ var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (it.next() != null) count += 1;
break :blk count;
};
@@ -157,8 +158,9 @@ pub const Output = struct {
}
var i: u32 = 0;
- var it = ViewStack.pendingIterator(self.views.first, output_tags);
- while (it.next()) |view| {
+ var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
+ while (it.next()) |node| {
+ const view = &node.view;
if (i < master_count) {
// Add the remainder to the first master to ensure every pixel of height is used
const master_height = @divTrunc(layout_height, master_count);
diff --git a/src/render.zig b/src/render.zig
index a330a5b..074228c 100644
--- a/src/render.zig
+++ b/src/render.zig
@@ -44,8 +44,9 @@ pub fn renderOutput(output: *Output) void {
renderLayer(output.*, output.layers[c.ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now, ox, oy);
// The first view in the list is "on top" so iterate in reverse.
- var it = ViewStack.reverseIterator(output.views.last, output.current_focused_tags);
- while (it.next()) |view| {
+ var it = ViewStack(View).reverseIterator(output.views.last, output.current_focused_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) {
diff --git a/src/root.zig b/src/root.zig
index 2ac8074..a5f2bf0 100644
--- a/src/root.zig
+++ b/src/root.zig
@@ -71,10 +71,10 @@ pub const Root = struct {
var output_it = self.outputs.first;
while (output_it) |node| : (output_it = node.next) {
const output = &node.data;
- var view_it = ViewStack.iterator(output.views.first, 0xFFFFFFFF);
- while (view_it.next()) |view| {
- if (view.isAt(lx, ly, surface, sx, sy)) {
- return view;
+ var view_it = ViewStack(View).iterator(output.views.first, 0xFFFFFFFF);
+ while (view_it.next()) |view_node| {
+ if (view_node.view.isAt(lx, ly, surface, sx, sy)) {
+ return &view_node.view;
}
}
}
@@ -95,22 +95,22 @@ pub const Root = struct {
const output = self.focusedOutput();
if (self.focused_view) |current_focus| {
// If there is a currently focused view, focus the next visible view in the stack.
- const current_node = @fieldParentPtr(ViewStack.Node, "view", current_focus);
- var it = ViewStack.iterator(current_node, output.current_focused_tags);
+ const current_node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus);
+ var it = ViewStack(View).iterator(current_node, output.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);
+ if (it.next()) |node| {
+ node.view.focus(node.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 = ViewStack.iterator(output.views.first, output.current_focused_tags);
- if (it.next()) |view| {
- view.focus(view.wlr_xdg_surface.surface);
+ var it = ViewStack(View).iterator(output.views.first, output.current_focused_tags);
+ if (it.next()) |node| {
+ node.view.focus(node.view.wlr_xdg_surface.surface);
} else {
// Otherwise clear the focus since there are no visible views
self.clearFocus();
@@ -123,22 +123,22 @@ pub const Root = struct {
const output = self.focusedOutput();
if (self.focused_view) |current_focus| {
// If there is a currently focused view, focus the previous visible view in the stack.
- const current_node = @fieldParentPtr(ViewStack.Node, "view", current_focus);
- var it = ViewStack.reverseIterator(current_node, output.current_focused_tags);
+ const current_node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus);
+ var it = ViewStack(View).reverseIterator(current_node, output.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);
+ if (it.next()) |node| {
+ node.view.focus(node.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 = ViewStack.reverseIterator(output.views.last, output.current_focused_tags);
- if (it.next()) |view| {
- view.focus(view.wlr_xdg_surface.surface);
+ var it = ViewStack(View).reverseIterator(output.views.last, output.current_focused_tags);
+ if (it.next()) |node| {
+ node.view.focus(node.view.wlr_xdg_surface.surface);
} else {
// Otherwise clear the focus since there are no visible views
self.clearFocus();
@@ -166,8 +166,9 @@ pub const Root = struct {
var output_it = self.outputs.first;
while (output_it) |node| : (output_it = node.next) {
const output = &node.data;
- var view_it = ViewStack.iterator(output.views.first, 0xFFFFFFFF);
- while (view_it.next()) |view| {
+ var view_it = ViewStack(View).iterator(output.views.first, 0xFFFFFFFF);
+ while (view_it.next()) |view_node| {
+ const view = &view_node.view;
// Clear the serial in case this transaction is interrupting a prior one.
view.pending_serial = null;
@@ -259,8 +260,9 @@ pub const Root = struct {
self.focusNextView();
}
- var view_it = ViewStack.iterator(output.views.first, 0xFFFFFFFF);
- while (view_it.next()) |view| {
+ var view_it = ViewStack(View).iterator(output.views.first, 0xFFFFFFFF);
+ while (view_it.next()) |view_node| {
+ const view = &view_node.view;
// Ensure that all pending state is cleared
view.pending_serial = null;
if (view.pending_box) |state| {
diff --git a/src/view.zig b/src/view.zig
index 824f98a..191bcf8 100644
--- a/src/view.zig
+++ b/src/view.zig
@@ -156,7 +156,7 @@ pub const View = struct {
const view = @fieldParentPtr(View, "listen_destroy", listener.?);
const output = view.output;
- const node = @fieldParentPtr(ViewStack.Node, "view", view);
+ const node = @fieldParentPtr(ViewStack(View).Node, "view", view);
output.views.remove(node);
output.root.server.allocator.destroy(node);
}
diff --git a/src/view_stack.zig b/src/view_stack.zig
index a729837..c1fe4e1 100644
--- a/src/view_stack.zig
+++ b/src/view_stack.zig
@@ -1,147 +1,151 @@
const View = @import("view.zig").View;
/// A specialized doubly-linked stack that allows for filtered iteration
-/// over the nodes
-pub const ViewStack = struct {
- const Self = @This();
+/// over the nodes. T must be View or *View.
+pub fn ViewStack(comptime T: type) type {
+ if (!(T == View or T == *View)) {
+ @compileError("ViewStack: T must be View or *View");
+ }
+ return struct {
+ const Self = @This();
- pub const Node = struct {
- /// Previous/next nodes in the stack
- prev: ?*Node,
- next: ?*Node,
+ pub const Node = struct {
+ /// Previous/next nodes in the stack
+ prev: ?*Node,
+ next: ?*Node,
- /// The view stored in this node
- view: View,
- };
+ /// The view stored in this node
+ view: T,
+ };
- /// Top/bottom nodes in the stack
- first: ?*Node,
- last: ?*Node,
+ /// 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;
- }
-
- /// Add a node to the top of the stack.
- pub fn push(self: *Self, new_node: *Node) void {
- // Set the prev/next pointers of the new node
- new_node.prev = null;
- new_node.next = self.first;
-
- if (self.first) |first| {
- // If the list is not empty, set the prev pointer of the current
- // first node to the new node.
- first.prev = new_node;
- } else {
- // If the list is empty set the last pointer to the new node.
- self.last = new_node;
+ /// Initialize an undefined stack
+ pub fn init(self: *Self) void {
+ self.first = null;
+ self.last = null;
}
- // Set the first pointer to the new node
- self.first = new_node;
- }
+ /// Add a node to the top of the stack.
+ pub fn push(self: *Self, new_node: *Node) void {
+ // Set the prev/next pointers of the new node
+ new_node.prev = null;
+ new_node.next = self.first;
+
+ if (self.first) |first| {
+ // If the list is not empty, set the prev pointer of the current
+ // first node to the new node.
+ first.prev = new_node;
+ } else {
+ // If the list is empty set the last pointer to the new node.
+ self.last = new_node;
+ }
- /// Remove a node from the view stack. This removes it from the stack of
- /// all views as well as the stack of visible ones.
- pub fn remove(self: *Self, target_node: *Node) void {
- // Set the previous node/list head to the next pointer
- if (target_node.prev) |prev_node| {
- prev_node.next = target_node.next;
- } else {
- self.first = target_node.next;
+ // Set the first pointer to the new node
+ self.first = new_node;
}
- // Set the next node/list tail to the previous pointer
- if (target_node.next) |next_node| {
- next_node.prev = target_node.prev;
- } else {
- self.last = target_node.prev;
+ /// Remove a node from the view stack. This removes it from the stack of
+ /// all views as well as the stack of visible ones.
+ pub fn remove(self: *Self, target_node: *Node) void {
+ // Set the previous node/list head to the next pointer
+ if (target_node.prev) |prev_node| {
+ prev_node.next = target_node.next;
+ } else {
+ self.first = target_node.next;
+ }
+
+ // Set the next node/list tail to the previous pointer
+ if (target_node.next) |next_node| {
+ next_node.prev = target_node.prev;
+ } else {
+ self.last = target_node.prev;
+ }
}
- }
- 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) ?*View {
- while (self.it) |node| : (self.it = if (self.reverse) node.prev else node.next) {
- if (node.view.mapped and if (self.pending)
- if (node.view.pending_tags) |pending_tags|
- self.tags & pending_tags != 0
+ 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 (node.view.mapped and if (self.pending)
+ if (node.view.pending_tags) |pending_tags|
+ self.tags & pending_tags != 0
+ else
+ self.tags & node.view.current_tags != 0
else
- self.tags & node.view.current_tags != 0
- else
- self.tags & node.view.current_tags != 0) {
- const ret = &node.view;
- self.it = if (self.reverse) node.prev else node.next;
- return ret;
+ self.tags & node.view.current_tags != 0) {
+ self.it = if (self.reverse) node.prev else node.next;
+ return node;
+ }
}
+ return null;
}
- return null;
- }
- };
-
- /// Returns an iterator starting at the passed node and filtered by
- /// checking the passed tags against the current tags of each view.
- /// Unmapped views are skipped.
- 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.
- /// Unmapped views are skipped.
- pub fn reverseIterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = true,
- .pending = false,
- };
- }
+ /// Returns an iterator starting at the passed node and filtered by
+ /// checking the passed tags against the current tags of each view.
+ /// Unmapped views are skipped.
+ pub fn iterator(start: ?*Node, tags: u32) Iterator {
+ return Iterator{
+ .it = start,
+ .tags = tags,
+ .reverse = false,
+ .pending = false,
+ };
+ }
- /// 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. Unmapped
- /// views are skipped.
- pub fn pendingIterator(start: ?*Node, tags: u32) Iterator {
- return Iterator{
- .it = start,
- .tags = tags,
- .reverse = false,
- .pending = true,
- };
- }
-};
+ /// Returns a reverse iterator starting at the passed node and filtered by
+ /// checking the passed tags against the current tags of each view.
+ /// Unmapped views are skipped.
+ pub fn reverseIterator(start: ?*Node, tags: u32) Iterator {
+ return Iterator{
+ .it = start,
+ .tags = tags,
+ .reverse = true,
+ .pending = false,
+ };
+ }
+
+ /// 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. Unmapped
+ /// views are skipped.
+ pub fn pendingIterator(start: ?*Node, tags: u32) Iterator {
+ return Iterator{
+ .it = start,
+ .tags = tags,
+ .reverse = false,
+ .pending = true,
+ };
+ }
+ };
+}
const testing = @import("std").testing;
-test "push/remove" {
+test "push/remove (*View)" {
const allocator = testing.allocator;
- var views: ViewStack = undefined;
+ var views: ViewStack(*View) = undefined;
views.init();
- const one = try allocator.create(ViewStack.Node);
+ const one = try allocator.create(ViewStack(*View).Node);
defer allocator.destroy(one);
- const two = try allocator.create(ViewStack.Node);
+ const two = try allocator.create(ViewStack(*View).Node);
defer allocator.destroy(two);
- const three = try allocator.create(ViewStack.Node);
+ const three = try allocator.create(ViewStack(*View).Node);
defer allocator.destroy(three);
- const four = try allocator.create(ViewStack.Node);
+ const four = try allocator.create(ViewStack(*View).Node);
defer allocator.destroy(four);
- const five = try allocator.create(ViewStack.Node);
+ const five = try allocator.create(ViewStack(*View).Node);
defer allocator.destroy(five);
views.push(three); // {3}
@@ -255,40 +259,40 @@ test "push/remove" {
testing.expect(views.last == null);
}
-test "iteration" {
+test "iteration (View)" {
const allocator = testing.allocator;
- var views: ViewStack = undefined;
+ var views: ViewStack(View) = undefined;
views.init();
- const one_a_pb = try allocator.create(ViewStack.Node);
+ const one_a_pb = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(one_a_pb);
one_a_pb.view.mapped = true;
one_a_pb.view.current_tags = 1 << 0;
one_a_pb.view.pending_tags = 1 << 1;
- const two_a = try allocator.create(ViewStack.Node);
+ const two_a = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(two_a);
two_a.view.mapped = true;
two_a.view.current_tags = 1 << 0;
- const three_b_pa = try allocator.create(ViewStack.Node);
+ const three_b_pa = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(three_b_pa);
three_b_pa.view.mapped = true;
three_b_pa.view.current_tags = 1 << 1;
three_b_pa.view.pending_tags = 1 << 0;
- const four_b = try allocator.create(ViewStack.Node);
+ const four_b = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(four_b);
four_b.view.mapped = true;
four_b.view.current_tags = 1 << 1;
- const five_b = try allocator.create(ViewStack.Node);
+ const five_b = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(five_b);
five_b.view.mapped = true;
five_b.view.current_tags = 1 << 1;
- const unmapped_1 = try allocator.create(ViewStack.Node);
+ const unmapped_1 = try allocator.create(ViewStack(View).Node);
defer allocator.destroy(unmapped_1);
unmapped_1.view.mapped = false;
@@ -301,92 +305,92 @@ test "iteration" {
// Iteration over all tags
{
- var it = ViewStack.iterator(views.first, 0xFFFFFFFF);
- 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);
+ var it = ViewStack(View).iterator(views.first, 0xFFFFFFFF);
+ 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.iterator(views.first, 1 << 0);
- testing.expect(it.next() == &two_a.view);
- testing.expect(it.next() == &one_a_pb.view);
+ 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.iterator(views.first, 1 << 1);
- testing.expect(it.next() == &five_b.view);
- testing.expect(it.next() == &four_b.view);
- testing.expect(it.next() == &three_b_pa.view);
+ 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
{
- var it = ViewStack.iterator(views.first, 1 << 2);
+ var it = ViewStack(View).iterator(views.first, 1 << 2);
testing.expect(it.next() == null);
}
// Reverse iteration over all tags
{
- var it = ViewStack.reverseIterator(views.last, 0xFFFFFFFF);
- 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);
+ var it = ViewStack(View).reverseIterator(views.last, 0xFFFFFFFF);
+ 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);
testing.expect(it.next() == null);
}
// Reverse iteration over 'a' tags
{
- var it = ViewStack.reverseIterator(views.last, 1 << 0);
- testing.expect(it.next() == &one_a_pb.view);
- testing.expect(it.next() == &two_a.view);
+ 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);
testing.expect(it.next() == null);
}
// Reverse iteration over 'b' tags
{
- var it = ViewStack.reverseIterator(views.last, 1 << 1);
- testing.expect(it.next() == &three_b_pa.view);
- testing.expect(it.next() == &four_b.view);
- testing.expect(it.next() == &five_b.view);
+ 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);
testing.expect(it.next() == null);
}
// Reverse iteration over tags that aren't present
{
- var it = ViewStack.reverseIterator(views.first, 1 << 2);
+ var it = ViewStack(View).reverseIterator(views.first, 1 << 2);
testing.expect(it.next() == null);
}
// Iteration over (pending) 'a' tags
{
- var it = ViewStack.pendingIterator(views.first, 1 << 0);
- testing.expect(it.next() == &two_a.view);
- testing.expect(it.next() == &three_b_pa.view);
+ 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);
testing.expect(it.next() == null);
}
// Iteration over (pending) 'b' tags
{
- var it = ViewStack.pendingIterator(views.first, 1 << 1);
- testing.expect(it.next() == &five_b.view);
- testing.expect(it.next() == &four_b.view);
- testing.expect(it.next() == &one_a_pb.view);
+ 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);
testing.expect(it.next() == null);
}
// Iteration over (pending) tags that aren't present
{
- var it = ViewStack.pendingIterator(views.first, 1 << 2);
+ var it = ViewStack(View).pendingIterator(views.first, 1 << 2);
testing.expect(it.next() == null);
}
}