From 15b6b678c1303b6ace3af47d21abb2df1d583824 Mon Sep 17 00:00:00 2001 From: mikairyuu Date: Fri, 9 Jan 2026 17:23:58 +0900 Subject: [PATCH] fix(shell): distinguish between unmapping and destroying surfaces Previously, `unmap_surface` automatically pushed all unmapped windows into the `pending_windows` list. This behavior is correct for X11 windows (which may be remapped) but incorrect for Wayland `toplevel_destroyed` events, where the role is permanently gone. This caused issues with clients like Telegram that reuse `wl_surface`s. Because the destroyed toplevel remained in `pending_windows`, a subsequent cleanup commit (e.g., null buffer) triggered a configure event. This prematurely marked the surface as `configured` in the shell state. Consequently, when the client attached a new `xdg_toplevel` role, the compositor skipped the mandatory initial configure event (assuming it was already done), causing the window to never appear. This refactors `unmap_surface` to return `Option` instead of mutating global state. - XWayland: Explicitly saves the pending window (behavior preserved). - XDG Shell: Drops the pending window, preventing ghost state interactions. Fixes #1816 --- src/shell/mod.rs | 8 +++++--- src/wayland/handlers/xdg_shell/mod.rs | 2 +- src/xwayland.rs | 6 +++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index f385dc07..95a60c7b 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2832,7 +2832,8 @@ impl Shell { surface: &S, seat: &Seat, toplevel_info: &mut ToplevelInfoState, - ) where + ) -> Option + where CosmicSurface: PartialEq, { for set in self.workspaces.sets.values_mut() { @@ -2890,15 +2891,16 @@ impl Shell { if let Some(surface) = surface { toplevel_info.remove_toplevel(&surface); - self.pending_windows.push(PendingWindow { + return Some(PendingWindow { surface, seat: seat.clone(), fullscreen: None, maximized: false, }); - return; } } + + None } pub fn move_current( diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index 56efd92e..43e6a46d 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -321,7 +321,7 @@ impl XdgShellHandler for State { let output = shell .visible_output_for_surface(surface.wl_surface()) .cloned(); - shell.unmap_surface( + let _ = shell.unmap_surface( surface.wl_surface(), &seat, &mut self.common.toplevel_info_state, diff --git a/src/xwayland.rs b/src/xwayland.rs index 9f65445c..2cd789de 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -873,7 +873,11 @@ impl XwmHandler for State { shell.override_redirect_windows.retain(|or| or != &window); } else { let seat = shell.seats.last_active().clone(); - shell.unmap_surface(&window, &seat, &mut self.common.toplevel_info_state); + if let Some(pending) = + shell.unmap_surface(&window, &seat, &mut self.common.toplevel_info_state) + { + shell.pending_windows.push(pending); + } } let outputs = if let Some(wl_surface) = window.wl_surface() {