use crate::{
sync::{call_once, OnceCell},
xlib_ffi::{xlib, X11Ffi, XDisplay},
XcbDisplay,
};
use __private::Sealed;
use alloc::sync::Arc;
use breadx::{
display::{Display, DisplayBase, RawReply, RawRequest},
protocol::{xproto::Setup, Event},
Error, Result,
};
use core::{
cell::Cell,
marker::PhantomData,
ptr::{null, NonNull},
};
use cstr_core::CStr;
use libc::c_void;
#[cfg(all(unix, feature = "to_socket"))]
use std::os::unix::io::{AsRawFd, RawFd};
pub struct XlibDisplay<ThreadSafety> {
xcb: XcbDisplay,
display: NonNull<XDisplay>,
disconnect: bool,
_phantom: PhantomData<ThreadSafety>,
}
pub trait ThreadSafety: Sealed {
fn initialize() -> Result<()>;
}
pub struct ThreadUnsafe {
_private: PhantomData<Cell<()>>,
}
impl ThreadSafety for ThreadUnsafe {
fn initialize() -> Result<()> {
Ok(())
}
}
pub struct ThreadSafe {
_private: (),
}
impl ThreadSafety for ThreadSafe {
fn initialize() -> Result<()> {
static THREADS_INIT: OnceCell<libc::c_int> = OnceCell::new();
let result = call_once(&THREADS_INIT, || {
unsafe { xlib().XInitThreads() }
});
match *result {
0 => Err(Error::make_msg("failed to initialize threading")),
_ => Ok(()),
}
}
}
impl<TS: ThreadSafety> XlibDisplay<TS> {
pub fn connect(name: Option<&CStr>) -> Result<Self> {
TS::initialize()?;
let display_name = name.map_or(null(), |name| name.as_ptr());
let conn = unsafe { xlib().XOpenDisplay(display_name) };
if conn.is_null() {
return Err(Error::make_msg("failed to connect to X server"));
}
Ok(unsafe { Self::from_ptr(conn.cast(), true) })
}
pub unsafe fn from_ptr(ptr: *mut c_void, disconnect: bool) -> Self {
let conn: *mut XDisplay = ptr.cast();
let screen = unsafe { xlib().XDefaultScreen(conn) };
let xcb_conn = unsafe { xlib().XGetXCBConnection(conn) };
let xcb = unsafe { XcbDisplay::from_ptr(xcb_conn.cast(), false, screen as usize) };
Self {
xcb,
display: NonNull::new_unchecked(conn),
disconnect,
_phantom: PhantomData,
}
}
}
impl<TS> XlibDisplay<TS> {
pub fn as_xlib_connection(&self) -> *mut c_void {
self.display.as_ptr().cast()
}
pub fn as_xcb_connection(&self) -> *mut c_void {
self.xcb.as_raw_connection()
}
}
#[cfg(all(unix, feature = "to_socket"))]
impl<TS> AsRawFd for XlibDisplay<TS> {
fn as_raw_fd(&self) -> RawFd {
self.xcb.as_raw_fd()
}
}
impl<TS> DisplayBase for XlibDisplay<TS> {
fn setup(&self) -> &Arc<Setup> {
self.xcb.setup()
}
fn default_screen_index(&self) -> usize {
self.xcb.default_screen_index()
}
fn poll_for_event(&mut self) -> Result<Option<Event>> {
self.xcb.poll_for_event()
}
fn poll_for_reply_raw(&mut self, seq: u64) -> Result<Option<RawReply>> {
self.xcb.poll_for_reply_raw(seq)
}
}
impl<TS> DisplayBase for &XlibDisplay<TS> {
fn setup(&self) -> &Arc<Setup> {
self.xcb.setup()
}
fn default_screen_index(&self) -> usize {
self.xcb.default_screen_index()
}
fn poll_for_event(&mut self) -> Result<Option<Event>> {
(&self.xcb).poll_for_event()
}
fn poll_for_reply_raw(&mut self, seq: u64) -> Result<Option<RawReply>> {
(&self.xcb).poll_for_reply_raw(seq)
}
}
impl<TS> Display for XlibDisplay<TS> {
fn flush(&mut self) -> Result<()> {
self.xcb.flush()
}
fn generate_xid(&mut self) -> Result<u32> {
self.xcb.generate_xid()
}
fn maximum_request_length(&mut self) -> Result<usize> {
self.xcb.maximum_request_length()
}
fn send_request_raw(&mut self, req: RawRequest<'_, '_>) -> Result<u64> {
self.xcb.send_request_raw(req)
}
fn synchronize(&mut self) -> Result<()> {
self.xcb.synchronize()
}
fn wait_for_event(&mut self) -> Result<Event> {
self.xcb.wait_for_event()
}
fn wait_for_reply_raw(&mut self, seq: u64) -> Result<RawReply> {
self.xcb.wait_for_reply_raw(seq)
}
fn check_for_error(&mut self, seq: u64) -> Result<()> {
self.xcb.check_for_error(seq)
}
}
impl<TS> Display for &XlibDisplay<TS> {
fn flush(&mut self) -> Result<()> {
(&self.xcb).flush()
}
fn generate_xid(&mut self) -> Result<u32> {
(&self.xcb).generate_xid()
}
fn maximum_request_length(&mut self) -> Result<usize> {
(&self.xcb).maximum_request_length()
}
fn send_request_raw(&mut self, req: RawRequest<'_, '_>) -> Result<u64> {
(&self.xcb).send_request_raw(req)
}
fn synchronize(&mut self) -> Result<()> {
(&self.xcb).synchronize()
}
fn wait_for_event(&mut self) -> Result<Event> {
(&self.xcb).wait_for_event()
}
fn wait_for_reply_raw(&mut self, seq: u64) -> Result<RawReply> {
(&self.xcb).wait_for_reply_raw(seq)
}
fn check_for_error(&mut self, seq: u64) -> Result<()> {
(&self.xcb).check_for_error(seq)
}
}
impl<TS> Drop for XlibDisplay<TS> {
fn drop(&mut self) {
if self.disconnect {
unsafe {
xlib().XCloseDisplay(self.display.as_ptr());
}
}
}
}
mod __private {
pub trait Sealed {
fn __sealed_trait_marker() {}
}
impl Sealed for super::ThreadUnsafe {}
impl Sealed for super::ThreadSafe {}
}