client.rs

   1use core::hash;
   2use std::cell::{RefCell, RefMut};
   3use std::ffi::OsString;
   4use std::ops::{Deref, DerefMut};
   5use std::os::fd::{AsRawFd, BorrowedFd};
   6use std::path::PathBuf;
   7use std::rc::{Rc, Weak};
   8use std::sync::Arc;
   9use std::time::{Duration, Instant};
  10
  11use async_task::Runnable;
  12use calloop::timer::{TimeoutAction, Timer};
  13use calloop::{EventLoop, LoopHandle};
  14use calloop_wayland_source::WaylandSource;
  15use collections::HashMap;
  16use copypasta::wayland_clipboard::{create_clipboards_from_external, Clipboard, Primary};
  17use copypasta::ClipboardProvider;
  18use filedescriptor::Pipe;
  19use parking_lot::Mutex;
  20use smallvec::SmallVec;
  21use util::ResultExt;
  22use wayland_backend::client::ObjectId;
  23use wayland_backend::protocol::WEnum;
  24use wayland_client::event_created_child;
  25use wayland_client::globals::{registry_queue_init, GlobalList, GlobalListContents};
  26use wayland_client::protocol::wl_callback::{self, WlCallback};
  27use wayland_client::protocol::wl_data_device_manager::DndAction;
  28use wayland_client::protocol::wl_pointer::AxisSource;
  29use wayland_client::protocol::wl_seat::WlSeat;
  30use wayland_client::protocol::{
  31    wl_data_device, wl_data_device_manager, wl_data_offer, wl_data_source, wl_output, wl_region,
  32};
  33use wayland_client::{
  34    delegate_noop,
  35    protocol::{
  36        wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat, wl_shm,
  37        wl_shm_pool, wl_surface,
  38    },
  39    Connection, Dispatch, Proxy, QueueHandle,
  40};
  41use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::Shape;
  42use wayland_protocols::wp::cursor_shape::v1::client::{
  43    wp_cursor_shape_device_v1, wp_cursor_shape_manager_v1,
  44};
  45use wayland_protocols::wp::fractional_scale::v1::client::{
  46    wp_fractional_scale_manager_v1, wp_fractional_scale_v1,
  47};
  48use wayland_protocols::wp::text_input::zv3::client::zwp_text_input_v3::{
  49    ContentHint, ContentPurpose,
  50};
  51use wayland_protocols::wp::text_input::zv3::client::{
  52    zwp_text_input_manager_v3, zwp_text_input_v3,
  53};
  54use wayland_protocols::wp::viewporter::client::{wp_viewport, wp_viewporter};
  55use wayland_protocols::xdg::activation::v1::client::{xdg_activation_token_v1, xdg_activation_v1};
  56use wayland_protocols::xdg::decoration::zv1::client::{
  57    zxdg_decoration_manager_v1, zxdg_toplevel_decoration_v1,
  58};
  59use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
  60use wayland_protocols_plasma::blur::client::{org_kde_kwin_blur, org_kde_kwin_blur_manager};
  61use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
  62use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS};
  63
  64use super::super::{open_uri_internal, read_fd, DOUBLE_CLICK_INTERVAL};
  65use super::window::{ImeInput, WaylandWindowState, WaylandWindowStatePtr};
  66use crate::platform::linux::is_within_click_distance;
  67use crate::platform::linux::wayland::cursor::Cursor;
  68use crate::platform::linux::wayland::serial::{SerialKind, SerialTracker};
  69use crate::platform::linux::wayland::window::WaylandWindow;
  70use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource};
  71use crate::platform::linux::LinuxClient;
  72use crate::platform::PlatformWindow;
  73use crate::{
  74    point, px, Bounds, FileDropEvent, ForegroundExecutor, MouseExitEvent, WindowAppearance,
  75    SCROLL_LINES,
  76};
  77use crate::{
  78    AnyWindowHandle, CursorStyle, DisplayId, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers,
  79    ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
  80    NavigationDirection, Pixels, PlatformDisplay, PlatformInput, Point, ScrollDelta,
  81    ScrollWheelEvent, TouchPhase,
  82};
  83use crate::{LinuxCommon, WindowParams};
  84
  85/// Used to convert evdev scancode to xkb scancode
  86const MIN_KEYCODE: u32 = 8;
  87
  88#[derive(Clone)]
  89pub struct Globals {
  90    pub qh: QueueHandle<WaylandClientStatePtr>,
  91    pub activation: Option<xdg_activation_v1::XdgActivationV1>,
  92    pub compositor: wl_compositor::WlCompositor,
  93    pub cursor_shape_manager: Option<wp_cursor_shape_manager_v1::WpCursorShapeManagerV1>,
  94    pub data_device_manager: Option<wl_data_device_manager::WlDataDeviceManager>,
  95    pub wm_base: xdg_wm_base::XdgWmBase,
  96    pub shm: wl_shm::WlShm,
  97    pub seat: wl_seat::WlSeat,
  98    pub viewporter: Option<wp_viewporter::WpViewporter>,
  99    pub fractional_scale_manager:
 100        Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
 101    pub decoration_manager: Option<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1>,
 102    pub blur_manager: Option<org_kde_kwin_blur_manager::OrgKdeKwinBlurManager>,
 103    pub text_input_manager: Option<zwp_text_input_manager_v3::ZwpTextInputManagerV3>,
 104    pub executor: ForegroundExecutor,
 105}
 106
 107impl Globals {
 108    fn new(
 109        globals: GlobalList,
 110        executor: ForegroundExecutor,
 111        qh: QueueHandle<WaylandClientStatePtr>,
 112        seat: wl_seat::WlSeat,
 113    ) -> Self {
 114        Globals {
 115            activation: globals.bind(&qh, 1..=1, ()).ok(),
 116            compositor: globals
 117                .bind(
 118                    &qh,
 119                    wl_surface::REQ_SET_BUFFER_SCALE_SINCE
 120                        ..=wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE,
 121                    (),
 122                )
 123                .unwrap(),
 124            cursor_shape_manager: globals.bind(&qh, 1..=1, ()).ok(),
 125            data_device_manager: globals
 126                .bind(
 127                    &qh,
 128                    WL_DATA_DEVICE_MANAGER_VERSION..=WL_DATA_DEVICE_MANAGER_VERSION,
 129                    (),
 130                )
 131                .ok(),
 132            shm: globals.bind(&qh, 1..=1, ()).unwrap(),
 133            seat,
 134            wm_base: globals.bind(&qh, 1..=1, ()).unwrap(),
 135            viewporter: globals.bind(&qh, 1..=1, ()).ok(),
 136            fractional_scale_manager: globals.bind(&qh, 1..=1, ()).ok(),
 137            decoration_manager: globals.bind(&qh, 1..=1, ()).ok(),
 138            blur_manager: globals.bind(&qh, 1..=1, ()).ok(),
 139            text_input_manager: globals.bind(&qh, 1..=1, ()).ok(),
 140            executor,
 141            qh,
 142        }
 143    }
 144}
 145
 146pub(crate) struct WaylandClientState {
 147    serial_tracker: SerialTracker,
 148    globals: Globals,
 149    wl_seat: wl_seat::WlSeat, // todo(linux): multi-seat support
 150    wl_pointer: Option<wl_pointer::WlPointer>,
 151    cursor_shape_device: Option<wp_cursor_shape_device_v1::WpCursorShapeDeviceV1>,
 152    data_device: Option<wl_data_device::WlDataDevice>,
 153    text_input: Option<zwp_text_input_v3::ZwpTextInputV3>,
 154    pre_edit_text: Option<String>,
 155    composing: bool,
 156    // Surface to Window mapping
 157    windows: HashMap<ObjectId, WaylandWindowStatePtr>,
 158    // Output to scale mapping
 159    output_scales: HashMap<ObjectId, i32>,
 160    keymap_state: Option<xkb::State>,
 161    compose_state: Option<xkb::compose::State>,
 162    drag: DragState,
 163    click: ClickState,
 164    repeat: KeyRepeat,
 165    modifiers: Modifiers,
 166    axis_source: AxisSource,
 167    mouse_location: Option<Point<Pixels>>,
 168    continuous_scroll_delta: Option<Point<Pixels>>,
 169    discrete_scroll_delta: Option<Point<f32>>,
 170    vertical_modifier: f32,
 171    horizontal_modifier: f32,
 172    scroll_event_received: bool,
 173    enter_token: Option<()>,
 174    button_pressed: Option<MouseButton>,
 175    mouse_focused_window: Option<WaylandWindowStatePtr>,
 176    keyboard_focused_window: Option<WaylandWindowStatePtr>,
 177    loop_handle: LoopHandle<'static, WaylandClientStatePtr>,
 178    cursor_style: Option<CursorStyle>,
 179    cursor: Cursor,
 180    clipboard: Option<Clipboard>,
 181    primary: Option<Primary>,
 182    event_loop: Option<EventLoop<'static, WaylandClientStatePtr>>,
 183    common: LinuxCommon,
 184
 185    pending_open_uri: Option<String>,
 186}
 187
 188pub struct DragState {
 189    data_offer: Option<wl_data_offer::WlDataOffer>,
 190    window: Option<WaylandWindowStatePtr>,
 191    position: Point<Pixels>,
 192}
 193
 194pub struct ClickState {
 195    last_click: Instant,
 196    last_location: Point<Pixels>,
 197    current_count: usize,
 198}
 199
 200pub(crate) struct KeyRepeat {
 201    characters_per_second: u32,
 202    delay: Duration,
 203    current_id: u64,
 204    current_keycode: Option<xkb::Keycode>,
 205}
 206
 207/// This struct is required to conform to Rust's orphan rules, so we can dispatch on the state but hand the
 208/// window to GPUI.
 209#[derive(Clone)]
 210pub struct WaylandClientStatePtr(Weak<RefCell<WaylandClientState>>);
 211
 212impl WaylandClientStatePtr {
 213    fn get_client(&self) -> Rc<RefCell<WaylandClientState>> {
 214        self.0
 215            .upgrade()
 216            .expect("The pointer should always be valid when dispatching in wayland")
 217    }
 218
 219    pub fn get_serial(&self, kind: SerialKind) -> u32 {
 220        self.0.upgrade().unwrap().borrow().serial_tracker.get(kind)
 221    }
 222
 223    pub fn enable_ime(&self) {
 224        let client = self.get_client();
 225        let mut state = client.borrow_mut();
 226        let Some(mut text_input) = state.text_input.take() else {
 227            return;
 228        };
 229
 230        text_input.enable();
 231        text_input.set_content_type(ContentHint::None, ContentPurpose::Normal);
 232        if let Some(window) = state.keyboard_focused_window.clone() {
 233            drop(state);
 234            if let Some(area) = window.get_ime_area() {
 235                text_input.set_cursor_rectangle(
 236                    area.origin.x.0 as i32,
 237                    area.origin.y.0 as i32,
 238                    area.size.width.0 as i32,
 239                    area.size.height.0 as i32,
 240                );
 241            }
 242            state = client.borrow_mut();
 243        }
 244        text_input.commit();
 245        state.text_input = Some(text_input);
 246    }
 247
 248    pub fn disable_ime(&self) {
 249        let client = self.get_client();
 250        let mut state = client.borrow_mut();
 251        state.composing = false;
 252        if let Some(text_input) = &state.text_input {
 253            text_input.disable();
 254            text_input.commit();
 255        }
 256    }
 257
 258    pub fn drop_window(&self, surface_id: &ObjectId) {
 259        let mut client = self.get_client();
 260        let mut state = client.borrow_mut();
 261        let closed_window = state.windows.remove(surface_id).unwrap();
 262        if let Some(window) = state.mouse_focused_window.take() {
 263            if !window.ptr_eq(&closed_window) {
 264                state.mouse_focused_window = Some(window);
 265            }
 266        }
 267        if let Some(window) = state.keyboard_focused_window.take() {
 268            if !window.ptr_eq(&closed_window) {
 269                state.keyboard_focused_window = Some(window);
 270            }
 271        }
 272        if state.windows.is_empty() {
 273            state.common.signal.stop();
 274        }
 275    }
 276}
 277
 278#[derive(Clone)]
 279pub struct WaylandClient(Rc<RefCell<WaylandClientState>>);
 280
 281impl Drop for WaylandClient {
 282    fn drop(&mut self) {
 283        let mut state = self.0.borrow_mut();
 284        state.windows.clear();
 285
 286        // Drop the clipboard to prevent a seg fault after we've closed all Wayland connections.
 287        state.primary = None;
 288        state.clipboard = None;
 289        if let Some(wl_pointer) = &state.wl_pointer {
 290            wl_pointer.release();
 291        }
 292        if let Some(cursor_shape_device) = &state.cursor_shape_device {
 293            cursor_shape_device.destroy();
 294        }
 295        if let Some(data_device) = &state.data_device {
 296            data_device.release();
 297        }
 298        if let Some(text_input) = &state.text_input {
 299            text_input.destroy();
 300        }
 301    }
 302}
 303
 304const WL_DATA_DEVICE_MANAGER_VERSION: u32 = 3;
 305const WL_OUTPUT_VERSION: u32 = 2;
 306
 307fn wl_seat_version(version: u32) -> u32 {
 308    // We rely on the wl_pointer.frame event
 309    const WL_SEAT_MIN_VERSION: u32 = 5;
 310    const WL_SEAT_MAX_VERSION: u32 = 9;
 311
 312    if version < WL_SEAT_MIN_VERSION {
 313        panic!(
 314            "wl_seat below required version: {} < {}",
 315            version, WL_SEAT_MIN_VERSION
 316        );
 317    }
 318
 319    version.clamp(WL_SEAT_MIN_VERSION, WL_SEAT_MAX_VERSION)
 320}
 321
 322impl WaylandClient {
 323    pub(crate) fn new() -> Self {
 324        let conn = Connection::connect_to_env().unwrap();
 325
 326        let (globals, mut event_queue) =
 327            registry_queue_init::<WaylandClientStatePtr>(&conn).unwrap();
 328        let qh = event_queue.handle();
 329
 330        let mut seat: Option<wl_seat::WlSeat> = None;
 331        let mut outputs = HashMap::default();
 332        globals.contents().with_list(|list| {
 333            for global in list {
 334                match &global.interface[..] {
 335                    "wl_seat" => {
 336                        seat = Some(globals.registry().bind::<wl_seat::WlSeat, _, _>(
 337                            global.name,
 338                            wl_seat_version(global.version),
 339                            &qh,
 340                            (),
 341                        ));
 342                    }
 343                    "wl_output" => {
 344                        let output = globals.registry().bind::<wl_output::WlOutput, _, _>(
 345                            global.name,
 346                            WL_OUTPUT_VERSION,
 347                            &qh,
 348                            (),
 349                        );
 350                        outputs.insert(output.id(), 1);
 351                    }
 352                    _ => {}
 353                }
 354            }
 355        });
 356
 357        let display = conn.backend().display_ptr() as *mut std::ffi::c_void;
 358
 359        let event_loop = EventLoop::<WaylandClientStatePtr>::try_new().unwrap();
 360
 361        let (common, main_receiver) = LinuxCommon::new(event_loop.get_signal());
 362
 363        let handle = event_loop.handle();
 364        handle.insert_source(main_receiver, |event, _, _: &mut WaylandClientStatePtr| {
 365            if let calloop::channel::Event::Msg(runnable) = event {
 366                runnable.run();
 367            }
 368        });
 369
 370        let seat = seat.unwrap();
 371        let globals = Globals::new(
 372            globals,
 373            common.foreground_executor.clone(),
 374            qh.clone(),
 375            seat.clone(),
 376        );
 377
 378        let data_device = globals
 379            .data_device_manager
 380            .as_ref()
 381            .map(|data_device_manager| data_device_manager.get_data_device(&seat, &qh, ()));
 382
 383        let (primary, clipboard) = unsafe { create_clipboards_from_external(display) };
 384
 385        let cursor = Cursor::new(&conn, &globals, 24);
 386
 387        handle.insert_source(XDPEventSource::new(&common.background_executor), {
 388            move |event, _, client| match event {
 389                XDPEvent::WindowAppearance(appearance) => {
 390                    if let Some(client) = client.0.upgrade() {
 391                        let mut client = client.borrow_mut();
 392
 393                        client.common.appearance = appearance;
 394
 395                        for (_, window) in &mut client.windows {
 396                            window.set_appearance(appearance);
 397                        }
 398                    }
 399                }
 400            }
 401        });
 402
 403        let mut state = Rc::new(RefCell::new(WaylandClientState {
 404            serial_tracker: SerialTracker::new(),
 405            globals,
 406            wl_seat: seat,
 407            wl_pointer: None,
 408            cursor_shape_device: None,
 409            data_device,
 410            text_input: None,
 411            pre_edit_text: None,
 412            composing: false,
 413            output_scales: outputs,
 414            windows: HashMap::default(),
 415            common,
 416            keymap_state: None,
 417            compose_state: None,
 418            drag: DragState {
 419                data_offer: None,
 420                window: None,
 421                position: Point::default(),
 422            },
 423            click: ClickState {
 424                last_click: Instant::now(),
 425                last_location: Point::default(),
 426                current_count: 0,
 427            },
 428            repeat: KeyRepeat {
 429                characters_per_second: 16,
 430                delay: Duration::from_millis(500),
 431                current_id: 0,
 432                current_keycode: None,
 433            },
 434            modifiers: Modifiers {
 435                shift: false,
 436                control: false,
 437                alt: false,
 438                function: false,
 439                platform: false,
 440            },
 441            scroll_event_received: false,
 442            axis_source: AxisSource::Wheel,
 443            mouse_location: None,
 444            continuous_scroll_delta: None,
 445            discrete_scroll_delta: None,
 446            vertical_modifier: -1.0,
 447            horizontal_modifier: -1.0,
 448            button_pressed: None,
 449            mouse_focused_window: None,
 450            keyboard_focused_window: None,
 451            loop_handle: handle.clone(),
 452            enter_token: None,
 453            cursor_style: None,
 454            cursor,
 455            clipboard: Some(clipboard),
 456            primary: Some(primary),
 457            event_loop: Some(event_loop),
 458
 459            pending_open_uri: None,
 460        }));
 461
 462        WaylandSource::new(conn, event_queue).insert(handle);
 463
 464        Self(state)
 465    }
 466}
 467
 468impl LinuxClient for WaylandClient {
 469    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
 470        Vec::new()
 471    }
 472
 473    fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
 474        unimplemented!()
 475    }
 476
 477    fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
 478        None
 479    }
 480
 481    fn open_window(
 482        &self,
 483        handle: AnyWindowHandle,
 484        params: WindowParams,
 485    ) -> Box<dyn PlatformWindow> {
 486        let mut state = self.0.borrow_mut();
 487
 488        let (window, surface_id) = WaylandWindow::new(
 489            state.globals.clone(),
 490            WaylandClientStatePtr(Rc::downgrade(&self.0)),
 491            params,
 492            state.common.appearance,
 493        );
 494        state.windows.insert(surface_id, window.0.clone());
 495
 496        Box::new(window)
 497    }
 498
 499    fn set_cursor_style(&self, style: CursorStyle) {
 500        let mut state = self.0.borrow_mut();
 501
 502        let need_update = state
 503            .cursor_style
 504            .map_or(true, |current_style| current_style != style);
 505
 506        if need_update {
 507            let serial = state.serial_tracker.get(SerialKind::MouseEnter);
 508            state.cursor_style = Some(style);
 509
 510            if let Some(cursor_shape_device) = &state.cursor_shape_device {
 511                cursor_shape_device.set_shape(serial, style.to_shape());
 512            } else if state.mouse_focused_window.is_some() {
 513                // cursor-shape-v1 isn't supported, set the cursor using a surface.
 514                let wl_pointer = state
 515                    .wl_pointer
 516                    .clone()
 517                    .expect("window is focused by pointer");
 518                state
 519                    .cursor
 520                    .set_icon(&wl_pointer, serial, &style.to_icon_name());
 521            }
 522        }
 523    }
 524
 525    fn open_uri(&self, uri: &str) {
 526        let mut state = self.0.borrow_mut();
 527        if let (Some(activation), Some(window)) = (
 528            state.globals.activation.clone(),
 529            state.mouse_focused_window.clone(),
 530        ) {
 531            state.pending_open_uri = Some(uri.to_owned());
 532            let token = activation.get_activation_token(&state.globals.qh, ());
 533            let serial = state.serial_tracker.get(SerialKind::MousePress);
 534            token.set_serial(serial, &state.wl_seat);
 535            token.set_surface(&window.surface());
 536            token.commit();
 537        } else {
 538            open_uri_internal(uri, None);
 539        }
 540    }
 541
 542    fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
 543        f(&mut self.0.borrow_mut().common)
 544    }
 545
 546    fn run(&self) {
 547        let mut event_loop = self
 548            .0
 549            .borrow_mut()
 550            .event_loop
 551            .take()
 552            .expect("App is already running");
 553
 554        event_loop
 555            .run(
 556                None,
 557                &mut WaylandClientStatePtr(Rc::downgrade(&self.0)),
 558                |_| {},
 559            )
 560            .log_err();
 561    }
 562
 563    fn write_to_primary(&self, item: crate::ClipboardItem) {
 564        self.0
 565            .borrow_mut()
 566            .primary
 567            .as_mut()
 568            .unwrap()
 569            .set_contents(item.text);
 570    }
 571
 572    fn write_to_clipboard(&self, item: crate::ClipboardItem) {
 573        self.0
 574            .borrow_mut()
 575            .clipboard
 576            .as_mut()
 577            .unwrap()
 578            .set_contents(item.text);
 579    }
 580
 581    fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
 582        self.0
 583            .borrow_mut()
 584            .primary
 585            .as_mut()
 586            .unwrap()
 587            .get_contents()
 588            .ok()
 589            .map(|s| crate::ClipboardItem {
 590                text: s,
 591                metadata: None,
 592            })
 593    }
 594
 595    fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
 596        self.0
 597            .borrow_mut()
 598            .clipboard
 599            .as_mut()
 600            .unwrap()
 601            .get_contents()
 602            .ok()
 603            .map(|s| crate::ClipboardItem {
 604                text: s,
 605                metadata: None,
 606            })
 607    }
 608}
 609
 610impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStatePtr {
 611    fn event(
 612        this: &mut Self,
 613        registry: &wl_registry::WlRegistry,
 614        event: wl_registry::Event,
 615        _: &GlobalListContents,
 616        _: &Connection,
 617        qh: &QueueHandle<Self>,
 618    ) {
 619        let mut client = this.get_client();
 620        let mut state = client.borrow_mut();
 621
 622        match event {
 623            wl_registry::Event::Global {
 624                name,
 625                interface,
 626                version,
 627            } => match &interface[..] {
 628                "wl_seat" => {
 629                    state.wl_pointer = None;
 630                    registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
 631                }
 632                "wl_output" => {
 633                    let output =
 634                        registry.bind::<wl_output::WlOutput, _, _>(name, WL_OUTPUT_VERSION, qh, ());
 635
 636                    state.output_scales.insert(output.id(), 1);
 637                }
 638                _ => {}
 639            },
 640            wl_registry::Event::GlobalRemove { name: _ } => {}
 641            _ => {}
 642        }
 643    }
 644}
 645
 646delegate_noop!(WaylandClientStatePtr: ignore xdg_activation_v1::XdgActivationV1);
 647delegate_noop!(WaylandClientStatePtr: ignore wl_compositor::WlCompositor);
 648delegate_noop!(WaylandClientStatePtr: ignore wp_cursor_shape_device_v1::WpCursorShapeDeviceV1);
 649delegate_noop!(WaylandClientStatePtr: ignore wp_cursor_shape_manager_v1::WpCursorShapeManagerV1);
 650delegate_noop!(WaylandClientStatePtr: ignore wl_data_device_manager::WlDataDeviceManager);
 651delegate_noop!(WaylandClientStatePtr: ignore wl_shm::WlShm);
 652delegate_noop!(WaylandClientStatePtr: ignore wl_shm_pool::WlShmPool);
 653delegate_noop!(WaylandClientStatePtr: ignore wl_buffer::WlBuffer);
 654delegate_noop!(WaylandClientStatePtr: ignore wl_region::WlRegion);
 655delegate_noop!(WaylandClientStatePtr: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
 656delegate_noop!(WaylandClientStatePtr: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
 657delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur_manager::OrgKdeKwinBlurManager);
 658delegate_noop!(WaylandClientStatePtr: ignore zwp_text_input_manager_v3::ZwpTextInputManagerV3);
 659delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur::OrgKdeKwinBlur);
 660delegate_noop!(WaylandClientStatePtr: ignore wp_viewporter::WpViewporter);
 661delegate_noop!(WaylandClientStatePtr: ignore wp_viewport::WpViewport);
 662
 663impl Dispatch<WlCallback, ObjectId> for WaylandClientStatePtr {
 664    fn event(
 665        state: &mut WaylandClientStatePtr,
 666        _: &wl_callback::WlCallback,
 667        event: wl_callback::Event,
 668        surface_id: &ObjectId,
 669        _: &Connection,
 670        qh: &QueueHandle<Self>,
 671    ) {
 672        let client = state.get_client();
 673        let mut state = client.borrow_mut();
 674        let Some(window) = get_window(&mut state, surface_id) else {
 675            return;
 676        };
 677        drop(state);
 678
 679        match event {
 680            wl_callback::Event::Done { callback_data } => {
 681                window.frame(true);
 682            }
 683            _ => {}
 684        }
 685    }
 686}
 687
 688fn get_window(
 689    mut state: &mut RefMut<WaylandClientState>,
 690    surface_id: &ObjectId,
 691) -> Option<WaylandWindowStatePtr> {
 692    state.windows.get(surface_id).cloned()
 693}
 694
 695impl Dispatch<wl_surface::WlSurface, ()> for WaylandClientStatePtr {
 696    fn event(
 697        this: &mut Self,
 698        surface: &wl_surface::WlSurface,
 699        event: <wl_surface::WlSurface as Proxy>::Event,
 700        _: &(),
 701        _: &Connection,
 702        _: &QueueHandle<Self>,
 703    ) {
 704        let mut client = this.get_client();
 705        let mut state = client.borrow_mut();
 706
 707        let Some(window) = get_window(&mut state, &surface.id()) else {
 708            return;
 709        };
 710        let scales = state.output_scales.clone();
 711        drop(state);
 712
 713        window.handle_surface_event(event, scales);
 714    }
 715}
 716
 717impl Dispatch<wl_output::WlOutput, ()> for WaylandClientStatePtr {
 718    fn event(
 719        this: &mut Self,
 720        output: &wl_output::WlOutput,
 721        event: <wl_output::WlOutput as Proxy>::Event,
 722        _: &(),
 723        _: &Connection,
 724        _: &QueueHandle<Self>,
 725    ) {
 726        let mut client = this.get_client();
 727        let mut state = client.borrow_mut();
 728
 729        let Some(mut output_scale) = state.output_scales.get_mut(&output.id()) else {
 730            return;
 731        };
 732
 733        match event {
 734            wl_output::Event::Scale { factor } => {
 735                *output_scale = factor;
 736            }
 737            _ => {}
 738        }
 739    }
 740}
 741
 742impl Dispatch<xdg_surface::XdgSurface, ObjectId> for WaylandClientStatePtr {
 743    fn event(
 744        state: &mut Self,
 745        xdg_surface: &xdg_surface::XdgSurface,
 746        event: xdg_surface::Event,
 747        surface_id: &ObjectId,
 748        _: &Connection,
 749        _: &QueueHandle<Self>,
 750    ) {
 751        let client = state.get_client();
 752        let mut state = client.borrow_mut();
 753        let Some(window) = get_window(&mut state, surface_id) else {
 754            return;
 755        };
 756        drop(state);
 757        window.handle_xdg_surface_event(event);
 758    }
 759}
 760
 761impl Dispatch<xdg_toplevel::XdgToplevel, ObjectId> for WaylandClientStatePtr {
 762    fn event(
 763        this: &mut Self,
 764        xdg_toplevel: &xdg_toplevel::XdgToplevel,
 765        event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
 766        surface_id: &ObjectId,
 767        _: &Connection,
 768        _: &QueueHandle<Self>,
 769    ) {
 770        let client = this.get_client();
 771        let mut state = client.borrow_mut();
 772        let Some(window) = get_window(&mut state, surface_id) else {
 773            return;
 774        };
 775
 776        drop(state);
 777        let should_close = window.handle_toplevel_event(event);
 778
 779        if should_close {
 780            this.drop_window(surface_id);
 781        }
 782    }
 783}
 784
 785impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
 786    fn event(
 787        _: &mut Self,
 788        wm_base: &xdg_wm_base::XdgWmBase,
 789        event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
 790        _: &(),
 791        _: &Connection,
 792        _: &QueueHandle<Self>,
 793    ) {
 794        if let xdg_wm_base::Event::Ping { serial } = event {
 795            wm_base.pong(serial);
 796        }
 797    }
 798}
 799
 800impl Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ()> for WaylandClientStatePtr {
 801    fn event(
 802        this: &mut Self,
 803        token: &xdg_activation_token_v1::XdgActivationTokenV1,
 804        event: <xdg_activation_token_v1::XdgActivationTokenV1 as Proxy>::Event,
 805        _: &(),
 806        _: &Connection,
 807        _: &QueueHandle<Self>,
 808    ) {
 809        let client = this.get_client();
 810        let mut state = client.borrow_mut();
 811        if let xdg_activation_token_v1::Event::Done { token } = event {
 812            if let Some(uri) = state.pending_open_uri.take() {
 813                open_uri_internal(&uri, Some(&token));
 814            } else {
 815                log::error!("called while pending_open_uri is None");
 816            }
 817        }
 818        token.destroy();
 819    }
 820}
 821
 822impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
 823    fn event(
 824        state: &mut Self,
 825        seat: &wl_seat::WlSeat,
 826        event: wl_seat::Event,
 827        data: &(),
 828        conn: &Connection,
 829        qh: &QueueHandle<Self>,
 830    ) {
 831        if let wl_seat::Event::Capabilities {
 832            capabilities: WEnum::Value(capabilities),
 833        } = event
 834        {
 835            let client = state.get_client();
 836            let mut state = client.borrow_mut();
 837            if capabilities.contains(wl_seat::Capability::Keyboard) {
 838                seat.get_keyboard(qh, ());
 839                state.text_input = state
 840                    .globals
 841                    .text_input_manager
 842                    .as_ref()
 843                    .map(|text_input_manager| text_input_manager.get_text_input(&seat, qh, ()));
 844            }
 845            if capabilities.contains(wl_seat::Capability::Pointer) {
 846                let pointer = seat.get_pointer(qh, ());
 847                state.cursor_shape_device = state
 848                    .globals
 849                    .cursor_shape_manager
 850                    .as_ref()
 851                    .map(|cursor_shape_manager| cursor_shape_manager.get_pointer(&pointer, qh, ()));
 852                state.wl_pointer = Some(pointer);
 853            }
 854        }
 855    }
 856}
 857
 858impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
 859    fn event(
 860        this: &mut Self,
 861        keyboard: &wl_keyboard::WlKeyboard,
 862        event: wl_keyboard::Event,
 863        data: &(),
 864        conn: &Connection,
 865        qh: &QueueHandle<Self>,
 866    ) {
 867        let mut client = this.get_client();
 868        let mut state = client.borrow_mut();
 869        match event {
 870            wl_keyboard::Event::RepeatInfo { rate, delay } => {
 871                state.repeat.characters_per_second = rate as u32;
 872                state.repeat.delay = Duration::from_millis(delay as u64);
 873            }
 874            wl_keyboard::Event::Keymap {
 875                format: WEnum::Value(format),
 876                fd,
 877                size,
 878                ..
 879            } => {
 880                assert_eq!(
 881                    format,
 882                    wl_keyboard::KeymapFormat::XkbV1,
 883                    "Unsupported keymap format"
 884                );
 885                let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
 886                let keymap = unsafe {
 887                    xkb::Keymap::new_from_fd(
 888                        &xkb_context,
 889                        fd,
 890                        size as usize,
 891                        XKB_KEYMAP_FORMAT_TEXT_V1,
 892                        KEYMAP_COMPILE_NO_FLAGS,
 893                    )
 894                    .log_err()
 895                    .flatten()
 896                    .expect("Failed to create keymap")
 897                };
 898                let table = {
 899                    let locale = std::env::var_os("LC_CTYPE").unwrap_or(OsString::from("C"));
 900                    xkb::compose::Table::new_from_locale(
 901                        &xkb_context,
 902                        &locale,
 903                        xkb::compose::COMPILE_NO_FLAGS,
 904                    )
 905                    .log_err()
 906                    .unwrap()
 907                };
 908                state.keymap_state = Some(xkb::State::new(&keymap));
 909                state.compose_state = Some(xkb::compose::State::new(
 910                    &table,
 911                    xkb::compose::STATE_NO_FLAGS,
 912                ));
 913            }
 914            wl_keyboard::Event::Enter { surface, .. } => {
 915                state.keyboard_focused_window = get_window(&mut state, &surface.id());
 916                state.enter_token = Some(());
 917
 918                if let Some(window) = state.keyboard_focused_window.clone() {
 919                    drop(state);
 920                    window.set_focused(true);
 921                }
 922            }
 923            wl_keyboard::Event::Leave { surface, .. } => {
 924                let keyboard_focused_window = get_window(&mut state, &surface.id());
 925                state.keyboard_focused_window = None;
 926                state.enter_token.take();
 927
 928                if let Some(window) = keyboard_focused_window {
 929                    if let Some(ref mut compose) = state.compose_state {
 930                        compose.reset();
 931                    }
 932                    state.pre_edit_text.take();
 933                    drop(state);
 934                    window.handle_ime(ImeInput::DeleteText);
 935                    window.set_focused(false);
 936                }
 937            }
 938            wl_keyboard::Event::Modifiers {
 939                mods_depressed,
 940                mods_latched,
 941                mods_locked,
 942                group,
 943                ..
 944            } => {
 945                let focused_window = state.keyboard_focused_window.clone();
 946                let Some(focused_window) = focused_window else {
 947                    return;
 948                };
 949
 950                let keymap_state = state.keymap_state.as_mut().unwrap();
 951                keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
 952                state.modifiers = Modifiers::from_xkb(keymap_state);
 953
 954                let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 955                    modifiers: state.modifiers,
 956                });
 957
 958                drop(state);
 959                focused_window.handle_input(input);
 960            }
 961            wl_keyboard::Event::Key {
 962                serial,
 963                key,
 964                state: WEnum::Value(key_state),
 965                ..
 966            } => {
 967                state.serial_tracker.update(SerialKind::KeyPress, serial);
 968
 969                let focused_window = state.keyboard_focused_window.clone();
 970                let Some(focused_window) = focused_window else {
 971                    return;
 972                };
 973                let focused_window = focused_window.clone();
 974
 975                let keymap_state = state.keymap_state.as_ref().unwrap();
 976                let keycode = Keycode::from(key + MIN_KEYCODE);
 977                let keysym = keymap_state.key_get_one_sym(keycode);
 978
 979                match key_state {
 980                    wl_keyboard::KeyState::Pressed if !keysym.is_modifier_key() => {
 981                        let mut keystroke =
 982                            Keystroke::from_xkb(&keymap_state, state.modifiers, keycode);
 983                        if let Some(mut compose) = state.compose_state.take() {
 984                            compose.feed(keysym);
 985                            match compose.status() {
 986                                xkb::Status::Composing => {
 987                                    state.pre_edit_text =
 988                                        compose.utf8().or(Keystroke::underlying_dead_key(keysym));
 989                                    let pre_edit =
 990                                        state.pre_edit_text.clone().unwrap_or(String::default());
 991                                    drop(state);
 992                                    focused_window.handle_ime(ImeInput::SetMarkedText(pre_edit));
 993                                    state = client.borrow_mut();
 994                                }
 995
 996                                xkb::Status::Composed => {
 997                                    state.pre_edit_text.take();
 998                                    keystroke.ime_key = compose.utf8();
 999                                    keystroke.key = xkb::keysym_get_name(compose.keysym().unwrap());
1000                                }
1001                                xkb::Status::Cancelled => {
1002                                    let pre_edit = state.pre_edit_text.take();
1003                                    drop(state);
1004                                    if let Some(pre_edit) = pre_edit {
1005                                        focused_window.handle_ime(ImeInput::InsertText(pre_edit));
1006                                    }
1007                                    if let Some(current_key) =
1008                                        Keystroke::underlying_dead_key(keysym)
1009                                    {
1010                                        focused_window
1011                                            .handle_ime(ImeInput::SetMarkedText(current_key));
1012                                    }
1013                                    compose.feed(keysym);
1014                                    state = client.borrow_mut();
1015                                }
1016                                _ => {}
1017                            }
1018                            state.compose_state = Some(compose);
1019                        }
1020                        let input = PlatformInput::KeyDown(KeyDownEvent {
1021                            keystroke: keystroke,
1022                            is_held: false, // todo(linux)
1023                        });
1024
1025                        state.repeat.current_id += 1;
1026                        state.repeat.current_keycode = Some(keycode);
1027
1028                        let rate = state.repeat.characters_per_second;
1029                        let id = state.repeat.current_id;
1030                        state
1031                            .loop_handle
1032                            .insert_source(Timer::from_duration(state.repeat.delay), {
1033                                let input = input.clone();
1034                                move |event, _metadata, this| {
1035                                    let mut client = this.get_client();
1036                                    let mut state = client.borrow_mut();
1037                                    let is_repeating = id == state.repeat.current_id
1038                                        && state.repeat.current_keycode.is_some()
1039                                        && state.keyboard_focused_window.is_some();
1040
1041                                    if !is_repeating {
1042                                        return TimeoutAction::Drop;
1043                                    }
1044
1045                                    let focused_window =
1046                                        state.keyboard_focused_window.as_ref().unwrap().clone();
1047
1048                                    drop(state);
1049                                    focused_window.handle_input(input.clone());
1050
1051                                    TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
1052                                }
1053                            })
1054                            .unwrap();
1055
1056                        drop(state);
1057                        focused_window.handle_input(input);
1058                    }
1059                    wl_keyboard::KeyState::Released if !keysym.is_modifier_key() => {
1060                        let input = PlatformInput::KeyUp(KeyUpEvent {
1061                            keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
1062                        });
1063
1064                        if state.repeat.current_keycode == Some(keycode) {
1065                            state.repeat.current_keycode = None;
1066                        }
1067
1068                        drop(state);
1069                        focused_window.handle_input(input);
1070                    }
1071                    _ => {}
1072                }
1073            }
1074            _ => {}
1075        }
1076    }
1077}
1078impl Dispatch<zwp_text_input_v3::ZwpTextInputV3, ()> for WaylandClientStatePtr {
1079    fn event(
1080        this: &mut Self,
1081        text_input: &zwp_text_input_v3::ZwpTextInputV3,
1082        event: <zwp_text_input_v3::ZwpTextInputV3 as Proxy>::Event,
1083        data: &(),
1084        conn: &Connection,
1085        qhandle: &QueueHandle<Self>,
1086    ) {
1087        let client = this.get_client();
1088        let mut state = client.borrow_mut();
1089        match event {
1090            zwp_text_input_v3::Event::Enter { surface } => {
1091                drop(state);
1092                this.enable_ime();
1093            }
1094            zwp_text_input_v3::Event::Leave { surface } => {
1095                drop(state);
1096                this.disable_ime();
1097            }
1098            zwp_text_input_v3::Event::CommitString { text } => {
1099                state.composing = false;
1100                let Some(window) = state.keyboard_focused_window.clone() else {
1101                    return;
1102                };
1103
1104                if let Some(commit_text) = text {
1105                    drop(state);
1106                    // IBus Intercepts keys like `a`, `b`, but those keys are needed for vim mode.
1107                    // We should only send ASCII characters to Zed, otherwise a user could remap a letter like `か` or `相`.
1108                    if commit_text.len() == 1 {
1109                        window.handle_input(PlatformInput::KeyDown(KeyDownEvent {
1110                            keystroke: Keystroke {
1111                                modifiers: Modifiers::default(),
1112                                key: commit_text.clone(),
1113                                ime_key: Some(commit_text),
1114                            },
1115                            is_held: false,
1116                        }));
1117                    } else {
1118                        window.handle_ime(ImeInput::InsertText(commit_text));
1119                    }
1120                }
1121            }
1122            zwp_text_input_v3::Event::PreeditString {
1123                text,
1124                cursor_begin,
1125                cursor_end,
1126            } => {
1127                state.composing = true;
1128                state.pre_edit_text = text;
1129            }
1130            zwp_text_input_v3::Event::Done { serial } => {
1131                let last_serial = state.serial_tracker.get(SerialKind::InputMethod);
1132                state.serial_tracker.update(SerialKind::InputMethod, serial);
1133                let Some(window) = state.keyboard_focused_window.clone() else {
1134                    return;
1135                };
1136
1137                if let Some(text) = state.pre_edit_text.take() {
1138                    drop(state);
1139                    window.handle_ime(ImeInput::SetMarkedText(text));
1140                    if let Some(area) = window.get_ime_area() {
1141                        text_input.set_cursor_rectangle(
1142                            area.origin.x.0 as i32,
1143                            area.origin.y.0 as i32,
1144                            area.size.width.0 as i32,
1145                            area.size.height.0 as i32,
1146                        );
1147                        if last_serial == serial {
1148                            text_input.commit();
1149                        }
1150                    }
1151                } else {
1152                    drop(state);
1153                    window.handle_ime(ImeInput::DeleteText);
1154                }
1155            }
1156            _ => {}
1157        }
1158    }
1159}
1160
1161fn linux_button_to_gpui(button: u32) -> Option<MouseButton> {
1162    // These values are coming from <linux/input-event-codes.h>.
1163    const BTN_LEFT: u32 = 0x110;
1164    const BTN_RIGHT: u32 = 0x111;
1165    const BTN_MIDDLE: u32 = 0x112;
1166    const BTN_SIDE: u32 = 0x113;
1167    const BTN_EXTRA: u32 = 0x114;
1168    const BTN_FORWARD: u32 = 0x115;
1169    const BTN_BACK: u32 = 0x116;
1170
1171    Some(match button {
1172        BTN_LEFT => MouseButton::Left,
1173        BTN_RIGHT => MouseButton::Right,
1174        BTN_MIDDLE => MouseButton::Middle,
1175        BTN_BACK | BTN_SIDE => MouseButton::Navigate(NavigationDirection::Back),
1176        BTN_FORWARD | BTN_EXTRA => MouseButton::Navigate(NavigationDirection::Forward),
1177        _ => return None,
1178    })
1179}
1180
1181impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
1182    fn event(
1183        this: &mut Self,
1184        wl_pointer: &wl_pointer::WlPointer,
1185        event: wl_pointer::Event,
1186        data: &(),
1187        conn: &Connection,
1188        qh: &QueueHandle<Self>,
1189    ) {
1190        let mut client = this.get_client();
1191        let mut state = client.borrow_mut();
1192
1193        match event {
1194            wl_pointer::Event::Enter {
1195                serial,
1196                surface,
1197                surface_x,
1198                surface_y,
1199                ..
1200            } => {
1201                state.serial_tracker.update(SerialKind::MouseEnter, serial);
1202                state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
1203                state.button_pressed = None;
1204
1205                if let Some(window) = get_window(&mut state, &surface.id()) {
1206                    state.mouse_focused_window = Some(window.clone());
1207                    if state.enter_token.is_some() {
1208                        state.enter_token = None;
1209                    }
1210                    if let Some(style) = state.cursor_style {
1211                        if let Some(cursor_shape_device) = &state.cursor_shape_device {
1212                            cursor_shape_device.set_shape(serial, style.to_shape());
1213                        } else {
1214                            state
1215                                .cursor
1216                                .set_icon(&wl_pointer, serial, &style.to_icon_name());
1217                        }
1218                    }
1219                    drop(state);
1220                    window.set_focused(true);
1221                }
1222            }
1223            wl_pointer::Event::Leave { surface, .. } => {
1224                if let Some(focused_window) = state.mouse_focused_window.clone() {
1225                    let input = PlatformInput::MouseExited(MouseExitEvent {
1226                        position: state.mouse_location.unwrap(),
1227                        pressed_button: state.button_pressed,
1228                        modifiers: state.modifiers,
1229                    });
1230                    state.mouse_focused_window = None;
1231                    state.mouse_location = None;
1232                    state.button_pressed = None;
1233
1234                    drop(state);
1235                    focused_window.handle_input(input);
1236                    focused_window.set_focused(false);
1237                }
1238            }
1239            wl_pointer::Event::Motion {
1240                time,
1241                surface_x,
1242                surface_y,
1243                ..
1244            } => {
1245                if state.mouse_focused_window.is_none() {
1246                    return;
1247                }
1248                state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
1249
1250                if let Some(window) = state.mouse_focused_window.clone() {
1251                    if state
1252                        .keyboard_focused_window
1253                        .as_ref()
1254                        .map_or(false, |keyboard_window| window.ptr_eq(&keyboard_window))
1255                    {
1256                        state.enter_token = None;
1257                    }
1258                    let input = PlatformInput::MouseMove(MouseMoveEvent {
1259                        position: state.mouse_location.unwrap(),
1260                        pressed_button: state.button_pressed,
1261                        modifiers: state.modifiers,
1262                    });
1263                    drop(state);
1264                    window.handle_input(input);
1265                }
1266            }
1267            wl_pointer::Event::Button {
1268                serial,
1269                button,
1270                state: WEnum::Value(button_state),
1271                ..
1272            } => {
1273                state.serial_tracker.update(SerialKind::MousePress, serial);
1274                let button = linux_button_to_gpui(button);
1275                let Some(button) = button else { return };
1276                if state.mouse_focused_window.is_none() {
1277                    return;
1278                }
1279                match button_state {
1280                    wl_pointer::ButtonState::Pressed => {
1281                        if let Some(window) = state.keyboard_focused_window.clone() {
1282                            if state.composing && state.text_input.is_some() {
1283                                let text_input = state.text_input.as_ref().unwrap();
1284                                drop(state);
1285                                // text_input_v3 don't have something like a reset function
1286                                this.disable_ime();
1287                                this.enable_ime();
1288                                window.handle_ime(ImeInput::UnmarkText);
1289                                state = client.borrow_mut();
1290                            } else if let (Some(text), Some(compose)) =
1291                                (state.pre_edit_text.take(), state.compose_state.as_mut())
1292                            {
1293                                compose.reset();
1294                                drop(state);
1295                                window.handle_ime(ImeInput::InsertText(text));
1296                                state = client.borrow_mut();
1297                            }
1298                        }
1299                        let click_elapsed = state.click.last_click.elapsed();
1300
1301                        if click_elapsed < DOUBLE_CLICK_INTERVAL
1302                            && is_within_click_distance(
1303                                state.click.last_location,
1304                                state.mouse_location.unwrap(),
1305                            )
1306                        {
1307                            state.click.current_count += 1;
1308                        } else {
1309                            state.click.current_count = 1;
1310                        }
1311
1312                        state.click.last_click = Instant::now();
1313                        state.click.last_location = state.mouse_location.unwrap();
1314
1315                        state.button_pressed = Some(button);
1316
1317                        if let Some(window) = state.mouse_focused_window.clone() {
1318                            let input = PlatformInput::MouseDown(MouseDownEvent {
1319                                button,
1320                                position: state.mouse_location.unwrap(),
1321                                modifiers: state.modifiers,
1322                                click_count: state.click.current_count,
1323                                first_mouse: state.enter_token.take().is_some(),
1324                            });
1325                            drop(state);
1326                            window.handle_input(input);
1327                        }
1328                    }
1329                    wl_pointer::ButtonState::Released => {
1330                        state.button_pressed = None;
1331
1332                        if let Some(window) = state.mouse_focused_window.clone() {
1333                            let input = PlatformInput::MouseUp(MouseUpEvent {
1334                                button,
1335                                position: state.mouse_location.unwrap(),
1336                                modifiers: state.modifiers,
1337                                click_count: state.click.current_count,
1338                            });
1339                            drop(state);
1340                            window.handle_input(input);
1341                        }
1342                    }
1343                    _ => {}
1344                }
1345            }
1346
1347            // Axis Events
1348            wl_pointer::Event::AxisSource {
1349                axis_source: WEnum::Value(axis_source),
1350            } => {
1351                state.axis_source = axis_source;
1352            }
1353            wl_pointer::Event::Axis {
1354                time,
1355                axis: WEnum::Value(axis),
1356                value,
1357                ..
1358            } => {
1359                if state.axis_source == AxisSource::Wheel {
1360                    return;
1361                }
1362                let axis_modifier = match axis {
1363                    wl_pointer::Axis::VerticalScroll => state.vertical_modifier,
1364                    wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
1365                    _ => 1.0,
1366                };
1367                let supports_relative_direction =
1368                    wl_pointer.version() >= wl_pointer::EVT_AXIS_RELATIVE_DIRECTION_SINCE;
1369                state.scroll_event_received = true;
1370                let scroll_delta = state
1371                    .continuous_scroll_delta
1372                    .get_or_insert(point(px(0.0), px(0.0)));
1373                // TODO: Make nice feeling kinetic scrolling that integrates with the platform's scroll settings
1374                let modifier = 3.0;
1375                match axis {
1376                    wl_pointer::Axis::VerticalScroll => {
1377                        scroll_delta.y += px(value as f32 * modifier * axis_modifier);
1378                    }
1379                    wl_pointer::Axis::HorizontalScroll => {
1380                        scroll_delta.x += px(value as f32 * modifier * axis_modifier);
1381                    }
1382                    _ => unreachable!(),
1383                }
1384            }
1385            wl_pointer::Event::AxisDiscrete {
1386                axis: WEnum::Value(axis),
1387                discrete,
1388            } => {
1389                state.scroll_event_received = true;
1390                let axis_modifier = match axis {
1391                    wl_pointer::Axis::VerticalScroll => state.vertical_modifier,
1392                    wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
1393                    _ => 1.0,
1394                };
1395
1396                let scroll_delta = state.discrete_scroll_delta.get_or_insert(point(0.0, 0.0));
1397                match axis {
1398                    wl_pointer::Axis::VerticalScroll => {
1399                        scroll_delta.y += discrete as f32 * axis_modifier * SCROLL_LINES as f32;
1400                    }
1401                    wl_pointer::Axis::HorizontalScroll => {
1402                        scroll_delta.x += discrete as f32 * axis_modifier * SCROLL_LINES as f32;
1403                    }
1404                    _ => unreachable!(),
1405                }
1406            }
1407            wl_pointer::Event::AxisValue120 {
1408                axis: WEnum::Value(axis),
1409                value120,
1410            } => {
1411                state.scroll_event_received = true;
1412                let axis_modifier = match axis {
1413                    wl_pointer::Axis::VerticalScroll => state.vertical_modifier,
1414                    wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
1415                    _ => unreachable!(),
1416                };
1417
1418                let scroll_delta = state.discrete_scroll_delta.get_or_insert(point(0.0, 0.0));
1419                let wheel_percent = value120 as f32 / 120.0;
1420                match axis {
1421                    wl_pointer::Axis::VerticalScroll => {
1422                        scroll_delta.y += wheel_percent * axis_modifier * SCROLL_LINES as f32;
1423                    }
1424                    wl_pointer::Axis::HorizontalScroll => {
1425                        scroll_delta.x += wheel_percent * axis_modifier * SCROLL_LINES as f32;
1426                    }
1427                    _ => unreachable!(),
1428                }
1429            }
1430            wl_pointer::Event::Frame => {
1431                if state.scroll_event_received {
1432                    state.scroll_event_received = false;
1433                    let continuous = state.continuous_scroll_delta.take();
1434                    let discrete = state.discrete_scroll_delta.take();
1435                    if let Some(continuous) = continuous {
1436                        if let Some(window) = state.mouse_focused_window.clone() {
1437                            let input = PlatformInput::ScrollWheel(ScrollWheelEvent {
1438                                position: state.mouse_location.unwrap(),
1439                                delta: ScrollDelta::Pixels(continuous),
1440                                modifiers: state.modifiers,
1441                                touch_phase: TouchPhase::Moved,
1442                            });
1443                            drop(state);
1444                            window.handle_input(input);
1445                        }
1446                    } else if let Some(discrete) = discrete {
1447                        if let Some(window) = state.mouse_focused_window.clone() {
1448                            let input = PlatformInput::ScrollWheel(ScrollWheelEvent {
1449                                position: state.mouse_location.unwrap(),
1450                                delta: ScrollDelta::Lines(discrete),
1451                                modifiers: state.modifiers,
1452                                touch_phase: TouchPhase::Moved,
1453                            });
1454                            drop(state);
1455                            window.handle_input(input);
1456                        }
1457                    }
1458                }
1459            }
1460            _ => {}
1461        }
1462    }
1463}
1464
1465impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientStatePtr {
1466    fn event(
1467        this: &mut Self,
1468        _: &wp_fractional_scale_v1::WpFractionalScaleV1,
1469        event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
1470        surface_id: &ObjectId,
1471        _: &Connection,
1472        _: &QueueHandle<Self>,
1473    ) {
1474        let client = this.get_client();
1475        let mut state = client.borrow_mut();
1476
1477        let Some(window) = get_window(&mut state, surface_id) else {
1478            return;
1479        };
1480
1481        drop(state);
1482        window.handle_fractional_scale_event(event);
1483    }
1484}
1485
1486impl Dispatch<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, ObjectId>
1487    for WaylandClientStatePtr
1488{
1489    fn event(
1490        this: &mut Self,
1491        _: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
1492        event: zxdg_toplevel_decoration_v1::Event,
1493        surface_id: &ObjectId,
1494        _: &Connection,
1495        _: &QueueHandle<Self>,
1496    ) {
1497        let client = this.get_client();
1498        let mut state = client.borrow_mut();
1499        let Some(window) = get_window(&mut state, surface_id) else {
1500            return;
1501        };
1502
1503        drop(state);
1504        window.handle_toplevel_decoration_event(event);
1505    }
1506}
1507
1508const FILE_LIST_MIME_TYPE: &str = "text/uri-list";
1509
1510impl Dispatch<wl_data_device::WlDataDevice, ()> for WaylandClientStatePtr {
1511    fn event(
1512        this: &mut Self,
1513        _: &wl_data_device::WlDataDevice,
1514        event: wl_data_device::Event,
1515        _: &(),
1516        _: &Connection,
1517        _: &QueueHandle<Self>,
1518    ) {
1519        let client = this.get_client();
1520        let mut state = client.borrow_mut();
1521
1522        match event {
1523            wl_data_device::Event::Enter {
1524                serial,
1525                surface,
1526                x,
1527                y,
1528                id: data_offer,
1529            } => {
1530                state.serial_tracker.update(SerialKind::DataDevice, serial);
1531                if let Some(data_offer) = data_offer {
1532                    let Some(drag_window) = get_window(&mut state, &surface.id()) else {
1533                        return;
1534                    };
1535
1536                    const ACTIONS: DndAction = DndAction::Copy;
1537                    data_offer.set_actions(ACTIONS, ACTIONS);
1538
1539                    let pipe = Pipe::new().unwrap();
1540                    data_offer.receive(FILE_LIST_MIME_TYPE.to_string(), unsafe {
1541                        BorrowedFd::borrow_raw(pipe.write.as_raw_fd())
1542                    });
1543                    let fd = pipe.read;
1544                    drop(pipe.write);
1545
1546                    let read_task = state
1547                        .common
1548                        .background_executor
1549                        .spawn(async { unsafe { read_fd(fd) } });
1550
1551                    let this = this.clone();
1552                    state
1553                        .common
1554                        .foreground_executor
1555                        .spawn(async move {
1556                            let file_list = match read_task.await {
1557                                Ok(list) => list,
1558                                Err(err) => {
1559                                    log::error!("error reading drag and drop pipe: {err:?}");
1560                                    return;
1561                                }
1562                            };
1563
1564                            let paths: SmallVec<[_; 2]> = file_list
1565                                .lines()
1566                                .map(|path| PathBuf::from(path.replace("file://", "")))
1567                                .collect();
1568                            let position = Point::new(x.into(), y.into());
1569
1570                            // Prevent dropping text from other programs.
1571                            if paths.is_empty() {
1572                                data_offer.finish();
1573                                data_offer.destroy();
1574                                return;
1575                            }
1576
1577                            let input = PlatformInput::FileDrop(FileDropEvent::Entered {
1578                                position,
1579                                paths: crate::ExternalPaths(paths),
1580                            });
1581
1582                            let client = this.get_client();
1583                            let mut state = client.borrow_mut();
1584                            state.drag.data_offer = Some(data_offer);
1585                            state.drag.window = Some(drag_window.clone());
1586                            state.drag.position = position;
1587
1588                            drop(state);
1589                            drag_window.handle_input(input);
1590                        })
1591                        .detach();
1592                }
1593            }
1594            wl_data_device::Event::Motion { x, y, .. } => {
1595                let Some(drag_window) = state.drag.window.clone() else {
1596                    return;
1597                };
1598                let position = Point::new(x.into(), y.into());
1599                state.drag.position = position;
1600
1601                let input = PlatformInput::FileDrop(FileDropEvent::Pending { position });
1602                drop(state);
1603                drag_window.handle_input(input);
1604            }
1605            wl_data_device::Event::Leave => {
1606                let Some(drag_window) = state.drag.window.clone() else {
1607                    return;
1608                };
1609                let data_offer = state.drag.data_offer.clone().unwrap();
1610                data_offer.destroy();
1611
1612                state.drag.data_offer = None;
1613                state.drag.window = None;
1614
1615                let input = PlatformInput::FileDrop(FileDropEvent::Exited {});
1616                drop(state);
1617                drag_window.handle_input(input);
1618            }
1619            wl_data_device::Event::Drop => {
1620                let Some(drag_window) = state.drag.window.clone() else {
1621                    return;
1622                };
1623                let data_offer = state.drag.data_offer.clone().unwrap();
1624                data_offer.finish();
1625                data_offer.destroy();
1626
1627                state.drag.data_offer = None;
1628                state.drag.window = None;
1629
1630                let input = PlatformInput::FileDrop(FileDropEvent::Submit {
1631                    position: state.drag.position,
1632                });
1633                drop(state);
1634                drag_window.handle_input(input);
1635            }
1636            _ => {}
1637        }
1638    }
1639
1640    event_created_child!(WaylandClientStatePtr, wl_data_device::WlDataDevice, [
1641        wl_data_device::EVT_DATA_OFFER_OPCODE => (wl_data_offer::WlDataOffer, ()),
1642    ]);
1643}
1644
1645impl Dispatch<wl_data_offer::WlDataOffer, ()> for WaylandClientStatePtr {
1646    fn event(
1647        this: &mut Self,
1648        data_offer: &wl_data_offer::WlDataOffer,
1649        event: wl_data_offer::Event,
1650        _: &(),
1651        _: &Connection,
1652        _: &QueueHandle<Self>,
1653    ) {
1654        let client = this.get_client();
1655        let mut state = client.borrow_mut();
1656
1657        match event {
1658            wl_data_offer::Event::Offer { mime_type } => {
1659                if mime_type == FILE_LIST_MIME_TYPE {
1660                    let serial = state.serial_tracker.get(SerialKind::DataDevice);
1661                    data_offer.accept(serial, Some(mime_type));
1662                }
1663            }
1664            _ => {}
1665        }
1666    }
1667}