more advanced logging, fixed floating windows not being on top
This commit is contained in:
parent
46e2c7448c
commit
09548522ff
|
@ -9,4 +9,6 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
x11 = {version = "2.18.2", features = ["xlib"] }
|
x11 = {version = "2.18.2", features = ["xlib"] }
|
||||||
log = "0.4.13"
|
log = "0.4.13"
|
||||||
simple_logger = "1.11.0"
|
simple_logger = "1.11.0"
|
||||||
|
dirs = "3.0.2"
|
||||||
|
log4rs = "1.0.0"
|
|
@ -146,12 +146,14 @@ mod tests {
|
||||||
window: 1,
|
window: 1,
|
||||||
size: (1, 1),
|
size: (1, 1),
|
||||||
position: (1, 1),
|
position: (1, 1),
|
||||||
|
transient_for: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
clients.insert(Client {
|
clients.insert(Client {
|
||||||
window: 2,
|
window: 2,
|
||||||
size: (1, 1),
|
size: (1, 1),
|
||||||
position: (1, 1),
|
position: (1, 1),
|
||||||
|
transient_for: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
clients.arrange_virtual_screen(600, 400, None);
|
clients.arrange_virtual_screen(600, 400, None);
|
||||||
|
@ -174,6 +176,7 @@ mod tests {
|
||||||
window: 3,
|
window: 3,
|
||||||
size: (1, 1),
|
size: (1, 1),
|
||||||
position: (1, 1),
|
position: (1, 1),
|
||||||
|
transient_for: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
clients.arrange_virtual_screen(600, 400, None);
|
clients.arrange_virtual_screen(600, 400, None);
|
||||||
|
@ -326,6 +329,12 @@ impl ClientState {
|
||||||
where
|
where
|
||||||
K: ClientKey,
|
K: ClientKey,
|
||||||
{
|
{
|
||||||
|
if let Some(focused_client) = self.focused {
|
||||||
|
if focused_client == key.key() {
|
||||||
|
self.focused = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.remove_from_virtual_screens(key);
|
self.remove_from_virtual_screens(key);
|
||||||
|
|
||||||
self.clients.remove(&key.key());
|
self.clients.remove(&key.key());
|
||||||
|
@ -354,6 +363,10 @@ impl ClientState {
|
||||||
.filter(move |&(k, _)| !self.is_client_visible(k))
|
.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)> {
|
pub fn iter_visible(&self) -> impl Iterator<Item = (&u64, &Client)> {
|
||||||
self.iter_all_clients()
|
self.iter_all_clients()
|
||||||
.filter(move |&(k, _)| self.is_client_visible(k))
|
.filter(move |&(k, _)| self.is_client_visible(k))
|
||||||
|
@ -527,10 +540,15 @@ impl ClientState {
|
||||||
{
|
{
|
||||||
if self.contains(key) {
|
if self.contains(key) {
|
||||||
match self.focused {
|
match self.focused {
|
||||||
// focus the new client and return reference to it and the previously focused client.
|
|
||||||
Some(focused) => {
|
Some(focused) => {
|
||||||
self.focused = Some(key.key());
|
// If we are trying to focus the focused client, do nothing
|
||||||
(self.get(key), self.get(&focused))
|
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
|
not currently focusing any client
|
||||||
|
|
67
src/main.rs
67
src/main.rs
|
@ -1,5 +1,10 @@
|
||||||
use log::info;
|
use log::{debug, error, info, trace, warn};
|
||||||
use std::io::Result;
|
use log4rs::{
|
||||||
|
append::{console::ConsoleAppender, file::FileAppender},
|
||||||
|
config::{Appender, Root},
|
||||||
|
encode::pattern::PatternEncoder,
|
||||||
|
Config,
|
||||||
|
};
|
||||||
|
|
||||||
mod clients;
|
mod clients;
|
||||||
mod state;
|
mod state;
|
||||||
|
@ -20,7 +25,7 @@ unsafe extern "C" fn xlib_error_handler(
|
||||||
{
|
{
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
eprintln!(
|
error!(
|
||||||
"wm: fatal error:\nrequest_code: {}\nerror_code: {}",
|
"wm: fatal error:\nrequest_code: {}\nerror_code: {}",
|
||||||
err.request_code, err.error_code
|
err.request_code, err.error_code
|
||||||
);
|
);
|
||||||
|
@ -28,9 +33,59 @@ unsafe extern "C" fn xlib_error_handler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn init_logger() {
|
||||||
simple_logger::SimpleLogger::new().init().unwrap();
|
let encoder = Box::new(PatternEncoder::new(
|
||||||
info!("Hello, World!");
|
"{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();
|
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,
|
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.add_keybind(KeyBinding::new(
|
||||||
self.xlib.make_key("M", Mod1Mask),
|
self.xlib.make_key("M", Mod1Mask),
|
||||||
Self::handle_switch_stack,
|
Self::handle_switch_stack,
|
||||||
|
@ -182,6 +205,8 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_switch_stack(&mut self, event: &XKeyEvent) {
|
fn handle_switch_stack(&mut self, event: &XKeyEvent) {
|
||||||
|
info!("Switching stack for window{:?}", event.subwindow);
|
||||||
|
|
||||||
self.clients.switch_stack_for_client(&event.subwindow);
|
self.clients.switch_stack_for_client(&event.subwindow);
|
||||||
|
|
||||||
self.arrange_clients();
|
self.arrange_clients();
|
||||||
|
@ -221,6 +246,7 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
xlib::MotionNotify => {
|
xlib::MotionNotify => {
|
||||||
|
//let event = self.xlib.squash_event(xlib::MotionNotify);
|
||||||
let event: &XMotionEvent = event.as_ref();
|
let event: &XMotionEvent = event.as_ref();
|
||||||
|
|
||||||
if let Some(move_window) = &mut self.move_window {
|
if let Some(move_window) = &mut self.move_window {
|
||||||
|
@ -271,6 +297,7 @@ impl WindowManager {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.xlib.move_cursor(client.window, position);
|
self.xlib.move_cursor(client.window, position);
|
||||||
|
self.xlib.grab_cursor();
|
||||||
|
|
||||||
self.resize_window = Some(MoveWindow {
|
self.resize_window = Some(MoveWindow {
|
||||||
key: event.subwindow,
|
key: event.subwindow,
|
||||||
|
@ -285,13 +312,16 @@ impl WindowManager {
|
||||||
|
|
||||||
if event.button == 3 && self.resize_window.is_some() {
|
if event.button == 3 && self.resize_window.is_some() {
|
||||||
self.resize_window = None;
|
self.resize_window = None;
|
||||||
|
self.xlib.release_cursor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xlib::MotionNotify => {
|
xlib::MotionNotify => {
|
||||||
|
let event = self.xlib.squash_event(xlib::MotionNotify);
|
||||||
let event: &XMotionEvent = event.as_ref();
|
let event: &XMotionEvent = event.as_ref();
|
||||||
|
|
||||||
if let Some(resize_window) = &mut self.resize_window {
|
if let Some(resize_window) = &mut self.resize_window {
|
||||||
|
info!("MotionNotify-resize");
|
||||||
let (x, y) = (
|
let (x, y) = (
|
||||||
event.x - resize_window.cached_cursor_position.0,
|
event.x - resize_window.cached_cursor_position.0,
|
||||||
event.y - resize_window.cached_cursor_position.1,
|
event.y - resize_window.cached_cursor_position.1,
|
||||||
|
@ -337,6 +367,16 @@ impl WindowManager {
|
||||||
.for_each(|(_, c)| self.xlib.hide_client(c));
|
.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) {
|
fn arrange_clients(&mut self) {
|
||||||
let (width, height) = self.xlib.dimensions();
|
let (width, height) = self.xlib.dimensions();
|
||||||
self.clients.arrange_virtual_screen(width, height, Some(2));
|
self.clients.arrange_virtual_screen(width, height, Some(2));
|
||||||
|
@ -347,9 +387,7 @@ impl WindowManager {
|
||||||
.iter_visible()
|
.iter_visible()
|
||||||
.for_each(|(_, c)| self.xlib.move_resize_client(c));
|
.for_each(|(_, c)| self.xlib.move_resize_client(c));
|
||||||
|
|
||||||
self.clients
|
self.raise_floating_clients();
|
||||||
.iter_floating()
|
|
||||||
.for_each(|(_, c)| self.xlib.raise_client(c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_client<K>(&mut self, key: &K)
|
fn focus_client<K>(&mut self, key: &K)
|
||||||
|
@ -364,10 +402,13 @@ impl WindowManager {
|
||||||
|
|
||||||
if let Some(new) = new.into_option() {
|
if let Some(new) = new.into_option() {
|
||||||
self.xlib.focus_client(new);
|
self.xlib.focus_client(new);
|
||||||
|
self.xlib.raise_client(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.raise_floating_clients();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[deprecated]
|
||||||
fn unfocus_client(&mut self) {
|
fn unfocus_client(&mut self) {
|
||||||
if let Some(client) = self.clients.unfocus().into_option() {
|
if let Some(client) = self.clients.unfocus().into_option() {
|
||||||
self.xlib.unfocus_client(client);
|
self.xlib.unfocus_client(client);
|
||||||
|
@ -375,6 +416,7 @@ impl WindowManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_client(&mut self, window: Window) {
|
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) {
|
let client = if let Some(transient_window) = self.xlib.get_transient_for_window(window) {
|
||||||
Client::new_transient(
|
Client::new_transient(
|
||||||
window,
|
window,
|
||||||
|
@ -405,6 +447,7 @@ impl WindowManager {
|
||||||
|
|
||||||
fn unmap_notify(&mut self, event: &XEvent) {
|
fn unmap_notify(&mut self, event: &XEvent) {
|
||||||
let event: &XUnmapEvent = event.as_ref();
|
let event: &XUnmapEvent = event.as_ref();
|
||||||
|
info!("unmap_notify: {:?}", event.window);
|
||||||
|
|
||||||
self.clients.remove(&event.window);
|
self.clients.remove(&event.window);
|
||||||
|
|
||||||
|
@ -413,6 +456,7 @@ impl WindowManager {
|
||||||
|
|
||||||
fn destroy_notify(&mut self, event: &XEvent) {
|
fn destroy_notify(&mut self, event: &XEvent) {
|
||||||
let event: &XDestroyWindowEvent = event.as_ref();
|
let event: &XDestroyWindowEvent = event.as_ref();
|
||||||
|
info!("destroy_notify: {:?}", event.window);
|
||||||
|
|
||||||
self.clients.remove(&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::ptr::{null, null_mut};
|
||||||
use std::{ffi::CString, rc::Rc};
|
use std::{ffi::CString, rc::Rc};
|
||||||
|
|
||||||
use x11::xlib::{
|
use x11::xlib::{
|
||||||
self, Atom, ButtonPressMask, CWEventMask, ControlMask, EnterWindowMask, FocusChangeMask,
|
self, Atom, ButtonPressMask, ButtonReleaseMask, CWEventMask, ControlMask, CurrentTime,
|
||||||
LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, PointerMotionMask,
|
EnterWindowMask, FocusChangeMask, LockMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask,
|
||||||
PropertyChangeMask, ShiftMask, Status, StructureNotifyMask, SubstructureNotifyMask,
|
PointerMotionMask, PropertyChangeMask, ShiftMask, Status, StructureNotifyMask,
|
||||||
SubstructureRedirectMask, Window, XCloseDisplay, XConfigureRequestEvent, XDefaultScreen,
|
SubstructureNotifyMask, SubstructureRedirectMask, Window, XCloseDisplay,
|
||||||
XEvent, XGetTransientForHint, XInternAtom, XKillClient, XMapWindow, XOpenDisplay, XRaiseWindow,
|
XConfigureRequestEvent, XDefaultScreen, XEvent, XGetTransientForHint, XGrabPointer,
|
||||||
XRootWindow, XSync, XWarpPointer,
|
XInternAtom, XKillClient, XMapWindow, XOpenDisplay, XRaiseWindow, XRootWindow, XSync,
|
||||||
|
XUngrabPointer, XWarpPointer,
|
||||||
};
|
};
|
||||||
use xlib::GrabModeAsync;
|
use xlib::GrabModeAsync;
|
||||||
|
|
||||||
|
@ -118,6 +120,16 @@ impl XLib {
|
||||||
self.display.get()
|
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 {
|
pub fn next_event(&self) -> XEvent {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut event = std::mem::MaybeUninit::<xlib::XEvent>::zeroed().assume_init();
|
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.send_event(client, self.atoms.take_focus);
|
||||||
|
|
||||||
|
self.raise_client(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unfocus_client(&self, client: &Client) {
|
pub fn unfocus_client(&self, client: &Client) {
|
||||||
|
info!("unfocusing client: {:?}", client);
|
||||||
unsafe {
|
unsafe {
|
||||||
xlib::XSetInputFocus(
|
xlib::XSetInputFocus(
|
||||||
self.dpy(),
|
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)) {
|
pub fn move_cursor(&self, window: Window, position: (i32, i32)) {
|
||||||
unsafe {
|
unsafe {
|
||||||
XWarpPointer(self.dpy(), 0, window, 0, 0, 0, 0, position.0, position.1);
|
XWarpPointer(self.dpy(), 0, window, 0, 0, 0, 0, position.0, position.1);
|
||||||
|
|
Loading…
Reference in a new issue