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