Merge pull request 'get_atom_property_leak_fix' (#2) from get_atom_property_leak_fix into main
Reviewed-on: https://desktop-host/git/janis/wm/pulls/2
This commit is contained in:
		
						commit
						71ddeb6af1
					
				|  | @ -1,10 +1,10 @@ | |||
| use log::{error, warn}; | ||||
| use log::{debug, error, warn}; | ||||
| use num_traits::Zero; | ||||
| use std::{ffi::CString, mem::MaybeUninit, rc::Rc}; | ||||
| use std::{ffi::CString, rc::Rc}; | ||||
| 
 | ||||
| use thiserror::Error; | ||||
| 
 | ||||
| use x11::xlib::{self, Atom, Window, XEvent, XInternAtom, XKeyEvent}; | ||||
| use x11::xlib::{self, Atom, Success, Window, XEvent, XInternAtom, XKeyEvent}; | ||||
| 
 | ||||
| use crate::backends::{ | ||||
|     keycodes::KeyOrButton, xlib::keysym::mouse_button_to_xbutton, | ||||
|  | @ -290,34 +290,44 @@ impl XLib { | |||
|             xlib::PropertyNotify => { | ||||
|                 let ev = unsafe { &event.property }; | ||||
| 
 | ||||
|                 (ev.atom == self.atoms.net_wm_window_type) | ||||
|                     .then(|| { | ||||
|                         (self.get_atom_property( | ||||
|                 match ev.atom { | ||||
|                     atom if atom == self.atoms.net_wm_window_type => { | ||||
|                         if self | ||||
|                             .get_atom_property( | ||||
|                                 ev.window, | ||||
|                                 self.atoms.net_wm_state, | ||||
|                         ) == Some(self.atoms.net_wm_state_fullscreen)) | ||||
|                         .then(|| { | ||||
|                             XLibWindowEvent::FullscreenEvent( | ||||
|                             ) | ||||
|                             .map(|atom| { | ||||
|                                 *atom == self.atoms.net_wm_state_fullscreen | ||||
|                             }) | ||||
|                             .unwrap_or(false) | ||||
|                         { | ||||
|                             debug!("fullscreen event"); | ||||
|                             Some(XLibWindowEvent::FullscreenEvent( | ||||
|                                 FullscreenEvent::new( | ||||
|                                     ev.window, | ||||
|                                     FullscreenState::On, | ||||
|                                 ), | ||||
|                             ) | ||||
|                         }) | ||||
|                     }) | ||||
|                     .flatten() | ||||
|                             )) | ||||
|                         } else { | ||||
|                             None | ||||
|                         } | ||||
|                     } | ||||
|                     _ => None, | ||||
|                 } | ||||
|             } | ||||
|             xlib::ClientMessage => { | ||||
|                 let ev = unsafe { &event.client_message }; | ||||
| 
 | ||||
|                 (ev.message_type == self.atoms.net_wm_state) | ||||
|                     .then(|| { | ||||
|                 match ev.message_type { | ||||
|                     message_type if message_type == self.atoms.net_wm_state => { | ||||
|                         let data = ev.data.as_longs(); | ||||
|                         (data[1] as u64 == self.atoms.net_wm_state_fullscreen | ||||
|                         if data[1] as u64 == self.atoms.net_wm_state_fullscreen | ||||
|                             || data[2] as u64 | ||||
|                                 == self.atoms.net_wm_state_fullscreen) | ||||
|                             .then(|| { | ||||
|                                 XLibWindowEvent::FullscreenEvent( | ||||
|                                 == self.atoms.net_wm_state_fullscreen | ||||
|                         { | ||||
|                             debug!("fullscreen event"); | ||||
|                             Some(XLibWindowEvent::FullscreenEvent( | ||||
|                                 FullscreenEvent::new( | ||||
|                                     ev.window, | ||||
|                                     match data[0] /* as u64 */ { | ||||
|  | @ -329,10 +339,13 @@ impl XLib { | |||
|                                         } | ||||
|                                     }, | ||||
|                                 ), | ||||
|                                 ) | ||||
|                             }) | ||||
|                     }) | ||||
|                     .flatten() | ||||
|                             )) | ||||
|                         } else { | ||||
|                             None | ||||
|                         } | ||||
|                     } | ||||
|                     _ => None, | ||||
|                 } | ||||
|             } | ||||
|             _ => None, | ||||
|         } | ||||
|  | @ -361,16 +374,15 @@ impl XLib { | |||
|         &self, | ||||
|         window: xlib::Window, | ||||
|         atom: xlib::Atom, | ||||
|     ) -> Option<xlib::Atom> { | ||||
|     ) -> Option<xpointer::XPointer<xlib::Atom>> { | ||||
|         let mut di = 0; | ||||
|         let mut dl0 = 0; | ||||
|         let mut dl1 = 0; | ||||
|         let mut da = 0; | ||||
| 
 | ||||
|         let mut atom_out = MaybeUninit::<xlib::Atom>::zeroed(); | ||||
| 
 | ||||
|         unsafe { | ||||
|             (xlib::XGetWindowProperty( | ||||
|         let (atom_out, success) = | ||||
|             xpointer::XPointer::<xlib::Atom>::build_with_result(|ptr| unsafe { | ||||
|                 xlib::XGetWindowProperty( | ||||
|                     self.dpy(), | ||||
|                     window, | ||||
|                     atom, | ||||
|  | @ -382,10 +394,13 @@ impl XLib { | |||
|                     &mut di, | ||||
|                     &mut dl0, | ||||
|                     &mut dl1, | ||||
|                 atom_out.as_mut_ptr() as *mut _, | ||||
|             ) != 0) | ||||
|                 .then(|| atom_out.assume_init()) | ||||
|         } | ||||
|                     ptr as *mut _ as *mut _, | ||||
|                 ) == Success.into() | ||||
|             }); | ||||
| 
 | ||||
|         debug!("get_atom_property: {} {:?}", success, atom_out); | ||||
| 
 | ||||
|         success.then(|| atom_out).flatten() | ||||
|     } | ||||
| 
 | ||||
|     fn check_for_protocol( | ||||
|  | @ -1056,3 +1071,79 @@ unsafe extern "C" fn xlib_error_handler( | |||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub mod xpointer { | ||||
|     use std::{ | ||||
|         ops::{Deref, DerefMut}, | ||||
|         ptr::{null, NonNull}, | ||||
|     }; | ||||
| 
 | ||||
|     use x11::xlib::XFree; | ||||
| 
 | ||||
|     #[repr(C)] | ||||
|     #[derive(Debug)] | ||||
|     pub struct XPointer<T>(NonNull<T>); | ||||
| 
 | ||||
|     impl<T> XPointer<T> { | ||||
|         pub fn build_with<F>(cb: F) -> Option<Self> | ||||
|         where | ||||
|             F: FnOnce(&mut *const ()), | ||||
|         { | ||||
|             let mut ptr = null() as *const (); | ||||
|             cb(&mut ptr); | ||||
|             NonNull::new(ptr as *mut T).map(|ptr| Self(ptr)) | ||||
|         } | ||||
| 
 | ||||
|         pub fn build_with_result<F, R>(cb: F) -> (Option<Self>, R) | ||||
|         where | ||||
|             F: FnOnce(&mut *const ()) -> R, | ||||
|         { | ||||
|             let mut ptr = null() as *const (); | ||||
|             let result = cb(&mut ptr); | ||||
|             (NonNull::new(ptr as *mut T).map(|ptr| Self(ptr)), result) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<T> AsRef<T> for XPointer<T> { | ||||
|         fn as_ref(&self) -> &T { | ||||
|             &**self | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<T> AsMut<T> for XPointer<T> { | ||||
|         fn as_mut(&mut self) -> &mut T { | ||||
|             &mut **self | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<T> PartialEq for XPointer<T> | ||||
|     where | ||||
|         T: PartialEq, | ||||
|     { | ||||
|         fn eq(&self, other: &Self) -> bool { | ||||
|             self.0 == other.0 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<T> Eq for XPointer<T> where T: Eq {} | ||||
| 
 | ||||
|     impl<T> Deref for XPointer<T> { | ||||
|         type Target = T; | ||||
| 
 | ||||
|         fn deref(&self) -> &Self::Target { | ||||
|             unsafe { self.0.as_ref() } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<T> DerefMut for XPointer<T> { | ||||
|         fn deref_mut(&mut self) -> &mut Self::Target { | ||||
|             unsafe { self.0.as_mut() } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl<T> Drop for XPointer<T> { | ||||
|         fn drop(&mut self) { | ||||
|             unsafe { XFree(self.0.as_ptr() as _) }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ fn init_logger() { | |||
|             Root::builder() | ||||
|                 .appender("stdout") | ||||
|                 //.appender("logfile")
 | ||||
|                 .build(log::LevelFilter::Info), | ||||
|                 .build(log::LevelFilter::Debug), | ||||
|         ) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										774
									
								
								src/xlib.rs
									
									
									
									
									
								
							
							
						
						
									
										774
									
								
								src/xlib.rs
									
									
									
									
									
								
							|  | @ -1,774 +0,0 @@ | |||
| use log::info; | ||||
| use std::ptr::{null, null_mut}; | ||||
| use std::{ffi::CString, rc::Rc}; | ||||
| 
 | ||||
| use x11::xlib::{ | ||||
|     self, AnyButton, AnyKey, AnyModifier, Atom, ButtonPressMask, | ||||
|     ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime, EnterWindowMask, | ||||
|     FocusChangeMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, | ||||
|     Mod5Mask, PointerMotionMask, PropertyChangeMask, ShiftMask, | ||||
|     StructureNotifyMask, SubstructureNotifyMask, SubstructureRedirectMask, | ||||
|     Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, XEvent, | ||||
|     XGetTransientForHint, XGrabPointer, XInternAtom, XKillClient, XMapWindow, | ||||
|     XOpenDisplay, XRaiseWindow, XRootWindow, XSetErrorHandler, XSync, | ||||
|     XUngrabButton, XUngrabKey, XUngrabPointer, XWarpPointer, XWindowAttributes, | ||||
| }; | ||||
| use xlib::GrabModeAsync; | ||||
| 
 | ||||
| use log::error; | ||||
| 
 | ||||
| use crate::clients::Client; | ||||
| 
 | ||||
| pub struct XLib { | ||||
|     display: Display, | ||||
|     root: Window, | ||||
|     _screen: i32, | ||||
|     atoms: Atoms, | ||||
|     global_keybinds: Vec<KeyOrButton>, | ||||
| } | ||||
| 
 | ||||
| struct Atoms { | ||||
|     protocols: Atom, | ||||
|     delete_window: Atom, | ||||
|     active_window: Atom, | ||||
|     take_focus: Atom, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||
| pub enum KeyOrButton { | ||||
|     Key(i32, u32), | ||||
|     Button(u32, u32, u64), | ||||
| } | ||||
| 
 | ||||
| impl KeyOrButton { | ||||
|     #[allow(dead_code)] | ||||
|     pub fn key(keycode: i32, modmask: u32) -> Self { | ||||
|         Self::Key(keycode, modmask) | ||||
|     } | ||||
|     pub fn button(button: u32, modmask: u32, buttonmask: i64) -> Self { | ||||
|         Self::Button(button, modmask, buttonmask as u64) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone)] | ||||
| pub struct Display(Rc<*mut xlib::Display>); | ||||
| 
 | ||||
| impl Drop for XLib { | ||||
|     fn drop(&mut self) { | ||||
|         self.close_dpy(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl XLib { | ||||
|     pub fn new() -> Self { | ||||
|         let (display, _screen, root) = unsafe { | ||||
|             let display = XOpenDisplay(null()); | ||||
| 
 | ||||
|             assert_ne!(display, null_mut()); | ||||
| 
 | ||||
|             let display = Display::new(display); | ||||
|             let screen = XDefaultScreen(display.get()); | ||||
|             let root = XRootWindow(display.get(), screen); | ||||
| 
 | ||||
|             (display, screen, root) | ||||
|         }; | ||||
| 
 | ||||
|         Self { | ||||
|             atoms: Atoms::init(display.clone()), | ||||
|             global_keybinds: Vec::new(), | ||||
|             root, | ||||
|             _screen, | ||||
|             display, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn init(&mut self) { | ||||
|         unsafe { | ||||
|             let mut window_attributes = | ||||
|                 std::mem::MaybeUninit::<xlib::XSetWindowAttributes>::zeroed() | ||||
|                     .assume_init(); | ||||
| 
 | ||||
|             window_attributes.event_mask = SubstructureRedirectMask | ||||
|                 | StructureNotifyMask | ||||
|                 | SubstructureNotifyMask | ||||
|                 | EnterWindowMask | ||||
|                 | PointerMotionMask | ||||
|                 | ButtonPressMask; | ||||
| 
 | ||||
|             xlib::XChangeWindowAttributes( | ||||
|                 self.dpy(), | ||||
|                 self.root, | ||||
|                 CWEventMask, | ||||
|                 &mut window_attributes, | ||||
|             ); | ||||
| 
 | ||||
|             xlib::XSelectInput( | ||||
|                 self.dpy(), | ||||
|                 self.root, | ||||
|                 window_attributes.event_mask, | ||||
|             ); | ||||
| 
 | ||||
|             XSetErrorHandler(Some(xlib_error_handler)); | ||||
| 
 | ||||
|             XSync(self.dpy(), 0); | ||||
|         } | ||||
| 
 | ||||
|         self.grab_global_keybinds(self.root); | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_global_keybind(&mut self, key: KeyOrButton) { | ||||
|         self.global_keybinds.push(key); | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     fn ungrab_global_keybings(&self, window: Window) { | ||||
|         unsafe { | ||||
|             XUngrabButton(self.dpy(), AnyButton as u32, AnyModifier, window); | ||||
|             XUngrabKey(self.dpy(), AnyKey, AnyModifier, window); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn grab_global_keybinds(&self, window: Window) { | ||||
|         for kb in self.global_keybinds.iter() { | ||||
|             self.grab_key_or_button(window, kb); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     pub fn remove_global_keybind(&mut self, key: &KeyOrButton) { | ||||
|         if self.global_keybinds.contains(key) { | ||||
|             self.global_keybinds.retain(|kb| kb != key); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn dpy(&self) -> *mut xlib::Display { | ||||
|         self.display.get() | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     pub fn squash_event(&self, event_type: i32) -> XEvent { | ||||
|         unsafe { | ||||
|             let mut event = | ||||
|                 std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init(); | ||||
| 
 | ||||
|             while xlib::XCheckTypedEvent(self.dpy(), event_type, &mut event) | ||||
|                 != 0 | ||||
|             {} | ||||
| 
 | ||||
|             event | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn next_event(&self) -> XEvent { | ||||
|         unsafe { | ||||
|             let mut event = | ||||
|                 std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init(); | ||||
|             xlib::XNextEvent(self.dpy(), &mut event); | ||||
| 
 | ||||
|             event | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn grab_key_or_button(&self, window: Window, key: &KeyOrButton) { | ||||
|         let numlock_mask = self.get_numlock_mask(); | ||||
|         let modifiers = | ||||
|             vec![0, LockMask, numlock_mask, LockMask | numlock_mask]; | ||||
| 
 | ||||
|         for modifier in modifiers.iter() { | ||||
|             match key { | ||||
|                 &KeyOrButton::Key(keycode, modmask) => { | ||||
|                     unsafe { | ||||
|                         xlib::XGrabKey( | ||||
|                             self.dpy(), | ||||
|                             keycode, | ||||
|                             modmask | modifier, | ||||
|                             window, | ||||
|                             1, /* true */ | ||||
|                             GrabModeAsync, | ||||
|                             GrabModeAsync, | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
|                 &KeyOrButton::Button(button, modmask, buttonmask) => { | ||||
|                     unsafe { | ||||
|                         xlib::XGrabButton( | ||||
|                             self.dpy(), | ||||
|                             button, | ||||
|                             modmask | modifier, | ||||
|                             window, | ||||
|                             1, /*true */ | ||||
|                             buttonmask as u32, | ||||
|                             GrabModeAsync, | ||||
|                             GrabModeAsync, | ||||
|                             0, | ||||
|                             0, | ||||
|                         ); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn focus_client(&self, client: &Client) { | ||||
|         unsafe { | ||||
|             xlib::XSetInputFocus( | ||||
|                 self.dpy(), | ||||
|                 client.window, | ||||
|                 xlib::RevertToPointerRoot, | ||||
|                 xlib::CurrentTime, | ||||
|             ); | ||||
| 
 | ||||
|             let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref(); | ||||
| 
 | ||||
|             if let Some(screen) = screen { | ||||
|                 xlib::XSetWindowBorder( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     screen.white_pixel, | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             xlib::XChangeProperty( | ||||
|                 self.dpy(), | ||||
|                 self.root, | ||||
|                 self.atoms.active_window, | ||||
|                 xlib::XA_WINDOW, | ||||
|                 32, | ||||
|                 xlib::PropModeReplace, | ||||
|                 &client.window as *const u64 as *const _, | ||||
|                 1, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         self.send_protocol(client, self.atoms.take_focus); | ||||
|     } | ||||
| 
 | ||||
|     pub fn unfocus_client(&self, client: &Client) { | ||||
|         //info!("unfocusing client: {:?}", client);
 | ||||
| 
 | ||||
|         unsafe { | ||||
|             xlib::XSetInputFocus( | ||||
|                 self.dpy(), | ||||
|                 self.root, | ||||
|                 xlib::RevertToPointerRoot, | ||||
|                 xlib::CurrentTime, | ||||
|             ); | ||||
| 
 | ||||
|             let screen = xlib::XDefaultScreenOfDisplay(self.dpy()).as_ref(); | ||||
| 
 | ||||
|             if let Some(screen) = screen { | ||||
|                 xlib::XSetWindowBorder( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     screen.black_pixel, | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             // xlib::XDeleteProperty(
 | ||||
|             //     self.dpy(),
 | ||||
|             //     self.root,
 | ||||
|             //     self.atoms.active_window,
 | ||||
|             // );
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn move_resize_client(&self, client: &Client) { | ||||
|         let mut windowchanges = xlib::XWindowChanges { | ||||
|             x: client.position.x, | ||||
|             y: client.position.y, | ||||
|             width: client.size.x, | ||||
|             height: client.size.y, | ||||
|             border_width: 0, | ||||
|             sibling: 0, | ||||
|             stack_mode: 0, | ||||
|         }; | ||||
| 
 | ||||
|         if client.size.x < 1 || client.size.y < 1 { | ||||
|             error!("client {:?} size is less than 1 pixel!", client); | ||||
|         } else { | ||||
|             unsafe { | ||||
|                 xlib::XConfigureWindow( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     (xlib::CWY | xlib::CWX | xlib::CWHeight | xlib::CWWidth) | ||||
|                         as u32, | ||||
|                     &mut windowchanges, | ||||
|                 ); | ||||
| 
 | ||||
|                 // I don't think I have to call this ~
 | ||||
|                 //self.configure_client(client);
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn move_client(&self, client: &Client) { | ||||
|         let mut wc = xlib::XWindowChanges { | ||||
|             x: client.position.x, | ||||
|             y: client.position.y, | ||||
|             width: client.size.x, | ||||
|             height: client.size.y, | ||||
|             border_width: 0, | ||||
|             sibling: 0, | ||||
|             stack_mode: 0, | ||||
|         }; | ||||
| 
 | ||||
|         if client.size.x < 1 || client.size.y < 1 { | ||||
|             error!("client {:?} size is less than 1 pixel!", client); | ||||
|         } else { | ||||
|             unsafe { | ||||
|                 xlib::XConfigureWindow( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     (xlib::CWX | xlib::CWY) as u32, | ||||
|                     &mut wc, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn resize_client(&self, client: &Client) { | ||||
|         let mut wc = xlib::XWindowChanges { | ||||
|             x: client.position.x, | ||||
|             y: client.position.y, | ||||
|             width: client.size.x, | ||||
|             height: client.size.y, | ||||
|             border_width: 0, | ||||
|             sibling: 0, | ||||
|             stack_mode: 0, | ||||
|         }; | ||||
| 
 | ||||
|         if client.size.x < 1 || client.size.y < 1 { | ||||
|             error!("client {:?} size is less than 1 pixel!", client); | ||||
|         } else { | ||||
|             unsafe { | ||||
|                 xlib::XConfigureWindow( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     (xlib::CWWidth | xlib::CWHeight) as u32, | ||||
|                     &mut wc, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn hide_client(&self, client: &Client) { | ||||
|         let mut wc = xlib::XWindowChanges { | ||||
|             x: client.size.x * -2, | ||||
|             y: client.position.y, | ||||
|             width: client.size.x, | ||||
|             height: client.size.y, | ||||
|             border_width: 0, | ||||
|             sibling: 0, | ||||
|             stack_mode: 0, | ||||
|         }; | ||||
| 
 | ||||
|         if client.size.x < 1 || client.size.y < 1 { | ||||
|             error!("client {:?} size is less than 1 pixel!", client); | ||||
|         } else { | ||||
|             unsafe { | ||||
|                 xlib::XConfigureWindow( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     (xlib::CWX | xlib::CWY) as u32, | ||||
|                     &mut wc, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn raise_client(&self, client: &Client) { | ||||
|         unsafe { | ||||
|             XRaiseWindow(self.dpy(), client.window); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_window_size(&self, window: Window) -> Option<(i32, i32)> { | ||||
|         let mut wa = unsafe { | ||||
|             std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed() | ||||
|                 .assume_init() | ||||
|         }; | ||||
| 
 | ||||
|         if unsafe { | ||||
|             xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0 | ||||
|         } { | ||||
|             Some((wa.width, wa.height)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     fn get_window_attributes( | ||||
|         &self, | ||||
|         window: Window, | ||||
|     ) -> Option<XWindowAttributes> { | ||||
|         let mut wa = unsafe { | ||||
|             std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed() | ||||
|                 .assume_init() | ||||
|         }; | ||||
| 
 | ||||
|         if unsafe { | ||||
|             xlib::XGetWindowAttributes(self.dpy(), window, &mut wa) != 0 | ||||
|         } { | ||||
|             Some(wa) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_transient_for_window(&self, window: Window) -> Option<Window> { | ||||
|         let mut transient_for: Window = 0; | ||||
| 
 | ||||
|         if unsafe { | ||||
|             XGetTransientForHint(self.dpy(), window, &mut transient_for) != 0 | ||||
|         } { | ||||
|             Some(transient_for) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     pub fn expose_client(&self, client: &Client) { | ||||
|         self.expose_window(client.window); | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     fn expose_window(&self, window: Window) { | ||||
|         if let Some(wa) = self.get_window_attributes(window) { | ||||
|             unsafe { | ||||
|                 xlib::XClearArea( | ||||
|                     self.dpy(), | ||||
|                     window, | ||||
|                     0, | ||||
|                     0, | ||||
|                     wa.width as u32, | ||||
|                     wa.height as u32, | ||||
|                     1, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn configure_window(&self, event: &XConfigureRequestEvent) { | ||||
|         let mut wc = xlib::XWindowChanges { | ||||
|             x: event.x, | ||||
|             y: event.y, | ||||
|             width: event.width, | ||||
|             height: event.height, | ||||
|             border_width: event.border_width, | ||||
|             sibling: event.above, | ||||
|             stack_mode: event.detail, | ||||
|         }; | ||||
| 
 | ||||
|         unsafe { | ||||
|             xlib::XConfigureWindow( | ||||
|                 self.dpy(), | ||||
|                 event.window, | ||||
|                 event.value_mask as u32, | ||||
|                 &mut wc, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn configure_client(&self, client: &Client, border: i32) { | ||||
|         let mut event = xlib::XConfigureEvent { | ||||
|             type_: xlib::ConfigureNotify, | ||||
|             display: self.dpy(), | ||||
|             event: client.window, | ||||
|             window: client.window, | ||||
|             x: client.position.x, | ||||
|             y: client.position.y, | ||||
|             width: client.size.x, | ||||
|             height: client.size.y, | ||||
|             border_width: border, | ||||
|             override_redirect: 0, | ||||
|             send_event: 0, | ||||
|             serial: 0, | ||||
|             above: 0, | ||||
|         }; | ||||
| 
 | ||||
|         unsafe { | ||||
|             xlib::XSetWindowBorderWidth( | ||||
|                 self.dpy(), | ||||
|                 event.window, | ||||
|                 event.border_width as u32, | ||||
|             ); | ||||
| 
 | ||||
|             xlib::XSendEvent( | ||||
|                 self.dpy(), | ||||
|                 event.window, | ||||
|                 0, | ||||
|                 StructureNotifyMask, | ||||
|                 &mut event as *mut _ as *mut XEvent, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_window(&self, window: Window) { | ||||
|         unsafe { | ||||
|             XMapWindow(self.dpy(), window); | ||||
| 
 | ||||
|             xlib::XSelectInput( | ||||
|                 self.dpy(), | ||||
|                 window, | ||||
|                 EnterWindowMask | ||||
|                     | FocusChangeMask | ||||
|                     | PropertyChangeMask | ||||
|                     | StructureNotifyMask, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         self.grab_global_keybinds(window); | ||||
|     } | ||||
| 
 | ||||
|     pub fn dimensions(&self) -> (i32, i32) { | ||||
|         unsafe { | ||||
|             let mut wa = | ||||
|                 std::mem::MaybeUninit::<xlib::XWindowAttributes>::zeroed() | ||||
|                     .assume_init(); | ||||
| 
 | ||||
|             xlib::XGetWindowAttributes(self.dpy(), self.root, &mut wa); | ||||
| 
 | ||||
|             info!("Root window dimensions: {}, {}", wa.width, wa.height); | ||||
| 
 | ||||
|             (wa.width, wa.height) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn close_dpy(&self) { | ||||
|         unsafe { | ||||
|             XCloseDisplay(self.dpy()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn kill_client(&self, client: &Client) { | ||||
|         if !self.send_protocol(client, self.atoms.delete_window) { | ||||
|             unsafe { | ||||
|                 XKillClient(self.dpy(), client.window); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn grab_cursor(&self) { | ||||
|         unsafe { | ||||
|             XGrabPointer( | ||||
|                 self.dpy(), | ||||
|                 self.root, | ||||
|                 0, | ||||
|                 (ButtonPressMask | ButtonReleaseMask | PointerMotionMask) | ||||
|                     as u32, | ||||
|                 GrabModeAsync, | ||||
|                 GrabModeAsync, | ||||
|                 0, | ||||
|                 0, | ||||
|                 CurrentTime, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn release_cursor(&self) { | ||||
|         unsafe { | ||||
|             XUngrabPointer(self.dpy(), CurrentTime); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn move_cursor(&self, window: Option<Window>, position: (i32, i32)) { | ||||
|         unsafe { | ||||
|             XWarpPointer( | ||||
|                 self.dpy(), | ||||
|                 0, | ||||
|                 window.unwrap_or(self.root), | ||||
|                 0, | ||||
|                 0, | ||||
|                 0, | ||||
|                 0, | ||||
|                 position.0, | ||||
|                 position.1, | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn check_for_protocol(&self, client: &Client, proto: xlib::Atom) -> bool { | ||||
|         let mut protos: *mut xlib::Atom = null_mut(); | ||||
|         let mut num_protos: i32 = 0; | ||||
| 
 | ||||
|         unsafe { | ||||
|             if xlib::XGetWMProtocols( | ||||
|                 self.dpy(), | ||||
|                 client.window, | ||||
|                 &mut protos, | ||||
|                 &mut num_protos, | ||||
|             ) != 0 | ||||
|             { | ||||
|                 for i in 0..num_protos { | ||||
|                     if *protos.offset(i as isize) == proto { | ||||
|                         return true; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     fn send_protocol(&self, client: &Client, proto: xlib::Atom) -> bool { | ||||
|         if self.check_for_protocol(client, proto) { | ||||
|             let mut data = xlib::ClientMessageData::default(); | ||||
|             data.set_long(0, proto as i64); | ||||
| 
 | ||||
|             let mut event = XEvent { | ||||
|                 client_message: xlib::XClientMessageEvent { | ||||
|                     type_: xlib::ClientMessage, | ||||
|                     serial: 0, | ||||
|                     display: self.dpy(), | ||||
|                     send_event: 0, | ||||
|                     window: client.window, | ||||
|                     format: 32, | ||||
|                     message_type: self.atoms.protocols, | ||||
|                     data, | ||||
|                 }, | ||||
|             }; | ||||
| 
 | ||||
|             unsafe { | ||||
|                 xlib::XSendEvent( | ||||
|                     self.dpy(), | ||||
|                     client.window, | ||||
|                     0, | ||||
|                     xlib::NoEventMask, | ||||
|                     &mut event, | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             true | ||||
|         } else { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn make_key<S>(&self, key: S, modmask: u32) -> KeyOrButton | ||||
|     where | ||||
|         S: AsRef<str>, | ||||
|     { | ||||
|         let key = self.keycode(key); | ||||
| 
 | ||||
|         KeyOrButton::Key(key, modmask) | ||||
|     } | ||||
| 
 | ||||
|     fn keycode<S>(&self, string: S) -> i32 | ||||
|     where | ||||
|         S: AsRef<str>, | ||||
|     { | ||||
|         let c_string = CString::new(string.as_ref()).unwrap(); | ||||
| 
 | ||||
|         unsafe { | ||||
|             let keysym = xlib::XStringToKeysym(c_string.as_ptr()); | ||||
|             xlib::XKeysymToKeycode(self.dpy(), keysym) as i32 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn get_numlock_mask(&self) -> u32 { | ||||
|         unsafe { | ||||
|             let modmap = xlib::XGetModifierMapping(self.dpy()); | ||||
|             let max_keypermod = (*modmap).max_keypermod; | ||||
| 
 | ||||
|             for i in 0..8 { | ||||
|                 for j in 0..max_keypermod { | ||||
|                     if *(*modmap) | ||||
|                         .modifiermap | ||||
|                         .offset((i * max_keypermod + j) as isize) | ||||
|                         == xlib::XKeysymToKeycode( | ||||
|                             self.dpy(), | ||||
|                             x11::keysym::XK_Num_Lock as u64, | ||||
|                         ) | ||||
|                     { | ||||
|                         return 1 << i; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         0 | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_clean_mask(&self) -> u32 { | ||||
|         !(self.get_numlock_mask() | LockMask) | ||||
|             & (ShiftMask | ||||
|                 | ControlMask | ||||
|                 | Mod1Mask | ||||
|                 | Mod2Mask | ||||
|                 | Mod3Mask | ||||
|                 | Mod4Mask | ||||
|                 | Mod5Mask) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(dead_code)] | ||||
|     pub fn clean_mask(&self, mask: u32) -> u32 { | ||||
|         mask & self.get_clean_mask() | ||||
|     } | ||||
| 
 | ||||
|     pub fn are_masks_equal(&self, rhs: u32, lhs: u32) -> bool { | ||||
|         let clean = self.get_clean_mask(); | ||||
| 
 | ||||
|         rhs & clean == lhs & clean | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display { | ||||
|     pub fn new(display: *mut x11::xlib::Display) -> Self { | ||||
|         Self { | ||||
|             0: Rc::new(display), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(&self) -> *mut x11::xlib::Display { | ||||
|         *self.0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Atoms { | ||||
|     fn init(display: Display) -> Self { | ||||
|         unsafe { | ||||
|             Self { | ||||
|                 protocols: { | ||||
|                     let name = CString::new("WM_PROTOCOLS").unwrap(); | ||||
|                     XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) | ||||
|                 }, | ||||
|                 delete_window: { | ||||
|                     let name = CString::new("WM_DELETE_WINDOW").unwrap(); | ||||
|                     XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) | ||||
|                 }, | ||||
|                 active_window: { | ||||
|                     let name = CString::new("WM_ACTIVE_WINDOW").unwrap(); | ||||
|                     XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) | ||||
|                 }, | ||||
|                 take_focus: { | ||||
|                     let name = CString::new("WM_TAKE_FOCUS").unwrap(); | ||||
|                     XInternAtom(display.get(), name.as_c_str().as_ptr(), 0) | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[allow(dead_code)] | ||||
| unsafe extern "C" fn xlib_error_handler( | ||||
|     _dpy: *mut x11::xlib::Display, | ||||
|     ee: *mut x11::xlib::XErrorEvent, | ||||
| ) -> std::os::raw::c_int { | ||||
|     let err = ee.as_ref().unwrap(); | ||||
| 
 | ||||
|     if err.error_code == x11::xlib::BadWindow | ||||
|         || err.error_code == x11::xlib::BadDrawable | ||||
|         || err.error_code == x11::xlib::BadAccess | ||||
|         || err.error_code == x11::xlib::BadMatch | ||||
|     { | ||||
|         0 | ||||
|     } else { | ||||
|         error!( | ||||
|             "wm: fatal error:\nrequest_code: {}\nerror_code: {}", | ||||
|             err.request_code, err.error_code | ||||
|         ); | ||||
|         std::process::exit(1); | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in a new issue