aboutsummaryrefslogtreecommitdiff
path: root/src/root.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/root.zig')
-rw-r--r--src/root.zig142
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| {