diff --git a/src/shell/xdg/mod.rs b/src/shell/xdg/mod.rs index 5e5a07703..21d45f4f0 100644 --- a/src/shell/xdg/mod.rs +++ b/src/shell/xdg/mod.rs @@ -105,7 +105,7 @@ impl XdgShell { qh, WindowData(weak.clone()), ); - let xdg_surface = XdgShellSurface { surface, xdg_surface }; + let xdg_surface = XdgShellSurface { surface: Some(surface), xdg_surface }; let xdg_toplevel = xdg_surface.xdg_surface().get_toplevel(qh, WindowData(weak.clone())); // If server side decorations are available, create the toplevel decoration. @@ -138,11 +138,11 @@ impl XdgShell { } }); - WindowInner { + WindowInner::new( xdg_surface, xdg_toplevel, toplevel_decoration, - pending_configure: Mutex::new(WindowConfigure { + Mutex::new(WindowConfigure { new_size: (None, None), suggested_bounds: None, // Initial configure will indicate whether there are server side decorations. @@ -151,7 +151,7 @@ impl XdgShell { // XXX by default we assume that everything is supported. capabilities: WindowManagerCapabilities::all(), }), - } + ) }); // Explicitly drop the queue freeze to allow the queue to resume work. @@ -221,7 +221,9 @@ impl wayland_client::backend::ObjectData for PositionerData { #[derive(Debug)] pub struct XdgShellSurface { xdg_surface: xdg_surface::XdgSurface, - surface: Surface, + // Will always be Some, only needed to extract surface in destroy before + // drop. + surface: Option, } impl XdgShellSurface { @@ -258,7 +260,7 @@ impl XdgShellSurface { let surface = surface.into(); let xdg_surface = wm_base.bound_global()?.get_xdg_surface(surface.wl_surface(), qh, udata); - Ok(XdgShellSurface { xdg_surface, surface }) + Ok(XdgShellSurface { xdg_surface, surface: Some(surface) }) } pub fn xdg_surface(&self) -> &xdg_surface::XdgSurface { @@ -266,7 +268,11 @@ impl XdgShellSurface { } pub fn wl_surface(&self) -> &wl_surface::WlSurface { - self.surface.wl_surface() + self.surface.as_ref().unwrap().wl_surface() + } + + pub fn destroy(mut self) -> Surface { + self.surface.take().unwrap() } } diff --git a/src/shell/xdg/popup.rs b/src/shell/xdg/popup.rs index ef78c40b7..fee0dc098 100644 --- a/src/shell/xdg/popup.rs +++ b/src/shell/xdg/popup.rs @@ -33,7 +33,9 @@ pub struct PopupData { #[derive(Debug)] struct PopupInner { - surface: XdgShellSurface, + // Will always be Some, only needed to extract surface in destroy before + // drop. + surface: Option, xdg_popup: xdg_popup::XdgPopup, pending_position: (AtomicI32, AtomicI32), pending_dimensions: (AtomicI32, AtomicI32), @@ -41,6 +43,16 @@ struct PopupInner { configure_state: AtomicU32, } +impl PopupInner { + pub fn surface(&self) -> &XdgShellSurface { + &self.surface.as_ref().unwrap() + } + + pub fn destroy(mut self) -> XdgShellSurface { + self.surface.take().unwrap() + } +} + impl Popup { /// Create a new popup. /// @@ -96,7 +108,7 @@ impl Popup { qh, PopupData { inner: weak.clone() }, ); - let surface = XdgShellSurface { surface, xdg_surface }; + let surface = XdgShellSurface { surface: Some(surface), xdg_surface }; let xdg_popup = surface.xdg_surface().get_popup( parent, position, @@ -105,7 +117,7 @@ impl Popup { ); PopupInner { - surface, + surface: Some(surface), xdg_popup, pending_position: (AtomicI32::new(0), AtomicI32::new(0)), pending_dimensions: (AtomicI32::new(-1), AtomicI32::new(-1)), @@ -122,20 +134,30 @@ impl Popup { } pub fn xdg_shell_surface(&self) -> &XdgShellSurface { - &self.inner.surface + &self.inner.surface() } pub fn xdg_surface(&self) -> &xdg_surface::XdgSurface { - self.inner.surface.xdg_surface() + self.inner.surface().xdg_surface() } pub fn wl_surface(&self) -> &wl_surface::WlSurface { - self.inner.surface.wl_surface() + self.inner.surface().wl_surface() } pub fn reposition(&self, position: &xdg_positioner::XdgPositioner, token: u32) { self.xdg_popup().reposition(position, token); } + + /// Destroy the popup and extract the underlying surface. Note that reusing + /// the surface for anything other than another xdg popup is a protocol + /// violation, and that the buffer attached to the surface must be cleared + /// before reuse as an xdg surface cannot have a buffer attached to it. + pub fn destroy(self) -> Surface { + // Should never panic because the only other Arc reference is a weak + // reference. + Arc::into_inner(self.inner).unwrap().destroy().destroy() + } } impl PopupData { diff --git a/src/shell/xdg/window/inner.rs b/src/shell/xdg/window/inner.rs index ed2f4d13f..05c660a35 100644 --- a/src/shell/xdg/window/inner.rs +++ b/src/shell/xdg/window/inner.rs @@ -27,6 +27,40 @@ use super::{ WindowState, }; +#[derive(Debug)] +pub struct WindowInner { + // Will always be Some, only needed to extract xdg_surface in destroy before + // drop. + xdg_surface: Option, + pub xdg_toplevel: xdg_toplevel::XdgToplevel, + pub toplevel_decoration: Option, + pub pending_configure: Mutex, +} + +impl WindowInner { + pub fn new( + xdg_surface: XdgShellSurface, + xdg_toplevel: xdg_toplevel::XdgToplevel, + toplevel_decoration: Option, + pending_configure: Mutex, + ) -> Self { + Self { + xdg_surface: Some(xdg_surface), + xdg_toplevel, + toplevel_decoration, + pending_configure, + } + } + + pub fn xdg_surface(&self) -> &XdgShellSurface { + &self.xdg_surface.as_ref().unwrap() + } + + pub fn destroy(mut self) -> XdgShellSurface { + self.xdg_surface.take().unwrap() + } +} + impl Drop for WindowInner { fn drop(&mut self) { // XDG decoration says we must destroy the decoration object before the toplevel @@ -41,14 +75,6 @@ impl Drop for WindowInner { } } -#[derive(Debug)] -pub struct WindowInner { - pub xdg_surface: XdgShellSurface, - pub xdg_toplevel: xdg_toplevel::XdgToplevel, - pub toplevel_decoration: Option, - pub pending_configure: Mutex, -} - impl ProvidesBoundGlobal for XdgShell { fn bound_global( &self, diff --git a/src/shell/xdg/window/mod.rs b/src/shell/xdg/window/mod.rs index 31eda58b5..bec1dab38 100644 --- a/src/shell/xdg/window/mod.rs +++ b/src/shell/xdg/window/mod.rs @@ -15,6 +15,7 @@ use crate::reexports::protocols::{ xdg::shell::client::{xdg_surface, xdg_toplevel}, }; +use crate::compositor::Surface; use crate::shell::WaylandSurface; use self::inner::WindowInner; @@ -285,17 +286,27 @@ impl Window { pub fn xdg_toplevel(&self) -> &xdg_toplevel::XdgToplevel { &self.0.xdg_toplevel } + + /// Destroy the window and extract the underlying surface. Note that reusing + /// the surface for anything other than another xdg toplevel is a protocol + /// violation, and that the buffer attached to the surface must be cleared + /// before reuse as an xdg surface cannot have a buffer attached to it. + pub fn destroy(self) -> Surface { + // Should never panic because the only other Arc reference is a weak + // reference. + Arc::into_inner(self.0).unwrap().destroy().destroy() + } } impl WaylandSurface for Window { fn wl_surface(&self) -> &wl_surface::WlSurface { - self.0.xdg_surface.wl_surface() + self.0.xdg_surface().wl_surface() } } impl XdgSurface for Window { fn xdg_surface(&self) -> &xdg_surface::XdgSurface { - self.0.xdg_surface.xdg_surface() + self.0.xdg_surface().xdg_surface() } }