smithay_client_toolkit/shell/xdg/window/
inner.rs1use std::{
2 convert::{TryFrom, TryInto},
3 num::NonZeroU32,
4 sync::Mutex,
5};
6
7use wayland_client::{Connection, QueueHandle};
8use wayland_protocols::{
9 xdg::decoration::zv1::client::{
10 zxdg_decoration_manager_v1,
11 zxdg_toplevel_decoration_v1::{self, Mode},
12 },
13 xdg::shell::client::{
14 xdg_surface,
15 xdg_toplevel::{self, State, WmCapabilities},
16 },
17};
18
19use crate::{
20 dispatch2::Dispatch2,
21 error::GlobalError,
22 globals::{GlobalData, ProvidesBoundGlobal},
23 shell::xdg::{XdgShell, XdgShellSurface},
24};
25
26use super::{
27 DecorationMode, Window, WindowConfigure, WindowData, WindowHandler, WindowManagerCapabilities,
28 WindowState,
29};
30
31impl Drop for WindowInner {
32 fn drop(&mut self) {
33 if let Some(toplevel_decoration) = self.toplevel_decoration.as_ref() {
35 toplevel_decoration.destroy();
36 }
37
38 self.xdg_toplevel.destroy();
40 }
43}
44
45#[derive(Debug)]
46pub struct WindowInner {
47 pub xdg_surface: XdgShellSurface,
48 pub xdg_toplevel: xdg_toplevel::XdgToplevel,
49 pub toplevel_decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
50 pub pending_configure: Mutex<WindowConfigure>,
51}
52
53impl ProvidesBoundGlobal<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, 1> for XdgShell {
54 fn bound_global(
55 &self,
56 ) -> Result<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, GlobalError> {
57 self.xdg_decoration_manager.get().cloned()
58 }
59}
60
61impl<D> Dispatch2<xdg_surface::XdgSurface, D> for WindowData
62where
63 D: WindowHandler,
64{
65 fn event(
66 &self,
67 data: &mut D,
68 xdg_surface: &xdg_surface::XdgSurface,
69 event: xdg_surface::Event,
70 conn: &Connection,
71 qh: &QueueHandle<D>,
72 ) {
73 if let Some(window) = Window::from_xdg_surface(xdg_surface) {
74 match event {
75 xdg_surface::Event::Configure { serial } => {
76 xdg_surface.ack_configure(serial);
78
79 let configure = { window.0.pending_configure.lock().unwrap().clone() };
80 WindowHandler::configure(data, conn, qh, &window, configure, serial);
81 }
82
83 _ => unreachable!(),
84 }
85 }
86 }
87}
88
89pub(crate) fn determine_window_state(states: &[u8]) -> WindowState {
90 states
93 .chunks_exact(4)
94 .flat_map(TryInto::<[u8; 4]>::try_into)
95 .map(u32::from_ne_bytes)
96 .flat_map(State::try_from)
97 .fold(WindowState::empty(), |mut acc, state| {
98 match state {
99 State::Maximized => acc.set(WindowState::MAXIMIZED, true),
100 State::Fullscreen => acc.set(WindowState::FULLSCREEN, true),
101 State::Resizing => acc.set(WindowState::RESIZING, true),
102 State::Activated => acc.set(WindowState::ACTIVATED, true),
103 State::TiledLeft => acc.set(WindowState::TILED_LEFT, true),
104 State::TiledRight => acc.set(WindowState::TILED_RIGHT, true),
105 State::TiledTop => acc.set(WindowState::TILED_TOP, true),
106 State::TiledBottom => acc.set(WindowState::TILED_BOTTOM, true),
107 State::Suspended => acc.set(WindowState::SUSPENDED, true),
108 _ => (),
109 }
110 acc
111 })
112}
113
114pub(crate) fn determine_wm_capabilities(capabilities: &[u8]) -> WindowManagerCapabilities {
115 capabilities
116 .chunks_exact(4)
117 .flat_map(TryInto::<[u8; 4]>::try_into)
118 .map(u32::from_ne_bytes)
119 .flat_map(WmCapabilities::try_from)
120 .fold(WindowManagerCapabilities::empty(), |mut acc, capability| {
121 match capability {
122 WmCapabilities::WindowMenu => acc.set(WindowManagerCapabilities::WINDOW_MENU, true),
123 WmCapabilities::Maximize => acc.set(WindowManagerCapabilities::MAXIMIZE, true),
124 WmCapabilities::Fullscreen => acc.set(WindowManagerCapabilities::FULLSCREEN, true),
125 WmCapabilities::Minimize => acc.set(WindowManagerCapabilities::MINIMIZE, true),
126 _ => (),
127 }
128 acc
129 })
130}
131
132pub(crate) fn determine_decoration_mode(mode: Mode) -> DecorationMode {
133 match mode {
134 Mode::ClientSide => DecorationMode::Client,
135 Mode::ServerSide => DecorationMode::Server,
136
137 _ => unreachable!(),
138 }
139}
140
141impl<D> Dispatch2<xdg_toplevel::XdgToplevel, D> for WindowData
142where
143 D: WindowHandler,
144{
145 fn event(
146 &self,
147 data: &mut D,
148 toplevel: &xdg_toplevel::XdgToplevel,
149 event: xdg_toplevel::Event,
150 conn: &Connection,
151 qh: &QueueHandle<D>,
152 ) {
153 if let Some(window) = Window::from_xdg_toplevel(toplevel) {
154 match event {
155 xdg_toplevel::Event::Configure { width, height, states } => {
156 let new_state = determine_window_state(&states);
157
158 let width = u32::try_from(width).ok().and_then(NonZeroU32::new);
161 let height = u32::try_from(height).ok().and_then(NonZeroU32::new);
162
163 let pending_configure = &mut window.0.pending_configure.lock().unwrap();
164 pending_configure.new_size = (width, height);
165 pending_configure.state = new_state;
166 }
167
168 xdg_toplevel::Event::Close => {
169 data.request_close(conn, qh, &window);
170 }
171
172 xdg_toplevel::Event::ConfigureBounds { width, height } => {
173 let pending_configure = &mut window.0.pending_configure.lock().unwrap();
174 if width == 0 && height == 0 {
175 pending_configure.suggested_bounds = None;
176 } else {
177 pending_configure.suggested_bounds = Some((width as u32, height as u32));
178 }
179 }
180 xdg_toplevel::Event::WmCapabilities { capabilities } => {
181 let pending_configure = &mut window.0.pending_configure.lock().unwrap();
182 pending_configure.capabilities = determine_wm_capabilities(&capabilities)
183 }
184 _ => unreachable!(),
185 }
186 }
187 }
188}
189
190impl<D> Dispatch2<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, D> for GlobalData
193where
194 D: WindowHandler,
195{
196 fn event(
197 &self,
198 _: &mut D,
199 _: &zxdg_decoration_manager_v1::ZxdgDecorationManagerV1,
200 _: zxdg_decoration_manager_v1::Event,
201 _: &Connection,
202 _: &QueueHandle<D>,
203 ) {
204 unreachable!("zxdg_decoration_manager_v1 has no events")
205 }
206}
207
208impl<D> Dispatch2<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, D> for WindowData
209where
210 D: WindowHandler,
211{
212 fn event(
213 &self,
214 _: &mut D,
215 decoration: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
216 event: zxdg_toplevel_decoration_v1::Event,
217 _: &Connection,
218 _: &QueueHandle<D>,
219 ) {
220 if let Some(window) = Window::from_toplevel_decoration(decoration) {
221 match event {
222 zxdg_toplevel_decoration_v1::Event::Configure { mode } => match mode {
223 wayland_client::WEnum::Value(mode) => {
224 let mode = determine_decoration_mode(mode);
225 window.0.pending_configure.lock().unwrap().decoration_mode = mode;
226 }
227
228 wayland_client::WEnum::Unknown(unknown) => {
229 log::error!(target: "sctk", "unknown decoration mode 0x{:x}", unknown);
230 }
231 },
232
233 _ => unreachable!(),
234 }
235 }
236 }
237}