aboutsummaryrefslogtreecommitdiff
path: root/src/safe_x11/display.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/safe_x11/display.rs')
-rw-r--r--src/safe_x11/display.rs101
1 files changed, 101 insertions, 0 deletions
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<unsafe extern fn(*mut xlib::Display, evptr: *mut xlib::XErrorEvent) -> c_int>;
+
+struct XConnection {
+ display: *mut xlib::Display,
+ last_error: RefCell<Option<XError>>,
+}
+
+#[derive(Debug)]
+struct XError {
+ description: String,
+ error_code: u8,
+ request_code: u8,
+ minor_code: u8,
+}
+
+lazy_static! {
+ static ref X: Arc<XConnection> = {
+ 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<XConnection, XError> {
+ 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 {}