client.rs

   1use std::cell::RefCell;
   2use std::collections::HashSet;
   3use std::ops::Deref;
   4use std::os::fd::AsRawFd;
   5use std::rc::{Rc, Weak};
   6use std::sync::Arc;
   7use std::time::{Duration, Instant};
   8
   9use anyhow::Context;
  10use async_task::Runnable;
  11use calloop::channel::Channel;
  12
  13use collections::HashMap;
  14
  15use futures::channel::oneshot;
  16use mio::{Interest, Token, Waker};
  17use util::ResultExt;
  18use x11rb::connection::{Connection, RequestConnection};
  19use x11rb::cursor;
  20use x11rb::errors::ConnectionError;
  21use x11rb::protocol::xinput::ConnectionExt;
  22use x11rb::protocol::xkb::ConnectionExt as _;
  23use x11rb::protocol::xproto::{ChangeWindowAttributesAux, ConnectionExt as _};
  24use x11rb::protocol::{randr, render, xinput, xkb, xproto, Event};
  25use x11rb::resource_manager::Database;
  26use x11rb::xcb_ffi::XCBConnection;
  27use xim::{x11rb::X11rbClient, Client};
  28use xim::{AttributeName, InputStyle};
  29use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION};
  30use xkbcommon::xkb as xkbc;
  31
  32use crate::platform::linux::LinuxClient;
  33use crate::platform::{LinuxCommon, PlatformWindow};
  34use crate::{
  35    modifiers_from_xinput_info, point, px, AnyWindowHandle, Bounds, ClipboardItem, CursorStyle,
  36    DisplayId, Keystroke, Modifiers, ModifiersChangedEvent, Pixels, PlatformDisplay, PlatformInput,
  37    Point, QuitSignal, ScrollDelta, Size, TouchPhase, WindowParams, X11Window,
  38};
  39
  40use super::{
  41    super::{get_xkb_compose_state, open_uri_internal, SCROLL_LINES},
  42    X11Display, X11WindowStatePtr, XcbAtoms,
  43};
  44use super::{button_of_key, modifiers_from_state, pressed_button_from_mask};
  45use super::{XimCallbackEvent, XimHandler};
  46use crate::platform::linux::is_within_click_distance;
  47use crate::platform::linux::platform::DOUBLE_CLICK_INTERVAL;
  48use crate::platform::linux::xdg_desktop_portal::{Event as XDPEvent, XDPEventSource};
  49
  50pub(super) const XINPUT_MASTER_DEVICE: u16 = 1;
  51
  52pub(crate) struct WindowRef {
  53    window: X11WindowStatePtr,
  54}
  55
  56impl WindowRef {
  57    pub fn handle(&self) -> AnyWindowHandle {
  58        self.window.state.borrow().handle
  59    }
  60}
  61
  62impl Deref for WindowRef {
  63    type Target = X11WindowStatePtr;
  64
  65    fn deref(&self) -> &Self::Target {
  66        &self.window
  67    }
  68}
  69
  70#[derive(Debug)]
  71#[non_exhaustive]
  72pub enum EventHandlerError {
  73    XCBConnectionError(ConnectionError),
  74    XIMClientError(xim::ClientError),
  75}
  76
  77impl std::error::Error for EventHandlerError {}
  78
  79impl std::fmt::Display for EventHandlerError {
  80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  81        match self {
  82            EventHandlerError::XCBConnectionError(err) => err.fmt(f),
  83            EventHandlerError::XIMClientError(err) => err.fmt(f),
  84        }
  85    }
  86}
  87
  88impl From<ConnectionError> for EventHandlerError {
  89    fn from(err: ConnectionError) -> Self {
  90        EventHandlerError::XCBConnectionError(err)
  91    }
  92}
  93
  94impl From<xim::ClientError> for EventHandlerError {
  95    fn from(err: xim::ClientError) -> Self {
  96        EventHandlerError::XIMClientError(err)
  97    }
  98}
  99
 100pub struct X11ClientState {
 101    /// poll is in an Option so we can take it out in `run()` without
 102    /// mutating self.
 103    poll: Option<mio::Poll>,
 104    quit_signal_rx: oneshot::Receiver<()>,
 105    runnables: Channel<Runnable>,
 106    xdp_event_source: XDPEventSource,
 107
 108    pub(crate) last_click: Instant,
 109    pub(crate) last_location: Point<Pixels>,
 110    pub(crate) current_count: usize,
 111
 112    pub(crate) scale_factor: f32,
 113    pub(crate) xcb_connection: Rc<XCBConnection>,
 114    pub(crate) x_root_index: usize,
 115    pub(crate) _resource_database: Database,
 116    pub(crate) atoms: XcbAtoms,
 117    pub(crate) windows: HashMap<xproto::Window, WindowRef>,
 118    pub(crate) focused_window: Option<xproto::Window>,
 119    pub(crate) xkb: xkbc::State,
 120    pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>,
 121    pub(crate) xim_handler: Option<XimHandler>,
 122    pub modifiers: Modifiers,
 123
 124    pub(crate) compose_state: Option<xkbc::compose::State>,
 125    pub(crate) pre_edit_text: Option<String>,
 126    pub(crate) composing: bool,
 127    pub(crate) cursor_handle: cursor::Handle,
 128    pub(crate) cursor_styles: HashMap<xproto::Window, CursorStyle>,
 129    pub(crate) cursor_cache: HashMap<CursorStyle, xproto::Cursor>,
 130
 131    pub(crate) scroll_class_data: Vec<xinput::DeviceClassDataScroll>,
 132    pub(crate) scroll_x: Option<f32>,
 133    pub(crate) scroll_y: Option<f32>,
 134
 135    pub(crate) common: LinuxCommon,
 136    pub(crate) clipboard: x11_clipboard::Clipboard,
 137    pub(crate) clipboard_item: Option<ClipboardItem>,
 138}
 139
 140#[derive(Clone)]
 141pub struct X11ClientStatePtr(pub Weak<RefCell<X11ClientState>>);
 142
 143impl X11ClientStatePtr {
 144    pub fn drop_window(&self, x_window: u32) {
 145        let client = X11Client(self.0.upgrade().expect("client already dropped"));
 146        let mut state = client.0.borrow_mut();
 147
 148        if state.windows.remove(&x_window).is_none() {
 149            log::warn!(
 150                "failed to remove X window {} from client state, does not exist",
 151                x_window
 152            );
 153        }
 154
 155        state.cursor_styles.remove(&x_window);
 156
 157        if state.windows.is_empty() {
 158            state.common.quit_signal.quit();
 159        }
 160    }
 161}
 162
 163struct ChannelQuitSignal {
 164    tx: Option<oneshot::Sender<()>>,
 165    waker: Option<Arc<Waker>>,
 166}
 167
 168impl ChannelQuitSignal {
 169    fn new(waker: Option<Arc<Waker>>) -> (Self, oneshot::Receiver<()>) {
 170        let (tx, rx) = oneshot::channel::<()>();
 171
 172        let quit_signal = ChannelQuitSignal {
 173            tx: Some(tx),
 174            waker,
 175        };
 176
 177        (quit_signal, rx)
 178    }
 179}
 180
 181impl QuitSignal for ChannelQuitSignal {
 182    fn quit(&mut self) {
 183        if let Some(tx) = self.tx.take() {
 184            tx.send(()).log_err();
 185            if let Some(waker) = self.waker.as_ref() {
 186                waker.wake().ok();
 187            }
 188        }
 189    }
 190}
 191
 192#[derive(Clone)]
 193pub(crate) struct X11Client(Rc<RefCell<X11ClientState>>);
 194
 195impl X11Client {
 196    pub(crate) fn new() -> Self {
 197        let mut poll = mio::Poll::new().unwrap();
 198
 199        let waker = Arc::new(Waker::new(poll.registry(), WAKER_TOKEN).unwrap());
 200
 201        let (quit_signal, quit_signal_rx) = ChannelQuitSignal::new(Some(waker.clone()));
 202        let (common, runnables) = LinuxCommon::new(Box::new(quit_signal), Some(waker.clone()));
 203
 204        let (xcb_connection, x_root_index) = XCBConnection::connect(None).unwrap();
 205        xcb_connection
 206            .prefetch_extension_information(xkb::X11_EXTENSION_NAME)
 207            .unwrap();
 208        xcb_connection
 209            .prefetch_extension_information(randr::X11_EXTENSION_NAME)
 210            .unwrap();
 211        xcb_connection
 212            .prefetch_extension_information(render::X11_EXTENSION_NAME)
 213            .unwrap();
 214        xcb_connection
 215            .prefetch_extension_information(xinput::X11_EXTENSION_NAME)
 216            .unwrap();
 217
 218        let xinput_version = xcb_connection
 219            .xinput_xi_query_version(2, 0)
 220            .unwrap()
 221            .reply()
 222            .unwrap();
 223        assert!(
 224            xinput_version.major_version >= 2,
 225            "XInput Extension v2 not supported."
 226        );
 227
 228        let master_device_query = xcb_connection
 229            .xinput_xi_query_device(XINPUT_MASTER_DEVICE)
 230            .unwrap()
 231            .reply()
 232            .unwrap();
 233        let scroll_class_data = master_device_query
 234            .infos
 235            .iter()
 236            .find(|info| info.type_ == xinput::DeviceType::MASTER_POINTER)
 237            .unwrap()
 238            .classes
 239            .iter()
 240            .filter_map(|class| class.data.as_scroll())
 241            .map(|class| *class)
 242            .collect::<Vec<_>>();
 243
 244        let atoms = XcbAtoms::new(&xcb_connection).unwrap();
 245        let xkb = xcb_connection
 246            .xkb_use_extension(XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION)
 247            .unwrap();
 248
 249        let atoms = atoms.reply().unwrap();
 250        let xkb = xkb.reply().unwrap();
 251        let events = xkb::EventType::STATE_NOTIFY;
 252        xcb_connection
 253            .xkb_select_events(
 254                xkb::ID::USE_CORE_KBD.into(),
 255                0u8.into(),
 256                events,
 257                0u8.into(),
 258                0u8.into(),
 259                &xkb::SelectEventsAux::new(),
 260            )
 261            .unwrap();
 262        assert!(xkb.supported);
 263
 264        let xkb_context = xkbc::Context::new(xkbc::CONTEXT_NO_FLAGS);
 265        let xkb_state = {
 266            let xkb_device_id = xkbc::x11::get_core_keyboard_device_id(&xcb_connection);
 267            let xkb_keymap = xkbc::x11::keymap_new_from_device(
 268                &xkb_context,
 269                &xcb_connection,
 270                xkb_device_id,
 271                xkbc::KEYMAP_COMPILE_NO_FLAGS,
 272            );
 273            xkbc::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id)
 274        };
 275        let compose_state = get_xkb_compose_state(&xkb_context);
 276        let resource_database = x11rb::resource_manager::new_from_default(&xcb_connection).unwrap();
 277
 278        let scale_factor = resource_database
 279            .get_value("Xft.dpi", "Xft.dpi")
 280            .ok()
 281            .flatten()
 282            .map(|dpi: f32| dpi / 96.0)
 283            .unwrap_or(1.0);
 284
 285        let cursor_handle = cursor::Handle::new(&xcb_connection, x_root_index, &resource_database)
 286            .unwrap()
 287            .reply()
 288            .unwrap();
 289
 290        let clipboard = x11_clipboard::Clipboard::new().unwrap();
 291
 292        let xcb_connection = Rc::new(xcb_connection);
 293
 294        let ximc = X11rbClient::init(Rc::clone(&xcb_connection), x_root_index, None).ok();
 295        let xim_handler = if ximc.is_some() {
 296            Some(XimHandler::new())
 297        } else {
 298            None
 299        };
 300
 301        let xdp_event_source =
 302            XDPEventSource::new(&common.background_executor, Some(waker.clone()));
 303
 304        X11Client(Rc::new(RefCell::new(X11ClientState {
 305            poll: Some(poll),
 306            runnables,
 307
 308            xdp_event_source,
 309            quit_signal_rx,
 310            common,
 311
 312            modifiers: Modifiers::default(),
 313            last_click: Instant::now(),
 314            last_location: Point::new(px(0.0), px(0.0)),
 315            current_count: 0,
 316            scale_factor,
 317
 318            xcb_connection,
 319            x_root_index,
 320            _resource_database: resource_database,
 321            atoms,
 322            windows: HashMap::default(),
 323            focused_window: None,
 324            xkb: xkb_state,
 325            ximc,
 326            xim_handler,
 327
 328            compose_state,
 329            pre_edit_text: None,
 330            composing: false,
 331
 332            cursor_handle,
 333            cursor_styles: HashMap::default(),
 334            cursor_cache: HashMap::default(),
 335
 336            scroll_class_data,
 337            scroll_x: None,
 338            scroll_y: None,
 339
 340            clipboard,
 341            clipboard_item: None,
 342        })))
 343    }
 344
 345    pub fn enable_ime(&self) {
 346        let mut state = self.0.borrow_mut();
 347        if state.ximc.is_none() {
 348            return;
 349        }
 350
 351        let mut ximc = state.ximc.take().unwrap();
 352        let mut xim_handler = state.xim_handler.take().unwrap();
 353        let mut ic_attributes = ximc
 354            .build_ic_attributes()
 355            .push(
 356                AttributeName::InputStyle,
 357                InputStyle::PREEDIT_CALLBACKS
 358                    | InputStyle::STATUS_NOTHING
 359                    | InputStyle::PREEDIT_NONE,
 360            )
 361            .push(AttributeName::ClientWindow, xim_handler.window)
 362            .push(AttributeName::FocusWindow, xim_handler.window);
 363
 364        let window_id = state.focused_window;
 365        drop(state);
 366        if let Some(window_id) = window_id {
 367            let window = self.get_window(window_id).unwrap();
 368            if let Some(area) = window.get_ime_area() {
 369                ic_attributes =
 370                    ic_attributes.nested_list(xim::AttributeName::PreeditAttributes, |b| {
 371                        b.push(
 372                            xim::AttributeName::SpotLocation,
 373                            xim::Point {
 374                                x: u32::from(area.origin.x + area.size.width) as i16,
 375                                y: u32::from(area.origin.y + area.size.height) as i16,
 376                            },
 377                        );
 378                    });
 379            }
 380        }
 381        ximc.create_ic(xim_handler.im_id, ic_attributes.build())
 382            .ok();
 383        state = self.0.borrow_mut();
 384        state.xim_handler = Some(xim_handler);
 385        state.ximc = Some(ximc);
 386    }
 387
 388    pub fn disable_ime(&self) {
 389        let mut state = self.0.borrow_mut();
 390        state.composing = false;
 391        if let Some(mut ximc) = state.ximc.take() {
 392            let xim_handler = state.xim_handler.as_ref().unwrap();
 393            ximc.destroy_ic(xim_handler.im_id, xim_handler.ic_id).ok();
 394            state.ximc = Some(ximc);
 395        }
 396    }
 397
 398    fn get_window(&self, win: xproto::Window) -> Option<X11WindowStatePtr> {
 399        let state = self.0.borrow();
 400        state
 401            .windows
 402            .get(&win)
 403            .filter(|window_reference| !window_reference.window.state.borrow().destroyed)
 404            .map(|window_reference| window_reference.window.clone())
 405    }
 406
 407    fn read_x11_events(&self) -> (HashSet<u32>, Vec<Event>) {
 408        let mut events = Vec::new();
 409        let mut windows_to_refresh = HashSet::new();
 410        let mut state = self.0.borrow_mut();
 411
 412        let mut last_key_release: Option<Event> = None;
 413
 414        loop {
 415            match state.xcb_connection.poll_for_event() {
 416                Ok(Some(event)) => {
 417                    if let Event::Expose(expose_event) = event {
 418                        windows_to_refresh.insert(expose_event.window);
 419                    } else {
 420                        match event {
 421                            Event::KeyRelease(_) => {
 422                                last_key_release = Some(event);
 423                            }
 424                            Event::KeyPress(key_press) => {
 425                                if let Some(Event::KeyRelease(key_release)) =
 426                                    last_key_release.take()
 427                                {
 428                                    // We ignore that last KeyRelease if it's too close to this KeyPress,
 429                                    // suggesting that it's auto-generated by X11 as a key-repeat event.
 430                                    if key_release.detail != key_press.detail
 431                                        || key_press.time.wrapping_sub(key_release.time) > 20
 432                                    {
 433                                        events.push(Event::KeyRelease(key_release));
 434                                    }
 435                                }
 436                                events.push(Event::KeyPress(key_press));
 437                            }
 438                            _ => {
 439                                if let Some(release_event) = last_key_release.take() {
 440                                    events.push(release_event);
 441                                }
 442                                events.push(event);
 443                            }
 444                        }
 445                    }
 446                }
 447                Ok(None) => {
 448                    // Add any remaining stored KeyRelease event
 449                    if let Some(release_event) = last_key_release.take() {
 450                        events.push(release_event);
 451                    }
 452                    break;
 453                }
 454                Err(e) => {
 455                    log::warn!("error polling for X11 events: {e:?}");
 456                    break;
 457                }
 458            }
 459        }
 460
 461        (windows_to_refresh, events)
 462    }
 463
 464    fn process_x11_events(&self, events: Vec<Event>) {
 465        for event in events.into_iter() {
 466            let mut state = self.0.borrow_mut();
 467            if state.ximc.is_none() || state.xim_handler.is_none() {
 468                drop(state);
 469                self.handle_event(event);
 470                continue;
 471            }
 472
 473            let mut ximc = state.ximc.take().unwrap();
 474            let mut xim_handler = state.xim_handler.take().unwrap();
 475            let xim_connected = xim_handler.connected;
 476            drop(state);
 477
 478            // let xim_filtered = false;
 479            let xim_filtered = match ximc.filter_event(&event, &mut xim_handler) {
 480                Ok(handled) => handled,
 481                Err(err) => {
 482                    log::error!("XIMClientError: {}", err);
 483                    false
 484                }
 485            };
 486            let xim_callback_event = xim_handler.last_callback_event.take();
 487
 488            let mut state = self.0.borrow_mut();
 489            state.ximc = Some(ximc);
 490            state.xim_handler = Some(xim_handler);
 491
 492            if let Some(event) = xim_callback_event {
 493                drop(state);
 494                self.handle_xim_callback_event(event);
 495            } else {
 496                drop(state);
 497            }
 498
 499            if xim_filtered {
 500                continue;
 501            }
 502
 503            if xim_connected {
 504                self.xim_handle_event(event);
 505            } else {
 506                self.handle_event(event);
 507            }
 508        }
 509    }
 510
 511    fn handle_event(&self, event: Event) -> Option<()> {
 512        match event {
 513            Event::ClientMessage(event) => {
 514                let window = self.get_window(event.window)?;
 515                let [atom, _arg1, arg2, arg3, _arg4] = event.data.as_data32();
 516                let mut state = self.0.borrow_mut();
 517
 518                if atom == state.atoms.WM_DELETE_WINDOW {
 519                    // window "x" button clicked by user
 520                    if window.should_close() {
 521                        // Rest of the close logic is handled in drop_window()
 522                        window.close();
 523                    }
 524                } else if atom == state.atoms._NET_WM_SYNC_REQUEST {
 525                    window.state.borrow_mut().last_sync_counter =
 526                        Some(x11rb::protocol::sync::Int64 {
 527                            lo: arg2,
 528                            hi: arg3 as i32,
 529                        })
 530                }
 531            }
 532            Event::ConfigureNotify(event) => {
 533                let bounds = Bounds {
 534                    origin: Point {
 535                        x: event.x.into(),
 536                        y: event.y.into(),
 537                    },
 538                    size: Size {
 539                        width: event.width.into(),
 540                        height: event.height.into(),
 541                    },
 542                };
 543                let window = self.get_window(event.window)?;
 544                window.configure(bounds);
 545            }
 546            Event::PropertyNotify(event) => {
 547                let window = self.get_window(event.window)?;
 548                window.property_notify(event);
 549            }
 550            Event::Expose(event) => {
 551                let window = self.get_window(event.window)?;
 552                window.refresh();
 553            }
 554            Event::FocusIn(event) => {
 555                let window = self.get_window(event.event)?;
 556                window.set_focused(true);
 557                let mut state = self.0.borrow_mut();
 558                state.focused_window = Some(event.event);
 559                drop(state);
 560                self.enable_ime();
 561            }
 562            Event::FocusOut(event) => {
 563                let window = self.get_window(event.event)?;
 564                window.set_focused(false);
 565                let mut state = self.0.borrow_mut();
 566                state.focused_window = None;
 567                if let Some(compose_state) = state.compose_state.as_mut() {
 568                    compose_state.reset();
 569                }
 570                state.pre_edit_text.take();
 571                drop(state);
 572                self.disable_ime();
 573                window.handle_ime_delete();
 574            }
 575            Event::XkbStateNotify(event) => {
 576                let mut state = self.0.borrow_mut();
 577                state.xkb.update_mask(
 578                    event.base_mods.into(),
 579                    event.latched_mods.into(),
 580                    event.locked_mods.into(),
 581                    0,
 582                    0,
 583                    event.locked_group.into(),
 584                );
 585
 586                let modifiers = Modifiers::from_xkb(&state.xkb);
 587                if state.modifiers == modifiers {
 588                    drop(state);
 589                } else {
 590                    let focused_window_id = state.focused_window?;
 591                    state.modifiers = modifiers;
 592                    drop(state);
 593
 594                    let focused_window = self.get_window(focused_window_id)?;
 595                    focused_window.handle_input(PlatformInput::ModifiersChanged(
 596                        ModifiersChangedEvent { modifiers },
 597                    ));
 598                }
 599            }
 600            Event::KeyPress(event) => {
 601                let window = self.get_window(event.event)?;
 602                let mut state = self.0.borrow_mut();
 603
 604                let modifiers = modifiers_from_state(event.state);
 605                state.modifiers = modifiers;
 606
 607                let keystroke = {
 608                    let code = event.detail.into();
 609                    let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
 610                    state.xkb.update_key(code, xkbc::KeyDirection::Down);
 611                    let keysym = state.xkb.key_get_one_sym(code);
 612                    if keysym.is_modifier_key() {
 613                        return Some(());
 614                    }
 615                    if let Some(mut compose_state) = state.compose_state.take() {
 616                        compose_state.feed(keysym);
 617                        match compose_state.status() {
 618                            xkbc::Status::Composed => {
 619                                state.pre_edit_text.take();
 620                                keystroke.ime_key = compose_state.utf8();
 621                                if let Some(keysym) = compose_state.keysym() {
 622                                    keystroke.key = xkbc::keysym_get_name(keysym);
 623                                }
 624                            }
 625                            xkbc::Status::Composing => {
 626                                keystroke.ime_key = None;
 627                                state.pre_edit_text = compose_state
 628                                    .utf8()
 629                                    .or(crate::Keystroke::underlying_dead_key(keysym));
 630                                let pre_edit =
 631                                    state.pre_edit_text.clone().unwrap_or(String::default());
 632                                drop(state);
 633                                window.handle_ime_preedit(pre_edit);
 634                                state = self.0.borrow_mut();
 635                            }
 636                            xkbc::Status::Cancelled => {
 637                                let pre_edit = state.pre_edit_text.take();
 638                                drop(state);
 639                                if let Some(pre_edit) = pre_edit {
 640                                    window.handle_ime_commit(pre_edit);
 641                                }
 642                                if let Some(current_key) = Keystroke::underlying_dead_key(keysym) {
 643                                    window.handle_ime_preedit(current_key);
 644                                }
 645                                state = self.0.borrow_mut();
 646                                compose_state.feed(keysym);
 647                            }
 648                            _ => {}
 649                        }
 650                        state.compose_state = Some(compose_state);
 651                    }
 652                    keystroke
 653                };
 654                drop(state);
 655                window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent {
 656                    keystroke,
 657                    is_held: false,
 658                }));
 659            }
 660            Event::KeyRelease(event) => {
 661                let window = self.get_window(event.event)?;
 662                let mut state = self.0.borrow_mut();
 663
 664                let modifiers = modifiers_from_state(event.state);
 665                state.modifiers = modifiers;
 666
 667                let keystroke = {
 668                    let code = event.detail.into();
 669                    let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
 670                    state.xkb.update_key(code, xkbc::KeyDirection::Up);
 671                    let keysym = state.xkb.key_get_one_sym(code);
 672                    if keysym.is_modifier_key() {
 673                        return Some(());
 674                    }
 675                    keystroke
 676                };
 677                drop(state);
 678                window.handle_input(PlatformInput::KeyUp(crate::KeyUpEvent { keystroke }));
 679            }
 680            Event::XinputButtonPress(event) => {
 681                let window = self.get_window(event.event)?;
 682                let mut state = self.0.borrow_mut();
 683
 684                let modifiers = modifiers_from_xinput_info(event.mods);
 685                state.modifiers = modifiers;
 686
 687                let position = point(
 688                    px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
 689                    px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
 690                );
 691
 692                if state.composing && state.ximc.is_some() {
 693                    drop(state);
 694                    self.disable_ime();
 695                    self.enable_ime();
 696                    window.handle_ime_unmark();
 697                    state = self.0.borrow_mut();
 698                } else if let Some(text) = state.pre_edit_text.take() {
 699                    if let Some(compose_state) = state.compose_state.as_mut() {
 700                        compose_state.reset();
 701                    }
 702                    drop(state);
 703                    window.handle_ime_commit(text);
 704                    state = self.0.borrow_mut();
 705                }
 706                if let Some(button) = button_of_key(event.detail.try_into().unwrap()) {
 707                    let click_elapsed = state.last_click.elapsed();
 708
 709                    if click_elapsed < DOUBLE_CLICK_INTERVAL
 710                        && is_within_click_distance(state.last_location, position)
 711                    {
 712                        state.current_count += 1;
 713                    } else {
 714                        state.current_count = 1;
 715                    }
 716
 717                    state.last_click = Instant::now();
 718                    state.last_location = position;
 719                    let current_count = state.current_count;
 720
 721                    drop(state);
 722                    window.handle_input(PlatformInput::MouseDown(crate::MouseDownEvent {
 723                        button,
 724                        position,
 725                        modifiers,
 726                        click_count: current_count,
 727                        first_mouse: false,
 728                    }));
 729                } else {
 730                    log::warn!("Unknown button press: {event:?}");
 731                }
 732            }
 733            Event::XinputButtonRelease(event) => {
 734                let window = self.get_window(event.event)?;
 735                let mut state = self.0.borrow_mut();
 736                let modifiers = modifiers_from_xinput_info(event.mods);
 737                state.modifiers = modifiers;
 738
 739                let position = point(
 740                    px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
 741                    px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
 742                );
 743                if let Some(button) = button_of_key(event.detail.try_into().unwrap()) {
 744                    let click_count = state.current_count;
 745                    drop(state);
 746                    window.handle_input(PlatformInput::MouseUp(crate::MouseUpEvent {
 747                        button,
 748                        position,
 749                        modifiers,
 750                        click_count,
 751                    }));
 752                }
 753            }
 754            Event::XinputMotion(event) => {
 755                let window = self.get_window(event.event)?;
 756                let mut state = self.0.borrow_mut();
 757                let pressed_button = pressed_button_from_mask(event.button_mask[0]);
 758                let position = point(
 759                    px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
 760                    px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
 761                );
 762                let modifiers = modifiers_from_xinput_info(event.mods);
 763                state.modifiers = modifiers;
 764                drop(state);
 765
 766                let axisvalues = event
 767                    .axisvalues
 768                    .iter()
 769                    .map(|axisvalue| fp3232_to_f32(*axisvalue))
 770                    .collect::<Vec<_>>();
 771
 772                if event.valuator_mask[0] & 3 != 0 {
 773                    window.handle_input(PlatformInput::MouseMove(crate::MouseMoveEvent {
 774                        position,
 775                        pressed_button,
 776                        modifiers,
 777                    }));
 778                }
 779
 780                let mut valuator_idx = 0;
 781                let scroll_class_data = self.0.borrow().scroll_class_data.clone();
 782                for shift in 0..32 {
 783                    if (event.valuator_mask[0] >> shift) & 1 == 0 {
 784                        continue;
 785                    }
 786
 787                    for scroll_class in &scroll_class_data {
 788                        if scroll_class.scroll_type == xinput::ScrollType::HORIZONTAL
 789                            && scroll_class.number == shift
 790                        {
 791                            let new_scroll = axisvalues[valuator_idx]
 792                                / fp3232_to_f32(scroll_class.increment)
 793                                * SCROLL_LINES as f32;
 794                            let old_scroll = self.0.borrow().scroll_x;
 795                            self.0.borrow_mut().scroll_x = Some(new_scroll);
 796
 797                            if let Some(old_scroll) = old_scroll {
 798                                let delta_scroll = old_scroll - new_scroll;
 799                                window.handle_input(PlatformInput::ScrollWheel(
 800                                    crate::ScrollWheelEvent {
 801                                        position,
 802                                        delta: ScrollDelta::Lines(Point::new(delta_scroll, 0.0)),
 803                                        modifiers,
 804                                        touch_phase: TouchPhase::default(),
 805                                    },
 806                                ));
 807                            }
 808                        } else if scroll_class.scroll_type == xinput::ScrollType::VERTICAL
 809                            && scroll_class.number == shift
 810                        {
 811                            // the `increment` is the valuator delta equivalent to one positive unit of scrolling. Here that means SCROLL_LINES lines.
 812                            let new_scroll = axisvalues[valuator_idx]
 813                                / fp3232_to_f32(scroll_class.increment)
 814                                * SCROLL_LINES as f32;
 815                            let old_scroll = self.0.borrow().scroll_y;
 816                            self.0.borrow_mut().scroll_y = Some(new_scroll);
 817
 818                            if let Some(old_scroll) = old_scroll {
 819                                let delta_scroll = old_scroll - new_scroll;
 820                                let (x, y) = if !modifiers.shift {
 821                                    (0.0, delta_scroll)
 822                                } else {
 823                                    (delta_scroll, 0.0)
 824                                };
 825                                window.handle_input(PlatformInput::ScrollWheel(
 826                                    crate::ScrollWheelEvent {
 827                                        position,
 828                                        delta: ScrollDelta::Lines(Point::new(x, y)),
 829                                        modifiers,
 830                                        touch_phase: TouchPhase::default(),
 831                                    },
 832                                ));
 833                            }
 834                        }
 835                    }
 836
 837                    valuator_idx += 1;
 838                }
 839            }
 840            Event::XinputLeave(event) if event.mode == xinput::NotifyMode::NORMAL => {
 841                self.0.borrow_mut().scroll_x = None; // Set last scroll to `None` so that a large delta isn't created if scrolling is done outside the window (the valuator is global)
 842                self.0.borrow_mut().scroll_y = None;
 843
 844                let window = self.get_window(event.event)?;
 845                let mut state = self.0.borrow_mut();
 846                let pressed_button = pressed_button_from_mask(event.buttons[0]);
 847                let position = point(
 848                    px(event.event_x as f32 / u16::MAX as f32 / state.scale_factor),
 849                    px(event.event_y as f32 / u16::MAX as f32 / state.scale_factor),
 850                );
 851                let modifiers = modifiers_from_xinput_info(event.mods);
 852                state.modifiers = modifiers;
 853                drop(state);
 854
 855                window.handle_input(PlatformInput::MouseExited(crate::MouseExitEvent {
 856                    pressed_button,
 857                    position,
 858                    modifiers,
 859                }));
 860            }
 861            _ => {}
 862        };
 863
 864        Some(())
 865    }
 866
 867    fn handle_xim_callback_event(&self, event: XimCallbackEvent) {
 868        match event {
 869            XimCallbackEvent::XimXEvent(event) => {
 870                self.handle_event(event);
 871            }
 872            XimCallbackEvent::XimCommitEvent(window, text) => {
 873                self.xim_handle_commit(window, text);
 874            }
 875            XimCallbackEvent::XimPreeditEvent(window, text) => {
 876                self.xim_handle_preedit(window, text);
 877            }
 878        };
 879    }
 880
 881    fn xim_handle_event(&self, event: Event) -> Option<()> {
 882        match event {
 883            Event::KeyPress(event) | Event::KeyRelease(event) => {
 884                let mut state = self.0.borrow_mut();
 885                let mut ximc = state.ximc.take().unwrap();
 886                let mut xim_handler = state.xim_handler.take().unwrap();
 887                drop(state);
 888                xim_handler.window = event.event;
 889                ximc.forward_event(
 890                    xim_handler.im_id,
 891                    xim_handler.ic_id,
 892                    xim::ForwardEventFlag::empty(),
 893                    &event,
 894                )
 895                .unwrap();
 896                let mut state = self.0.borrow_mut();
 897                state.ximc = Some(ximc);
 898                state.xim_handler = Some(xim_handler);
 899                drop(state);
 900            }
 901            event => {
 902                self.handle_event(event);
 903            }
 904        }
 905        Some(())
 906    }
 907
 908    fn xim_handle_commit(&self, window: xproto::Window, text: String) -> Option<()> {
 909        let window = self.get_window(window).unwrap();
 910        let mut state = self.0.borrow_mut();
 911        state.composing = false;
 912        drop(state);
 913
 914        window.handle_ime_commit(text);
 915        Some(())
 916    }
 917
 918    fn xim_handle_preedit(&self, window: xproto::Window, text: String) -> Option<()> {
 919        let window = self.get_window(window).unwrap();
 920        window.handle_ime_preedit(text);
 921
 922        let mut state = self.0.borrow_mut();
 923        let mut ximc = state.ximc.take().unwrap();
 924        let mut xim_handler = state.xim_handler.take().unwrap();
 925        state.composing = true;
 926        drop(state);
 927
 928        if let Some(area) = window.get_ime_area() {
 929            let ic_attributes = ximc
 930                .build_ic_attributes()
 931                .push(
 932                    xim::AttributeName::InputStyle,
 933                    xim::InputStyle::PREEDIT_CALLBACKS
 934                        | xim::InputStyle::STATUS_NOTHING
 935                        | xim::InputStyle::PREEDIT_POSITION,
 936                )
 937                .push(xim::AttributeName::ClientWindow, xim_handler.window)
 938                .push(xim::AttributeName::FocusWindow, xim_handler.window)
 939                .nested_list(xim::AttributeName::PreeditAttributes, |b| {
 940                    b.push(
 941                        xim::AttributeName::SpotLocation,
 942                        xim::Point {
 943                            x: u32::from(area.origin.x + area.size.width) as i16,
 944                            y: u32::from(area.origin.y + area.size.height) as i16,
 945                        },
 946                    );
 947                })
 948                .build();
 949            ximc.set_ic_values(xim_handler.im_id, xim_handler.ic_id, ic_attributes)
 950                .ok();
 951        }
 952        let mut state = self.0.borrow_mut();
 953        state.ximc = Some(ximc);
 954        state.xim_handler = Some(xim_handler);
 955        drop(state);
 956        Some(())
 957    }
 958}
 959
 960const XCB_CONNECTION_TOKEN: Token = Token(0);
 961const WAKER_TOKEN: Token = Token(1);
 962
 963impl LinuxClient for X11Client {
 964    fn compositor_name(&self) -> &'static str {
 965        "X11"
 966    }
 967    fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R {
 968        f(&mut self.0.borrow_mut().common)
 969    }
 970
 971    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
 972        let state = self.0.borrow();
 973        let setup = state.xcb_connection.setup();
 974        setup
 975            .roots
 976            .iter()
 977            .enumerate()
 978            .filter_map(|(root_id, _)| {
 979                Some(Rc::new(X11Display::new(
 980                    &state.xcb_connection,
 981                    state.scale_factor,
 982                    root_id,
 983                )?) as Rc<dyn PlatformDisplay>)
 984            })
 985            .collect()
 986    }
 987
 988    fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
 989        let state = self.0.borrow();
 990
 991        Some(Rc::new(
 992            X11Display::new(
 993                &state.xcb_connection,
 994                state.scale_factor,
 995                state.x_root_index,
 996            )
 997            .expect("There should always be a root index"),
 998        ))
 999    }
