LayerSurface: fix use-after-free on destroy
The scene_layer_surface may be destroyed before handleDestroy is called, which means we can't rely on it to access the wlr_layer_surface in destroyPopups().
This commit is contained in:
parent
005bde367c
commit
e11d4dc0de
@ -346,7 +346,7 @@ fn updateKeyboardFocus(self: Self, result: Root.AtResult) void {
|
|||||||
self.seat.focusOutput(layer_surface.output);
|
self.seat.focusOutput(layer_surface.output);
|
||||||
// If a keyboard inteactive layer surface has been clicked on,
|
// If a keyboard inteactive layer surface has been clicked on,
|
||||||
// give it keyboard focus.
|
// give it keyboard focus.
|
||||||
if (layer_surface.scene_layer_surface.layer_surface.current.keyboard_interactive != .none) {
|
if (layer_surface.wlr_layer_surface.current.keyboard_interactive != .none) {
|
||||||
self.seat.setFocusRaw(.{ .layer = layer_surface });
|
self.seat.setFocusRaw(.{ .layer = layer_surface });
|
||||||
} else {
|
} else {
|
||||||
self.seat.focus(null);
|
self.seat.focus(null);
|
||||||
|
@ -32,6 +32,7 @@ const XdgPopup = @import("XdgPopup.zig");
|
|||||||
const log = std.log.scoped(.layer_shell);
|
const log = std.log.scoped(.layer_shell);
|
||||||
|
|
||||||
output: *Output,
|
output: *Output,
|
||||||
|
wlr_layer_surface: *wlr.LayerSurfaceV1,
|
||||||
scene_layer_surface: *wlr.SceneLayerSurfaceV1,
|
scene_layer_surface: *wlr.SceneLayerSurfaceV1,
|
||||||
popup_tree: *wlr.SceneTree,
|
popup_tree: *wlr.SceneTree,
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
|
|||||||
|
|
||||||
layer_surface.* = .{
|
layer_surface.* = .{
|
||||||
.output = output,
|
.output = output,
|
||||||
|
.wlr_layer_surface = wlr_layer_surface,
|
||||||
.scene_layer_surface = try layer_tree.createSceneLayerSurfaceV1(wlr_layer_surface),
|
.scene_layer_surface = try layer_tree.createSceneLayerSurfaceV1(wlr_layer_surface),
|
||||||
.popup_tree = try output.layers.popups.createSceneTree(),
|
.popup_tree = try output.layers.popups.createSceneTree(),
|
||||||
};
|
};
|
||||||
@ -71,14 +73,14 @@ pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroyPopups(layer_surface: *LayerSurface) void {
|
pub fn destroyPopups(layer_surface: *LayerSurface) void {
|
||||||
var it = layer_surface.scene_layer_surface.layer_surface.popups.safeIterator(.forward);
|
var it = layer_surface.wlr_layer_surface.popups.safeIterator(.forward);
|
||||||
while (it.next()) |wlr_xdg_popup| wlr_xdg_popup.destroy();
|
while (it.next()) |wlr_xdg_popup| wlr_xdg_popup.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
|
fn handleDestroy(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurfaceV1) void {
|
||||||
const layer_surface = @fieldParentPtr(LayerSurface, "destroy", listener);
|
const layer_surface = @fieldParentPtr(LayerSurface, "destroy", listener);
|
||||||
|
|
||||||
log.debug("layer surface '{s}' destroyed", .{wlr_layer_surface.namespace});
|
log.debug("layer surface '{s}' destroyed", .{layer_surface.wlr_layer_surface.namespace});
|
||||||
|
|
||||||
layer_surface.destroy.link.remove();
|
layer_surface.destroy.link.remove();
|
||||||
layer_surface.map.link.remove();
|
layer_surface.map.link.remove();
|
||||||
@ -112,7 +114,7 @@ fn handleUnmap(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *
|
|||||||
|
|
||||||
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||||
const layer_surface = @fieldParentPtr(LayerSurface, "commit", listener);
|
const layer_surface = @fieldParentPtr(LayerSurface, "commit", listener);
|
||||||
const wlr_layer_surface = layer_surface.scene_layer_surface.layer_surface;
|
const wlr_layer_surface = layer_surface.wlr_layer_surface;
|
||||||
|
|
||||||
assert(wlr_layer_surface.output != null);
|
assert(wlr_layer_surface.output != null);
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ fn handleKeyboardInteractiveExclusive(output: *Output) void {
|
|||||||
assert(node.type == .tree);
|
assert(node.type == .tree);
|
||||||
if (@intToPtr(?*SceneNodeData, node.data)) |node_data| {
|
if (@intToPtr(?*SceneNodeData, node.data)) |node_data| {
|
||||||
const layer_surface = node_data.data.layer_surface;
|
const layer_surface = node_data.data.layer_surface;
|
||||||
const wlr_layer_surface = layer_surface.scene_layer_surface.layer_surface;
|
const wlr_layer_surface = layer_surface.wlr_layer_surface;
|
||||||
if (wlr_layer_surface.mapped and
|
if (wlr_layer_surface.mapped and
|
||||||
wlr_layer_surface.current.keyboard_interactive == .exclusive)
|
wlr_layer_surface.current.keyboard_interactive == .exclusive)
|
||||||
{
|
{
|
||||||
@ -167,7 +169,7 @@ fn handleKeyboardInteractiveExclusive(output: *Output) void {
|
|||||||
// seats.
|
// seats.
|
||||||
seat.setFocusRaw(.{ .layer = to_focus });
|
seat.setFocusRaw(.{ .layer = to_focus });
|
||||||
} else if (seat.focused == .layer) {
|
} else if (seat.focused == .layer) {
|
||||||
const current_focus = seat.focused.layer.scene_layer_surface.layer_surface;
|
const current_focus = seat.focused.layer.wlr_layer_surface;
|
||||||
// If the seat is currently focusing an unmapped layer surface or one
|
// If the seat is currently focusing an unmapped layer surface or one
|
||||||
// without keyboard interactivity, stop focusing that layer surface.
|
// without keyboard interactivity, stop focusing that layer surface.
|
||||||
if (!current_focus.mapped or current_focus.current.keyboard_interactive == .none) {
|
if (!current_focus.mapped or current_focus.current.keyboard_interactive == .none) {
|
||||||
|
@ -283,7 +283,7 @@ pub fn removeOutput(root: *Self, output: *Output) void {
|
|||||||
while (it.next()) |scene_node| {
|
while (it.next()) |scene_node| {
|
||||||
assert(scene_node.type == .tree);
|
assert(scene_node.type == .tree);
|
||||||
if (@intToPtr(?*SceneNodeData, scene_node.data)) |node_data| {
|
if (@intToPtr(?*SceneNodeData, scene_node.data)) |node_data| {
|
||||||
node_data.data.layer_surface.scene_layer_surface.layer_surface.destroy();
|
node_data.data.layer_surface.wlr_layer_surface.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ pub fn focus(self: *Self, _target: ?*View) void {
|
|||||||
|
|
||||||
// While a layer surface is exclusively focused, views may not receive focus
|
// While a layer surface is exclusively focused, views may not receive focus
|
||||||
if (self.focused == .layer) {
|
if (self.focused == .layer) {
|
||||||
const wlr_layer_surface = self.focused.layer.scene_layer_surface.layer_surface;
|
const wlr_layer_surface = self.focused.layer.wlr_layer_surface;
|
||||||
if (wlr_layer_surface.current.keyboard_interactive == .exclusive and
|
if (wlr_layer_surface.current.keyboard_interactive == .exclusive and
|
||||||
(wlr_layer_surface.current.layer == .top or wlr_layer_surface.current.layer == .overlay))
|
(wlr_layer_surface.current.layer == .top or wlr_layer_surface.current.layer == .overlay))
|
||||||
{
|
{
|
||||||
@ -210,7 +210,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
|||||||
const target_surface = switch (new_focus) {
|
const target_surface = switch (new_focus) {
|
||||||
.view => |target_view| target_view.rootSurface(),
|
.view => |target_view| target_view.rootSurface(),
|
||||||
.xwayland_override_redirect => |target_or| target_or.xwayland_surface.surface,
|
.xwayland_override_redirect => |target_or| target_or.xwayland_surface.surface,
|
||||||
.layer => |target_layer| target_layer.scene_layer_surface.layer_surface.surface,
|
.layer => |target_layer| target_layer.wlr_layer_surface.surface,
|
||||||
.lock_surface => |lock_surface| lock_surface.wlr_lock_surface.surface,
|
.lock_surface => |lock_surface| lock_surface.wlr_lock_surface.surface,
|
||||||
.none => null,
|
.none => null,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user