1 use std::{cell::RefCell, convert::TryInto, rc::Rc};
2 
3 use wayland_client::{
4     protocol::{wl_output, wl_seat, wl_surface},
5     DispatchData,
6 };
7 
8 use wayland_protocols::{
9     unstable::xdg_shell::v6::client::{zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6},
10     xdg_shell::client::xdg_toplevel,
11 };
12 
13 use super::{Event, ShellSurface};
14 
15 pub(crate) struct Zxdg {
16     surface: zxdg_surface_v6::ZxdgSurfaceV6,
17     toplevel: zxdg_toplevel_v6::ZxdgToplevelV6,
18 }
19 
20 impl Zxdg {
create<Impl>( surface: &wl_surface::WlSurface, shell: &zxdg_shell_v6::ZxdgShellV6, implementation: Impl, ) -> Zxdg where Impl: FnMut(Event, DispatchData) + 'static,21     pub(crate) fn create<Impl>(
22         surface: &wl_surface::WlSurface,
23         shell: &zxdg_shell_v6::ZxdgShellV6,
24         implementation: Impl,
25     ) -> Zxdg
26     where
27         Impl: FnMut(Event, DispatchData) + 'static,
28     {
29         let pending_configure = Rc::new(RefCell::new(None));
30         let pending_configure_2 = pending_configure.clone();
31 
32         let implementation = Rc::new(RefCell::new(implementation));
33         let implementation_2 = implementation.clone();
34         let xdgs = shell.get_xdg_surface(surface);
35         xdgs.quick_assign(move |xdgs, evt, ddata| match evt {
36             zxdg_surface_v6::Event::Configure { serial } => {
37                 xdgs.ack_configure(serial);
38                 if let Some((new_size, states)) = pending_configure_2.borrow_mut().take() {
39                     (&mut *implementation_2.borrow_mut())(
40                         Event::Configure { new_size, states },
41                         ddata,
42                     );
43                 }
44             }
45             _ => unreachable!(),
46         });
47         let toplevel = xdgs.get_toplevel();
48         toplevel.quick_assign(move |_, evt, ddata| {
49             match evt {
50                 zxdg_toplevel_v6::Event::Close => {
51                     (&mut *implementation.borrow_mut())(Event::Close, ddata)
52                 }
53                 zxdg_toplevel_v6::Event::Configure { width, height, states } => {
54                     use std::cmp::max;
55                     let new_size = if width == 0 || height == 0 {
56                         // if either w or h is zero, then we get to choose our size
57                         None
58                     } else {
59                         Some((max(width, 1) as u32, max(height, 1) as u32))
60                     };
61                     let translated_states = states
62                         .chunks_exact(4)
63                         .map(|c| u32::from_ne_bytes(c.try_into().unwrap()))
64                         .flat_map(xdg_toplevel::State::from_raw)
65                         .collect::<Vec<_>>();
66 
67                     *pending_configure.borrow_mut() = Some((new_size, translated_states));
68                 }
69                 _ => unreachable!(),
70             }
71         });
72         surface.commit();
73         Zxdg { surface: xdgs.detach(), toplevel: toplevel.detach() }
74     }
75 }
76 
77 impl ShellSurface for Zxdg {
resize(&self, seat: &wl_seat::WlSeat, serial: u32, edges: xdg_toplevel::ResizeEdge)78     fn resize(&self, seat: &wl_seat::WlSeat, serial: u32, edges: xdg_toplevel::ResizeEdge) {
79         self.toplevel.resize(seat, serial, edges as u32);
80     }
81 
move_(&self, seat: &wl_seat::WlSeat, serial: u32)82     fn move_(&self, seat: &wl_seat::WlSeat, serial: u32) {
83         self.toplevel._move(seat, serial);
84     }
85 
set_title(&self, title: String)86     fn set_title(&self, title: String) {
87         self.toplevel.set_title(title);
88     }
89 
set_app_id(&self, app_id: String)90     fn set_app_id(&self, app_id: String) {
91         self.toplevel.set_app_id(app_id);
92     }
93 
set_fullscreen(&self, output: Option<&wl_output::WlOutput>)94     fn set_fullscreen(&self, output: Option<&wl_output::WlOutput>) {
95         self.toplevel.set_fullscreen(output)
96     }
97 
unset_fullscreen(&self)98     fn unset_fullscreen(&self) {
99         self.toplevel.unset_fullscreen();
100     }
101 
set_maximized(&self)102     fn set_maximized(&self) {
103         self.toplevel.set_maximized();
104     }
105 
unset_maximized(&self)106     fn unset_maximized(&self) {
107         self.toplevel.unset_maximized();
108     }
109 
set_minimized(&self)110     fn set_minimized(&self) {
111         self.toplevel.set_minimized();
112     }
113 
show_window_menu(&self, seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32)114     fn show_window_menu(&self, seat: &wl_seat::WlSeat, serial: u32, x: i32, y: i32) {
115         self.toplevel.show_window_menu(seat, serial, x, y);
116     }
117 
set_geometry(&self, x: i32, y: i32, width: i32, height: i32)118     fn set_geometry(&self, x: i32, y: i32, width: i32, height: i32) {
119         self.surface.set_window_geometry(x, y, width, height);
120     }
121 
set_min_size(&self, size: Option<(i32, i32)>)122     fn set_min_size(&self, size: Option<(i32, i32)>) {
123         if let Some((w, h)) = size {
124             self.toplevel.set_min_size(w, h);
125         } else {
126             self.toplevel.set_min_size(0, 0);
127         }
128     }
129 
set_max_size(&self, size: Option<(i32, i32)>)130     fn set_max_size(&self, size: Option<(i32, i32)>) {
131         if let Some((w, h)) = size {
132             self.toplevel.set_max_size(w, h);
133         } else {
134             self.toplevel.set_max_size(0, 0);
135         }
136     }
137 
get_xdg(&self) -> Option<&xdg_toplevel::XdgToplevel>138     fn get_xdg(&self) -> Option<&xdg_toplevel::XdgToplevel> {
139         None
140     }
141 }
142 
143 impl Drop for Zxdg {
drop(&mut self)144     fn drop(&mut self) {
145         self.toplevel.destroy();
146         self.surface.destroy();
147     }
148 }
149