river: properly teardown surface tree
When an xdg toplevel, layer surface, etc is destroyed, it is not guaranteed that all the children in the surface tree have already been destroyed. If there are still children around, destroying the root of the tree would leave dangling pointers. To fix this, destroy all children when destroying any node in the tree.
This commit is contained in:
@ -18,6 +18,7 @@
|
||||
const Subsurface = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const wlr = @import("wlroots");
|
||||
const wl = @import("wayland").server.wl;
|
||||
|
||||
@ -26,16 +27,16 @@ const util = @import("util.zig");
|
||||
|
||||
const DragIcon = @import("DragIcon.zig");
|
||||
const LayerSurface = @import("LayerSurface.zig");
|
||||
const View = @import("View.zig");
|
||||
const XdgToplevel = @import("XdgToplevel.zig");
|
||||
|
||||
pub const Parent = union(enum) {
|
||||
view: *View,
|
||||
xdg_toplevel: *XdgToplevel,
|
||||
layer_surface: *LayerSurface,
|
||||
drag_icon: *DragIcon,
|
||||
|
||||
pub fn damageWholeOutput(parent: Parent) void {
|
||||
switch (parent) {
|
||||
.view => |view| view.output.damage.addWhole(),
|
||||
.xdg_toplevel => |xdg_toplevel| xdg_toplevel.view.output.damage.addWhole(),
|
||||
.layer_surface => |layer_surface| layer_surface.output.damage.addWhole(),
|
||||
.drag_icon => |drag_icon| {
|
||||
var it = server.root.outputs.first;
|
||||
@ -50,7 +51,7 @@ parent: Parent,
|
||||
wlr_subsurface: *wlr.Subsurface,
|
||||
|
||||
// Always active
|
||||
destroy: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleDestroy),
|
||||
subsurface_destroy: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleDestroy),
|
||||
map: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleMap),
|
||||
unmap: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleUnmap),
|
||||
new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface),
|
||||
@ -65,8 +66,10 @@ pub fn create(wlr_subsurface: *wlr.Subsurface, parent: Parent) void {
|
||||
return;
|
||||
};
|
||||
subsurface.* = .{ .wlr_subsurface = wlr_subsurface, .parent = parent };
|
||||
assert(wlr_subsurface.data == 0);
|
||||
wlr_subsurface.data = @ptrToInt(subsurface);
|
||||
|
||||
wlr_subsurface.events.destroy.add(&subsurface.destroy);
|
||||
wlr_subsurface.events.destroy.add(&subsurface.subsurface_destroy);
|
||||
wlr_subsurface.events.map.add(&subsurface.map);
|
||||
wlr_subsurface.events.unmap.add(&subsurface.unmap);
|
||||
wlr_subsurface.surface.events.new_subsurface.add(&subsurface.new_subsurface);
|
||||
@ -85,17 +88,37 @@ pub fn handleExisting(surface: *wlr.Surface, parent: Parent) void {
|
||||
while (above_it.next()) |s| Subsurface.create(s, parent);
|
||||
}
|
||||
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
|
||||
const subsurface = @fieldParentPtr(Subsurface, "destroy", listener);
|
||||
|
||||
subsurface.destroy.link.remove();
|
||||
/// Destroy this Subsurface and all of its children
|
||||
pub fn destroy(subsurface: *Subsurface) void {
|
||||
subsurface.subsurface_destroy.link.remove();
|
||||
subsurface.map.link.remove();
|
||||
subsurface.unmap.link.remove();
|
||||
subsurface.new_subsurface.link.remove();
|
||||
|
||||
Subsurface.destroySubsurfaces(subsurface.wlr_subsurface.surface);
|
||||
|
||||
subsurface.wlr_subsurface.data = 0;
|
||||
util.gpa.destroy(subsurface);
|
||||
}
|
||||
|
||||
pub fn destroySubsurfaces(surface: *wlr.Surface) void {
|
||||
var below_it = surface.subsurfaces_below.iterator(.forward);
|
||||
while (below_it.next()) |wlr_subsurface| {
|
||||
if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy();
|
||||
}
|
||||
|
||||
var above_it = surface.subsurfaces_above.iterator(.forward);
|
||||
while (above_it.next()) |wlr_subsurface| {
|
||||
if (@intToPtr(?*Subsurface, wlr_subsurface.data)) |s| s.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
fn handleDestroy(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
|
||||
const subsurface = @fieldParentPtr(Subsurface, "subsurface_destroy", listener);
|
||||
|
||||
subsurface.destroy();
|
||||
}
|
||||
|
||||
fn handleMap(listener: *wl.Listener(*wlr.Subsurface), wlr_subsurface: *wlr.Subsurface) void {
|
||||
const subsurface = @fieldParentPtr(Subsurface, "map", listener);
|
||||
|
||||
|
Reference in New Issue
Block a user