client.rs

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