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 num_traits::Zero; | ||||||
| use std::{ffi::CString, mem::MaybeUninit, rc::Rc}; | use std::{ffi::CString, rc::Rc}; | ||||||
| 
 | 
 | ||||||
| use thiserror::Error; | 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::{ | use crate::backends::{ | ||||||
|     keycodes::KeyOrButton, xlib::keysym::mouse_button_to_xbutton, |     keycodes::KeyOrButton, xlib::keysym::mouse_button_to_xbutton, | ||||||
|  | @ -290,49 +290,62 @@ impl XLib { | ||||||
|             xlib::PropertyNotify => { |             xlib::PropertyNotify => { | ||||||
|                 let ev = unsafe { &event.property }; |                 let ev = unsafe { &event.property }; | ||||||
| 
 | 
 | ||||||
|                 (ev.atom == self.atoms.net_wm_window_type) |                 match ev.atom { | ||||||
|                     .then(|| { |                     atom if atom == self.atoms.net_wm_window_type => { | ||||||
|                         (self.get_atom_property( |                         if self | ||||||
|                             ev.window, |                             .get_atom_property( | ||||||
|                             self.atoms.net_wm_state, |                                 ev.window, | ||||||
|                         ) == Some(self.atoms.net_wm_state_fullscreen)) |                                 self.atoms.net_wm_state, | ||||||
|                         .then(|| { |                             ) | ||||||
|                             XLibWindowEvent::FullscreenEvent( |                             .map(|atom| { | ||||||
|  |                                 *atom == self.atoms.net_wm_state_fullscreen | ||||||
|  |                             }) | ||||||
|  |                             .unwrap_or(false) | ||||||
|  |                         { | ||||||
|  |                             debug!("fullscreen event"); | ||||||
|  |                             Some(XLibWindowEvent::FullscreenEvent( | ||||||
|                                 FullscreenEvent::new( |                                 FullscreenEvent::new( | ||||||
|                                     ev.window, |                                     ev.window, | ||||||
|                                     FullscreenState::On, |                                     FullscreenState::On, | ||||||
|                                 ), |                                 ), | ||||||
|                             ) |                             )) | ||||||
|                         }) |                         } else { | ||||||
|                     }) |                             None | ||||||
|                     .flatten() |                         } | ||||||
|  |                     } | ||||||
|  |                     _ => None, | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             xlib::ClientMessage => { |             xlib::ClientMessage => { | ||||||
|                 let ev = unsafe { &event.client_message }; |                 let ev = unsafe { &event.client_message }; | ||||||
| 
 | 
 | ||||||
|                 (ev.message_type == self.atoms.net_wm_state) |                 match ev.message_type { | ||||||
|                     .then(|| { |                     message_type if message_type == self.atoms.net_wm_state => { | ||||||
|                         let data = ev.data.as_longs(); |                         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 |                             || data[2] as u64 | ||||||
|                                 == self.atoms.net_wm_state_fullscreen) |                                 == self.atoms.net_wm_state_fullscreen | ||||||
|                             .then(|| { |                         { | ||||||
|                                 XLibWindowEvent::FullscreenEvent( |                             debug!("fullscreen event"); | ||||||
|                                     FullscreenEvent::new( |                             Some(XLibWindowEvent::FullscreenEvent( | ||||||
|                                         ev.window, |                                 FullscreenEvent::new( | ||||||
|                                         match data[0] /* as u64 */ { |                                     ev.window, | ||||||
|                                             0 => FullscreenState::Off, |                                     match data[0] /* as u64 */ { | ||||||
|                                             1 => FullscreenState::On, |                                         0 => FullscreenState::Off, | ||||||
|                                             2 => FullscreenState::Toggle, |                                         1 => FullscreenState::On, | ||||||
|                                             _ => { |                                         2 => FullscreenState::Toggle, | ||||||
|                                                 unreachable!() |                                         _ => { | ||||||
|                                             } |                                             unreachable!() | ||||||
|                                         }, |                                         } | ||||||
|                                     ), |                                     }, | ||||||
|                                 ) |                                 ), | ||||||
|                             }) |                             )) | ||||||
|                     }) |                         } else { | ||||||
|                     .flatten() |                             None | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     _ => None, | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             _ => None, |             _ => None, | ||||||
|         } |         } | ||||||
|  | @ -361,31 +374,33 @@ impl XLib { | ||||||
|         &self, |         &self, | ||||||
|         window: xlib::Window, |         window: xlib::Window, | ||||||
|         atom: xlib::Atom, |         atom: xlib::Atom, | ||||||
|     ) -> Option<xlib::Atom> { |     ) -> Option<xpointer::XPointer<xlib::Atom>> { | ||||||
|         let mut di = 0; |         let mut di = 0; | ||||||
|         let mut dl0 = 0; |         let mut dl0 = 0; | ||||||
|         let mut dl1 = 0; |         let mut dl1 = 0; | ||||||
|         let mut da = 0; |         let mut da = 0; | ||||||
| 
 | 
 | ||||||
|         let mut atom_out = MaybeUninit::<xlib::Atom>::zeroed(); |         let (atom_out, success) = | ||||||
|  |             xpointer::XPointer::<xlib::Atom>::build_with_result(|ptr| unsafe { | ||||||
|  |                 xlib::XGetWindowProperty( | ||||||
|  |                     self.dpy(), | ||||||
|  |                     window, | ||||||
|  |                     atom, | ||||||
|  |                     0, | ||||||
|  |                     std::mem::size_of::<xlib::Atom>() as i64, | ||||||
|  |                     0, | ||||||
|  |                     xlib::XA_ATOM, | ||||||
|  |                     &mut da, | ||||||
|  |                     &mut di, | ||||||
|  |                     &mut dl0, | ||||||
|  |                     &mut dl1, | ||||||
|  |                     ptr as *mut _ as *mut _, | ||||||
|  |                 ) == Success.into() | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
|         unsafe { |         debug!("get_atom_property: {} {:?}", success, atom_out); | ||||||
|             (xlib::XGetWindowProperty( | 
 | ||||||
|                 self.dpy(), |         success.then(|| atom_out).flatten() | ||||||
|                 window, |  | ||||||
|                 atom, |  | ||||||
|                 0, |  | ||||||
|                 std::mem::size_of::<xlib::Atom>() as i64, |  | ||||||
|                 0, |  | ||||||
|                 xlib::XA_ATOM, |  | ||||||
|                 &mut da, |  | ||||||
|                 &mut di, |  | ||||||
|                 &mut dl0, |  | ||||||
|                 &mut dl1, |  | ||||||
|                 atom_out.as_mut_ptr() as *mut _, |  | ||||||
|             ) != 0) |  | ||||||
|                 .then(|| atom_out.assume_init()) |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn check_for_protocol( |     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() |             Root::builder() | ||||||
|                 .appender("stdout") |                 .appender("stdout") | ||||||
|                 //.appender("logfile")
 |                 //.appender("logfile")
 | ||||||
|                 .build(log::LevelFilter::Info), |                 .build(log::LevelFilter::Debug), | ||||||
|         ) |         ) | ||||||
|         .unwrap(); |         .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