client.rs

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