native/desktop-linux/src/linux/mouse.rs (135 lines of code) (raw):

use log::debug; use smithay_client_toolkit::{ compositor::SurfaceData, delegate_pointer, reexports::client::{ Connection, Dispatch, Proxy as _, QueueHandle, protocol::{ wl_pointer::{AxisRelativeDirection, WlPointer}, wl_surface::{self, WlSurface}, }, }, seat::pointer::{AxisScroll, PointerEvent, PointerEventKind, PointerHandler}, }; use crate::linux::{ application_state::ApplicationState, events::{ MouseButton, MouseDownEvent, MouseEnteredEvent, MouseExitedEvent, MouseMovedEvent, MouseUpEvent, ScrollData, ScrollWheelEvent, Timestamp, // }, geometry::LogicalPixels, }; impl From<AxisScroll> for ScrollData { fn from(value: AxisScroll) -> Self { let wheel_value120 = if value.value120 != 0 { value.value120 } else { value.discrete * 120 }; Self { delta: LogicalPixels(value.absolute), wheel_value120, is_inverted: value.relative_direction == Some(AxisRelativeDirection::Inverted), is_stop: value.stop, } } } impl PointerHandler for ApplicationState { fn pointer_frame(&mut self, conn: &Connection, qh: &QueueHandle<Self>, _pointer: &WlPointer, events: &[PointerEvent]) { for event in events { let Some(window) = self.windows.get_mut(&event.surface.id()) else { continue; }; let scale = window.current_scale; let window_id = window.window_id; _ = match event.kind { PointerEventKind::Enter { .. } => { window.num_pointer_buttons_down = 0; window.set_cursor = true; let res = self.send_event(MouseEnteredEvent { window_id, location_in_window: event.position.into(), }); if let Some(themed_pointer) = self.themed_pointer.take() { let pointer_surface = themed_pointer.surface(); if let Some(pointer_surface_data) = pointer_surface.data() { #[allow(clippy::cast_possible_truncation)] let pointer_surface_event = wl_surface::Event::PreferredBufferScale { factor: scale.round() as i32, }; debug!("Setting cursor scale to {scale:?}"); Dispatch::<WlSurface, SurfaceData>::event( self, pointer_surface, pointer_surface_event, pointer_surface_data, conn, qh, ); } self.themed_pointer = Some(themed_pointer); } res } PointerEventKind::Leave { .. } => { window.num_pointer_buttons_down = 0; self.send_event(MouseExitedEvent { window_id, location_in_window: event.position.into(), }) } PointerEventKind::Motion { time } => self.send_event(MouseMovedEvent { window_id, location_in_window: event.position.into(), timestamp: Timestamp(time), }), PointerEventKind::Press { button, serial, time } => { if window.num_pointer_buttons_down == 0 { self.last_pointer_down_event_serial = Some(serial); } window.num_pointer_buttons_down += 1; self.send_event(MouseDownEvent { window_id, button: MouseButton(button), location_in_window: event.position.into(), timestamp: Timestamp(time), }) } PointerEventKind::Release { button, serial: _, time } => { // Sometimes the Release event can occur without the Press event beforehand. E.g., when dismissing the window menu. if window.num_pointer_buttons_down > 0 { window.num_pointer_buttons_down -= 1; } self.send_event(MouseUpEvent { window_id, button: MouseButton(button), location_in_window: event.position.into(), timestamp: Timestamp(time), }) } PointerEventKind::Axis { time, horizontal, vertical, .. } => { debug!("wl_pointer vertical={vertical:?}"); self.send_event(ScrollWheelEvent { window_id, location_in_window: event.position.into(), timestamp: Timestamp(time), horizontal_scroll: horizontal.into(), vertical_scroll: vertical.into(), }) } }; } } } delegate_pointer!(ApplicationState);