1000
1001    fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1002        let state = self.0.borrow();
1003
1004        Some(Rc::new(X11Display::new(
1005            &state.xcb_connection,
1006            state.scale_factor,
1007            id.0 as usize,
1008        )?))
1009    }
1010
1011    fn open_window(
1012        &self,
1013        handle: AnyWindowHandle,
1014        params: WindowParams,
1015    ) -> anyhow::Result<Box<dyn PlatformWindow>> {
1016        let mut state = self.0.borrow_mut();
1017        let x_window = state.xcb_connection.generate_id().unwrap();
1018
1019        let window = X11Window::new(
1020            handle,
1021            X11ClientStatePtr(Rc::downgrade(&self.0)),
1022            state.common.foreground_executor.clone(),
1023            params,
1024            &state.xcb_connection,
1025            state.x_root_index,
1026            x_window,
1027            &state.atoms,
1028            state.scale_factor,
1029            state.common.appearance,
1030        )?;
1031
1032        let window_ref = WindowRef {
1033            window: window.0.clone(),
1034        };
1035
1036        state.windows.insert(x_window, window_ref);
1037        Ok(Box::new(window))
1038    }
1039
1040    fn set_cursor_style(&self, style: CursorStyle) {
1041        let mut state = self.0.borrow_mut();
1042        let Some(focused_window) = state.focused_window else {
1043            return;
1044        };
1045        let current_style = state
1046            .cursor_styles
1047            .get(&focused_window)
1048            .unwrap_or(&CursorStyle::Arrow);
1049        if *current_style == style {
1050            return;
1051        }
1052
1053        let cursor = match state.cursor_cache.get(&style) {
1054            Some(cursor) => *cursor,
1055            None => {
1056                let cursor = state
1057                    .cursor_handle
1058                    .load_cursor(&state.xcb_connection, &style.to_icon_name())
1059                    .expect("failed to load cursor");
1060                state.cursor_cache.insert(style, cursor);
1061                cursor
1062            }
1063        };
1064
1065        state.cursor_styles.insert(focused_window, style);
1066        state
1067            .xcb_connection
1068            .change_window_attributes(
1069                focused_window,
1070                &ChangeWindowAttributesAux {
1071                    cursor: Some(cursor),
1072                    ..Default::default()
1073                },
1074            )
1075            .expect("failed to change window cursor")
1076            .check()
1077            .unwrap();
1078    }
1079
1080    fn open_uri(&self, uri: &str) {
1081        open_uri_internal(uri, None);
1082    }
1083
1084    fn write_to_primary(&self, item: crate::ClipboardItem) {
1085        let state = self.0.borrow_mut();
1086        state
1087            .clipboard
1088            .store(
1089                state.clipboard.setter.atoms.primary,
1090                state.clipboard.setter.atoms.utf8_string,
1091                item.text().as_bytes(),
1092            )
1093            .ok();
1094    }
1095
1096    fn write_to_clipboard(&self, item: crate::ClipboardItem) {
1097        let mut state = self.0.borrow_mut();
1098        state
1099            .clipboard
1100            .store(
1101                state.clipboard.setter.atoms.clipboard,
1102                state.clipboard.setter.atoms.utf8_string,
1103                item.text().as_bytes(),
1104            )
1105            .ok();
1106        state.clipboard_item.replace(item);
1107    }
1108
1109    fn read_from_primary(&self) -> Option<crate::ClipboardItem> {
1110        let state = self.0.borrow_mut();
1111        state
1112            .clipboard
1113            .load(
1114                state.clipboard.getter.atoms.primary,
1115                state.clipboard.getter.atoms.utf8_string,
1116                state.clipboard.getter.atoms.property,
1117                Duration::from_secs(3),
1118            )
1119            .map(|text| crate::ClipboardItem {
1120                text: String::from_utf8(text).unwrap(),
1121                metadata: None,
1122            })
1123            .ok()
1124    }
1125
1126    fn read_from_clipboard(&self) -> Option<crate::ClipboardItem> {
1127        let state = self.0.borrow_mut();
1128        // if the last copy was from this app, return our cached item
1129        // which has metadata attached.
1130        if state
1131            .clipboard
1132            .setter
1133            .connection
1134            .get_selection_owner(state.clipboard.setter.atoms.clipboard)
1135            .ok()
1136            .and_then(|r| r.reply().ok())
1137            .map(|reply| reply.owner == state.clipboard.setter.window)
1138            .unwrap_or(false)
1139        {
1140            return state.clipboard_item.clone();
1141        }
1142        state
1143            .clipboard
1144            .load(
1145                state.clipboard.getter.atoms.clipboard,
1146                state.clipboard.getter.atoms.utf8_string,
1147                state.clipboard.getter.atoms.property,
1148                Duration::from_secs(3),
1149            )
1150            .map(|text| crate::ClipboardItem {
1151                text: String::from_utf8(text).unwrap(),
1152                metadata: None,
1153            })
1154            .ok()
1155    }
1156
1157    fn run(&self) {
1158        let mut poll = self
1159            .0
1160            .borrow_mut()
1161            .poll
1162            .take()
1163            .context("no poll set on X11Client. calling run more than once is not possible")
1164            .unwrap();
1165
1166        let xcb_fd = self.0.borrow().xcb_connection.as_raw_fd();
1167        let mut xcb_source = mio::unix::SourceFd(&xcb_fd);
1168        poll.registry()
1169            .register(&mut xcb_source, XCB_CONNECTION_TOKEN, Interest::READABLE)
1170            .unwrap();
1171
1172        let mut events = mio::Events::with_capacity(1024);
1173        let mut next_refresh_needed = Instant::now();
1174
1175        'run_loop: loop {
1176            let poll_timeout = next_refresh_needed - Instant::now();
1177            // We rounding the poll_timeout down so `mio` doesn't round it up to the next higher milliseconds
1178            let poll_timeout = Duration::from_millis(poll_timeout.as_millis() as u64);
1179
1180            if poll_timeout >= Duration::from_millis(1) {
1181                let _ = poll.poll(&mut events, Some(poll_timeout));
1182            };
1183
1184            let mut state = self.0.borrow_mut();
1185
1186            // Check if we need to quit
1187            if let Ok(Some(())) = state.quit_signal_rx.try_recv() {
1188                return;
1189            }
1190
1191            // Redraw windows
1192            let now = Instant::now();
1193            if now > next_refresh_needed {
1194                // This will be pulled down to 16ms (or less) if a window is open
1195                let mut frame_length = Duration::from_millis(100);
1196
1197                let mut windows = vec![];
1198                for (_, window_ref) in state.windows.iter() {
1199                    if !window_ref.window.state.borrow().destroyed {
1200                        frame_length = frame_length.min(window_ref.window.refresh_rate());
1201                        windows.push(window_ref.window.clone());
1202                    }
1203                }
1204
1205                drop(state);
1206
1207                for window in windows {
1208                    window.refresh();
1209                }
1210
1211                state = self.0.borrow_mut();
1212
1213                // In the case that we're looping a bit too fast, slow down
1214                next_refresh_needed = now.max(next_refresh_needed) + frame_length;
1215            }
1216
1217            // X11 events
1218            drop(state);
1219
1220            loop {
1221                let (x_windows, events) = self.read_x11_events();
1222                for x_window in x_windows {
1223                    if let Some(window) = self.get_window(x_window) {
1224                        window.refresh();
1225                    }
1226                }
1227
1228                if events.len() == 0 {
1229                    break;
1230                }
1231                self.process_x11_events(events);
1232
1233                // When X11 is sending us events faster than we can handle we'll
1234                // let the frame rate drop to 10fps to try and avoid getting too behind.
1235                if Instant::now() > next_refresh_needed + Duration::from_millis(80) {
1236                    continue 'run_loop;
1237                }
1238            }
1239
1240            state = self.0.borrow_mut();
1241
1242            // Runnables
1243            while let Ok(runnable) = state.runnables.try_recv() {
1244                drop(state);
1245                runnable.run();
1246                state = self.0.borrow_mut();
1247
1248                if Instant::now() + Duration::from_millis(1) >= next_refresh_needed {
1249                    continue 'run_loop;
1250                }
1251            }
1252
1253            // XDG events
1254            if let Ok(event) = state.xdp_event_source.try_recv() {
1255                match event {
1256                    XDPEvent::WindowAppearance(appearance) => {
1257                        let mut windows = state
1258                            .windows
1259                            .values()
1260                            .map(|window| window.window.clone())
1261                            .collect::<Vec<_>>();
1262                        drop(state);
1263
1264                        self.with_common(|common| common.appearance = appearance);
1265                        for mut window in windows {
1266                            window.set_appearance(appearance);
1267                        }
1268                    }
1269                    XDPEvent::CursorTheme(_) | XDPEvent::CursorSize(_) => {
1270                        // noop, X11 manages this for us.
1271                    }
1272                };
1273            };
1274        }
1275    }
1276
1277    fn active_window(&self) -> Option<AnyWindowHandle> {
1278        let state = self.0.borrow();
1279        state.focused_window.and_then(|focused_window| {
1280            state
1281                .windows
1282                .get(&focused_window)
1283                .map(|window| window.handle())
1284        })
1285    }
1286}
1287
1288fn fp3232_to_f32(value: xinput::Fp3232) -> f32 {
1289    value.integral as f32 + value.frac as f32 / u32::MAX as f32
1290}