client.rs

  1use std::cell::RefCell;
  2use std::rc::Rc;
  3use std::sync::Arc;
  4use std::time::Duration;
  5
  6use parking_lot::Mutex;
  7use smol::Timer;
  8use wayland_backend::client::ObjectId;
  9use wayland_backend::protocol::WEnum;
 10use wayland_client::protocol::wl_callback::WlCallback;
 11use wayland_client::protocol::wl_pointer::AxisRelativeDirection;
 12use wayland_client::{
 13    delegate_noop,
 14    protocol::{
 15        wl_buffer, wl_callback, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat,
 16        wl_shm, wl_shm_pool,
 17        wl_surface::{self, WlSurface},
 18    },
 19    Connection, Dispatch, EventQueue, Proxy, QueueHandle,
 20};
 21use wayland_protocols::wp::fractional_scale::v1::client::{
 22    wp_fractional_scale_manager_v1, wp_fractional_scale_v1,
 23};
 24use wayland_protocols::wp::viewporter::client::{wp_viewport, wp_viewporter};
 25use wayland_protocols::xdg::decoration::zv1::client::{
 26    zxdg_decoration_manager_v1, zxdg_toplevel_decoration_v1,
 27};
 28use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
 29use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
 30use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS};
 31
 32use crate::platform::linux::client::Client;
 33use crate::platform::linux::wayland::window::{WaylandDecorationState, WaylandWindow};
 34use crate::platform::{LinuxPlatformInner, PlatformWindow};
 35use crate::{
 36    platform::linux::wayland::window::WaylandWindowState, AnyWindowHandle, DisplayId, KeyDownEvent,
 37    KeyUpEvent, Keystroke, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
 38    NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScrollDelta,
 39    ScrollWheelEvent, TouchPhase, WindowOptions,
 40};
 41
 42const MIN_KEYCODE: u32 = 8; // used to convert evdev scancode to xkb scancode
 43
 44pub(crate) struct WaylandClientStateInner {
 45    compositor: Option<wl_compositor::WlCompositor>,
 46    buffer: Option<wl_buffer::WlBuffer>,
 47    wm_base: Option<xdg_wm_base::XdgWmBase>,
 48    viewporter: Option<wp_viewporter::WpViewporter>,
 49    fractional_scale_manager: Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
 50    decoration_manager: Option<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1>,
 51    windows: Vec<(xdg_surface::XdgSurface, Rc<WaylandWindowState>)>,
 52    platform_inner: Rc<LinuxPlatformInner>,
 53    wl_seat: Option<wl_seat::WlSeat>,
 54    keymap_state: Option<xkb::State>,
 55    repeat: KeyRepeat,
 56    modifiers: Modifiers,
 57    scroll_direction: f64,
 58    mouse_location: Option<Point<Pixels>>,
 59    button_pressed: Option<MouseButton>,
 60    mouse_focused_window: Option<Rc<WaylandWindowState>>,
 61    keyboard_focused_window: Option<Rc<WaylandWindowState>>,
 62}
 63
 64#[derive(Clone)]
 65pub(crate) struct WaylandClientState(Rc<RefCell<WaylandClientStateInner>>);
 66
 67pub(crate) struct KeyRepeat {
 68    characters_per_second: u32,
 69    delay: Duration,
 70    current_id: u64,
 71    current_keysym: Option<xkb::Keysym>,
 72}
 73
 74pub(crate) struct WaylandClient {
 75    platform_inner: Rc<LinuxPlatformInner>,
 76    conn: Arc<Connection>,
 77    state: WaylandClientState,
 78    event_queue: Mutex<EventQueue<WaylandClientState>>,
 79    qh: Arc<QueueHandle<WaylandClientState>>,
 80}
 81
 82impl WaylandClient {
 83    pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>, conn: Arc<Connection>) -> Self {
 84        let state = WaylandClientState(Rc::new(RefCell::new(WaylandClientStateInner {
 85            compositor: None,
 86            buffer: None,
 87            wm_base: None,
 88            viewporter: None,
 89            fractional_scale_manager: None,
 90            decoration_manager: None,
 91            windows: Vec::new(),
 92            platform_inner: Rc::clone(&linux_platform_inner),
 93            wl_seat: None,
 94            keymap_state: None,
 95            repeat: KeyRepeat {
 96                characters_per_second: 16,
 97                delay: Duration::from_millis(500),
 98                current_id: 0,
 99                current_keysym: None,
100            },
101            modifiers: Modifiers {
102                shift: false,
103                control: false,
104                alt: false,
105                function: false,
106                command: false,
107            },
108            scroll_direction: -1.0,
109            mouse_location: None,
110            button_pressed: None,
111            mouse_focused_window: None,
112            keyboard_focused_window: None,
113        })));
114        let event_queue: EventQueue<WaylandClientState> = conn.new_event_queue();
115        let qh = event_queue.handle();
116        Self {
117            platform_inner: linux_platform_inner,
118            conn,
119            state,
120            event_queue: Mutex::new(event_queue),
121            qh: Arc::new(qh),
122        }
123    }
124}
125
126impl Client for WaylandClient {
127    fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
128        let display = self.conn.display();
129        let mut eq = self.event_queue.lock();
130        let _registry = display.get_registry(&self.qh, ());
131
132        eq.roundtrip(&mut self.state.clone()).unwrap();
133
134        on_finish_launching();
135        while !self.platform_inner.state.lock().quit_requested {
136            eq.flush().unwrap();
137            eq.dispatch_pending(&mut self.state.clone()).unwrap();
138            if let Some(guard) = self.conn.prepare_read() {
139                guard.read().unwrap();
140                eq.dispatch_pending(&mut self.state.clone()).unwrap();
141            }
142            if let Ok(runnable) = self.platform_inner.main_receiver.try_recv() {
143                runnable.run();
144            }
145        }
146    }
147
148    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
149        Vec::new()
150    }
151
152    fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
153        unimplemented!()
154    }
155
156    fn open_window(
157        &self,
158        handle: AnyWindowHandle,
159        options: WindowOptions,
160    ) -> Box<dyn PlatformWindow> {
161        let mut state = self.state.0.borrow_mut();
162
163        let wm_base = state.wm_base.as_ref().unwrap();
164        let compositor = state.compositor.as_ref().unwrap();
165        let wl_surface = compositor.create_surface(&self.qh, ());
166        let xdg_surface = wm_base.get_xdg_surface(&wl_surface, &self.qh, ());
167        let toplevel = xdg_surface.get_toplevel(&self.qh, ());
168        let wl_surface = Arc::new(wl_surface);
169
170        // Attempt to set up window decorations based on the requested configuration
171        //
172        // Note that wayland compositors may either not support decorations at all, or may
173        // support them but not allow clients to choose whether they are enabled or not.
174        // We attempt to account for these cases here.
175
176        if let Some(decoration_manager) = state.decoration_manager.as_ref() {
177            // The protocol for managing decorations is present at least, but that doesn't
178            // mean that the compositor will allow us to use it.
179
180            let decoration =
181                decoration_manager.get_toplevel_decoration(&toplevel, &self.qh, xdg_surface.id());
182
183            // todo!(linux) - options.titlebar is lacking information required for wayland.
184            //                Especially, whether a titlebar is wanted in itself.
185            //
186            // Removing the titlebar also removes the entire window frame (ie. the ability to
187            // close, move and resize the window [snapping still works]). This needs additional
188            // handling in Zed, in order to implement drag handlers on a titlebar element.
189            //
190            // Since all of this handling is not present, we request server-side decorations
191            // for now as a stopgap solution.
192            decoration.set_mode(zxdg_toplevel_decoration_v1::Mode::ServerSide);
193        }
194
195        let viewport = state
196            .viewporter
197            .as_ref()
198            .map(|viewporter| viewporter.get_viewport(&wl_surface, &self.qh, ()));
199
200        wl_surface.frame(&self.qh, wl_surface.clone());
201        wl_surface.commit();
202
203        let window_state = Rc::new(WaylandWindowState::new(
204            &self.conn,
205            wl_surface.clone(),
206            viewport,
207            Arc::new(toplevel),
208            options,
209        ));
210
211        if let Some(fractional_scale_manager) = state.fractional_scale_manager.as_ref() {
212            fractional_scale_manager.get_fractional_scale(&wl_surface, &self.qh, xdg_surface.id());
213        }
214
215        state.windows.push((xdg_surface, Rc::clone(&window_state)));
216        Box::new(WaylandWindow(window_state))
217    }
218}
219
220impl Dispatch<wl_registry::WlRegistry, ()> for WaylandClientState {
221    fn event(
222        state: &mut Self,
223        registry: &wl_registry::WlRegistry,
224        event: wl_registry::Event,
225        _: &(),
226        _: &Connection,
227        qh: &QueueHandle<Self>,
228    ) {
229        let mut state = state.0.borrow_mut();
230        if let wl_registry::Event::Global {
231            name, interface, ..
232        } = event
233        {
234            match &interface[..] {
235                "wl_compositor" => {
236                    let compositor =
237                        registry.bind::<wl_compositor::WlCompositor, _, _>(name, 1, qh, ());
238                    state.compositor = Some(compositor);
239                }
240                "xdg_wm_base" => {
241                    let wm_base = registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 1, qh, ());
242                    state.wm_base = Some(wm_base);
243                }
244                "wl_seat" => {
245                    let seat = registry.bind::<wl_seat::WlSeat, _, _>(name, 4, qh, ());
246                    state.wl_seat = Some(seat);
247                }
248                "wp_fractional_scale_manager_v1" => {
249                    let manager = registry
250                        .bind::<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1, _, _>(
251                        name,
252                        1,
253                        qh,
254                        (),
255                    );
256                    state.fractional_scale_manager = Some(manager);
257                }
258                "wp_viewporter" => {
259                    let view_porter =
260                        registry.bind::<wp_viewporter::WpViewporter, _, _>(name, 1, qh, ());
261                    state.viewporter = Some(view_porter);
262                }
263                "zxdg_decoration_manager_v1" => {
264                    // Unstable and optional
265                    let decoration_manager = registry
266                        .bind::<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1, _, _>(
267                        name,
268                        1,
269                        qh,
270                        (),
271                    );
272                    state.decoration_manager = Some(decoration_manager);
273                }
274                _ => {}
275            };
276        }
277    }
278}
279
280delegate_noop!(WaylandClientState: ignore wl_compositor::WlCompositor);
281delegate_noop!(WaylandClientState: ignore wl_surface::WlSurface);
282delegate_noop!(WaylandClientState: ignore wl_shm::WlShm);
283delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool);
284delegate_noop!(WaylandClientState: ignore wl_buffer::WlBuffer);
285delegate_noop!(WaylandClientState: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
286delegate_noop!(WaylandClientState: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
287delegate_noop!(WaylandClientState: ignore wp_viewporter::WpViewporter);
288delegate_noop!(WaylandClientState: ignore wp_viewport::WpViewport);
289
290impl Dispatch<WlCallback, Arc<WlSurface>> for WaylandClientState {
291    fn event(
292        state: &mut Self,
293        _: &WlCallback,
294        event: wl_callback::Event,
295        surf: &Arc<WlSurface>,
296        _: &Connection,
297        qh: &QueueHandle<Self>,
298    ) {
299        let mut state = state.0.borrow_mut();
300        if let wl_callback::Event::Done { .. } = event {
301            for window in &state.windows {
302                if window.1.surface.id() == surf.id() {
303                    window.1.surface.frame(qh, surf.clone());
304                    window.1.update();
305                    window.1.surface.commit();
306                }
307            }
308        }
309    }
310}
311
312impl Dispatch<xdg_surface::XdgSurface, ()> for WaylandClientState {
313    fn event(
314        state: &mut Self,
315        xdg_surface: &xdg_surface::XdgSurface,
316        event: xdg_surface::Event,
317        _: &(),
318        _: &Connection,
319        _: &QueueHandle<Self>,
320    ) {
321        let mut state = state.0.borrow_mut();
322        if let xdg_surface::Event::Configure { serial, .. } = event {
323            xdg_surface.ack_configure(serial);
324            for window in &state.windows {
325                if &window.0 == xdg_surface {
326                    window.1.update();
327                    window.1.surface.commit();
328                    return;
329                }
330            }
331        }
332    }
333}
334
335impl Dispatch<xdg_toplevel::XdgToplevel, ()> for WaylandClientState {
336    fn event(
337        state: &mut Self,
338        xdg_toplevel: &xdg_toplevel::XdgToplevel,
339        event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
340        _: &(),
341        _: &Connection,
342        _: &QueueHandle<Self>,
343    ) {
344        let mut state = state.0.borrow_mut();
345        if let xdg_toplevel::Event::Configure {
346            width,
347            height,
348            states: _states,
349        } = event
350        {
351            if width == 0 || height == 0 {
352                return;
353            }
354            for window in &state.windows {
355                if window.1.toplevel.id() == xdg_toplevel.id() {
356                    window.1.resize(width, height);
357                    window.1.surface.commit();
358                    return;
359                }
360            }
361        } else if let xdg_toplevel::Event::Close = event {
362            state.windows.retain(|(_, window)| {
363                if window.toplevel.id() == xdg_toplevel.id() {
364                    window.toplevel.destroy();
365                    false
366                } else {
367                    true
368                }
369            });
370            state.platform_inner.state.lock().quit_requested |= state.windows.is_empty();
371        }
372    }
373}
374
375impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientState {
376    fn event(
377        _: &mut Self,
378        wm_base: &xdg_wm_base::XdgWmBase,
379        event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
380        _: &(),
381        _: &Connection,
382        _: &QueueHandle<Self>,
383    ) {
384        if let xdg_wm_base::Event::Ping { serial } = event {
385            wm_base.pong(serial);
386        }
387    }
388}
389
390impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientState {
391    fn event(
392        state: &mut Self,
393        seat: &wl_seat::WlSeat,
394        event: wl_seat::Event,
395        data: &(),
396        conn: &Connection,
397        qh: &QueueHandle<Self>,
398    ) {
399        if let wl_seat::Event::Capabilities {
400            capabilities: WEnum::Value(capabilities),
401        } = event
402        {
403            if capabilities.contains(wl_seat::Capability::Keyboard) {
404                seat.get_keyboard(qh, ());
405            }
406            if capabilities.contains(wl_seat::Capability::Pointer) {
407                seat.get_pointer(qh, ());
408            }
409        }
410    }
411}
412
413impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
414    fn event(
415        this: &mut Self,
416        keyboard: &wl_keyboard::WlKeyboard,
417        event: wl_keyboard::Event,
418        data: &(),
419        conn: &Connection,
420        qh: &QueueHandle<Self>,
421    ) {
422        let mut state = this.0.borrow_mut();
423        match event {
424            wl_keyboard::Event::RepeatInfo { rate, delay } => {
425                state.repeat.characters_per_second = rate as u32;
426                state.repeat.delay = Duration::from_millis(delay as u64);
427            }
428            wl_keyboard::Event::Keymap {
429                format: WEnum::Value(format),
430                fd,
431                size,
432                ..
433            } => {
434                assert_eq!(
435                    format,
436                    wl_keyboard::KeymapFormat::XkbV1,
437                    "Unsupported keymap format"
438                );
439                let keymap = unsafe {
440                    xkb::Keymap::new_from_fd(
441                        &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
442                        fd,
443                        size as usize,
444                        XKB_KEYMAP_FORMAT_TEXT_V1,
445                        KEYMAP_COMPILE_NO_FLAGS,
446                    )
447                    .unwrap()
448                }
449                .unwrap();
450                state.keymap_state = Some(xkb::State::new(&keymap));
451            }
452            wl_keyboard::Event::Enter { surface, .. } => {
453                state.keyboard_focused_window = state
454                    .windows
455                    .iter()
456                    .find(|&w| w.1.surface.id() == surface.id())
457                    .map(|w| w.1.clone());
458
459                if let Some(window) = &state.keyboard_focused_window {
460                    window.set_focused(true);
461                }
462            }
463            wl_keyboard::Event::Leave { surface, .. } => {
464                let keyboard_focused_window = state
465                    .windows
466                    .iter()
467                    .find(|&w| w.1.surface.id() == surface.id())
468                    .map(|w| w.1.clone());
469
470                if let Some(window) = keyboard_focused_window {
471                    window.set_focused(false);
472                }
473
474                state.keyboard_focused_window = None;
475            }
476            wl_keyboard::Event::Modifiers {
477                mods_depressed,
478                mods_latched,
479                mods_locked,
480                group,
481                ..
482            } => {
483                let keymap_state = state.keymap_state.as_mut().unwrap();
484                keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
485
486                let shift =
487                    keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE);
488                let alt =
489                    keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);
490                let control =
491                    keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);
492                let command =
493                    keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE);
494
495                state.modifiers.shift = shift;
496                state.modifiers.alt = alt;
497                state.modifiers.control = control;
498                state.modifiers.command = command;
499            }
500            wl_keyboard::Event::Key {
501                key,
502                state: WEnum::Value(key_state),
503                ..
504            } => {
505                let focused_window = &state.keyboard_focused_window;
506                let Some(focused_window) = focused_window else {
507                    return;
508                };
509
510                let keymap_state = state.keymap_state.as_ref().unwrap();
511                let keycode = Keycode::from(key + MIN_KEYCODE);
512                let keysym = keymap_state.key_get_one_sym(keycode);
513
514                match key_state {
515                    wl_keyboard::KeyState::Pressed => {
516                        let input = PlatformInput::KeyDown(KeyDownEvent {
517                            keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
518                            is_held: false, // todo!(linux)
519                        });
520
521                        focused_window.handle_input(input.clone());
522
523                        if !keysym.is_modifier_key() {
524                            state.repeat.current_id += 1;
525                            state.repeat.current_keysym = Some(keysym);
526
527                            let rate = state.repeat.characters_per_second;
528                            let delay = state.repeat.delay;
529                            let id = state.repeat.current_id;
530                            let this = this.clone();
531
532                            state
533                                .platform_inner
534                                .foreground_executor
535                                .spawn(async move {
536                                    let mut wait_time = delay;
537
538                                    loop {
539                                        Timer::after(wait_time).await;
540
541                                        let state = this.0.borrow_mut();
542                                        let is_repeating = id == state.repeat.current_id
543                                            && state.repeat.current_keysym.is_some()
544                                            && state.keyboard_focused_window.is_some();
545
546                                        if !is_repeating {
547                                            return;
548                                        }
549
550                                        state
551                                            .keyboard_focused_window
552                                            .as_ref()
553                                            .unwrap()
554                                            .handle_input(input.clone());
555
556                                        wait_time = Duration::from_secs(1) / rate;
557                                    }
558                                })
559                                .detach();
560                        }
561                    }
562                    wl_keyboard::KeyState::Released => {
563                        focused_window.handle_input(PlatformInput::KeyUp(KeyUpEvent {
564                            keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
565                        }));
566
567                        if !keysym.is_modifier_key() {
568                            state.repeat.current_keysym = None;
569                        }
570                    }
571                    _ => {}
572                }
573            }
574            _ => {}
575        }
576    }
577}
578
579fn linux_button_to_gpui(button: u32) -> Option<MouseButton> {
580    // These values are coming from <linux/input-event-codes.h>.
581    const BTN_LEFT: u32 = 0x110;
582    const BTN_RIGHT: u32 = 0x111;
583    const BTN_MIDDLE: u32 = 0x112;
584    const BTN_SIDE: u32 = 0x113;
585    const BTN_EXTRA: u32 = 0x114;
586    const BTN_FORWARD: u32 = 0x115;
587    const BTN_BACK: u32 = 0x116;
588
589    Some(match button {
590        BTN_LEFT => MouseButton::Left,
591        BTN_RIGHT => MouseButton::Right,
592        BTN_MIDDLE => MouseButton::Middle,
593        BTN_BACK | BTN_SIDE => MouseButton::Navigate(NavigationDirection::Back),
594        BTN_FORWARD | BTN_EXTRA => MouseButton::Navigate(NavigationDirection::Forward),
595        _ => return None,
596    })
597}
598
599impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
600    fn event(
601        state: &mut Self,
602        wl_pointer: &wl_pointer::WlPointer,
603        event: wl_pointer::Event,
604        data: &(),
605        conn: &Connection,
606        qh: &QueueHandle<Self>,
607    ) {
608        let mut state = state.0.borrow_mut();
609        match event {
610            wl_pointer::Event::Enter {
611                surface,
612                surface_x,
613                surface_y,
614                ..
615            } => {
616                let mut mouse_focused_window = None;
617                for window in &state.windows {
618                    if window.1.surface.id() == surface.id() {
619                        mouse_focused_window = Some(Rc::clone(&window.1));
620                    }
621                }
622                if mouse_focused_window.is_some() {
623                    state.mouse_focused_window = mouse_focused_window;
624                }
625
626                state.mouse_location = Some(Point {
627                    x: Pixels::from(surface_x),
628                    y: Pixels::from(surface_y),
629                });
630            }
631            wl_pointer::Event::Motion {
632                time,
633                surface_x,
634                surface_y,
635                ..
636            } => {
637                if state.mouse_focused_window.is_none() {
638                    return;
639                }
640                state.mouse_location = Some(Point {
641                    x: Pixels::from(surface_x),
642                    y: Pixels::from(surface_y),
643                });
644                state.mouse_focused_window.as_ref().unwrap().handle_input(
645                    PlatformInput::MouseMove(MouseMoveEvent {
646                        position: state.mouse_location.unwrap(),
647                        pressed_button: state.button_pressed,
648                        modifiers: state.modifiers,
649                    }),
650                );
651            }
652            wl_pointer::Event::Button {
653                button,
654                state: WEnum::Value(button_state),
655                ..
656            } => {
657                let button = linux_button_to_gpui(button);
658                let Some(button) = button else { return };
659                if state.mouse_focused_window.is_none() || state.mouse_location.is_none() {
660                    return;
661                }
662                match button_state {
663                    wl_pointer::ButtonState::Pressed => {
664                        state.button_pressed = Some(button);
665                        state.mouse_focused_window.as_ref().unwrap().handle_input(
666                            PlatformInput::MouseDown(MouseDownEvent {
667                                button,
668                                position: state.mouse_location.unwrap(),
669                                modifiers: state.modifiers,
670                                click_count: 1,
671                            }),
672                        );
673                    }
674                    wl_pointer::ButtonState::Released => {
675                        state.button_pressed = None;
676                        state.mouse_focused_window.as_ref().unwrap().handle_input(
677                            PlatformInput::MouseUp(MouseUpEvent {
678                                button,
679                                position: state.mouse_location.unwrap(),
680                                modifiers: Modifiers::default(),
681                                click_count: 1,
682                            }),
683                        );
684                    }
685                    _ => {}
686                }
687            }
688            wl_pointer::Event::AxisRelativeDirection {
689                direction: WEnum::Value(direction),
690                ..
691            } => {
692                state.scroll_direction = match direction {
693                    AxisRelativeDirection::Identical => -1.0,
694                    AxisRelativeDirection::Inverted => 1.0,
695                    _ => -1.0,
696                }
697            }
698            wl_pointer::Event::Axis {
699                time,
700                axis: WEnum::Value(axis),
701                value,
702                ..
703            } => {
704                let focused_window = &state.mouse_focused_window;
705                let mouse_location = &state.mouse_location;
706                if let (Some(focused_window), Some(mouse_location)) =
707                    (focused_window, mouse_location)
708                {
709                    let value = value * state.scroll_direction;
710                    focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent {
711                        position: *mouse_location,
712                        delta: match axis {
713                            wl_pointer::Axis::VerticalScroll => {
714                                ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32)))
715                            }
716                            wl_pointer::Axis::HorizontalScroll => {
717                                ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0)))
718                            }
719                            _ => unimplemented!(),
720                        },
721                        modifiers: state.modifiers,
722                        touch_phase: TouchPhase::Started,
723                    }))
724                }
725            }
726            wl_pointer::Event::Leave { surface, .. } => {
727                let focused_window = &state.mouse_focused_window;
728                if let Some(focused_window) = focused_window {
729                    focused_window.handle_input(PlatformInput::MouseMove(MouseMoveEvent {
730                        position: Point::<Pixels>::default(),
731                        pressed_button: None,
732                        modifiers: Modifiers::default(),
733                    }));
734                }
735                state.mouse_focused_window = None;
736                state.mouse_location = None;
737            }
738            _ => {}
739        }
740    }
741}
742
743impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientState {
744    fn event(
745        state: &mut Self,
746        _: &wp_fractional_scale_v1::WpFractionalScaleV1,
747        event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
748        id: &ObjectId,
749        _: &Connection,
750        _: &QueueHandle<Self>,
751    ) {
752        let mut state = state.0.borrow_mut();
753        if let wp_fractional_scale_v1::Event::PreferredScale { scale, .. } = event {
754            for window in &state.windows {
755                if window.0.id() == *id {
756                    window.1.rescale(scale as f32 / 120.0);
757                    return;
758                }
759            }
760        }
761    }
762}
763
764impl Dispatch<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, ObjectId>
765    for WaylandClientState
766{
767    fn event(
768        state: &mut Self,
769        _: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
770        event: zxdg_toplevel_decoration_v1::Event,
771        surface_id: &ObjectId,
772        _: &Connection,
773        _: &QueueHandle<Self>,
774    ) {
775        let mut state = state.0.borrow_mut();
776        if let zxdg_toplevel_decoration_v1::Event::Configure { mode, .. } = event {
777            for window in &state.windows {
778                if window.0.id() == *surface_id {
779                    match mode {
780                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => {
781                            window
782                                .1
783                                .set_decoration_state(WaylandDecorationState::Server);
784                        }
785                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => {
786                            window
787                                .1
788                                .set_decoration_state(WaylandDecorationState::Client);
789                        }
790                        WEnum::Value(_) => {
791                            log::warn!("Unknown decoration mode");
792                        }
793                        WEnum::Unknown(v) => {
794                            log::warn!("Unknown decoration mode: {}", v);
795                        }
796                    }
797                    return;
798                }
799            }
800        }
801    }
802}