client.rs

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