use x11::xlib; use libc::{c_int, c_char}; use std::ptr; use std::fmt; use std::sync::Arc; use std::cell::RefCell; use std::error::Error; pub type XErrorHandler = Option c_int>; struct XConnection { display: *mut xlib::Display, last_error: RefCell>, } #[derive(Debug)] struct XError { description: String, error_code: u8, request_code: u8, minor_code: u8, } lazy_static! { static ref X: Arc = { match XConnection::new(Some(x_error_handler)) { Ok(x) => Arc::new(x), Err(_) => panic!("Error connecting to the X server"), } }; } unsafe extern "C" fn x_error_handler(d: *mut xlib::Display, evptr: *mut xlib::XErrorEvent) -> c_int { let ev = ptr::read(evptr); let mut buf: [i8; 1024] = [0i8; 1024]; let bufptr = buf.as_mut_ptr(); xlib::XGetErrorText(d, ev.error_code as i32, bufptr as *mut c_char, 1024); *X.last_error.borrow_mut() = Some(XError { description: String::from_raw_parts(bufptr as *mut u8, 1024, 1024), error_code: ev.error_code, request_code: ev.request_code, minor_code: ev.minor_code, }); 0 } impl Error for XError { #[inline] fn description(&self) -> &str { &self.description } } impl fmt::Display for XError { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(formatter, "X error: {} (code: {}, request code: {}, minor code: {})", self.description, self.error_code, self.request_code, self.minor_code) } } impl XConnection { /// Open a display. If the string passed by parameter is `""`, it will open the /// default display. /// /// # Failures /// /// This function can raise a NulError when the bytes yielded contains an internal /// 0 byte. /// fn new(handler: XErrorHandler) -> Result { let d = unsafe { xlib::XOpenDisplay(0x0 as *const i8) }; unsafe { xlib::XSetErrorHandler(handler) }; if d.is_null() { Err(XError { description: "Cannot open display!".to_owned(), error_code: 0, request_code: 0, minor_code: 0, }) } else { Ok(XConnection { display: d, last_error: RefCell::new(None), }) } } } impl Drop for XConnection { #[inline] fn drop(&mut self) { unsafe { xlib::XCloseDisplay(self.display) }; } } unsafe impl Send for XConnection {} unsafe impl Sync for XConnection {}