From 09548522ff4d19d244e450664ed1b79326f2691a Mon Sep 17 00:00:00 2001 From: NoOneBtw Date: Sat, 1 May 2021 22:17:43 +0200 Subject: [PATCH] more advanced logging, fixed floating windows not being on top --- Cargo.toml | 4 ++- src/clients.rs | 24 +++++++++++++++--- src/main.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++----- src/state.rs | 52 ++++++++++++++++++++++++++++++++++++--- src/xlib.rs | 49 +++++++++++++++++++++++++++++++----- 5 files changed, 176 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c2bd4c..a4473a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,6 @@ edition = "2018" [dependencies] x11 = {version = "2.18.2", features = ["xlib"] } log = "0.4.13" -simple_logger = "1.11.0" \ No newline at end of file +simple_logger = "1.11.0" +dirs = "3.0.2" +log4rs = "1.0.0" \ No newline at end of file diff --git a/src/clients.rs b/src/clients.rs index 79f97ce..881c344 100644 --- a/src/clients.rs +++ b/src/clients.rs @@ -146,12 +146,14 @@ mod tests { window: 1, size: (1, 1), position: (1, 1), + transient_for: None, }); clients.insert(Client { window: 2, size: (1, 1), position: (1, 1), + transient_for: None, }); clients.arrange_virtual_screen(600, 400, None); @@ -174,6 +176,7 @@ mod tests { window: 3, size: (1, 1), position: (1, 1), + transient_for: None, }); clients.arrange_virtual_screen(600, 400, None); @@ -326,6 +329,12 @@ impl ClientState { where K: ClientKey, { + if let Some(focused_client) = self.focused { + if focused_client == key.key() { + self.focused = None; + } + } + self.remove_from_virtual_screens(key); self.clients.remove(&key.key()); @@ -354,6 +363,10 @@ impl ClientState { .filter(move |&(k, _)| !self.is_client_visible(k)) } + pub fn iter_transient(&self) -> impl Iterator { + self.iter_floating().filter(|&(_, c)| c.is_transient()) + } + pub fn iter_visible(&self) -> impl Iterator { self.iter_all_clients() .filter(move |&(k, _)| self.is_client_visible(k)) @@ -527,10 +540,15 @@ impl ClientState { { if self.contains(key) { match self.focused { - // focus the new client and return reference to it and the previously focused client. Some(focused) => { - self.focused = Some(key.key()); - (self.get(key), self.get(&focused)) + // If we are trying to focus the focused client, do nothing + if focused == key.key() { + (ClientEntry::Vacant, ClientEntry::Vacant) + } else { + // focus the new client and return reference to it and the previously focused client. + self.focused = Some(key.key()); + (self.get(key), self.get(&focused)) + } } /* not currently focusing any client diff --git a/src/main.rs b/src/main.rs index 94e3f06..3bb1fc9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,10 @@ -use log::info; -use std::io::Result; +use log::{debug, error, info, trace, warn}; +use log4rs::{ + append::{console::ConsoleAppender, file::FileAppender}, + config::{Appender, Root}, + encode::pattern::PatternEncoder, + Config, +}; mod clients; mod state; @@ -20,7 +25,7 @@ unsafe extern "C" fn xlib_error_handler( { 0 } else { - eprintln!( + error!( "wm: fatal error:\nrequest_code: {}\nerror_code: {}", err.request_code, err.error_code ); @@ -28,9 +33,59 @@ unsafe extern "C" fn xlib_error_handler( } } -fn main() -> Result<()> { - simple_logger::SimpleLogger::new().init().unwrap(); - info!("Hello, World!"); +fn init_logger() { + let encoder = Box::new(PatternEncoder::new( + "{d(%Y-%m-%d %H:%M:%S %Z)(utc)} │ {({M}::{f}:{L}):>25} │ {h({l:>5})} │ {m}{n}", + )); + + let stdout = ConsoleAppender::builder().encoder(encoder.clone()).build(); + + let home = dirs::home_dir().expect("Failed to get $HOME env var."); + + let logfile = FileAppender::builder() + //.encoder(Box::new(PatternEncoder::default())) + .encoder(encoder) + .build(home.join(".local/portlights.log")) + .unwrap(); + + let config = Config::builder() + .appender(Appender::builder().build("stdout", Box::new(stdout))) + .appender(Appender::builder().build("logfile", Box::new(logfile))) + .build( + Root::builder() + .appender("stdout") + .appender("logfile") + .build(log::LevelFilter::Info), + ) + .unwrap(); + + log4rs::init_config(config).unwrap(); +} + +fn main() { + init_logger(); + + log_prologue(); state::WindowManager::new().init().run(); } + +fn log_prologue() { + info!("========================================================================"); + info!("Portlights Window Manager"); + info!("Version: {}", env!("CARGO_PKG_VERSION")); + info!("Warning levels:"); + info!("Info!"); + warn!("Warning!"); + debug!("Debug!"); + error!("Error!"); + trace!("Trace!"); + info!("========================================================================"); +} + +#[test] +fn test_logger() { + init_logger(); + + log_prologue(); +} diff --git a/src/state.rs b/src/state.rs index fb2a631..b1a30c7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -70,6 +70,29 @@ impl WindowManager { ButtonPressMask | ButtonReleaseMask | PointerMotionMask, )); + self.add_keybind(KeyBinding::new( + self.xlib.make_key("P", Mod1Mask), + |wm, _| { + wm.spawn( + "dmenu_run", + &[ + "-m", + "0", + "-fn", + "'New York:size=13'", + "-nb", + "#222222", + "-nf", + "#bbbbbb", + "-sb", + "#dddddd", + "-sf", + "#eeeeee", + ], + ) + }, + )); + self.add_keybind(KeyBinding::new( self.xlib.make_key("M", Mod1Mask), Self::handle_switch_stack, @@ -182,6 +205,8 @@ impl WindowManager { } fn handle_switch_stack(&mut self, event: &XKeyEvent) { + info!("Switching stack for window{:?}", event.subwindow); + self.clients.switch_stack_for_client(&event.subwindow); self.arrange_clients(); @@ -221,6 +246,7 @@ impl WindowManager { } xlib::MotionNotify => { + //let event = self.xlib.squash_event(xlib::MotionNotify); let event: &XMotionEvent = event.as_ref(); if let Some(move_window) = &mut self.move_window { @@ -271,6 +297,7 @@ impl WindowManager { }; self.xlib.move_cursor(client.window, position); + self.xlib.grab_cursor(); self.resize_window = Some(MoveWindow { key: event.subwindow, @@ -285,13 +312,16 @@ impl WindowManager { if event.button == 3 && self.resize_window.is_some() { self.resize_window = None; + self.xlib.release_cursor(); } } xlib::MotionNotify => { + let event = self.xlib.squash_event(xlib::MotionNotify); let event: &XMotionEvent = event.as_ref(); if let Some(resize_window) = &mut self.resize_window { + info!("MotionNotify-resize"); let (x, y) = ( event.x - resize_window.cached_cursor_position.0, event.y - resize_window.cached_cursor_position.1, @@ -337,6 +367,16 @@ impl WindowManager { .for_each(|(_, c)| self.xlib.hide_client(c)); } + fn raise_floating_clients(&self) { + self.clients + .iter_floating() + .for_each(|(_, c)| self.xlib.raise_client(c)); + + self.clients + .iter_transient() + .for_each(|(_, c)| self.xlib.raise_client(c)); + } + fn arrange_clients(&mut self) { let (width, height) = self.xlib.dimensions(); self.clients.arrange_virtual_screen(width, height, Some(2)); @@ -347,9 +387,7 @@ impl WindowManager { .iter_visible() .for_each(|(_, c)| self.xlib.move_resize_client(c)); - self.clients - .iter_floating() - .for_each(|(_, c)| self.xlib.raise_client(c)); + self.raise_floating_clients(); } fn focus_client(&mut self, key: &K) @@ -364,10 +402,13 @@ impl WindowManager { if let Some(new) = new.into_option() { self.xlib.focus_client(new); + self.xlib.raise_client(new); } + + self.raise_floating_clients(); } - #[allow(dead_code)] + #[deprecated] fn unfocus_client(&mut self) { if let Some(client) = self.clients.unfocus().into_option() { self.xlib.unfocus_client(client); @@ -375,6 +416,7 @@ impl WindowManager { } fn new_client(&mut self, window: Window) { + info!("new client: {:?}", window); let client = if let Some(transient_window) = self.xlib.get_transient_for_window(window) { Client::new_transient( window, @@ -405,6 +447,7 @@ impl WindowManager { fn unmap_notify(&mut self, event: &XEvent) { let event: &XUnmapEvent = event.as_ref(); + info!("unmap_notify: {:?}", event.window); self.clients.remove(&event.window); @@ -413,6 +456,7 @@ impl WindowManager { fn destroy_notify(&mut self, event: &XEvent) { let event: &XDestroyWindowEvent = event.as_ref(); + info!("destroy_notify: {:?}", event.window); self.clients.remove(&event.window); diff --git a/src/xlib.rs b/src/xlib.rs index 154d904..6d17ee6 100644 --- a/src/xlib.rs +++ b/src/xlib.rs @@ -1,13 +1,15 @@ +use log::info; use std::ptr::{null, null_mut}; use std::{ffi::CString, rc::Rc}; use x11::xlib::{ - self, Atom, ButtonPressMask, CWEventMask, ControlMask, EnterWindowMask, FocusChangeMask, - LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, PointerMotionMask, - PropertyChangeMask, ShiftMask, Status, StructureNotifyMask, SubstructureNotifyMask, - SubstructureRedirectMask, Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen, - XEvent, XGetTransientForHint, XInternAtom, XKillClient, XMapWindow, XOpenDisplay, XRaiseWindow, - XRootWindow, XSync, XWarpPointer, + self, Atom, ButtonPressMask, ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime, + EnterWindowMask, FocusChangeMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, + PointerMotionMask, PropertyChangeMask, ShiftMask, Status, StructureNotifyMask, + SubstructureNotifyMask, SubstructureRedirectMask, Window, XCloseDisplay, + XConfigureRequestEvent, XDefaultScreen, XEvent, XGetTransientForHint, XGrabPointer, + XInternAtom, XKillClient, XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow, XSync, + XUngrabPointer, XWarpPointer, }; use xlib::GrabModeAsync; @@ -118,6 +120,16 @@ impl XLib { self.display.get() } + pub fn squash_event(&self, event_type: i32) -> XEvent { + unsafe { + let mut event = std::mem::MaybeUninit::::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::::zeroed().assume_init(); @@ -188,9 +200,12 @@ impl XLib { } self.send_event(client, self.atoms.take_focus); + + self.raise_client(client); } pub fn unfocus_client(&self, client: &Client) { + info!("unfocusing client: {:?}", client); unsafe { xlib::XSetInputFocus( self.dpy(), @@ -423,6 +438,28 @@ impl XLib { } } + 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: Window, position: (i32, i32)) { unsafe { XWarpPointer(self.dpy(), 0, window, 0, 0, 0, 0, position.0, position.1);