client.rs

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