From 3594fe501e69f0172d0d09d2b583b3360ea8aa96 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 8 Apr 2024 12:54:05 +0200 Subject: [PATCH] View: fix assertion failure if focused while destroying Also clean up this code a bit, it's no longer necessary to split these one line functions out into separate files as Zig's conditional compilation support has improved since these functions were originally written. --- river/View.zig | 34 +++++++++++++++++----------------- river/XdgToplevel.zig | 19 ------------------- river/XwaylandView.zig | 19 ------------------- 3 files changed, 17 insertions(+), 55 deletions(-) diff --git a/river/View.zig b/river/View.zig index a11bd92..84a0214 100644 --- a/river/View.zig +++ b/river/View.zig @@ -453,12 +453,14 @@ pub fn configure(view: *View) bool { } } -pub fn rootSurface(view: View) *wlr.Surface { - assert(view.mapped and !view.destroying); +/// Returns null if the view is currently being destroyed and no longer has +/// an associated surface. +/// May also return null for Xwayland views that are not currently mapped. +pub fn rootSurface(view: View) ?*wlr.Surface { return switch (view.impl) { - .toplevel => |toplevel| toplevel.rootSurface(), - .xwayland_view => |xwayland_view| xwayland_view.rootSurface(), - .none => unreachable, + .toplevel => |toplevel| toplevel.wlr_toplevel.base.surface, + .xwayland_view => |xwayland_view| xwayland_view.xwayland_surface.surface, + .none => null, }; } @@ -466,7 +468,7 @@ pub fn sendFrameDone(view: View) void { assert(view.mapped and !view.destroying); var now: os.timespec = undefined; os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); - view.rootSurface().sendFrameDone(&now); + view.rootSurface().?.sendFrameDone(&now); } pub fn dropSavedSurfaceTree(view: *View) void { @@ -528,20 +530,17 @@ pub fn setPendingOutput(view: *View, output: *Output) void { } pub fn close(view: View) void { - assert(!view.destroying); switch (view.impl) { - .toplevel => |toplevel| toplevel.close(), - .xwayland_view => |xwayland_view| xwayland_view.close(), - .none => unreachable, + .toplevel => |toplevel| toplevel.wlr_toplevel.sendClose(), + .xwayland_view => |xwayland_view| xwayland_view.xwayland_surface.close(), + .none => {}, } } pub fn destroyPopups(view: View) void { - assert(!view.destroying); switch (view.impl) { .toplevel => |toplevel| toplevel.destroyPopups(), - .xwayland_view => {}, - .none => unreachable, + .xwayland_view, .none => {}, } } @@ -549,8 +548,8 @@ pub fn destroyPopups(view: View) void { pub fn getTitle(view: View) ?[*:0]const u8 { assert(!view.destroying); return switch (view.impl) { - .toplevel => |toplevel| toplevel.getTitle(), - .xwayland_view => |xwayland_view| xwayland_view.getTitle(), + .toplevel => |toplevel| toplevel.wlr_toplevel.title, + .xwayland_view => |xwayland_view| xwayland_view.xwayland_surface.title, .none => unreachable, }; } @@ -559,8 +558,9 @@ pub fn getTitle(view: View) ?[*:0]const u8 { pub fn getAppId(view: View) ?[*:0]const u8 { assert(!view.destroying); return switch (view.impl) { - .toplevel => |toplevel| toplevel.getAppId(), - .xwayland_view => |xwayland_view| xwayland_view.getAppId(), + .toplevel => |toplevel| toplevel.wlr_toplevel.app_id, + // X11 clients don't have an app_id but the class serves a similar role. + .xwayland_view => |xwayland_view| xwayland_view.xwayland_surface.class, .none => unreachable, }; } diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index 3e28933..b307f26 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -194,25 +194,6 @@ pub fn configure(toplevel: *XdgToplevel) bool { return true; } -pub fn rootSurface(toplevel: XdgToplevel) *wlr.Surface { - return toplevel.wlr_toplevel.base.surface; -} - -/// Close the view. This will lead to the unmap and destroy events being sent -pub fn close(toplevel: XdgToplevel) void { - toplevel.wlr_toplevel.sendClose(); -} - -/// Return the current title of the toplevel if any. -pub fn getTitle(toplevel: XdgToplevel) ?[*:0]const u8 { - return toplevel.wlr_toplevel.title; -} - -/// Return the current app_id of the toplevel if any . -pub fn getAppId(toplevel: XdgToplevel) ?[*:0]const u8 { - return toplevel.wlr_toplevel.app_id; -} - pub fn destroyPopups(toplevel: XdgToplevel) void { var it = toplevel.wlr_toplevel.base.popups.safeIterator(.forward); while (it.next()) |wlr_xdg_popup| wlr_xdg_popup.destroy(); diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index 57bcb58..9aa5b63 100644 --- a/river/XwaylandView.zig +++ b/river/XwaylandView.zig @@ -119,15 +119,6 @@ pub fn configure(xwayland_view: XwaylandView) bool { return false; } -pub fn rootSurface(xwayland_view: XwaylandView) *wlr.Surface { - return xwayland_view.xwayland_surface.surface.?; -} - -/// Close the view. This will lead to the unmap and destroy events being sent -pub fn close(xwayland_view: XwaylandView) void { - xwayland_view.xwayland_surface.close(); -} - fn setActivated(xwayland_view: XwaylandView, activated: bool) void { // See comment on handleRequestMinimize() for details if (activated and xwayland_view.xwayland_surface.minimized) { @@ -139,16 +130,6 @@ fn setActivated(xwayland_view: XwaylandView, activated: bool) void { } } -/// Get the current title of the xwayland surface if any. -pub fn getTitle(xwayland_view: XwaylandView) ?[*:0]const u8 { - return xwayland_view.xwayland_surface.title; -} -/// X11 clients don't have an app_id but the class serves a similar role. -/// Get the current class of the xwayland surface if any. -pub fn getAppId(xwayland_view: XwaylandView) ?[*:0]const u8 { - return xwayland_view.xwayland_surface.class; -} - fn handleDestroy(listener: *wl.Listener(void)) void { const xwayland_view = @fieldParentPtr(XwaylandView, "destroy", listener);