From d4922eb10b708682c19dd68e521895133df6153d Mon Sep 17 00:00:00 2001 From: apricotbucket28 <71973804+apricotbucket28@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:02:05 -0300 Subject: [PATCH] wayland: Fix window close (#10702) Partially fixes https://github.com/zed-industries/zed/issues/10483 (X11 still has this issue) Also adds some missing destroy() calls for some objects. Thanks @phisch! Release Notes: - N/A --- .../gpui/src/platform/linux/wayland/client.rs | 32 +++++++++--- .../gpui/src/platform/linux/wayland/window.rs | 49 +++++++++++++------ 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index bf287956a4991b3f4d84878c4f30fdc97d4e2685..1eb438795fa0c3f08a87db688658afd7b41c5a60 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -118,8 +118,8 @@ pub(crate) struct WaylandClientState { loop_handle: LoopHandle<'static, WaylandClientStatePtr>, cursor_icon_name: String, cursor: Cursor, - clipboard: Clipboard, - primary: Primary, + clipboard: Option, + primary: Option, event_loop: Option>, common: LinuxCommon, } @@ -163,6 +163,12 @@ impl WaylandClientStatePtr { state.mouse_focused_window = Some(window); } } + if state.windows.is_empty() { + // Drop the clipboard to prevent a seg fault after we've closed all Wayland connections. + state.clipboard = None; + state.primary = None; + state.common.signal.stop(); + } } } @@ -278,8 +284,8 @@ impl WaylandClient { cursor_icon_name: "arrow".to_string(), enter_token: None, cursor, - clipboard, - primary, + clipboard: Some(clipboard), + primary: Some(primary), event_loop: Some(event_loop), })); @@ -378,17 +384,29 @@ impl LinuxClient for WaylandClient { } fn write_to_primary(&self, item: crate::ClipboardItem) { - self.0.borrow_mut().primary.set_contents(item.text); + self.0 + .borrow_mut() + .primary + .as_mut() + .unwrap() + .set_contents(item.text); } fn write_to_clipboard(&self, item: crate::ClipboardItem) { - self.0.borrow_mut().clipboard.set_contents(item.text); + self.0 + .borrow_mut() + .clipboard + .as_mut() + .unwrap() + .set_contents(item.text); } fn read_from_primary(&self) -> Option { self.0 .borrow_mut() .primary + .as_mut() + .unwrap() .get_contents() .ok() .map(|s| crate::ClipboardItem { @@ -401,6 +419,8 @@ impl LinuxClient for WaylandClient { self.0 .borrow_mut() .clipboard + .as_mut() + .unwrap() .get_contents() .ok() .map(|s| crate::ClipboardItem { diff --git a/crates/gpui/src/platform/linux/wayland/window.rs b/crates/gpui/src/platform/linux/wayland/window.rs index 41bbd09e7e806312c4028af13f9072e39247763c..56f2b876b8ada06395ce373d4330b4d2af9f4fe0 100644 --- a/crates/gpui/src/platform/linux/wayland/window.rs +++ b/crates/gpui/src/platform/linux/wayland/window.rs @@ -68,6 +68,7 @@ unsafe impl HasRawDisplayHandle for RawWindow { pub struct WaylandWindowState { xdg_surface: xdg_surface::XdgSurface, pub surface: wl_surface::WlSurface, + decoration: Option, toplevel: xdg_toplevel::XdgToplevel, viewport: Option, outputs: HashSet, @@ -90,11 +91,13 @@ pub struct WaylandWindowStatePtr { } impl WaylandWindowState { + #[allow(clippy::too_many_arguments)] pub(crate) fn new( surface: wl_surface::WlSurface, xdg_surface: xdg_surface::XdgSurface, - viewport: Option, toplevel: xdg_toplevel::XdgToplevel, + decoration: Option, + viewport: Option, client: WaylandClientStatePtr, globals: Globals, options: WindowParams, @@ -132,6 +135,7 @@ impl WaylandWindowState { Self { xdg_surface, surface, + decoration, toplevel, viewport, globals, @@ -158,16 +162,27 @@ impl Drop for WaylandWindow { let mut state = self.0.state.borrow_mut(); let surface_id = state.surface.id(); let client = state.client.clone(); + state.renderer.destroy(); + if let Some(decoration) = &state.decoration { + decoration.destroy(); + } state.toplevel.destroy(); + if let Some(viewport) = &state.viewport { + viewport.destroy(); + } state.xdg_surface.destroy(); state.surface.destroy(); let state_ptr = self.0.clone(); - state.globals.executor.spawn(async move { - state_ptr.close(); - client.drop_window(&surface_id) - }); + state + .globals + .executor + .spawn(async move { + state_ptr.close(); + client.drop_window(&surface_id) + }) + .detach(); drop(state); } } @@ -197,13 +212,18 @@ impl WaylandWindow { } // Attempt to set up window decorations based on the requested configuration - if let Some(decoration_manager) = globals.decoration_manager.as_ref() { - let decoration = - decoration_manager.get_toplevel_decoration(&toplevel, &globals.qh, surface.id()); - - // Request client side decorations if possible - decoration.set_mode(zxdg_toplevel_decoration_v1::Mode::ClientSide); - } + let decoration = globals + .decoration_manager + .as_ref() + .map(|decoration_manager| { + let decoration = decoration_manager.get_toplevel_decoration( + &toplevel, + &globals.qh, + surface.id(), + ); + decoration.set_mode(zxdg_toplevel_decoration_v1::Mode::ClientSide); + decoration + }); let viewport = globals .viewporter @@ -216,8 +236,9 @@ impl WaylandWindow { state: Rc::new(RefCell::new(WaylandWindowState::new( surface.clone(), xdg_surface, - viewport, toplevel, + decoration, + viewport, client, globals, params, @@ -319,7 +340,7 @@ impl WaylandWindowStatePtr { } result } else { - false + true } } _ => false,