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