client.rs

  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}