wl_proxy/protocols/wayland/
wl_shell_surface.rs

1//! desktop-style metadata interface
2//!
3//! An interface that may be implemented by a wl_surface, for
4//! implementations that provide a desktop-style user interface.
5//!
6//! It provides requests to treat surfaces like toplevel, fullscreen
7//! or popup windows, move, resize or maximize them, associate
8//! metadata like title and class, etc.
9//!
10//! On the server side the object is automatically destroyed when
11//! the related wl_surface is destroyed. On the client side,
12//! wl_shell_surface_destroy() must be called before destroying
13//! the wl_surface object.
14
15use crate::protocol_helpers::prelude::*;
16use super::super::all_types::*;
17
18/// A wl_shell_surface object.
19///
20/// See the documentation of [the module][self] for the interface description.
21pub struct WlShellSurface {
22    core: ObjectCore,
23    handler: HandlerHolder<dyn WlShellSurfaceHandler>,
24}
25
26struct DefaultHandler;
27
28impl WlShellSurfaceHandler for DefaultHandler { }
29
30impl ConcreteObject for WlShellSurface {
31    const XML_VERSION: u32 = 1;
32    const INTERFACE: ObjectInterface = ObjectInterface::WlShellSurface;
33    const INTERFACE_NAME: &str = "wl_shell_surface";
34}
35
36impl WlShellSurface {
37    /// Sets a new handler.
38    pub fn set_handler(&self, handler: impl WlShellSurfaceHandler) {
39        self.set_boxed_handler(Box::new(handler));
40    }
41
42    /// Sets a new, already boxed handler.
43    pub fn set_boxed_handler(&self, handler: Box<dyn WlShellSurfaceHandler>) {
44        if self.core.state.destroyed.get() {
45            return;
46        }
47        self.handler.set(Some(handler));
48    }
49}
50
51impl Debug for WlShellSurface {
52    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
53        f.debug_struct("WlShellSurface")
54            .field("server_obj_id", &self.core.server_obj_id.get())
55            .field("client_id", &self.core.client_id.get())
56            .field("client_obj_id", &self.core.client_obj_id.get())
57            .finish()
58    }
59}
60
61impl WlShellSurface {
62    /// Since when the pong message is available.
63    pub const MSG__PONG__SINCE: u32 = 1;
64
65    /// respond to a ping event
66    ///
67    /// A client must respond to a ping event with a pong request or
68    /// the client may be deemed unresponsive.
69    ///
70    /// # Arguments
71    ///
72    /// - `serial`: serial number of the ping event
73    #[inline]
74    pub fn try_send_pong(
75        &self,
76        serial: u32,
77    ) -> Result<(), ObjectError> {
78        let (
79            arg0,
80        ) = (
81            serial,
82        );
83        let core = self.core();
84        let Some(id) = core.server_obj_id.get() else {
85            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
86        };
87        #[cfg(feature = "logging")]
88        if self.core.state.log {
89            #[cold]
90            fn log(state: &State, id: u32, arg0: u32) {
91                let (millis, micros) = time_since_epoch();
92                let prefix = &state.log_prefix;
93                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.pong(serial: {})\n", id, arg0);
94                state.log(args);
95            }
96            log(&self.core.state, id, arg0);
97        }
98        let Some(endpoint) = &self.core.state.server else {
99            return Ok(());
100        };
101        if !endpoint.flush_queued.replace(true) {
102            self.core.state.add_flushable_endpoint(endpoint, None);
103        }
104        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
105        let outgoing = &mut *outgoing_ref;
106        let mut fmt = outgoing.formatter();
107        fmt.words([
108            id,
109            0,
110            arg0,
111        ]);
112        Ok(())
113    }
114
115    /// respond to a ping event
116    ///
117    /// A client must respond to a ping event with a pong request or
118    /// the client may be deemed unresponsive.
119    ///
120    /// # Arguments
121    ///
122    /// - `serial`: serial number of the ping event
123    #[inline]
124    pub fn send_pong(
125        &self,
126        serial: u32,
127    ) {
128        let res = self.try_send_pong(
129            serial,
130        );
131        if let Err(e) = res {
132            log_send("wl_shell_surface.pong", &e);
133        }
134    }
135
136    /// Since when the move message is available.
137    pub const MSG__MOVE__SINCE: u32 = 1;
138
139    /// start an interactive move
140    ///
141    /// Start a pointer-driven move of the surface.
142    ///
143    /// This request must be used in response to a button press event.
144    /// The server may ignore move requests depending on the state of
145    /// the surface (e.g. fullscreen or maximized).
146    ///
147    /// # Arguments
148    ///
149    /// - `seat`: seat whose pointer is used
150    /// - `serial`: serial number of the implicit grab on the pointer
151    #[inline]
152    pub fn try_send_move(
153        &self,
154        seat: &Rc<WlSeat>,
155        serial: u32,
156    ) -> Result<(), ObjectError> {
157        let (
158            arg0,
159            arg1,
160        ) = (
161            seat,
162            serial,
163        );
164        let arg0 = arg0.core();
165        let core = self.core();
166        let Some(id) = core.server_obj_id.get() else {
167            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
168        };
169        let arg0_id = match arg0.server_obj_id.get() {
170            None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("seat"))),
171            Some(id) => id,
172        };
173        #[cfg(feature = "logging")]
174        if self.core.state.log {
175            #[cold]
176            fn log(state: &State, id: u32, arg0: u32, arg1: u32) {
177                let (millis, micros) = time_since_epoch();
178                let prefix = &state.log_prefix;
179                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.move(seat: wl_seat#{}, serial: {})\n", id, arg0, arg1);
180                state.log(args);
181            }
182            log(&self.core.state, id, arg0_id, arg1);
183        }
184        let Some(endpoint) = &self.core.state.server else {
185            return Ok(());
186        };
187        if !endpoint.flush_queued.replace(true) {
188            self.core.state.add_flushable_endpoint(endpoint, None);
189        }
190        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
191        let outgoing = &mut *outgoing_ref;
192        let mut fmt = outgoing.formatter();
193        fmt.words([
194            id,
195            1,
196            arg0_id,
197            arg1,
198        ]);
199        Ok(())
200    }
201
202    /// start an interactive move
203    ///
204    /// Start a pointer-driven move of the surface.
205    ///
206    /// This request must be used in response to a button press event.
207    /// The server may ignore move requests depending on the state of
208    /// the surface (e.g. fullscreen or maximized).
209    ///
210    /// # Arguments
211    ///
212    /// - `seat`: seat whose pointer is used
213    /// - `serial`: serial number of the implicit grab on the pointer
214    #[inline]
215    pub fn send_move(
216        &self,
217        seat: &Rc<WlSeat>,
218        serial: u32,
219    ) {
220        let res = self.try_send_move(
221            seat,
222            serial,
223        );
224        if let Err(e) = res {
225            log_send("wl_shell_surface.move", &e);
226        }
227    }
228
229    /// Since when the resize message is available.
230    pub const MSG__RESIZE__SINCE: u32 = 1;
231
232    /// start an interactive resize
233    ///
234    /// Start a pointer-driven resizing of the surface.
235    ///
236    /// This request must be used in response to a button press event.
237    /// The server may ignore resize requests depending on the state of
238    /// the surface (e.g. fullscreen or maximized).
239    ///
240    /// # Arguments
241    ///
242    /// - `seat`: seat whose pointer is used
243    /// - `serial`: serial number of the implicit grab on the pointer
244    /// - `edges`: which edge or corner is being dragged
245    #[inline]
246    pub fn try_send_resize(
247        &self,
248        seat: &Rc<WlSeat>,
249        serial: u32,
250        edges: WlShellSurfaceResize,
251    ) -> Result<(), ObjectError> {
252        let (
253            arg0,
254            arg1,
255            arg2,
256        ) = (
257            seat,
258            serial,
259            edges,
260        );
261        let arg0 = arg0.core();
262        let core = self.core();
263        let Some(id) = core.server_obj_id.get() else {
264            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
265        };
266        let arg0_id = match arg0.server_obj_id.get() {
267            None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("seat"))),
268            Some(id) => id,
269        };
270        #[cfg(feature = "logging")]
271        if self.core.state.log {
272            #[cold]
273            fn log(state: &State, id: u32, arg0: u32, arg1: u32, arg2: WlShellSurfaceResize) {
274                let (millis, micros) = time_since_epoch();
275                let prefix = &state.log_prefix;
276                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.resize(seat: wl_seat#{}, serial: {}, edges: {:?})\n", id, arg0, arg1, arg2);
277                state.log(args);
278            }
279            log(&self.core.state, id, arg0_id, arg1, arg2);
280        }
281        let Some(endpoint) = &self.core.state.server else {
282            return Ok(());
283        };
284        if !endpoint.flush_queued.replace(true) {
285            self.core.state.add_flushable_endpoint(endpoint, None);
286        }
287        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
288        let outgoing = &mut *outgoing_ref;
289        let mut fmt = outgoing.formatter();
290        fmt.words([
291            id,
292            2,
293            arg0_id,
294            arg1,
295            arg2.0,
296        ]);
297        Ok(())
298    }
299
300    /// start an interactive resize
301    ///
302    /// Start a pointer-driven resizing of the surface.
303    ///
304    /// This request must be used in response to a button press event.
305    /// The server may ignore resize requests depending on the state of
306    /// the surface (e.g. fullscreen or maximized).
307    ///
308    /// # Arguments
309    ///
310    /// - `seat`: seat whose pointer is used
311    /// - `serial`: serial number of the implicit grab on the pointer
312    /// - `edges`: which edge or corner is being dragged
313    #[inline]
314    pub fn send_resize(
315        &self,
316        seat: &Rc<WlSeat>,
317        serial: u32,
318        edges: WlShellSurfaceResize,
319    ) {
320        let res = self.try_send_resize(
321            seat,
322            serial,
323            edges,
324        );
325        if let Err(e) = res {
326            log_send("wl_shell_surface.resize", &e);
327        }
328    }
329
330    /// Since when the set_toplevel message is available.
331    pub const MSG__SET_TOPLEVEL__SINCE: u32 = 1;
332
333    /// make the surface a toplevel surface
334    ///
335    /// Map the surface as a toplevel surface.
336    ///
337    /// A toplevel surface is not fullscreen, maximized or transient.
338    #[inline]
339    pub fn try_send_set_toplevel(
340        &self,
341    ) -> Result<(), ObjectError> {
342        let core = self.core();
343        let Some(id) = core.server_obj_id.get() else {
344            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
345        };
346        #[cfg(feature = "logging")]
347        if self.core.state.log {
348            #[cold]
349            fn log(state: &State, id: u32) {
350                let (millis, micros) = time_since_epoch();
351                let prefix = &state.log_prefix;
352                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_toplevel()\n", id);
353                state.log(args);
354            }
355            log(&self.core.state, id);
356        }
357        let Some(endpoint) = &self.core.state.server else {
358            return Ok(());
359        };
360        if !endpoint.flush_queued.replace(true) {
361            self.core.state.add_flushable_endpoint(endpoint, None);
362        }
363        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
364        let outgoing = &mut *outgoing_ref;
365        let mut fmt = outgoing.formatter();
366        fmt.words([
367            id,
368            3,
369        ]);
370        Ok(())
371    }
372
373    /// make the surface a toplevel surface
374    ///
375    /// Map the surface as a toplevel surface.
376    ///
377    /// A toplevel surface is not fullscreen, maximized or transient.
378    #[inline]
379    pub fn send_set_toplevel(
380        &self,
381    ) {
382        let res = self.try_send_set_toplevel(
383        );
384        if let Err(e) = res {
385            log_send("wl_shell_surface.set_toplevel", &e);
386        }
387    }
388
389    /// Since when the set_transient message is available.
390    pub const MSG__SET_TRANSIENT__SINCE: u32 = 1;
391
392    /// make the surface a transient surface
393    ///
394    /// Map the surface relative to an existing surface.
395    ///
396    /// The x and y arguments specify the location of the upper left
397    /// corner of the surface relative to the upper left corner of the
398    /// parent surface, in surface-local coordinates.
399    ///
400    /// The flags argument controls details of the transient behaviour.
401    ///
402    /// # Arguments
403    ///
404    /// - `parent`: parent surface
405    /// - `x`: surface-local x coordinate
406    /// - `y`: surface-local y coordinate
407    /// - `flags`: transient surface behavior
408    #[inline]
409    pub fn try_send_set_transient(
410        &self,
411        parent: &Rc<WlSurface>,
412        x: i32,
413        y: i32,
414        flags: WlShellSurfaceTransient,
415    ) -> Result<(), ObjectError> {
416        let (
417            arg0,
418            arg1,
419            arg2,
420            arg3,
421        ) = (
422            parent,
423            x,
424            y,
425            flags,
426        );
427        let arg0 = arg0.core();
428        let core = self.core();
429        let Some(id) = core.server_obj_id.get() else {
430            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
431        };
432        let arg0_id = match arg0.server_obj_id.get() {
433            None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("parent"))),
434            Some(id) => id,
435        };
436        #[cfg(feature = "logging")]
437        if self.core.state.log {
438            #[cold]
439            fn log(state: &State, id: u32, arg0: u32, arg1: i32, arg2: i32, arg3: WlShellSurfaceTransient) {
440                let (millis, micros) = time_since_epoch();
441                let prefix = &state.log_prefix;
442                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_transient(parent: wl_surface#{}, x: {}, y: {}, flags: {:?})\n", id, arg0, arg1, arg2, arg3);
443                state.log(args);
444            }
445            log(&self.core.state, id, arg0_id, arg1, arg2, arg3);
446        }
447        let Some(endpoint) = &self.core.state.server else {
448            return Ok(());
449        };
450        if !endpoint.flush_queued.replace(true) {
451            self.core.state.add_flushable_endpoint(endpoint, None);
452        }
453        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
454        let outgoing = &mut *outgoing_ref;
455        let mut fmt = outgoing.formatter();
456        fmt.words([
457            id,
458            4,
459            arg0_id,
460            arg1 as u32,
461            arg2 as u32,
462            arg3.0,
463        ]);
464        Ok(())
465    }
466
467    /// make the surface a transient surface
468    ///
469    /// Map the surface relative to an existing surface.
470    ///
471    /// The x and y arguments specify the location of the upper left
472    /// corner of the surface relative to the upper left corner of the
473    /// parent surface, in surface-local coordinates.
474    ///
475    /// The flags argument controls details of the transient behaviour.
476    ///
477    /// # Arguments
478    ///
479    /// - `parent`: parent surface
480    /// - `x`: surface-local x coordinate
481    /// - `y`: surface-local y coordinate
482    /// - `flags`: transient surface behavior
483    #[inline]
484    pub fn send_set_transient(
485        &self,
486        parent: &Rc<WlSurface>,
487        x: i32,
488        y: i32,
489        flags: WlShellSurfaceTransient,
490    ) {
491        let res = self.try_send_set_transient(
492            parent,
493            x,
494            y,
495            flags,
496        );
497        if let Err(e) = res {
498            log_send("wl_shell_surface.set_transient", &e);
499        }
500    }
501
502    /// Since when the set_fullscreen message is available.
503    pub const MSG__SET_FULLSCREEN__SINCE: u32 = 1;
504
505    /// make the surface a fullscreen surface
506    ///
507    /// Map the surface as a fullscreen surface.
508    ///
509    /// If an output parameter is given then the surface will be made
510    /// fullscreen on that output. If the client does not specify the
511    /// output then the compositor will apply its policy - usually
512    /// choosing the output on which the surface has the biggest surface
513    /// area.
514    ///
515    /// The client may specify a method to resolve a size conflict
516    /// between the output size and the surface size - this is provided
517    /// through the method parameter.
518    ///
519    /// The framerate parameter is used only when the method is set
520    /// to "driver", to indicate the preferred framerate. A value of 0
521    /// indicates that the client does not care about framerate.  The
522    /// framerate is specified in mHz, that is framerate of 60000 is 60Hz.
523    ///
524    /// A method of "scale" or "driver" implies a scaling operation of
525    /// the surface, either via a direct scaling operation or a change of
526    /// the output mode. This will override any kind of output scaling, so
527    /// that mapping a surface with a buffer size equal to the mode can
528    /// fill the screen independent of buffer_scale.
529    ///
530    /// A method of "fill" means we don't scale up the buffer, however
531    /// any output scale is applied. This means that you may run into
532    /// an edge case where the application maps a buffer with the same
533    /// size of the output mode but buffer_scale 1 (thus making a
534    /// surface larger than the output). In this case it is allowed to
535    /// downscale the results to fit the screen.
536    ///
537    /// The compositor must reply to this request with a configure event
538    /// with the dimensions for the output on which the surface will
539    /// be made fullscreen.
540    ///
541    /// # Arguments
542    ///
543    /// - `method`: method for resolving size conflict
544    /// - `framerate`: framerate in mHz
545    /// - `output`: output on which the surface is to be fullscreen
546    #[inline]
547    pub fn try_send_set_fullscreen(
548        &self,
549        method: WlShellSurfaceFullscreenMethod,
550        framerate: u32,
551        output: Option<&Rc<WlOutput>>,
552    ) -> Result<(), ObjectError> {
553        let (
554            arg0,
555            arg1,
556            arg2,
557        ) = (
558            method,
559            framerate,
560            output,
561        );
562        let arg2 = arg2.map(|a| a.core());
563        let core = self.core();
564        let Some(id) = core.server_obj_id.get() else {
565            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
566        };
567        let arg2_id = match arg2 {
568            None => 0,
569            Some(arg2) => match arg2.server_obj_id.get() {
570                None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("output"))),
571                Some(id) => id,
572            },
573        };
574        #[cfg(feature = "logging")]
575        if self.core.state.log {
576            #[cold]
577            fn log(state: &State, id: u32, arg0: WlShellSurfaceFullscreenMethod, arg1: u32, arg2: u32) {
578                let (millis, micros) = time_since_epoch();
579                let prefix = &state.log_prefix;
580                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_fullscreen(method: {:?}, framerate: {}, output: wl_output#{})\n", id, arg0, arg1, arg2);
581                state.log(args);
582            }
583            log(&self.core.state, id, arg0, arg1, arg2_id);
584        }
585        let Some(endpoint) = &self.core.state.server else {
586            return Ok(());
587        };
588        if !endpoint.flush_queued.replace(true) {
589            self.core.state.add_flushable_endpoint(endpoint, None);
590        }
591        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
592        let outgoing = &mut *outgoing_ref;
593        let mut fmt = outgoing.formatter();
594        fmt.words([
595            id,
596            5,
597            arg0.0,
598            arg1,
599            arg2_id,
600        ]);
601        Ok(())
602    }
603
604    /// make the surface a fullscreen surface
605    ///
606    /// Map the surface as a fullscreen surface.
607    ///
608    /// If an output parameter is given then the surface will be made
609    /// fullscreen on that output. If the client does not specify the
610    /// output then the compositor will apply its policy - usually
611    /// choosing the output on which the surface has the biggest surface
612    /// area.
613    ///
614    /// The client may specify a method to resolve a size conflict
615    /// between the output size and the surface size - this is provided
616    /// through the method parameter.
617    ///
618    /// The framerate parameter is used only when the method is set
619    /// to "driver", to indicate the preferred framerate. A value of 0
620    /// indicates that the client does not care about framerate.  The
621    /// framerate is specified in mHz, that is framerate of 60000 is 60Hz.
622    ///
623    /// A method of "scale" or "driver" implies a scaling operation of
624    /// the surface, either via a direct scaling operation or a change of
625    /// the output mode. This will override any kind of output scaling, so
626    /// that mapping a surface with a buffer size equal to the mode can
627    /// fill the screen independent of buffer_scale.
628    ///
629    /// A method of "fill" means we don't scale up the buffer, however
630    /// any output scale is applied. This means that you may run into
631    /// an edge case where the application maps a buffer with the same
632    /// size of the output mode but buffer_scale 1 (thus making a
633    /// surface larger than the output). In this case it is allowed to
634    /// downscale the results to fit the screen.
635    ///
636    /// The compositor must reply to this request with a configure event
637    /// with the dimensions for the output on which the surface will
638    /// be made fullscreen.
639    ///
640    /// # Arguments
641    ///
642    /// - `method`: method for resolving size conflict
643    /// - `framerate`: framerate in mHz
644    /// - `output`: output on which the surface is to be fullscreen
645    #[inline]
646    pub fn send_set_fullscreen(
647        &self,
648        method: WlShellSurfaceFullscreenMethod,
649        framerate: u32,
650        output: Option<&Rc<WlOutput>>,
651    ) {
652        let res = self.try_send_set_fullscreen(
653            method,
654            framerate,
655            output,
656        );
657        if let Err(e) = res {
658            log_send("wl_shell_surface.set_fullscreen", &e);
659        }
660    }
661
662    /// Since when the set_popup message is available.
663    pub const MSG__SET_POPUP__SINCE: u32 = 1;
664
665    /// make the surface a popup surface
666    ///
667    /// Map the surface as a popup.
668    ///
669    /// A popup surface is a transient surface with an added pointer
670    /// grab.
671    ///
672    /// An existing implicit grab will be changed to owner-events mode,
673    /// and the popup grab will continue after the implicit grab ends
674    /// (i.e. releasing the mouse button does not cause the popup to
675    /// be unmapped).
676    ///
677    /// The popup grab continues until the window is destroyed or a
678    /// mouse button is pressed in any other client's window. A click
679    /// in any of the client's surfaces is reported as normal, however,
680    /// clicks in other clients' surfaces will be discarded and trigger
681    /// the callback.
682    ///
683    /// The x and y arguments specify the location of the upper left
684    /// corner of the surface relative to the upper left corner of the
685    /// parent surface, in surface-local coordinates.
686    ///
687    /// # Arguments
688    ///
689    /// - `seat`: seat whose pointer is used
690    /// - `serial`: serial number of the implicit grab on the pointer
691    /// - `parent`: parent surface
692    /// - `x`: surface-local x coordinate
693    /// - `y`: surface-local y coordinate
694    /// - `flags`: transient surface behavior
695    #[inline]
696    pub fn try_send_set_popup(
697        &self,
698        seat: &Rc<WlSeat>,
699        serial: u32,
700        parent: &Rc<WlSurface>,
701        x: i32,
702        y: i32,
703        flags: WlShellSurfaceTransient,
704    ) -> Result<(), ObjectError> {
705        let (
706            arg0,
707            arg1,
708            arg2,
709            arg3,
710            arg4,
711            arg5,
712        ) = (
713            seat,
714            serial,
715            parent,
716            x,
717            y,
718            flags,
719        );
720        let arg0 = arg0.core();
721        let arg2 = arg2.core();
722        let core = self.core();
723        let Some(id) = core.server_obj_id.get() else {
724            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
725        };
726        let arg0_id = match arg0.server_obj_id.get() {
727            None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("seat"))),
728            Some(id) => id,
729        };
730        let arg2_id = match arg2.server_obj_id.get() {
731            None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("parent"))),
732            Some(id) => id,
733        };
734        #[cfg(feature = "logging")]
735        if self.core.state.log {
736            #[cold]
737            fn log(state: &State, id: u32, arg0: u32, arg1: u32, arg2: u32, arg3: i32, arg4: i32, arg5: WlShellSurfaceTransient) {
738                let (millis, micros) = time_since_epoch();
739                let prefix = &state.log_prefix;
740                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_popup(seat: wl_seat#{}, serial: {}, parent: wl_surface#{}, x: {}, y: {}, flags: {:?})\n", id, arg0, arg1, arg2, arg3, arg4, arg5);
741                state.log(args);
742            }
743            log(&self.core.state, id, arg0_id, arg1, arg2_id, arg3, arg4, arg5);
744        }
745        let Some(endpoint) = &self.core.state.server else {
746            return Ok(());
747        };
748        if !endpoint.flush_queued.replace(true) {
749            self.core.state.add_flushable_endpoint(endpoint, None);
750        }
751        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
752        let outgoing = &mut *outgoing_ref;
753        let mut fmt = outgoing.formatter();
754        fmt.words([
755            id,
756            6,
757            arg0_id,
758            arg1,
759            arg2_id,
760            arg3 as u32,
761            arg4 as u32,
762            arg5.0,
763        ]);
764        Ok(())
765    }
766
767    /// make the surface a popup surface
768    ///
769    /// Map the surface as a popup.
770    ///
771    /// A popup surface is a transient surface with an added pointer
772    /// grab.
773    ///
774    /// An existing implicit grab will be changed to owner-events mode,
775    /// and the popup grab will continue after the implicit grab ends
776    /// (i.e. releasing the mouse button does not cause the popup to
777    /// be unmapped).
778    ///
779    /// The popup grab continues until the window is destroyed or a
780    /// mouse button is pressed in any other client's window. A click
781    /// in any of the client's surfaces is reported as normal, however,
782    /// clicks in other clients' surfaces will be discarded and trigger
783    /// the callback.
784    ///
785    /// The x and y arguments specify the location of the upper left
786    /// corner of the surface relative to the upper left corner of the
787    /// parent surface, in surface-local coordinates.
788    ///
789    /// # Arguments
790    ///
791    /// - `seat`: seat whose pointer is used
792    /// - `serial`: serial number of the implicit grab on the pointer
793    /// - `parent`: parent surface
794    /// - `x`: surface-local x coordinate
795    /// - `y`: surface-local y coordinate
796    /// - `flags`: transient surface behavior
797    #[inline]
798    pub fn send_set_popup(
799        &self,
800        seat: &Rc<WlSeat>,
801        serial: u32,
802        parent: &Rc<WlSurface>,
803        x: i32,
804        y: i32,
805        flags: WlShellSurfaceTransient,
806    ) {
807        let res = self.try_send_set_popup(
808            seat,
809            serial,
810            parent,
811            x,
812            y,
813            flags,
814        );
815        if let Err(e) = res {
816            log_send("wl_shell_surface.set_popup", &e);
817        }
818    }
819
820    /// Since when the set_maximized message is available.
821    pub const MSG__SET_MAXIMIZED__SINCE: u32 = 1;
822
823    /// make the surface a maximized surface
824    ///
825    /// Map the surface as a maximized surface.
826    ///
827    /// If an output parameter is given then the surface will be
828    /// maximized on that output. If the client does not specify the
829    /// output then the compositor will apply its policy - usually
830    /// choosing the output on which the surface has the biggest surface
831    /// area.
832    ///
833    /// The compositor will reply with a configure event telling
834    /// the expected new surface size. The operation is completed
835    /// on the next buffer attach to this surface.
836    ///
837    /// A maximized surface typically fills the entire output it is
838    /// bound to, except for desktop elements such as panels. This is
839    /// the main difference between a maximized shell surface and a
840    /// fullscreen shell surface.
841    ///
842    /// The details depend on the compositor implementation.
843    ///
844    /// # Arguments
845    ///
846    /// - `output`: output on which the surface is to be maximized
847    #[inline]
848    pub fn try_send_set_maximized(
849        &self,
850        output: Option<&Rc<WlOutput>>,
851    ) -> Result<(), ObjectError> {
852        let (
853            arg0,
854        ) = (
855            output,
856        );
857        let arg0 = arg0.map(|a| a.core());
858        let core = self.core();
859        let Some(id) = core.server_obj_id.get() else {
860            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
861        };
862        let arg0_id = match arg0 {
863            None => 0,
864            Some(arg0) => match arg0.server_obj_id.get() {
865                None => return Err(ObjectError(ObjectErrorKind::ArgNoServerId("output"))),
866                Some(id) => id,
867            },
868        };
869        #[cfg(feature = "logging")]
870        if self.core.state.log {
871            #[cold]
872            fn log(state: &State, id: u32, arg0: u32) {
873                let (millis, micros) = time_since_epoch();
874                let prefix = &state.log_prefix;
875                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_maximized(output: wl_output#{})\n", id, arg0);
876                state.log(args);
877            }
878            log(&self.core.state, id, arg0_id);
879        }
880        let Some(endpoint) = &self.core.state.server else {
881            return Ok(());
882        };
883        if !endpoint.flush_queued.replace(true) {
884            self.core.state.add_flushable_endpoint(endpoint, None);
885        }
886        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
887        let outgoing = &mut *outgoing_ref;
888        let mut fmt = outgoing.formatter();
889        fmt.words([
890            id,
891            7,
892            arg0_id,
893        ]);
894        Ok(())
895    }
896
897    /// make the surface a maximized surface
898    ///
899    /// Map the surface as a maximized surface.
900    ///
901    /// If an output parameter is given then the surface will be
902    /// maximized on that output. If the client does not specify the
903    /// output then the compositor will apply its policy - usually
904    /// choosing the output on which the surface has the biggest surface
905    /// area.
906    ///
907    /// The compositor will reply with a configure event telling
908    /// the expected new surface size. The operation is completed
909    /// on the next buffer attach to this surface.
910    ///
911    /// A maximized surface typically fills the entire output it is
912    /// bound to, except for desktop elements such as panels. This is
913    /// the main difference between a maximized shell surface and a
914    /// fullscreen shell surface.
915    ///
916    /// The details depend on the compositor implementation.
917    ///
918    /// # Arguments
919    ///
920    /// - `output`: output on which the surface is to be maximized
921    #[inline]
922    pub fn send_set_maximized(
923        &self,
924        output: Option<&Rc<WlOutput>>,
925    ) {
926        let res = self.try_send_set_maximized(
927            output,
928        );
929        if let Err(e) = res {
930            log_send("wl_shell_surface.set_maximized", &e);
931        }
932    }
933
934    /// Since when the set_title message is available.
935    pub const MSG__SET_TITLE__SINCE: u32 = 1;
936
937    /// set surface title
938    ///
939    /// Set a short title for the surface.
940    ///
941    /// This string may be used to identify the surface in a task bar,
942    /// window list, or other user interface elements provided by the
943    /// compositor.
944    ///
945    /// The string must be encoded in UTF-8.
946    ///
947    /// # Arguments
948    ///
949    /// - `title`: surface title
950    #[inline]
951    pub fn try_send_set_title(
952        &self,
953        title: &str,
954    ) -> Result<(), ObjectError> {
955        let (
956            arg0,
957        ) = (
958            title,
959        );
960        let core = self.core();
961        let Some(id) = core.server_obj_id.get() else {
962            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
963        };
964        #[cfg(feature = "logging")]
965        if self.core.state.log {
966            #[cold]
967            fn log(state: &State, id: u32, arg0: &str) {
968                let (millis, micros) = time_since_epoch();
969                let prefix = &state.log_prefix;
970                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_title(title: {:?})\n", id, arg0);
971                state.log(args);
972            }
973            log(&self.core.state, id, arg0);
974        }
975        let Some(endpoint) = &self.core.state.server else {
976            return Ok(());
977        };
978        if !endpoint.flush_queued.replace(true) {
979            self.core.state.add_flushable_endpoint(endpoint, None);
980        }
981        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
982        let outgoing = &mut *outgoing_ref;
983        let mut fmt = outgoing.formatter();
984        fmt.words([
985            id,
986            8,
987        ]);
988        fmt.string(arg0);
989        Ok(())
990    }
991
992    /// set surface title
993    ///
994    /// Set a short title for the surface.
995    ///
996    /// This string may be used to identify the surface in a task bar,
997    /// window list, or other user interface elements provided by the
998    /// compositor.
999    ///
1000    /// The string must be encoded in UTF-8.
1001    ///
1002    /// # Arguments
1003    ///
1004    /// - `title`: surface title
1005    #[inline]
1006    pub fn send_set_title(
1007        &self,
1008        title: &str,
1009    ) {
1010        let res = self.try_send_set_title(
1011            title,
1012        );
1013        if let Err(e) = res {
1014            log_send("wl_shell_surface.set_title", &e);
1015        }
1016    }
1017
1018    /// Since when the set_class message is available.
1019    pub const MSG__SET_CLASS__SINCE: u32 = 1;
1020
1021    /// set surface class
1022    ///
1023    /// Set a class for the surface.
1024    ///
1025    /// The surface class identifies the general class of applications
1026    /// to which the surface belongs. A common convention is to use the
1027    /// file name (or the full path if it is a non-standard location) of
1028    /// the application's .desktop file as the class.
1029    ///
1030    /// # Arguments
1031    ///
1032    /// - `class_`: surface class
1033    #[inline]
1034    pub fn try_send_set_class(
1035        &self,
1036        class_: &str,
1037    ) -> Result<(), ObjectError> {
1038        let (
1039            arg0,
1040        ) = (
1041            class_,
1042        );
1043        let core = self.core();
1044        let Some(id) = core.server_obj_id.get() else {
1045            return Err(ObjectError(ObjectErrorKind::ReceiverNoServerId));
1046        };
1047        #[cfg(feature = "logging")]
1048        if self.core.state.log {
1049            #[cold]
1050            fn log(state: &State, id: u32, arg0: &str) {
1051                let (millis, micros) = time_since_epoch();
1052                let prefix = &state.log_prefix;
1053                let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      <= wl_shell_surface#{}.set_class(class_: {:?})\n", id, arg0);
1054                state.log(args);
1055            }
1056            log(&self.core.state, id, arg0);
1057        }
1058        let Some(endpoint) = &self.core.state.server else {
1059            return Ok(());
1060        };
1061        if !endpoint.flush_queued.replace(true) {
1062            self.core.state.add_flushable_endpoint(endpoint, None);
1063        }
1064        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
1065        let outgoing = &mut *outgoing_ref;
1066        let mut fmt = outgoing.formatter();
1067        fmt.words([
1068            id,
1069            9,
1070        ]);
1071        fmt.string(arg0);
1072        Ok(())
1073    }
1074
1075    /// set surface class
1076    ///
1077    /// Set a class for the surface.
1078    ///
1079    /// The surface class identifies the general class of applications
1080    /// to which the surface belongs. A common convention is to use the
1081    /// file name (or the full path if it is a non-standard location) of
1082    /// the application's .desktop file as the class.
1083    ///
1084    /// # Arguments
1085    ///
1086    /// - `class_`: surface class
1087    #[inline]
1088    pub fn send_set_class(
1089        &self,
1090        class_: &str,
1091    ) {
1092        let res = self.try_send_set_class(
1093            class_,
1094        );
1095        if let Err(e) = res {
1096            log_send("wl_shell_surface.set_class", &e);
1097        }
1098    }
1099
1100    /// Since when the ping message is available.
1101    pub const MSG__PING__SINCE: u32 = 1;
1102
1103    /// ping client
1104    ///
1105    /// Ping a client to check if it is receiving events and sending
1106    /// requests. A client is expected to reply with a pong request.
1107    ///
1108    /// # Arguments
1109    ///
1110    /// - `serial`: serial number of the ping
1111    #[inline]
1112    pub fn try_send_ping(
1113        &self,
1114        serial: u32,
1115    ) -> Result<(), ObjectError> {
1116        let (
1117            arg0,
1118        ) = (
1119            serial,
1120        );
1121        let core = self.core();
1122        let client_ref = core.client.borrow();
1123        let Some(client) = &*client_ref else {
1124            return Err(ObjectError(ObjectErrorKind::ReceiverNoClient));
1125        };
1126        let id = core.client_obj_id.get().unwrap_or(0);
1127        #[cfg(feature = "logging")]
1128        if self.core.state.log {
1129            #[cold]
1130            fn log(state: &State, client_id: u64, id: u32, arg0: u32) {
1131                let (millis, micros) = time_since_epoch();
1132                let prefix = &state.log_prefix;
1133                let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} <= wl_shell_surface#{}.ping(serial: {})\n", client_id, id, arg0);
1134                state.log(args);
1135            }
1136            log(&self.core.state, client.endpoint.id, id, arg0);
1137        }
1138        let endpoint = &client.endpoint;
1139        if !endpoint.flush_queued.replace(true) {
1140            self.core.state.add_flushable_endpoint(endpoint, Some(client));
1141        }
1142        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
1143        let outgoing = &mut *outgoing_ref;
1144        let mut fmt = outgoing.formatter();
1145        fmt.words([
1146            id,
1147            0,
1148            arg0,
1149        ]);
1150        Ok(())
1151    }
1152
1153    /// ping client
1154    ///
1155    /// Ping a client to check if it is receiving events and sending
1156    /// requests. A client is expected to reply with a pong request.
1157    ///
1158    /// # Arguments
1159    ///
1160    /// - `serial`: serial number of the ping
1161    #[inline]
1162    pub fn send_ping(
1163        &self,
1164        serial: u32,
1165    ) {
1166        let res = self.try_send_ping(
1167            serial,
1168        );
1169        if let Err(e) = res {
1170            log_send("wl_shell_surface.ping", &e);
1171        }
1172    }
1173
1174    /// Since when the configure message is available.
1175    pub const MSG__CONFIGURE__SINCE: u32 = 1;
1176
1177    /// suggest resize
1178    ///
1179    /// The configure event asks the client to resize its surface.
1180    ///
1181    /// The size is a hint, in the sense that the client is free to
1182    /// ignore it if it doesn't resize, pick a smaller size (to
1183    /// satisfy aspect ratio or resize in steps of NxM pixels).
1184    ///
1185    /// The edges parameter provides a hint about how the surface
1186    /// was resized. The client may use this information to decide
1187    /// how to adjust its content to the new size (e.g. a scrolling
1188    /// area might adjust its content position to leave the viewable
1189    /// content unmoved).
1190    ///
1191    /// The client is free to dismiss all but the last configure
1192    /// event it received.
1193    ///
1194    /// The width and height arguments specify the size of the window
1195    /// in surface-local coordinates.
1196    ///
1197    /// # Arguments
1198    ///
1199    /// - `edges`: how the surface was resized
1200    /// - `width`: new width of the surface
1201    /// - `height`: new height of the surface
1202    #[inline]
1203    pub fn try_send_configure(
1204        &self,
1205        edges: WlShellSurfaceResize,
1206        width: i32,
1207        height: i32,
1208    ) -> Result<(), ObjectError> {
1209        let (
1210            arg0,
1211            arg1,
1212            arg2,
1213        ) = (
1214            edges,
1215            width,
1216            height,
1217        );
1218        let core = self.core();
1219        let client_ref = core.client.borrow();
1220        let Some(client) = &*client_ref else {
1221            return Err(ObjectError(ObjectErrorKind::ReceiverNoClient));
1222        };
1223        let id = core.client_obj_id.get().unwrap_or(0);
1224        #[cfg(feature = "logging")]
1225        if self.core.state.log {
1226            #[cold]
1227            fn log(state: &State, client_id: u64, id: u32, arg0: WlShellSurfaceResize, arg1: i32, arg2: i32) {
1228                let (millis, micros) = time_since_epoch();
1229                let prefix = &state.log_prefix;
1230                let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} <= wl_shell_surface#{}.configure(edges: {:?}, width: {}, height: {})\n", client_id, id, arg0, arg1, arg2);
1231                state.log(args);
1232            }
1233            log(&self.core.state, client.endpoint.id, id, arg0, arg1, arg2);
1234        }
1235        let endpoint = &client.endpoint;
1236        if !endpoint.flush_queued.replace(true) {
1237            self.core.state.add_flushable_endpoint(endpoint, Some(client));
1238        }
1239        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
1240        let outgoing = &mut *outgoing_ref;
1241        let mut fmt = outgoing.formatter();
1242        fmt.words([
1243            id,
1244            1,
1245            arg0.0,
1246            arg1 as u32,
1247            arg2 as u32,
1248        ]);
1249        Ok(())
1250    }
1251
1252    /// suggest resize
1253    ///
1254    /// The configure event asks the client to resize its surface.
1255    ///
1256    /// The size is a hint, in the sense that the client is free to
1257    /// ignore it if it doesn't resize, pick a smaller size (to
1258    /// satisfy aspect ratio or resize in steps of NxM pixels).
1259    ///
1260    /// The edges parameter provides a hint about how the surface
1261    /// was resized. The client may use this information to decide
1262    /// how to adjust its content to the new size (e.g. a scrolling
1263    /// area might adjust its content position to leave the viewable
1264    /// content unmoved).
1265    ///
1266    /// The client is free to dismiss all but the last configure
1267    /// event it received.
1268    ///
1269    /// The width and height arguments specify the size of the window
1270    /// in surface-local coordinates.
1271    ///
1272    /// # Arguments
1273    ///
1274    /// - `edges`: how the surface was resized
1275    /// - `width`: new width of the surface
1276    /// - `height`: new height of the surface
1277    #[inline]
1278    pub fn send_configure(
1279        &self,
1280        edges: WlShellSurfaceResize,
1281        width: i32,
1282        height: i32,
1283    ) {
1284        let res = self.try_send_configure(
1285            edges,
1286            width,
1287            height,
1288        );
1289        if let Err(e) = res {
1290            log_send("wl_shell_surface.configure", &e);
1291        }
1292    }
1293
1294    /// Since when the popup_done message is available.
1295    pub const MSG__POPUP_DONE__SINCE: u32 = 1;
1296
1297    /// popup interaction is done
1298    ///
1299    /// The popup_done event is sent out when a popup grab is broken,
1300    /// that is, when the user clicks a surface that doesn't belong
1301    /// to the client owning the popup surface.
1302    #[inline]
1303    pub fn try_send_popup_done(
1304        &self,
1305    ) -> Result<(), ObjectError> {
1306        let core = self.core();
1307        let client_ref = core.client.borrow();
1308        let Some(client) = &*client_ref else {
1309            return Err(ObjectError(ObjectErrorKind::ReceiverNoClient));
1310        };
1311        let id = core.client_obj_id.get().unwrap_or(0);
1312        #[cfg(feature = "logging")]
1313        if self.core.state.log {
1314            #[cold]
1315            fn log(state: &State, client_id: u64, id: u32) {
1316                let (millis, micros) = time_since_epoch();
1317                let prefix = &state.log_prefix;
1318                let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} <= wl_shell_surface#{}.popup_done()\n", client_id, id);
1319                state.log(args);
1320            }
1321            log(&self.core.state, client.endpoint.id, id);
1322        }
1323        let endpoint = &client.endpoint;
1324        if !endpoint.flush_queued.replace(true) {
1325            self.core.state.add_flushable_endpoint(endpoint, Some(client));
1326        }
1327        let mut outgoing_ref = endpoint.outgoing.borrow_mut();
1328        let outgoing = &mut *outgoing_ref;
1329        let mut fmt = outgoing.formatter();
1330        fmt.words([
1331            id,
1332            2,
1333        ]);
1334        Ok(())
1335    }
1336
1337    /// popup interaction is done
1338    ///
1339    /// The popup_done event is sent out when a popup grab is broken,
1340    /// that is, when the user clicks a surface that doesn't belong
1341    /// to the client owning the popup surface.
1342    #[inline]
1343    pub fn send_popup_done(
1344        &self,
1345    ) {
1346        let res = self.try_send_popup_done(
1347        );
1348        if let Err(e) = res {
1349            log_send("wl_shell_surface.popup_done", &e);
1350        }
1351    }
1352}
1353
1354/// A message handler for [`WlShellSurface`] proxies.
1355pub trait WlShellSurfaceHandler: Any {
1356    /// Event handler for wl_display.delete_id messages deleting the ID of this object.
1357    ///
1358    /// The default handler forwards the event to the client, if any.
1359    #[inline]
1360    fn delete_id(&mut self, slf: &Rc<WlShellSurface>) {
1361        slf.core.delete_id();
1362    }
1363
1364    /// respond to a ping event
1365    ///
1366    /// A client must respond to a ping event with a pong request or
1367    /// the client may be deemed unresponsive.
1368    ///
1369    /// # Arguments
1370    ///
1371    /// - `serial`: serial number of the ping event
1372    #[inline]
1373    fn handle_pong(
1374        &mut self,
1375        slf: &Rc<WlShellSurface>,
1376        serial: u32,
1377    ) {
1378        if !slf.core.forward_to_server.get() {
1379            return;
1380        }
1381        let res = slf.try_send_pong(
1382            serial,
1383        );
1384        if let Err(e) = res {
1385            log_forward("wl_shell_surface.pong", &e);
1386        }
1387    }
1388
1389    /// start an interactive move
1390    ///
1391    /// Start a pointer-driven move of the surface.
1392    ///
1393    /// This request must be used in response to a button press event.
1394    /// The server may ignore move requests depending on the state of
1395    /// the surface (e.g. fullscreen or maximized).
1396    ///
1397    /// # Arguments
1398    ///
1399    /// - `seat`: seat whose pointer is used
1400    /// - `serial`: serial number of the implicit grab on the pointer
1401    ///
1402    /// All borrowed proxies passed to this function are guaranteed to be
1403    /// immutable and non-null.
1404    #[inline]
1405    fn handle_move(
1406        &mut self,
1407        slf: &Rc<WlShellSurface>,
1408        seat: &Rc<WlSeat>,
1409        serial: u32,
1410    ) {
1411        if !slf.core.forward_to_server.get() {
1412            return;
1413        }
1414        let res = slf.try_send_move(
1415            seat,
1416            serial,
1417        );
1418        if let Err(e) = res {
1419            log_forward("wl_shell_surface.move", &e);
1420        }
1421    }
1422
1423    /// start an interactive resize
1424    ///
1425    /// Start a pointer-driven resizing of the surface.
1426    ///
1427    /// This request must be used in response to a button press event.
1428    /// The server may ignore resize requests depending on the state of
1429    /// the surface (e.g. fullscreen or maximized).
1430    ///
1431    /// # Arguments
1432    ///
1433    /// - `seat`: seat whose pointer is used
1434    /// - `serial`: serial number of the implicit grab on the pointer
1435    /// - `edges`: which edge or corner is being dragged
1436    ///
1437    /// All borrowed proxies passed to this function are guaranteed to be
1438    /// immutable and non-null.
1439    #[inline]
1440    fn handle_resize(
1441        &mut self,
1442        slf: &Rc<WlShellSurface>,
1443        seat: &Rc<WlSeat>,
1444        serial: u32,
1445        edges: WlShellSurfaceResize,
1446    ) {
1447        if !slf.core.forward_to_server.get() {
1448            return;
1449        }
1450        let res = slf.try_send_resize(
1451            seat,
1452            serial,
1453            edges,
1454        );
1455        if let Err(e) = res {
1456            log_forward("wl_shell_surface.resize", &e);
1457        }
1458    }
1459
1460    /// make the surface a toplevel surface
1461    ///
1462    /// Map the surface as a toplevel surface.
1463    ///
1464    /// A toplevel surface is not fullscreen, maximized or transient.
1465    #[inline]
1466    fn handle_set_toplevel(
1467        &mut self,
1468        slf: &Rc<WlShellSurface>,
1469    ) {
1470        if !slf.core.forward_to_server.get() {
1471            return;
1472        }
1473        let res = slf.try_send_set_toplevel(
1474        );
1475        if let Err(e) = res {
1476            log_forward("wl_shell_surface.set_toplevel", &e);
1477        }
1478    }
1479
1480    /// make the surface a transient surface
1481    ///
1482    /// Map the surface relative to an existing surface.
1483    ///
1484    /// The x and y arguments specify the location of the upper left
1485    /// corner of the surface relative to the upper left corner of the
1486    /// parent surface, in surface-local coordinates.
1487    ///
1488    /// The flags argument controls details of the transient behaviour.
1489    ///
1490    /// # Arguments
1491    ///
1492    /// - `parent`: parent surface
1493    /// - `x`: surface-local x coordinate
1494    /// - `y`: surface-local y coordinate
1495    /// - `flags`: transient surface behavior
1496    ///
1497    /// All borrowed proxies passed to this function are guaranteed to be
1498    /// immutable and non-null.
1499    #[inline]
1500    fn handle_set_transient(
1501        &mut self,
1502        slf: &Rc<WlShellSurface>,
1503        parent: &Rc<WlSurface>,
1504        x: i32,
1505        y: i32,
1506        flags: WlShellSurfaceTransient,
1507    ) {
1508        if !slf.core.forward_to_server.get() {
1509            return;
1510        }
1511        let res = slf.try_send_set_transient(
1512            parent,
1513            x,
1514            y,
1515            flags,
1516        );
1517        if let Err(e) = res {
1518            log_forward("wl_shell_surface.set_transient", &e);
1519        }
1520    }
1521
1522    /// make the surface a fullscreen surface
1523    ///
1524    /// Map the surface as a fullscreen surface.
1525    ///
1526    /// If an output parameter is given then the surface will be made
1527    /// fullscreen on that output. If the client does not specify the
1528    /// output then the compositor will apply its policy - usually
1529    /// choosing the output on which the surface has the biggest surface
1530    /// area.
1531    ///
1532    /// The client may specify a method to resolve a size conflict
1533    /// between the output size and the surface size - this is provided
1534    /// through the method parameter.
1535    ///
1536    /// The framerate parameter is used only when the method is set
1537    /// to "driver", to indicate the preferred framerate. A value of 0
1538    /// indicates that the client does not care about framerate.  The
1539    /// framerate is specified in mHz, that is framerate of 60000 is 60Hz.
1540    ///
1541    /// A method of "scale" or "driver" implies a scaling operation of
1542    /// the surface, either via a direct scaling operation or a change of
1543    /// the output mode. This will override any kind of output scaling, so
1544    /// that mapping a surface with a buffer size equal to the mode can
1545    /// fill the screen independent of buffer_scale.
1546    ///
1547    /// A method of "fill" means we don't scale up the buffer, however
1548    /// any output scale is applied. This means that you may run into
1549    /// an edge case where the application maps a buffer with the same
1550    /// size of the output mode but buffer_scale 1 (thus making a
1551    /// surface larger than the output). In this case it is allowed to
1552    /// downscale the results to fit the screen.
1553    ///
1554    /// The compositor must reply to this request with a configure event
1555    /// with the dimensions for the output on which the surface will
1556    /// be made fullscreen.
1557    ///
1558    /// # Arguments
1559    ///
1560    /// - `method`: method for resolving size conflict
1561    /// - `framerate`: framerate in mHz
1562    /// - `output`: output on which the surface is to be fullscreen
1563    ///
1564    /// All borrowed proxies passed to this function are guaranteed to be
1565    /// immutable and non-null.
1566    #[inline]
1567    fn handle_set_fullscreen(
1568        &mut self,
1569        slf: &Rc<WlShellSurface>,
1570        method: WlShellSurfaceFullscreenMethod,
1571        framerate: u32,
1572        output: Option<&Rc<WlOutput>>,
1573    ) {
1574        if !slf.core.forward_to_server.get() {
1575            return;
1576        }
1577        let res = slf.try_send_set_fullscreen(
1578            method,
1579            framerate,
1580            output,
1581        );
1582        if let Err(e) = res {
1583            log_forward("wl_shell_surface.set_fullscreen", &e);
1584        }
1585    }
1586
1587    /// make the surface a popup surface
1588    ///
1589    /// Map the surface as a popup.
1590    ///
1591    /// A popup surface is a transient surface with an added pointer
1592    /// grab.
1593    ///
1594    /// An existing implicit grab will be changed to owner-events mode,
1595    /// and the popup grab will continue after the implicit grab ends
1596    /// (i.e. releasing the mouse button does not cause the popup to
1597    /// be unmapped).
1598    ///
1599    /// The popup grab continues until the window is destroyed or a
1600    /// mouse button is pressed in any other client's window. A click
1601    /// in any of the client's surfaces is reported as normal, however,
1602    /// clicks in other clients' surfaces will be discarded and trigger
1603    /// the callback.
1604    ///
1605    /// The x and y arguments specify the location of the upper left
1606    /// corner of the surface relative to the upper left corner of the
1607    /// parent surface, in surface-local coordinates.
1608    ///
1609    /// # Arguments
1610    ///
1611    /// - `seat`: seat whose pointer is used
1612    /// - `serial`: serial number of the implicit grab on the pointer
1613    /// - `parent`: parent surface
1614    /// - `x`: surface-local x coordinate
1615    /// - `y`: surface-local y coordinate
1616    /// - `flags`: transient surface behavior
1617    ///
1618    /// All borrowed proxies passed to this function are guaranteed to be
1619    /// immutable and non-null.
1620    #[inline]
1621    fn handle_set_popup(
1622        &mut self,
1623        slf: &Rc<WlShellSurface>,
1624        seat: &Rc<WlSeat>,
1625        serial: u32,
1626        parent: &Rc<WlSurface>,
1627        x: i32,
1628        y: i32,
1629        flags: WlShellSurfaceTransient,
1630    ) {
1631        if !slf.core.forward_to_server.get() {
1632            return;
1633        }
1634        let res = slf.try_send_set_popup(
1635            seat,
1636            serial,
1637            parent,
1638            x,
1639            y,
1640            flags,
1641        );
1642        if let Err(e) = res {
1643            log_forward("wl_shell_surface.set_popup", &e);
1644        }
1645    }
1646
1647    /// make the surface a maximized surface
1648    ///
1649    /// Map the surface as a maximized surface.
1650    ///
1651    /// If an output parameter is given then the surface will be
1652    /// maximized on that output. If the client does not specify the
1653    /// output then the compositor will apply its policy - usually
1654    /// choosing the output on which the surface has the biggest surface
1655    /// area.
1656    ///
1657    /// The compositor will reply with a configure event telling
1658    /// the expected new surface size. The operation is completed
1659    /// on the next buffer attach to this surface.
1660    ///
1661    /// A maximized surface typically fills the entire output it is
1662    /// bound to, except for desktop elements such as panels. This is
1663    /// the main difference between a maximized shell surface and a
1664    /// fullscreen shell surface.
1665    ///
1666    /// The details depend on the compositor implementation.
1667    ///
1668    /// # Arguments
1669    ///
1670    /// - `output`: output on which the surface is to be maximized
1671    ///
1672    /// All borrowed proxies passed to this function are guaranteed to be
1673    /// immutable and non-null.
1674    #[inline]
1675    fn handle_set_maximized(
1676        &mut self,
1677        slf: &Rc<WlShellSurface>,
1678        output: Option<&Rc<WlOutput>>,
1679    ) {
1680        if !slf.core.forward_to_server.get() {
1681            return;
1682        }
1683        let res = slf.try_send_set_maximized(
1684            output,
1685        );
1686        if let Err(e) = res {
1687            log_forward("wl_shell_surface.set_maximized", &e);
1688        }
1689    }
1690
1691    /// set surface title
1692    ///
1693    /// Set a short title for the surface.
1694    ///
1695    /// This string may be used to identify the surface in a task bar,
1696    /// window list, or other user interface elements provided by the
1697    /// compositor.
1698    ///
1699    /// The string must be encoded in UTF-8.
1700    ///
1701    /// # Arguments
1702    ///
1703    /// - `title`: surface title
1704    #[inline]
1705    fn handle_set_title(
1706        &mut self,
1707        slf: &Rc<WlShellSurface>,
1708        title: &str,
1709    ) {
1710        if !slf.core.forward_to_server.get() {
1711            return;
1712        }
1713        let res = slf.try_send_set_title(
1714            title,
1715        );
1716        if let Err(e) = res {
1717            log_forward("wl_shell_surface.set_title", &e);
1718        }
1719    }
1720
1721    /// set surface class
1722    ///
1723    /// Set a class for the surface.
1724    ///
1725    /// The surface class identifies the general class of applications
1726    /// to which the surface belongs. A common convention is to use the
1727    /// file name (or the full path if it is a non-standard location) of
1728    /// the application's .desktop file as the class.
1729    ///
1730    /// # Arguments
1731    ///
1732    /// - `class_`: surface class
1733    #[inline]
1734    fn handle_set_class(
1735        &mut self,
1736        slf: &Rc<WlShellSurface>,
1737        class_: &str,
1738    ) {
1739        if !slf.core.forward_to_server.get() {
1740            return;
1741        }
1742        let res = slf.try_send_set_class(
1743            class_,
1744        );
1745        if let Err(e) = res {
1746            log_forward("wl_shell_surface.set_class", &e);
1747        }
1748    }
1749
1750    /// ping client
1751    ///
1752    /// Ping a client to check if it is receiving events and sending
1753    /// requests. A client is expected to reply with a pong request.
1754    ///
1755    /// # Arguments
1756    ///
1757    /// - `serial`: serial number of the ping
1758    #[inline]
1759    fn handle_ping(
1760        &mut self,
1761        slf: &Rc<WlShellSurface>,
1762        serial: u32,
1763    ) {
1764        if !slf.core.forward_to_client.get() {
1765            return;
1766        }
1767        let res = slf.try_send_ping(
1768            serial,
1769        );
1770        if let Err(e) = res {
1771            log_forward("wl_shell_surface.ping", &e);
1772        }
1773    }
1774
1775    /// suggest resize
1776    ///
1777    /// The configure event asks the client to resize its surface.
1778    ///
1779    /// The size is a hint, in the sense that the client is free to
1780    /// ignore it if it doesn't resize, pick a smaller size (to
1781    /// satisfy aspect ratio or resize in steps of NxM pixels).
1782    ///
1783    /// The edges parameter provides a hint about how the surface
1784    /// was resized. The client may use this information to decide
1785    /// how to adjust its content to the new size (e.g. a scrolling
1786    /// area might adjust its content position to leave the viewable
1787    /// content unmoved).
1788    ///
1789    /// The client is free to dismiss all but the last configure
1790    /// event it received.
1791    ///
1792    /// The width and height arguments specify the size of the window
1793    /// in surface-local coordinates.
1794    ///
1795    /// # Arguments
1796    ///
1797    /// - `edges`: how the surface was resized
1798    /// - `width`: new width of the surface
1799    /// - `height`: new height of the surface
1800    #[inline]
1801    fn handle_configure(
1802        &mut self,
1803        slf: &Rc<WlShellSurface>,
1804        edges: WlShellSurfaceResize,
1805        width: i32,
1806        height: i32,
1807    ) {
1808        if !slf.core.forward_to_client.get() {
1809            return;
1810        }
1811        let res = slf.try_send_configure(
1812            edges,
1813            width,
1814            height,
1815        );
1816        if let Err(e) = res {
1817            log_forward("wl_shell_surface.configure", &e);
1818        }
1819    }
1820
1821    /// popup interaction is done
1822    ///
1823    /// The popup_done event is sent out when a popup grab is broken,
1824    /// that is, when the user clicks a surface that doesn't belong
1825    /// to the client owning the popup surface.
1826    #[inline]
1827    fn handle_popup_done(
1828        &mut self,
1829        slf: &Rc<WlShellSurface>,
1830    ) {
1831        if !slf.core.forward_to_client.get() {
1832            return;
1833        }
1834        let res = slf.try_send_popup_done(
1835        );
1836        if let Err(e) = res {
1837            log_forward("wl_shell_surface.popup_done", &e);
1838        }
1839    }
1840}
1841
1842impl ObjectPrivate for WlShellSurface {
1843    fn new(state: &Rc<State>, version: u32) -> Rc<Self> {
1844        Rc::<Self>::new_cyclic(|slf| Self {
1845            core: ObjectCore::new(state, slf.clone(), ObjectInterface::WlShellSurface, version),
1846            handler: Default::default(),
1847        })
1848    }
1849
1850    fn delete_id(self: Rc<Self>) -> Result<(), (ObjectError, Rc<dyn Object>)> {
1851        let Some(mut handler) = self.handler.try_borrow_mut() else {
1852            return Err((ObjectError(ObjectErrorKind::HandlerBorrowed), self));
1853        };
1854        if let Some(handler) = &mut *handler {
1855            handler.delete_id(&self);
1856        } else {
1857            self.core.delete_id();
1858        }
1859        Ok(())
1860    }
1861
1862    fn handle_request(self: Rc<Self>, client: &Rc<Client>, msg: &[u32], fds: &mut VecDeque<Rc<OwnedFd>>) -> Result<(), ObjectError> {
1863        let Some(mut handler) = self.handler.try_borrow_mut() else {
1864            return Err(ObjectError(ObjectErrorKind::HandlerBorrowed));
1865        };
1866        let handler = &mut *handler;
1867        match msg[1] & 0xffff {
1868            0 => {
1869                let [
1870                    arg0,
1871                ] = msg[2..] else {
1872                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 12)));
1873                };
1874                #[cfg(feature = "logging")]
1875                if self.core.state.log {
1876                    #[cold]
1877                    fn log(state: &State, client_id: u64, id: u32, arg0: u32) {
1878                        let (millis, micros) = time_since_epoch();
1879                        let prefix = &state.log_prefix;
1880                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.pong(serial: {})\n", client_id, id, arg0);
1881                        state.log(args);
1882                    }
1883                    log(&self.core.state, client.endpoint.id, msg[0], arg0);
1884                }
1885                if let Some(handler) = handler {
1886                    (**handler).handle_pong(&self, arg0);
1887                } else {
1888                    DefaultHandler.handle_pong(&self, arg0);
1889                }
1890            }
1891            1 => {
1892                let [
1893                    arg0,
1894                    arg1,
1895                ] = msg[2..] else {
1896                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 16)));
1897                };
1898                #[cfg(feature = "logging")]
1899                if self.core.state.log {
1900                    #[cold]
1901                    fn log(state: &State, client_id: u64, id: u32, arg0: u32, arg1: u32) {
1902                        let (millis, micros) = time_since_epoch();
1903                        let prefix = &state.log_prefix;
1904                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.move(seat: wl_seat#{}, serial: {})\n", client_id, id, arg0, arg1);
1905                        state.log(args);
1906                    }
1907                    log(&self.core.state, client.endpoint.id, msg[0], arg0, arg1);
1908                }
1909                let arg0_id = arg0;
1910                let Some(arg0) = client.endpoint.lookup(arg0_id) else {
1911                    return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg0_id)));
1912                };
1913                let Ok(arg0) = (arg0 as Rc<dyn Any>).downcast::<WlSeat>() else {
1914                    let o = client.endpoint.lookup(arg0_id).unwrap();
1915                    return Err(ObjectError(ObjectErrorKind::WrongObjectType("seat", o.core().interface, ObjectInterface::WlSeat)));
1916                };
1917                let arg0 = &arg0;
1918                if let Some(handler) = handler {
1919                    (**handler).handle_move(&self, arg0, arg1);
1920                } else {
1921                    DefaultHandler.handle_move(&self, arg0, arg1);
1922                }
1923            }
1924            2 => {
1925                let [
1926                    arg0,
1927                    arg1,
1928                    arg2,
1929                ] = msg[2..] else {
1930                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 20)));
1931                };
1932                let arg2 = WlShellSurfaceResize(arg2);
1933                #[cfg(feature = "logging")]
1934                if self.core.state.log {
1935                    #[cold]
1936                    fn log(state: &State, client_id: u64, id: u32, arg0: u32, arg1: u32, arg2: WlShellSurfaceResize) {
1937                        let (millis, micros) = time_since_epoch();
1938                        let prefix = &state.log_prefix;
1939                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.resize(seat: wl_seat#{}, serial: {}, edges: {:?})\n", client_id, id, arg0, arg1, arg2);
1940                        state.log(args);
1941                    }
1942                    log(&self.core.state, client.endpoint.id, msg[0], arg0, arg1, arg2);
1943                }
1944                let arg0_id = arg0;
1945                let Some(arg0) = client.endpoint.lookup(arg0_id) else {
1946                    return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg0_id)));
1947                };
1948                let Ok(arg0) = (arg0 as Rc<dyn Any>).downcast::<WlSeat>() else {
1949                    let o = client.endpoint.lookup(arg0_id).unwrap();
1950                    return Err(ObjectError(ObjectErrorKind::WrongObjectType("seat", o.core().interface, ObjectInterface::WlSeat)));
1951                };
1952                let arg0 = &arg0;
1953                if let Some(handler) = handler {
1954                    (**handler).handle_resize(&self, arg0, arg1, arg2);
1955                } else {
1956                    DefaultHandler.handle_resize(&self, arg0, arg1, arg2);
1957                }
1958            }
1959            3 => {
1960                if msg.len() != 2 {
1961                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 8)));
1962                }
1963                #[cfg(feature = "logging")]
1964                if self.core.state.log {
1965                    #[cold]
1966                    fn log(state: &State, client_id: u64, id: u32) {
1967                        let (millis, micros) = time_since_epoch();
1968                        let prefix = &state.log_prefix;
1969                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_toplevel()\n", client_id, id);
1970                        state.log(args);
1971                    }
1972                    log(&self.core.state, client.endpoint.id, msg[0]);
1973                }
1974                if let Some(handler) = handler {
1975                    (**handler).handle_set_toplevel(&self);
1976                } else {
1977                    DefaultHandler.handle_set_toplevel(&self);
1978                }
1979            }
1980            4 => {
1981                let [
1982                    arg0,
1983                    arg1,
1984                    arg2,
1985                    arg3,
1986                ] = msg[2..] else {
1987                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 24)));
1988                };
1989                let arg1 = arg1 as i32;
1990                let arg2 = arg2 as i32;
1991                let arg3 = WlShellSurfaceTransient(arg3);
1992                #[cfg(feature = "logging")]
1993                if self.core.state.log {
1994                    #[cold]
1995                    fn log(state: &State, client_id: u64, id: u32, arg0: u32, arg1: i32, arg2: i32, arg3: WlShellSurfaceTransient) {
1996                        let (millis, micros) = time_since_epoch();
1997                        let prefix = &state.log_prefix;
1998                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_transient(parent: wl_surface#{}, x: {}, y: {}, flags: {:?})\n", client_id, id, arg0, arg1, arg2, arg3);
1999                        state.log(args);
2000                    }
2001                    log(&self.core.state, client.endpoint.id, msg[0], arg0, arg1, arg2, arg3);
2002                }
2003                let arg0_id = arg0;
2004                let Some(arg0) = client.endpoint.lookup(arg0_id) else {
2005                    return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg0_id)));
2006                };
2007                let Ok(arg0) = (arg0 as Rc<dyn Any>).downcast::<WlSurface>() else {
2008                    let o = client.endpoint.lookup(arg0_id).unwrap();
2009                    return Err(ObjectError(ObjectErrorKind::WrongObjectType("parent", o.core().interface, ObjectInterface::WlSurface)));
2010                };
2011                let arg0 = &arg0;
2012                if let Some(handler) = handler {
2013                    (**handler).handle_set_transient(&self, arg0, arg1, arg2, arg3);
2014                } else {
2015                    DefaultHandler.handle_set_transient(&self, arg0, arg1, arg2, arg3);
2016                }
2017            }
2018            5 => {
2019                let [
2020                    arg0,
2021                    arg1,
2022                    arg2,
2023                ] = msg[2..] else {
2024                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 20)));
2025                };
2026                let arg0 = WlShellSurfaceFullscreenMethod(arg0);
2027                #[cfg(feature = "logging")]
2028                if self.core.state.log {
2029                    #[cold]
2030                    fn log(state: &State, client_id: u64, id: u32, arg0: WlShellSurfaceFullscreenMethod, arg1: u32, arg2: u32) {
2031                        let (millis, micros) = time_since_epoch();
2032                        let prefix = &state.log_prefix;
2033                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_fullscreen(method: {:?}, framerate: {}, output: wl_output#{})\n", client_id, id, arg0, arg1, arg2);
2034                        state.log(args);
2035                    }
2036                    log(&self.core.state, client.endpoint.id, msg[0], arg0, arg1, arg2);
2037                }
2038                let arg2 = if arg2 == 0 {
2039                    None
2040                } else {
2041                    let arg2_id = arg2;
2042                    let Some(arg2) = client.endpoint.lookup(arg2_id) else {
2043                        return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg2_id)));
2044                    };
2045                    let Ok(arg2) = (arg2 as Rc<dyn Any>).downcast::<WlOutput>() else {
2046                        let o = client.endpoint.lookup(arg2_id).unwrap();
2047                        return Err(ObjectError(ObjectErrorKind::WrongObjectType("output", o.core().interface, ObjectInterface::WlOutput)));
2048                    };
2049                    Some(arg2)
2050                };
2051                let arg2 = arg2.as_ref();
2052                if let Some(handler) = handler {
2053                    (**handler).handle_set_fullscreen(&self, arg0, arg1, arg2);
2054                } else {
2055                    DefaultHandler.handle_set_fullscreen(&self, arg0, arg1, arg2);
2056                }
2057            }
2058            6 => {
2059                let [
2060                    arg0,
2061                    arg1,
2062                    arg2,
2063                    arg3,
2064                    arg4,
2065                    arg5,
2066                ] = msg[2..] else {
2067                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 32)));
2068                };
2069                let arg3 = arg3 as i32;
2070                let arg4 = arg4 as i32;
2071                let arg5 = WlShellSurfaceTransient(arg5);
2072                #[cfg(feature = "logging")]
2073                if self.core.state.log {
2074                    #[cold]
2075                    fn log(state: &State, client_id: u64, id: u32, arg0: u32, arg1: u32, arg2: u32, arg3: i32, arg4: i32, arg5: WlShellSurfaceTransient) {
2076                        let (millis, micros) = time_since_epoch();
2077                        let prefix = &state.log_prefix;
2078                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_popup(seat: wl_seat#{}, serial: {}, parent: wl_surface#{}, x: {}, y: {}, flags: {:?})\n", client_id, id, arg0, arg1, arg2, arg3, arg4, arg5);
2079                        state.log(args);
2080                    }
2081                    log(&self.core.state, client.endpoint.id, msg[0], arg0, arg1, arg2, arg3, arg4, arg5);
2082                }
2083                let arg0_id = arg0;
2084                let Some(arg0) = client.endpoint.lookup(arg0_id) else {
2085                    return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg0_id)));
2086                };
2087                let Ok(arg0) = (arg0 as Rc<dyn Any>).downcast::<WlSeat>() else {
2088                    let o = client.endpoint.lookup(arg0_id).unwrap();
2089                    return Err(ObjectError(ObjectErrorKind::WrongObjectType("seat", o.core().interface, ObjectInterface::WlSeat)));
2090                };
2091                let arg2_id = arg2;
2092                let Some(arg2) = client.endpoint.lookup(arg2_id) else {
2093                    return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg2_id)));
2094                };
2095                let Ok(arg2) = (arg2 as Rc<dyn Any>).downcast::<WlSurface>() else {
2096                    let o = client.endpoint.lookup(arg2_id).unwrap();
2097                    return Err(ObjectError(ObjectErrorKind::WrongObjectType("parent", o.core().interface, ObjectInterface::WlSurface)));
2098                };
2099                let arg0 = &arg0;
2100                let arg2 = &arg2;
2101                if let Some(handler) = handler {
2102                    (**handler).handle_set_popup(&self, arg0, arg1, arg2, arg3, arg4, arg5);
2103                } else {
2104                    DefaultHandler.handle_set_popup(&self, arg0, arg1, arg2, arg3, arg4, arg5);
2105                }
2106            }
2107            7 => {
2108                let [
2109                    arg0,
2110                ] = msg[2..] else {
2111                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 12)));
2112                };
2113                #[cfg(feature = "logging")]
2114                if self.core.state.log {
2115                    #[cold]
2116                    fn log(state: &State, client_id: u64, id: u32, arg0: u32) {
2117                        let (millis, micros) = time_since_epoch();
2118                        let prefix = &state.log_prefix;
2119                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_maximized(output: wl_output#{})\n", client_id, id, arg0);
2120                        state.log(args);
2121                    }
2122                    log(&self.core.state, client.endpoint.id, msg[0], arg0);
2123                }
2124                let arg0 = if arg0 == 0 {
2125                    None
2126                } else {
2127                    let arg0_id = arg0;
2128                    let Some(arg0) = client.endpoint.lookup(arg0_id) else {
2129                        return Err(ObjectError(ObjectErrorKind::NoClientObject(client.endpoint.id, arg0_id)));
2130                    };
2131                    let Ok(arg0) = (arg0 as Rc<dyn Any>).downcast::<WlOutput>() else {
2132                        let o = client.endpoint.lookup(arg0_id).unwrap();
2133                        return Err(ObjectError(ObjectErrorKind::WrongObjectType("output", o.core().interface, ObjectInterface::WlOutput)));
2134                    };
2135                    Some(arg0)
2136                };
2137                let arg0 = arg0.as_ref();
2138                if let Some(handler) = handler {
2139                    (**handler).handle_set_maximized(&self, arg0);
2140                } else {
2141                    DefaultHandler.handle_set_maximized(&self, arg0);
2142                }
2143            }
2144            8 => {
2145                let mut offset = 2;
2146                let arg0;
2147                (arg0, offset) = parse_string::<NonNullString>(msg, offset, "title")?;
2148                if offset != msg.len() {
2149                    return Err(ObjectError(ObjectErrorKind::TrailingBytes));
2150                }
2151                #[cfg(feature = "logging")]
2152                if self.core.state.log {
2153                    #[cold]
2154                    fn log(state: &State, client_id: u64, id: u32, arg0: &str) {
2155                        let (millis, micros) = time_since_epoch();
2156                        let prefix = &state.log_prefix;
2157                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_title(title: {:?})\n", client_id, id, arg0);
2158                        state.log(args);
2159                    }
2160                    log(&self.core.state, client.endpoint.id, msg[0], arg0);
2161                }
2162                if let Some(handler) = handler {
2163                    (**handler).handle_set_title(&self, arg0);
2164                } else {
2165                    DefaultHandler.handle_set_title(&self, arg0);
2166                }
2167            }
2168            9 => {
2169                let mut offset = 2;
2170                let arg0;
2171                (arg0, offset) = parse_string::<NonNullString>(msg, offset, "class_")?;
2172                if offset != msg.len() {
2173                    return Err(ObjectError(ObjectErrorKind::TrailingBytes));
2174                }
2175                #[cfg(feature = "logging")]
2176                if self.core.state.log {
2177                    #[cold]
2178                    fn log(state: &State, client_id: u64, id: u32, arg0: &str) {
2179                        let (millis, micros) = time_since_epoch();
2180                        let prefix = &state.log_prefix;
2181                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}client#{:<4} -> wl_shell_surface#{}.set_class(class_: {:?})\n", client_id, id, arg0);
2182                        state.log(args);
2183                    }
2184                    log(&self.core.state, client.endpoint.id, msg[0], arg0);
2185                }
2186                if let Some(handler) = handler {
2187                    (**handler).handle_set_class(&self, arg0);
2188                } else {
2189                    DefaultHandler.handle_set_class(&self, arg0);
2190                }
2191            }
2192            n => {
2193                let _ = client;
2194                let _ = msg;
2195                let _ = fds;
2196                let _ = handler;
2197                return Err(ObjectError(ObjectErrorKind::UnknownMessageId(n)));
2198            }
2199        }
2200        Ok(())
2201    }
2202
2203    fn handle_event(self: Rc<Self>, server: &Endpoint, msg: &[u32], fds: &mut VecDeque<Rc<OwnedFd>>) -> Result<(), ObjectError> {
2204        let Some(mut handler) = self.handler.try_borrow_mut() else {
2205            return Err(ObjectError(ObjectErrorKind::HandlerBorrowed));
2206        };
2207        let handler = &mut *handler;
2208        match msg[1] & 0xffff {
2209            0 => {
2210                let [
2211                    arg0,
2212                ] = msg[2..] else {
2213                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 12)));
2214                };
2215                #[cfg(feature = "logging")]
2216                if self.core.state.log {
2217                    #[cold]
2218                    fn log(state: &State, id: u32, arg0: u32) {
2219                        let (millis, micros) = time_since_epoch();
2220                        let prefix = &state.log_prefix;
2221                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      -> wl_shell_surface#{}.ping(serial: {})\n", id, arg0);
2222                        state.log(args);
2223                    }
2224                    log(&self.core.state, msg[0], arg0);
2225                }
2226                if let Some(handler) = handler {
2227                    (**handler).handle_ping(&self, arg0);
2228                } else {
2229                    DefaultHandler.handle_ping(&self, arg0);
2230                }
2231            }
2232            1 => {
2233                let [
2234                    arg0,
2235                    arg1,
2236                    arg2,
2237                ] = msg[2..] else {
2238                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 20)));
2239                };
2240                let arg0 = WlShellSurfaceResize(arg0);
2241                let arg1 = arg1 as i32;
2242                let arg2 = arg2 as i32;
2243                #[cfg(feature = "logging")]
2244                if self.core.state.log {
2245                    #[cold]
2246                    fn log(state: &State, id: u32, arg0: WlShellSurfaceResize, arg1: i32, arg2: i32) {
2247                        let (millis, micros) = time_since_epoch();
2248                        let prefix = &state.log_prefix;
2249                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      -> wl_shell_surface#{}.configure(edges: {:?}, width: {}, height: {})\n", id, arg0, arg1, arg2);
2250                        state.log(args);
2251                    }
2252                    log(&self.core.state, msg[0], arg0, arg1, arg2);
2253                }
2254                if let Some(handler) = handler {
2255                    (**handler).handle_configure(&self, arg0, arg1, arg2);
2256                } else {
2257                    DefaultHandler.handle_configure(&self, arg0, arg1, arg2);
2258                }
2259            }
2260            2 => {
2261                if msg.len() != 2 {
2262                    return Err(ObjectError(ObjectErrorKind::WrongMessageSize(msg.len() as u32 * 4, 8)));
2263                }
2264                #[cfg(feature = "logging")]
2265                if self.core.state.log {
2266                    #[cold]
2267                    fn log(state: &State, id: u32) {
2268                        let (millis, micros) = time_since_epoch();
2269                        let prefix = &state.log_prefix;
2270                        let args = format_args!("[{millis:7}.{micros:03}] {prefix}server      -> wl_shell_surface#{}.popup_done()\n", id);
2271                        state.log(args);
2272                    }
2273                    log(&self.core.state, msg[0]);
2274                }
2275                if let Some(handler) = handler {
2276                    (**handler).handle_popup_done(&self);
2277                } else {
2278                    DefaultHandler.handle_popup_done(&self);
2279                }
2280            }
2281            n => {
2282                let _ = server;
2283                let _ = msg;
2284                let _ = fds;
2285                let _ = handler;
2286                return Err(ObjectError(ObjectErrorKind::UnknownMessageId(n)));
2287            }
2288        }
2289        Ok(())
2290    }
2291
2292    fn get_request_name(&self, id: u32) -> Option<&'static str> {
2293        let name = match id {
2294            0 => "pong",
2295            1 => "move",
2296            2 => "resize",
2297            3 => "set_toplevel",
2298            4 => "set_transient",
2299            5 => "set_fullscreen",
2300            6 => "set_popup",
2301            7 => "set_maximized",
2302            8 => "set_title",
2303            9 => "set_class",
2304            _ => return None,
2305        };
2306        Some(name)
2307    }
2308
2309    fn get_event_name(&self, id: u32) -> Option<&'static str> {
2310        let name = match id {
2311            0 => "ping",
2312            1 => "configure",
2313            2 => "popup_done",
2314            _ => return None,
2315        };
2316        Some(name)
2317    }
2318}
2319
2320impl Object for WlShellSurface {
2321    fn core(&self) -> &ObjectCore {
2322        &self.core
2323    }
2324
2325    fn unset_handler(&self) {
2326        self.handler.set(None);
2327    }
2328
2329    fn get_handler_any_ref(&self) -> Result<HandlerRef<'_, dyn Any>, HandlerAccessError> {
2330        let borrowed = self.handler.try_borrow().ok_or(HandlerAccessError::AlreadyBorrowed)?;
2331        if borrowed.is_none() {
2332            return Err(HandlerAccessError::NoHandler);
2333        }
2334        Ok(HandlerRef::map(borrowed, |handler| &**handler.as_ref().unwrap() as &dyn Any))
2335    }
2336
2337    fn get_handler_any_mut(&self) -> Result<HandlerMut<'_, dyn Any>, HandlerAccessError> {
2338        let borrowed = self.handler.try_borrow_mut().ok_or(HandlerAccessError::AlreadyBorrowed)?;
2339        if borrowed.is_none() {
2340            return Err(HandlerAccessError::NoHandler);
2341        }
2342        Ok(HandlerMut::map(borrowed, |handler| &mut **handler.as_mut().unwrap() as &mut dyn Any))
2343    }
2344}
2345
2346impl WlShellSurface {
2347    /// Since when the resize.none enum variant is available.
2348    pub const ENM__RESIZE_NONE__SINCE: u32 = 1;
2349    /// Since when the resize.top enum variant is available.
2350    pub const ENM__RESIZE_TOP__SINCE: u32 = 1;
2351    /// Since when the resize.bottom enum variant is available.
2352    pub const ENM__RESIZE_BOTTOM__SINCE: u32 = 1;
2353    /// Since when the resize.left enum variant is available.
2354    pub const ENM__RESIZE_LEFT__SINCE: u32 = 1;
2355    /// Since when the resize.top_left enum variant is available.
2356    pub const ENM__RESIZE_TOP_LEFT__SINCE: u32 = 1;
2357    /// Since when the resize.bottom_left enum variant is available.
2358    pub const ENM__RESIZE_BOTTOM_LEFT__SINCE: u32 = 1;
2359    /// Since when the resize.right enum variant is available.
2360    pub const ENM__RESIZE_RIGHT__SINCE: u32 = 1;
2361    /// Since when the resize.top_right enum variant is available.
2362    pub const ENM__RESIZE_TOP_RIGHT__SINCE: u32 = 1;
2363    /// Since when the resize.bottom_right enum variant is available.
2364    pub const ENM__RESIZE_BOTTOM_RIGHT__SINCE: u32 = 1;
2365
2366    /// Since when the transient.inactive enum variant is available.
2367    pub const ENM__TRANSIENT_INACTIVE__SINCE: u32 = 1;
2368
2369    /// Since when the fullscreen_method.default enum variant is available.
2370    pub const ENM__FULLSCREEN_METHOD_DEFAULT__SINCE: u32 = 1;
2371    /// Since when the fullscreen_method.scale enum variant is available.
2372    pub const ENM__FULLSCREEN_METHOD_SCALE__SINCE: u32 = 1;
2373    /// Since when the fullscreen_method.driver enum variant is available.
2374    pub const ENM__FULLSCREEN_METHOD_DRIVER__SINCE: u32 = 1;
2375    /// Since when the fullscreen_method.fill enum variant is available.
2376    pub const ENM__FULLSCREEN_METHOD_FILL__SINCE: u32 = 1;
2377}
2378
2379/// edge values for resizing
2380///
2381/// These values are used to indicate which edge of a surface
2382/// is being dragged in a resize operation. The server may
2383/// use this information to adapt its behavior, e.g. choose
2384/// an appropriate cursor image.
2385#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
2386#[derive(Default)]
2387pub struct WlShellSurfaceResize(pub u32);
2388
2389/// An iterator over the set bits in a [`WlShellSurfaceResize`].
2390///
2391/// You can construct this with the `IntoIterator` implementation of `WlShellSurfaceResize`.
2392#[derive(Clone, Debug)]
2393pub struct WlShellSurfaceResizeIter(pub u32);
2394
2395impl WlShellSurfaceResize {
2396    /// no edge
2397    pub const NONE: Self = Self(0);
2398
2399    /// top edge
2400    pub const TOP: Self = Self(1);
2401
2402    /// bottom edge
2403    pub const BOTTOM: Self = Self(2);
2404
2405    /// left edge
2406    pub const LEFT: Self = Self(4);
2407
2408    /// top and left edges
2409    pub const TOP_LEFT: Self = Self(5);
2410
2411    /// bottom and left edges
2412    pub const BOTTOM_LEFT: Self = Self(6);
2413
2414    /// right edge
2415    pub const RIGHT: Self = Self(8);
2416
2417    /// top and right edges
2418    pub const TOP_RIGHT: Self = Self(9);
2419
2420    /// bottom and right edges
2421    pub const BOTTOM_RIGHT: Self = Self(10);
2422}
2423
2424impl WlShellSurfaceResize {
2425    #[inline]
2426    pub const fn empty() -> Self {
2427        Self(0)
2428    }
2429
2430    #[inline]
2431    #[must_use]
2432    pub const fn is_empty(self) -> bool {
2433        self.0 == 0
2434    }
2435
2436    #[inline]
2437    #[must_use]
2438    pub const fn contains(self, other: Self) -> bool {
2439        self.0 & other.0 == other.0
2440    }
2441
2442    #[inline]
2443    #[must_use]
2444    pub const fn intersects(self, other: Self) -> bool {
2445        self.0 & other.0 != 0
2446    }
2447
2448    #[inline]
2449    pub const fn insert(&mut self, other: Self) {
2450        *self = self.union(other);
2451    }
2452
2453    #[inline]
2454    pub const fn remove(&mut self, other: Self) {
2455        *self = self.difference(other);
2456    }
2457
2458    #[inline]
2459    pub const fn toggle(&mut self, other: Self) {
2460        *self = self.symmetric_difference(other);
2461    }
2462
2463    #[inline]
2464    pub const fn set(&mut self, other: Self, value: bool) {
2465        if value {
2466            self.insert(other);
2467        } else {
2468            self.remove(other);
2469        }
2470    }
2471
2472    #[inline]
2473    #[must_use]
2474    pub const fn intersection(self, other: Self) -> Self {
2475        Self(self.0 & other.0)
2476    }
2477
2478    #[inline]
2479    #[must_use]
2480    pub const fn union(self, other: Self) -> Self {
2481        Self(self.0 | other.0)
2482    }
2483
2484    #[inline]
2485    #[must_use]
2486    pub const fn difference(self, other: Self) -> Self {
2487        Self(self.0 & !other.0)
2488    }
2489
2490    #[inline]
2491    #[must_use]
2492    pub const fn complement(self) -> Self {
2493        Self(!self.0)
2494    }
2495
2496    #[inline]
2497    #[must_use]
2498    pub const fn symmetric_difference(self, other: Self) -> Self {
2499        Self(self.0 ^ other.0)
2500    }
2501
2502    #[inline]
2503    pub const fn all_known() -> Self {
2504        #[allow(clippy::eq_op, clippy::identity_op)]
2505        Self(0 | 0 | 1 | 2 | 4 | 5 | 6 | 8 | 9 | 10)
2506    }
2507}
2508
2509impl Iterator for WlShellSurfaceResizeIter {
2510    type Item = WlShellSurfaceResize;
2511
2512    fn next(&mut self) -> Option<Self::Item> {
2513        if self.0 == 0 {
2514            return None;
2515        }
2516        let bit = 1 << self.0.trailing_zeros();
2517        self.0 &= !bit;
2518        Some(WlShellSurfaceResize(bit))
2519    }
2520}
2521
2522impl IntoIterator for WlShellSurfaceResize {
2523    type Item = WlShellSurfaceResize;
2524    type IntoIter = WlShellSurfaceResizeIter;
2525
2526    fn into_iter(self) -> Self::IntoIter {
2527        WlShellSurfaceResizeIter(self.0)
2528    }
2529}
2530
2531impl BitAnd for WlShellSurfaceResize {
2532    type Output = Self;
2533
2534    fn bitand(self, rhs: Self) -> Self::Output {
2535        self.intersection(rhs)
2536    }
2537}
2538
2539impl BitAndAssign for WlShellSurfaceResize {
2540    fn bitand_assign(&mut self, rhs: Self) {
2541        *self = self.intersection(rhs);
2542    }
2543}
2544
2545impl BitOr for WlShellSurfaceResize {
2546    type Output = Self;
2547
2548    fn bitor(self, rhs: Self) -> Self::Output {
2549        self.union(rhs)
2550    }
2551}
2552
2553impl BitOrAssign for WlShellSurfaceResize {
2554    fn bitor_assign(&mut self, rhs: Self) {
2555        *self = self.union(rhs);
2556    }
2557}
2558
2559impl BitXor for WlShellSurfaceResize {
2560    type Output = Self;
2561
2562    fn bitxor(self, rhs: Self) -> Self::Output {
2563        self.symmetric_difference(rhs)
2564    }
2565}
2566
2567impl BitXorAssign for WlShellSurfaceResize {
2568    fn bitxor_assign(&mut self, rhs: Self) {
2569        *self = self.symmetric_difference(rhs);
2570    }
2571}
2572
2573impl Sub for WlShellSurfaceResize {
2574    type Output = Self;
2575
2576    fn sub(self, rhs: Self) -> Self::Output {
2577        self.difference(rhs)
2578    }
2579}
2580
2581impl SubAssign for WlShellSurfaceResize {
2582    fn sub_assign(&mut self, rhs: Self) {
2583        *self = self.difference(rhs);
2584    }
2585}
2586
2587impl Not for WlShellSurfaceResize {
2588    type Output = Self;
2589
2590    fn not(self) -> Self::Output {
2591        self.complement()
2592    }
2593}
2594
2595impl Debug for WlShellSurfaceResize {
2596    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2597        let mut v = self.0;
2598        let mut first = true;
2599        if v & 1 == 1 {
2600            v &= !1;
2601            if first {
2602                first = false;
2603            } else {
2604                f.write_str(" | ")?;
2605            }
2606            f.write_str("TOP")?;
2607        }
2608        if v & 2 == 2 {
2609            v &= !2;
2610            if first {
2611                first = false;
2612            } else {
2613                f.write_str(" | ")?;
2614            }
2615            f.write_str("BOTTOM")?;
2616        }
2617        if v & 4 == 4 {
2618            v &= !4;
2619            if first {
2620                first = false;
2621            } else {
2622                f.write_str(" | ")?;
2623            }
2624            f.write_str("LEFT")?;
2625        }
2626        if v & 5 == 5 {
2627            v &= !5;
2628            if first {
2629                first = false;
2630            } else {
2631                f.write_str(" | ")?;
2632            }
2633            f.write_str("TOP_LEFT")?;
2634        }
2635        if v & 6 == 6 {
2636            v &= !6;
2637            if first {
2638                first = false;
2639            } else {
2640                f.write_str(" | ")?;
2641            }
2642            f.write_str("BOTTOM_LEFT")?;
2643        }
2644        if v & 8 == 8 {
2645            v &= !8;
2646            if first {
2647                first = false;
2648            } else {
2649                f.write_str(" | ")?;
2650            }
2651            f.write_str("RIGHT")?;
2652        }
2653        if v & 9 == 9 {
2654            v &= !9;
2655            if first {
2656                first = false;
2657            } else {
2658                f.write_str(" | ")?;
2659            }
2660            f.write_str("TOP_RIGHT")?;
2661        }
2662        if v & 10 == 10 {
2663            v &= !10;
2664            if first {
2665                first = false;
2666            } else {
2667                f.write_str(" | ")?;
2668            }
2669            f.write_str("BOTTOM_RIGHT")?;
2670        }
2671        if v != 0 {
2672            if first {
2673                first = false;
2674            } else {
2675                f.write_str(" | ")?;
2676            }
2677            write!(f, "0x{v:032x}")?;
2678        }
2679        if first {
2680            f.write_str("NONE")?;
2681        }
2682        Ok(())
2683    }
2684}
2685
2686/// details of transient behaviour
2687///
2688/// These flags specify details of the expected behaviour
2689/// of transient surfaces. Used in the set_transient request.
2690#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
2691#[derive(Default)]
2692pub struct WlShellSurfaceTransient(pub u32);
2693
2694/// An iterator over the set bits in a [`WlShellSurfaceTransient`].
2695///
2696/// You can construct this with the `IntoIterator` implementation of `WlShellSurfaceTransient`.
2697#[derive(Clone, Debug)]
2698pub struct WlShellSurfaceTransientIter(pub u32);
2699
2700impl WlShellSurfaceTransient {
2701    /// do not set keyboard focus
2702    pub const INACTIVE: Self = Self(0x1);
2703}
2704
2705impl WlShellSurfaceTransient {
2706    #[inline]
2707    pub const fn empty() -> Self {
2708        Self(0)
2709    }
2710
2711    #[inline]
2712    #[must_use]
2713    pub const fn is_empty(self) -> bool {
2714        self.0 == 0
2715    }
2716
2717    #[inline]
2718    #[must_use]
2719    pub const fn contains(self, other: Self) -> bool {
2720        self.0 & other.0 == other.0
2721    }
2722
2723    #[inline]
2724    #[must_use]
2725    pub const fn intersects(self, other: Self) -> bool {
2726        self.0 & other.0 != 0
2727    }
2728
2729    #[inline]
2730    pub const fn insert(&mut self, other: Self) {
2731        *self = self.union(other);
2732    }
2733
2734    #[inline]
2735    pub const fn remove(&mut self, other: Self) {
2736        *self = self.difference(other);
2737    }
2738
2739    #[inline]
2740    pub const fn toggle(&mut self, other: Self) {
2741        *self = self.symmetric_difference(other);
2742    }
2743
2744    #[inline]
2745    pub const fn set(&mut self, other: Self, value: bool) {
2746        if value {
2747            self.insert(other);
2748        } else {
2749            self.remove(other);
2750        }
2751    }
2752
2753    #[inline]
2754    #[must_use]
2755    pub const fn intersection(self, other: Self) -> Self {
2756        Self(self.0 & other.0)
2757    }
2758
2759    #[inline]
2760    #[must_use]
2761    pub const fn union(self, other: Self) -> Self {
2762        Self(self.0 | other.0)
2763    }
2764
2765    #[inline]
2766    #[must_use]
2767    pub const fn difference(self, other: Self) -> Self {
2768        Self(self.0 & !other.0)
2769    }
2770
2771    #[inline]
2772    #[must_use]
2773    pub const fn complement(self) -> Self {
2774        Self(!self.0)
2775    }
2776
2777    #[inline]
2778    #[must_use]
2779    pub const fn symmetric_difference(self, other: Self) -> Self {
2780        Self(self.0 ^ other.0)
2781    }
2782
2783    #[inline]
2784    pub const fn all_known() -> Self {
2785        #[allow(clippy::eq_op, clippy::identity_op)]
2786        Self(0 | 0x1)
2787    }
2788}
2789
2790impl Iterator for WlShellSurfaceTransientIter {
2791    type Item = WlShellSurfaceTransient;
2792
2793    fn next(&mut self) -> Option<Self::Item> {
2794        if self.0 == 0 {
2795            return None;
2796        }
2797        let bit = 1 << self.0.trailing_zeros();
2798        self.0 &= !bit;
2799        Some(WlShellSurfaceTransient(bit))
2800    }
2801}
2802
2803impl IntoIterator for WlShellSurfaceTransient {
2804    type Item = WlShellSurfaceTransient;
2805    type IntoIter = WlShellSurfaceTransientIter;
2806
2807    fn into_iter(self) -> Self::IntoIter {
2808        WlShellSurfaceTransientIter(self.0)
2809    }
2810}
2811
2812impl BitAnd for WlShellSurfaceTransient {
2813    type Output = Self;
2814
2815    fn bitand(self, rhs: Self) -> Self::Output {
2816        self.intersection(rhs)
2817    }
2818}
2819
2820impl BitAndAssign for WlShellSurfaceTransient {
2821    fn bitand_assign(&mut self, rhs: Self) {
2822        *self = self.intersection(rhs);
2823    }
2824}
2825
2826impl BitOr for WlShellSurfaceTransient {
2827    type Output = Self;
2828
2829    fn bitor(self, rhs: Self) -> Self::Output {
2830        self.union(rhs)
2831    }
2832}
2833
2834impl BitOrAssign for WlShellSurfaceTransient {
2835    fn bitor_assign(&mut self, rhs: Self) {
2836        *self = self.union(rhs);
2837    }
2838}
2839
2840impl BitXor for WlShellSurfaceTransient {
2841    type Output = Self;
2842
2843    fn bitxor(self, rhs: Self) -> Self::Output {
2844        self.symmetric_difference(rhs)
2845    }
2846}
2847
2848impl BitXorAssign for WlShellSurfaceTransient {
2849    fn bitxor_assign(&mut self, rhs: Self) {
2850        *self = self.symmetric_difference(rhs);
2851    }
2852}
2853
2854impl Sub for WlShellSurfaceTransient {
2855    type Output = Self;
2856
2857    fn sub(self, rhs: Self) -> Self::Output {
2858        self.difference(rhs)
2859    }
2860}
2861
2862impl SubAssign for WlShellSurfaceTransient {
2863    fn sub_assign(&mut self, rhs: Self) {
2864        *self = self.difference(rhs);
2865    }
2866}
2867
2868impl Not for WlShellSurfaceTransient {
2869    type Output = Self;
2870
2871    fn not(self) -> Self::Output {
2872        self.complement()
2873    }
2874}
2875
2876impl Debug for WlShellSurfaceTransient {
2877    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2878        let mut v = self.0;
2879        let mut first = true;
2880        if v & 0x1 == 0x1 {
2881            v &= !0x1;
2882            if first {
2883                first = false;
2884            } else {
2885                f.write_str(" | ")?;
2886            }
2887            f.write_str("INACTIVE")?;
2888        }
2889        if v != 0 {
2890            if first {
2891                first = false;
2892            } else {
2893                f.write_str(" | ")?;
2894            }
2895            write!(f, "0x{v:032x}")?;
2896        }
2897        if first {
2898            f.write_str("0")?;
2899        }
2900        Ok(())
2901    }
2902}
2903
2904/// different method to set the surface fullscreen
2905///
2906/// Hints to indicate to the compositor how to deal with a conflict
2907/// between the dimensions of the surface and the dimensions of the
2908/// output. The compositor is free to ignore this parameter.
2909#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
2910pub struct WlShellSurfaceFullscreenMethod(pub u32);
2911
2912impl WlShellSurfaceFullscreenMethod {
2913    /// no preference, apply default policy
2914    pub const DEFAULT: Self = Self(0);
2915
2916    /// scale, preserve the surface's aspect ratio and center on output
2917    pub const SCALE: Self = Self(1);
2918
2919    /// switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch
2920    pub const DRIVER: Self = Self(2);
2921
2922    /// no upscaling, center on output and add black borders to compensate size mismatch
2923    pub const FILL: Self = Self(3);
2924}
2925
2926impl Debug for WlShellSurfaceFullscreenMethod {
2927    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2928        let name = match *self {
2929            Self::DEFAULT => "DEFAULT",
2930            Self::SCALE => "SCALE",
2931            Self::DRIVER => "DRIVER",
2932            Self::FILL => "FILL",
2933            _ => return Debug::fmt(&self.0, f),
2934        };
2935        f.write_str(name)
2936    }
2937}