Allow storing *View in ViewStack
This is done in preparation for implementing focus stacks.
This commit is contained in:
parent
0f52f664f2
commit
b822084f39
@ -3,6 +3,7 @@ const c = @import("c.zig");
|
|||||||
|
|
||||||
const Log = @import("log.zig").Log;
|
const Log = @import("log.zig").Log;
|
||||||
const Server = @import("server.zig").Server;
|
const Server = @import("server.zig").Server;
|
||||||
|
const View = @import("view.zig").View;
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
|
|
||||||
pub const Arg = union {
|
pub const Arg = union {
|
||||||
@ -60,7 +61,7 @@ pub fn modifyMasterFactor(server: *Server, arg: Arg) void {
|
|||||||
pub fn zoom(server: *Server, arg: Arg) void {
|
pub fn zoom(server: *Server, arg: Arg) void {
|
||||||
if (server.root.focused_view) |current_focus| {
|
if (server.root.focused_view) |current_focus| {
|
||||||
const output = server.root.focusedOutput();
|
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) {
|
if (node != output.views.first) {
|
||||||
output.views.remove(node);
|
output.views.remove(node);
|
||||||
output.views.push(node);
|
output.views.push(node);
|
||||||
|
@ -6,6 +6,7 @@ const Box = @import("box.zig").Box;
|
|||||||
const LayerSurface = @import("layer_surface.zig").LayerSurface;
|
const LayerSurface = @import("layer_surface.zig").LayerSurface;
|
||||||
const Log = @import("log.zig").Log;
|
const Log = @import("log.zig").Log;
|
||||||
const Root = @import("root.zig").Root;
|
const Root = @import("root.zig").Root;
|
||||||
|
const View = @import("view.zig").View;
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
|
|
||||||
pub const Output = struct {
|
pub const Output = struct {
|
||||||
@ -22,7 +23,7 @@ pub const Output = struct {
|
|||||||
usable_box: Box,
|
usable_box: Box,
|
||||||
|
|
||||||
/// The top of the stack is the "most important" view.
|
/// The top of the stack is the "most important" view.
|
||||||
views: ViewStack,
|
views: ViewStack(View),
|
||||||
|
|
||||||
/// A bit field of focused tags
|
/// A bit field of focused tags
|
||||||
current_focused_tags: u32,
|
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
|
/// Add a new view to the output. arrangeViews() will be called by the view
|
||||||
/// when it is mapped.
|
/// when it is mapped.
|
||||||
pub fn addView(self: *Self, wlr_xdg_surface: *c.wlr_xdg_surface) void {
|
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);
|
node.view.init(self, wlr_xdg_surface, self.current_focused_tags);
|
||||||
self.views.push(node);
|
self.views.push(node);
|
||||||
}
|
}
|
||||||
@ -129,7 +130,7 @@ pub const Output = struct {
|
|||||||
|
|
||||||
const visible_count = blk: {
|
const visible_count = blk: {
|
||||||
var count: u32 = 0;
|
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;
|
while (it.next() != null) count += 1;
|
||||||
break :blk count;
|
break :blk count;
|
||||||
};
|
};
|
||||||
@ -157,8 +158,9 @@ pub const Output = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
var it = ViewStack.pendingIterator(self.views.first, output_tags);
|
var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
|
||||||
while (it.next()) |view| {
|
while (it.next()) |node| {
|
||||||
|
const view = &node.view;
|
||||||
if (i < master_count) {
|
if (i < master_count) {
|
||||||
// Add the remainder to the first master to ensure every pixel of height is used
|
// Add the remainder to the first master to ensure every pixel of height is used
|
||||||
const master_height = @divTrunc(layout_height, master_count);
|
const master_height = @divTrunc(layout_height, master_count);
|
||||||
|
@ -44,8 +44,9 @@ pub fn renderOutput(output: *Output) void {
|
|||||||
renderLayer(output.*, output.layers[c.ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now, ox, oy);
|
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.
|
// The first view in the list is "on top" so iterate in reverse.
|
||||||
var it = ViewStack.reverseIterator(output.views.last, output.current_focused_tags);
|
var it = ViewStack(View).reverseIterator(output.views.last, output.current_focused_tags);
|
||||||
while (it.next()) |view| {
|
while (it.next()) |node| {
|
||||||
|
const view = &node.view;
|
||||||
// This check prevents a race condition when a frame is requested
|
// This check prevents a race condition when a frame is requested
|
||||||
// between mapping of a view and the first configure being handled.
|
// between mapping of a view and the first configure being handled.
|
||||||
if (view.current_box.width == 0 or view.current_box.height == 0) {
|
if (view.current_box.width == 0 or view.current_box.height == 0) {
|
||||||
|
46
src/root.zig
46
src/root.zig
@ -71,10 +71,10 @@ pub const Root = struct {
|
|||||||
var output_it = self.outputs.first;
|
var output_it = self.outputs.first;
|
||||||
while (output_it) |node| : (output_it = node.next) {
|
while (output_it) |node| : (output_it = node.next) {
|
||||||
const output = &node.data;
|
const output = &node.data;
|
||||||
var view_it = ViewStack.iterator(output.views.first, 0xFFFFFFFF);
|
var view_it = ViewStack(View).iterator(output.views.first, 0xFFFFFFFF);
|
||||||
while (view_it.next()) |view| {
|
while (view_it.next()) |view_node| {
|
||||||
if (view.isAt(lx, ly, surface, sx, sy)) {
|
if (view_node.view.isAt(lx, ly, surface, sx, sy)) {
|
||||||
return view;
|
return &view_node.view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,22 +95,22 @@ pub const Root = struct {
|
|||||||
const output = self.focusedOutput();
|
const output = self.focusedOutput();
|
||||||
if (self.focused_view) |current_focus| {
|
if (self.focused_view) |current_focus| {
|
||||||
// If there is a currently focused view, focus the next visible view in the stack.
|
// If there is a currently focused view, focus the next visible view in the stack.
|
||||||
const current_node = @fieldParentPtr(ViewStack.Node, "view", current_focus);
|
const current_node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus);
|
||||||
var it = ViewStack.iterator(current_node, output.current_focused_tags);
|
var it = ViewStack(View).iterator(current_node, output.current_focused_tags);
|
||||||
// Skip past the current node
|
// Skip past the current node
|
||||||
_ = it.next();
|
_ = it.next();
|
||||||
// Focus the next visible node if there is one
|
// Focus the next visible node if there is one
|
||||||
if (it.next()) |view| {
|
if (it.next()) |node| {
|
||||||
view.focus(view.wlr_xdg_surface.surface);
|
node.view.focus(node.view.wlr_xdg_surface.surface);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is either no currently focused view or the last visible view in the
|
// There is either no currently focused view or the last visible view in the
|
||||||
// stack is focused and we need to wrap.
|
// stack is focused and we need to wrap.
|
||||||
var it = ViewStack.iterator(output.views.first, output.current_focused_tags);
|
var it = ViewStack(View).iterator(output.views.first, output.current_focused_tags);
|
||||||
if (it.next()) |view| {
|
if (it.next()) |node| {
|
||||||
view.focus(view.wlr_xdg_surface.surface);
|
node.view.focus(node.view.wlr_xdg_surface.surface);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise clear the focus since there are no visible views
|
// Otherwise clear the focus since there are no visible views
|
||||||
self.clearFocus();
|
self.clearFocus();
|
||||||
@ -123,22 +123,22 @@ pub const Root = struct {
|
|||||||
const output = self.focusedOutput();
|
const output = self.focusedOutput();
|
||||||
if (self.focused_view) |current_focus| {
|
if (self.focused_view) |current_focus| {
|
||||||
// If there is a currently focused view, focus the previous visible view in the stack.
|
// If there is a currently focused view, focus the previous visible view in the stack.
|
||||||
const current_node = @fieldParentPtr(ViewStack.Node, "view", current_focus);
|
const current_node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus);
|
||||||
var it = ViewStack.reverseIterator(current_node, output.current_focused_tags);
|
var it = ViewStack(View).reverseIterator(current_node, output.current_focused_tags);
|
||||||
// Skip past the current node
|
// Skip past the current node
|
||||||
_ = it.next();
|
_ = it.next();
|
||||||
// Focus the previous visible node if there is one
|
// Focus the previous visible node if there is one
|
||||||
if (it.next()) |view| {
|
if (it.next()) |node| {
|
||||||
view.focus(view.wlr_xdg_surface.surface);
|
node.view.focus(node.view.wlr_xdg_surface.surface);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is either no currently focused view or the first visible view in the
|
// There is either no currently focused view or the first visible view in the
|
||||||
// stack is focused and we need to wrap.
|
// stack is focused and we need to wrap.
|
||||||
var it = ViewStack.reverseIterator(output.views.last, output.current_focused_tags);
|
var it = ViewStack(View).reverseIterator(output.views.last, output.current_focused_tags);
|
||||||
if (it.next()) |view| {
|
if (it.next()) |node| {
|
||||||
view.focus(view.wlr_xdg_surface.surface);
|
node.view.focus(node.view.wlr_xdg_surface.surface);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise clear the focus since there are no visible views
|
// Otherwise clear the focus since there are no visible views
|
||||||
self.clearFocus();
|
self.clearFocus();
|
||||||
@ -166,8 +166,9 @@ pub const Root = struct {
|
|||||||
var output_it = self.outputs.first;
|
var output_it = self.outputs.first;
|
||||||
while (output_it) |node| : (output_it = node.next) {
|
while (output_it) |node| : (output_it = node.next) {
|
||||||
const output = &node.data;
|
const output = &node.data;
|
||||||
var view_it = ViewStack.iterator(output.views.first, 0xFFFFFFFF);
|
var view_it = ViewStack(View).iterator(output.views.first, 0xFFFFFFFF);
|
||||||
while (view_it.next()) |view| {
|
while (view_it.next()) |view_node| {
|
||||||
|
const view = &view_node.view;
|
||||||
// Clear the serial in case this transaction is interrupting a prior one.
|
// Clear the serial in case this transaction is interrupting a prior one.
|
||||||
view.pending_serial = null;
|
view.pending_serial = null;
|
||||||
|
|
||||||
@ -259,8 +260,9 @@ pub const Root = struct {
|
|||||||
self.focusNextView();
|
self.focusNextView();
|
||||||
}
|
}
|
||||||
|
|
||||||
var view_it = ViewStack.iterator(output.views.first, 0xFFFFFFFF);
|
var view_it = ViewStack(View).iterator(output.views.first, 0xFFFFFFFF);
|
||||||
while (view_it.next()) |view| {
|
while (view_it.next()) |view_node| {
|
||||||
|
const view = &view_node.view;
|
||||||
// Ensure that all pending state is cleared
|
// Ensure that all pending state is cleared
|
||||||
view.pending_serial = null;
|
view.pending_serial = null;
|
||||||
if (view.pending_box) |state| {
|
if (view.pending_box) |state| {
|
||||||
|
@ -156,7 +156,7 @@ pub const View = struct {
|
|||||||
const view = @fieldParentPtr(View, "listen_destroy", listener.?);
|
const view = @fieldParentPtr(View, "listen_destroy", listener.?);
|
||||||
const output = view.output;
|
const output = view.output;
|
||||||
|
|
||||||
const node = @fieldParentPtr(ViewStack.Node, "view", view);
|
const node = @fieldParentPtr(ViewStack(View).Node, "view", view);
|
||||||
output.views.remove(node);
|
output.views.remove(node);
|
||||||
output.root.server.allocator.destroy(node);
|
output.root.server.allocator.destroy(node);
|
||||||
}
|
}
|
||||||
|
@ -1,147 +1,151 @@
|
|||||||
const View = @import("view.zig").View;
|
const View = @import("view.zig").View;
|
||||||
|
|
||||||
/// A specialized doubly-linked stack that allows for filtered iteration
|
/// A specialized doubly-linked stack that allows for filtered iteration
|
||||||
/// over the nodes
|
/// over the nodes. T must be View or *View.
|
||||||
pub const ViewStack = struct {
|
pub fn ViewStack(comptime T: type) type {
|
||||||
const Self = @This();
|
if (!(T == View or T == *View)) {
|
||||||
|
@compileError("ViewStack: T must be View or *View");
|
||||||
pub const Node = struct {
|
|
||||||
/// Previous/next nodes in the stack
|
|
||||||
prev: ?*Node,
|
|
||||||
next: ?*Node,
|
|
||||||
|
|
||||||
/// The view stored in this node
|
|
||||||
view: View,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 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;
|
|
||||||
}
|
}
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
/// Add a node to the top of the stack.
|
pub const Node = struct {
|
||||||
pub fn push(self: *Self, new_node: *Node) void {
|
/// Previous/next nodes in the stack
|
||||||
// Set the prev/next pointers of the new node
|
prev: ?*Node,
|
||||||
new_node.prev = null;
|
next: ?*Node,
|
||||||
new_node.next = self.first;
|
|
||||||
|
|
||||||
if (self.first) |first| {
|
/// The view stored in this node
|
||||||
// If the list is not empty, set the prev pointer of the current
|
view: T,
|
||||||
// first node to the new node.
|
};
|
||||||
first.prev = new_node;
|
|
||||||
} else {
|
/// Top/bottom nodes in the stack
|
||||||
// If the list is empty set the last pointer to the new node.
|
first: ?*Node,
|
||||||
self.last = new_node;
|
last: ?*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
|
/// Add a node to the top of the stack.
|
||||||
self.first = new_node;
|
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;
|
||||||
|
|
||||||
/// Remove a node from the view stack. This removes it from the stack of
|
if (self.first) |first| {
|
||||||
/// all views as well as the stack of visible ones.
|
// If the list is not empty, set the prev pointer of the current
|
||||||
pub fn remove(self: *Self, target_node: *Node) void {
|
// first node to the new node.
|
||||||
// Set the previous node/list head to the next pointer
|
first.prev = new_node;
|
||||||
if (target_node.prev) |prev_node| {
|
} else {
|
||||||
prev_node.next = target_node.next;
|
// If the list is empty set the last pointer to the new node.
|
||||||
} else {
|
self.last = new_node;
|
||||||
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
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
// Set the first pointer to the new node
|
||||||
|
self.first = 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 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) ?*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) {
|
||||||
|
self.it = if (self.reverse) node.prev else node.next;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 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 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 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;
|
const testing = @import("std").testing;
|
||||||
|
|
||||||
test "push/remove" {
|
test "push/remove (*View)" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
var views: ViewStack = undefined;
|
var views: ViewStack(*View) = undefined;
|
||||||
views.init();
|
views.init();
|
||||||
|
|
||||||
const one = try allocator.create(ViewStack.Node);
|
const one = try allocator.create(ViewStack(*View).Node);
|
||||||
defer allocator.destroy(one);
|
defer allocator.destroy(one);
|
||||||
const two = try allocator.create(ViewStack.Node);
|
const two = try allocator.create(ViewStack(*View).Node);
|
||||||
defer allocator.destroy(two);
|
defer allocator.destroy(two);
|
||||||
const three = try allocator.create(ViewStack.Node);
|
const three = try allocator.create(ViewStack(*View).Node);
|
||||||
defer allocator.destroy(three);
|
defer allocator.destroy(three);
|
||||||
const four = try allocator.create(ViewStack.Node);
|
const four = try allocator.create(ViewStack(*View).Node);
|
||||||
defer allocator.destroy(four);
|
defer allocator.destroy(four);
|
||||||
const five = try allocator.create(ViewStack.Node);
|
const five = try allocator.create(ViewStack(*View).Node);
|
||||||
defer allocator.destroy(five);
|
defer allocator.destroy(five);
|
||||||
|
|
||||||
views.push(three); // {3}
|
views.push(three); // {3}
|
||||||
@ -255,40 +259,40 @@ test "push/remove" {
|
|||||||
testing.expect(views.last == null);
|
testing.expect(views.last == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "iteration" {
|
test "iteration (View)" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
var views: ViewStack = undefined;
|
var views: ViewStack(View) = undefined;
|
||||||
views.init();
|
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);
|
defer allocator.destroy(one_a_pb);
|
||||||
one_a_pb.view.mapped = true;
|
one_a_pb.view.mapped = true;
|
||||||
one_a_pb.view.current_tags = 1 << 0;
|
one_a_pb.view.current_tags = 1 << 0;
|
||||||
one_a_pb.view.pending_tags = 1 << 1;
|
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);
|
defer allocator.destroy(two_a);
|
||||||
two_a.view.mapped = true;
|
two_a.view.mapped = true;
|
||||||
two_a.view.current_tags = 1 << 0;
|
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);
|
defer allocator.destroy(three_b_pa);
|
||||||
three_b_pa.view.mapped = true;
|
three_b_pa.view.mapped = true;
|
||||||
three_b_pa.view.current_tags = 1 << 1;
|
three_b_pa.view.current_tags = 1 << 1;
|
||||||
three_b_pa.view.pending_tags = 1 << 0;
|
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);
|
defer allocator.destroy(four_b);
|
||||||
four_b.view.mapped = true;
|
four_b.view.mapped = true;
|
||||||
four_b.view.current_tags = 1 << 1;
|
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);
|
defer allocator.destroy(five_b);
|
||||||
five_b.view.mapped = true;
|
five_b.view.mapped = true;
|
||||||
five_b.view.current_tags = 1 << 1;
|
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);
|
defer allocator.destroy(unmapped_1);
|
||||||
unmapped_1.view.mapped = false;
|
unmapped_1.view.mapped = false;
|
||||||
|
|
||||||
@ -301,92 +305,92 @@ test "iteration" {
|
|||||||
|
|
||||||
// Iteration over all tags
|
// Iteration over all tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.iterator(views.first, 0xFFFFFFFF);
|
var it = ViewStack(View).iterator(views.first, 0xFFFFFFFF);
|
||||||
testing.expect(it.next() == &two_a.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
|
||||||
testing.expect(it.next() == &five_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
|
||||||
testing.expect(it.next() == &four_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
|
||||||
testing.expect(it.next() == &one_a_pb.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
|
||||||
testing.expect(it.next() == &three_b_pa.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration over 'a' tags
|
// Iteration over 'a' tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.iterator(views.first, 1 << 0);
|
var it = ViewStack(View).iterator(views.first, 1 << 0);
|
||||||
testing.expect(it.next() == &two_a.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
|
||||||
testing.expect(it.next() == &one_a_pb.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration over 'b' tags
|
// Iteration over 'b' tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.iterator(views.first, 1 << 1);
|
var it = ViewStack(View).iterator(views.first, 1 << 1);
|
||||||
testing.expect(it.next() == &five_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
|
||||||
testing.expect(it.next() == &four_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
|
||||||
testing.expect(it.next() == &three_b_pa.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration over tags that aren't present
|
// 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);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse iteration over all tags
|
// Reverse iteration over all tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.reverseIterator(views.last, 0xFFFFFFFF);
|
var it = ViewStack(View).reverseIterator(views.last, 0xFFFFFFFF);
|
||||||
testing.expect(it.next() == &three_b_pa.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
|
||||||
testing.expect(it.next() == &one_a_pb.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
|
||||||
testing.expect(it.next() == &four_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
|
||||||
testing.expect(it.next() == &five_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
|
||||||
testing.expect(it.next() == &two_a.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse iteration over 'a' tags
|
// Reverse iteration over 'a' tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.reverseIterator(views.last, 1 << 0);
|
var it = ViewStack(View).reverseIterator(views.last, 1 << 0);
|
||||||
testing.expect(it.next() == &one_a_pb.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
|
||||||
testing.expect(it.next() == &two_a.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse iteration over 'b' tags
|
// Reverse iteration over 'b' tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.reverseIterator(views.last, 1 << 1);
|
var it = ViewStack(View).reverseIterator(views.last, 1 << 1);
|
||||||
testing.expect(it.next() == &three_b_pa.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
|
||||||
testing.expect(it.next() == &four_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
|
||||||
testing.expect(it.next() == &five_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse iteration over tags that aren't present
|
// 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);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration over (pending) 'a' tags
|
// Iteration over (pending) 'a' tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.pendingIterator(views.first, 1 << 0);
|
var it = ViewStack(View).pendingIterator(views.first, 1 << 0);
|
||||||
testing.expect(it.next() == &two_a.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &two_a.view);
|
||||||
testing.expect(it.next() == &three_b_pa.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &three_b_pa.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration over (pending) 'b' tags
|
// Iteration over (pending) 'b' tags
|
||||||
{
|
{
|
||||||
var it = ViewStack.pendingIterator(views.first, 1 << 1);
|
var it = ViewStack(View).pendingIterator(views.first, 1 << 1);
|
||||||
testing.expect(it.next() == &five_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &five_b.view);
|
||||||
testing.expect(it.next() == &four_b.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &four_b.view);
|
||||||
testing.expect(it.next() == &one_a_pb.view);
|
testing.expect((if (it.next()) |node| &node.view else null) == &one_a_pb.view);
|
||||||
testing.expect(it.next() == null);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iteration over (pending) tags that aren't present
|
// 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);
|
testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user