use std::error::Error;
use std::fmt::Formatter;
use std::os::raw::c_int;
use std::ptr::NonNull;
use x11_dl::xlib::{Display, Xlib};
use x11_dl::xlib_xcb::{XEventQueueOwner, Xlib_xcb};
pub struct XlibConnection {
display: NonNull<Display>,
xlib: Box<Xlib>,
default_screen: c_int,
}
impl XlibConnection {
pub fn open() -> Result<Self, Box<dyn Error>> {
let xlib = Box::new(Xlib::open()?);
let ptr = unsafe { (xlib.XOpenDisplay)(core::ptr::null()) };
let Some(display) = NonNull::new(ptr) else { return Err(DisplayOpenFailedError.into()) };
let mut this = Self { display, xlib, default_screen: 0 };
this.default_screen = this.fetch_default_screen();
Ok(this)
}
pub fn set_xcb_queue_owner(&self, xlib_xcb: &Xlib_xcb) {
unsafe {
(xlib_xcb.XSetEventQueueOwner)(
self.display.as_ptr(),
XEventQueueOwner::XCBOwnsEventQueue,
)
}
}
pub fn default_screen_index(&self) -> c_int {
self.default_screen
}
fn fetch_default_screen(&self) -> c_int {
unsafe { (self.xlib.XDefaultScreen)(self.display.as_ptr()) }
}
pub fn as_raw(&self) -> *mut Display {
self.display.as_ptr()
}
}
#[cfg(feature = "opengl")]
impl XlibConnection {
pub fn xlib(&self) -> &Xlib {
&self.xlib
}
pub fn sync(&self) {
unsafe { (self.xlib.XSync)(self.display.as_ptr(), 0) };
}
pub fn get_error_text(
&self, buf: &mut [u8], error_code: core::ffi::c_uchar,
) -> &core::ffi::CStr {
if buf.is_empty() {
return c"";
}
let buf_len = buf.len() - 1;
let Ok(buf_len) = buf_len.try_into() else {
return c"";
};
unsafe {
(self.xlib.XGetErrorText)(
self.as_raw(),
error_code.into(),
buf.as_mut_ptr().cast(),
buf_len,
)
};
*buf.last_mut().unwrap() = 0;
unsafe { std::ffi::CStr::from_ptr(buf.as_mut_ptr().cast()) }
}
pub fn set_error_handler(
&self, new_error_handler: Option<ErrorHandler>,
) -> Option<ErrorHandler> {
unsafe { (self.xlib.XSetErrorHandler)(new_error_handler) }
}
}
#[cfg(feature = "opengl")]
type ErrorHandler = unsafe extern "C" fn(*mut Display, *mut x11_dl::xlib::XErrorEvent) -> c_int;
impl Drop for XlibConnection {
fn drop(&mut self) {
unsafe { (self.xlib.XCloseDisplay)(self.display.as_ptr()) };
}
}
#[derive(Debug)]
struct DisplayOpenFailedError;
impl std::fmt::Display for DisplayOpenFailedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("Failed to open X11 display connection: XOpenDisplay() failed")
}
}
impl Error for DisplayOpenFailedError {}