From 5cada36ae8eade018bbad035b538bc01347ff7a8 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 8 Mar 2025 10:14:08 +0300 Subject: [PATCH] x11: move x11 specific code to x11 from linux/mod.rs --- src/platform/x11.rs | 2 +- src/platform_impl/linux/mod.rs | 70 +---------------------------- src/platform_impl/linux/x11/mod.rs | 72 ++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 73 deletions(-) diff --git a/src/platform/x11.rs b/src/platform/x11.rs index 9e70a298..656df8a2 100644 --- a/src/platform/x11.rs +++ b/src/platform/x11.rs @@ -79,7 +79,7 @@ pub type XWindow = u32; #[inline] pub fn register_xlib_error_hook(hook: XlibErrorHook) { // Append new hook. - crate::platform_impl::XLIB_ERROR_HOOKS.lock().unwrap().push(hook); + crate::platform_impl::x11::XLIB_ERROR_HOOKS.lock().unwrap().push(hook); } /// Additional methods on [`ActiveEventLoop`] that are specific to X11. diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 8d6d57ec..de58deac 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -6,12 +6,8 @@ compile_error!("Please select a feature to build for unix: `x11`, `wayland`"); use std::env; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::time::Duration; -#[cfg(x11_platform)] -use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Arc, sync::Mutex}; pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey}; -#[cfg(x11_platform)] -use self::x11::{XConnection, XError, XNotSupported}; use crate::application::ApplicationHandler; pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource; #[cfg(x11_platform)] @@ -21,9 +17,7 @@ use crate::event_loop::ActiveEventLoop; pub(crate) use crate::icon::RgbaIcon as PlatformIcon; use crate::platform::pump_events::PumpStatus; #[cfg(x11_platform)] -use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook}; -#[cfg(x11_platform)] -use crate::utils::Lazy; +use crate::platform::x11::WindowType as XWindowType; use crate::window::ActivationToken; pub(crate) mod common; @@ -98,10 +92,6 @@ impl Default for PlatformSpecificWindowAttributes { } } -#[cfg(x11_platform)] -pub(crate) static X11_BACKEND: Lazy, XNotSupported>>> = - Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new))); - /// `x11_or_wayland!(match expr; Enum(foo) => foo.something())` /// expands to the equivalent of /// ```ignore @@ -138,57 +128,6 @@ pub(crate) enum PlatformCustomCursor { X(x11::CustomCursor), } -/// Hooks for X11 errors. -#[cfg(x11_platform)] -pub(crate) static XLIB_ERROR_HOOKS: Mutex> = Mutex::new(Vec::new()); - -#[cfg(x11_platform)] -unsafe extern "C" fn x_error_callback( - display: *mut x11::ffi::Display, - event: *mut x11::ffi::XErrorEvent, -) -> c_int { - let xconn_lock = X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()); - if let Ok(ref xconn) = *xconn_lock { - // Call all the hooks. - let mut error_handled = false; - for hook in XLIB_ERROR_HOOKS.lock().unwrap().iter() { - error_handled |= hook(display as *mut _, event as *mut _); - } - - // `assume_init` is safe here because the array consists of `MaybeUninit` values, - // which do not require initialization. - let mut buf: [MaybeUninit; 1024] = unsafe { MaybeUninit::uninit().assume_init() }; - unsafe { - (xconn.xlib.XGetErrorText)( - display, - (*event).error_code as c_int, - buf.as_mut_ptr() as *mut c_char, - buf.len() as c_int, - ) - }; - let description = - unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) }.to_string_lossy(); - - let error = unsafe { - XError { - description: description.into_owned(), - error_code: (*event).error_code, - request_code: (*event).request_code, - minor_code: (*event).minor_code, - } - }; - - // Don't log error. - if !error_handled { - tracing::error!("X11 error: {:#?}", error); - // XXX only update the error, if it wasn't handled by any of the hooks. - *xconn.latest_error.lock().unwrap() = Some(error); - } - } - // Fun fact: this return value is completely ignored. - 0 -} - #[derive(Debug)] pub enum EventLoop { #[cfg(wayland_platform)] @@ -262,12 +201,7 @@ impl EventLoop { #[cfg(x11_platform)] fn new_x11_any_thread() -> Result { - let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() { - Ok(xconn) => xconn.clone(), - Err(err) => return Err(os_error!(err.clone()).into()), - }; - - Ok(EventLoop::X(x11::EventLoop::new(xconn))) + x11::EventLoop::new().map(EventLoop::X) } #[inline] diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index eb3e064e..ab86c304 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -6,7 +6,7 @@ use std::ops::Deref; use std::os::raw::*; use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd}; use std::sync::mpsc::{self, Receiver, Sender, TryRecvError}; -use std::sync::{Arc, Weak}; +use std::sync::{Arc, Mutex, Weak}; use std::time::{Duration, Instant}; use std::{fmt, mem, ptr, slice, str}; @@ -32,10 +32,12 @@ use crate::event_loop::{ }; use crate::monitor::MonitorHandle as CoreMonitorHandle; use crate::platform::pump_events::PumpStatus; +use crate::platform::x11::XlibErrorHook; use crate::platform_impl::common::xkb::Context; use crate::platform_impl::platform::min_timeout; use crate::platform_impl::x11::window::Window; use crate::platform_impl::PlatformCustomCursor; +use crate::utils::Lazy; use crate::window::{ CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow, WindowAttributes, WindowId, @@ -72,6 +74,61 @@ type X11rbConnection = x11rb::xcb_ffi::XCBConnection; type X11Source = Generic>; +#[cfg(x11_platform)] +pub(crate) static X11_BACKEND: Lazy, XNotSupported>>> = + Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new))); + +/// Hooks for X11 errors. +#[cfg(x11_platform)] +pub(crate) static XLIB_ERROR_HOOKS: Mutex> = Mutex::new(Vec::new()); + +#[cfg(x11_platform)] +unsafe extern "C" fn x_error_callback( + display: *mut ffi::Display, + event: *mut ffi::XErrorEvent, +) -> c_int { + let xconn_lock = X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()); + if let Ok(ref xconn) = *xconn_lock { + // Call all the hooks. + let mut error_handled = false; + for hook in XLIB_ERROR_HOOKS.lock().unwrap().iter() { + error_handled |= hook(display as *mut _, event as *mut _); + } + + // `assume_init` is safe here because the array consists of `MaybeUninit` values, + // which do not require initialization. + let mut buf: [MaybeUninit; 1024] = unsafe { MaybeUninit::uninit().assume_init() }; + unsafe { + (xconn.xlib.XGetErrorText)( + display, + (*event).error_code as c_int, + buf.as_mut_ptr() as *mut c_char, + buf.len() as c_int, + ) + }; + let description = + unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) }.to_string_lossy(); + + let error = unsafe { + XError { + description: description.into_owned(), + error_code: (*event).error_code, + request_code: (*event).request_code, + minor_code: (*event).minor_code, + } + }; + + // Don't log error. + if !error_handled { + tracing::error!("X11 error: {:#?}", error); + // XXX only update the error, if it wasn't handled by any of the hooks. + *xconn.latest_error.lock().unwrap() = Some(error); + } + } + // Fun fact: this return value is completely ignored. + 0 +} + #[derive(Debug)] struct WakeSender { sender: Sender, @@ -172,7 +229,12 @@ struct EventLoopState { } impl EventLoop { - pub(crate) fn new(xconn: Arc) -> EventLoop { + pub(crate) fn new() -> Result { + let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() { + Ok(xconn) => xconn.clone(), + Err(err) => return Err(os_error!(err.clone()).into()), + }; + let root = xconn.default_root().root; let atoms = xconn.atoms(); @@ -365,14 +427,16 @@ impl EventLoop { event_processor.init_device(ALL_DEVICES); - EventLoop { + let event_loop = EventLoop { loop_running: false, event_loop, event_processor, redraw_receiver: PeekableReceiver::from_recv(redraw_channel), activation_receiver: PeekableReceiver::from_recv(activation_token_channel), state: EventLoopState { x11_readiness: Readiness::EMPTY, proxy_wake_up: false }, - } + }; + + Ok(event_loop) } pub(crate) fn window_target(&self) -> &dyn RootActiveEventLoop {