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, |event, _, _: &mut WaylandClientStatePtr| {
 407                if let calloop::channel::Event::Msg(runnable) = event {
 408                    runnable.run();
 409                }
 410            })
 411            .unwrap();
 412
 413        let seat = seat.unwrap();
 414        let globals = Globals::new(
 415            globals,
 416            common.foreground_executor.clone(),
 417            qh.clone(),
 418            seat.clone(),
 419        );
 420
 421        let data_device = globals
 422            .data_device_manager
 423            .as_ref()
 424            .map(|data_device_manager| data_device_manager.get_data_device(&seat, &qh, ()));
 425
 426        let (primary, clipboard) = unsafe { create_clipboards_from_external(display) };
 427
 428        let cursor = Cursor::new(&conn, &globals, 24);
 429
 430        handle
 431            .insert_source(XDPEventSource::new(&common.background_executor), {
 432                move |event, _, client| match event {
 433                    XDPEvent::WindowAppearance(appearance) => {
 434                        if let Some(client) = client.0.upgrade() {
 435                            let mut client = client.borrow_mut();
 436
 437                            client.common.appearance = appearance;
 438
 439                            for (_, window) in &mut client.windows {
 440                                window.set_appearance(appearance);
 441                            }
 442                        }
 443                    }
 444                }
 445            })
 446            .unwrap();
 447
 448        let mut state = Rc::new(RefCell::new(WaylandClientState {
 449            serial_tracker: SerialTracker::new(),
 450            globals,
 451            wl_seat: seat,
 452            wl_pointer: None,
 453            wl_keyboard: None,
 454            cursor_shape_device: None,
 455            data_device,
 456            text_input: None,
 457            pre_edit_text: None,
 458            composing: false,
 459            outputs: HashMap::default(),
 460            in_progress_outputs,
 461            windows: HashMap::default(),
 462            common,
 463            keymap_state: None,
 464            compose_state: None,
 465            drag: DragState {
 466                data_offer: None,
 467                window: None,
 468                position: Point::default(),
 469            },
 470            click: ClickState {
 471                last_click: Instant::now(),
 472                last_location: Point::default(),
 473                current_count: 0,
 474            },
 475            repeat: KeyRepeat {
 476                characters_per_second: 16,
 477                delay: Duration::from_millis(500),
 478                current_id: 0,
 479                current_keycode: None,
 480            },
 481            modifiers: Modifiers {
 482                shift: false,
 483                control: false,
 484                alt: false,
 485                function: false,
 486                platform: false,
 487            },
 488            scroll_event_received: false,
 489            axis_source: AxisSource::Wheel,
 490            mouse_location: None,
 491            continuous_scroll_delta: None,
 492            discrete_scroll_delta: None,
 493            vertical_modifier: -1.0,
 494            horizontal_modifier: -1.0,
 495            button_pressed: None,
 496            mouse_focused_window: None,
 497            keyboard_focused_window: None,
 498            loop_handle: handle.clone(),
 499            enter_token: None,
 500            cursor_style: None,
 501            cursor,
 502            clipboard: Some(clipboard),
 503            primary: Some(primary),
 504            event_loop: Some(event_loop),
 505
 506            pending_open_uri: None,
 507        }));
 508
 509        WaylandSource::new(conn, event_queue)
 510            .insert(handle)
 511            .unwrap();
 512
 513        Self(state)
 514    }
 515}
 516
 517impl LinuxClient for WaylandClient {
 518    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
 519        self.0
 520            .borrow()
 521            .outputs
 522            .iter()
 523            .map(|(id, output)| {
 524                Rc::new(WaylandDisplay {
 525                    id: id.clone(),
 526                    name: output.name.clone(),
 527                    bounds: output.bounds,
 528                }) as Rc<dyn PlatformDisplay>
 529            })
 530            .collect()
 531    }
 532
 533    fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
 534        self.0
 535            .borrow()
 536            .outputs
 537            .iter()
 538            .find_map(|(object_id, output)| {
 539                (object_id.protocol_id() == id.0).then(|| {
 540                    Rc::new(WaylandDisplay {
 541                        id: object_id.clone(),
 542                        name: output.name.clone(),
 543                        bounds: output.bounds,
 544                    }) as Rc<dyn PlatformDisplay>
 545                })
 546            })
 547    }
 548
 549    fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
 550        None
 551    }
 552
 553    fn open_window(
 554        &self,
 555        handle: AnyWindowHandle,
 556        params: WindowParams,
 557    ) -> Box<dyn PlatformWindow> {
 558        let mut state = self.0.borrow_mut();
 559
 560        let (window, surface_id) = WaylandWindow::new(
 561            handle,
 562            state.globals.clone(),
 563            WaylandClientStatePtr(Rc::downgrade(&self.0)),
 564            params,
 565            state.common.appearance,
 566        );
 567        state.windows.insert(surface_id, window.0.clone());
 568
 569        Box::new(window)
 570    }
 571
 572    fn set_cursor_style(&self, style: CursorStyle) {
 573        let mut state = self.0.borrow_mut();
 574
 575        let need_update = state
 576            .cursor_style
 577            .map_or(true, |current_style| current_style != style);
 578
 579        if need_update {
 580            let serial = state.serial_tracker.get(SerialKind::MouseEnter);
 581            state.cursor_style = Some(style);
 582
 583            if let Some(cursor_shape_device) = &state.cursor_shape_device {
 584                cursor_shape_device.set_shape(serial, style.to_shape());
 585            } else if state.mouse_focused_window.is_some() {
 586                // cursor-shape-v1 isn't supported, set the cursor using a surface.
 587                let wl_pointer = state
 588                    .wl_pointer
 589                    .clone()
 590                    .expect("window is focused by pointer");
 591                state
 592                    .cursor
 593                    .set_icon(&wl_pointer, serial, &style.to_icon_name());
 594            }
 595        }
 596    }
 597
 598    fn open_uri(&self, uri: &str) {
 599        let mut state = self.0.borrow_mut();
 600        if let (Some(activation), Some(window)) = (
 601            state.globals.activation.clone(),
 602            state.mouse_focused_window.clone(),
 603        ) {
 604            state.pending_open_uri = Some(uri.to_owned());
 605            let token = activation.get_activation_token(&state.globals.qh, ());
 606            let serial = state.serial_tracker.get(SerialKind::MousePress);
 607            token.set_serial(serial, &state.wl_seat);
 608            token.set_surface(&window.surface());
 609            token.commit();
 610        } else {
 611            open_uri_internal(uri, None);
 612        }
 613    }
 614
 615    fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
 616        f(&mut self.0.borrow_mut().common)
 617    }
 618
 619    fn run(&self) {
 620        let mut event_loop = self
 621            .0
 622            .borrow_mut()
 623            .event_loop
 624            .take()
 625            .expect("App is already running");
 626
 627        event_loop
 628            .run(
 629                None,
 630                &mut WaylandClientStatePtr(Rc::downgrade(&self.0)),
 631                |_| {},
 632            )
 633            .log_err();
 634    }
 635
 636    fn write_to_primary(&self, item: crate::ClipboardItem) {
 637        self.0
 638            .borrow_mut()
 639            .primary
 640            .as_mut()
 641            .unwrap()
 642            .set_contents(item.text)
 643            .ok();
 644    }
 645
 646    fn write_to_clipboard(&self, item: crate::ClipboardItem) {
 647        self.0
 648            .borrow_mut()
 649            .clipboard
 650            .as_mut()
 651            .unwrap()
 652            .set_contents(item.text)
 653            .ok();
 654    }
 655
 656    fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
 657        self.0
 658            .borrow_mut()
 659            .primary
 660            .as_mut()
 661            .unwrap()
 662            .get_contents()
 663            .ok()
 664            .map(|s| crate::ClipboardItem {
 665                text: s,
 666                metadata: None,
 667            })
 668    }
 669
 670    fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
 671        self.0
 672            .borrow_mut()
 673            .clipboard
 674            .as_mut()
 675            .unwrap()
 676            .get_contents()
 677            .ok()
 678            .map(|s| crate::ClipboardItem {
 679                text: s,
 680                metadata: None,
 681            })
 682    }
 683
 684    fn active_window(&self) -> Option<AnyWindowHandle> {
 685        self.0
 686            .borrow_mut()
 687            .keyboard_focused_window
 688            .as_ref()
 689            .map(|window| window.handle())
 690    }
 691}
 692
 693impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStatePtr {
 694    fn event(
 695        this: &mut Self,
 696        registry: &wl_registry::WlRegistry,
 697        event: wl_registry::Event,
 698        _: &GlobalListContents,
 699        _: &Connection,
 700        qh: &QueueHandle<Self>,
 701    ) {
 702        let mut client = this.get_client();
 703        let mut state = client.borrow_mut();
 704
 705        match event {
 706            wl_registry::Event::Global {
 707                name,
 708                interface,
 709                version,
 710            } => match &interface[..] {
 711                "wl_seat" => {
 712                    if let Some(wl_pointer) = state.wl_pointer.take() {
 713                        wl_pointer.release();
 714                    }
 715                    if let Some(wl_keyboard) = state.wl_keyboard.take() {
 716                        wl_keyboard.release();
 717                    }
 718                    state.wl_seat.release();
 719                    state.wl_seat = registry.bind::<wl_seat::WlSeat, _, _>(
 720                        name,
 721                        wl_seat_version(version),
 722                        qh,
 723                        (),
 724                    );
 725                }
 726                "wl_output" => {
 727                    let output = registry.bind::<wl_output::WlOutput, _, _>(
 728                        name,
 729                        wl_output_version(version),
 730                        qh,
 731                        (),
 732                    );
 733
 734                    state
 735                        .in_progress_outputs
 736                        .insert(output.id(), InProgressOutput::default());
 737                }
 738                _ => {}
 739            },
 740            wl_registry::Event::GlobalRemove { name: _ } => {
 741                // TODO: handle global removal
 742            }
 743            _ => {}
 744        }
 745    }
 746}
 747
 748delegate_noop!(WaylandClientStatePtr: ignore xdg_activation_v1::XdgActivationV1);
 749delegate_noop!(WaylandClientStatePtr: ignore wl_compositor::WlCompositor);
 750delegate_noop!(WaylandClientStatePtr: ignore wp_cursor_shape_device_v1::WpCursorShapeDeviceV1);
 751delegate_noop!(WaylandClientStatePtr: ignore wp_cursor_shape_manager_v1::WpCursorShapeManagerV1);
 752delegate_noop!(WaylandClientStatePtr: ignore wl_data_device_manager::WlDataDeviceManager);
 753delegate_noop!(WaylandClientStatePtr: ignore wl_shm::WlShm);
 754delegate_noop!(WaylandClientStatePtr: ignore wl_shm_pool::WlShmPool);
 755delegate_noop!(WaylandClientStatePtr: ignore wl_buffer::WlBuffer);
 756delegate_noop!(WaylandClientStatePtr: ignore wl_region::WlRegion);
 757delegate_noop!(WaylandClientStatePtr: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
 758delegate_noop!(WaylandClientStatePtr: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
 759delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur_manager::OrgKdeKwinBlurManager);
 760delegate_noop!(WaylandClientStatePtr: ignore zwp_text_input_manager_v3::ZwpTextInputManagerV3);
 761delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur::OrgKdeKwinBlur);
 762delegate_noop!(WaylandClientStatePtr: ignore wp_viewporter::WpViewporter);
 763delegate_noop!(WaylandClientStatePtr: ignore wp_viewport::WpViewport);
 764
 765impl Dispatch<WlCallback, ObjectId> for WaylandClientStatePtr {
 766    fn event(
 767        state: &mut WaylandClientStatePtr,
 768        _: &wl_callback::WlCallback,
 769        event: wl_callback::Event,
 770        surface_id: &ObjectId,
 771        _: &Connection,
 772        _: &QueueHandle<Self>,
 773    ) {
 774        let client = state.get_client();
 775        let mut state = client.borrow_mut();
 776        let Some(window) = get_window(&mut state, surface_id) else {
 777            return;
 778        };
 779        drop(state);
 780
 781        match event {
 782            wl_callback::Event::Done { .. } => {
 783                window.frame(true);
 784            }
 785            _ => {}
 786        }
 787    }
 788}
 789
 790fn get_window(
 791    mut state: &mut RefMut<WaylandClientState>,
 792    surface_id: &ObjectId,
 793) -> Option<WaylandWindowStatePtr> {
 794    state.windows.get(surface_id).cloned()
 795}
 796
 797impl Dispatch<wl_surface::WlSurface, ()> for WaylandClientStatePtr {
 798    fn event(
 799        this: &mut Self,
 800        surface: &wl_surface::WlSurface,
 801        event: <wl_surface::WlSurface as Proxy>::Event,
 802        _: &(),
 803        _: &Connection,
 804        _: &QueueHandle<Self>,
 805    ) {
 806        let mut client = this.get_client();
 807        let mut state = client.borrow_mut();
 808
 809        let Some(window) = get_window(&mut state, &surface.id()) else {
 810            return;
 811        };
 812        let outputs = state.outputs.clone();
 813        drop(state);
 814
 815        window.handle_surface_event(event, outputs);
 816    }
 817}
 818
 819impl Dispatch<wl_output::WlOutput, ()> for WaylandClientStatePtr {
 820    fn event(
 821        this: &mut Self,
 822        output: &wl_output::WlOutput,
 823        event: <wl_output::WlOutput as Proxy>::Event,
 824        _: &(),
 825        _: &Connection,
 826        _: &QueueHandle<Self>,
 827    ) {
 828        let mut client = this.get_client();
 829        let mut state = client.borrow_mut();
 830
 831        let Some(mut in_progress_output) = state.in_progress_outputs.get_mut(&output.id()) else {
 832            return;
 833        };
 834
 835        match event {
 836            wl_output::Event::Name { name } => {
 837                in_progress_output.name = Some(name);
 838            }
 839            wl_output::Event::Scale { factor } => {
 840                in_progress_output.scale = Some(factor);
 841            }
 842            wl_output::Event::Geometry { x, y, .. } => {
 843                in_progress_output.position = Some(point(DevicePixels(x), DevicePixels(y)))
 844            }
 845            wl_output::Event::Mode { width, height, .. } => {
 846                in_progress_output.size = Some(size(DevicePixels(width), DevicePixels(height)))
 847            }
 848            wl_output::Event::Done => {
 849                if let Some(complete) = in_progress_output.complete() {
 850                    state.outputs.insert(output.id(), complete);
 851                }
 852                state.in_progress_outputs.remove(&output.id());
 853            }
 854            _ => {}
 855        }
 856    }
 857}
 858
 859impl Dispatch<xdg_surface::XdgSurface, ObjectId> for WaylandClientStatePtr {
 860    fn event(
 861        state: &mut Self,
 862        _: &xdg_surface::XdgSurface,
 863        event: xdg_surface::Event,
 864        surface_id: &ObjectId,
 865        _: &Connection,
 866        _: &QueueHandle<Self>,
 867    ) {
 868        let client = state.get_client();
 869        let mut state = client.borrow_mut();
 870        let Some(window) = get_window(&mut state, surface_id) else {
 871            return;
 872        };
 873        drop(state);
 874        window.handle_xdg_surface_event(event);
 875    }
 876}
 877
 878impl Dispatch<xdg_toplevel::XdgToplevel, ObjectId> for WaylandClientStatePtr {
 879    fn event(
 880        this: &mut Self,
 881        _: &xdg_toplevel::XdgToplevel,
 882        event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
 883        surface_id: &ObjectId,
 884        _: &Connection,
 885        _: &QueueHandle<Self>,
 886    ) {
 887        let client = this.get_client();
 888        let mut state = client.borrow_mut();
 889        let Some(window) = get_window(&mut state, surface_id) else {
 890            return;
 891        };
 892
 893        drop(state);
 894        let should_close = window.handle_toplevel_event(event);
 895
 896        if should_close {
 897            this.drop_window(surface_id);
 898        }
 899    }
 900}
 901
 902impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
 903    fn event(
 904        _: &mut Self,
 905        wm_base: &xdg_wm_base::XdgWmBase,
 906        event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
 907        _: &(),
 908        _: &Connection,
 909        _: &QueueHandle<Self>,
 910    ) {
 911        if let xdg_wm_base::Event::Ping { serial } = event {
 912            wm_base.pong(serial);
 913        }
 914    }
 915}
 916
 917impl Dispatch<xdg_activation_token_v1::XdgActivationTokenV1, ()> for WaylandClientStatePtr {
 918    fn event(
 919        this: &mut Self,
 920        token: &xdg_activation_token_v1::XdgActivationTokenV1,
 921        event: <xdg_activation_token_v1::XdgActivationTokenV1 as Proxy>::Event,
 922        _: &(),
 923        _: &Connection,
 924        _: &QueueHandle<Self>,
 925    ) {
 926        let client = this.get_client();
 927        let mut state = client.borrow_mut();
 928        if let xdg_activation_token_v1::Event::Done { token } = event {
 929            if let Some(uri) = state.pending_open_uri.take() {
 930                open_uri_internal(&uri, Some(&token));
 931            } else {
 932                log::error!("called while pending_open_uri is None");
 933            }
 934        }
 935        token.destroy();
 936    }
 937}
 938
 939impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientStatePtr {
 940    fn event(
 941        state: &mut Self,
 942        seat: &wl_seat::WlSeat,
 943        event: wl_seat::Event,
 944        _: &(),
 945        _: &Connection,
 946        qh: &QueueHandle<Self>,
 947    ) {
 948        if let wl_seat::Event::Capabilities {
 949            capabilities: WEnum::Value(capabilities),
 950        } = event
 951        {
 952            let client = state.get_client();
 953            let mut state = client.borrow_mut();
 954            if capabilities.contains(wl_seat::Capability::Keyboard) {
 955                let keyboard = seat.get_keyboard(qh, ());
 956
 957                state.text_input = state
 958                    .globals
 959                    .text_input_manager
 960                    .as_ref()
 961                    .map(|text_input_manager| text_input_manager.get_text_input(&seat, qh, ()));
 962
 963                if let Some(wl_keyboard) = &state.wl_keyboard {
 964                    wl_keyboard.release();
 965                }
 966
 967                state.wl_keyboard = Some(keyboard);
 968            }
 969            if capabilities.contains(wl_seat::Capability::Pointer) {
 970                let pointer = seat.get_pointer(qh, ());
 971                state.cursor_shape_device = state
 972                    .globals
 973                    .cursor_shape_manager
 974                    .as_ref()
 975                    .map(|cursor_shape_manager| cursor_shape_manager.get_pointer(&pointer, qh, ()));
 976
 977                if let Some(wl_pointer) = &state.wl_pointer {
 978                    wl_pointer.release();
 979                }
 980
 981                state.wl_pointer = Some(pointer);
 982            }
 983        }
 984    }
 985}
 986
 987impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientStatePtr {
 988    fn event(
 989        this: &mut Self,
 990        _: &wl_keyboard::WlKeyboard,
 991        event: wl_keyboard::Event,
 992        _: &(),
 993        _: &Connection,
 994        _: &QueueHandle<Self>,
 995    ) {
 996        let mut client = this.get_client();
 997        let mut state = client.borrow_mut();
 998        match event {
 999            wl_keyboard::Event::RepeatInfo { rate, delay } => {
1000                state.repeat.characters_per_second = rate as u32;
1001                state.repeat.delay = Duration::from_millis(delay as u64);
1002            }
1003            wl_keyboard::Event::Keymap {
1004                format: WEnum::Value(format),
1005                fd,
1006                size,
1007                ..
1008            } => {
1009                assert_eq!(
1010                    format,
1011                    wl_keyboard::KeymapFormat::XkbV1,
1012                    "Unsupported keymap format"
1013                );
1014                let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
1015                let keymap = unsafe {
1016                    xkb::Keymap::new_from_fd(
1017                        &xkb_context,
1018                        fd,
1019                        size as usize,
1020                        XKB_KEYMAP_FORMAT_TEXT_V1,
1021                        KEYMAP_COMPILE_NO_FLAGS,
1022                    )
1023                    .log_err()
1024                    .flatten()
1025                    .expect("Failed to create keymap")
1026                };
1027                let table = {
1028                    let locale = std::env::var_os("LC_CTYPE").unwrap_or(OsString::from("C"));
1029                    xkb::compose::Table::new_from_locale(
1030                        &xkb_context,
1031                        &locale,
1032                        xkb::compose::COMPILE_NO_FLAGS,
1033                    )
1034                    .log_err()
1035                    .unwrap()
1036                };
1037                state.keymap_state = Some(xkb::State::new(&keymap));
1038                state.compose_state = Some(xkb::compose::State::new(
1039                    &table,
1040                    xkb::compose::STATE_NO_FLAGS,
1041                ));
1042            }
1043            wl_keyboard::Event::Enter { surface, .. } => {
1044                state.keyboard_focused_window = get_window(&mut state, &surface.id());
1045                state.enter_token = Some(());
1046
1047                if let Some(window) = state.keyboard_focused_window.clone() {
1048                    drop(state);
1049                    window.set_focused(true);
1050                }
1051            }
1052            wl_keyboard::Event::Leave { surface, .. } => {
1053                let keyboard_focused_window = get_window(&mut state, &surface.id());
1054                state.keyboard_focused_window = None;
1055                state.enter_token.take();
1056
1057                if let Some(window) = keyboard_focused_window {
1058                    if let Some(ref mut compose) = state.compose_state {
1059                        compose.reset();
1060                    }
1061                    state.pre_edit_text.take();
1062                    drop(state);
1063                    window.handle_ime(ImeInput::DeleteText);
1064                    window.set_focused(false);
1065                }
1066            }
1067            wl_keyboard::Event::Modifiers {
1068                mods_depressed,
1069                mods_latched,
1070                mods_locked,
1071                group,
1072                ..
1073            } => {
1074                let focused_window = state.keyboard_focused_window.clone();
1075                let Some(focused_window) = focused_window else {
1076                    return;
1077                };
1078
1079                let keymap_state = state.keymap_state.as_mut().unwrap();
1080                keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
1081                state.modifiers = Modifiers::from_xkb(keymap_state);
1082
1083                let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent {
1084                    modifiers: state.modifiers,
1085                });
1086
1087                drop(state);
1088                focused_window.handle_input(input);
1089            }
1090            wl_keyboard::Event::Key {
1091                serial,
1092                key,
1093                state: WEnum::Value(key_state),
1094                ..
1095            } => {
1096                state.serial_tracker.update(SerialKind::KeyPress, serial);
1097
1098                let focused_window = state.keyboard_focused_window.clone();
1099                let Some(focused_window) = focused_window else {
1100                    return;
1101                };
1102                let focused_window = focused_window.clone();
1103
1104                let keymap_state = state.keymap_state.as_ref().unwrap();
1105                let keycode = Keycode::from(key + MIN_KEYCODE);
1106                let keysym = keymap_state.key_get_one_sym(keycode);
1107
1108                match key_state {
1109                    wl_keyboard::KeyState::Pressed if !keysym.is_modifier_key() => {
1110                        let mut keystroke =
1111                            Keystroke::from_xkb(&keymap_state, state.modifiers, keycode);
1112                        if let Some(mut compose) = state.compose_state.take() {
1113                            compose.feed(keysym);
1114                            match compose.status() {
1115                                xkb::Status::Composing => {
1116                                    state.pre_edit_text =
1117                                        compose.utf8().or(Keystroke::underlying_dead_key(keysym));
1118                                    let pre_edit =
1119                                        state.pre_edit_text.clone().unwrap_or(String::default());
1120                                    drop(state);
1121                                    focused_window.handle_ime(ImeInput::SetMarkedText(pre_edit));
1122                                    state = client.borrow_mut();
1123                                }
1124
1125                                xkb::Status::Composed => {
1126                                    state.pre_edit_text.take();
1127                                    keystroke.ime_key = compose.utf8();
1128                                    keystroke.key = xkb::keysym_get_name(compose.keysym().unwrap());
1129                                }
1130                                xkb::Status::Cancelled => {
1131                                    let pre_edit = state.pre_edit_text.take();
1132                                    drop(state);
1133                                    if let Some(pre_edit) = pre_edit {
1134                                        focused_window.handle_ime(ImeInput::InsertText(pre_edit));
1135                                    }
1136                                    if let Some(current_key) =
1137                                        Keystroke::underlying_dead_key(keysym)
1138                                    {
1139                                        focused_window
1140                                            .handle_ime(ImeInput::SetMarkedText(current_key));
1141                                    }
1142                                    compose.feed(keysym);
1143                                    state = client.borrow_mut();
1144                                }
1145                                _ => {}
1146                            }
1147                            state.compose_state = Some(compose);
1148                        }
1149                        let input = PlatformInput::KeyDown(KeyDownEvent {
1150                            keystroke: keystroke.clone(),
1151                            is_held: false,
1152                        });
1153
1154                        state.repeat.current_id += 1;
1155                        state.repeat.current_keycode = Some(keycode);
1156
1157                        let rate = state.repeat.characters_per_second;
1158                        let id = state.repeat.current_id;
1159                        state
1160                            .loop_handle
1161                            .insert_source(Timer::from_duration(state.repeat.delay), {
1162                                let input = PlatformInput::KeyDown(KeyDownEvent {
1163                                    keystroke,
1164                                    is_held: true,
1165                                });
1166                                move |_event, _metadata, this| {
1167                                    let mut client = this.get_client();
1168                                    let mut state = client.borrow_mut();
1169                                    let is_repeating = id == state.repeat.current_id
1170                                        && state.repeat.current_keycode.is_some()
1171                                        && state.keyboard_focused_window.is_some();
1172
1173                                    if !is_repeating {
1174                                        return TimeoutAction::Drop;
1175                                    }
1176
1177                                    let focused_window =
1178                                        state.keyboard_focused_window.as_ref().unwrap().clone();
1179
1180                                    drop(state);
1181                                    focused_window.handle_input(input.clone());
1182
1183                                    TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
1184                                }
1185                            })
1186                            .unwrap();
1187
1188                        drop(state);
1189                        focused_window.handle_input(input);
1190                    }
1191                    wl_keyboard::KeyState::Released if !keysym.is_modifier_key() => {
1192                        let input = PlatformInput::KeyUp(KeyUpEvent {
1193                            keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
1194                        });
1195
1196                        if state.repeat.current_keycode == Some(keycode) {
1197                            state.repeat.current_keycode = None;
1198                        }
1199
1200                        drop(state);
1201                        focused_window.handle_input(input);
1202                    }
1203                    _ => {}
1204                }
1205            }
1206            _ => {}
1207        }
1208    }
1209}
1210impl Dispatch<zwp_text_input_v3::ZwpTextInputV3, ()> for WaylandClientStatePtr {
1211    fn event(
1212        this: &mut Self,
1213        text_input: &zwp_text_input_v3::ZwpTextInputV3,
1214        event: <zwp_text_input_v3::ZwpTextInputV3 as Proxy>::Event,
1215        _: &(),
1216        _: &Connection,
1217        _: &QueueHandle<Self>,
1218    ) {
1219        let client = this.get_client();
1220        let mut state = client.borrow_mut();
1221        match event {
1222            zwp_text_input_v3::Event::Enter { .. } => {
1223                drop(state);
1224                this.enable_ime();
1225            }
1226            zwp_text_input_v3::Event::Leave { .. } => {
1227                drop(state);
1228                this.disable_ime();
1229            }
1230            zwp_text_input_v3::Event::CommitString { text } => {
1231                state.composing = false;
1232                let Some(window) = state.keyboard_focused_window.clone() else {
1233                    return;
1234                };
1235
1236                if let Some(commit_text) = text {
1237                    drop(state);
1238                    // IBus Intercepts keys like `a`, `b`, but those keys are needed for vim mode.
1239                    // We should only send ASCII characters to Zed, otherwise a user could remap a letter like `か` or `相`.
1240                    if commit_text.len() == 1 {
1241                        window.handle_input(PlatformInput::KeyDown(KeyDownEvent {
1242                            keystroke: Keystroke {
1243                                modifiers: Modifiers::default(),
1244                                key: commit_text.clone(),
1245                                ime_key: Some(commit_text),
1246                            },
1247                            is_held: false,
1248                        }));
1249                    } else {
1250                        window.handle_ime(ImeInput::InsertText(commit_text));
1251                    }
1252                }
1253            }
1254            zwp_text_input_v3::Event::PreeditString { text, .. } => {
1255                state.composing = true;
1256                state.pre_edit_text = text;
1257            }
1258            zwp_text_input_v3::Event::Done { serial } => {
1259                let last_serial = state.serial_tracker.get(SerialKind::InputMethod);
1260                state.serial_tracker.update(SerialKind::InputMethod, serial);
1261                let Some(window) = state.keyboard_focused_window.clone() else {
1262                    return;
1263                };
1264
1265                if let Some(text) = state.pre_edit_text.take() {
1266                    drop(state);
1267                    window.handle_ime(ImeInput::SetMarkedText(text));
1268                    if let Some(area) = window.get_ime_area() {
1269                        text_input.set_cursor_rectangle(
1270                            area.origin.x.0 as i32,
1271                            area.origin.y.0 as i32,
1272                            area.size.width.0 as i32,
1273                            area.size.height.0 as i32,
1274                        );
1275                        if last_serial == serial {
1276                            text_input.commit();
1277                        }
1278                    }
1279                } else {
1280                    drop(state);
1281                    window.handle_ime(ImeInput::DeleteText);
1282                }
1283            }
1284            _ => {}
1285        }
1286    }
1287}
1288
1289fn linux_button_to_gpui(button: u32) -> Option<MouseButton> {
1290    // These values are coming from <linux/input-event-codes.h>.
1291    const BTN_LEFT: u32 = 0x110;
1292    const BTN_RIGHT: u32 = 0x111;
1293    const BTN_MIDDLE: u32 = 0x112;
1294    const BTN_SIDE: u32 = 0x113;
1295    const BTN_EXTRA: u32 = 0x114;
1296    const BTN_FORWARD: u32 = 0x115;
1297    const BTN_BACK: u32 = 0x116;
1298
1299    Some(match button {
1300        BTN_LEFT => MouseButton::Left,
1301        BTN_RIGHT => MouseButton::Right,
1302        BTN_MIDDLE => MouseButton::Middle,
1303        BTN_BACK | BTN_SIDE => MouseButton::Navigate(NavigationDirection::Back),
1304        BTN_FORWARD | BTN_EXTRA => MouseButton::Navigate(NavigationDirection::Forward),
1305        _ => return None,
1306    })
1307}
1308
1309impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientStatePtr {
1310    fn event(
1311        this: &mut Self,
1312        wl_pointer: &wl_pointer::WlPointer,
1313        event: wl_pointer::Event,
1314        _: &(),
1315        _: &Connection,
1316        _: &QueueHandle<Self>,
1317    ) {
1318        let mut client = this.get_client();
1319        let mut state = client.borrow_mut();
1320
1321        match event {
1322            wl_pointer::Event::Enter {
1323                serial,
1324                surface,
1325                surface_x,
1326                surface_y,
1327                ..
1328            } => {
1329                state.serial_tracker.update(SerialKind::MouseEnter, serial);
1330                state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
1331                state.button_pressed = None;
1332
1333                if let Some(window) = get_window(&mut state, &surface.id()) {
1334                    state.mouse_focused_window = Some(window.clone());
1335                    if state.enter_token.is_some() {
1336                        state.enter_token = None;
1337                    }
1338                    if let Some(style) = state.cursor_style {
1339                        if let Some(cursor_shape_device) = &state.cursor_shape_device {
1340                            cursor_shape_device.set_shape(serial, style.to_shape());
1341                        } else {
1342                            state
1343                                .cursor
1344                                .set_icon(&wl_pointer, serial, &style.to_icon_name());
1345                        }
1346                    }
1347                    drop(state);
1348                    window.set_focused(true);
1349                }
1350            }
1351            wl_pointer::Event::Leave { .. } => {
1352                if let Some(focused_window) = state.mouse_focused_window.clone() {
1353                    let input = PlatformInput::MouseExited(MouseExitEvent {
1354                        position: state.mouse_location.unwrap(),
1355                        pressed_button: state.button_pressed,
1356                        modifiers: state.modifiers,
1357                    });
1358                    state.mouse_focused_window = None;
1359                    state.mouse_location = None;
1360                    state.button_pressed = None;
1361
1362                    drop(state);
1363                    focused_window.handle_input(input);
1364                    focused_window.set_focused(false);
1365                }
1366            }
1367            wl_pointer::Event::Motion {
1368                surface_x,
1369                surface_y,
1370                ..
1371            } => {
1372                if state.mouse_focused_window.is_none() {
1373                    return;
1374                }
1375                state.mouse_location = Some(point(px(surface_x as f32), px(surface_y as f32)));
1376
1377                if let Some(window) = state.mouse_focused_window.clone() {
1378                    if state
1379                        .keyboard_focused_window
1380                        .as_ref()
1381                        .map_or(false, |keyboard_window| window.ptr_eq(&keyboard_window))
1382                    {
1383                        state.enter_token = None;
1384                    }
1385                    let input = PlatformInput::MouseMove(MouseMoveEvent {
1386                        position: state.mouse_location.unwrap(),
1387                        pressed_button: state.button_pressed,
1388                        modifiers: state.modifiers,
1389                    });
1390                    drop(state);
1391                    window.handle_input(input);
1392                }
1393            }
1394            wl_pointer::Event::Button {
1395                serial,
1396                button,
1397                state: WEnum::Value(button_state),
1398                ..
1399            } => {
1400                state.serial_tracker.update(SerialKind::MousePress, serial);
1401                let button = linux_button_to_gpui(button);
1402                let Some(button) = button else { return };
1403                if state.mouse_focused_window.is_none() {
1404                    return;
1405                }
1406                match button_state {
1407                    wl_pointer::ButtonState::Pressed => {
1408                        if let Some(window) = state.keyboard_focused_window.clone() {
1409                            if state.composing && state.text_input.is_some() {
1410                                drop(state);
1411                                // text_input_v3 don't have something like a reset function
1412                                this.disable_ime();
1413                                this.enable_ime();
1414                                window.handle_ime(ImeInput::UnmarkText);
1415                                state = client.borrow_mut();
1416                            } else if let (Some(text), Some(compose)) =
1417                                (state.pre_edit_text.take(), state.compose_state.as_mut())
1418                            {
1419                                compose.reset();
1420                                drop(state);
1421                                window.handle_ime(ImeInput::InsertText(text));
1422                                state = client.borrow_mut();
1423                            }
1424                        }
1425                        let click_elapsed = state.click.last_click.elapsed();
1426
1427                        if click_elapsed < DOUBLE_CLICK_INTERVAL
1428                            && is_within_click_distance(
1429                                state.click.last_location,
1430                                state.mouse_location.unwrap(),
1431                            )
1432                        {
1433                            state.click.current_count += 1;
1434                        } else {
1435                            state.click.current_count = 1;
1436                        }
1437
1438                        state.click.last_click = Instant::now();
1439                        state.click.last_location = state.mouse_location.unwrap();
1440
1441                        state.button_pressed = Some(button);
1442
1443                        if let Some(window) = state.mouse_focused_window.clone() {
1444                            let input = PlatformInput::MouseDown(MouseDownEvent {
1445                                button,
1446                                position: state.mouse_location.unwrap(),
1447                                modifiers: state.modifiers,
1448                                click_count: state.click.current_count,
1449                                first_mouse: state.enter_token.take().is_some(),
1450                            });
1451                            drop(state);
1452                            window.handle_input(input);
1453                        }
1454                    }
1455                    wl_pointer::ButtonState::Released => {
1456                        state.button_pressed = None;
1457
1458                        if let Some(window) = state.mouse_focused_window.clone() {
1459                            let input = PlatformInput::MouseUp(MouseUpEvent {
1460                                button,
1461                                position: state.mouse_location.unwrap(),
1462                                modifiers: state.modifiers,
1463                                click_count: state.click.current_count,
1464                            });
1465                            drop(state);
1466                            window.handle_input(input);
1467                        }
1468                    }
1469                    _ => {}
1470                }
1471            }
1472
1473            // Axis Events
1474            wl_pointer::Event::AxisSource {
1475                axis_source: WEnum::Value(axis_source),
1476            } => {
1477                state.axis_source = axis_source;
1478            }
1479            wl_pointer::Event::Axis {
1480                axis: WEnum::Value(axis),
1481                value,
1482                ..
1483            } => {
1484                if state.axis_source == AxisSource::Wheel {
1485                    return;
1486                }
1487                let axis_modifier = match axis {
1488                    wl_pointer::Axis::VerticalScroll => state.vertical_modifier,
1489                    wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
1490                    _ => 1.0,
1491                };
1492                state.scroll_event_received = true;
1493                let scroll_delta = state
1494                    .continuous_scroll_delta
1495                    .get_or_insert(point(px(0.0), px(0.0)));
1496                let modifier = 3.0;
1497                match axis {
1498                    wl_pointer::Axis::VerticalScroll => {
1499                        scroll_delta.y += px(value as f32 * modifier * axis_modifier);
1500                    }
1501                    wl_pointer::Axis::HorizontalScroll => {
1502                        scroll_delta.x += px(value as f32 * modifier * axis_modifier);
1503                    }
1504                    _ => unreachable!(),
1505                }
1506            }
1507            wl_pointer::Event::AxisDiscrete {
1508                axis: WEnum::Value(axis),
1509                discrete,
1510            } => {
1511                state.scroll_event_received = true;
1512                let axis_modifier = match axis {
1513                    wl_pointer::Axis::VerticalScroll => state.vertical_modifier,
1514                    wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
1515                    _ => 1.0,
1516                };
1517
1518                let scroll_delta = state.discrete_scroll_delta.get_or_insert(point(0.0, 0.0));
1519                match axis {
1520                    wl_pointer::Axis::VerticalScroll => {
1521                        scroll_delta.y += discrete as f32 * axis_modifier * SCROLL_LINES as f32;
1522                    }
1523                    wl_pointer::Axis::HorizontalScroll => {
1524                        scroll_delta.x += discrete as f32 * axis_modifier * SCROLL_LINES as f32;
1525                    }
1526                    _ => unreachable!(),
1527                }
1528            }
1529            wl_pointer::Event::AxisValue120 {
1530                axis: WEnum::Value(axis),
1531                value120,
1532            } => {
1533                state.scroll_event_received = true;
1534                let axis_modifier = match axis {
1535                    wl_pointer::Axis::VerticalScroll => state.vertical_modifier,
1536                    wl_pointer::Axis::HorizontalScroll => state.horizontal_modifier,
1537                    _ => unreachable!(),
1538                };
1539
1540                let scroll_delta = state.discrete_scroll_delta.get_or_insert(point(0.0, 0.0));
1541                let wheel_percent = value120 as f32 / 120.0;
1542                match axis {
1543                    wl_pointer::Axis::VerticalScroll => {
1544                        scroll_delta.y += wheel_percent * axis_modifier * SCROLL_LINES as f32;
1545                    }
1546                    wl_pointer::Axis::HorizontalScroll => {
1547                        scroll_delta.x += wheel_percent * axis_modifier * SCROLL_LINES as f32;
1548                    }
1549                    _ => unreachable!(),
1550                }
1551            }
1552            wl_pointer::Event::Frame => {
1553                if state.scroll_event_received {
1554                    state.scroll_event_received = false;
1555                    let continuous = state.continuous_scroll_delta.take();
1556                    let discrete = state.discrete_scroll_delta.take();
1557                    if let Some(continuous) = continuous {
1558                        if let Some(window) = state.mouse_focused_window.clone() {
1559                            let input = PlatformInput::ScrollWheel(ScrollWheelEvent {
1560                                position: state.mouse_location.unwrap(),
1561                                delta: ScrollDelta::Pixels(continuous),
1562                                modifiers: state.modifiers,
1563                                touch_phase: TouchPhase::Moved,
1564                            });
1565                            drop(state);
1566                            window.handle_input(input);
1567                        }
1568                    } else if let Some(discrete) = discrete {
1569                        if let Some(window) = state.mouse_focused_window.clone() {
1570                            let input = PlatformInput::ScrollWheel(ScrollWheelEvent {
1571                                position: state.mouse_location.unwrap(),
1572                                delta: ScrollDelta::Lines(discrete),
1573                                modifiers: state.modifiers,
1574                                touch_phase: TouchPhase::Moved,
1575                            });
1576                            drop(state);
1577                            window.handle_input(input);
1578                        }
1579                    }
1580                }
1581            }
1582            _ => {}
1583        }
1584    }
1585}
1586
1587impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientStatePtr {
1588    fn event(
1589        this: &mut Self,
1590        _: &wp_fractional_scale_v1::WpFractionalScaleV1,
1591        event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
1592        surface_id: &ObjectId,
1593        _: &Connection,
1594        _: &QueueHandle<Self>,
1595    ) {
1596        let client = this.get_client();
1597        let mut state = client.borrow_mut();
1598
1599        let Some(window) = get_window(&mut state, surface_id) else {
1600            return;
1601        };
1602
1603        drop(state);
1604        window.handle_fractional_scale_event(event);
1605    }
1606}
1607
1608impl Dispatch<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, ObjectId>
1609    for WaylandClientStatePtr
1610{
1611    fn event(
1612        this: &mut Self,
1613        _: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
1614        event: zxdg_toplevel_decoration_v1::Event,
1615        surface_id: &ObjectId,
1616        _: &Connection,
1617        _: &QueueHandle<Self>,
1618    ) {
1619        let client = this.get_client();
1620        let mut state = client.borrow_mut();
1621        let Some(window) = get_window(&mut state, surface_id) else {
1622            return;
1623        };
1624
1625        drop(state);
1626        window.handle_toplevel_decoration_event(event);
1627    }
1628}
1629
1630const FILE_LIST_MIME_TYPE: &str = "text/uri-list";
1631
1632impl Dispatch<wl_data_device::WlDataDevice, ()> for WaylandClientStatePtr {
1633    fn event(
1634        this: &mut Self,
1635        _: &wl_data_device::WlDataDevice,
1636        event: wl_data_device::Event,
1637        _: &(),
1638        _: &Connection,
1639        _: &QueueHandle<Self>,
1640    ) {
1641        let client = this.get_client();
1642        let mut state = client.borrow_mut();
1643
1644        match event {
1645            wl_data_device::Event::Enter {
1646                serial,
1647                surface,
1648                x,
1649                y,
1650                id: data_offer,
1651            } => {
1652                state.serial_tracker.update(SerialKind::DataDevice, serial);
1653                if let Some(data_offer) = data_offer {
1654                    let Some(drag_window) = get_window(&mut state, &surface.id()) else {
1655                        return;
1656                    };
1657
1658                    const ACTIONS: DndAction = DndAction::Copy;
1659                    data_offer.set_actions(ACTIONS, ACTIONS);
1660
1661                    let pipe = Pipe::new().unwrap();
1662                    data_offer.receive(FILE_LIST_MIME_TYPE.to_string(), unsafe {
1663                        BorrowedFd::borrow_raw(pipe.write.as_raw_fd())
1664                    });
1665                    let fd = pipe.read;
1666                    drop(pipe.write);
1667
1668                    let read_task = state
1669                        .common
1670                        .background_executor
1671                        .spawn(async { unsafe { read_fd(fd) } });
1672
1673                    let this = this.clone();
1674                    state
1675                        .common
1676                        .foreground_executor
1677                        .spawn(async move {
1678                            let file_list = match read_task.await {
1679                                Ok(list) => list,
1680                                Err(err) => {
1681                                    log::error!("error reading drag and drop pipe: {err:?}");
1682                                    return;
1683                                }
1684                            };
1685
1686                            let paths: SmallVec<[_; 2]> = file_list
1687                                .lines()
1688                                .map(|path| PathBuf::from(path.replace("file://", "")))
1689                                .collect();
1690                            let position = Point::new(x.into(), y.into());
1691
1692                            // Prevent dropping text from other programs.
1693                            if paths.is_empty() {
1694                                data_offer.finish();
1695                                data_offer.destroy();
1696                                return;
1697                            }
1698
1699                            let input = PlatformInput::FileDrop(FileDropEvent::Entered {
1700                                position,
1701                                paths: crate::ExternalPaths(paths),
1702                            });
1703
1704                            let client = this.get_client();
1705                            let mut state = client.borrow_mut();
1706                            state.drag.data_offer = Some(data_offer);
1707                            state.drag.window = Some(drag_window.clone());
1708                            state.drag.position = position;
1709
1710                            drop(state);
1711                            drag_window.handle_input(input);
1712                        })
1713                        .detach();
1714                }
1715            }
1716            wl_data_device::Event::Motion { x, y, .. } => {
1717                let Some(drag_window) = state.drag.window.clone() else {
1718                    return;
1719                };
1720                let position = Point::new(x.into(), y.into());
1721                state.drag.position = position;
1722
1723                let input = PlatformInput::FileDrop(FileDropEvent::Pending { position });
1724                drop(state);
1725                drag_window.handle_input(input);
1726            }
1727            wl_data_device::Event::Leave => {
1728                let Some(drag_window) = state.drag.window.clone() else {
1729                    return;
1730                };
1731                let data_offer = state.drag.data_offer.clone().unwrap();
1732                data_offer.destroy();
1733
1734                state.drag.data_offer = None;
1735                state.drag.window = None;
1736
1737                let input = PlatformInput::FileDrop(FileDropEvent::Exited {});
1738                drop(state);
1739                drag_window.handle_input(input);
1740            }
1741            wl_data_device::Event::Drop => {
1742                let Some(drag_window) = state.drag.window.clone() else {
1743                    return;
1744                };
1745                let data_offer = state.drag.data_offer.clone().unwrap();
1746                data_offer.finish();
1747                data_offer.destroy();
1748
1749                state.drag.data_offer = None;
1750                state.drag.window = None;
1751
1752                let input = PlatformInput::FileDrop(FileDropEvent::Submit {
1753                    position: state.drag.position,
1754                });
1755                drop(state);
1756                drag_window.handle_input(input);
1757            }
1758            _ => {}
1759        }
1760    }
1761
1762    event_created_child!(WaylandClientStatePtr, wl_data_device::WlDataDevice, [
1763        wl_data_device::EVT_DATA_OFFER_OPCODE => (wl_data_offer::WlDataOffer, ()),
1764    ]);
1765}
1766
1767impl Dispatch<wl_data_offer::WlDataOffer, ()> for WaylandClientStatePtr {
1768    fn event(
1769        this: &mut Self,
1770        data_offer: &wl_data_offer::WlDataOffer,
1771        event: wl_data_offer::Event,
1772        _: &(),
1773        _: &Connection,
1774        _: &QueueHandle<Self>,
1775    ) {
1776        let client = this.get_client();
1777        let mut state = client.borrow_mut();
1778
1779        match event {
1780            wl_data_offer::Event::Offer { mime_type } => {
1781                if mime_type == FILE_LIST_MIME_TYPE {
1782                    let serial = state.serial_tracker.get(SerialKind::DataDevice);
1783                    data_offer.accept(serial, Some(mime_type));
1784                }
1785            }
1786            _ => {}
1787        }
1788    }
1789}