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}