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