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        let mut cursor_state = self.state.cursor_state.borrow_mut();
 317        cursor_state.cursor_icon_name = cursor_icon_name;
 318    }
 319
 320    fn get_clipboard(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
 321        self.state.clipboard.clone()
 322    }
 323
 324    fn get_primary(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
 325        self.state.primary.clone()
 326    }
 327}
 328
 329impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientState {
 330    fn event(
 331        state: &mut Self,
 332        registry: &wl_registry::WlRegistry,
 333        event: wl_registry::Event,
 334        _: &GlobalListContents,
 335        _: &Connection,
 336        qh: &QueueHandle<Self>,
 337    ) {
 338        let mut state = state.client_state_inner.borrow_mut();
 339        match event {
 340            wl_registry::Event::Global {
 341                name,
 342                interface,
 343                version,
 344            } => match &interface[..] {
 345                "wl_seat" => {
 346                    registry.bind::<wl_seat::WlSeat, _, _>(name, wl_seat_version(version), qh, ());
 347                }
 348                "wl_output" => {
 349                    state.outputs.push((
 350                        registry.bind::<wl_output::WlOutput, _, _>(name, WL_OUTPUT_VERSION, qh, ()),
 351                        Rc::new(RefCell::new(OutputState::default())),
 352                    ));
 353                }
 354                _ => {}
 355            },
 356            wl_registry::Event::GlobalRemove { name: _ } => {}
 357            _ => {}
 358        }
 359    }
 360}
 361
 362delegate_noop!(WaylandClientState: ignore wl_compositor::WlCompositor);
 363delegate_noop!(WaylandClientState: ignore wl_shm::WlShm);
 364delegate_noop!(WaylandClientState: ignore wl_shm_pool::WlShmPool);
 365delegate_noop!(WaylandClientState: ignore wl_buffer::WlBuffer);
 366delegate_noop!(WaylandClientState: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
 367delegate_noop!(WaylandClientState: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
 368delegate_noop!(WaylandClientState: ignore wp_viewporter::WpViewporter);
 369delegate_noop!(WaylandClientState: ignore wp_viewport::WpViewport);
 370
 371impl Dispatch<WlCallback, Arc<WlSurface>> for WaylandClientState {
 372    fn event(
 373        state: &mut Self,
 374        _: &WlCallback,
 375        event: wl_callback::Event,
 376        surf: &Arc<WlSurface>,
 377        _: &Connection,
 378        qh: &QueueHandle<Self>,
 379    ) {
 380        let mut state = state.client_state_inner.borrow_mut();
 381        if let wl_callback::Event::Done { .. } = event {
 382            for window in &state.windows {
 383                if window.1.surface.id() == surf.id() {
 384                    window.1.surface.frame(qh, surf.clone());
 385                    window.1.update();
 386                    window.1.surface.commit();
 387                }
 388            }
 389        }
 390    }
 391}
 392
 393impl Dispatch<wl_surface::WlSurface, ()> for WaylandClientState {
 394    fn event(
 395        state: &mut Self,
 396        surface: &wl_surface::WlSurface,
 397        event: <wl_surface::WlSurface as Proxy>::Event,
 398        _: &(),
 399        _: &Connection,
 400        _: &QueueHandle<Self>,
 401    ) {
 402        let mut state = state.client_state_inner.borrow_mut();
 403
 404        // We use `WpFractionalScale` instead to set the scale if it's available
 405        // or give up on scaling if `WlSurface::set_buffer_scale` isn't available
 406        if state.fractional_scale_manager.is_some()
 407            || state.compositor.version() < wl_surface::REQ_SET_BUFFER_SCALE_SINCE
 408        {
 409            return;
 410        }
 411
 412        let Some(window) = state
 413            .windows
 414            .iter()
 415            .map(|(_, state)| state)
 416            .find(|state| &*state.surface == surface)
 417        else {
 418            return;
 419        };
 420
 421        let mut outputs = window.outputs.borrow_mut();
 422
 423        match event {
 424            wl_surface::Event::Enter { output } => {
 425                // We use `PreferredBufferScale` instead to set the scale if it's available
 426                if surface.version() >= wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE {
 427                    return;
 428                }
 429                let mut scale = 1;
 430                for global_output in &state.outputs {
 431                    if output == global_output.0 {
 432                        outputs.insert(output.id());
 433                        scale = scale.max(global_output.1.borrow().scale.get());
 434                    } else if outputs.contains(&global_output.0.id()) {
 435                        scale = scale.max(global_output.1.borrow().scale.get());
 436                    }
 437                }
 438                window.rescale(scale as f32);
 439                window.surface.set_buffer_scale(scale as i32);
 440            }
 441            wl_surface::Event::Leave { output } => {
 442                // We use `PreferredBufferScale` instead to set the scale if it's available
 443                if surface.version() >= 6 {
 444                    return;
 445                }
 446
 447                outputs.remove(&output.id());
 448
 449                let mut scale = 1;
 450                for global_output in &state.outputs {
 451                    if outputs.contains(&global_output.0.id()) {
 452                        scale = scale.max(global_output.1.borrow().scale.get());
 453                    }
 454                }
 455                window.rescale(scale as f32);
 456                window.surface.set_buffer_scale(scale as i32);
 457            }
 458            wl_surface::Event::PreferredBufferScale { factor } => {
 459                window.rescale(factor as f32);
 460                surface.set_buffer_scale(factor);
 461            }
 462            _ => {}
 463        }
 464    }
 465}
 466
 467#[derive(Debug, Clone)]
 468struct OutputState {
 469    scale: NonZeroU32,
 470}
 471
 472impl Default for OutputState {
 473    fn default() -> Self {
 474        Self {
 475            scale: NonZeroU32::new(1).unwrap(),
 476        }
 477    }
 478}
 479
 480impl Dispatch<wl_output::WlOutput, ()> for WaylandClientState {
 481    fn event(
 482        state: &mut Self,
 483        output: &wl_output::WlOutput,
 484        event: <wl_output::WlOutput as Proxy>::Event,
 485        _: &(),
 486        _: &Connection,
 487        _: &QueueHandle<Self>,
 488    ) {
 489        let mut state = state.client_state_inner.borrow_mut();
 490        let mut output_state = state
 491            .outputs
 492            .iter_mut()
 493            .find(|(o, _)| o == output)
 494            .map(|(_, state)| state)
 495            .unwrap()
 496            .borrow_mut();
 497        match event {
 498            wl_output::Event::Scale { factor } => {
 499                if factor > 0 {
 500                    output_state.scale = NonZeroU32::new(factor as u32).unwrap();
 501                }
 502            }
 503            _ => {}
 504        }
 505    }
 506}
 507
 508impl Dispatch<xdg_surface::XdgSurface, ()> for WaylandClientState {
 509    fn event(
 510        state: &mut Self,
 511        xdg_surface: &xdg_surface::XdgSurface,
 512        event: xdg_surface::Event,
 513        _: &(),
 514        _: &Connection,
 515        _: &QueueHandle<Self>,
 516    ) {
 517        let mut state = state.client_state_inner.borrow_mut();
 518        if let xdg_surface::Event::Configure { serial, .. } = event {
 519            xdg_surface.ack_configure(serial);
 520            for window in &state.windows {
 521                if &window.0 == xdg_surface {
 522                    window.1.update();
 523                    window.1.surface.commit();
 524                    return;
 525                }
 526            }
 527        }
 528    }
 529}
 530
 531impl Dispatch<xdg_toplevel::XdgToplevel, ()> for WaylandClientState {
 532    fn event(
 533        state: &mut Self,
 534        xdg_toplevel: &xdg_toplevel::XdgToplevel,
 535        event: <xdg_toplevel::XdgToplevel as Proxy>::Event,
 536        _: &(),
 537        _: &Connection,
 538        _: &QueueHandle<Self>,
 539    ) {
 540        let mut state = state.client_state_inner.borrow_mut();
 541        if let xdg_toplevel::Event::Configure {
 542            width,
 543            height,
 544            states,
 545        } = event
 546        {
 547            let width = NonZeroU32::new(width as u32);
 548            let height = NonZeroU32::new(height as u32);
 549            let fullscreen = states.contains(&(xdg_toplevel::State::Fullscreen as u8));
 550            for window in &state.windows {
 551                if window.1.toplevel.id() == xdg_toplevel.id() {
 552                    window.1.resize(width, height);
 553                    window.1.set_fullscreen(fullscreen);
 554                    window.1.surface.commit();
 555                    return;
 556                }
 557            }
 558        } else if let xdg_toplevel::Event::Close = event {
 559            state.windows.retain(|(_, window)| {
 560                if window.toplevel.id() == xdg_toplevel.id() {
 561                    window.toplevel.destroy();
 562                    false
 563                } else {
 564                    true
 565                }
 566            });
 567            state.platform_inner.loop_signal.stop();
 568        }
 569    }
 570}
 571
 572impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientState {
 573    fn event(
 574        _: &mut Self,
 575        wm_base: &xdg_wm_base::XdgWmBase,
 576        event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
 577        _: &(),
 578        _: &Connection,
 579        _: &QueueHandle<Self>,
 580    ) {
 581        if let xdg_wm_base::Event::Ping { serial } = event {
 582            wm_base.pong(serial);
 583        }
 584    }
 585}
 586
 587impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientState {
 588    fn event(
 589        state: &mut Self,
 590        seat: &wl_seat::WlSeat,
 591        event: wl_seat::Event,
 592        data: &(),
 593        conn: &Connection,
 594        qh: &QueueHandle<Self>,
 595    ) {
 596        if let wl_seat::Event::Capabilities {
 597            capabilities: WEnum::Value(capabilities),
 598        } = event
 599        {
 600            if capabilities.contains(wl_seat::Capability::Keyboard) {
 601                seat.get_keyboard(qh, ());
 602            }
 603            if capabilities.contains(wl_seat::Capability::Pointer) {
 604                seat.get_pointer(qh, ());
 605            }
 606        }
 607    }
 608}
 609
 610impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
 611    fn event(
 612        this: &mut Self,
 613        keyboard: &wl_keyboard::WlKeyboard,
 614        event: wl_keyboard::Event,
 615        data: &(),
 616        conn: &Connection,
 617        qh: &QueueHandle<Self>,
 618    ) {
 619        let mut state = this.client_state_inner.borrow_mut();
 620        match event {
 621            wl_keyboard::Event::RepeatInfo { rate, delay } => {
 622                state.repeat.characters_per_second = rate as u32;
 623                state.repeat.delay = Duration::from_millis(delay as u64);
 624            }
 625            wl_keyboard::Event::Keymap {
 626                format: WEnum::Value(format),
 627                fd,
 628                size,
 629                ..
 630            } => {
 631                assert_eq!(
 632                    format,
 633                    wl_keyboard::KeymapFormat::XkbV1,
 634                    "Unsupported keymap format"
 635                );
 636                let keymap = unsafe {
 637                    xkb::Keymap::new_from_fd(
 638                        &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
 639                        fd,
 640                        size as usize,
 641                        XKB_KEYMAP_FORMAT_TEXT_V1,
 642                        KEYMAP_COMPILE_NO_FLAGS,
 643                    )
 644                    .unwrap()
 645                }
 646                .unwrap();
 647                state.keymap_state = Some(xkb::State::new(&keymap));
 648            }
 649            wl_keyboard::Event::Enter { surface, .. } => {
 650                state.keyboard_focused_window = state
 651                    .windows
 652                    .iter()
 653                    .find(|&w| w.1.surface.id() == surface.id())
 654                    .map(|w| w.1.clone());
 655
 656                if let Some(window) = &state.keyboard_focused_window {
 657                    window.set_focused(true);
 658                }
 659            }
 660            wl_keyboard::Event::Leave { surface, .. } => {
 661                let keyboard_focused_window = state
 662                    .windows
 663                    .iter()
 664                    .find(|&w| w.1.surface.id() == surface.id())
 665                    .map(|w| w.1.clone());
 666
 667                if let Some(window) = keyboard_focused_window {
 668                    window.set_focused(false);
 669                }
 670
 671                state.keyboard_focused_window = None;
 672            }
 673            wl_keyboard::Event::Modifiers {
 674                mods_depressed,
 675                mods_latched,
 676                mods_locked,
 677                group,
 678                ..
 679            } => {
 680                let keymap_state = state.keymap_state.as_mut().unwrap();
 681                keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
 682
 683                let shift =
 684                    keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE);
 685                let alt =
 686                    keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);
 687                let control =
 688                    keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);
 689                let command =
 690                    keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE);
 691
 692                state.modifiers.shift = shift;
 693                state.modifiers.alt = alt;
 694                state.modifiers.control = control;
 695                state.modifiers.command = command;
 696            }
 697            wl_keyboard::Event::Key {
 698                key,
 699                state: WEnum::Value(key_state),
 700                ..
 701            } => {
 702                let focused_window = &state.keyboard_focused_window;
 703                let Some(focused_window) = focused_window else {
 704                    return;
 705                };
 706                let focused_window = focused_window.clone();
 707
 708                let keymap_state = state.keymap_state.as_ref().unwrap();
 709                let keycode = Keycode::from(key + MIN_KEYCODE);
 710                let keysym = keymap_state.key_get_one_sym(keycode);
 711
 712                match key_state {
 713                    wl_keyboard::KeyState::Pressed => {
 714                        let input = if keysym.is_modifier_key() {
 715                            PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 716                                modifiers: state.modifiers,
 717                            })
 718                        } else {
 719                            PlatformInput::KeyDown(KeyDownEvent {
 720                                keystroke: Keystroke::from_xkb(
 721                                    keymap_state,
 722                                    state.modifiers,
 723                                    keycode,
 724                                ),
 725                                is_held: false, // todo(linux)
 726                            })
 727                        };
 728
 729                        if !keysym.is_modifier_key() {
 730                            state.repeat.current_id += 1;
 731                            state.repeat.current_keysym = Some(keysym);
 732
 733                            let rate = state.repeat.characters_per_second;
 734                            let delay = state.repeat.delay;
 735                            let id = state.repeat.current_id;
 736                            let this = this.clone();
 737
 738                            let timer = Timer::from_duration(delay);
 739                            let state_ = Rc::clone(&this.client_state_inner);
 740                            let input_ = input.clone();
 741                            state
 742                                .loop_handle
 743                                .insert_source(timer, move |event, _metadata, shared_data| {
 744                                    let state_ = state_.borrow_mut();
 745                                    let is_repeating = id == state_.repeat.current_id
 746                                        && state_.repeat.current_keysym.is_some()
 747                                        && state_.keyboard_focused_window.is_some();
 748
 749                                    if !is_repeating {
 750                                        return TimeoutAction::Drop;
 751                                    }
 752
 753                                    let focused_window =
 754                                        state_.keyboard_focused_window.as_ref().unwrap().clone();
 755
 756                                    drop(state_);
 757
 758                                    focused_window.handle_input(input_.clone());
 759
 760                                    TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
 761                                })
 762                                .unwrap();
 763                        }
 764
 765                        drop(state);
 766
 767                        focused_window.handle_input(input);
 768                    }
 769                    wl_keyboard::KeyState::Released => {
 770                        let input = if keysym.is_modifier_key() {
 771                            PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 772                                modifiers: state.modifiers,
 773                            })
 774                        } else {
 775                            PlatformInput::KeyUp(KeyUpEvent {
 776                                keystroke: Keystroke::from_xkb(
 777                                    keymap_state,
 778                                    state.modifiers,
 779                                    keycode,
 780                                ),
 781                            })
 782                        };
 783
 784                        if !keysym.is_modifier_key() {
 785                            state.repeat.current_keysym = None;
 786                        }
 787
 788                        drop(state);
 789
 790                        focused_window.handle_input(input);
 791                    }
 792                    _ => {}
 793                }
 794            }
 795            _ => {}
 796        }
 797    }
 798}
 799
 800fn linux_button_to_gpui(button: u32) -> Option<MouseButton> {
 801    // These values are coming from <linux/input-event-codes.h>.
 802    const BTN_LEFT: u32 = 0x110;
 803    const BTN_RIGHT: u32 = 0x111;
 804    const BTN_MIDDLE: u32 = 0x112;
 805    const BTN_SIDE: u32 = 0x113;
 806    const BTN_EXTRA: u32 = 0x114;
 807    const BTN_FORWARD: u32 = 0x115;
 808    const BTN_BACK: u32 = 0x116;
 809
 810    Some(match button {
 811        BTN_LEFT => MouseButton::Left,
 812        BTN_RIGHT => MouseButton::Right,
 813        BTN_MIDDLE => MouseButton::Middle,
 814        BTN_BACK | BTN_SIDE => MouseButton::Navigate(NavigationDirection::Back),
 815        BTN_FORWARD | BTN_EXTRA => MouseButton::Navigate(NavigationDirection::Forward),
 816        _ => return None,
 817    })
 818}
 819
 820impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
 821    fn event(
 822        state: &mut Self,
 823        wl_pointer: &wl_pointer::WlPointer,
 824        event: wl_pointer::Event,
 825        data: &(),
 826        conn: &Connection,
 827        qh: &QueueHandle<Self>,
 828    ) {
 829        let mut cursor_state = state.cursor_state.borrow_mut();
 830        let mut state = state.client_state_inner.borrow_mut();
 831
 832        if cursor_state.cursor.is_none() {
 833            cursor_state.cursor = Some(Cursor::new(&conn, &state.compositor, &qh, &state.shm, 24));
 834        }
 835        let cursor_icon_name = cursor_state.cursor_icon_name.clone();
 836        let mut cursor: &mut Cursor = cursor_state.cursor.as_mut().unwrap();
 837
 838        match event {
 839            wl_pointer::Event::Enter {
 840                serial,
 841                surface,
 842                surface_x,
 843                surface_y,
 844                ..
 845            } => {
 846                let mut mouse_focused_window = None;
 847                for window in &state.windows {
 848                    if window.1.surface.id() == surface.id() {
 849                        window.1.set_focused(true);
 850                        mouse_focused_window = Some(Rc::clone(&window.1));
 851                    }
 852                }
 853                if mouse_focused_window.is_some() {
 854                    state.mouse_focused_window = mouse_focused_window;
 855                    cursor.set_serial_id(serial);
 856                    cursor.set_icon(&wl_pointer, cursor_icon_name);
 857                }
 858
 859                state.mouse_location = Some(Point {
 860                    x: Pixels::from(surface_x),
 861                    y: Pixels::from(surface_y),
 862                });
 863            }
 864            wl_pointer::Event::Motion {
 865                time,
 866                surface_x,
 867                surface_y,
 868                ..
 869            } => {
 870                if state.mouse_focused_window.is_none() {
 871                    return;
 872                }
 873                state.mouse_location = Some(Point {
 874                    x: Pixels::from(surface_x),
 875                    y: Pixels::from(surface_y),
 876                });
 877                state.mouse_focused_window.as_ref().unwrap().handle_input(
 878                    PlatformInput::MouseMove(MouseMoveEvent {
 879                        position: state.mouse_location.unwrap(),
 880                        pressed_button: state.button_pressed,
 881                        modifiers: state.modifiers,
 882                    }),
 883                );
 884                cursor.set_icon(&wl_pointer, cursor_icon_name);
 885            }
 886            wl_pointer::Event::Button {
 887                button,
 888                state: WEnum::Value(button_state),
 889                ..
 890            } => {
 891                let button = linux_button_to_gpui(button);
 892                let Some(button) = button else { return };
 893                if state.mouse_focused_window.is_none() || state.mouse_location.is_none() {
 894                    return;
 895                }
 896                match button_state {
 897                    wl_pointer::ButtonState::Pressed => {
 898                        state.button_pressed = Some(button);
 899                        state.mouse_focused_window.as_ref().unwrap().handle_input(
 900                            PlatformInput::MouseDown(MouseDownEvent {
 901                                button,
 902                                position: state.mouse_location.unwrap(),
 903                                modifiers: state.modifiers,
 904                                click_count: 1,
 905                            }),
 906                        );
 907                    }
 908                    wl_pointer::ButtonState::Released => {
 909                        state.button_pressed = None;
 910                        state.mouse_focused_window.as_ref().unwrap().handle_input(
 911                            PlatformInput::MouseUp(MouseUpEvent {
 912                                button,
 913                                position: state.mouse_location.unwrap(),
 914                                modifiers: Modifiers::default(),
 915                                click_count: 1,
 916                            }),
 917                        );
 918                    }
 919                    _ => {}
 920                }
 921            }
 922            wl_pointer::Event::AxisRelativeDirection {
 923                direction: WEnum::Value(direction),
 924                ..
 925            } => {
 926                state.scroll_direction = match direction {
 927                    AxisRelativeDirection::Identical => -1.0,
 928                    AxisRelativeDirection::Inverted => 1.0,
 929                    _ => -1.0,
 930                }
 931            }
 932            wl_pointer::Event::AxisSource {
 933                axis_source: WEnum::Value(axis_source),
 934            } => {
 935                state.axis_source = axis_source;
 936            }
 937            wl_pointer::Event::AxisValue120 {
 938                axis: WEnum::Value(axis),
 939                value120,
 940            } => {
 941                let focused_window = &state.mouse_focused_window;
 942                let mouse_location = &state.mouse_location;
 943                if let (Some(focused_window), Some(mouse_location)) =
 944                    (focused_window, mouse_location)
 945                {
 946                    let value = value120 as f64 * state.scroll_direction;
 947                    focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent {
 948                        position: *mouse_location,
 949                        delta: match axis {
 950                            wl_pointer::Axis::VerticalScroll => {
 951                                ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32)))
 952                            }
 953                            wl_pointer::Axis::HorizontalScroll => {
 954                                ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0)))
 955                            }
 956                            _ => unimplemented!(),
 957                        },
 958                        modifiers: state.modifiers,
 959                        touch_phase: TouchPhase::Moved,
 960                    }))
 961                }
 962            }
 963            wl_pointer::Event::Axis {
 964                time,
 965                axis: WEnum::Value(axis),
 966                value,
 967                ..
 968            } => {
 969                if wl_pointer.version() >= wl_pointer::EVT_AXIS_VALUE120_SINCE
 970                    && state.axis_source != AxisSource::Continuous
 971                {
 972                    return;
 973                }
 974
 975                let focused_window = &state.mouse_focused_window;
 976                let mouse_location = &state.mouse_location;
 977                if let (Some(focused_window), Some(mouse_location)) =
 978                    (focused_window, mouse_location)
 979                {
 980                    let value = value * state.scroll_direction;
 981                    focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent {
 982                        position: *mouse_location,
 983                        delta: match axis {
 984                            wl_pointer::Axis::VerticalScroll => {
 985                                ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32)))
 986                            }
 987                            wl_pointer::Axis::HorizontalScroll => {
 988                                ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0)))
 989                            }
 990                            _ => unimplemented!(),
 991                        },
 992                        modifiers: state.modifiers,
 993                        touch_phase: TouchPhase::Moved,
 994                    }))
 995                }
 996            }
 997            wl_pointer::Event::Leave { surface, .. } => {
 998                let focused_window = &state.mouse_focused_window;
 999                if let Some(focused_window) = focused_window {
1000                    focused_window.handle_input(PlatformInput::MouseMove(MouseMoveEvent {
1001                        position: Point::<Pixels>::default(),
1002                        pressed_button: None,
1003                        modifiers: Modifiers::default(),
1004                    }));
1005                    focused_window.set_focused(false);
1006                }
1007                state.mouse_focused_window = None;
1008                state.mouse_location = None;
1009            }
1010            _ => {}
1011        }
1012    }
1013}
1014
1015impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientState {
1016    fn event(
1017        state: &mut Self,
1018        _: &wp_fractional_scale_v1::WpFractionalScaleV1,
1019        event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
1020        id: &ObjectId,
1021        _: &Connection,
1022        _: &QueueHandle<Self>,
1023    ) {
1024        let mut state = state.client_state_inner.borrow_mut();
1025        if let wp_fractional_scale_v1::Event::PreferredScale { scale, .. } = event {
1026            for window in &state.windows {
1027                if window.0.id() == *id {
1028                    window.1.rescale(scale as f32 / 120.0);
1029                    return;
1030                }
1031            }
1032        }
1033    }
1034}
1035
1036impl Dispatch<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, ObjectId>
1037    for WaylandClientState
1038{
1039    fn event(
1040        state: &mut Self,
1041        _: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
1042        event: zxdg_toplevel_decoration_v1::Event,
1043        surface_id: &ObjectId,
1044        _: &Connection,
1045        _: &QueueHandle<Self>,
1046    ) {
1047        let mut state = state.client_state_inner.borrow_mut();
1048        if let zxdg_toplevel_decoration_v1::Event::Configure { mode, .. } = event {
1049            for window in &state.windows {
1050                if window.0.id() == *surface_id {
1051                    match mode {
1052                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => {
1053                            window
1054                                .1
1055                                .set_decoration_state(WaylandDecorationState::Server);
1056                        }
1057                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => {
1058                            window
1059                                .1
1060                                .set_decoration_state(WaylandDecorationState::Client);
1061                        }
1062                        WEnum::Value(_) => {
1063                            log::warn!("Unknown decoration mode");
1064                        }
1065                        WEnum::Unknown(v) => {
1066                            log::warn!("Unknown decoration mode: {}", v);
1067                        }
1068                    }
1069                    return;
1070                }
1071            }
1072        }
1073    }
1074}