x11: move x11 specific code to x11 from linux/mod.rs

This commit is contained in:
Kirill Chibisov 2025-03-08 10:14:08 +03:00 committed by GitHub
parent b3dcfa1275
commit 5cada36ae8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 73 deletions

View file

@ -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.

View file

@ -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<Mutex<Result<Arc<XConnection>, 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<Vec<XlibErrorHook>> = 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<c_char>; 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<EventLoop, EventLoopError> {
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]

View file

@ -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<BorrowedFd<'static>>;
#[cfg(x11_platform)]
pub(crate) static X11_BACKEND: Lazy<Mutex<Result<Arc<XConnection>, 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<Vec<XlibErrorHook>> = 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<c_char>; 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<T> {
sender: Sender<T>,
@ -172,7 +229,12 @@ struct EventLoopState {
}
impl EventLoop {
pub(crate) fn new(xconn: Arc<XConnection>) -> EventLoop {
pub(crate) fn new() -> Result<EventLoop, EventLoopError> {
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 {