From acf4a04b7452b6dd2e69064b4f85144b8445bbe9 Mon Sep 17 00:00:00 2001 From: Matias Linares Date: Sun, 8 Nov 2015 23:02:00 -0300 Subject: Initial commit This initial commit has the following: * We can spawn a terminal. * Given a new window, we can move it around the screen, but only the window that was created, all the other windows disappear on the void, so.. :( and that's it --- src/safe_x11/mod.rs | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ src/safe_x11/window.rs | 144 +++++++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 src/safe_x11/mod.rs create mode 100644 src/safe_x11/window.rs (limited to 'src/safe_x11') diff --git a/src/safe_x11/mod.rs b/src/safe_x11/mod.rs new file mode 100644 index 0000000..199c402 --- /dev/null +++ b/src/safe_x11/mod.rs @@ -0,0 +1,201 @@ +//! 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, + Screen, + Cursor, + XDefaultRootWindow, + XQueryTree, + + // Windows + Window, + + // Events + XEvent, +}; +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; + +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); } +} + +/// 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) { + 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); + } +} + +/// Get the next event from the xserver. This call will block until a +/// event spawns. +pub fn next_xevent(display: *mut Display) -> XEvent { + unsafe { + let mut last_event: XEvent = uninitialized(); + println!("xevent: getting next event!"); + xlib::XNextEvent(display, &mut last_event); + last_event + } +} + +// 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) } +} diff --git a/src/safe_x11/window.rs b/src/safe_x11/window.rs new file mode 100644 index 0000000..624fea4 --- /dev/null +++ b/src/safe_x11/window.rs @@ -0,0 +1,144 @@ +use x11::xlib; +use x11::xlib::{ + Window, + XWindowAttributes, + XGetWindowAttributes, + XDefaultScreenOfDisplay, + XMoveWindow, + + XSetInputFocus, + XSetWindowBorder, + + IsViewable, RevertToParent, CurrentTime, +}; + +use std::ptr; +use std::mem::uninitialized; +use std::cmp::{max}; + +use safe_x11::{screen_ratio,get_color}; + +/// Representation of [`xlib::Window`](../../x11/xlib/type.Window.html) +pub struct XWindow { + display: *mut xlib::Display, + /// xlib::Window that wraps this struct. + pub inner: Window, +} + +fn fixed_with_ratio(x: i32, ratio: f32) -> i32 { + let fx = x as f32; + let fixed = fx * ratio; + fixed as i32 +} + +impl XWindow { + /// Generate a reference to the window in certain display. This will return + /// `None` if the window is the root window. + pub fn new(d: *mut xlib::Display, w: Window) -> Option { + if w != 0 { + Some(XWindow { + display: d, + inner: w, + }) + } else { + None + } + } + + /// Set the border width To the window. + pub fn set_border_width(&self, size: u32) { + unsafe { xlib::XSetWindowBorderWidth(self.display, self.inner, size) }; + } + + pub fn set_boder_color>>(&self, color: T) { + let c = get_color(self.display, color); + unsafe { XSetWindowBorder(self.display, self.inner, c); } + } + + /// Raises a window. + pub fn raise(&self) { + unsafe { xlib::XRaiseWindow(self.display, self.inner); } + } + + /// Register input events on some [`xlib::Window`](../../x11/xlib/type.Window.html) + /// + /// # Example + /// + /// if we want to handle when a pointer enter into a window rectangle, we + /// should do something like: + /// + /// ``` + /// use x11::xlib; + /// + /// let display = open_display("").unwrap(); + /// // Raw window + /// let window = 0xc00022; + /// + /// window.select_input(xlib::EnterWindowMask); + /// ``` + pub fn select_input(&self, mask: i64) { + unsafe { xlib::XSelectInput(self.display, self.inner, mask); } + } + + /// Returns the window attributes from certain window. + pub fn attributes(&self) -> XWindowAttributes { + unsafe { + let attrptr: *mut XWindowAttributes = uninitialized(); + XGetWindowAttributes(self.display, self.inner, attrptr); + ptr::read(attrptr) + } + } + + /// Moves the window given an offset from where it is. + pub fn move_offset(&self, xoffset: i32, yoffset: i32) { + unsafe { + let mut attributes: XWindowAttributes = uninitialized(); + XGetWindowAttributes(self.display, self.inner, &mut attributes); + println!("Moving window({:x}), {} + {} = {}, {} + {} = {}", + self.inner as u64, + attributes.x, xoffset, attributes.x + xoffset, + attributes.y, yoffset, attributes.y + yoffset); + XMoveWindow(self.display, self.inner, + attributes.x + xoffset, + attributes.y + yoffset); + } + } + + /// Moves the window to a particular coord in the screen. + pub fn move_to(&self, x: i32, y: i32) -> Result<(), &str> { + let screen = unsafe { + let s = XDefaultScreenOfDisplay(self.display); + ptr::read(s) + }; + + if 0 > x && x <= screen.width || 0 > y && y <= screen.height { + Err("Cannot move the window outside the screen!") + } else { + unsafe { XMoveWindow(self.display, self.inner, x, y) }; + Ok(()) + } + } + + /// Resizes the window a fixed amount within the height and width. + pub fn resize(&self, w: i32, h: i32) { + let ratio = screen_ratio(self.display); + let attrs = self.attributes(); + unsafe { + let ww: u32 = max(1, (attrs.width + fixed_with_ratio(w, ratio)) as u32); + let wh: u32 = max(1, (attrs.height + fixed_with_ratio(h, ratio)) as u32); + xlib::XResizeWindow(self.display, self.inner, + ww, wh); + } + } + + /// Raise the focus of the window. + pub fn focus(&self) { + let attrs = self.attributes(); + if attrs.map_state == IsViewable { + unsafe { + XSetInputFocus(self.display, self.inner, + RevertToParent, CurrentTime) + }; + } + } +} -- cgit v1.2.3-70-g09d2