started with a backend using x11rb
				
					
				
			This commit is contained in:
		
							parent
							
								
									507bc75ccc
								
							
						
					
					
						commit
						98459d620c
					
				|  | @ -8,6 +8,9 @@ edition = "2018" | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
| x11 = {version = "2.18.2", features = ["xlib"] } | x11 = {version = "2.18.2", features = ["xlib"] } | ||||||
|  | x11rb = "0.8.1" | ||||||
|  | num-derive = "0.3.3" | ||||||
|  | num-traits = "0.2.14" | ||||||
| log = "0.4.13" | log = "0.4.13" | ||||||
| simple_logger = "1.11.0" | simple_logger = "1.11.0" | ||||||
| dirs = "3.0.2" | dirs = "3.0.2" | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								src/backends/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/backends/mod.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | mod xcb; | ||||||
|  | mod xlib; | ||||||
|  | 
 | ||||||
|  | pub trait WindowServerBackend {} | ||||||
							
								
								
									
										363
									
								
								src/backends/xcb.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								src/backends/xcb.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,363 @@ | ||||||
|  | //x11 backend
 | ||||||
|  | #![allow(dead_code)] | ||||||
|  | 
 | ||||||
|  | use log::error; | ||||||
|  | use num_traits::FromPrimitive; | ||||||
|  | use num_traits::ToPrimitive; | ||||||
|  | use std::sync::Arc; | ||||||
|  | 
 | ||||||
