more advanced logging, fixed floating windows not being on top
This commit is contained in:
parent
46e2c7448c
commit
09548522ff
|
@ -10,3 +10,5 @@ edition = "2018"
|
|||
x11 = {version = "2.18.2", features = ["xlib"] }
|
||||
log = "0.4.13"
|
||||
simple_logger = "1.11.0"
|
||||
dirs = "3.0.2"
|
||||
log4rs = "1.0.0"
|
|
@ -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<Item = (&u64, &Client)> {
|
||||
self.iter_floating().filter(|&(_, c)| c.is_transient())
|
||||
}
|
||||
|
||||
pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> {
|
||||
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
|
||||
|
|
67
src/main.rs
67
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();
|
||||
}
|
||||
|
|
52
src/state.rs
52
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<K>(&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);
|
||||
|
||||
|
|
49
src/xlib.rs
49
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::<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();
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue