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: _states,
 524        } = event
 525        {
 526            if width == 0 || height == 0 {
 527                return;
 528            }
 529            for window in &state.windows {
 530                if window.1.toplevel.id() == xdg_toplevel.id() {
 531                    window.1.resize(width, height);
 532                    window.1.surface.commit();
 533                    return;
 534                }
 535            }
 536        } else if let xdg_toplevel::Event::Close = event {
 537            state.windows.retain(|(_, window)| {
 538                if window.toplevel.id() == xdg_toplevel.id() {
 539                    window.toplevel.destroy();
 540                    false
 541                } else {
 542                    true
 543                }
 544            });
 545            state.platform_inner.loop_signal.stop();
 546        }
 547    }
 548}
 549
 550impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientState {
 551    fn event(
 552        _: &mut Self,
 553        wm_base: &xdg_wm_base::XdgWmBase,
 554        event: <xdg_wm_base::XdgWmBase as Proxy>::Event,
 555        _: &(),
 556        _: &Connection,
 557        _: &QueueHandle<Self>,
 558    ) {
 559        if let xdg_wm_base::Event::Ping { serial } = event {
 560            wm_base.pong(serial);
 561        }
 562    }
 563}
 564
 565impl Dispatch<wl_seat::WlSeat, ()> for WaylandClientState {
 566    fn event(
 567        state: &mut Self,
 568        seat: &wl_seat::WlSeat,
 569        event: wl_seat::Event,
 570        data: &(),
 571        conn: &Connection,
 572        qh: &QueueHandle<Self>,
 573    ) {
 574        if let wl_seat::Event::Capabilities {
 575            capabilities: WEnum::Value(capabilities),
 576        } = event
 577        {
 578            if capabilities.contains(wl_seat::Capability::Keyboard) {
 579                seat.get_keyboard(qh, ());
 580            }
 581            if capabilities.contains(wl_seat::Capability::Pointer) {
 582                seat.get_pointer(qh, ());
 583            }
 584        }
 585    }
 586}
 587
 588impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
 589    fn event(
 590        this: &mut Self,
 591        keyboard: &wl_keyboard::WlKeyboard,
 592        event: wl_keyboard::Event,
 593        data: &(),
 594        conn: &Connection,
 595        qh: &QueueHandle<Self>,
 596    ) {
 597        let mut state = this.client_state_inner.borrow_mut();
 598        match event {
 599            wl_keyboard::Event::RepeatInfo { rate, delay } => {
 600                state.repeat.characters_per_second = rate as u32;
 601                state.repeat.delay = Duration::from_millis(delay as u64);
 602            }
 603            wl_keyboard::Event::Keymap {
 604                format: WEnum::Value(format),
 605                fd,
 606                size,
 607                ..
 608            } => {
 609                assert_eq!(
 610                    format,
 611                    wl_keyboard::KeymapFormat::XkbV1,
 612                    "Unsupported keymap format"
 613                );
 614                let keymap = unsafe {
 615                    xkb::Keymap::new_from_fd(
 616                        &xkb::Context::new(xkb::CONTEXT_NO_FLAGS),
 617                        fd,
 618                        size as usize,
 619                        XKB_KEYMAP_FORMAT_TEXT_V1,
 620                        KEYMAP_COMPILE_NO_FLAGS,
 621                    )
 622                    .unwrap()
 623                }
 624                .unwrap();
 625                state.keymap_state = Some(xkb::State::new(&keymap));
 626            }
 627            wl_keyboard::Event::Enter { surface, .. } => {
 628                state.keyboard_focused_window = state
 629                    .windows
 630                    .iter()
 631                    .find(|&w| w.1.surface.id() == surface.id())
 632                    .map(|w| w.1.clone());
 633
 634                if let Some(window) = &state.keyboard_focused_window {
 635                    window.set_focused(true);
 636                }
 637            }
 638            wl_keyboard::Event::Leave { surface, .. } => {
 639                let keyboard_focused_window = state
 640                    .windows
 641                    .iter()
 642                    .find(|&w| w.1.surface.id() == surface.id())
 643                    .map(|w| w.1.clone());
 644
 645                if let Some(window) = keyboard_focused_window {
 646                    window.set_focused(false);
 647                }
 648
 649                state.keyboard_focused_window = None;
 650            }
 651            wl_keyboard::Event::Modifiers {
 652                mods_depressed,
 653                mods_latched,
 654                mods_locked,
 655                group,
 656                ..
 657            } => {
 658                let keymap_state = state.keymap_state.as_mut().unwrap();
 659                keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
 660
 661                let shift =
 662                    keymap_state.mod_name_is_active(xkb::MOD_NAME_SHIFT, xkb::STATE_MODS_EFFECTIVE);
 663                let alt =
 664                    keymap_state.mod_name_is_active(xkb::MOD_NAME_ALT, xkb::STATE_MODS_EFFECTIVE);
 665                let control =
 666                    keymap_state.mod_name_is_active(xkb::MOD_NAME_CTRL, xkb::STATE_MODS_EFFECTIVE);
 667                let command =
 668                    keymap_state.mod_name_is_active(xkb::MOD_NAME_LOGO, xkb::STATE_MODS_EFFECTIVE);
 669
 670                state.modifiers.shift = shift;
 671                state.modifiers.alt = alt;
 672                state.modifiers.control = control;
 673                state.modifiers.command = command;
 674            }
 675            wl_keyboard::Event::Key {
 676                key,
 677                state: WEnum::Value(key_state),
 678                ..
 679            } => {
 680                let focused_window = &state.keyboard_focused_window;
 681                let Some(focused_window) = focused_window else {
 682                    return;
 683                };
 684                let focused_window = focused_window.clone();
 685
 686                let keymap_state = state.keymap_state.as_ref().unwrap();
 687                let keycode = Keycode::from(key + MIN_KEYCODE);
 688                let keysym = keymap_state.key_get_one_sym(keycode);
 689
 690                match key_state {
 691                    wl_keyboard::KeyState::Pressed => {
 692                        let input = if keysym.is_modifier_key() {
 693                            PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 694                                modifiers: state.modifiers,
 695                            })
 696                        } else {
 697                            PlatformInput::KeyDown(KeyDownEvent {
 698                                keystroke: Keystroke::from_xkb(
 699                                    keymap_state,
 700                                    state.modifiers,
 701                                    keycode,
 702                                ),
 703                                is_held: false, // todo(linux)
 704                            })
 705                        };
 706
 707                        if !keysym.is_modifier_key() {
 708                            state.repeat.current_id += 1;
 709                            state.repeat.current_keysym = Some(keysym);
 710
 711                            let rate = state.repeat.characters_per_second;
 712                            let delay = state.repeat.delay;
 713                            let id = state.repeat.current_id;
 714                            let this = this.clone();
 715
 716                            let timer = Timer::from_duration(delay);
 717                            let state_ = Rc::clone(&this.client_state_inner);
 718                            let input_ = input.clone();
 719                            state
 720                                .loop_handle
 721                                .insert_source(timer, move |event, _metadata, shared_data| {
 722                                    let state_ = state_.borrow_mut();
 723                                    let is_repeating = id == state_.repeat.current_id
 724                                        && state_.repeat.current_keysym.is_some()
 725                                        && state_.keyboard_focused_window.is_some();
 726
 727                                    if !is_repeating {
 728                                        return TimeoutAction::Drop;
 729                                    }
 730
 731                                    let focused_window =
 732                                        state_.keyboard_focused_window.as_ref().unwrap().clone();
 733
 734                                    drop(state_);
 735
 736                                    focused_window.handle_input(input_.clone());
 737
 738                                    TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
 739                                })
 740                                .unwrap();
 741                        }
 742
 743                        drop(state);
 744
 745                        focused_window.handle_input(input);
 746                    }
 747                    wl_keyboard::KeyState::Released => {
 748                        let input = if keysym.is_modifier_key() {
 749                            PlatformInput::ModifiersChanged(ModifiersChangedEvent {
 750                                modifiers: state.modifiers,
 751                            })
 752                        } else {
 753                            PlatformInput::KeyUp(KeyUpEvent {
 754                                keystroke: Keystroke::from_xkb(
 755                                    keymap_state,
 756                                    state.modifiers,
 757                                    keycode,
 758                                ),
 759                            })
 760                        };
 761
 762                        if !keysym.is_modifier_key() {
 763                            state.repeat.current_keysym = None;
 764                        }
 765
 766                        drop(state);
 767
 768                        focused_window.handle_input(input);
 769                    }
 770                    _ => {}
 771                }
 772            }
 773            _ => {}
 774        }
 775    }
 776}
 777
 778fn linux_button_to_gpui(button: u32) -> Option<MouseButton> {
 779    // These values are coming from <linux/input-event-codes.h>.
 780    const BTN_LEFT: u32 = 0x110;
 781    const BTN_RIGHT: u32 = 0x111;
 782    const BTN_MIDDLE: u32 = 0x112;
 783    const BTN_SIDE: u32 = 0x113;
 784    const BTN_EXTRA: u32 = 0x114;
 785    const BTN_FORWARD: u32 = 0x115;
 786    const BTN_BACK: u32 = 0x116;
 787
 788    Some(match button {
 789        BTN_LEFT => MouseButton::Left,
 790        BTN_RIGHT => MouseButton::Right,
 791        BTN_MIDDLE => MouseButton::Middle,
 792        BTN_BACK | BTN_SIDE => MouseButton::Navigate(NavigationDirection::Back),
 793        BTN_FORWARD | BTN_EXTRA => MouseButton::Navigate(NavigationDirection::Forward),
 794        _ => return None,
 795    })
 796}
 797
 798impl Dispatch<wl_pointer::WlPointer, ()> for WaylandClientState {
 799    fn event(
 800        state: &mut Self,
 801        wl_pointer: &wl_pointer::WlPointer,
 802        event: wl_pointer::Event,
 803        data: &(),
 804        conn: &Connection,
 805        qh: &QueueHandle<Self>,
 806    ) {
 807        let mut cursor_state = state.cursor_state.borrow_mut();
 808        let mut state = state.client_state_inner.borrow_mut();
 809
 810        if cursor_state.cursor.is_none() {
 811            cursor_state.cursor = Some(Cursor::new(&conn, &state.compositor, &qh, &state.shm, 24));
 812        }
 813        let cursor_icon_name = cursor_state.cursor_icon_name.clone();
 814        let mut cursor: &mut Cursor = cursor_state.cursor.as_mut().unwrap();
 815
 816        match event {
 817            wl_pointer::Event::Enter {
 818                serial,
 819                surface,
 820                surface_x,
 821                surface_y,
 822                ..
 823            } => {
 824                let mut mouse_focused_window = None;
 825                for window in &state.windows {
 826                    if window.1.surface.id() == surface.id() {
 827                        window.1.set_focused(true);
 828                        mouse_focused_window = Some(Rc::clone(&window.1));
 829                    }
 830                }
 831                if mouse_focused_window.is_some() {
 832                    state.mouse_focused_window = mouse_focused_window;
 833                    cursor.set_serial_id(serial);
 834                    cursor.set_icon(&wl_pointer, cursor_icon_name);
 835                }
 836
 837                state.mouse_location = Some(Point {
 838                    x: Pixels::from(surface_x),
 839                    y: Pixels::from(surface_y),
 840                });
 841            }
 842            wl_pointer::Event::Motion {
 843                time,
 844                surface_x,
 845                surface_y,
 846                ..
 847            } => {
 848                if state.mouse_focused_window.is_none() {
 849                    return;
 850                }
 851                state.mouse_location = Some(Point {
 852                    x: Pixels::from(surface_x),
 853                    y: Pixels::from(surface_y),
 854                });
 855                state.mouse_focused_window.as_ref().unwrap().handle_input(
 856                    PlatformInput::MouseMove(MouseMoveEvent {
 857                        position: state.mouse_location.unwrap(),
 858                        pressed_button: state.button_pressed,
 859                        modifiers: state.modifiers,
 860                    }),
 861                );
 862                cursor.set_icon(&wl_pointer, cursor_icon_name);
 863            }
 864            wl_pointer::Event::Button {
 865                button,
 866                state: WEnum::Value(button_state),
 867                ..
 868            } => {
 869                let button = linux_button_to_gpui(button);
 870                let Some(button) = button else { return };
 871                if state.mouse_focused_window.is_none() || state.mouse_location.is_none() {
 872                    return;
 873                }
 874                match button_state {
 875                    wl_pointer::ButtonState::Pressed => {
 876                        state.button_pressed = Some(button);
 877                        state.mouse_focused_window.as_ref().unwrap().handle_input(
 878                            PlatformInput::MouseDown(MouseDownEvent {
 879                                button,
 880                                position: state.mouse_location.unwrap(),
 881                                modifiers: state.modifiers,
 882                                click_count: 1,
 883                            }),
 884                        );
 885                    }
 886                    wl_pointer::ButtonState::Released => {
 887                        state.button_pressed = None;
 888                        state.mouse_focused_window.as_ref().unwrap().handle_input(
 889                            PlatformInput::MouseUp(MouseUpEvent {
 890                                button,
 891                                position: state.mouse_location.unwrap(),
 892                                modifiers: Modifiers::default(),
 893                                click_count: 1,
 894                            }),
 895                        );
 896                    }
 897                    _ => {}
 898                }
 899            }
 900            wl_pointer::Event::AxisRelativeDirection {
 901                direction: WEnum::Value(direction),
 902                ..
 903            } => {
 904                state.scroll_direction = match direction {
 905                    AxisRelativeDirection::Identical => -1.0,
 906                    AxisRelativeDirection::Inverted => 1.0,
 907                    _ => -1.0,
 908                }
 909            }
 910            wl_pointer::Event::Axis {
 911                time,
 912                axis: WEnum::Value(axis),
 913                value,
 914                ..
 915            } => {
 916                let focused_window = &state.mouse_focused_window;
 917                let mouse_location = &state.mouse_location;
 918                if let (Some(focused_window), Some(mouse_location)) =
 919                    (focused_window, mouse_location)
 920                {
 921                    let value = value * state.scroll_direction;
 922                    focused_window.handle_input(PlatformInput::ScrollWheel(ScrollWheelEvent {
 923                        position: *mouse_location,
 924                        delta: match axis {
 925                            wl_pointer::Axis::VerticalScroll => {
 926                                ScrollDelta::Pixels(Point::new(Pixels(0.0), Pixels(value as f32)))
 927                            }
 928                            wl_pointer::Axis::HorizontalScroll => {
 929                                ScrollDelta::Pixels(Point::new(Pixels(value as f32), Pixels(0.0)))
 930                            }
 931                            _ => unimplemented!(),
 932                        },
 933                        modifiers: state.modifiers,
 934                        touch_phase: TouchPhase::Started,
 935                    }))
 936                }
 937            }
 938            wl_pointer::Event::Leave { surface, .. } => {
 939                let focused_window = &state.mouse_focused_window;
 940                if let Some(focused_window) = focused_window {
 941                    focused_window.handle_input(PlatformInput::MouseMove(MouseMoveEvent {
 942                        position: Point::<Pixels>::default(),
 943                        pressed_button: None,
 944                        modifiers: Modifiers::default(),
 945                    }));
 946                    focused_window.set_focused(false);
 947                }
 948                state.mouse_focused_window = None;
 949                state.mouse_location = None;
 950            }
 951            _ => {}
 952        }
 953    }
 954}
 955
 956impl Dispatch<wp_fractional_scale_v1::WpFractionalScaleV1, ObjectId> for WaylandClientState {
 957    fn event(
 958        state: &mut Self,
 959        _: &wp_fractional_scale_v1::WpFractionalScaleV1,
 960        event: <wp_fractional_scale_v1::WpFractionalScaleV1 as Proxy>::Event,
 961        id: &ObjectId,
 962        _: &Connection,
 963        _: &QueueHandle<Self>,
 964    ) {
 965        let mut state = state.client_state_inner.borrow_mut();
 966        if let wp_fractional_scale_v1::Event::PreferredScale { scale, .. } = event {
 967            for window in &state.windows {
 968                if window.0.id() == *id {
 969                    window.1.rescale(scale as f32 / 120.0);
 970                    return;
 971                }
 972            }
 973        }
 974    }
 975}
 976
 977impl Dispatch<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1, ObjectId>
 978    for WaylandClientState
 979{
 980    fn event(
 981        state: &mut Self,
 982        _: &zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1,
 983        event: zxdg_toplevel_decoration_v1::Event,
 984        surface_id: &ObjectId,
 985        _: &Connection,
 986        _: &QueueHandle<Self>,
 987    ) {
 988        let mut state = state.client_state_inner.borrow_mut();
 989        if let zxdg_toplevel_decoration_v1::Event::Configure { mode, .. } = event {
 990            for window in &state.windows {
 991                if window.0.id() == *surface_id {
 992                    match mode {
 993                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => {
 994                            window
 995                                .1
 996                                .set_decoration_state(WaylandDecorationState::Server);
 997                        }
 998                        WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => {
 999                            window
1000                                .1
1001                                .set_decoration_state(WaylandDecorationState::Client);
1002                        }
1003                        WEnum::Value(_) => {
1004                            log::warn!("Unknown decoration mode");
1005                        }
1006                        WEnum::Unknown(v) => {
1007                            log::warn!("Unknown decoration mode: {}", v);
1008                        }
1009                    }
1010                    return;
1011                }
1012            }
1013        }
1014    }
1015}