1use std::rc::Rc;
2use std::sync::Arc;
3
4use parking_lot::Mutex;
5use wayland_client::protocol::wl_callback::WlCallback;
6use wayland_client::{
7 delegate_noop,
8 protocol::{
9 wl_buffer, wl_callback, wl_compositor, wl_keyboard, wl_registry, wl_seat, wl_shm,
10 wl_shm_pool,
11 wl_surface::{self, WlSurface},
12 },
13 Connection, Dispatch, EventQueue, Proxy, QueueHandle,
14};
15use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
16
17use crate::platform::linux::client::Client;
18use crate::platform::linux::wayland::window::WaylandWindow;
19use crate::platform::{LinuxPlatformInner, PlatformWindow};
20use crate::{
21 platform::linux::wayland::window::WaylandWindowState, AnyWindowHandle, DisplayId,
22 PlatformDisplay, WindowOptions,
23};
24
25pub(crate) struct WaylandClientState {
26 compositor: Option<wl_compositor::WlCompositor>,
27 buffer: Option<wl_buffer::WlBuffer>,
28 wm_base: Option<xdg_wm_base::XdgWmBase>,
29 windows: Vec<(xdg_surface::XdgSurface, Rc<WaylandWindowState>)>,
30 platform_inner: Rc<LinuxPlatformInner>,
31}
32
33pub(crate) struct WaylandClient {
34 platform_inner: Rc<LinuxPlatformInner>,
35 conn: Arc<Connection>,
36 state: Mutex<WaylandClientState>,
37 event_queue: Mutex<EventQueue<WaylandClientState>>,
38 qh: Arc<QueueHandle<WaylandClientState>>,
39}
40
41impl WaylandClient {
42 pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>, conn: Arc<Connection>) -> Self {
43 let state = WaylandClientState {
44 compositor: None,
45 buffer: None,
46 wm_base: None,
47 windows: Vec::new(),
48 platform_inner: Rc::clone(&linux_platform_inner),
49 };
50 let event_queue: EventQueue<WaylandClientState> = conn.new_event_queue();
51 let qh = event_queue.handle();
52 Self {
53 platform_inner: linux_platform_inner,
54 conn,
55 state: Mutex::new(state),
56 event_queue: Mutex::new(event_queue),
57 qh: Arc::new(qh),
58 }
59 }
60}
61
62impl Client for WaylandClient {
63 fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
64 let display = self.conn.display();
65 let mut eq = self.event_queue.lock();
66 let _registry = display.get_registry(&self.qh, ());
67
68 eq.roundtrip(&mut self.state.lock()).unwrap();
69
70 on_finish_launching();
71 while !self.platform_inner.state.lock().quit_requested {
72 eq.flush().unwrap();
73 eq.dispatch_pending(&mut self.state.lock()).unwrap();
74 if let Some(guard) = self.conn.prepare_read() {
75 guard.read().unwrap();
76 eq.dispatch_pending(&mut self.state.lock()).unwrap();
77 }
78 if let Ok(runnable) = self.platform_inner.main_receiver.try_recv() {
79 runnable.run();
80 }
81 }
82 }
83
84 fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
85 Vec::new()
86 }
87
88 fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
89 unimplemented!()
90 }
91
92 fn open_window(
93 &self,
94 handle: AnyWindowHandle,
95 options: WindowOptions,
96 ) -> Box<dyn PlatformWindow> {
97 let mut state = self.state.lock();
98
99 let wm_base = state.wm_base.as_ref().unwrap();
100 let compositor = state.compositor.as_ref().unwrap();
101 let wl_surface = compositor.create_surface(&self.qh, ());
102 let xdg_surface = wm_base.get_xdg_surface(&wl_surface, &self.qh, ());
103 let toplevel = xdg_surface.get_toplevel(&self.qh, ());
104 let wl_surface = Arc::new(wl_surface);
105
106 wl_surface.frame(&self.qh, wl_surface.clone());
107 wl_surface.commit();
108
109 let window_state = Rc::new(WaylandWindowState::new(
110 &self.conn,
111 wl_surface.clone(),
112 Arc::new(toplevel),
113 options,
114 ));
115
116 state.windows.push((xdg_surface, Rc::clone(&window_state)));
117 Box::new(WaylandWindow(window_state))
118 }
119}
120
121impl Dispatch<wl_registry::WlRegistry, ()> for WaylandClientState {
122 fn event(
123 state: &mut Self,
124 registry: &wl_registry::WlRegistry,
125 event: wl_registry::Event,
126 _: &(),
127 _: &Connection,
128 qh: &QueueHandle<Self>,
129 ) {
130 if let wl_registry::Event::Global {
131 name, interface, ..
132 } = event
133 {
134 match &interface[..] {
135 "wl_compositor" => {
136 let compositor =
137 registry.bind::<wl_compositor::WlCompositor, _, _>(name, 1, qh, ());
138 state.compositor = Some(compositor);
139 }
140 "xdg_wm_base" => {
141 let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 1, qh, ());
142 state.wm_base = Some(wm_base);
143 }
144 _ => {}
145 };
146 }
147 }
148}
149
150delegate_noop!(WaylandClientState: ignore wl_compositor::WlCompositor);
151delegate_noop!(WaylandClientState: ignore wl_surface::WlSurface);
152delegate_noop!(WaylandClientState: ignore wl_shm::WlShm);
153delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool);
154delegate_noop!(WaylandClientState: ignore wl_buffer::WlBuffer);
155delegate_noop!(WaylandClientState: ignore wl_seat::WlSeat);
156delegate_noop!(WaylandClientState: ignore wl_keyboard::WlKeyboard);
157
158impl Dispatch<WlCallback, Arc<WlSurface>> for WaylandClientState {
159 fn event(
160 state: &mut Self,
161 _: &WlCallback,
162 event: wl_callback::Event,
163 surf: &Arc<WlSurface>,
164 _: &Connection,
165 qh: &QueueHandle<Self>,
166 ) {
167 if let wl_callback::Event::Done { .. } = event {
168 for window in &state.windows {
169 if window.1.surface.id() == surf.id() {
170 window.1.surface.frame(qh, surf.clone());
171 window.1.update();
172 window.1.surface.commit();
173 }
174 }
175 }
176 }
177}
178
179impl Dispatch<xdg_surface::XdgSurface, ()> for WaylandClientState {
180 fn event(
181 state: &mut Self,
182 xdg_surface: &xdg_surface::XdgSurface,
183 event: xdg_surface::Event,
184 _: &(),
185 _: &Connection,
186 _: &QueueHandle<Self>,
187 ) {
188 if let xdg_surface::Event::Configure { serial, .. } = event {
189 xdg_surface.ack_configure(serial);
190 for window in &state.windows {
191 if &window.0 == xdg_surface {
192 window.1.update();
193 window.1.surface.commit();
194 return;
195 }
196 }
197 }
198 }
199}
200
201impl Dispatch<xdg_toplevel::XdgToplevel, ()> for WaylandClientState {
202 fn event(
203 state: &mut Self,
204 xdg_toplevel: &xdg_toplevel::XdgToplevel,
205 event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
206 _: &(),
207 _: &Connection,
208 _: &QueueHandle<Self>,
209 ) {
210 if let xdg_toplevel::Event::Configure {
211 width,
212 height,
213 states: _states,
214 } = event
215 {
216 if width == 0 || height == 0 {
217 return;
218 }
219 for window in &state.windows {
220 if window.1.toplevel.id() == xdg_toplevel.id() {
221 window.1.resize(width, height);
222 window.1.surface.commit();
223 return;
224 }
225 }
226 } else if let xdg_toplevel::Event::Close = event {
227 state.windows.retain(|(_, window)| {
228 if window.toplevel.id() == xdg_toplevel.id() {
229 window.toplevel.destroy();
230 false
231 } else {
232 true
233 }
234 });
235 state.platform_inner.state.lock().quit_requested |= state.windows.is_empty();
236 }
237 }
238}
239
240impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientState {
241 fn event(
242 _: &mut Self,
243 wm_base: &xdg_wm_base::XdgWmBase,
244 event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
245 _: &(),
246 _: &Connection,
247 _: &QueueHandle<Self>,
248 ) {
249 if let xdg_wm_base::Event::Ping { serial } = event {
250 wm_base.pong(serial);
251 }
252 }
253}