// See LICENSE file for copyright and license details. //! Safe wrapper around the `x11-rs` crate. This should be as much safe as possible. #![allow(dead_code)] use x11::xlib; use x11::xlib::{ Display, XDisplayWidth, XDisplayHeight, XDefaultScreen, XConnectionNumber, Screen, Cursor, XDefaultRootWindow, XQueryTree, XEvent, XNextEvent, // Windows Window, Atom, XInternAtom, }; use x11::xlib::XKeyEvent; use std::ffi::CString; use std::ffi::NulError; use std::ptr; use std::error; use std::mem::uninitialized; use std::slice; use std::fmt; use libc::c_int; pub mod window; #[derive(Debug)] pub struct XSafeError<'a> { _description: &'a str, } impl<'a> XSafeError<'a> { fn new(desc: &'static str) -> XSafeError<'a> { XSafeError { _description: desc } } } impl<'a> From for XSafeError<'a> { fn from(_: NulError) -> XSafeError<'a> { XSafeError::new("Null ponter error!") } } impl<'a> error::Error for XSafeError<'a> { fn description(&self) -> &str { self._description } fn cause(&self) -> Option<&error::Error> { None } } impl<'a> fmt::Display for XSafeError<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self._description) } } /// 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. /// pub fn open_display(display: &str) -> Result<*mut Display, XSafeError> { let d = if display == "" { println!("Opening default display"); unsafe { xlib::XOpenDisplay(0x0 as *const i8) } } else { println!("Opening {}", display); let cstr = try!(CString::new(display)); unsafe { xlib::XOpenDisplay(cstr.as_ptr()) } }; if d.is_null() { Err(XSafeError::new("Cannot open display!")) } else { Ok(d) } } pub fn close_display(display: *mut Display) { unsafe { xlib::XCloseDisplay(display); } } /// Get the file descriptor for the XServer pub fn x11_fd(display: *mut Display) -> c_int { unsafe { XConnectionNumber(display) } } /// Get the next event from the xserver. This call will not block forever /// (like XNextEvent), instead it will wait for a certain time (1 second /// for now, but it can change) so we're not blocking the socket interface /// on the main thread. pub fn next_xevent(display: *mut Display) -> XEvent { unsafe { let mut last_event: XEvent = uninitialized(); XNextEvent(display, &mut last_event); last_event } } pub fn screen_size(display: *mut Display) -> (u32, u32) { let screen = unsafe { XDefaultScreen(display) }; let dw: u32 = unsafe { XDisplayWidth(display, screen) as u32 }; let dh: u32 = unsafe { XDisplayHeight(display, screen) as u32 }; (dw, dh) } /// Grab pointer buttons. /// /// # Example /// /// ``` /// grab_button( /// // Display /// display, /// // Button to press /// xlib::Button1 as i32, /// // Modifiers (can be an or of modifiers). /// xlib::Mod1Mask, /// // owner events. /// true, /// // Which motions we'll handle /// ButtonPressMask | ButtonReleaseMask | PointerMotionMask, /// // Keyboard and pointer sync moddes /// GrabModeAsync, GrabModeAsync, /// // Confine to and cursor. (Can be 0 :) ) /// 0, 0 /// ); /// ``` pub fn grab_button(display: *mut Display, button: u32, modifiers: u32, owner_events: bool, event_mask: i64, pointer_mode: i32, keyboard_mode: i32, confine_to: Window, cursor: Cursor) { unsafe { let default_win = xlib::XDefaultRootWindow(display); xlib::XGrabButton(display, button, modifiers, default_win, owner_events as i32, event_mask as u32, pointer_mode, keyboard_mode, confine_to, cursor); } } /// Register a combination of keys that will send a `XEvent` /// pub fn grab_key(display: *mut Display, key: u32, modifiers: u32, owner_events: bool, pointer_mode: i32, keyboard_mode: i32) { println!("Modifiers {:x}", modifiers); unsafe { let default_win = xlib::XDefaultRootWindow(display); let keycode: i32 = xlib::XKeysymToKeycode(display, key as u64) as i32; xlib::XGrabKey(display, keycode, modifiers, default_win, owner_events as i32, pointer_mode, keyboard_mode); } } /// Unregister a combination of keys that will send a `XEvent` pub fn ungrab_key(display: *mut Display, key: u32, modifiers: u32) { unsafe { let default_win = xlib::XDefaultRootWindow(display); let keycode: i32 = xlib::XKeysymToKeycode(display, key as u64) as i32; xlib::XUngrabKey(display, keycode, modifiers, default_win); } } // Window code. /// Get a list from the active windows. This doesn't generate a hierarchical /// struture, so it may change on the future. pub fn window_list(display: *mut Display) -> &'static [Window] { let mut root: Window = 0; let mut parent: Window = 0; let mut children_count: u32 = 0; unsafe { let root_window = XDefaultRootWindow(display); let mut children: *mut Window = uninitialized(); XQueryTree(display, root_window, &mut root, &mut parent, &mut children, &mut children_count); slice::from_raw_parts(children as *const Window, children_count as usize) } } fn screen_ratio(d: *mut Display) -> f32 { let screen: xlib::Screen = unsafe { let scrptr = xlib::XDefaultScreenOfDisplay(d); ptr::read(scrptr) }; screen.height as f32 / screen.width as f32 } /// Get certain color from the display. /// /// # Example. /// /// This function can be called with a &str /// /// ``` /// get_color(display, "red"); /// ``` fn get_color>>(display: *mut Display, color: T) -> u64{ let screen_num = unsafe { xlib::XDefaultScreen(display) }; let colormap = unsafe { xlib::XDefaultColormap(display, screen_num) }; unsafe { let mut xcolor: xlib::XColor = uninitialized(); let cstr = CString::new(color).unwrap(); xlib::XAllocNamedColor(display, colormap, cstr.as_ptr(), &mut xcolor, &mut xcolor); xcolor.pixel } } /// Get the keysym for the given event. pub fn lookup_keysym(ev: &mut XKeyEvent) -> xlib::KeySym { unsafe { xlib::XLookupKeysym(ev, 0) } } pub fn atom>>(display: *mut Display, name: T) -> Atom { unsafe { let cstr = CString::new(name).unwrap(); XInternAtom(display, cstr.as_ptr(), 0) } }