summaryrefslogtreecommitdiff
path: root/src/dotwm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotwm.rs')
-rw-r--r--src/dotwm.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/dotwm.rs b/src/dotwm.rs
new file mode 100644
index 0000000..2d64584
--- /dev/null
+++ b/src/dotwm.rs
@@ -0,0 +1,140 @@
+use x11::xlib;
+use x11::xlib::{
+ Display,
+ XErrorEvent,
+ XEvent,
+
+ GrabModeAsync,
+};
+
+use safe_x11::{
+ open_display,
+ close_display,
+ grab_key,
+};
+
+use safe_x11::window::XWindow;
+
+use std::ptr;
+use std::process::exit;
+use std::mem::uninitialized;
+use std::collections::HashMap;
+use libc::c_int;
+
+#[allow(unused_variables)]
+unsafe extern "C" fn error_handler(d: *mut Display, evptr: *mut XErrorEvent) -> c_int {
+ println!("ERRORR");
+ let ev = ptr::read(evptr);
+ if ev.error_code == xlib::BadAccess {
+ println!("Another widnow manager is running :C");
+ exit(1);
+ }
+
+ 0
+}
+
+/// Defines a callback to call no certains events.
+pub type ExecFn = fn(&DotWM, XEvent, &[String]) -> bool;
+
+pub struct DotWM {
+ pub display: *mut Display,
+ // Map with the keys as (key, mod)
+ bindings: HashMap<(u32, u32), (ExecFn, Vec<String>)>,
+ cw_idx: usize,
+ pub window_list: Vec<XWindow>,
+}
+
+/// DotWM state.
+impl DotWM {
+ /// Create a state of the Dot Window Manager
+ pub fn new() -> DotWM {
+ let d = open_display("").unwrap();
+ unsafe { xlib::XSetErrorHandler(Some(error_handler)) };
+ // Some testings.
+ unsafe {
+ let root = xlib::XDefaultRootWindow(d);
+ let mut attrs: xlib::XSetWindowAttributes = uninitialized();
+ attrs.event_mask = xlib::SubstructureNotifyMask;
+ xlib::XChangeWindowAttributes(d, root, xlib::CWEventMask, &mut attrs);
+ }
+
+ DotWM {
+ display: d,
+ bindings: HashMap::new(),
+ cw_idx: 0,
+ window_list: vec![],
+ }
+ }
+
+ /// Add a binding to the WM.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// fn exec(_: &DotWM, _: xlib::XEvent, args: &[String]) -> bool {
+ /// if let Some(program) = args.first() {
+ /// let mut prog_args = vec![];
+ /// for arg in args[1..].iter() {
+ /// prog_args.push(arg);
+ /// }
+ /// exec_cmd(program, prog_args.deref()).unwrap();
+ /// }
+ /// true
+ /// }
+ ///
+ /// // ...
+ ///
+ /// dotwm.add_binding(keysym::XK_Return, xlib::Mod4Mask, exec,
+ /// &["xterm"]);
+ /// ```
+ pub fn add_binding(&mut self, key: u32, modifiers: u32, func: ExecFn, args: &[&str]) {
+ grab_key(self.display, key, modifiers, true, GrabModeAsync, GrabModeAsync);
+ let mut v = vec![];
+ for arg in args {
+ v.push(arg.to_string());
+ }
+ self.bindings.insert((key, modifiers), (func, v));
+ }
+
+ pub fn exec_func(&mut self, key: u32, modifiers: u32, ev: xlib::XEvent) {
+ if let Some(&(func, ref args)) = self.bindings.get(&(key, modifiers)) {
+ let v = args.clone();
+ func(&self, ev, &v);
+ }
+ }
+
+ pub fn add_window(&mut self, w: xlib::Window) {
+ if let Some(w) = XWindow::new(self.display, w) {
+ self.window_list.push(w);
+ // Last windows get focus.
+ self.cw_idx = self.window_list.len() - 1;
+ }
+ }
+
+ pub fn current_window(&self) -> Option<&XWindow> {
+ if self.cw_idx < self.window_list.len() {
+ self.window_list.get(self.cw_idx)
+ } else {
+ None
+ }
+ }
+
+ pub fn remove_window(&mut self, w: xlib::Window) {
+ let pos = self.window_list.iter().position(|xw| xw.inner == w);
+
+ match pos {
+ Some(idx) => {
+ self.window_list.remove(idx);
+ self.cw_idx = usize::max_value();
+ },
+ None => (),
+ }
+ }
+}
+
+impl Drop for DotWM {
+ fn drop(&mut self) {
+ println!("Closing display");
+ close_display(self.display);
+ }
+}