From 5bec8f4fcb361d3c7527d367bc66c0810e3c91d9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 11 May 2020 23:43:04 +0200 Subject: [PATCH] Only store mapped views in the view stack --- src/Output.zig | 9 --------- src/Server.zig | 11 +++++++++-- src/View.zig | 17 ++++++++++++++++- src/XdgToplevel.zig | 5 +---- src/XwaylandView.zig | 6 +----- src/view_stack.zig | 28 +++++----------------------- 6 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/Output.zig b/src/Output.zig index cb5cba4..c2315bc 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -147,15 +147,6 @@ pub fn getRenderer(self: Self) *c.wlr_renderer { return c.river_wlr_backend_get_renderer(self.wlr_output.backend); } -/// Add a new view to the output. arrangeViews() will be called by the view -/// when it is mapped. The surface argument must be a c.wlr_xdg_surface or -/// c.wlr_xwayland_surface (if xwayland is enabled) -pub fn addView(self: *Self, surface: var) !void { - const node = try self.root.server.allocator.create(ViewStack(View).Node); - node.view.init(self, self.current_focused_tags, surface); - self.views.push(node); -} - /// Add a newly created layer surface to the output. pub fn addLayerSurface(self: *Self, wlr_layer_surface: *c.wlr_layer_surface_v1) !void { const layer = wlr_layer_surface.client_pending.layer; diff --git a/src/Server.zig b/src/Server.zig index 944f297..8639233 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -190,7 +190,10 @@ fn handleNewXdgSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) v Log.Debug.log("New xdg_toplevel", .{}); - self.input_manager.default_seat.focused_output.addView(wlr_xdg_surface) catch unreachable; + // The View will add itself to the output's view stack on map + const output = self.input_manager.default_seat.focused_output; + const node = self.allocator.create(ViewStack(View).Node) catch unreachable; + node.view.init(output, output.current_focused_tags, wlr_xdg_surface); } /// This event is raised when the layer_shell recieves a new surface from a client. @@ -261,5 +264,9 @@ fn handleNewXwaylandSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv( "New xwayland surface: title '{}', class '{}'", .{ wlr_xwayland_surface.title, wlr_xwayland_surface.class }, ); - self.input_manager.default_seat.focused_output.addView(wlr_xwayland_surface) catch unreachable; + + // The View will add itself to the output's view stack on map + const output = self.input_manager.default_seat.focused_output; + const node = self.allocator.create(ViewStack(View).Node) catch unreachable; + node.view.init(output, output.current_focused_tags, wlr_xwayland_surface); } diff --git a/src/View.zig b/src/View.zig index 32924b4..8ab32cc 100644 --- a/src/View.zig +++ b/src/View.zig @@ -105,7 +105,7 @@ pub fn init( } else unreachable; } -pub fn deinit(self: *Self) void { +pub fn deinit(self: Self) void { if (self.stashed_buffer) |buffer| { c.wlr_buffer_unref(buffer); } @@ -227,6 +227,10 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surfa pub fn map(self: *Self) void { const root = self.output.root; + // Add the view to the stack of its output + const node = @fieldParentPtr(ViewStack(Self).Node, "view", self); + self.output.views.push(node); + // Focus the newly mapped view. Note: if a seat is focusing a different output // it will continue to do so. var it = root.server.input_manager.seats.first; @@ -252,5 +256,16 @@ pub fn unmap(self: *Self) void { seat.handleViewUnmap(self); } + // Remove the view from its output's stack + const node = @fieldParentPtr(ViewStack(Self).Node, "view", self); + self.output.views.remove(node); + root.arrange(); } + +/// Destory the view and free the ViewStack node holding it. +pub fn destroy(self: *const Self) void { + self.deinit(); + const node = @fieldParentPtr(ViewStack(Self).Node, "view", self); + self.output.root.server.allocator.destroy(node); +} diff --git a/src/XdgToplevel.zig b/src/XdgToplevel.zig index a9c2040..95fee3e 100644 --- a/src/XdgToplevel.zig +++ b/src/XdgToplevel.zig @@ -110,10 +110,7 @@ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { c.wl_list_remove(&self.listen_map.link); c.wl_list_remove(&self.listen_unmap.link); - // Remove the view from the stack - const node = @fieldParentPtr(ViewStack(View).Node, "view", self.view); - output.views.remove(node); - output.root.server.allocator.destroy(node); + self.view.destroy(); } /// Called when the xdg surface is mapped, or ready to display on-screen. diff --git a/src/XwaylandView.zig b/src/XwaylandView.zig index a6bf0e1..dbd35e4 100644 --- a/src/XwaylandView.zig +++ b/src/XwaylandView.zig @@ -108,17 +108,13 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surfa /// Called when the xwayland surface is destroyed fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const self = @fieldParentPtr(Self, "listen_destroy", listener.?); - const output = self.view.output; // Remove listeners that are active for the entire lifetime of the view c.wl_list_remove(&self.listen_destroy.link); c.wl_list_remove(&self.listen_map.link); c.wl_list_remove(&self.listen_unmap.link); - // Remove the view from the stack - const node = @fieldParentPtr(ViewStack(View).Node, "view", self.view); - output.views.remove(node); - output.root.server.allocator.destroy(node); + self.view.destroy(); } /// Called when the xwayland surface is mapped, or ready to display on-screen. diff --git a/src/view_stack.zig b/src/view_stack.zig index 7e32a91..0543d03 100644 --- a/src/view_stack.zig +++ b/src/view_stack.zig @@ -92,7 +92,7 @@ pub fn ViewStack(comptime T: type) type { /// 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.wlr_surface != null and if (self.pending) + if (if (self.pending) if (node.view.pending_tags) |pending_tags| self.tags & pending_tags != 0 else @@ -109,7 +109,6 @@ pub fn ViewStack(comptime T: type) type { /// 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, @@ -121,7 +120,6 @@ pub fn ViewStack(comptime T: type) type { /// 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, @@ -133,8 +131,7 @@ pub fn ViewStack(comptime T: type) type { /// 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. + /// If a view has no pending tags, the current tags are used. pub fn pendingIterator(start: ?*Node, tags: u32) Iterator { return Iterator{ .it = start, @@ -285,51 +282,36 @@ test "iteration (View)" { var views: ViewStack(View) = undefined; views.init(); - // Pretty nice hack for testing: we don't actually need a wlr_surface here, - // but we need the iteration function to thing that the view has a non-null - // wlr_surface. So, just cast an integer to a pointer to get an arbitrary - // but non-null value. Use 8 so the alignment checks out. - const one_a_pb = try allocator.create(ViewStack(View).Node); defer allocator.destroy(one_a_pb); - one_a_pb.view.wlr_surface = @intToPtr(*c.wlr_surface, 8); one_a_pb.view.current_tags = 1 << 0; one_a_pb.view.pending_tags = 1 << 1; const two_a = try allocator.create(ViewStack(View).Node); defer allocator.destroy(two_a); - two_a.view.wlr_surface = @intToPtr(*c.wlr_surface, 8); two_a.view.current_tags = 1 << 0; two_a.view.pending_tags = null; const three_b_pa = try allocator.create(ViewStack(View).Node); defer allocator.destroy(three_b_pa); - three_b_pa.view.wlr_surface = @intToPtr(*c.wlr_surface, 8); three_b_pa.view.current_tags = 1 << 1; three_b_pa.view.pending_tags = 1 << 0; const four_b = try allocator.create(ViewStack(View).Node); defer allocator.destroy(four_b); - four_b.view.wlr_surface = @intToPtr(*c.wlr_surface, 8); four_b.view.current_tags = 1 << 1; four_b.view.pending_tags = null; const five_b = try allocator.create(ViewStack(View).Node); defer allocator.destroy(five_b); - five_b.view.wlr_surface = @intToPtr(*c.wlr_surface, 8); five_b.view.current_tags = 1 << 1; five_b.view.pending_tags = null; - const unmapped_1 = try allocator.create(ViewStack(View).Node); - defer allocator.destroy(unmapped_1); - unmapped_1.view.wlr_surface = null; - views.push(three_b_pa); // {3} views.push(one_a_pb); // {1, 3} - views.push(unmapped_1); // {u, 1, 3} - views.push(four_b); // {4, u, 1, 3} - views.push(five_b); // {5, 4, u, 1, 3} - views.push(two_a); // {2, 5, 4, u, 1, 3} + views.push(four_b); // {4, 1, 3} + views.push(five_b); // {5, 4, 1, 3} + views.push(two_a); // {2, 5, 4, 1, 3} // Iteration over all tags {