Only store mapped views in the view stack

This commit is contained in:
Isaac Freund 2020-05-11 23:43:04 +02:00
parent b2f172e91b
commit 5bec8f4fcb
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
6 changed files with 32 additions and 44 deletions

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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.

View File

@ -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
{