client.rs

   1use std::cell::RefCell;
   2use std::num::NonZeroU32;
   3use std::rc::Rc;
   4use std::sync::Arc;
   5use std::time::Duration;
   6
   7use calloop::timer::{TimeoutAction, Timer};
   8use calloop::LoopHandle;
   9use calloop_wayland_source::WaylandSource;
  10use copypasta::wayland_clipboard::{create_clipboards_from_external, Clipboard, Primary};
  11use copypasta::ClipboardProvider;
  12use wayland_backend::client::ObjectId;
  13use wayland_backend::protocol::WEnum;
  14use wayland_client::globals::{registry_queue_init, GlobalListContents};
  15use wayland_client::protocol::wl_callback::WlCallback;
  16use wayland_client::protocol::wl_output;
  17use wayland_client::protocol::wl_pointer::AxisRelativeDirection;
  18use wayland_client::{
  19    delegate_noop,
  20    protocol::{
  21        wl_buffer, wl_callback, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat,
  22        wl_shm, wl_shm_pool,
  23        wl_surface::{self, WlSurface},
  24    },
  25    Connection, Dispatch, Proxy, QueueHandle,
  26};
  27use wayland_protocols::wp::fractional_scale::v1::client::{
  28    wp_fractional_scale_manager_v1, wp_fractional_scale_v1,
  29};
  30use wayland_protocols::wp::viewporter::client::{wp_viewport, wp_viewporter};
  31use wayland_protocols::xdg::decoration::zv1::client::{
  32    zxdg_decoration_manager_v1, zxdg_toplevel_decoration_v1,
  33};
  34use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
  35use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
  36use xkbcommon::xkb::{self, Keycode, KEYMAP_COMPILE_NO_FLAGS};
  37
  38use crate::platform::linux::client::Client;
  39use crate::platform::linux::wayland::cursor::Cursor;
  40use crate::platform::linux::wayland::window::{WaylandDecorationState, WaylandWindow};
  41use crate::platform::{LinuxPlatformInner, PlatformWindow};
  42use crate::{
  43    platform::linux::wayland::window::WaylandWindowState, AnyWindowHandle, CursorStyle, DisplayId,
  44    KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
  45    MouseDownEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay,
  46    PlatformInput, Point, ScrollDelta, ScrollWheelEvent, TouchPhase, WindowOptions,
  47};
  48
  49/// Used to convert evdev scancode to xkb scancode
  50const MIN_KEYCODE: u32 = 8;
  51
  52pub(crate) struct WaylandClientStateInner {
  53    compositor: wl_compositor::WlCompositor,
  54    wm_base: xdg_wm_base::XdgWmBase,
  55    shm: wl_shm::WlShm,
  56    viewporter: Option<wp_viewporter::WpViewporter>,
  57    fractional_scale_manager: Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
  58    decoration_manager: Option<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1>,
  59    windows: Vec<(xdg_surface::XdgSurface, Rc<WaylandWindowState>)>,
  60    outputs: Vec<(wl_output::WlOutput, Rc<RefCell<OutputState>>)>,
  61    platform_inner: Rc<LinuxPlatformInner>,
  62    keymap_state: Option<xkb::State>,
  63    repeat: KeyRepeat,
  64    modifiers: Modifiers,
  65    scroll_direction: f64,
  66    mouse_location: Option<Point<Pixels>>,
  67    button_pressed: Option<MouseButton>,
  68    mouse_focused_window: Option<Rc<WaylandWindowState>>,
  69    keyboard_focused_window: Option<Rc<WaylandWindowState>>,
  70    loop_handle: Rc<LoopHandle<'static, ()>>,
  71}
  72
  73pub(crate) struct CursorState {
  74    cursor_icon_name: String,
  75    cursor: Option<Cursor>,
  76}
  77
  78#[derive(Clone)]
  79pub(crate) struct WaylandClientState {
  80    client_state_inner: Rc<RefCell<WaylandClientStateInner>>,
  81    cursor_state: Rc<RefCell<CursorState>>,
  82    clipboard: Rc<RefCell<Clipboard>>,
  83    primary: Rc<RefCell<Primary>>,
  84}
  85
  86pub(crate) struct KeyRepeat {
  87    characters_per_second: u32,
  88    delay: Duration,
  89    current_id: u64,
  90    current_keysym: Option<xkb::Keysym>,
  91}
  92
  93pub(crate) struct WaylandClient {
  94    platform_inner: Rc<LinuxPlatformInner>,
  95    state: WaylandClientState,
  96    qh: Arc<QueueHandle<WaylandClientState>>,
  97}
  98
  99const WL_SEAT_VERSION: u32 = 4;
 100const WL_OUTPUT_VERSION: u32 = 2;
 101
 102impl WaylandClient {
 103    pub(crate) fn new(linux_platform_inner: Rc<LinuxPlatformInner>) -> Self {
 104        let conn = Connection::connect_to_env().unwrap();
 105
 106        let (globals, mut event_queue) = registry_queue_init::<WaylandClientState>(&conn).unwrap();
 107        let qh = event_queue.handle();
 108        let mut outputs = Vec::new();
 109
 110        globals.contents().with_list(|list| {
 111            for global in list {
 112                match &global.interface[..] {
 113                    "wl_seat" => {
 114                        globals.registry().bind::<wl_seat::WlSeat, _, _>(
 115                            global.name,
 116                            WL_SEAT_VERSION,
 117                            &qh,
 118                            (),
 119                        );
 120                    }
 121                    "wl_output" => outputs.push((
 122                        globals.registry().bind::<wl_output::WlOutput, _, _>(
 123                            global.name,
 124                            WL_OUTPUT_VERSION,
 125                            &qh,
 126                            (),
 127                        ),
 128                        Rc::new(RefCell::new(OutputState::default())),
 129                    )),
 130                    _ => {}
 131                }
 132            }
 133        });
 134
 135        let display = conn.backend().display_ptr() as *mut std::ffi::c_void;
 136        let (primary, clipboard) = unsafe { create_clipboards_from_external(display) };
 137
 138        let mut state_inner = Rc::new(RefCell::new(WaylandClientStateInner {
 139            compositor: globals
 140                .bind(&qh, 1..=wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE, ())
 141                .unwrap(),
 142            wm_base: globals.bind(&qh, 1..=1, ()).unwrap(),
 143            shm: globals.bind(&qh, 1..=1, ()).unwrap(),
 144            outputs,
 145            viewporter: globals.bind(&qh, 1..=1, ()).ok(),
 146            fractional_scale_manager: globals.bind(&qh, 1..=1, ()).ok(),
 147            decoration_manager: globals.bind(&qh, 1..=1, ()).ok(),
 148            windows: Vec::new(),
 149            platform_inner: Rc::clone(&linux_platform_inner),
 150            keymap_state: None,
 151            repeat: KeyRepeat {
 152                characters_per_second: 16,
 153                delay: Duration::from_millis(500),
 154                current_id: 0,
 155                current_keysym: None,
 156            },
 157            modifiers: Modifiers {
 158                shift: false,
 159                control: false,
 160                alt: false,
 161                function: false,
 162                command: false,
 163            },
 164            scroll_direction: -1.0,
 165            mouse_location: None,
 166            button_pressed: None,
 167            mouse_focused_window: None,
 168            keyboard_focused_window: None,
 169            loop_handle: Rc::clone(&linux_platform_inner.loop_handle),
 170        }));
 171
 172        let mut cursor_state = Rc::new(RefCell::new(CursorState {
 173            cursor_icon_name: "arrow".to_string(),
 174            cursor: None,
 175        }));
 176
 177        let source = WaylandSource::new(conn, event_queue);
 178
 179        let mut state = WaylandClientState {
 180            client_state_inner: Rc::clone(&state_inner),
 181            cursor_state: Rc::clone(&cursor_state),
 182            clipboard: Rc::new(RefCell::new(clipboard)),
 183            primary: Rc::new(RefCell::new(primary)),
 184        };
 185        let mut state_loop = state.clone();
 186        linux_platform_inner
 187            .loop_handle
 188            .insert_source(source, move |_, queue, _| {
 189                queue.dispatch_pending(&mut state_loop)
 190            })
 191            .unwrap();
 192
 193        Self {
 194            platform_inner: linux_platform_inner,
 195            state,
 196            qh: Arc::new(qh),
 197        }
 198    }
 199}
 200
 201impl Client for WaylandClient {
 202    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
 203        Vec::new()
 204    }
 205
 206    fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
 207        unimplemented!()
 208    }
 209
 210    fn open_window(
 211        &self,
 212        handle: AnyWindowHandle,
 213        options: WindowOptions,
 214    ) -> Box<dyn PlatformWindow> {
 215        let mut state = self.state.client_state_inner.borrow_mut();
 216
 217        let wl_surface = state.compositor.create_surface(&self.qh, ());
 218        let xdg_surface = state.wm_base.get_xdg_surface(&wl_surface, &self.qh, ());
 219        let toplevel = xdg_surface.get_toplevel(&self.qh, ());
 220        let wl_surface = Arc::new(wl_surface);
 221
 222        // Attempt to set up window decorations based on the requested configuration
 223        //
 224        // Note that wayland compositors may either not support decorations at all, or may
 225        // support them but not allow clients to choose whether they are enabled or not.
 226        // We attempt to account for these cases here.
 227
 228        if let Some(decoration_manager) = state.decoration_manager.as_ref() {
 229            // The protocol for managing decorations is present at least, but that doesn't
 230            // mean that the compositor will allow us to use it.
 231
 232            let decoration =
 233                decoration_manager.get_toplevel_decoration(&toplevel, &self.qh, xdg_surface.id());
 234
 235            // todo(linux) - options.titlebar is lacking information required for wayland.
 236            //                Especially, whether a titlebar is wanted in itself.
 237            //
 238            // Removing the titlebar also removes the entire window frame (ie. the ability to
 239            // close, move and resize the window [snapping still works]). This needs additional
 240            // handling in Zed, in order to implement drag handlers on a titlebar element.
 241            //
 242            // Since all of this handling is not present, we request server-side decorations
 243            // for now as a stopgap solution.
 244            decoration.set_mode(zxdg_toplevel_decoration_v1::Mode::ServerSide);
 245        }
 246
 247        let viewport = state
 248            .viewporter
 249            .as_ref()
 250            .map(|viewporter| viewporter.get_viewport(&wl_surface, &self.qh, ()));
 251
 252        wl_surface.frame(&self.qh, wl_surface.clone());
 253        wl_surface.commit();
 254
 255        let window_state: Rc<WaylandWindowState> = Rc::new(WaylandWindowState::new(
 256            wl_surface.clone(),
 257            viewport,
 258            Arc::new(toplevel),
 259            options,
 260        ));
 261
 262        if let Some(fractional_scale_manager) = state.fractional_scale_manager.as_ref() {
 263            fractional_scale_manager.get_fractional_scale(&wl_surface, &self.qh, xdg_surface.id());
 264        }
 265
 266        state.windows.push((xdg_surface, Rc::clone(&window_state)));
 267        Box::new(WaylandWindow(window_state))
 268    }
 269
 270    fn set_cursor_style(&self, style: CursorStyle) {
 271        // Based on cursor names from https://gitlab.gnome.org/GNOME/adwaita-icon-theme (GNOME)
 272        // and https://github.com/KDE/breeze (KDE). Both of them seem to be also derived from
 273        // Web CSS cursor names: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#values
 274        let cursor_icon_name = match style {
 275            CursorStyle::Arrow => "arrow",
 276            CursorStyle::IBeam => "text",
 277            CursorStyle::Crosshair => "crosshair",
 278            CursorStyle::ClosedHand => "grabbing",
 279            CursorStyle::OpenHand => "grab",
 280            CursorStyle::PointingHand => "pointer",
 281            CursorStyle::ResizeLeft => "w-resize",
 282            CursorStyle::ResizeRight => "e-resize",
 283            CursorStyle::ResizeLeftRight => "ew-resize",
 284            CursorStyle::ResizeUp => "n-resize",
 285            CursorStyle::ResizeDown => "s-resize",
 286            CursorStyle::ResizeUpDown => "ns-resize",
 287            CursorStyle::DisappearingItem => "grabbing", // todo(linux) - couldn't find equivalent icon in linux
 288            CursorStyle::IBeamCursorForVerticalLayout => "vertical-text",
 289            CursorStyle::OperationNotAllowed => "not-allowed",
 290            CursorStyle::DragLink => "alias",
 291            CursorStyle::DragCopy => "copy",
 292            CursorStyle::ContextualMenu => "context-menu",
 293        }
 294        .to_string();
 295
 296        let mut cursor_state = self.state.cursor_state.borrow_mut();
 297        cursor_state.cursor_icon_name = cursor_icon_name;
 298    }
 299
 300    fn get_clipboard(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
 301        self.state.clipboard.clone()
 302    }
 303
 304    fn get_primary(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
 305        self.state.primary.clone()
 306    }
 307}
 308
 309impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientState {
 310    fn event(
 311        state: &mut Self,
 312        registry: &wl_registry::WlRegistry,
 313        event: wl_registry::Event,
 314        _: &GlobalListContents,
 315        _: &Connection,
 316        qh: &QueueHandle<Self>,
 317    ) {
 318        let mut state = state.client_state_inner.borrow_mut();
 319        match event {
 320            wl_registry::Event::Global {
 321                name,
 322                interface,
 323                version: _,
 324            } => match &interface[..] {
 325                "wl_seat" => {
 326                    registry.bind::<wl_seat::WlSeat, _, _>(name, WL_SEAT_VERSION, qh, ());
 327                }
 328                "wl_output" => {
 329                    state.outputs.push((
 330                        registry.bind::<wl_output::WlOutput, _, _>(name, WL_OUTPUT_VERSION, qh, ()),
 331                        Rc::new(RefCell::new(OutputState::default())),
 332                    ));
 333                }
 334                _ => {}
 335            },
 336            wl_registry::Event::GlobalRemove { name: _ } => {}
 337            _ => {}
 338        }
 339    }
 340}
 341
 342delegate_noop!(WaylandClientState: ignore wl_compositor::WlCompositor);
 343delegate_noop!(WaylandClientState: ignore wl_shm::WlShm);
 344delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool);
 345delegate_noop!(WaylandClientState: ignore wl_buffer::WlBuffer);
 346delegate_noop!(WaylandClientState: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
 347delegate_noop!(WaylandClientState: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
 348delegate_noop!(WaylandClientState: ignore wp_viewporter::WpViewporter);
 349delegate_noop!(WaylandClientState: ignore wp_viewport::WpViewport);
 350
 351impl Dispatch<WlCallback, Arc<WlSurface>> for WaylandClientState {
 352    fn event(
 353        state: &mut Self,
 354        _: &WlCallback,
 355        event: wl_callback::Event,
 356        surf: &Arc<WlSurface>,
 357        _: &Connection,
 358        qh: &QueueHandle<Self>,
 359    ) {
 360        let mut state = state.client_state_inner.borrow_mut();
 361        if let wl_callback::Event::Done { .. } = event {
 362            for window in &state.windows {
 363                if window.1.surface.id() == surf.id() {
 364                    window.1.surface.frame(qh, surf.clone());
 365                    window.1.update();
 366                    window.1.surface.commit();
 367                }
 368            }
 369        }
 370    }
 371}
 372
 373impl Dispatch<wl_surface::WlSurface, ()> for WaylandClientState {
 374    fn event(
 375        state: &mut Self,
 376        surface: &wl_surface::WlSurface,
 377        event: <wl_surface::WlSurface as Proxy>::Event,
 378        _: &(),
 379        _: &Connection,
 380        _: &QueueHandle<Self>,
 381    ) {
 382        let mut state = state.client_state_inner.borrow_mut();
 383
 384        // We use `WpFractionalScale` instead to set the scale if it's available
 385        // or give up on scaling if `WlSurface::set_buffer_scale` isn't available
 386        if state.fractional_scale_manager.is_some()
 387            || state.compositor.version() < wl_surface::REQ_SET_BUFFER_SCALE_SINCE
 388        {
 389            return;
 390        }
 391
 392        let Some(window) = state
 393            .windows
 394            .iter()
 395            .map(|(_, state)| state)
 396            .find(|state| &*state.surface == surface)
 397        else {
 398            return;
 399        };
 400
 401        let mut outputs = window.outputs.borrow_mut();
 402
 403        match event {
 404            wl_surface::Event::Enter { output } => {
 405                // We use `PreferredBufferScale` instead to set the scale if it's available
 406                if surface.version() >= wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE {
 407                    return;
 408                }
 409                let mut scale = 1;
 410                for global_output in &state.outputs {
 411                    if output == global_output.0 {
 412                        outputs.insert(output.id());
 413                        scale = scale.max(global_output.1.borrow().scale.get());
 414                    } else if outputs.contains(&global_output.0.id()) {
 415                        scale = scale.max(global_output.1.borrow().scale.get());
 416                    }
 417                }
 418                window.rescale(scale as f32);
 419                window.surface.set_buffer_scale(scale as i32);
 420                window.surface.commit();
 421            }
 422            wl_surface::Event::Leave { output } => {
 423                // We use `PreferredBufferScale` instead to set the scale if it's available
 424                if surface.version() >= 6 {
 425                    return;
 426                }
 427
 428                outputs.remove(&output.id());
 429
 430                let mut scale = 1;
 431                for global_output in &state.outputs {
 432                    if outputs.contains(&global_output.0.id()) {
 433                        scale = scale.max(global_output.1.borrow().scale.get());
 434                    }
 435                }
 436                window.rescale(scale as f32);
 437                window.surface.set_buffer_scale(scale as i32);
 438                window.surface.commit();
 439            }
 440            wl_surface::Event::PreferredBufferScale { factor } => {
 441                window.rescale(factor as f32);
 442                surface.set_buffer_scale(factor);
 443                window.surface.commit();
 444            }
 445            _ => {}
 446        }
 447    }
 448}
 449
 450#[derive(Debug, Clone)]
 451struct OutputState {
 452    scale: NonZeroU32,
 453}
 454
 455impl Default for OutputState {
 456    fn default() -> Self {
 457        Self {
 458            scale: NonZeroU32::new(1).unwrap(),
 459        }
 460    }
 461}
 462
 463impl Dispatch<wl_output::WlOutput, ()> for WaylandClientState {
 464    fn event(
 465        state: &mut Self,
 466        output: &wl_output::WlOutput,
 467        event: <wl_output::WlOutput as Proxy>::Event,
 468        _: &(),
 469        _: &Connection,
 470        _: &QueueHandle<Self>,
 471    ) {
 472        let mut state = state.client_state_inner.borrow_mut();
 473        let mut output_state = state
 474            .outputs
 475            .iter_mut()
 476            .find(|(o, _)| o == output)
 477            .map(|(_, state)| state)
 478            .unwrap()
 479            .borrow_mut();
 480        match event {
 481            wl_output::Event::Scale { factor } => {
 482                if factor > 0 {
 483                    output_state.scale = NonZeroU32::new(factor as u32).unwrap();
 484                }
 485            }
 486            _ => {}
 487        }
 488    }
 489}
 490
 491impl Dispatch<xdg_surface::XdgSurface, ()> for WaylandClientState {
 492    fn event(
 493        state: &mut Self,
 494        xdg_surface: &xdg_surface::XdgSurface,
 495        event: xdg_surface::Event,
 496        _: &(),
 497        _: &Connection,
 498        _: &QueueHandle<Self>,
 499    ) {
 500        let mut state = state.client_state_inner.borrow_mut();
 501        if let xdg_surface::Event::Configure { serial, .. } = event {
 502            xdg_surface.ack_configure(serial);
 503            for window in &state.windows {
 504                if &window.0 == xdg_surface {
 505                    window.1.update();
 506                    window.1.surface.commit();
 507                    return;
 508                }
 509            }
 510        }
 511    }
 512}
 513
 514impl Dispatch<xdg_toplevel::XdgToplevel, ()> for WaylandClientState {
 515    fn event(
 516        state: &mut Self,
 517        xdg_toplevel: &xdg_toplevel::XdgToplevel,
 518        event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
 519        _: &(),
 520        _: &Connection,
 521        _: &QueueHandle<Self>,
 522    ) {
 523        let mut state = state.client_state_inner.borrow_mut();
 524        if let xdg_toplevel::Event::Configure {
 525            width,
 526            height,
 527            states,
 528        } = event
 529        {
 530            let width = NonZeroU32::new(width as u32);
 531            let height = NonZeroU32::new(height as u32);
 532            let fullscreen = states.contains(&(xdg_toplevel::State::Fullscreen as u8));
 533            for window in &state.windows {
 534                if window.1.toplevel.id() == xdg_toplevel.id() {
 535                    window.1.resize(width, height);
 536                    window.1.set_fullscreen(fullscreen);
 537                    window.1.surface.commit();
 538                    return;
 539                }
 540            }
 541        } else if let xdg_toplevel::Event::Close = event {
 542            state.windows.retain(|(_, window)| {
 543                if window.toplevel.id() == xdg_toplevel.id() {
 544                    window.toplevel.destroy();
 545                    false
 546                } else {
 547                    true
 548                }
 549            });
 550            state.platform_inner.loop_signal.stop();
 551        }
 552    }
 553}
 554
 555impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientState {
 556    fn event(
 557        _: &mut Self,
 558        wm_base: &xdg_wm_base::XdgWmBase,
 559        event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
 560        _: &(),
 561        _: &Connection,
 562        _: &QueueHandle<Self>,
 563    ) {
 564        if let xdg_wm_base::Event::Ping { serial } = event {
 565            wm_base.pong(serial);
 566        }
 567    }
 568}
 569
 570impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientState {
 571    fn event(
 572        state: &mut Self,
 573        seat: &wl_seat::WlSeat,
 574        event: wl_seat::Event,
 575        data: &(),
 576        conn: &Connection,
 577        qh: &QueueHandle<Self>,
 578    ) {
 579        if let wl_seat::Event::Capabilities {
 580            capabilities: WEnum::Value(capabilities),
 581        } = event
 582        {
 583            if capabilities.contains(wl_seat::Capability::Keyboard) {
 584                seat.get_keyboard(qh, ());
 585            }
 586            if capabilities.contains(wl_seat::Capability::Pointer) {
 587                seat.get_pointer(qh, ());
 588            }
 589        }
 590    }
 591}
 592
 593impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
 594    fn event(
 595        this: &mut Self,
 596        keyboard: &wl_keyboard::WlKeyboard,
 597        event: wl_keyboard::Event,
 598        data: &(),
 599        conn: &Connection,
 600        qh: &QueueHandle<Self>,
 601    ) {
 602        let mut state = this.client_state_inner.borrow_mut();
 603        match event {
 604            wl_keyboard::Event::RepeatInfo { rate, delay } => {
 605                state.repeat.characters_per_second = rate as u32;
 606                state.repeat.delay = Duration::from_millis(delay as u64);
 607            }
 608            wl_keyboard::Event::Keymap {
 609                format: WEnum::Value(format),
 610                fd,
 611                size,
 612                ..
 613            } => {
 614                assert_eq!(
 615                    format,
 616                    wl_keyboard::KeymapFormat::XkbV1,
 617                    "Unsupported keymap format"
 618                );
 619                let keymap = unsafe {
 620                    xkb::Keymap::new_from_fd(
 621                        &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
 622                        fd,
 623                        size as usize,
 624                        XKB_KEYMAP_FORMAT_TEXT_V1,
 625                        KEYMAP_COMPILE_NO_FLAGS,
 626                    )
 627                    .unwrap()
 628                }
 629                .unwrap();
 630                state.keymap_state = Some(xkb::State::new(&keymap));
 631            }
 632            wl_keyboard::Event::Enter { surface, .. } => {
 633                state.keyboard_focused_window = state
 634                    .windows
 635                    .iter()
 636                    .find(|&w| w.1.surface.id() == surface.id())
 637                    .map(|w| w.1.clone());
 638
 639                if let Some(window) = &state.keyboard_focused_window {
 640                    window.set_focused(true);
 641                }
 642            }
 643            wl_keyboard::Event::Leave { surface, .. } => {
 644                let keyboard_focused_window = state
 645                    .windows
 646                    .iter()
 647                    .find(|&w| w.1.surface.id() == surface.id())
 648                    .map(|w| w.1.clone());
 649
 650                if let Some(window) = keyboard_focused_window {
 651                    window.set_focused(false);
 652                }
 653
 654                state.keyboard_focused_window = None;
 655            }
 656            wl_keyboard::Event::Modifiers {
 657                mods_depressed,
 658                mods_latched,
 659                mods_locked,
 660                group,
 661                ..
 662            } => {
 663                let keymap_state = state.keymap_state.as_mut().unwrap();
 664                keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
 665
 666                let shift =
 667                    keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE);
 668                let alt =
 669                    keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);
 670                let control =
 671                    keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);
 672                let command =
 673                    keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE);
 674
 675                state.modifiers.shift = shift;
 676                state.modifiers.alt = alt;
 677                state.modifiers.control = control;
 678                state.modifiers.command = command;
 679            }
 680            wl_keyboard::Event::Key {
 681                key,
 682                state: WEnum::Value(key_state),
 683                ..
 684            } => {
 685                let focused_window = &state.keyboard_focused_window;
 686                let Some(focused_window) = focused_window else {
 687                    return;
 688                };
 689                let focused_window = focused_window.clone();
 690
 691                let keymap_state = state.keymap_state.as_ref().unwrap();
 692                let keycode = Keycode::from(key + MIN_KEYCODE);
 693                let keysym = keymap_state.key_get_one_sym(keycode);
 694
 695                match key_state {
 696                    wl_keyboard::KeyState::Pressed => {
 697                        let input = if keysym.is_modifier_key() {
 698                            PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 699                                modifiers: state.modifiers,
 700                            })
 701                        } else {
 702                            PlatformInput::KeyDown(KeyDownEvent {
 703                                keystroke: Keystroke::from_xkb(
 704                                    keymap_state,
 705                                    state.modifiers,
 706                                    keycode,
 707                                ),
 708                                is_held: false, // todo(linux)
 709                            })
 710                        };
 711
 712                        if !keysym.is_modifier_key() {
 713                            state.repeat.current_id += 1;
 714                            state.repeat.current_keysym = Some(keysym);
 715
 716                            let rate = state.repeat.characters_per_second;
 717                            let delay = state.repeat.delay;
 718                            let id = state.repeat.current_id;
 719                            let this = this.clone();
 720
 721                            let timer = Timer::from_duration(delay);
 722                            let state_ = Rc::clone(&this.client_state_inner);
 723                            let input_ = input.clone();
 724                            state
 725                                .loop_handle
 726                                .insert_source(timer, move |event, _metadata, shared_data| {
 727                                    let state_ = state_.borrow_mut();
 728                                    let is_repeating = id == state_.repeat.current_id
 729                                        && state_.repeat.current_keysym.is_some()
 730                                        && state_.keyboard_focused_window.is_some();
 731
 732                                    if !is_repeating {
 733                                        return TimeoutAction::Drop;
 734                                    }
 735
 736                                    let focused_window =
 737                                        state_.keyboard_focused_window.as_ref().unwrap().clone();
 738
 739                                    drop(state_);
 740
 741                                    focused_window.handle_input(input_.clone());
 742
 743                                    TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
 744                                })
 745                                .unwrap();
 746                        }
 747
 748                        drop(state);
 749
 750                        focused_window.handle_input(input);
 751                    }
 752                    wl_keyboard::KeyState::Released => {
 753                        let input = if keysym.is_modifier_key() {
 754                            PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 755                                modifiers: state.modifiers,
 756                            })
 757                        } else {
 758                            PlatformInput::KeyUp(KeyUpEvent {
 759                                keystroke: Keystroke::from_xkb(
 760                                    keymap_state,
 761                                    state.modifiers,
 762                                    keycode,
 763                                ),
 764                            })
 765                        };
 766
 767                        if !keysym.is_modifier_key() {
 768                            state.repeat.current_keysym = None;
 769                        }
 770
 771                        drop(state);
 772
 773                        focused_window.handle_input(input);
 774                    }
 775                    _ => {}
 776                }
 777            }
 778            _ => {}
 779        }
 780    }
 781}
 782
 783fn linux_button_to_gpui(button: u32) -> Option<MouseButton> {
 784    // These values are coming from <linux/input-event-codes.h>.
 785    const BTN_LEFT: u32 = 0x110;
 786    const BTN_RIGHT: u32 = 0x111;
 787    const BTN_MIDDLE: u32 = 0x112;
 788    const BTN_SIDE: u32 = 0x113;
 789    const BTN_EXTRA: u32 = 0x114;
 790    const BTN_FORWARD: u32 = 0x115;
 791    const BTN_BACK: u32 = 0x116;
 792
 793    Some(match button {
 794        BTN_LEFT => MouseButton::Left,
 795        BTN_RIGHT => MouseButton::Right,
 796        BTN_MIDDLE => MouseButton::Middle,
 797        BTN_BACK | BTN_SIDE => MouseButton::Navigate(NavigationDirection::Back),
 798        BTN_FORWARD | BTN_EXTRA => MouseButton::Navigate(NavigationDirection::Forward),
 799        _ => return None,
 800    })
 801}
 802
 803impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
 804    fn event(
 805        state: &mut Self,
 806        wl_pointer: &wl_pointer::WlPointer,
 807        event: wl_pointer::Event,
 808        data: &(),
 809        conn: &Connection,
 810        qh: &QueueHandle<Self>,
 811    ) {
 812        let mut cursor_state = state.cursor_state.borrow_mut();
 813        let mut state = state.client_state_inner.borrow_mut();
 814
 815        if cursor_state.cursor.is_none() {
 816            cursor_state.cursor = Some(Cursor::new(&conn, &state.compositor, &qh, &state.shm, 24));
 817        }
 818        let cursor_icon_name = cursor_state.cursor_icon_name.clone();
 819        let mut cursor: &mut Cursor = cursor_state.cursor.as_mut().unwrap();
 820
 821        match event {
 822            wl_pointer::Event::Enter {
 823                serial,
 824                surface,
 825                surface_x,
 826                surface_y,
 827                ..
 828            } => {
 829                let mut mouse_focused_window = None;
 830                for window in &state.windows {
 831                    if window.1.surface.id() == surface.id() {
 832                        window.1.set_focused(true);
 833                        mouse_focused_window = Some(Rc::clone(&window.1));
 834                    }
 835                }
 836                if mouse_focused_window.is_some() {
 837                    state.mouse_focused_window = mouse_focused_window;
 838                    cursor.set_serial_id(serial);
 839                    cursor.set_icon(&wl_pointer, cursor_icon_name);
 840                }
 841
 842                state.mouse_location = Some(Point {
 843                    x: Pixels::from(surface_x),
 844                    y: Pixels::from(surface_y),
 845                });
 846            }
 847            wl_pointer::Event::Motion {
 848                time,
 849                surface_x,
 850                surface_y,
 851                ..
 852            } => {
 853                if state.mouse_focused_window.is_none() {
 854                    return;
 855                }
 856                state.mouse_location = Some(Point {
 857                    x: Pixels::from(surface_x),
 858                    y: Pixels::from(surface_y),
 859                });
 860                state.mouse_focused_window.as_ref().unwrap().handle_input(
 861                    PlatformInput::MouseMove(MouseMoveEvent {
 862                        position: state.mouse_location.unwrap(),
 863                        pressed_button: state.button_pressed,
 864                        modifiers: state.modifiers,
 865                    }),
 866                );
 867                cursor.set_icon(&wl_pointer, cursor_icon_name);
 868            }
 869            wl_pointer::Event::Button {
 870                button,
 871                state: WEnum::Value(button_state),
 872                ..
 873            } => {
 874                let button = linux_button_to_gpui(button);
 875                let Some(button) = button else { return };
 876                if state.mouse_focused_window.is_none() || state.mouse_location.is_none() {
 877                    return;
 878                }
 879                match button_state {
 880                    wl_pointer::ButtonState::Pressed => {
 881                        state.button_pressed = Some(button);
 882                        state.mouse_focused_window.as_ref().unwrap().handle_input(
 883                            PlatformInput::MouseDown(MouseDownEvent {
 884                                button,
 885                                position: state.mouse_location.unwrap(),
 886                                modifiers: state.modifiers,
 887                                click_count: 1,
 888                            }),
 889                        );
 890                    }
 891                    wl_pointer::ButtonState::Released => {
 892                        state.button_pressed = None;
 893                        state.mouse_focused_window.as_ref().unwrap().handle_input(
 894                            PlatformInput::MouseUp(MouseUpEvent {
 895                                button,
 896                                position: state.mouse_location.unwrap(),
 897                                modifiers: Modifiers::default(),
 898                                click_count: 1,
 899                            }),
 900                        );
 901                    }
 902                    _ => {}
 903                }
 904            }
 905            wl_pointer::Event::AxisRelativeDirection {
 906                direction: WEnum::Value(direction),
 907                ..
 908            } => {
 909                state.scroll_direction = match direction {
 910                    AxisRelativeDirection::Identical => -1.0,
 911                    AxisRelativeDirection::Inverted => 1.0,
 912                    _ => -1.0,
 913                }
 914            }
 915            wl_pointer::Event::Axis {
 916                time,
 917                axis: WEnum::Value(axis),
 918                value,
 919                ..
 920            } => {
 921                let focused_window = &state.mouse_focused_window;
 922                let mouse_location = &state.mouse_location;
 923                if let (Some(focused_window), Some(mouse_location)) =
 924                    (focused_window, mouse_location)
 925                {
 926                    let value = value * state.scroll_direction;
 927                    focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent {
 928                        position: *mouse_location,
 929                        delta: match axis {
 930                            wl_pointer::Axis::VerticalScroll => {
 931                                ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32)))
 932                            }
 933                            wl_pointer::Axis::HorizontalScroll => {
 934                                ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0)))
 935                            }
 936                            _ => unimplemented!(),
 937                        },
 938                        modifiers: state.modifiers,
 939                        touch_phase: TouchPhase::Started,
 940                    }))
 941                }
 942            }
 943            wl_pointer::Event::Leave { surface, .. } => {
 944                let focused_window = &state.mouse_focused_window;
 945                if let Some(focused_window) = focused_window {
 946                    focused_window.handle_input(PlatformInput::MouseMove(MouseMoveEvent {
 947                        position: Point::<Pixels>::default(),
 948                        pressed_button: None,
 949                        modifiers: Modifiers::default(),
 950                    }));
 951                    focused_window.set_focused(false);
 952                }
 953                state.mouse_focused_window = None;
 954                state.mouse_location = None;
 955            }
 956            _ => {}
 957        }
 958    }
 959}
 960
 961impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientState {
 962    fn event(
 963        state: &mut Self,
 964        _: &wp_fractional_scale_v1::WpFractionalScaleV1,
 965        event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
 966        id: &ObjectId,
 967        _: &Connection,
 968        _: &QueueHandle<Self>,
 969    ) {
 970        let mut state = state.client_state_inner.borrow_mut();
 971        if let wp_fractional_scale_v1::Event::PreferredScale { scale, .. } = event {
 972            for window in &state.windows {
 973                if window.0.id() == *id {
 974                    window.1.rescale(scale as f32 / 120.0);
 975                    return;
 976                }
 977            }
 978        }
 979    }
 980}
 981
 982impl Dispatch<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, ObjectId>
 983    for WaylandClientState
 984{
 985    fn event(
 986        state: &mut Self,
 987        _: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
 988        event: zxdg_toplevel_decoration_v1::Event,
 989        surface_id: &ObjectId,
 990        _: &Connection,
 991        _: &QueueHandle<Self>,
 992    ) {
 993        let mut state = state.client_state_inner.borrow_mut();
 994        if let zxdg_toplevel_decoration_v1::Event::Configure { mode, .. } = event {
 995            for window in &state.windows {
 996                if window.0.id() == *surface_id {
 997                    match mode {
 998                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => {
 999                            window
1000                                .1
1001                                .set_decoration_state(WaylandDecorationState::Server);
1002                        }
1003                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => {
1004                            window
1005                                .1
1006                                .set_decoration_state(WaylandDecorationState::Client);
1007                        }
1008                        WEnum::Value(_) => {
1009                            log::warn!("Unknown decoration mode");
1010                        }
1011                        WEnum::Unknown(v) => {
1012                            log::warn!("Unknown decoration mode: {}", v);
1013                        }
1014                    }
1015                    return;
1016                }
1017            }
1018        }
1019    }
1020}