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