Skip to content

Commit f541570

Browse files
committed
Allow extracting the Surface used to construct a Window or Popup.
Wayland allows reusing a surface for the same role it had previously.
1 parent 8a0b336 commit f541570

File tree

5 files changed

+89
-23
lines changed

5 files changed

+89
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
- Add `Clone` for dmabuf feedback structs.
2525
- Implement `AsFd` for `RawPool`.
2626
- Implement `From<RawPool>` for `OwnedFd`.
27+
- Add method to destroy a Window or Popup and extract the underlying Surface.
2728

2829
## 0.19.2 - 2024-07-15
2930

src/shell/xdg/mod.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl XdgShell {
105105
qh,
106106
WindowData(weak.clone()),
107107
);
108-
let xdg_surface = XdgShellSurface { surface, xdg_surface };
108+
let xdg_surface = XdgShellSurface { surface: Some(surface), xdg_surface };
109109
let xdg_toplevel = xdg_surface.xdg_surface().get_toplevel(qh, WindowData(weak.clone()));
110110

111111
// If server side decorations are available, create the toplevel decoration.
@@ -138,11 +138,11 @@ impl XdgShell {
138138
}
139139
});
140140

141-
WindowInner {
141+
WindowInner::new(
142142
xdg_surface,
143143
xdg_toplevel,
144144
toplevel_decoration,
145-
pending_configure: Mutex::new(WindowConfigure {
145+
Mutex::new(WindowConfigure {
146146
new_size: (None, None),
147147
suggested_bounds: None,
148148
// Initial configure will indicate whether there are server side decorations.
@@ -151,7 +151,7 @@ impl XdgShell {
151151
// XXX by default we assume that everything is supported.
152152
capabilities: WindowManagerCapabilities::all(),
153153
}),
154-
}
154+
)
155155
});
156156

157157
// Explicitly drop the queue freeze to allow the queue to resume work.
@@ -221,7 +221,9 @@ impl wayland_client::backend::ObjectData for PositionerData {
221221
#[derive(Debug)]
222222
pub struct XdgShellSurface {
223223
xdg_surface: xdg_surface::XdgSurface,
224-
surface: Surface,
224+
// Will always be Some, only needed to extract surface in destroy before
225+
// drop.
226+
surface: Option<Surface>,
225227
}
226228

227229
impl XdgShellSurface {
@@ -258,15 +260,19 @@ impl XdgShellSurface {
258260
let surface = surface.into();
259261
let xdg_surface = wm_base.bound_global()?.get_xdg_surface(surface.wl_surface(), qh, udata);
260262

261-
Ok(XdgShellSurface { xdg_surface, surface })
263+
Ok(XdgShellSurface { xdg_surface, surface: Some(surface) })
262264
}
263265

264266
pub fn xdg_surface(&self) -> &xdg_surface::XdgSurface {
265267
&self.xdg_surface
266268
}
267269

268270
pub fn wl_surface(&self) -> &wl_surface::WlSurface {
269-
self.surface.wl_surface()
271+
self.surface.as_ref().unwrap().wl_surface()
272+
}
273+
274+
pub fn destroy(mut self) -> Surface {
275+
self.surface.take().unwrap()
270276
}
271277
}
272278

src/shell/xdg/popup.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,26 @@ pub struct PopupData {
3333

3434
#[derive(Debug)]
3535
struct PopupInner {
36-
surface: XdgShellSurface,
36+
// Will always be Some, only needed to extract surface in destroy before
37+
// drop.
38+
surface: Option<XdgShellSurface>,
3739
xdg_popup: xdg_popup::XdgPopup,
3840
pending_position: (AtomicI32, AtomicI32),
3941
pending_dimensions: (AtomicI32, AtomicI32),
4042
pending_token: AtomicU32,
4143
configure_state: AtomicU32,
4244
}
4345

46+
impl PopupInner {
47+
pub fn surface(&self) -> &XdgShellSurface {
48+
&self.surface.as_ref().unwrap()
49+
}
50+
51+
pub fn destroy(mut self) -> XdgShellSurface {
52+
self.surface.take().unwrap()
53+
}
54+
}
55+
4456
impl Popup {
4557
/// Create a new popup.
4658
///
@@ -96,7 +108,7 @@ impl Popup {
96108
qh,
97109
PopupData { inner: weak.clone() },
98110
);
99-
let surface = XdgShellSurface { surface, xdg_surface };
111+
let surface = XdgShellSurface { surface: Some(surface), xdg_surface };
100112
let xdg_popup = surface.xdg_surface().get_popup(
101113
parent,
102114
position,
@@ -105,7 +117,7 @@ impl Popup {
105117
);
106118

107119
PopupInner {
108-
surface,
120+
surface: Some(surface),
109121
xdg_popup,
110122
pending_position: (AtomicI32::new(0), AtomicI32::new(0)),
111123
pending_dimensions: (AtomicI32::new(-1), AtomicI32::new(-1)),
@@ -122,20 +134,30 @@ impl Popup {
122134
}
123135

124136
pub fn xdg_shell_surface(&self) -> &XdgShellSurface {
125-
&self.inner.surface
137+
&self.inner.surface()
126138
}
127139

128140
pub fn xdg_surface(&self) -> &xdg_surface::XdgSurface {
129-
self.inner.surface.xdg_surface()
141+
self.inner.surface().xdg_surface()
130142
}
131143

132144
pub fn wl_surface(&self) -> &wl_surface::WlSurface {
133-
self.inner.surface.wl_surface()
145+
self.inner.surface().wl_surface()
134146
}
135147

136148
pub fn reposition(&self, position: &xdg_positioner::XdgPositioner, token: u32) {
137149
self.xdg_popup().reposition(position, token);
138150
}
151+
152+
/// Destroy the popup and extract the underlying surface. Note that reusing
153+
/// the surface for anything other than another xdg popup is a protocol
154+
/// violation, and that the buffer attached to the surface must be cleared
155+
/// before reuse as an xdg surface cannot have a buffer attached to it.
156+
pub fn destroy(self) -> Surface {
157+
// Should never panic because the only other Arc reference is a weak
158+
// reference.
159+
Arc::into_inner(self.inner).unwrap().destroy().destroy()
160+
}
139161
}
140162

141163
impl PopupData {

src/shell/xdg/window/inner.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,40 @@ use super::{
2727
WindowState,
2828
};
2929

30+
#[derive(Debug)]
31+
pub struct WindowInner {
32+
// Will always be Some, only needed to extract xdg_surface in destroy before
33+
// drop.
34+
xdg_surface: Option<XdgShellSurface>,
35+
pub xdg_toplevel: xdg_toplevel::XdgToplevel,
36+
pub toplevel_decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
37+
pub pending_configure: Mutex<WindowConfigure>,
38+
}
39+
40+
impl WindowInner {
41+
pub fn new(
42+
xdg_surface: XdgShellSurface,
43+
xdg_toplevel: xdg_toplevel::XdgToplevel,
44+
toplevel_decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
45+
pending_configure: Mutex<WindowConfigure>,
46+
) -> Self {
47+
Self {
48+
xdg_surface: Some(xdg_surface),
49+
xdg_toplevel,
50+
toplevel_decoration,
51+
pending_configure,
52+
}
53+
}
54+
55+
pub fn xdg_surface(&self) -> &XdgShellSurface {
56+
&self.xdg_surface.as_ref().unwrap()
57+
}
58+
59+
pub fn destroy(mut self) -> XdgShellSurface {
60+
self.xdg_surface.take().unwrap()
61+
}
62+
}
63+
3064
impl Drop for WindowInner {
3165
fn drop(&mut self) {
3266
// XDG decoration says we must destroy the decoration object before the toplevel
@@ -41,14 +75,6 @@ impl Drop for WindowInner {
4175
}
4276
}
4377

44-
#[derive(Debug)]
45-
pub struct WindowInner {
46-
pub xdg_surface: XdgShellSurface,
47-
pub xdg_toplevel: xdg_toplevel::XdgToplevel,
48-
pub toplevel_decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
49-
pub pending_configure: Mutex<WindowConfigure>,
50-
}
51-
5278
impl ProvidesBoundGlobal<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, 1> for XdgShell {
5379
fn bound_global(
5480
&self,

src/shell/xdg/window/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::reexports::protocols::{
1515
xdg::shell::client::{xdg_surface, xdg_toplevel},
1616
};
1717

18+
use crate::compositor::Surface;
1819
use crate::shell::WaylandSurface;
1920

2021
use self::inner::WindowInner;
@@ -285,17 +286,27 @@ impl Window {
285286
pub fn xdg_toplevel(&self) -> &xdg_toplevel::XdgToplevel {
286287
&self.0.xdg_toplevel
287288
}
289+
290+
/// Destroy the window and extract the underlying surface. Note that reusing
291+
/// the surface for anything other than another xdg toplevel is a protocol
292+
/// violation, and that the buffer attached to the surface must be cleared
293+
/// before reuse as an xdg surface cannot have a buffer attached to it.
294+
pub fn destroy(self) -> Surface {
295+
// Should never panic because the only other Arc reference is a weak
296+
// reference.
297+
Arc::into_inner(self.0).unwrap().destroy().destroy()
298+
}
288299
}
289300

290301
impl WaylandSurface for Window {
291302
fn wl_surface(&self) -> &wl_surface::WlSurface {
292-
self.0.xdg_surface.wl_surface()
303+
self.0.xdg_surface().wl_surface()
293304
}
294305
}
295306

296307
impl XdgSurface for Window {
297308
fn xdg_surface(&self) -> &xdg_surface::XdgSurface {
298-
self.0.xdg_surface.xdg_surface()
309+
self.0.xdg_surface().xdg_surface()
299310
}
300311
}
301312

0 commit comments

Comments
 (0)