|  | use x11rb::{ | ||||||
|  |     connect, | ||||||
|  |     connection::Connection, | ||||||
|  |     errors::ReplyError, | ||||||
|  |     errors::ReplyOrIdError, | ||||||
|  |     protocol::xproto::{ | ||||||
|  |         Atom, ChangeWindowAttributesAux, ConnectionExt, EventMask, Screen, | ||||||
|  |         Setup, | ||||||
|  |     }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #[cfg(test)] | ||||||
|  | mod tests { | ||||||
|  |     use super::*; | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn keysyms() { | ||||||
|  |         let xcb = create_backend().unwrap(); | ||||||
|  | 
 | ||||||
|  |         let mapping = xcb | ||||||
|  |             .connection | ||||||
|  |             .get_keyboard_mapping( | ||||||
|  |                 xcb.setup().min_keycode, | ||||||
|  |                 xcb.setup().max_keycode - xcb.setup().min_keycode + 1, | ||||||
|  |             ) | ||||||
|  |             .unwrap(); | ||||||
|  | 
 | ||||||
|  |         let mapping = mapping.reply().unwrap(); | ||||||
|  | 
 | ||||||
|  |         for (i, keysyms) in mapping | ||||||
|  |             .keysyms | ||||||
|  |             .chunks(mapping.keysyms_per_keycode as usize) | ||||||
|  |             .enumerate() | ||||||
|  |         { | ||||||
|  |             println!( | ||||||
|  |                 "keycode: {:#x?}\tkeysyms: {:0x?}", | ||||||
|  |                 xcb.setup().min_keycode as usize + i, | ||||||
|  |                 keysyms | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[repr(u8)] | ||||||
|  | #[derive(FromPrimitive, ToPrimitive)] | ||||||
|  | pub enum MouseButton { | ||||||
|  |     Left = 1, | ||||||
|  |     Middle, | ||||||
|  |     Right, | ||||||
|  |     ScrollUp, | ||||||
|  |     ScrollDown, | ||||||
|  |     ScrollLeft, | ||||||
|  |     ScrollRight, | ||||||
|  |     Backwards, | ||||||
|  |     Forwards, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(FromPrimitive, ToPrimitive)] | ||||||
|  | pub enum Key { | ||||||
|  |     BackSpace = 0xff08, | ||||||
|  |     Tab = 0xff09, | ||||||
|  |     Linefeed = 0xff0a, | ||||||
|  |     Clear = 0xff0b, | ||||||
|  |     Return = 0xff0d, | ||||||
|  |     Pause = 0xff13, | ||||||
|  |     ScrollLock = 0xff14, | ||||||
|  |     SysReq = 0xff15, | ||||||
|  |     Escape = 0xff1b, | ||||||
|  |     Delete = 0xffff, | ||||||
|  |     Home = 0xff50, | ||||||
|  |     Left = 0xff51, | ||||||
|  |     Up = 0xff52, | ||||||
|  |     Right = 0xff53, | ||||||
|  |     Down = 0xff54, | ||||||
|  |     PageUp = 0xff55, | ||||||
|  |     PageDown = 0xff56, | ||||||
|  |     End = 0xff57, | ||||||
|  |     Begin = 0xff58, | ||||||
|  |     Space = 0x0020, | ||||||
|  |     Exclam = 0x0021, | ||||||
|  |     Quotedbl = 0x0022, | ||||||
|  |     Numbersign = 0x0023, | ||||||
|  |     Dollar = 0x0024, | ||||||
|  |     Percent = 0x0025, | ||||||
|  |     Ampersand = 0x0026, | ||||||
|  |     Apostrophe = 0x0027, | ||||||
|  |     ParenLeft = 0x0028, | ||||||
|  |     ParenRight = 0x0029, | ||||||
|  |     Asterisk = 0x002a, | ||||||
|  |     Plus = 0x002b, | ||||||
|  |     Comma = 0x002c, | ||||||
|  |     Minus = 0x002d, | ||||||
|  |     Period = 0x002e, | ||||||
|  |     Slash = 0x002f, | ||||||
|  |     Zero = 0x0030, | ||||||
|  |     One = 0x0031, | ||||||
|  |     Two = 0x0032, | ||||||
|  |     Three = 0x0033, | ||||||
|  |     Four = 0x0034, | ||||||
|  |     Five = 0x0035, | ||||||
|  |     Six = 0x0036, | ||||||
|  |     Seven = 0x0037, | ||||||
|  |     Eight = 0x0038, | ||||||
|  |     Nine = 0x0039, | ||||||
|  |     Colon = 0x003a, | ||||||
|  |     Semicolon = 0x003b, | ||||||
|  |     Less = 0x003c, | ||||||
|  |     Equal = 0x003d, | ||||||
|  |     Greater = 0x003e, | ||||||
|  |     Question = 0x003f, | ||||||
|  |     At = 0x0040, | ||||||
|  |     UppercaseA = 0x0041, | ||||||
|  |     UppercaseB = 0x0042, | ||||||
|  |     UppercaseC = 0x0043, | ||||||
|  |     UppercaseD = 0x0044, | ||||||
|  |     UppercaseE = 0x0045, | ||||||
|  |     UppercaseF = 0x0046, | ||||||
|  |     UppercaseG = 0x0047, | ||||||
|  |     UppercaseH = 0x0048, | ||||||
|  |     UppercaseI = 0x0049, | ||||||
|  |     UppercaseJ = 0x004a, | ||||||
|  |     UppercaseK = 0x004b, | ||||||
|  |     UppercaseL = 0x004c, | ||||||
|  |     UppercaseM = 0x004d, | ||||||
|  |     UppercaseN = 0x004e, | ||||||
|  |     UppercaseO = 0x004f, | ||||||
|  |     UppercaseP = 0x0050, | ||||||
|  |     UppercaseQ = 0x0051, | ||||||
|  |     UppercaseR = 0x0052, | ||||||
|  |     UppercaseS = 0x0053, | ||||||
|  |     UppercaseT = 0x0054, | ||||||
|  |     UppercaseU = 0x0055, | ||||||
|  |     UppercaseV = 0x0056, | ||||||
|  |     UppercaseW = 0x0057, | ||||||
|  |     UppercaseX = 0x0058, | ||||||
|  |     UppercaseY = 0x0059, | ||||||
|  |     UppercaseZ = 0x005a, | ||||||
|  |     BracketLeft = 0x005b, | ||||||
|  |     Backslash = 0x005c, | ||||||
|  |     BracketRight = 0x005d, | ||||||
|  |     AsciiCircum = 0x005e, | ||||||
|  |     Underscore = 0x005f, | ||||||
|  |     Grave = 0x0060, | ||||||
|  |     LowercaseA = 0x0061, | ||||||
|  |     LowercaseB = 0x0062, | ||||||
|  |     LowercaseC = 0x0063, | ||||||
|  |     LowercaseD = 0x0064, | ||||||
|  |     LowercaseE = 0x0065, | ||||||
|  |     LowercaseF = 0x0066, | ||||||
|  |     LowercaseG = 0x0067, | ||||||
|  |     LowercaseH = 0x0068, | ||||||
|  |     LowercaseI = 0x0069, | ||||||
|  |     LowercaseJ = 0x006a, | ||||||
|  |     LowercaseK = 0x006b, | ||||||
|  |     LowercaseL = 0x006c, | ||||||
|  |     LowercaseM = 0x006d, | ||||||
|  |     LowercaseN = 0x006e, | ||||||
|  |     LowercaseO = 0x006f, | ||||||
|  |     LowercaseP = 0x0070, | ||||||
|  |     LowercaseQ = 0x0071, | ||||||
|  |     LowercaseR = 0x0072, | ||||||
|  |     LowercaseS = 0x0073, | ||||||
|  |     LowercaseT = 0x0074, | ||||||
|  |     LowercaseU = 0x0075, | ||||||
|  |     LowercaseV = 0x0076, | ||||||
|  |     LowercaseW = 0x0077, | ||||||
|  |     LowercaseX = 0x0078, | ||||||
|  |     LowercaseY = 0x0079, | ||||||
|  |     LowercaseZ = 0x007a, | ||||||
|  |     BraceLeft = 0x007b, | ||||||
|  |     Bar = 0x007c, | ||||||
|  |     BraceRight = 0x007d, | ||||||
|  |     AsciiTilde = 0x007e, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Key {} | ||||||
|  | 
 | ||||||
|  | // '<,'>s/.* XK_\([A-z,_]*\)[ ]*\(0x[a-f,0-9]*\).*/\1 = \2,/
 | ||||||
|  | 
 | ||||||
|  | struct Atoms { | ||||||
|  |     wm_protocols: Atom, | ||||||
|  |     wm_state: Atom, | ||||||
|  |     wm_delete_window: Atom, | ||||||
|  |     wm_take_focus: Atom, | ||||||
|  |     net_supported: Atom, | ||||||
|  |     net_active_window: Atom, | ||||||
|  |     net_client_list: Atom, | ||||||
|  |     net_wm_name: Atom, | ||||||
|  |     net_wm_state: Atom, | ||||||
|  |     net_wm_state_fullscreen: Atom, | ||||||
|  |     net_wm_window_type: Atom, | ||||||
|  |     net_wm_window_type_dialog: Atom, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Atoms { | ||||||
|  |     fn new<C>(connection: Arc<C>) -> Result<Self, ReplyOrIdError> | ||||||
|  |     where | ||||||
|  |         C: Connection, | ||||||
|  |     { | ||||||
|  |         let wm_protocols = connection.intern_atom(false, b"WM_PROTOCOLS")?; | ||||||
|  |         let wm_state = connection.intern_atom(false, b"WM_STATE")?; | ||||||
|  |         let wm_delete_window = | ||||||
|  |             connection.intern_atom(false, b"WM_DELETE_WINDOW")?; | ||||||
|  |         let wm_take_focus = connection.intern_atom(false, b"WM_TAKE_FOCUS")?; | ||||||
|  |         let net_supported = connection.intern_atom(false, b"_NET_SUPPORTED")?; | ||||||
|  |         let net_active_window = | ||||||
|  |             connection.intern_atom(false, b"_NET_ACTIVE_WINDOW")?; | ||||||
|  |         let net_client_list = | ||||||
|  |             connection.intern_atom(false, b"_NET_CLIENT_LIST")?; | ||||||
|  |         let net_wm_name = connection.intern_atom(false, b"_NET_WM_NAME")?; | ||||||
|  |         let net_wm_state = connection.intern_atom(false, b"_NET_WM_STATE")?; | ||||||
|  |         let net_wm_state_fullscreen = | ||||||
|  |             connection.intern_atom(false, b"_NET_WM_STATE_FULLSCREEN")?; | ||||||
|  |         let net_wm_window_type = | ||||||
|  |             connection.intern_atom(false, b"_NET_WM_WINDOW_TYPE")?; | ||||||
|  |         let net_wm_window_type_dialog = | ||||||
|  |             connection.intern_atom(false, b"_NET_WM_WINDOW_TYPE_DIALOG")?; | ||||||
|  | 
 | ||||||
|  |         Ok(Self { | ||||||
|  |             wm_protocols: wm_protocols.reply()?.atom, | ||||||
|  |             wm_state: wm_state.reply()?.atom, | ||||||
|  |             wm_delete_window: wm_delete_window.reply()?.atom, | ||||||
|  |             wm_take_focus: wm_take_focus.reply()?.atom, | ||||||
|  |             net_supported: net_supported.reply()?.atom, | ||||||
|  |             net_active_window: net_active_window.reply()?.atom, | ||||||
|  |             net_client_list: net_client_list.reply()?.atom, | ||||||
|  |             net_wm_name: net_wm_name.reply()?.atom, | ||||||
|  |             net_wm_state: net_wm_state.reply()?.atom, | ||||||
|  |             net_wm_state_fullscreen: net_wm_state_fullscreen.reply()?.atom, | ||||||
|  |             net_wm_window_type: net_wm_window_type.reply()?.atom, | ||||||
|  |             net_wm_window_type_dialog: net_wm_window_type_dialog.reply()?.atom, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct X11Backend<C> | ||||||
|  | where | ||||||
|  |     C: Connection, | ||||||
|  | { | ||||||
|  |     connection: Arc<C>, | ||||||
|  |     screen: usize, | ||||||
|  |     atoms: Atoms, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn create_backend( | ||||||
|  | ) -> Result<X11Backend<impl Connection + Send + Sync>, Box<dyn std::error::Error>> | ||||||
|  | { | ||||||
|  |     let (connection, screen) = connect(None)?; | ||||||
|  | 
 | ||||||
|  |     Ok(X11Backend::new(Arc::new(connection), screen)?) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<C> X11Backend<C> | ||||||
|  | where | ||||||
|  |     C: Connection, | ||||||
|  | { | ||||||
|  |     pub fn new( | ||||||
|  |         connection: Arc<C>, | ||||||
|  |         screen: usize, | ||||||
|  |     ) -> Result<Self, ReplyOrIdError> { | ||||||
|  |         let atoms = Atoms::new(connection.clone())?; | ||||||
|  |         Ok(Self { | ||||||
|  |             connection, | ||||||
|  |             screen, | ||||||
|  |             atoms, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn setup(&self) -> &Setup { | ||||||
|  |         self.connection.setup() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn screen(&self) -> &Screen { | ||||||
|  |         &self.connection.setup().roots[self.screen] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn root(&self) -> u32 { | ||||||
|  |         self.screen().root | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // this needs the mask aswell to determine the keysym
 | ||||||
|  |     fn keysym_for_keycode(&self, keycode: u8) -> Option<Key> { | ||||||
|  |         let setup = self.setup(); | ||||||
|  |         let mapping = self | ||||||
|  |             .connection | ||||||
|  |             .get_keyboard_mapping( | ||||||
|  |                 setup.min_keycode, | ||||||
|  |                 setup.max_keycode - setup.min_keycode + 1, | ||||||
|  |             ) | ||||||
|  |             .ok()?; | ||||||
|  | 
 | ||||||
|  |         let mapping = mapping.reply().ok()?; | ||||||
|  | 
 | ||||||
|  |         mapping | ||||||
|  |             .keysyms | ||||||
|  |             .chunks(mapping.keysyms_per_keycode as usize) | ||||||
|  |             .nth(keycode as usize) | ||||||
|  |             .and_then(|keysyms| Key::from_u32(keysyms[0])) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn keycode_for_keysym<K>(&self, keysym: &K) -> Option<u8> | ||||||
|  |     where | ||||||
|  |         K: num_traits::ToPrimitive, | ||||||
|  |     { | ||||||
|  |         if let Some(keysym) = keysym.to_u32() { | ||||||
|  |             let setup = self.setup(); | ||||||
|  |             let mapping = self | ||||||
|  |                 .connection | ||||||
|  |                 .get_keyboard_mapping( | ||||||
|  |                     setup.min_keycode, | ||||||
|  |                     setup.max_keycode - setup.min_keycode + 1, | ||||||
|  |                 ) | ||||||
|  |                 .ok()?; | ||||||
|  | 
 | ||||||
|  |             let mapping = mapping.reply().ok()?; | ||||||
|  | 
 | ||||||
|  |             mapping | ||||||
|  |                 .keysyms | ||||||
|  |                 .chunks(mapping.keysyms_per_keycode as usize) | ||||||
|  |                 .enumerate() | ||||||
|  |                 .find_map(|(i, keysyms)| { | ||||||
|  |                     if keysyms.contains(&keysym) { | ||||||
|  |                         Some(setup.min_keycode + i as u8) | ||||||
|  |                     } else { | ||||||
|  |                         None | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn request_substructure_events(&self) -> Result<(), ReplyError> { | ||||||
|  |         let attributes = ChangeWindowAttributesAux::default().event_mask( | ||||||
|  |             EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY, | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         match self | ||||||
|  |             .connection | ||||||
|  |             .change_window_attributes(self.root(), &attributes)? | ||||||
|  |             .check() | ||||||
|  |         { | ||||||
|  |             Ok(_) => Ok(()), | ||||||
|  |             Err(err) => { | ||||||
|  |                 error!( | ||||||
|  |                     "Failed to request substructure redirect/notify: another \ | ||||||
|  |                      window manager is running. {:#?}",
 | ||||||
|  |                     err | ||||||
|  |                 ); | ||||||
|  | 
 | ||||||
|  |                 Err(err) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								src/backends/xlib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/backends/xlib.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | use std::ptr::null; | ||||||
|  | 
 | ||||||
|  | use x11::xlib::{Window, XRootWindow}; | ||||||
|  | 
 | ||||||
|  | // xlib backend
 | ||||||
|  | 
 | ||||||
|  | pub struct XLib { | ||||||
|  |     display: *mut x11::xlib::Display, | ||||||
|  |     screen: i32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Drop for XLib { | ||||||
|  |     fn drop(&mut self) { | ||||||
|  |         unsafe { | ||||||
|  |             x11::xlib::XCloseDisplay(self.display); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl XLib { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         let (display, screen) = unsafe { | ||||||
|  |             let display = x11::xlib::XOpenDisplay(null()); | ||||||
|  |             let screen = x11::xlib::XDefaultScreen(display); | ||||||
|  | 
 | ||||||
|  |             (display, screen) | ||||||
|  |         }; | ||||||
|  |         Self { display, screen } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn root_window(&self) -> Window { | ||||||
|  |         unsafe { XRootWindow(self.display, self.screen) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -7,6 +7,10 @@ use log4rs::{ | ||||||
| }; | }; | ||||||
| use state::WMConfig; | use state::WMConfig; | ||||||
| 
 | 
 | ||||||
|  | #[macro_use] | ||||||
|  | extern crate num_derive; | ||||||
|  | 
 | ||||||
|  | mod backends; | ||||||
| mod client_logic; | mod client_logic; | ||||||
| mod clients; | mod clients; | ||||||
| mod clients2; | mod clients2; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue