wl_proxy/protocols/wayland/
wl_shell.rs

1//! create desktop-style surfaces
2//!
3//! This interface is implemented by servers that provide
4//! desktop-style user interfaces.
5//!
6//! It allows clients to associate a wl_shell_surface with
7//! a basic surface.
8//!
9//! Note! This protocol is deprecated and not intended for production use.
10//! For desktop-style user interfaces, use xdg_shell. Compositors and clients
11//! should not implement this interface.
12
13use crate::protocol_helpers::prelude::*;
14use super::super::all_types::*;
15
16/// A wl_shell object.
17///
18/// See the documentation of [the module][self] for the interface description.
19pub struct WlShell {
20    core: ObjectCore,
21    handler: HandlerHolder<dyn WlShellHandler>,
22}
23
24struct DefaultHandler;
25
26impl WlShellHandler for DefaultHandler { }
27
28impl ConcreteObject for WlShell {
29    const XML_VERSION: u32 = 1;
30    const INTERFACE: ObjectInterface = ObjectInterface::WlShell;
31    const INTERFACE_NAME: &str = "wl_shell";
32}
33
34impl WlShell {
35    /// Sets a new handler.
36    pub fn set_handler(&self, handler: impl WlShellHandler) {
37        self.set_boxed_handler(Box::new(handler));
38    }
39
40    /// Sets a new, already boxed handler.
41    pub fn set_boxed_handler(&self, handler: Box<dyn WlShellHandler>) {
42        if self.core.state.destroyed.get() {
43            return;
44        }
45        self.handler.set(Some(handler));
46    }
47}
48
49impl Debug for WlShell {
50    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
51        f.debug_struct("WlShell")
52            .field("server_obj_id", &self.core.server_obj_id.get())
53            .field("client_id", &self.core.client_id.get())
54            .field("client_obj_id", &self.core.client_obj_id.get())
55            .finish()
56    }
57}
58
59impl WlShell {
60    /// Since when the get_shell_surface message is available.
61    pub const MSG__GET_SHELL_SURFACE__SINCE: u32 = 1;
62
63    /// create a shell surface from a surface
64    ///
65    /// Create a shell surface for an existing surface. This gives
66    /// the wl_surface the role of a shell surface. If the wl_surface
67    /// already has another role, it raises a protocol error.
68    ///
69    /// Only one shell surface can be associated with a given surface.
70    ///
71    /// # Arguments
72    ///
73    /// - `id`: shell surface to create
74    /// - `surface`: surface to be given the shell surface role
75    #[inline]
76    pub fn try_send_get_shell_surface(
77        &self,
78        id: &Rc<WlShellSurface>,
79        surface: &Rc<WlSurface>,
80    ) -> Result<(), ObjectError> {
81        let (
82            arg0,
83            arg1,
84        ) = (
85            id,
86            surface,
87        );
88        let arg0_obj = arg0;
89        let arg0 = arg0_obj.core();
90        let arg1 = arg1.core();
91        let core = self.core();
92        let Some(id) = core.server_obj_id.get() else {
93            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
94        };
95        let arg1_id = match arg1.server_obj_id.get() {
96            None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("surface"))),
97            Some(id) => id,
98        };
99        arg0.generate_server_id(arg0_obj.clone())
100            .map_err(|e| ObjectError(ObjectErrorKind::GenerateServerId("id", e)))?;
101        let arg0_id = arg0.server_obj_id.get().unwrap_or(0);
102        #[cfg(feature = "logging")]
103        if self.core.state.log {
104            #[cold]
105            fn log(state: &State, id: u32, arg0: u32, arg1: u32) {
106                let (millis, micros) = time_since_epoch();
107                let prefix = &state.log_prefix;
108                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell#{}.get_shell_surface(id: wl_shell_surface#{}, surface: wl_surface#{})\n", id, arg0, arg1);
109                state.log(args);
110            }
111            log(&self.core.state, id, arg0_id, arg1_id);
112        }
113        let Some(endpoint) = &self.core.state.server else {
114            return Ok(());
115        };
116        if !endpoint.flush_queued.replace(true) {
117            self.core.state.add_flushable_endpoint(endpoint, None);
118        }
119        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
120        let outgoing = &mut *outgoing_ref;
121        let mut fmt = outgoing.formatter();
122        fmt.words([
123            id,
124            0,
125            arg0_id,
126            arg1_id,
127        ]);
128        Ok(())
129    }
130
131    /// create a shell surface from a surface
132    ///
133    /// Create a shell surface for an existing surface. This gives
134    /// the wl_surface the role of a shell surface. If the wl_surface
135    /// already has another role, it raises a protocol error.
136    ///
137    /// Only one shell surface can be associated with a given surface.
138    ///
139    /// # Arguments
140    ///
141    /// - `id`: shell surface to create
142    /// - `surface`: surface to be given the shell surface role
143    #[inline]
144    pub fn send_get_shell_surface(
145        &self,
146        id: &Rc<WlShellSurface>,
147        surface: &Rc<WlSurface>,
148    ) {
149        let res = self.try_send_get_shell_surface(
150            id,
151            surface,
152        );
153        if let Err(e) = res {
154            log_send("wl_shell.get_shell_surface", &e);
155        }
156    }
157
158    /// create a shell surface from a surface
159    ///
160    /// Create a shell surface for an existing surface. This gives
161    /// the wl_surface the role of a shell surface. If the wl_surface
162    /// already has another role, it raises a protocol error.
163    ///
164    /// Only one shell surface can be associated with a given surface.
165    ///
166    /// # Arguments
167    ///
168    /// - `surface`: surface to be given the shell surface role
169    #[inline]
170    pub fn new_try_send_get_shell_surface(
171        &self,
172        surface: &Rc<WlSurface>,
173    ) -> Result<Rc<WlShellSurface>, ObjectError> {
174        let id = self.core.create_child();
175        self.try_send_get_shell_surface(
176            &id,
177            surface,
178        )?;
179        Ok(id)
180    }
181
182    /// create a shell surface from a surface
183    ///
184    /// Create a shell surface for an existing surface. This gives
185    /// the wl_surface the role of a shell surface. If the wl_surface
186    /// already has another role, it raises a protocol error.
187    ///
188    /// Only one shell surface can be associated with a given surface.
189    ///
190    /// # Arguments
191    ///
192    /// - `surface`: surface to be given the shell surface role
193    #[inline]
194    pub fn new_send_get_shell_surface(
195        &self,
196        surface: &Rc<WlSurface>,
197    ) -> Rc<WlShellSurface> {
198        let id = self.core.create_child();
199        self.send_get_shell_surface(
200            &id,
201            surface,
202        );
203        id
204    }
205}
206
207/// A message handler for [`WlShell`] proxies.
208pub trait WlShellHandler: Any {
209    /// Event handler for wl_display.delete_id messages deleting the ID of this object.
210    ///
211    /// The default handler forwards the event to the client, if any.
212    #[inline]
213    fn delete_id(&mut self, slf: &Rc<WlShell>) {
214        slf.core.delete_id();
215    }
216
217    /// create a shell surface from a surface
218    ///
219    /// Create a shell surface for an existing surface. This gives
220    /// the wl_surface the role of a shell surface. If the wl_surface
221    /// already has another role, it raises a protocol error.
222    ///
223    /// Only one shell surface can be associated with a given surface.
224    ///
225    /// # Arguments
226    ///
227    /// - `id`: shell surface to create
228    /// - `surface`: surface to be given the shell surface role
229    ///
230    /// All borrowed proxies passed to this function are guaranteed to be
231    /// immutable and non-null.
232    #[inline]
233    fn handle_get_shell_surface(
234        &mut self,
235        slf: &Rc<WlShell>,
236        id: &Rc<WlShellSurface>,
237        surface: &Rc<WlSurface>,
238    ) {
239        if !slf.core.forward_to_server.get() {
240            return;
241        }
242        let res = slf.try_send_get_shell_surface(
243            id,
244            surface,
245        );
246        if let Err(e) = res {
247            log_forward("wl_shell.get_shell_surface", &e);
248        }
249    }
250}
251
252impl ObjectPrivate for WlShell {
253    fn new(state: &Rc<State>, version: u32) -> Rc<Self> {
254        Rc::<Self>::new_cyclic(|slf| Self {
255            core: ObjectCore::new(state, slf.clone(), ObjectInterface::WlShell, version),
256            handler: Default::default(),
257        })
258    }
259
260    fn delete_id(self: Rc<Self>) -> Result<(), (ObjectError, Rc<dyn Object>)> {
261        let Some(mut handler) = self.handler.try_borrow_mut() else {
262            return Err((ObjectError(ObjectErrorKind::HandlerBorrowed), self));
263        };
264        if let Some(handler) = &mut *handler {
265            handler.delete_id(&self);
266        } else {
267            self.core.delete_id();
268        }
269        Ok(())
270    }
271
272    fn handle_request(self: Rc<Self>, client: &Rc<Client>, msg: &[u32], fds: &mut VecDeque<Rc<OwnedFd>>) -> Result<(), ObjectError> {
273        let Some(mut handler) = self.handler.try_borrow_mut() else {
274            return Err(ObjectError(ObjectErrorKind::HandlerBorrowed));
275        };
276        let handler = &mut *handler;
277        match msg[1] & 0xffff {
278            0 => {
279                let [
280                    arg0,
281                    arg1,
282                ] = msg[2..] else {
283                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 16)));
284                };
285                #[cfg(feature = "logging")]
286                if self.core.state.log {
287                    #[cold]
288                    fn log(state: &State, client_id: u64, id: u32, arg0: u32, arg1: u32) {
289                        let (millis, micros) = time_since_epoch();
290                        let prefix = &state.log_prefix;
291                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell#{}.get_shell_surface(id: wl_shell_surface#{}, surface: wl_surface#{})\n", client_id, id, arg0, arg1);
292                        state.log(args);
293                    }
294                    log(&self.core.state, client.endpoint.id, msg[0], arg0, arg1);
295                }
296                let arg0_id = arg0;
297                let arg0 = WlShellSurface::new(&self.core.state, self.core.version);
298                arg0.core().set_client_id(client, arg0_id, arg0.clone())
299                    .map_err(|e| ObjectError(ObjectErrorKind::SetClientId(arg0_id, "id", e)))?;
300                let arg1_id = arg1;
301                let Some(arg1) = client.endpoint.lookup(arg1_id) else {
302                    return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg1_id)));
303                };
304                let Ok(arg1) = (arg1 as Rc<dyn Any>).downcast::<WlSurface>() else {
305                    let o = client.endpoint.lookup(arg1_id).unwrap();
306                    return Err(ObjectError(ObjectErrorKind::WrongObjectType("surface", o.core().interface, ObjectInterface::WlSurface)));
307                };
308                let arg0 = &arg0;
309                let arg1 = &arg1;
310                if let Some(handler) = handler {
311                    (**handler).handle_get_shell_surface(&self, arg0, arg1);
312                } else {
313                    DefaultHandler.handle_get_shell_surface(&self, arg0, arg1);
314                }
315            }
316            n => {
317                let _ = client;
318                let _ = msg;
319                let _ = fds;
320                let _ = handler;
321                return Err(ObjectError(ObjectErrorKind::UnknownMessageId(n)));
322            }
323        }
324        Ok(())
325    }
326
327    fn handle_event(self: Rc<Self>, server: &Endpoint, msg: &[u32], fds: &mut VecDeque<Rc<OwnedFd>>) -> Result<(), ObjectError> {
328        let Some(mut handler) = self.handler.try_borrow_mut() else {
329            return Err(ObjectError(ObjectErrorKind::HandlerBorrowed));
330        };
331        let handler = &mut *handler;
332        match msg[1] & 0xffff {
333            n => {
334                let _ = server;
335                let _ = msg;
336                let _ = fds;
337                let _ = handler;
338                return Err(ObjectError(ObjectErrorKind::UnknownMessageId(n)));
339            }
340        }
341    }
342
343    fn get_request_name(&self, id: u32) -> Option<&'static str> {
344        let name = match id {
345            0 => "get_shell_surface",
346            _ => return None,
347        };
348        Some(name)
349    }
350
351    fn get_event_name(&self, id: u32) -> Option<&'static str> {
352        let _ = id;
353        None
354    }
355}
356
357impl Object for WlShell {
358    fn core(&self) -> &ObjectCore {
359        &self.core
360    }
361
362    fn unset_handler(&self) {
363        self.handler.set(None);
364    }
365
366    fn get_handler_any_ref(&self) -> Result<HandlerRef<'_, dyn Any>, HandlerAccessError> {
367        let borrowed = self.handler.try_borrow().ok_or(HandlerAccessError::AlreadyBorrowed)?;
368        if borrowed.is_none() {
369            return Err(HandlerAccessError::NoHandler);
370        }
371        Ok(HandlerRef::map(borrowed, |handler| &**handler.as_ref().unwrap() as &dyn Any))
372    }
373
374    fn get_handler_any_mut(&self) -> Result<HandlerMut<'_, dyn Any>, HandlerAccessError> {
375        let borrowed = self.handler.try_borrow_mut().ok_or(HandlerAccessError::AlreadyBorrowed)?;
376        if borrowed.is_none() {
377            return Err(HandlerAccessError::NoHandler);
378        }
379        Ok(HandlerMut::map(borrowed, |handler| &mut **handler.as_mut().unwrap() as &mut dyn Any))
380    }
381}
382
383impl WlShell {
384    /// Since when the error.role enum variant is available.
385    pub const ENM__ERROR_ROLE__SINCE: u32 = 1;
386}
387
388#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
389pub struct WlShellError(pub u32);
390
391impl WlShellError {
392    /// given wl_surface has another role
393    pub const ROLE: Self = Self(0);
394}
395
396impl Debug for WlShellError {
397    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
398        let name = match *self {
399            Self::ROLE => "ROLE",
400            _ => return Debug::fmt(&self.0, f),
401        };
402        f.write_str(name)
403    }
404}