From da3fa00ccf4cde76d1d6489c6043d7e56d4f52c5 Mon Sep 17 00:00:00 2001 From: Matias Linares Date: Wed, 25 May 2016 13:18:18 -0300 Subject: Add a lazy_static connection to the X server --- src/safe_x11/display.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/safe_x11/display.rs (limited to 'src/safe_x11/display.rs') diff --git a/src/safe_x11/display.rs b/src/safe_x11/display.rs new file mode 100644 index 0000000..72b5b49 --- /dev/null +++ b/src/safe_x11/display.rs @@ -0,0 +1,101 @@ +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 {} -- cgit v1.2.3-70-g09d2