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