diff --git a/Cargo.lock b/Cargo.lock index 9eddc1de..cb18985f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -19,15 +19,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.53" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ "clap_builder", "clap_derive", @@ -64,9 +64,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" dependencies = [ "anstream", "anstyle", @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck", "proc-macro2", @@ -88,15 +88,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "equivalent" @@ -106,9 +106,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -118,9 +118,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.12.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", @@ -134,26 +134,32 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libmars" version = "0.6.2" dependencies = [ "serde", - "serde_norway", "x11", "xdg", + "yaml_serde", ] +[[package]] +name = "libyaml-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e126dda6f34391ab7b444f9922055facc83c07a910da3eb16f1e4d9c45dc777" + [[package]] name = "mars-relay" version = "0.6.2" @@ -191,39 +197,39 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] [[package]] name = "ryu" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -231,37 +237,24 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "serde_norway" -version = "0.9.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e408f29489b5fd500fab51ff1484fc859bb655f32c671f307dcd733b72e8168c" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml-norway", -] - [[package]] name = "strsim" version = "0.11.1" @@ -270,9 +263,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.111" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -281,15 +274,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unsafe-libyaml-norway" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39abd59bf32521c7f2301b52d05a6a2c975b6003521cbd0c6dc1582f0a22104" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "utf8parse" @@ -327,3 +314,16 @@ name = "xdg" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" + +[[package]] +name = "yaml_serde" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b729a08a9a6be689bbad3e2bf8015926db54b6622cc89c3a5f7dc174b9e918" +dependencies = [ + "indexmap", + "itoa", + "libyaml-rs", + "ryu", + "serde", +] diff --git a/Cargo.toml b/Cargo.toml index a2bc2ec2..1fb5446f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,10 @@ license-file = "LICENSE" readme = "README.md" [workspace.dependencies] -clap = { version = "4.5.23", features = ["derive"] } +clap = { version = "4.6.6", features = ["derive"] } libmars = { path = "./libmars", version = "0.6.1" } -serde = { version = "1.0.216", features = ["derive"] } -serde_norway = { version = "0.9.41" } +serde = { version = "1.0.229", features = ["derive"] } +yaml_serde = { version = "0.10.7" } x11 = { version = "2.21.0", features = ["xlib"] } diff --git a/libmars/Cargo.toml b/libmars/Cargo.toml index 1aadd2b9..f64b2338 100644 --- a/libmars/Cargo.toml +++ b/libmars/Cargo.toml @@ -13,11 +13,11 @@ readme.workspace = true [dependencies] serde = { workspace = true, features = ["derive"], optional = true } -serde_norway = { workspace = true, optional = true } +yaml_serde = { workspace = true, optional = true } x11 = { workspace = true, features = ["xinerama", "xrandr", "xft"] } xdg = { version = "3.0.0", optional = true } [features] -configuration = ["dep:serde", "dep:serde_norway", "dep:xdg"] +configuration = ["dep:serde", "dep:yaml_serde", "dep:xdg"] xlib = [] # TODO implement configuration option diff --git a/libmars/src/common/error.rs b/libmars/src/common/error.rs index 75d96c46..7adc9aa0 100644 --- a/libmars/src/common/error.rs +++ b/libmars/src/common/error.rs @@ -5,13 +5,13 @@ use crate::platforms::x11::misc::atoms::X11Atom; pub type Result = CoreResult; -#[derive(Debug,Clone)] +#[derive(Debug, Clone)] pub struct MarsError { kind: MarsErrorKind, info: Option, } -#[derive(Debug,Copy,Clone)] +#[derive(Debug, Copy, Clone)] pub enum MarsErrorKind { ConnectionFailed, FailedRequest, @@ -22,7 +22,6 @@ pub enum MarsErrorKind { UnsupportedProtocol, } - impl MarsError { pub fn failed_request(call: &str) -> MarsError { MarsError { @@ -34,7 +33,10 @@ impl MarsError { pub fn failed_conversion(value: impl std::fmt::Debug, from: &str, to: &str) -> MarsError { MarsError { kind: MarsErrorKind::IllegalValue, - info: Some(format!("unable to convert {:?} from {} to {}", value, from, to)), + info: Some(format!( + "unable to convert {:?} from {} to {}", + value, from, to + )), } } @@ -81,7 +83,6 @@ impl MarsError { } } - impl Display for MarsError { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { self.kind.fmt(f)?; @@ -112,5 +113,3 @@ impl Display for MarsErrorKind { write!(f, "{}", name) } } - - diff --git a/libmars/src/common/mod.rs b/libmars/src/common/mod.rs index 5c7b5b7d..e1e3b8ad 100644 --- a/libmars/src/common/mod.rs +++ b/libmars/src/common/mod.rs @@ -1,9 +1,7 @@ use std::cmp; - pub mod error; - pub trait Dimensioned { /// Get x coordinate fn x(&self) -> i32; @@ -66,8 +64,7 @@ pub trait Dimensioned { } } - -#[derive(Copy,Clone,PartialEq,Eq,Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Dimensions { x: i32, y: i32, @@ -75,17 +72,16 @@ pub struct Dimensions { h: u32, } -#[derive(Clone,PartialEq,Debug)] +#[derive(Clone, PartialEq, Debug)] pub struct MonitorConfig { name: String, dims: Dimensions, win_area: Dimensions, } - impl Dimensions { pub fn new(x: i32, y: i32, w: u32, h: u32) -> Dimensions { - Dimensions {x, y, w, h} + Dimensions { x, y, w, h } } pub fn as_tuple(&self) -> (i32, i32, u32, u32) { @@ -95,16 +91,25 @@ impl Dimensions { impl MonitorConfig { pub fn new(name: String, dimensions: Dimensions, win_area: Dimensions) -> MonitorConfig { - MonitorConfig { name, dims: dimensions, win_area } + MonitorConfig { + name, + dims: dimensions, + win_area, + } } pub fn add_inset_top(&mut self, inset: u32) { - self.win_area.set_y(cmp::max(self.win_area.y(), self.win_area.y() + inset as i32)); - self.win_area.set_h(cmp::min(self.win_area.h(), self.win_area.h() - inset)); + self.win_area.set_y(cmp::max( + self.win_area.y(), + self.win_area.y() + inset as i32, + )); + self.win_area + .set_h(cmp::min(self.win_area.h(), self.win_area.h() - inset)); } pub fn add_inset_bottom(&mut self, inset: u32) { - self.win_area.set_h(cmp::min(self.win_area.h(), self.win_area.h() - inset)); + self.win_area + .set_h(cmp::min(self.win_area.h(), self.win_area.h() - inset)); } pub fn contains_point(&self, point: (i32, i32)) -> bool { @@ -129,18 +134,43 @@ impl MonitorConfig { } impl Dimensioned for Dimensions { - fn x(&self) -> i32 { self.x } - fn y(&self) -> i32 { self.y } - fn w(&self) -> u32 { self.w } - fn h(&self) -> u32 { self.h } - fn pos(&self) -> (i32, i32) { (self.x, self.y) } - fn size(&self) -> (u32, u32) { (self.w, self.h) } - fn set_x(&mut self, x: i32) { self.x = x; } - fn set_y(&mut self, y: i32) { self.y = y; } - fn set_w(&mut self, w: u32) { self.w = w; } - fn set_h(&mut self, h: u32) { self.h = h; } - fn set_pos(&mut self, pos: (i32, i32)) { (self.x, self.y) = pos; } - fn set_size(&mut self, size: (u32, u32)) { (self.w, self.h) = size; } - fn dimensions(&self) -> Dimensions { *self } + fn x(&self) -> i32 { + self.x + } + fn y(&self) -> i32 { + self.y + } + fn w(&self) -> u32 { + self.w + } + fn h(&self) -> u32 { + self.h + } + fn pos(&self) -> (i32, i32) { + (self.x, self.y) + } + fn size(&self) -> (u32, u32) { + (self.w, self.h) + } + fn set_x(&mut self, x: i32) { + self.x = x; + } + fn set_y(&mut self, y: i32) { + self.y = y; + } + fn set_w(&mut self, w: u32) { + self.w = w; + } + fn set_h(&mut self, h: u32) { + self.h = h; + } + fn set_pos(&mut self, pos: (i32, i32)) { + (self.x, self.y) = pos; + } + fn set_size(&mut self, size: (u32, u32)) { + (self.w, self.h) = size; + } + fn dimensions(&self) -> Dimensions { + *self + } } - diff --git a/libmars/src/interfaces/control.rs b/libmars/src/interfaces/control.rs index 3060be3f..c94e09c9 100644 --- a/libmars/src/interfaces/control.rs +++ b/libmars/src/interfaces/control.rs @@ -2,9 +2,10 @@ use crate::common::error::*; - pub enum SettingMode { - Set, Unset, Toggle + Set, + Unset, + Toggle, } pub trait WMController { diff --git a/libmars/src/interfaces/draw.rs b/libmars/src/interfaces/draw.rs index 6d899416..10fa7702 100644 --- a/libmars/src/interfaces/draw.rs +++ b/libmars/src/interfaces/draw.rs @@ -1,15 +1,23 @@ //! A very basic toolkit for creating simple applications and drawing on windows. //! //! Currently only X11 is supported. -use crate::common::*; use crate::common::error::*; +use crate::common::*; pub trait Canvas { fn dimensions(&self) -> Dimensions; fn draw_line(&mut self, pt1: (i32, i32), pt2: (i32, i32)); fn draw_line_with(&mut self, pt1: (i32, i32), pt2: (i32, i32), color: u64, line_width: u32); fn draw_rectangle(&mut self, x: i32, y: i32, width: u32, height: u32); - fn draw_rectangle_with(&mut self, x: i32, y: i32, width: u32, height: u32, color: u64, line_width: u32); + fn draw_rectangle_with( + &mut self, + x: i32, + y: i32, + width: u32, + height: u32, + color: u64, + line_width: u32, + ); fn draw_text(&mut self, x: i32, y: i32, height: u32, text: &str) -> Result<(u32, u32)>; fn fill_rectangle(&mut self, x: i32, y: i32, width: u32, height: u32); fn fill_rectangle_with(&mut self, x: i32, y: i32, width: u32, height: u32, color: u64); @@ -21,4 +29,3 @@ pub trait Canvas { fn set_line_width(&mut self, line_width: u32); fn text_size(&self, text: &str) -> Result<(u32, u32)>; } - diff --git a/libmars/src/interfaces/wm.rs b/libmars/src/interfaces/wm.rs index 3224db4f..f862c32d 100644 --- a/libmars/src/interfaces/wm.rs +++ b/libmars/src/interfaces/wm.rs @@ -3,8 +3,8 @@ use std::cell::RefCell; use std::rc::Rc; -use crate::common::*; use crate::common::error::*; +use crate::common::*; pub trait WindowManager, A> { fn active_client(&self) -> Option>>; @@ -14,15 +14,59 @@ pub trait WindowManager, A> { fn client_switches_monitor(&mut self, client_rc: Rc>, monitor: u32); fn clients(&self) -> Box>> + '_>; fn focus_client(&mut self, backend: &mut B, client_option: Option>>); - fn fullscreen_client(&mut self, backend: &mut B, client_rc: Rc>, state: bool); - fn handle_button(&mut self, backend: &mut B, modifiers: u32, button: u32, target: ButtonTarget, - client_option: Option>>); - fn handle_key(&mut self, backend: &mut B, modifiers: u32, key: u32, client_option: Option>>); - fn manage(&mut self, backend: &mut B, client_rc: Rc>, workspace_preference: Option); - fn move_request(&mut self, backend: &mut B, client_rc: Rc>, x: i32, y: i32) -> bool; - fn move_to_workspace(&mut self, backend: &mut B, client_rc: Rc>, workspace_idx: u32); - fn resize_request(&mut self, backend: &mut B, client_rc: Rc>, width: u32, height: u32) -> bool; - fn set_client_pinned(&mut self, backend: &mut B, client_rc: Rc>, state: bool); + fn fullscreen_client( + &mut self, + backend: &mut B, + client_rc: Rc>, + state: bool, + ); + fn handle_button( + &mut self, + backend: &mut B, + modifiers: u32, + button: u32, + target: ButtonTarget, + client_option: Option>>, + ); + fn handle_key( + &mut self, + backend: &mut B, + modifiers: u32, + key: u32, + client_option: Option>>, + ); + fn manage( + &mut self, + backend: &mut B, + client_rc: Rc>, + workspace_preference: Option, + ); + fn move_request( + &mut self, + backend: &mut B, + client_rc: Rc>, + x: i32, + y: i32, + ) -> bool; + fn move_to_workspace( + &mut self, + backend: &mut B, + client_rc: Rc>, + workspace_idx: u32, + ); + fn resize_request( + &mut self, + backend: &mut B, + client_rc: Rc>, + width: u32, + height: u32, + ) -> bool; + fn set_client_pinned( + &mut self, + backend: &mut B, + client_rc: Rc>, + state: bool, + ); fn switch_workspace(&mut self, backend: &mut B, workspace_idx: u32); fn tile_client(&mut self, backend: &mut B, client_rc: Rc>, state: bool); fn toggle_fullscreen_client(&mut self, backend: &mut B, client_rc: Rc>); @@ -75,7 +119,8 @@ pub trait Client: Eq + Dimensioned { fn warp_pointer_to_corner(&self); } -pub type MouseActionFn = fn(&mut B, &mut WM, &Rc>, (i32, i32), (u32, u32), (i32, i32)); +pub type MouseActionFn = + fn(&mut B, &mut WM, &Rc>, (i32, i32), (u32, u32), (i32, i32)); pub trait Backend { /// Associated client type @@ -85,7 +130,11 @@ pub trait Backend { fn export_active_window(&self, client_option: &Option>>); /// Make client list information available to clients - fn export_client_list(&self, clients: Vec<&Rc>>, clients_stacked: Vec<&Rc>>); + fn export_client_list( + &self, + clients: Vec<&Rc>>, + clients_stacked: Vec<&Rc>>, + ); /// Make currently active workspace available to clients fn export_current_workspace(&self, workspace_idx: u32); @@ -99,16 +148,28 @@ pub trait Backend { /// Handle windows existing before initialization fn handle_existing_windows(&mut self, wm: &mut dyn WindowManager); - fn mouse_action + ?Sized>(&mut self, wm: &mut WM, - client_rc: Rc>, cursor_type: u32, - action: MouseActionFn) - where Self: Sized; + fn mouse_action + ?Sized>( + &mut self, + wm: &mut WM, + client_rc: Rc>, + cursor_type: u32, + action: MouseActionFn, + ) where + Self: Sized; /// Move client with mouse - fn mouse_move(&mut self, wm: &mut dyn WindowManager, client_rc: Rc>); + fn mouse_move( + &mut self, + wm: &mut dyn WindowManager, + client_rc: Rc>, + ); /// Resize client with mouse - fn mouse_resize(&mut self, wm: &mut dyn WindowManager, client_rc: Rc>); + fn mouse_resize( + &mut self, + wm: &mut dyn WindowManager, + client_rc: Rc>, + ); fn point_to_monitor(&self, point: (i32, i32)) -> Option; @@ -126,9 +187,11 @@ pub trait Backend { fn shutdown(&mut self); } - -#[derive(Clone,Copy,PartialEq,Eq,Debug)] -#[cfg_attr(feature = "configuration", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr( + feature = "configuration", + derive(serde::Serialize, serde::Deserialize) +)] #[cfg_attr(feature = "configuration", serde(rename_all = "kebab-case"))] pub enum ButtonTarget { Window, diff --git a/libmars/src/lib.rs b/libmars/src/lib.rs index bba7ef89..b6d94d10 100644 --- a/libmars/src/lib.rs +++ b/libmars/src/lib.rs @@ -1,5 +1,5 @@ #![allow(clippy::not_unsafe_ptr_arg_deref)] pub mod common; -pub mod utils; pub mod interfaces; pub mod platforms; +pub mod utils; diff --git a/libmars/src/platforms/x11/control.rs b/libmars/src/platforms/x11/control.rs index 5c66b603..f5793a57 100644 --- a/libmars/src/platforms/x11/control.rs +++ b/libmars/src/platforms/x11/control.rs @@ -1,20 +1,17 @@ extern crate x11; -use std::ptr; use std::ffi::*; +use std::ptr; use x11::xlib::{self, XDefaultRootWindow}; use crate::common::error::*; use crate::interfaces::control::*; use crate::platforms::x11::misc::{ - atoms::X11Atom, - atoms::X11Atom::*, - send_client_message, - window::X11Window, + atoms::X11Atom, atoms::X11Atom::*, send_client_message, window::X11Window, }; - -pub type EventHandlerFn = Option c_int>; +pub type EventHandlerFn = + Option c_int>; pub struct X11Controller { display: *mut xlib::Display, @@ -22,12 +19,16 @@ pub struct X11Controller { event_handler: EventHandlerFn, } - impl X11Controller { - pub fn new_from_display(display: *mut xlib::Display, event_handler: EventHandlerFn) -> X11Controller { + pub fn new_from_display( + display: *mut xlib::Display, + event_handler: EventHandlerFn, + ) -> X11Controller { let root = unsafe { XDefaultRootWindow(display) }; X11Controller { - display, root, event_handler, + display, + root, + event_handler, } } @@ -42,7 +43,6 @@ impl X11Controller { } } - impl WMController for X11Controller { fn activate_window(&self, window: xlib::Window) -> Result<()> { require_ewmh_atom(self.display, NetActiveWindow)?; @@ -71,21 +71,29 @@ impl WMController for X11Controller { fn count_workspaces(&self) -> Result { require_ewmh_atom(self.display, NetNumberOfDesktops)?; - let data = self.root.x11_read_property_long(self.display, NetNumberOfDesktops, xlib::XA_CARDINAL) + let data = self + .root + .x11_read_property_long(self.display, NetNumberOfDesktops, xlib::XA_CARDINAL) .map_err(MarsError::unknown)?; - let ws_u64 = data.first() - .ok_or(MarsError::invalid_response("reading property _NET_NUMBER_OF_DESKTOPS"))?; - (*ws_u64).try_into() + let ws_u64 = data.first().ok_or(MarsError::invalid_response( + "reading property _NET_NUMBER_OF_DESKTOPS", + ))?; + (*ws_u64) + .try_into() .map_err(|_| MarsError::failed_conversion(ws_u64, stringify!(u64), stringify!(u32))) } fn current_workspace(&self) -> Result { require_ewmh_atom(self.display, NetCurrentDesktop)?; - let data = self.root.x11_read_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL) + let data = self + .root + .x11_read_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL) .map_err(MarsError::unknown)?; - let ws_u64 = data.first() - .ok_or(MarsError::invalid_response("reading property _NET_CURRENT_DESKTOP"))?; - (*ws_u64).try_into() + let ws_u64 = data.first().ok_or(MarsError::invalid_response( + "reading property _NET_CURRENT_DESKTOP", + ))?; + (*ws_u64) + .try_into() .map_err(|_| MarsError::failed_conversion(ws_u64, stringify!(u64), stringify!(u32))) } @@ -101,21 +109,27 @@ impl WMController for X11Controller { fn get_active_window(&self) -> Result { require_ewmh_atom(self.display, NetActiveWindow)?; - let data = self.root.x11_read_property_long(self.display, NetActiveWindow, xlib::XA_WINDOW) - .map_err(MarsError::unknown)?; - data.first().copied() - .ok_or(MarsError::invalid_response("reading property _NET_ACTIVE_WINDOW")) + let data = self + .root + .x11_read_property_long(self.display, NetActiveWindow, xlib::XA_WINDOW) + .map_err(MarsError::unknown)?; + data.first().copied().ok_or(MarsError::invalid_response( + "reading property _NET_ACTIVE_WINDOW", + )) } fn get_workspace(&self, window: xlib::Window) -> Result { require_ewmh_atom(self.display, NetWMDesktop)?; if self.window_is_pinned(window)? { - let data = window.x11_read_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL) + let data = window + .x11_read_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL) .map_err(MarsError::unknown)?; - let ws_u64 = data.first() - .ok_or(MarsError::invalid_response("reading property _NET_WM_DESKTOP"))?; - (*ws_u64).try_into() + let ws_u64 = data.first().ok_or(MarsError::invalid_response( + "reading property _NET_WM_DESKTOP", + ))?; + (*ws_u64) + .try_into() .map_err(|_| MarsError::failed_conversion(ws_u64, stringify!(u64), stringify!(u32))) } else { self.current_workspace() @@ -129,11 +143,11 @@ impl WMController for X11Controller { let mut data = xlib::ClientMessageData::new(); data.set_long(0, -1); send_client_message(self.display, NetWMDesktop, window, data); - }, + } SettingMode::Unset => { let current_workspace = self.current_workspace()?; self.send_window_to_workspace(window, current_workspace)?; - }, + } SettingMode::Toggle => { if self.window_is_pinned(window)? { return self.pin_window(window, SettingMode::Unset); @@ -155,9 +169,12 @@ impl WMController for X11Controller { } fn set_status(&self, status: String) -> Result<()> { - let data = vec!(status); - self.root.x11_set_text_list_property(self.display, MarsStatus, &data); - unsafe { xlib::XFlush(self.display); } + let data = vec![status]; + self.root + .x11_set_text_list_property(self.display, MarsStatus, &data); + unsafe { + xlib::XFlush(self.display); + } Ok(()) } @@ -181,7 +198,8 @@ impl WMController for X11Controller { fn window_is_fullscreen(&self, window: xlib::Window) -> Result { require_ewmh_atom(self.display, NetWMState)?; - let is_fullscreen = window.x11_net_wm_state(self.display) + let is_fullscreen = window + .x11_net_wm_state(self.display) .map_err(MarsError::unknown)? .contains(&NetWMStateFullscreen); Ok(is_fullscreen) @@ -189,16 +207,19 @@ impl WMController for X11Controller { fn window_is_pinned(&self, window: xlib::Window) -> Result { require_ewmh_atom(self.display, NetWMDesktop)?; - let data = window.x11_read_property_long(self.display, NetWMDesktop, xlib::XA_CARDINAL) + let data = window + .x11_read_property_long(self.display, NetWMDesktop, xlib::XA_CARDINAL) .map_err(MarsError::unknown)?; - let ws_u64 = data.first() - .ok_or(MarsError::invalid_response("reading property _NET_WM_DESKTOP"))?; + let ws_u64 = data.first().ok_or(MarsError::invalid_response( + "reading property _NET_WM_DESKTOP", + ))?; Ok(*ws_u64 == u64::MAX) } fn window_is_tiled(&self, window: xlib::Window) -> Result { require_ewmh_atom(self.display, NetWMState)?; - let is_fullscreen = window.x11_net_wm_state(self.display) + let is_fullscreen = window + .x11_net_wm_state(self.display) .map_err(MarsError::unknown)? .contains(&MarsWMStateTiled); Ok(is_fullscreen) @@ -206,7 +227,8 @@ impl WMController for X11Controller { fn workspaces(&self) -> Result> { require_ewmh_atom(self.display, NetDesktopNames)?; - self.root.x11_get_text_list_property(self.display, NetDesktopNames) + self.root + .x11_get_text_list_property(self.display, NetDesktopNames) .map_err(MarsError::unknown) } } @@ -222,11 +244,10 @@ impl From for i64 { } fn require_ewmh_atom(display: *mut xlib::Display, atom: X11Atom) -> Result<()> { - let root = unsafe { - xlib::XDefaultRootWindow(display) - }; + let root = unsafe { xlib::XDefaultRootWindow(display) }; let xatom = atom.to_xlib_atom(display); - let supported = root.x11_read_property_long(display, NetSupported, xlib::XA_ATOM) + let supported = root + .x11_read_property_long(display, NetSupported, xlib::XA_ATOM) .map_err(|_| MarsError::x11_unsupported_atom(NetSupported))?; if supported.contains(&xatom) { diff --git a/libmars/src/platforms/x11/draw/canvas.rs b/libmars/src/platforms/x11/draw/canvas.rs index 1ccb9998..741f08f4 100644 --- a/libmars/src/platforms/x11/draw/canvas.rs +++ b/libmars/src/platforms/x11/draw/canvas.rs @@ -8,8 +8,8 @@ use x11::xft; use x11::xlib; use x11::xrender; -use crate::common::*; use crate::common::error::*; +use crate::common::*; use crate::interfaces::draw::*; use crate::platforms::x11::misc::window::*; @@ -33,21 +33,30 @@ pub struct X11Canvas { style: CanvasStyle, } - impl X11Canvas { pub fn new_for_window(display: *mut xlib::Display, window: xlib::Window) -> Result { let screen = unsafe { xlib::XDefaultScreen(display) }; let style = CanvasStyle::default(); let pixbuffer = Self::create_pixmap(display, screen, window)?; - let gc = Self::create_default_gc(display, window, false) - .inspect_err(|_| unsafe { xlib::XFreePixmap(display, pixbuffer); })?; - - Ok( X11Canvas { - display, screen, window, pixbuffer, gc, style, - } ) + let gc = Self::create_default_gc(display, window, false).inspect_err(|_| unsafe { + xlib::XFreePixmap(display, pixbuffer); + })?; + + Ok(X11Canvas { + display, + screen, + window, + pixbuffer, + gc, + style, + }) } - fn create_default_gc(display: *mut xlib::Display, window: xlib::Window, reverse_video: bool) -> Result { + fn create_default_gc( + display: *mut xlib::Display, + window: xlib::Window, + reverse_video: bool, + ) -> Result { let style = CanvasStyle::default(); unsafe { let screen = xlib::XDefaultScreen(display); @@ -69,19 +78,36 @@ impl X11Canvas { } // set drawing style - xlib::XSetLineAttributes(display, gc, style.line_width, style.line_style, style.cap_style, style.join_style); + xlib::XSetLineAttributes( + display, + gc, + style.line_width, + style.line_style, + style.cap_style, + style.join_style, + ); xlib::XSetFillStyle(display, gc, style.fill_style); Ok(gc) } } - fn create_pixmap(display: *mut xlib::Display, screen: i32, window: xlib::Window) -> Result { + fn create_pixmap( + display: *mut xlib::Display, + screen: i32, + window: xlib::Window, + ) -> Result { unsafe { let window_dims = window.x11_dimensions(display)?; let depth = xlib::XDefaultDepth(display, screen); let root = xlib::XDefaultRootWindow(display); - Ok(xlib::XCreatePixmap(display, root, window_dims.w(), window_dims.h(), depth as u32)) + Ok(xlib::XCreatePixmap( + display, + root, + window_dims.w(), + window_dims.h(), + depth as u32, + )) } } @@ -91,8 +117,7 @@ impl X11Canvas { unsafe { xlib::XNextEvent(display, event.as_mut_ptr()); let event = event.assume_init(); - if event.get_type() == xlib::Expose - && event.expose.window == self.window() { + if event.get_type() == xlib::Expose && event.expose.window == self.window() { draw(self); self.flush(); } @@ -108,8 +133,14 @@ impl X11Canvas { fn gc_apply_line_attrib(&self) { unsafe { - xlib::XSetLineAttributes(self.display, self.gc, self.style.line_width, - self.style.line_style, self.style.cap_style, self.style.join_style); + xlib::XSetLineAttributes( + self.display, + self.gc, + self.style.line_width, + self.style.line_style, + self.style.cap_style, + self.style.join_style, + ); } } @@ -128,8 +159,17 @@ impl X11Canvas { unsafe { let visual = xlib::XDefaultVisual(self.display, self.screen); let colormap = xlib::XDefaultColormap(self.display, self.screen); - if xft::XftColorAllocValue(self.display, visual, colormap, &xr_color, xft_color.as_mut_ptr()) == 0 { - Err(MarsError::failed_request(stringify!(xft::XftColorAllocValue))) + if xft::XftColorAllocValue( + self.display, + visual, + colormap, + &xr_color, + xft_color.as_mut_ptr(), + ) == 0 + { + Err(MarsError::failed_request(stringify!( + xft::XftColorAllocValue + ))) } else { Ok(xft_color.assume_init()) } @@ -148,8 +188,15 @@ impl Canvas for X11Canvas { fn draw_line(&mut self, pt1: (i32, i32), pt2: (i32, i32)) { unsafe { - xlib::XDrawLine(self.display, self.pixbuffer, self.gc, - pt1.0, pt1.1, pt2.0, pt2.1); + xlib::XDrawLine( + self.display, + self.pixbuffer, + self.gc, + pt1.0, + pt1.1, + pt2.0, + pt2.1, + ); } } @@ -178,12 +225,19 @@ impl Canvas for X11Canvas { fn draw_rectangle(&mut self, x: i32, y: i32, width: u32, height: u32) { unsafe { - xlib::XDrawRectangle(self.display, self.pixbuffer, self.gc, - x, y, width, height); + xlib::XDrawRectangle(self.display, self.pixbuffer, self.gc, x, y, width, height); } } - fn draw_rectangle_with(&mut self, x: i32, y: i32, width: u32, height: u32, color: u64, line_width: u32) { + fn draw_rectangle_with( + &mut self, + x: i32, + y: i32, + width: u32, + height: u32, + color: u64, + line_width: u32, + ) { if let Ok(xft_color) = self.alloc_color(color) { let saved_color = self.style.xft_color; let saved_line_width = self.style.line_width; @@ -210,19 +264,33 @@ impl Canvas for X11Canvas { if let Some(xfont) = self.style.xfont { let strlen = match text.len().try_into() { Ok(i) => i, - Err(_) => return Err(MarsError::failed_conversion(text.len(), stringify!(usize), stringify!(i32))), + Err(_) => { + return Err(MarsError::failed_conversion( + text.len(), + stringify!(usize), + stringify!(i32), + )); + } }; unsafe { let mut extents: MaybeUninit = MaybeUninit::uninit(); - xft::XftTextExtentsUtf8(self.display, xfont, text.as_ptr(), strlen, extents.as_mut_ptr()); + xft::XftTextExtentsUtf8( + self.display, + xfont, + text.as_ptr(), + strlen, + extents.as_mut_ptr(), + ); let extents = extents.assume_init(); let height = (*xfont).ascent + (*xfont).descent; Ok((extents.width.into(), height as u32)) } } else { - Err(MarsError::invalid_input("unable to get text size - no font specified")) + Err(MarsError::invalid_input( + "unable to get text size - no font specified", + )) } } @@ -234,7 +302,13 @@ impl Canvas for X11Canvas { // make string length c compatible let strlen = match text.len().try_into() { Ok(i) => i, - Err(_) => return Err(MarsError::failed_conversion(text.len(), stringify!(usize), stringify!(i32))), + Err(_) => { + return Err(MarsError::failed_conversion( + text.len(), + stringify!(usize), + stringify!(i32), + )); + } }; // get font dimensions @@ -249,8 +323,15 @@ impl Canvas for X11Canvas { let colormap = xlib::XDefaultColormap(self.display, self.screen); let xft_draw = xft::XftDrawCreate(self.display, self.pixbuffer, visual, colormap); - xft::XftDrawStringUtf8(xft_draw, (&self.style.xft_color) as *const xft::XftColor, - font, x, y, text.as_ptr(), strlen); + xft::XftDrawStringUtf8( + xft_draw, + (&self.style.xft_color) as *const xft::XftColor, + font, + x, + y, + text.as_ptr(), + strlen, + ); xft::XftDrawDestroy(xft_draw); } @@ -260,8 +341,7 @@ impl Canvas for X11Canvas { fn fill_rectangle(&mut self, x: i32, y: i32, width: u32, height: u32) { unsafe { - xlib::XFillRectangle(self.display, self.pixbuffer, self.gc, - x, y, width, height); + xlib::XFillRectangle(self.display, self.pixbuffer, self.gc, x, y, width, height); } } @@ -286,7 +366,18 @@ impl Canvas for X11Canvas { fn flush(&self) { unsafe { if let Ok(d) = self.window.x11_dimensions(self.display) { - xlib::XCopyArea(self.display, self.pixbuffer, self.window, self.gc, 0, 0, d.w(), d.h(), 0, 0); + xlib::XCopyArea( + self.display, + self.pixbuffer, + self.window, + self.gc, + 0, + 0, + d.w(), + d.h(), + 0, + 0, + ); } xlib::XFlush(self.display); } @@ -307,7 +398,7 @@ impl Canvas for X11Canvas { // set background for associated window let mut swa: xlib::XSetWindowAttributes = MaybeUninit::zeroed().assume_init(); swa.background_pixel = color; - xlib::XChangeWindowAttributes(self.display, self.window, xlib::CWBackPixel, &mut swa); + xlib::XChangeWindowAttributes(self.display, self.window, xlib::CWBackPixel, &mut swa); // set background for gc xlib::XSetBackground(self.display, self.gc, xft_color.pixel); @@ -323,8 +414,9 @@ impl Canvas for X11Canvas { } // allocate font - let c_font_name = CString::new(font_name) - .map_err(|_| MarsError::failed_conversion(font_name, stringify!(&str), stringify!(CString)))?; + let c_font_name = CString::new(font_name).map_err(|_| { + MarsError::failed_conversion(font_name, stringify!(&str), stringify!(CString)) + })?; let xfont = xft::XftFontOpenName(self.display, self.screen, c_font_name.as_ptr()); if xfont.is_null() { return Err(MarsError::failed_request(stringify!(xft::XftFontOpenName))); diff --git a/libmars/src/platforms/x11/draw/widget.rs b/libmars/src/platforms/x11/draw/widget.rs index 864bf393..fba7b5b1 100644 --- a/libmars/src/platforms/x11/draw/widget.rs +++ b/libmars/src/platforms/x11/draw/widget.rs @@ -3,17 +3,15 @@ extern crate x11; use std::cmp; use x11::xlib; -use crate::common::*; use crate::common::error::*; -use crate::platforms::x11::misc::window::*; +use crate::common::*; use crate::interfaces::draw::*; use crate::platforms::x11::draw::canvas::X11Canvas; - +use crate::platforms::x11::misc::window::*; pub const MIN_SIZE: (u32, u32) = (10, 10); pub const MAX_SIZE: (u32, u32) = (u32::MAX, u32::MAX); - pub trait WidgetEventHandler { fn handle_action_event(&self, event: WidgetEvent, already_handled: bool) -> bool; } @@ -29,13 +27,13 @@ pub trait Widget { fn wid(&self) -> xlib::Window; } -#[derive(Copy,Clone,Debug)] +#[derive(Copy, Clone, Debug)] pub enum WidgetEvent { ButtonPressed(u32), Redraw(), } -#[derive(Copy,Clone,Debug)] +#[derive(Copy, Clone, Debug)] pub struct X11WidgetParams { x: i32, y: i32, @@ -75,23 +73,35 @@ pub struct X11TextWidget { } impl X11FlowLayoutWidget { - pub fn new(display: *mut xlib::Display, parent: xlib::Window, params: X11WidgetParams, ipad: u32, - children: Vec, bg_color: u64) -> Result> { + pub fn new( + display: *mut xlib::Display, + parent: xlib::Window, + params: X11WidgetParams, + ipad: u32, + children: Vec, + bg_color: u64, + ) -> Result> { let outer_dimensions = Dimensions::new(params.x, params.y, MIN_SIZE.0, MIN_SIZE.1); let window = create_widget_window(display, parent, outer_dimensions)?; - let mut canvas = X11Canvas::new_for_window(display, window) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; + let mut canvas = X11Canvas::new_for_window(display, window).inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; - canvas.set_foreground(bg_color) + canvas + .set_foreground(bg_color) .and(canvas.set_background(bg_color)) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; + .inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; let mut widget = X11FlowLayoutWidget { display, children, - window, canvas, + window, + canvas, event_handlers: Vec::new(), - width: MIN_SIZE.0, height: MIN_SIZE.1, + width: MIN_SIZE.0, + height: MIN_SIZE.1, min_size: MIN_SIZE, max_size: MAX_SIZE, hpad: params.hpad, @@ -177,30 +187,43 @@ impl X11FlowLayoutWidget { } impl X11TextWidget { - pub fn new(display: *mut xlib::Display, parent: xlib::Window, params: X11WidgetParams, - label: String, font: &str, fg_color: u64, bg_color: u64) -> Result { - + pub fn new( + display: *mut xlib::Display, + parent: xlib::Window, + params: X11WidgetParams, + label: String, + font: &str, + fg_color: u64, + bg_color: u64, + ) -> Result { let outer_dimensions = Dimensions::new(params.x, params.y, MIN_SIZE.0, MIN_SIZE.1); let window = create_widget_window(display, parent, outer_dimensions)?; - let mut canvas = X11Canvas::new_for_window(display, window) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; + let mut canvas = X11Canvas::new_for_window(display, window).inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; - canvas.set_foreground(fg_color) + canvas + .set_foreground(fg_color) .and(canvas.set_background(bg_color)) .and(canvas.set_font(font)) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; + .inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; let mut widget = X11TextWidget { display, label, - window, canvas, + window, + canvas, event_handlers: Vec::new(), - width: MIN_SIZE.0, height: MIN_SIZE.1, + width: MIN_SIZE.0, + height: MIN_SIZE.1, min_size: MIN_SIZE, max_size: MAX_SIZE, hpad: params.hpad, vpad: params.vpad, - fg_color, bg_color, + fg_color, + bg_color, }; widget.resize_to_content(); @@ -304,7 +327,7 @@ impl Widget for X11FlowLayoutWidget { xlib::ButtonPress => { let button = event.button.button; Some(WidgetEvent::ButtonPressed(button)) - }, + } xlib::Expose => { self.redraw(); None @@ -313,10 +336,11 @@ impl Widget for X11FlowLayoutWidget { }; if let Some(widget_event) = widget_event { - let _handled = self.event_handlers.iter() - .fold(false, { - |already_handled, handler| handler.handle_action_event(widget_event, already_handled) - }); + let _handled = self.event_handlers.iter().fold(false, { + |already_handled, handler| { + handler.handle_action_event(widget_event, already_handled) + } + }); } true } else { @@ -358,15 +382,26 @@ impl Widget for X11TextWidget { } fn redraw(&mut self) { - self.canvas.fill_rectangle_with(0, 0, self.width, self.height, self.bg_color); + self.canvas + .fill_rectangle_with(0, 0, self.width, self.height, self.bg_color); if let Ok(text_size) = self.canvas.text_size(&self.label) { // center text if possible // the min() call is necessary as the text_size might be bigger than the max size let x = (self.width - cmp::min(self.width, text_size.0)) / 2; - let _ = self.canvas.draw_text(x as i32, self.vpad as i32, self.height - 2*self.vpad, &self.label); + let _ = self.canvas.draw_text( + x as i32, + self.vpad as i32, + self.height - 2 * self.vpad, + &self.label, + ); } else { // otherwise just align to the left - let _ = self.canvas.draw_text(self.hpad as i32, self.vpad as i32, self.height - 2*self.vpad, &self.label); + let _ = self.canvas.draw_text( + self.hpad as i32, + self.vpad as i32, + self.height - 2 * self.vpad, + &self.label, + ); } self.canvas.flush(); } @@ -382,7 +417,7 @@ impl Widget for X11TextWidget { xlib::ButtonPress => { let button = event.button.button; Some(WidgetEvent::ButtonPressed(button)) - }, + } xlib::Expose => { self.redraw(); None @@ -391,10 +426,11 @@ impl Widget for X11TextWidget { }; if let Some(widget_event) = widget_event { - let _handled = self.event_handlers.iter() - .fold(false, { - |already_handled, handler| handler.handle_action_event(widget_event, already_handled) - }); + let _handled = self.event_handlers.iter().fold(false, { + |already_handled, handler| { + handler.handle_action_event(widget_event, already_handled) + } + }); } true } else { @@ -434,15 +470,26 @@ impl Drop for X11TextWidget { } } -pub fn create_widget_window(display: *mut xlib::Display, parent: xlib::Window, dimensions: Dimensions) -> Result { +pub fn create_widget_window( + display: *mut xlib::Display, + parent: xlib::Window, + dimensions: Dimensions, +) -> Result { unsafe { let screen = xlib::XDefaultScreen(display); let border_width = 0; - let win = xlib::XCreateSimpleWindow(display, xlib::XDefaultRootWindow(display), - dimensions.x(), dimensions.y(), dimensions.w(), dimensions.h(), border_width, - xlib::XBlackPixel(display, screen), - xlib::XWhitePixel(display, screen)); + let win = xlib::XCreateSimpleWindow( + display, + xlib::XDefaultRootWindow(display), + dimensions.x(), + dimensions.y(), + dimensions.w(), + dimensions.h(), + border_width, + xlib::XBlackPixel(display, screen), + xlib::XWhitePixel(display, screen), + ); // subscribe to StructureNotifyMask for MapNotify events // subscribe to ExposureMask for Expose events @@ -466,7 +513,10 @@ pub fn create_widget_window(display: *mut xlib::Display, parent: xlib::Window, d } } -pub fn distribute_widget_event<'a, I: Iterator>(widgets: &mut I, xevent: xlib::XEvent) { +pub fn distribute_widget_event<'a, I: Iterator>( + widgets: &mut I, + xevent: xlib::XEvent, +) { for widget in widgets { if widget.handle_xevent(xevent) { return; diff --git a/libmars/src/platforms/x11/misc/atoms.rs b/libmars/src/platforms/x11/misc/atoms.rs index cd3b8cee..50d09dd1 100644 --- a/libmars/src/platforms/x11/misc/atoms.rs +++ b/libmars/src/platforms/x11/misc/atoms.rs @@ -1,8 +1,8 @@ extern crate x11; +use std::ffi::*; use std::fmt::{Display, Formatter, Result}; use x11::xlib; -use std::ffi::*; use crate::*; @@ -135,9 +135,7 @@ impl X11Atom { pub fn to_xlib_atom(&self, display: *mut xlib::Display) -> xlib::Atom { let atom_name = CString::new(self.to_string()).unwrap().into_raw(); - unsafe { - xlib::XInternAtom(display, atom_name, xlib::False) - } + unsafe { xlib::XInternAtom(display, atom_name, xlib::False) } } } diff --git a/libmars/src/platforms/x11/misc/mod.rs b/libmars/src/platforms/x11/misc/mod.rs index 18b5b5ee..71a4a570 100644 --- a/libmars/src/platforms/x11/misc/mod.rs +++ b/libmars/src/platforms/x11/misc/mod.rs @@ -11,16 +11,11 @@ use x11::xrandr; use crate::common::error::*; use crate::common::*; -use crate::platforms::x11::misc::{ - atoms::*, - atoms::X11Atom::*, - window::*, -}; +use crate::platforms::x11::misc::{atoms::X11Atom::*, atoms::*, window::*}; pub mod atoms; pub mod window; - pub const XLIB_NONE: u64 = 0; pub const BUTTONMASK: i64 = xlib::ButtonPressMask | xlib::ButtonReleaseMask; pub const MOUSEMASK: i64 = BUTTONMASK | xlib::PointerMotionMask; @@ -41,12 +36,15 @@ pub const MWM_DECOR_ALL: u64 = 1 << 0; pub const MWM_DECOR_BORDER: u64 = 1 << 1; pub const MWM_DECOR_TITLE: u64 = 1 << 3; - impl From for MonitorConfig { fn from(info: xinerama::XineramaScreenInfo) -> MonitorConfig { - let area = Dimensions::new(info.x_org.into(), info.y_org.into(), - info.width.try_into().unwrap(), info.height.try_into().unwrap()); - MonitorConfig::new( format!("output{}", info.screen_number), area, area) + let area = Dimensions::new( + info.x_org.into(), + info.y_org.into(), + info.width.try_into().unwrap(), + info.height.try_into().unwrap(), + ); + MonitorConfig::new(format!("output{}", info.screen_number), area, area) } } @@ -56,8 +54,12 @@ impl From<(*mut xlib::Display, &xrandr::XRRMonitorInfo)> for MonitorConfig { Some(name) => name, None => format!("monitor{}", monitor_info.noutput), }; - let area = Dimensions::new(monitor_info.x, monitor_info.y, - monitor_info.width as u32, monitor_info.height as u32); + let area = Dimensions::new( + monitor_info.x, + monitor_info.y, + monitor_info.width as u32, + monitor_info.height as u32, + ); MonitorConfig::new(name, area, area) } @@ -73,13 +75,9 @@ impl From<*mut xlib::Screen> for MonitorConfig { } } - /// Returs all permutiations of your modifiers with NumLock and Level3 pub fn alternative_modifiers(modifiers: u32) -> Vec { - vec![ - modifiers, - modifiers | xlib::Mod2Mask, - ] + vec![modifiers, modifiers | xlib::Mod2Mask] } /// Waits for MapNotify on the specified window. @@ -90,8 +88,7 @@ pub fn await_map_notify(display: *mut xlib::Display, window: xlib::Window) { unsafe { xlib::XNextEvent(display, event.as_mut_ptr()); let event = event.assume_init(); - if event.get_type() == xlib::MapNotify - && event.map.window == window { + if event.get_type() == xlib::MapNotify && event.map.window == window { break; } } @@ -108,17 +105,29 @@ pub fn close_display(display: *mut xlib::Display) { } /// Creates and maps a top-level window to be used by an application -pub fn create_window(display: *mut xlib::Display, dimensions: Dimensions, class: &str, name: &str, - win_type: Option) -> Result { +pub fn create_window( + display: *mut xlib::Display, + dimensions: Dimensions, + class: &str, + name: &str, + win_type: Option, +) -> Result { let (x, y, width, height) = dimensions.as_tuple(); unsafe { let screen = xlib::XDefaultScreen(display); let border_width = 0; - let win = xlib::XCreateSimpleWindow(display, xlib::XDefaultRootWindow(display), - x, y, width, height, border_width, - xlib::XBlackPixel(display, screen), - xlib::XWhitePixel(display, screen)); + let win = xlib::XCreateSimpleWindow( + display, + xlib::XDefaultRootWindow(display), + x, + y, + width, + height, + border_width, + xlib::XBlackPixel(display, screen), + xlib::XWhitePixel(display, screen), + ); // subscribe to StructureNotifyMask for MapNotify events // subscribe to ExposureMask for Expose events @@ -127,7 +136,13 @@ pub fn create_window(display: *mut xlib::Display, dimensions: Dimensions, class: // set class hint let class_cstring = match CString::new(class) { Ok(cstring) => cstring, - Err(_) => return Err(MarsError::failed_conversion(class, stringify!(&str), stringify!(CString))), + Err(_) => { + return Err(MarsError::failed_conversion( + class, + stringify!(&str), + stringify!(CString), + )); + } }; let mut class_bytes = class_cstring.into_bytes_with_nul(); let mut class_hint = xlib::XClassHint { @@ -139,13 +154,22 @@ pub fn create_window(display: *mut xlib::Display, dimensions: Dimensions, class: // set window title let name_cstring = match CString::new(name) { Ok(cstring) => cstring, - Err(_) => return Err(MarsError::failed_conversion(name, stringify!(&str), stringify!(CString))), + Err(_) => { + return Err(MarsError::failed_conversion( + name, + stringify!(&str), + stringify!(CString), + )); + } }; let mut name_property: MaybeUninit = MaybeUninit::uninit(); let mut data = [name_cstring.as_ptr() as *mut c_char]; - if xlib::XStringListToTextProperty(data.as_mut_ptr(), - 1, name_property.as_mut_ptr()) == 0 { - return Err(MarsError::failed_conversion(name, stringify!(&str), stringify!(xlib::XTextProperty))); + if xlib::XStringListToTextProperty(data.as_mut_ptr(), 1, name_property.as_mut_ptr()) == 0 { + return Err(MarsError::failed_conversion( + name, + stringify!(&str), + stringify!(xlib::XTextProperty), + )); }; xlib::XSetWMName(display, win, name_property.assume_init_mut()); @@ -187,14 +211,20 @@ pub fn get_keysym(name: &str) -> xlib::KeySym { } } -pub extern "C" fn on_error_dummy(_display: *mut xlib::Display, _error: *mut xlib::XErrorEvent) -> c_int { +pub extern "C" fn on_error_dummy( + _display: *mut xlib::Display, + _error: *mut xlib::XErrorEvent, +) -> c_int { 0 } /// Get the current monitor configuration /// /// * `ignore_overlapping` - Ignore monitors that overlap with other monitors -pub fn query_monitor_config(display: *mut xlib::Display, ignore_overlapping: bool) -> Vec { +pub fn query_monitor_config( + display: *mut xlib::Display, + ignore_overlapping: bool, +) -> Vec { unsafe { let mut monitors = VecDeque::new(); @@ -218,14 +248,15 @@ pub fn query_monitor_config(display: *mut xlib::Display, ignore_overlapping: boo if monitors.is_empty() && xinerama::XineramaIsActive(display) != 0 { let mut screen_count = 0; let screens_raw = xinerama::XineramaQueryScreens(display, &mut screen_count); - let screens_slice = slice::from_raw_parts_mut(screens_raw, screen_count.try_into().unwrap()); + let screens_slice = + slice::from_raw_parts_mut(screens_raw, screen_count.try_into().unwrap()); monitors.extend(screens_slice.iter().map(|x| MonitorConfig::from(*x))); xlib::XFree(screens_slice.as_mut_ptr() as *mut c_void); } // use whole screen as fallback if monitors.is_empty() { - return vec!(MonitorConfig::from(xlib::XDefaultScreenOfDisplay(display))); + return vec![MonitorConfig::from(xlib::XDefaultScreenOfDisplay(display))]; } if ignore_overlapping { @@ -233,7 +264,7 @@ pub fn query_monitor_config(display: *mut xlib::Display, ignore_overlapping: boo m1.dimensions().right() <= m2.dimensions().x() // m1 is left of m2 || m1.dimensions().x() >= m2.dimensions().right() // m1 is right of m2 || m1.dimensions().bottom() <= m2.dimensions().y() // m1 is on top of m2 - || m1.dimensions().y() >= m2.dimensions().bottom() // m1 is below m2 + || m1.dimensions().y() >= m2.dimensions().bottom() // m1 is below m2 }; let mut non_overlapping = Vec::new(); for mon in monitors.drain(..) { @@ -250,11 +281,17 @@ pub fn query_monitor_config(display: *mut xlib::Display, ignore_overlapping: boo /// Remove unrelated mask bits on button or key events pub fn sanitize_modifiers(modifiers: u32) -> u32 { - modifiers & (xlib::ShiftMask | xlib::ControlMask | xlib::Mod1Mask | xlib::Mod3Mask | xlib::Mod4Mask) + modifiers + & (xlib::ShiftMask | xlib::ControlMask | xlib::Mod1Mask | xlib::Mod3Mask | xlib::Mod4Mask) } /// Send a ClientMessage to the default root window -pub fn send_client_message(display: *mut xlib::Display, atom: X11Atom, window: xlib::Window, data: xlib::ClientMessageData) { +pub fn send_client_message( + display: *mut xlib::Display, + atom: X11Atom, + window: xlib::Window, + data: xlib::ClientMessageData, +) { let mut event = xlib::XEvent { client_message: xlib::XClientMessageEvent { type_: xlib::ClientMessage, @@ -265,10 +302,9 @@ pub fn send_client_message(display: *mut xlib::Display, atom: X11Atom, window: x message_type: atom.to_xlib_atom(display), format: 32, data, - } + }, }; - unsafe { let root = xlib::XDefaultRootWindow(display); let mask = xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask; diff --git a/libmars/src/platforms/x11/misc/window.rs b/libmars/src/platforms/x11/misc/window.rs index df3d4e5e..a2ccc57e 100644 --- a/libmars/src/platforms/x11/misc/window.rs +++ b/libmars/src/platforms/x11/misc/window.rs @@ -1,43 +1,81 @@ extern crate x11; -use std::ffi::*; use std::mem::MaybeUninit; use std::os::raw::c_void; use std::ptr; use std::slice; use x11::xlib; -use crate::common::error::*; use crate::platforms::x11::misc::*; - pub trait X11Window { fn x11_attributes(&self, display: *mut xlib::Display) -> Result; fn x11_class_hint(&self, display: *mut xlib::Display) -> Result<(String, String)>; - fn x11_close(&self, display: *mut xlib::Display, - error_handler: Option c_int>); + fn x11_close( + &self, + display: *mut xlib::Display, + error_handler: Option< + unsafe extern "C" fn(_: *mut xlib::Display, _: *mut xlib::XErrorEvent) -> c_int, + >, + ); fn x11_destroy(&self, display: *mut xlib::Display); fn x11_get_state(&self, display: *mut xlib::Display) -> Result; - fn x11_get_text_list_property(&self, display: *mut xlib::Display, property: X11Atom) -> Result>; + fn x11_get_text_list_property( + &self, + display: *mut xlib::Display, + property: X11Atom, + ) -> Result>; fn x11_net_wm_state(&self, display: *mut xlib::Display) -> Result>; fn x11_net_wm_state_add(&self, display: *mut xlib::Display, state: X11Atom); fn x11_net_wm_state_remove(&self, display: *mut xlib::Display, state: X11Atom); - fn x11_read_property_long(&self, display: *mut xlib::Display, property: X11Atom, prop_type: c_ulong) -> Result>; - fn x11_read_property_string(&self, display: *mut xlib::Display, property: X11Atom) -> Result; - fn x11_replace_property_long(&self, display: *mut xlib::Display, property: X11Atom, prop_type: c_ulong, data: &[c_ulong]); + fn x11_read_property_long( + &self, + display: *mut xlib::Display, + property: X11Atom, + prop_type: c_ulong, + ) -> Result>; + fn x11_read_property_string( + &self, + display: *mut xlib::Display, + property: X11Atom, + ) -> Result; + fn x11_replace_property_long( + &self, + display: *mut xlib::Display, + property: X11Atom, + prop_type: c_ulong, + data: &[c_ulong], + ); fn x11_set_state(&self, display: *mut xlib::Display, state: i32); - fn x11_set_text_list_property(&self, display: *mut xlib::Display, property: X11Atom, list: &[String]); + fn x11_set_text_list_property( + &self, + display: *mut xlib::Display, + property: X11Atom, + list: &[String], + ); fn x11_supports_protocol(&self, display: *mut xlib::Display, protocol: X11Atom) -> bool; fn x11_dimensions(&self, display: *mut xlib::Display) -> Result; - fn x11_geometry(&self, display: *mut xlib::Display) -> Result<(u64, i32, i32, u32, u32, u32, u32)>; + fn x11_geometry( + &self, + display: *mut xlib::Display, + ) -> Result<(u64, i32, i32, u32, u32, u32, u32)>; fn x11_get_window_types(&self, display: *mut xlib::Display) -> Vec; fn x11_is_transient_for(&self, display: *mut xlib::Display) -> Option; fn x11_map(&self, display: *mut xlib::Display); - fn x11_message(&self, display: *mut xlib::Display, msg_type: atoms::X11Atom, msg_format: c_int, msg_data: xlib::ClientMessageData); + fn x11_message( + &self, + display: *mut xlib::Display, + msg_type: atoms::X11Atom, + msg_format: c_int, + msg_data: xlib::ClientMessageData, + ); fn x11_unmap(&self, display: *mut xlib::Display); fn x11_wm_protocols(&self, display: *mut xlib::Display) -> Vec; fn x11_wm_name(&self, display: *mut xlib::Display) -> Result; - fn x11_wm_normal_hints(&self, display: *mut xlib::Display) -> Result<(xlib::XSizeHints, c_long)>; + fn x11_wm_normal_hints( + &self, + display: *mut xlib::Display, + ) -> Result<(xlib::XSizeHints, c_long)>; } impl X11Window for xlib::Window { @@ -47,7 +85,9 @@ impl X11Window for xlib::Window { if xlib::XGetWindowAttributes(display, *self, attributes.as_mut_ptr()) != 0 { Ok(attributes.assume_init()) } else { - Err(MarsError::failed_request(stringify!(xlib::XGetWindowAttributes))) + Err(MarsError::failed_request(stringify!( + xlib::XGetWindowAttributes + ))) } } } @@ -60,9 +100,13 @@ impl X11Window for xlib::Window { let class_hints = class_hints.assume_init(); if !class_hints.res_name.is_null() && !class_hints.res_class.is_null() { let res_name = CStr::from_ptr(class_hints.res_name) - .to_str().unwrap().to_owned(); + .to_str() + .unwrap() + .to_owned(); let res_class = CStr::from_ptr(class_hints.res_class) - .to_str().unwrap().to_owned(); + .to_str() + .unwrap() + .to_owned(); let ret_val = Ok((res_name, res_class)); xlib::XFree(class_hints.res_name as *mut c_void); xlib::XFree(class_hints.res_class as *mut c_void); @@ -76,8 +120,13 @@ impl X11Window for xlib::Window { } } - fn x11_close(&self, display: *mut xlib::Display, - error_handler: Option c_int>) { + fn x11_close( + &self, + display: *mut xlib::Display, + error_handler: Option< + unsafe extern "C" fn(_: *mut xlib::Display, _: *mut xlib::XErrorEvent) -> c_int, + >, + ) { if self.x11_supports_protocol(display, X11Atom::WMDeleteWindow) { let msg_type = X11Atom::WMProtocols; let mut msg_data = xlib::ClientMessageData::new(); @@ -103,20 +152,41 @@ impl X11Window for xlib::Window { } fn x11_get_state(&self, display: *mut xlib::Display) -> Result { - let result = self.x11_read_property_long(display, WMState, WMState.to_xlib_atom(display))?; + let result = + self.x11_read_property_long(display, WMState, WMState.to_xlib_atom(display))?; Ok(result[0]) } - fn x11_get_text_list_property(&self, display: *mut xlib::Display, property: X11Atom) -> Result> { + fn x11_get_text_list_property( + &self, + display: *mut xlib::Display, + property: X11Atom, + ) -> Result> { let mut text: MaybeUninit = MaybeUninit::uninit(); let mut nitems = 0; let mut data_ptr: *mut *mut c_char = ptr::null_mut(); let mut data = Vec::new(); unsafe { - if xlib::XGetTextProperty(display, *self, text.as_mut_ptr(), property.to_xlib_atom(display)) == 0 { + if xlib::XGetTextProperty( + display, + *self, + text.as_mut_ptr(), + property.to_xlib_atom(display), + ) == 0 + { Err(MarsError::property_unavailable(property)) - } else if xlib::Xutf8TextPropertyToTextList(display, text.as_ptr(), &mut data_ptr, &mut nitems) != 0 { - Err(MarsError::failed_conversion(text.as_ptr(), stringify!(*mut *mut i8), stringify!(xlib::TextProperty))) + } else if xlib::Xutf8TextPropertyToTextList( + display, + text.as_ptr(), + &mut data_ptr, + &mut nitems, + ) != 0 + { + Err(MarsError::failed_conversion( + text.as_ptr(), + stringify!(*mut *mut i8), + stringify!(xlib::TextProperty), + )) } else if data_ptr.is_null() { Err(MarsError::property_unavailable(property)) } else { @@ -126,8 +196,12 @@ impl X11Window for xlib::Window { Ok(s) => s, Err(_) => { xlib::XFreeStringList(data_ptr); - return Err(MarsError::failed_conversion(cstr, stringify!(CStr), stringify!(String))); - }, + return Err(MarsError::failed_conversion( + cstr, + stringify!(CStr), + stringify!(String), + )); + } }; data.push(s.to_owned()); } @@ -138,8 +212,11 @@ impl X11Window for xlib::Window { } fn x11_net_wm_state(&self, display: *mut xlib::Display) -> Result> { - let atoms = self.x11_read_property_long(display, NetWMState, xlib::XA_ATOM)? - .iter().filter_map(|a| X11Atom::from_xlib_atom(display, *a)).collect(); + let atoms = self + .x11_read_property_long(display, NetWMState, xlib::XA_ATOM)? + .iter() + .filter_map(|a| X11Atom::from_xlib_atom(display, *a)) + .collect(); Ok(atoms) } @@ -166,7 +243,12 @@ impl X11Window for xlib::Window { self.x11_replace_property_long(display, NetWMState, xlib::XA_ATOM, &states); } - fn x11_read_property_long(&self, display: *mut xlib::Display, property: X11Atom, prop_type: c_ulong) -> Result> { + fn x11_read_property_long( + &self, + display: *mut xlib::Display, + property: X11Atom, + prop_type: c_ulong, + ) -> Result> { let mut actual_type = 0; let mut actual_format = 0; let mut nitems = 0; @@ -177,22 +259,35 @@ impl X11Window for xlib::Window { unsafe { let mut data_ptr: *mut u8 = ptr::null_mut(); first_run = false; - let status = xlib::XGetWindowProperty(display, *self, property.to_xlib_atom(display), - data.len() as i64 / 2, 8, xlib::False, - prop_type, &mut actual_type, + let status = xlib::XGetWindowProperty( + display, + *self, + property.to_xlib_atom(display), + data.len() as i64 / 2, + 8, + xlib::False, + prop_type, + &mut actual_type, &mut actual_format, - &mut nitems, &mut remaining_bytes, - &mut data_ptr); + &mut nitems, + &mut remaining_bytes, + &mut data_ptr, + ); if status != 0 { - return Err(MarsError::failed_request(stringify!(xlib::XGetWindowProperty))); - } else if actual_type == XLIB_NONE - && actual_format == 0 - && remaining_bytes == 0 { + return Err(MarsError::failed_request(stringify!( + xlib::XGetWindowProperty + ))); + } else if actual_type == XLIB_NONE && actual_format == 0 && remaining_bytes == 0 { return Err(MarsError::property_unavailable(property)); } else if actual_type != prop_type || actual_format != 32 { - return Err(MarsError::invalid_response(stringify!(xlib::XGetWindowProperty))); + return Err(MarsError::invalid_response(stringify!( + xlib::XGetWindowProperty + ))); } else { - data.extend_from_slice(slice::from_raw_parts(data_ptr as *mut u64, nitems.try_into().unwrap())); + data.extend_from_slice(slice::from_raw_parts( + data_ptr as *mut u64, + nitems.try_into().unwrap(), + )); xlib::XFree(data_ptr as *mut c_void); } } @@ -200,7 +295,11 @@ impl X11Window for xlib::Window { Ok(data) } - fn x11_read_property_string(&self, display: *mut xlib::Display, property: X11Atom) -> Result { + fn x11_read_property_string( + &self, + display: *mut xlib::Display, + property: X11Atom, + ) -> Result { let v = self.x11_get_text_list_property(display, property)?; match v.first() { Some(string) => Ok(string.to_owned()), @@ -208,16 +307,24 @@ impl X11Window for xlib::Window { } } - fn x11_replace_property_long(&self, display: *mut xlib::Display, property: X11Atom, prop_type: c_ulong, data: &[c_ulong]) { + fn x11_replace_property_long( + &self, + display: *mut xlib::Display, + property: X11Atom, + prop_type: c_ulong, + data: &[c_ulong], + ) { unsafe { - xlib::XChangeProperty(display, - *self, - property.to_xlib_atom(display), - prop_type, - 32, - xlib::PropModeReplace, - data.as_ptr().cast::(), - data.len() as i32); + xlib::XChangeProperty( + display, + *self, + property.to_xlib_atom(display), + prop_type, + 32, + xlib::PropModeReplace, + data.as_ptr().cast::(), + data.len() as i32, + ); } } @@ -226,21 +333,47 @@ impl X11Window for xlib::Window { let state_atom = WMState.to_xlib_atom(display); unsafe { - xlib::XChangeProperty(display, *self, state_atom, state_atom, - 32, xlib::PropModeReplace, &data as *const i32 as *const u8, 1); + xlib::XChangeProperty( + display, + *self, + state_atom, + state_atom, + 32, + xlib::PropModeReplace, + &data as *const i32 as *const u8, + 1, + ); } } - - fn x11_set_text_list_property(&self, display: *mut xlib::Display, property: X11Atom, list: &[String]) { - let mut pointers: Vec<*mut c_char> = list.iter().flat_map(|s| CString::new(s.clone())) - .map(|s| s.into_raw()).collect(); + fn x11_set_text_list_property( + &self, + display: *mut xlib::Display, + property: X11Atom, + list: &[String], + ) { + let mut pointers: Vec<*mut c_char> = list + .iter() + .flat_map(|s| CString::new(s.clone())) + .map(|s| s.into_raw()) + .collect(); let slice = &mut pointers; let mut text: MaybeUninit = MaybeUninit::uninit(); let size = slice.len().try_into().unwrap(); unsafe { - xlib::Xutf8TextListToTextProperty(display, slice.as_mut_ptr(), size, xlib::XUTF8StringStyle, text.as_mut_ptr()); - xlib::XSetTextProperty(display, *self, &mut text.assume_init(), property.to_xlib_atom(display)); + xlib::Xutf8TextListToTextProperty( + display, + slice.as_mut_ptr(), + size, + xlib::XUTF8StringStyle, + text.as_mut_ptr(), + ); + xlib::XSetTextProperty( + display, + *self, + &mut text.assume_init(), + property.to_xlib_atom(display), + ); } } @@ -249,7 +382,10 @@ impl X11Window for xlib::Window { .map(|(_root, x, y, w, h, _bw, _depth)| Dimensions::new(x, y, w, h)) } - fn x11_geometry(&self, display: *mut xlib::Display) -> Result<(u64, i32, i32, u32, u32, u32, u32)> { + fn x11_geometry( + &self, + display: *mut xlib::Display, + ) -> Result<(u64, i32, i32, u32, u32, u32, u32)> { unsafe { let mut root: u64 = 0; let mut x: i32 = 0; @@ -258,7 +394,10 @@ impl X11Window for xlib::Window { let mut h: u32 = 0; let mut bw: u32 = 0; let mut depth: u32 = 0; - if xlib::XGetGeometry(display, *self, &mut root, &mut x, &mut y, &mut w, &mut h, &mut bw, &mut depth) != 0 { + if xlib::XGetGeometry( + display, *self, &mut root, &mut x, &mut y, &mut w, &mut h, &mut bw, &mut depth, + ) != 0 + { Ok((root, x, y, w, h, bw, depth)) } else { Err(MarsError::failed_request(stringify!(xlib::XGetGeometry))) @@ -276,15 +415,32 @@ impl X11Window for xlib::Window { unsafe { let mut win_types_ptr: *mut u8 = ptr::null_mut(); // TODO use x11_read_property_long - let result = xlib::XGetWindowProperty(display, *self, NetWMWindowType.to_xlib_atom(display), - 0, 8, xlib::False, xlib::XA_ATOM, - &mut da, &mut di, &mut nitems, &mut dl, &mut win_types_ptr); + let result = xlib::XGetWindowProperty( + display, + *self, + NetWMWindowType.to_xlib_atom(display), + 0, + 8, + xlib::False, + xlib::XA_ATOM, + &mut da, + &mut di, + &mut nitems, + &mut dl, + &mut win_types_ptr, + ); if result == xlib::Success.into() && !win_types_ptr.is_null() { - let temp = slice::from_raw_parts(win_types_ptr as *mut xlib::Atom, nitems.try_into().unwrap()); + let temp = slice::from_raw_parts( + win_types_ptr as *mut xlib::Atom, + nitems.try_into().unwrap(), + ); types = temp.to_vec(); } } - types.iter().filter_map(|xa| X11Atom::from_xlib_atom(display, *xa)).collect() + types + .iter() + .filter_map(|xa| X11Atom::from_xlib_atom(display, *xa)) + .collect() } fn x11_is_transient_for(&self, display: *mut xlib::Display) -> Option { @@ -303,7 +459,13 @@ impl X11Window for xlib::Window { } } - fn x11_message(&self, display: *mut xlib::Display, msg_type: atoms::X11Atom, msg_format: c_int, msg_data: xlib::ClientMessageData) { + fn x11_message( + &self, + display: *mut xlib::Display, + msg_type: atoms::X11Atom, + msg_format: c_int, + msg_data: xlib::ClientMessageData, + ) { unsafe { let msg_type_x11 = msg_type.to_xlib_atom(display); let msg_event = xlib::XClientMessageEvent { @@ -317,7 +479,9 @@ impl X11Window for xlib::Window { data: msg_data, }; - let mut event = xlib::XEvent { client_message: msg_event }; + let mut event = xlib::XEvent { + client_message: msg_event, + }; xlib::XSendEvent(display, *self, xlib::False, 0, &mut event); } @@ -343,18 +507,26 @@ impl X11Window for xlib::Window { supported_atoms.push(*n); } } - supported_atoms.iter().filter_map(|xa| X11Atom::from_xlib_atom(display, *xa)).collect() + supported_atoms + .iter() + .filter_map(|xa| X11Atom::from_xlib_atom(display, *xa)) + .collect() } fn x11_wm_name(&self, display: *mut xlib::Display) -> Result { self.x11_read_property_string(display, WMName) } - fn x11_wm_normal_hints(&self, display: *mut xlib::Display) -> Result<(xlib::XSizeHints, c_long)> { + fn x11_wm_normal_hints( + &self, + display: *mut xlib::Display, + ) -> Result<(xlib::XSizeHints, c_long)> { unsafe { let mut size_hints: MaybeUninit = MaybeUninit::uninit(); let mut supplied_hints: c_long = 0; - if xlib::XGetWMNormalHints(display, *self, size_hints.as_mut_ptr(), &mut supplied_hints) != 0 { + if xlib::XGetWMNormalHints(display, *self, size_hints.as_mut_ptr(), &mut supplied_hints) + != 0 + { Ok((size_hints.assume_init(), supplied_hints)) } else { Err(MarsError::property_unavailable(WMNormalHints)) diff --git a/libmars/src/platforms/x11/wm/backend.rs b/libmars/src/platforms/x11/wm/backend.rs index 7e10ae9b..0e56ab9a 100644 --- a/libmars/src/platforms/x11/wm/backend.rs +++ b/libmars/src/platforms/x11/wm/backend.rs @@ -1,7 +1,6 @@ extern crate x11; use std::cell::RefCell; -use std::ffi::*; use std::marker::PhantomData; use std::mem::MaybeUninit; use std::ptr; @@ -10,37 +9,44 @@ use std::slice; use x11::xlib; use x11::xrandr; -use super::*; -use super::unmanaged::*; use super::client::*; -use crate::common::*; +use super::unmanaged::*; +use super::*; use crate::common::error::Result; +use crate::common::*; use crate::interfaces::wm::*; -use crate::platforms::x11::misc::{ - *, - atoms::*, - atoms::X11Atom::*, - window::*, -}; - - +use crate::platforms::x11::misc::{atoms::X11Atom::*, atoms::*, window::*, *}; #[allow(unused_macros)] macro_rules! print_event { ($wm:expr, $event:expr) => { #[cfg(debug_assertions)] if let Some(client) = $wm.clients().find(|c| c.borrow().window() == $event.window) { - eprintln!("Received {} for window 0x{:x} (window of {})", event_type(&$event), $event.window, client.borrow().name()); + eprintln!( + "Received {} for window 0x{:x} (window of {})", + event_type(&$event), + $event.window, + client.borrow().name() + ); } else if let Some(client) = $wm.clients().find(|c| c.borrow().frame() == $event.window) { - eprintln!("Received {} for window 0x{:x} (frame of {})", event_type(&$event), $event.window, client.borrow().name()); + eprintln!( + "Received {} for window 0x{:x} (frame of {})", + event_type(&$event), + $event.window, + client.borrow().name() + ); } else { - eprintln!("Received {} for window 0x{:x} (not a client)", event_type(&$event), $event.window); + eprintln!( + "Received {} for window 0x{:x} (not a client)", + event_type(&$event), + $event.window + ); } #[cfg(debug_assertions)] eprintln!("\t{:?}", $event); #[cfg(not(debug_assertions))] let (_, _) = (&$wm, &$event); - } + }; } type WM<'a, A> = dyn WindowManager, A> + 'a; @@ -61,9 +67,8 @@ struct XRandrInfo { _error_base: i32, } - const MAX_FRAMERATE: u64 = 120; -const SUPPORTED_ATOMS: &[X11Atom; 22] = & [ +const SUPPORTED_ATOMS: &[X11Atom; 22] = &[ NetActiveWindow, NetClientList, NetClientListStacking, @@ -84,12 +89,10 @@ const SUPPORTED_ATOMS: &[X11Atom; 22] = & [ NetWMWindowTypeMenu, NetWMWindowTypeNotification, NetWorkarea, - MarsCenter, MarsWMStateTiled, ]; - impl X11Backend { /// Register window manager and initialize backend with new connection. pub fn init(name: &str) -> Result> { @@ -119,21 +122,53 @@ impl X11Backend { // export wm name x11b.wmcheck_win = xlib::XCreateSimpleWindow(display, root, 0, 0, 1, 1, 0, 0, 0); - xlib::XChangeProperty(display, x11b.wmcheck_win, NetSupportingWMCheck.to_xlib_atom(display), xlib::XA_WINDOW, - 32, xlib::PropModeReplace, &x11b.wmcheck_win as *const u64 as *const u8, 1); - xlib::XChangeProperty(display, x11b.wmcheck_win, NetWMName.to_xlib_atom(display), - UTF8String.to_xlib_atom(display), 8, xlib::PropModeReplace, name.as_ptr(), name.len() as i32); - xlib::XChangeProperty(display, root, NetSupportingWMCheck.to_xlib_atom(display), xlib::XA_WINDOW, - 32, xlib::PropModeReplace, &x11b.wmcheck_win as *const u64 as *const u8, 1); + xlib::XChangeProperty( + display, + x11b.wmcheck_win, + NetSupportingWMCheck.to_xlib_atom(display), + xlib::XA_WINDOW, + 32, + xlib::PropModeReplace, + &x11b.wmcheck_win as *const u64 as *const u8, + 1, + ); + xlib::XChangeProperty( + display, + x11b.wmcheck_win, + NetWMName.to_xlib_atom(display), + UTF8String.to_xlib_atom(display), + 8, + xlib::PropModeReplace, + name.as_ptr(), + name.len() as i32, + ); + xlib::XChangeProperty( + display, + root, + NetSupportingWMCheck.to_xlib_atom(display), + xlib::XA_WINDOW, + 32, + xlib::PropModeReplace, + &x11b.wmcheck_win as *const u64 as *const u8, + 1, + ); // register as window manager xlib::XSetErrorHandler(Some(on_wm_detected)); // select events let mut attributes: MaybeUninit = MaybeUninit::uninit(); (*attributes.as_mut_ptr()).cursor = xlib::XCreateFontCursor(display, CURSOR_NORMAL); - (*attributes.as_mut_ptr()).event_mask = xlib::SubstructureRedirectMask | - xlib::SubstructureNotifyMask | xlib::StructureNotifyMask | xlib::KeyPressMask | xlib::ButtonPressMask; - xlib::XChangeWindowAttributes(display, root, xlib::CWEventMask | xlib::CWCursor, attributes.as_mut_ptr()); + (*attributes.as_mut_ptr()).event_mask = xlib::SubstructureRedirectMask + | xlib::SubstructureNotifyMask + | xlib::StructureNotifyMask + | xlib::KeyPressMask + | xlib::ButtonPressMask; + xlib::XChangeWindowAttributes( + display, + root, + xlib::CWEventMask | xlib::CWCursor, + attributes.as_mut_ptr(), + ); xlib::XSync(display, xlib::False); xlib::XSetErrorHandler(Some(on_error)); @@ -151,13 +186,21 @@ impl X11Backend { fn apply_dock_insets(&mut self) { self.monitors.iter_mut().for_each(|m| m.remove_insets()); - for dock in self.unmanaged_clients.iter().filter(|u| u.get_type() == UnmanagedType::Dock) { + for dock in self + .unmanaged_clients + .iter() + .filter(|u| u.get_type() == UnmanagedType::Dock) + { let dimensions = match dock.window().x11_dimensions(self.display) { Ok(dimensions) => dimensions, Err(_) => continue, }; - if let Some(mon) = self.monitors.iter_mut().find(|m| m.contains_point(dimensions.center())) { + if let Some(mon) = self + .monitors + .iter_mut() + .find(|m| m.contains_point(dimensions.center())) + { // apply top indent if dimensions.center().1 < mon.dimensions().center().1 { let inset = dimensions.bottom() - mon.dimensions().y(); @@ -190,13 +233,26 @@ impl X11Backend { }; let mut xevent = xlib::XEvent::from(ce); unsafe { - xlib::XSendEvent(self.display, client.window(), xlib::False, xlib::StructureNotifyMask, &mut xevent); + xlib::XSendEvent( + self.display, + client.window(), + xlib::False, + xlib::StructureNotifyMask, + &mut xevent, + ); } } - fn handle_xevent(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XEvent) { - unsafe { // unsafe because of access to union field - if self.xrandr.supported && event.get_type() == self.xrandr.event_base + xrandr::RRNotify { + fn handle_xevent( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XEvent, + ) { + unsafe { + // unsafe because of access to union field + if self.xrandr.supported + && event.get_type() == self.xrandr.event_base + xrandr::RRNotify + { self.monitors = query_monitor_config(self.display, true); self.apply_dock_insets(); wm.update_monitor_config(self, self.monitors.clone()); @@ -244,26 +300,50 @@ impl X11Backend { for win_type in &window_types { match win_type { NetWMWindowTypeDesktop => unsafe { - xlib::XGrabKey(self.display, xlib::AnyKey, xlib::AnyModifier, window, xlib::True, xlib::GrabModeAsync, xlib::GrabModeAsync); - self.unmanaged_clients.push(UnmanagedClient::new(self.display, window, UnmanagedType::Desktop)); + xlib::XGrabKey( + self.display, + xlib::AnyKey, + xlib::AnyModifier, + window, + xlib::True, + xlib::GrabModeAsync, + xlib::GrabModeAsync, + ); + self.unmanaged_clients.push(UnmanagedClient::new( + self.display, + window, + UnmanagedType::Desktop, + )); return; }, NetWMWindowTypeDialog | NetWMWindowTypeSplash => { is_dialog = true; - }, + } NetWMWindowTypeDock => { - self.unmanaged_clients.push(UnmanagedClient::new(self.display, window, UnmanagedType::Dock)); + self.unmanaged_clients.push(UnmanagedClient::new( + self.display, + window, + UnmanagedType::Dock, + )); self.apply_dock_insets(); wm.update_monitor_config(self, self.monitors.clone()); return; - }, + } NetWMWindowTypeMenu => unsafe { - xlib::XSelectInput(self.display, window, xlib::EnterWindowMask | xlib::LeaveWindowMask); + xlib::XSelectInput( + self.display, + window, + xlib::EnterWindowMask | xlib::LeaveWindowMask, + ); xlib::XMapRaised(self.display, window); return; }, NetWMWindowTypeNotification => { - self.unmanaged_clients.push(UnmanagedClient::new(self.display, window, UnmanagedType::Notification)); + self.unmanaged_clients.push(UnmanagedClient::new( + self.display, + window, + UnmanagedType::Notification, + )); return; } _ => (), @@ -299,7 +379,7 @@ impl X11Backend { } else { Some(data[0] as u32) } - }, + } Err(_msg) => None, } }; @@ -316,58 +396,102 @@ impl X11Backend { // TODO move transient clients to workspace and monitor of their counterpart } - fn mouse_action_move(&mut self, _wm: &mut (impl WindowManager + ?Sized), client_rc: &Rc>>, - orig_client_pos: (i32, i32), _orig_client_size: (u32, u32), delta: (i32, i32)) { + fn mouse_action_move( + &mut self, + _wm: &mut (impl WindowManager + ?Sized), + client_rc: &Rc>>, + orig_client_pos: (i32, i32), + _orig_client_size: (u32, u32), + delta: (i32, i32), + ) { let dest_x = orig_client_pos.0 + delta.0; let dest_y = orig_client_pos.1 + delta.1; let size = client_rc.borrow().size(); - client_rc.borrow_mut().move_resize(dest_x, dest_y, size.0, size.1); + client_rc + .borrow_mut() + .move_resize(dest_x, dest_y, size.0, size.1); } - fn mouse_action_resize(&mut self, _wm: &mut (impl WindowManager + ?Sized), client_rc: &Rc>>, - _orig_client_pos: (i32, i32), orig_client_size: (u32, u32), delta: (i32, i32)) { + fn mouse_action_resize( + &mut self, + _wm: &mut (impl WindowManager + ?Sized), + client_rc: &Rc>>, + _orig_client_pos: (i32, i32), + orig_client_size: (u32, u32), + delta: (i32, i32), + ) { let dest_w = orig_client_size.0 as i32 + delta.0; let dest_h = orig_client_size.1 as i32 + delta.1; let pos = client_rc.borrow().pos(); - let dest_w: u32 = if dest_w < WINDOW_MIN_SIZE as i32 { WINDOW_MIN_SIZE } else { dest_w as u32 }; - let dest_h: u32 = if dest_h < WINDOW_MIN_SIZE as i32 { WINDOW_MIN_SIZE } else { dest_h as u32 }; - client_rc.borrow_mut().move_resize(pos.0, pos.1, dest_w, dest_h); + let dest_w: u32 = if dest_w < WINDOW_MIN_SIZE as i32 { + WINDOW_MIN_SIZE + } else { + dest_w as u32 + }; + let dest_h: u32 = if dest_h < WINDOW_MIN_SIZE as i32 { + WINDOW_MIN_SIZE + } else { + dest_h as u32 + }; + client_rc + .borrow_mut() + .move_resize(pos.0, pos.1, dest_w, dest_h); } - fn on_button_press(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XButtonEvent) { + fn on_button_press( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XButtonEvent, + ) { //print_event!(wm, event); let modifiers = sanitize_modifiers(event.state); if let Some(client_rc) = Self::client_by_frame(wm, event.window) { - wm.handle_button(self, modifiers, event.button, ButtonTarget::Frame, Some(client_rc)); + wm.handle_button( + self, + modifiers, + event.button, + ButtonTarget::Frame, + Some(client_rc), + ); } else if let Some(client_rc) = Self::client_by_window(wm, event.window) { - wm.handle_button(self, modifiers, event.button, ButtonTarget::Window, Some(client_rc)); + wm.handle_button( + self, + modifiers, + event.button, + ButtonTarget::Window, + Some(client_rc), + ); } else if event.window == self.root { wm.handle_button(self, modifiers, event.button, ButtonTarget::Root, None); } } - fn on_client_message(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XClientMessageEvent) { + fn on_client_message( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XClientMessageEvent, + ) { //print_event!(wm, event); if let Some(atom) = X11Atom::from_xlib_atom(self.display, event.message_type) { match atom { NetActiveWindow => { - if let Some(client_rc) = Self::client_by_window(wm, event.window){ + if let Some(client_rc) = Self::client_by_window(wm, event.window) { wm.activate_client(self, client_rc); } - }, + } NetCloseWindow => { if let Some(client_rc) = Self::client_by_window(wm, event.window) { client_rc.borrow().close(); } else { event.window.x11_close(self.display, Some(on_error)); } - }, + } NetCurrentDesktop => { if let Ok(workspace) = event.data.get_long(0).try_into() { wm.switch_workspace(self, workspace); } - }, + } NetWMDesktop => { if let Some(client_rc) = Self::client_by_window(wm, event.window) { let workspace = event.data.get_long(0); @@ -376,11 +500,14 @@ impl X11Backend { wm.move_to_workspace(self, client_rc, workspace as u32); } } - }, + } NetWMState => { if let Some(client_rc) = Self::client_by_window(wm, event.window) { - if event.data.get_long(1) as u64 == NetWMStateFullscreen.to_xlib_atom(self.display) - || event.data.get_long(2) as u64 == NetWMStateFullscreen.to_xlib_atom(self.display) { + if event.data.get_long(1) as u64 + == NetWMStateFullscreen.to_xlib_atom(self.display) + || event.data.get_long(2) as u64 + == NetWMStateFullscreen.to_xlib_atom(self.display) + { let mode = event.data.get_long(0) as u64; if mode == 1 { wm.fullscreen_client(self, client_rc, true); @@ -389,8 +516,11 @@ impl X11Backend { } else if mode == 2 { wm.toggle_fullscreen_client(self, client_rc); } - } else if event.data.get_long(1) as u64 == MarsWMStateTiled.to_xlib_atom(self.display) - || event.data.get_long(2) as u64 == MarsWMStateTiled.to_xlib_atom(self.display) { + } else if event.data.get_long(1) as u64 + == MarsWMStateTiled.to_xlib_atom(self.display) + || event.data.get_long(2) as u64 + == MarsWMStateTiled.to_xlib_atom(self.display) + { let mode = event.data.get_long(0) as u64; if mode == 1 { wm.tile_client(self, client_rc, true); @@ -401,18 +531,22 @@ impl X11Backend { } } } - }, + } MarsCenter => { if let Some(client_rc) = Self::client_by_window(wm, event.window) { wm.center_client(self, client_rc); } - }, + } _ => (), } } } - fn on_configure_notify(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XConfigureEvent) { + fn on_configure_notify( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XConfigureEvent, + ) { //print_event!(wm, event); if event.window == self.root && !self.xrandr.supported { self.monitors = query_monitor_config(self.display, true); @@ -421,9 +555,19 @@ impl X11Backend { } } - fn on_configure_request(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XConfigureRequestEvent) { - let client = wm.clients().find(|c| c.borrow().window() == event.window).cloned(); - let inner = wm.clients().find(|c| c.borrow().window() == event.window).map(|c| c.borrow().inner_dimensions()); + fn on_configure_request( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XConfigureRequestEvent, + ) { + let client = wm + .clients() + .find(|c| c.borrow().window() == event.window) + .cloned(); + let inner = wm + .clients() + .find(|c| c.borrow().window() == event.window) + .map(|c| c.borrow().inner_dimensions()); if let Some(client_rc) = client { if let Some(inner) = inner { // get dimensions from event @@ -490,17 +634,30 @@ impl X11Backend { stack_mode: event.detail, }; unsafe { - xlib::XConfigureWindow(self.display, event.window, event.value_mask as u32, &mut wc); + xlib::XConfigureWindow( + self.display, + event.window, + event.value_mask as u32, + &mut wc, + ); } - if self.unmanaged_clients.iter().any(|u| u.window() == event.window && u.get_type() == UnmanagedType::Dock) { + if self + .unmanaged_clients + .iter() + .any(|u| u.window() == event.window && u.get_type() == UnmanagedType::Dock) + { self.apply_dock_insets(); wm.update_monitor_config(self, self.monitors.clone()); } } } - fn on_destroy_notify(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XDestroyWindowEvent) { + fn on_destroy_notify( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XDestroyWindowEvent, + ) { if self.remove_unmanaged_client(wm, event.window) { return; } @@ -515,7 +672,11 @@ impl X11Backend { self.unmanage(wm, client_rc); } - fn on_enter_notify(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XCrossingEvent) { + fn on_enter_notify( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XCrossingEvent, + ) { //print_event!(wm, event); // if let Some(client_rc) = Self::client_by_frame(wm, event.window) { // println!("EnterNotify on frame for client {}", client_rc.borrow().window()); @@ -530,7 +691,12 @@ impl X11Backend { Some(client_rc) } else { unsafe { - xlib::XSetInputFocus(self.display, event.window, xlib::RevertToPointerRoot, xlib::CurrentTime); + xlib::XSetInputFocus( + self.display, + event.window, + xlib::RevertToPointerRoot, + xlib::CurrentTime, + ); } None }; @@ -538,18 +704,25 @@ impl X11Backend { wm.focus_client(self, client_option.clone()); } - fn on_expose_event(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XExposeEvent) { + fn on_expose_event( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XExposeEvent, + ) { if let Some(client_rc) = Self::client_by_frame(wm, event.window) { client_rc.borrow_mut().update_title(); } } - fn on_key_press(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XKeyEvent) { + fn on_key_press( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XKeyEvent, + ) { //print_event!(wm, event); - let keysym = unsafe { - xlib::XKeycodeToKeysym(self.display, event.keycode.try_into().unwrap(), 0) - }; + let keysym = + unsafe { xlib::XKeycodeToKeysym(self.display, event.keycode.try_into().unwrap(), 0) }; let modifiers = sanitize_modifiers(event.state); let client_opt = Self::client_by_frame(wm, event.window); @@ -557,7 +730,11 @@ impl X11Backend { wm.handle_key(self, modifiers, key, client_opt) } - fn on_leave_notify(&mut self, _wm: &mut (impl WindowManager + ?Sized), _event: xlib::XCrossingEvent) { + fn on_leave_notify( + &mut self, + _wm: &mut (impl WindowManager + ?Sized), + _event: xlib::XCrossingEvent, + ) { //print_event!(wm, event); // if let Some(client_rc) = Self::client_by_frame(wm, event.window) { // println!("LeaveNotify on frame for client {}", client_rc.borrow().window()); @@ -573,7 +750,11 @@ impl X11Backend { // } } - fn on_unmap_notify(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XUnmapEvent) { + fn on_unmap_notify( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XUnmapEvent, + ) { if self.remove_unmanaged_client(wm, event.window) { return; } @@ -593,14 +774,20 @@ impl X11Backend { if event.event == root || client_rc.borrow().is_reparenting() { client_rc.borrow_mut().set_reparenting(false); } else if event.send_event == xlib::True { - client_rc.borrow_mut().x11_set_state(self.display, WITHDRAWN_STATE); + client_rc + .borrow_mut() + .x11_set_state(self.display, WITHDRAWN_STATE); } else { - client_rc.borrow_mut().hide(); + client_rc.borrow_mut().hide(); self.unmanage(wm, client_rc); } } - fn on_map_request(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XMapRequestEvent) { + fn on_map_request( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XMapRequestEvent, + ) { //print_event!(wm, event); let already_managed = wm.clients().any(|c| c.borrow().window() == event.window); if !already_managed { @@ -608,18 +795,37 @@ impl X11Backend { } } - fn on_map_notify(&mut self, _wm: &mut (impl WindowManager + ?Sized), _event: xlib::XMapEvent) { + fn on_map_notify( + &mut self, + _wm: &mut (impl WindowManager + ?Sized), + _event: xlib::XMapEvent, + ) { //print_event!(wm, event); } - pub fn on_property_notify(&mut self, wm: &mut (impl WindowManager + ?Sized), event: xlib::XPropertyEvent) { + pub fn on_property_notify( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + event: xlib::XPropertyEvent, + ) { if let Some(client_rc) = Self::client_by_window(wm, event.window) && let Some(atom) = X11Atom::from_xlib_atom(self.display, event.atom) - && atom == WMName { client_rc.borrow_mut().update_title() } + && atom == WMName + { + client_rc.borrow_mut().update_title() + } } - fn remove_unmanaged_client(&mut self, wm: &mut (impl WindowManager + ?Sized), window: xlib::Window) -> bool { - if let Some(index) = self.unmanaged_clients.iter().position(|u| u.window() == window) { + fn remove_unmanaged_client( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + window: xlib::Window, + ) -> bool { + if let Some(index) = self + .unmanaged_clients + .iter() + .position(|u| u.window() == window) + { let unmanaged = self.unmanaged_clients.swap_remove(index); // reconfigure insets for monitors @@ -635,12 +841,20 @@ impl X11Backend { } fn set_supported_atoms(&mut self, supported_atoms: &[X11Atom]) { - let atom_vec: Vec = (*supported_atoms).iter().map(|a| a.to_xlib_atom(self.display)).collect(); + let atom_vec: Vec = (*supported_atoms) + .iter() + .map(|a| a.to_xlib_atom(self.display)) + .collect(); let data = atom_vec.as_slice(); - self.root.x11_replace_property_long(self.display, NetSupported, xlib::XA_ATOM, data) + self.root + .x11_replace_property_long(self.display, NetSupported, xlib::XA_ATOM, data) } - fn unmanage(&mut self, wm: &mut (impl WindowManager + ?Sized), client_rc: Rc>>) { + fn unmanage( + &mut self, + wm: &mut (impl WindowManager + ?Sized), + client_rc: Rc>>, + ) { // eprintln!("Closing client: {}", client_rc.borrow().name()); // tell window manager to drop client @@ -658,13 +872,24 @@ impl X11Backend { window.x11_replace_property_long(self.display, WMState, wm_state_atom, &data); } - - fn client_by_frame(wm: &(impl WindowManager + ?Sized), frame: u64) -> Option>>> { - return wm.clients().find(|c| c.borrow().frame() == frame || c.borrow().title_window() == Some(frame)).cloned(); + fn client_by_frame( + wm: &(impl WindowManager + ?Sized), + frame: u64, + ) -> Option>>> { + return wm + .clients() + .find(|c| c.borrow().frame() == frame || c.borrow().title_window() == Some(frame)) + .cloned(); } - fn client_by_window(wm: &(impl WindowManager + ?Sized), window: u64) -> Option>>> { - return wm.clients().find(|c| c.borrow().window() == window).cloned(); + fn client_by_window( + wm: &(impl WindowManager + ?Sized), + window: u64, + ) -> Option>>> { + return wm + .clients() + .find(|c| c.borrow().window() == window) + .cloned(); } } @@ -672,11 +897,14 @@ impl XRandrInfo { pub fn query(display: *mut xlib::Display) -> XRandrInfo { let mut event_base = 0; let mut error_base = 0; - let supported = unsafe { - xrandr::XRRQueryExtension(display, &mut event_base, &mut error_base) != 0 - }; + let supported = + unsafe { xrandr::XRRQueryExtension(display, &mut event_base, &mut error_base) != 0 }; - XRandrInfo { supported, event_base, _error_base: error_base } + XRandrInfo { + supported, + event_base, + _error_base: error_base, + } } } @@ -689,24 +917,41 @@ impl Backend for X11Backend { None => XLIB_NONE, }; let data = &[window]; - self.root.x11_replace_property_long(self.display, NetActiveWindow, xlib::XA_WINDOW, data); + self.root + .x11_replace_property_long(self.display, NetActiveWindow, xlib::XA_WINDOW, data); } - fn export_client_list(&self, clients: Vec<&Rc>>, - clients_stacked: Vec<&Rc>>) { + fn export_client_list( + &self, + clients: Vec<&Rc>>, + clients_stacked: Vec<&Rc>>, + ) { let data_vec: Vec = clients.iter().map(|c| c.borrow().window()).collect(); - let data_stacked_vec: Vec = clients_stacked.iter().map(|c| c.borrow().window()).collect(); + let data_stacked_vec: Vec = clients_stacked + .iter() + .map(|c| c.borrow().window()) + .collect(); let data = data_vec.as_slice(); let data_stacked = data_stacked_vec.as_slice(); - self.root.x11_replace_property_long(self.display, NetClientList, xlib::XA_WINDOW, data); - self.root.x11_replace_property_long(self.display, NetClientListStacking, xlib::XA_WINDOW, data_stacked); - + self.root + .x11_replace_property_long(self.display, NetClientList, xlib::XA_WINDOW, data); + self.root.x11_replace_property_long( + self.display, + NetClientListStacking, + xlib::XA_WINDOW, + data_stacked, + ); } fn export_current_workspace(&self, workspace_idx: u32) { let idx: u64 = workspace_idx.into(); let data = &[idx]; - self.root.x11_replace_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL, data); + self.root.x11_replace_property_long( + self.display, + NetCurrentDesktop, + xlib::XA_CARDINAL, + data, + ); } fn export_workspaces(&self, mut workspaces: Vec<(String, Dimensions, Dimensions)>) { @@ -725,14 +970,21 @@ impl Backend for X11Backend { // export number of workspaces let data = &[nworkspaces]; - self.root.x11_replace_property_long(self.display, NetNumberOfDesktops, xlib::XA_CARDINAL, data); + self.root.x11_replace_property_long( + self.display, + NetNumberOfDesktops, + xlib::XA_CARDINAL, + data, + ); // export workspace names - self.root.x11_set_text_list_property(self.display, NetDesktopNames, &names); + self.root + .x11_set_text_list_property(self.display, NetDesktopNames, &names); // export workareas let data = workareas.as_slice(); - self.root.x11_replace_property_long(self.display, NetWorkarea, xlib::XA_CARDINAL, data); + self.root + .x11_replace_property_long(self.display, NetWorkarea, xlib::XA_CARDINAL, data); } fn get_monitor_config(&self) -> Vec { @@ -747,12 +999,21 @@ impl Backend for X11Backend { let mut top_level_windows: *mut xlib::Window = ptr::null_mut(); let mut num_top_level_windows: u32 = 0; - let windows = match xlib::XQueryTree(self.display, self.root, - &mut returned_root, &mut returned_parent, - &mut top_level_windows, &mut num_top_level_windows) { + let windows = match xlib::XQueryTree( + self.display, + self.root, + &mut returned_root, + &mut returned_parent, + &mut top_level_windows, + &mut num_top_level_windows, + ) { 0 => Err(()), - _ => Ok(slice::from_raw_parts(top_level_windows, num_top_level_windows.try_into().unwrap())), - }.expect("Unable to query x window tree"); + _ => Ok(slice::from_raw_parts( + top_level_windows, + num_top_level_windows.try_into().unwrap(), + )), + } + .expect("Unable to query x window tree"); // closure to check and manage windows let display = self.display; @@ -767,10 +1028,16 @@ impl Backend for X11Backend { }; // manage non-transient windows first - windows.iter().filter(|w| w.x11_is_transient_for(display).is_none()) - .filter(check_manage_window).for_each(|w| self.manage(wm, *w)); - windows.iter().filter(|w| w.x11_is_transient_for(display).is_some()) - .filter(check_manage_window).for_each(|w| self.manage(wm, *w)); + windows + .iter() + .filter(|w| w.x11_is_transient_for(display).is_none()) + .filter(check_manage_window) + .for_each(|w| self.manage(wm, *w)); + windows + .iter() + .filter(|w| w.x11_is_transient_for(display).is_some()) + .filter(check_manage_window) + .for_each(|w| self.manage(wm, *w)); println!("Initially managed {} windows", windows.len()); @@ -779,13 +1046,27 @@ impl Backend for X11Backend { } } - fn mouse_action + ?Sized>(&mut self, wm: &mut WM, client_rc: Rc>, - cursor_type: u32, action: MouseActionFn) { + fn mouse_action + ?Sized>( + &mut self, + wm: &mut WM, + client_rc: Rc>, + cursor_type: u32, + action: MouseActionFn, + ) { unsafe { // grab pointer let cursor = xlib::XCreateFontCursor(self.display, cursor_type); - let success = xlib::XGrabPointer(self.display, self.root, xlib::False, MOUSEMASK as u32, - xlib::GrabModeAsync, xlib::GrabModeAsync, XLIB_NONE, cursor, xlib::CurrentTime); + let success = xlib::XGrabPointer( + self.display, + self.root, + xlib::False, + MOUSEMASK as u32, + xlib::GrabModeAsync, + xlib::GrabModeAsync, + XLIB_NONE, + cursor, + xlib::CurrentTime, + ); if success != xlib::GrabSuccess { xlib::XFreeCursor(self.display, cursor); return; @@ -798,7 +1079,11 @@ impl Backend for X11Backend { let mut event: MaybeUninit = MaybeUninit::uninit(); loop { - xlib::XMaskEvent(self.display, MOUSEMASK | xlib::ExposureMask | xlib::SubstructureRedirectMask, event.as_mut_ptr()); + xlib::XMaskEvent( + self.display, + MOUSEMASK | xlib::ExposureMask | xlib::SubstructureRedirectMask, + event.as_mut_ptr(), + ); let event = event.assume_init(); if event.get_type() == xlib::MotionNotify { @@ -809,20 +1094,32 @@ impl Backend for X11Backend { // cast event to XMotionEvent let event = event.motion; - let delta = (event.x_root - orig_pointer_pos.0, - event.y_root - orig_pointer_pos.1); + let delta = ( + event.x_root - orig_pointer_pos.0, + event.y_root - orig_pointer_pos.1, + ); let old_center = client_rc.borrow().center(); let old_mon = self.point_to_monitor(old_center); - action(self, wm, &client_rc, orig_client_pos, orig_client_size, delta); + action( + self, + wm, + &client_rc, + orig_client_pos, + orig_client_size, + delta, + ); if let Some(old_mon) = old_mon { let new_center = client_rc.borrow().center(); if let Some(new_mon) = self.point_to_monitor(new_center) - && old_mon != new_mon { - wm.client_switches_monitor(client_rc.clone(), new_mon); - } + && old_mon != new_mon + { + wm.client_switches_monitor(client_rc.clone(), new_mon); + } } - } else if event.get_type() == xlib::ButtonRelease || event.get_type() == xlib::ButtonPress { + } else if event.get_type() == xlib::ButtonRelease + || event.get_type() == xlib::ButtonPress + { break; } else { self.handle_xevent(wm, event); @@ -859,8 +1156,9 @@ impl Backend for X11Backend { if point.0 >= mon.dimensions().x() && point.0 < mon.dimensions().x() + mon.dimensions().w() as i32 && point.1 >= mon.dimensions().y() - && point.1 < mon.dimensions().y() + mon.dimensions().h() as i32 { - return Some(i as u32); + && point.1 < mon.dimensions().y() + mon.dimensions().h() as i32 + { + return Some(i as u32); } } None @@ -874,8 +1172,18 @@ impl Backend for X11Backend { let mut dui: u32 = 0; let mut dummy: xlib::Window = 0; - if xlib::XQueryPointer(self.display, self.root, &mut dummy, &mut dummy, &mut x, &mut y, - &mut di, &mut di, &mut dui) == xlib::True { + if xlib::XQueryPointer( + self.display, + self.root, + &mut dummy, + &mut dummy, + &mut x, + &mut y, + &mut di, + &mut di, + &mut dui, + ) == xlib::True + { (x, y) } else { panic!("Cannot find pointer"); @@ -890,7 +1198,12 @@ impl Backend for X11Backend { } unsafe { - xlib::XSetInputFocus(self.display, client.window(), xlib::RevertToPointerRoot, xlib::CurrentTime); + xlib::XSetInputFocus( + self.display, + client.window(), + xlib::RevertToPointerRoot, + xlib::CurrentTime, + ); } } diff --git a/libmars/src/platforms/x11/wm/client.rs b/libmars/src/platforms/x11/wm/client.rs index 8d6de9f5..31621246 100644 --- a/libmars/src/platforms/x11/wm/client.rs +++ b/libmars/src/platforms/x11/wm/client.rs @@ -1,22 +1,15 @@ extern crate x11; use std::cmp; -use std::ffi::*; use x11::xlib; use crate::common::error::*; use crate::common::*; use crate::interfaces::wm::*; use crate::platforms::x11::{ - draw::widget::*, - misc::*, - misc::atoms::*, - misc::atoms::X11Atom::*, - misc::window::*, - wm::*, + draw::widget::*, misc::atoms::X11Atom::*, misc::atoms::*, misc::window::*, misc::*, wm::*, }; - type Decoration = (u32, u32, (u32, u32, u32, u32)); pub struct X11Client { @@ -29,10 +22,13 @@ pub struct X11Client { attributes: A, orig_pos: (i32, i32), // position prior to reparenting - x: i32, y: i32, // x, y position - w: u32, h: u32, // width, height - ibw: u32, obw: u32, // inner and outer border width - fw: (u32, u32, u32, u32), // frame width + x: i32, + y: i32, // x, y position + w: u32, + h: u32, // width, height + ibw: u32, + obw: u32, // inner and outer border width + fw: (u32, u32, u32, u32), // frame width actively_reparenting: bool, dont_decorate: bool, @@ -46,21 +42,33 @@ pub struct X11Client { } impl X11Client { - pub fn new(display: *mut xlib::Display, root: u64, window: xlib::Window, is_dialog: bool) -> Result> { + pub fn new( + display: *mut xlib::Display, + root: u64, + window: xlib::Window, + is_dialog: bool, + ) -> Result> { let attributes = window.x11_attributes(display)?; let x = attributes.x; let y = attributes.y; let w: u32 = attributes.width.try_into().unwrap(); let h: u32 = attributes.height.try_into().unwrap(); - // create frame window and reparent the original window let frame = unsafe { - let frame = xlib:: XCreateSimpleWindow(display, root, x, y, w, h, 0, 0, 0); - xlib::XSelectInput(display, frame, - xlib::SubstructureRedirectMask | xlib::SubstructureNotifyMask - | xlib::ButtonPressMask | xlib::PointerMotionMask | xlib::ButtonReleaseMask - | xlib::ButtonMotionMask | xlib::EnterWindowMask | xlib::LeaveWindowMask); + let frame = xlib::XCreateSimpleWindow(display, root, x, y, w, h, 0, 0, 0); + xlib::XSelectInput( + display, + frame, + xlib::SubstructureRedirectMask + | xlib::SubstructureNotifyMask + | xlib::ButtonPressMask + | xlib::PointerMotionMask + | xlib::ButtonReleaseMask + | xlib::ButtonMotionMask + | xlib::EnterWindowMask + | xlib::LeaveWindowMask, + ); xlib::XAddToSaveSet(display, window); xlib::XReparentWindow(display, window, frame, 0, 0); xlib::XResizeWindow(display, window, w, h); @@ -69,7 +77,11 @@ impl X11Client { }; unsafe { - xlib::XSelectInput(display, window, xlib::EnterWindowMask | xlib::LeaveWindowMask | xlib::PropertyChangeMask); + xlib::XSelectInput( + display, + window, + xlib::EnterWindowMask | xlib::LeaveWindowMask | xlib::PropertyChangeMask, + ); } let name = match window.x11_class_hint(display) { @@ -77,17 +89,23 @@ impl X11Client { Err(msg) => { println!("Unable to get class hint: {}", msg); format!("0x{:x}", window) - }, + } }; - Ok( X11Client { + Ok(X11Client { name, - display, root, window, frame, + display, + root, + window, + frame, title_widget: None, attributes: A::default(), orig_pos: (x, y), - x, y, w, h, + x, + y, + w, + h, ibw: 0, obw: 0, fw: (0, 0, 0, 0), @@ -101,7 +119,7 @@ impl X11Client { frame_color: 0x000000, saved_decorations: None, saved_dimensions: None, - } ) + }) } } @@ -110,11 +128,12 @@ impl X11Client { let motif_atom = MotifWMHints.to_xlib_atom(self.display); if let Ok(hints) = self.x11_read_property_long(self.display, MotifWMHints, motif_atom) && hints[MWM_HINTS_FLAGS_FIELD] & MWM_HINTS_DECORATIONS != 0 - && hints[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_ALL == 0 - && hints[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_BORDER == 0 - && hints[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_TITLE == 0 { - self.dont_decorate = true; - } + && hints[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_ALL == 0 + && hints[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_BORDER == 0 + && hints[MWM_HINTS_DECORATIONS_FIELD] & MWM_DECOR_TITLE == 0 + { + self.dont_decorate = true; + } } pub fn apply_size_hints(&mut self) { @@ -178,7 +197,8 @@ impl X11Client { self.h = (self.w as f32 * mina + 0.5) as u32; } } - if basew >= minw && baseh > minh { // required for increment calculation + if basew >= minw && baseh > minh { + // required for increment calculation self.w -= basew; self.h -= baseh; } @@ -256,8 +276,15 @@ impl Client for X11Client { fn add_title(&mut self, font: &str, hpad: u32, vpad: u32, color: u64) -> Result<()> { let title = self.title(); let params = X11WidgetParams::new(0, 0, hpad, vpad); - let mut widget = X11TextWidget::new(self.display, self.frame, params, - title.clone(), font, color, self.frame_color)?; + let mut widget = X11TextWidget::new( + self.display, + self.frame, + params, + title.clone(), + font, + color, + self.frame_color, + )?; unsafe { xlib::XLowerWindow(self.display, widget.wid()); widget.set_label(title); @@ -284,19 +311,32 @@ impl Client for X11Client { fn bind_button(&mut self, modifiers: u32, button: u32, target: ButtonTarget) { let mask: u32 = (xlib::ButtonPressMask | xlib::ButtonReleaseMask | xlib::ButtonMotionMask) - .try_into().unwrap(); + .try_into() + .unwrap(); let window = match target { ButtonTarget::Window => self.window, // ButtonTarget::Frame => self.frame, - ButtonTarget::Frame => return, // already grabbed as we own the window - ButtonTarget::Root => panic!("You can't bind actions to the root window through a client window"), + ButtonTarget::Frame => return, // already grabbed as we own the window + ButtonTarget::Root => { + panic!("You can't bind actions to the root window through a client window") + } }; for modifiers in alternative_modifiers(modifiers) { unsafe { - xlib::XGrabButton(self.display, button, modifiers, window, xlib::False, mask, - xlib::GrabModeAsync, xlib::GrabModeAsync, window, 0); + xlib::XGrabButton( + self.display, + button, + modifiers, + window, + xlib::False, + mask, + xlib::GrabModeAsync, + xlib::GrabModeAsync, + window, + 0, + ); } } } @@ -305,17 +345,27 @@ impl Client for X11Client { unsafe { let keycode = xlib::XKeysymToKeycode(self.display, key.into()); for modifiers in alternative_modifiers(modifiers) { - xlib::XGrabKey(self.display, keycode.into(), modifiers, self.frame, xlib::False, - xlib::GrabModeAsync, xlib::GrabModeAsync); + xlib::XGrabKey( + self.display, + keycode.into(), + modifiers, + self.frame, + xlib::False, + xlib::GrabModeAsync, + xlib::GrabModeAsync, + ); } } } fn center_on_screen(&mut self, dimensions: Dimensions) { let (center_x, center_y) = dimensions.center(); - self.move_resize(center_x - (self.w as i32 / 2), + self.move_resize( + center_x - (self.w as i32 / 2), center_y - (self.h as i32 / 2), - self.w(), self.h()) + self.w(), + self.h(), + ) } fn close(&self) { @@ -327,9 +377,16 @@ impl Client for X11Client { } fn export_pinned(&self, state: bool, workspace_idx: Option) { - let idx: u64 = if state { 0xffffffff } else { workspace_idx.expect("Need workspace index to unpin window").into() }; + let idx: u64 = if state { + 0xffffffff + } else { + workspace_idx + .expect("Need workspace index to unpin window") + .into() + }; let data = &[idx]; - self.window.x11_replace_property_long(self.display, NetWMDesktop, xlib::XA_CARDINAL, data); + self.window + .x11_replace_property_long(self.display, NetWMDesktop, xlib::XA_CARDINAL, data); } fn export_tiled(&self, state: bool) { @@ -343,7 +400,8 @@ impl Client for X11Client { fn export_workspace(&self, workspace_idx: u32) { let idx: u64 = workspace_idx.into(); let data = &[idx]; - self.window.x11_replace_property_long(self.display, NetWMDesktop, xlib::XA_CARDINAL, data); + self.window + .x11_replace_property_long(self.display, NetWMDesktop, xlib::XA_CARDINAL, data); } fn frame_width(&self) -> (u32, u32, u32, u32) { @@ -361,8 +419,16 @@ impl Client for X11Client { let fa = self.frame.x11_attributes(self.display).unwrap(); let ra = self.root.x11_attributes(self.display).unwrap(); // prevent UnmapNotify events - xlib::XSelectInput(self.display, self.root, ra.your_event_mask & !xlib::SubstructureNotifyMask); - xlib::XSelectInput(self.display, self.frame, fa.your_event_mask & !xlib::StructureNotifyMask & !xlib::SubstructureNotifyMask); + xlib::XSelectInput( + self.display, + self.root, + ra.your_event_mask & !xlib::SubstructureNotifyMask, + ); + xlib::XSelectInput( + self.display, + self.frame, + fa.your_event_mask & !xlib::StructureNotifyMask & !xlib::SubstructureNotifyMask, + ); xlib::XUnmapWindow(self.display, self.frame); xlib::XUnmapWindow(self.display, self.window); // @TODO set IconicState (see moonwm - window_set_state(dpy, win, IconicState)) @@ -382,17 +448,18 @@ impl Client for X11Client { fn inner_dimensions(&self) -> Dimensions { let (fw_north, fw_east, _, _) = self.fw; let (bw_north, bw_east, bw_south, bw_west) = self.total_bw(); - Dimensions::new(fw_east.try_into().unwrap(), - fw_north.try_into().unwrap(), - self.w - bw_east - bw_west, - self.h - bw_north - bw_south) + Dimensions::new( + fw_east.try_into().unwrap(), + fw_north.try_into().unwrap(), + self.w - bw_east - bw_west, + self.h - bw_north - bw_south, + ) } fn is_centered_on_screen(&self, dimensions: Dimensions) -> bool { let (center_x, center_y) = dimensions.center(); - self.x == center_x - (self.w as i32 / 2) - && self.y == center_y - (self.h as i32 / 2) + self.x == center_x - (self.w as i32 / 2) && self.y == center_y - (self.h as i32 / 2) } fn is_dialog(&self) -> bool { @@ -408,7 +475,7 @@ impl Client for X11Client { } fn move_resize(&mut self, x: i32, y: i32, width: u32, height: u32) { - let min_size = 2*self.obw + WINDOW_MIN_SIZE; + let min_size = 2 * self.obw + WINDOW_MIN_SIZE; if width < min_size { self.move_resize(x, y, min_size, height); return; @@ -424,11 +491,22 @@ impl Client for X11Client { let inner_dimensions = self.inner_dimensions(); unsafe { - xlib::XMoveResizeWindow(self.display, self.frame, self.x, self.y, - self.w - 2*self.obw, self.h - 2 * self.obw); - xlib::XMoveResizeWindow(self.display, self.window, - inner_dimensions.x(), inner_dimensions.y(), - inner_dimensions.w(), inner_dimensions.h()); + xlib::XMoveResizeWindow( + self.display, + self.frame, + self.x, + self.y, + self.w - 2 * self.obw, + self.h - 2 * self.obw, + ); + xlib::XMoveResizeWindow( + self.display, + self.window, + inner_dimensions.x(), + inner_dimensions.y(), + inner_dimensions.w(), + inner_dimensions.h(), + ); } } @@ -447,7 +525,12 @@ impl Client for X11Client { } fn set_dimensions(&mut self, dimensions: Dimensions) { - self.move_resize(dimensions.x(), dimensions.y(), dimensions.w(), dimensions.h()) + self.move_resize( + dimensions.x(), + dimensions.y(), + dimensions.w(), + dimensions.h(), + ) } fn set_frame_color(&mut self, color: u64) { @@ -469,7 +552,12 @@ impl Client for X11Client { let diff_south = (width.2 as i32) - (self.fw.2 as i32); let diff_west = (width.3 as i32) - (self.fw.3 as i32); self.fw = width; - self.move_resize(self.x - diff_west, self.y - diff_north, (self.w as i32 + diff_east + diff_west) as u32, (self.h as i32 + diff_north + diff_south) as u32); + self.move_resize( + self.x - diff_west, + self.y - diff_north, + (self.w as i32 + diff_east + diff_west) as u32, + (self.h as i32 + diff_north + diff_south) as u32, + ); } fn set_fullscreen(&mut self, monitor_conf: &MonitorConfig) { @@ -478,7 +566,12 @@ impl Client for X11Client { self.fullscreen = true; self.x11_net_wm_state_add(self.display, NetWMStateFullscreen); self.remove_decoration(); - self.move_resize(dimensions.x(), dimensions.y(), dimensions.w(), dimensions.h()); + self.move_resize( + dimensions.x(), + dimensions.y(), + dimensions.w(), + dimensions.h(), + ); self.raise(); } @@ -492,7 +585,12 @@ impl Client for X11Client { unsafe { xlib::XSetWindowBorderWidth(self.display, self.window, self.ibw); } - self.move_resize(self.x - diff, self.y - diff, (self.w as i32 + 2 * diff) as u32, (self.h as i32 + 2 * diff) as u32); + self.move_resize( + self.x - diff, + self.y - diff, + (self.w as i32 + 2 * diff) as u32, + (self.h as i32 + 2 * diff) as u32, + ); } fn set_inner_color(&mut self, color: u64) { @@ -507,7 +605,12 @@ impl Client for X11Client { unsafe { xlib::XSetWindowBorderWidth(self.display, self.frame, self.obw); } - self.move_resize(self.x - diff, self.y - diff, (self.w as i32 + 2 * diff) as u32, (self.h as i32 + 2 * diff) as u32); + self.move_resize( + self.x - diff, + self.y - diff, + (self.w as i32 + 2 * diff) as u32, + (self.h as i32 + 2 * diff) as u32, + ); } fn set_outer_color(&mut self, color: u64) { @@ -531,7 +634,12 @@ impl Client for X11Client { xlib::XMapWindow(self.display, self.window); xlib::XMapWindow(self.display, self.frame); self.x11_set_state(self.display, NORMAL_STATE); - xlib::XSetInputFocus(self.display, self.frame, xlib::RevertToPointerRoot, xlib::CurrentTime); + xlib::XSetInputFocus( + self.display, + self.frame, + xlib::RevertToPointerRoot, + xlib::CurrentTime, + ); } self.visible = true; @@ -542,10 +650,12 @@ impl Client for X11Client { } fn total_bw(&self) -> (u32, u32, u32, u32) { - (self.ibw + self.fw.0 + self.obw, - self.ibw + self.fw.1 + self.obw, - self.ibw + self.fw.2 + self.obw, - self.ibw + self.fw.3 + self.obw) + ( + self.ibw + self.fw.0 + self.obw, + self.ibw + self.fw.1 + self.obw, + self.ibw + self.fw.2 + self.obw, + self.ibw + self.fw.3 + self.obw, + ) } fn unset_fullscreen(&mut self) { @@ -553,7 +663,12 @@ impl Client for X11Client { self.fullscreen = false; self.x11_net_wm_state_remove(self.display, NetWMStateFullscreen); self.restore_decoration(); - self.move_resize(dimensions.x(), dimensions.y(), dimensions.w(), dimensions.h()); + self.move_resize( + dimensions.x(), + dimensions.y(), + dimensions.w(), + dimensions.h(), + ); self.saved_dimensions = None; } } @@ -578,12 +693,24 @@ impl Client for X11Client { } impl Dimensioned for X11Client { - fn x(&self) -> i32 { self.x } - fn y(&self) -> i32 { self.y } - fn w(&self) -> u32 { self.w } - fn h(&self) -> u32 { self.h } - fn pos(&self) -> (i32, i32) { (self.x, self.y) } - fn size(&self) -> (u32, u32) { (self.w, self.h) } + fn x(&self) -> i32 { + self.x + } + fn y(&self) -> i32 { + self.y + } + fn w(&self) -> u32 { + self.w + } + fn h(&self) -> u32 { + self.h + } + fn pos(&self) -> (i32, i32) { + (self.x, self.y) + } + fn size(&self) -> (u32, u32) { + (self.w, self.h) + } fn set_x(&mut self, x: i32) { self.x = x; @@ -615,7 +742,9 @@ impl Dimensioned for X11Client { self.move_resize(self.x, self.y, self.w, self.h); } - fn dimensions(&self) -> Dimensions { Dimensions::new(self.x, self.y, self.w, self.h) } + fn dimensions(&self) -> Dimensions { + Dimensions::new(self.x, self.y, self.w, self.h) + } } impl Drop for X11Client { @@ -623,7 +752,13 @@ impl Drop for X11Client { unsafe { // These generate xlib errors if the window is already unmapped xlib::XSetErrorHandler(Some(on_error_dummy)); - xlib::XReparentWindow(self.display, self.window, self.root, self.orig_pos.0, self.orig_pos.1); + xlib::XReparentWindow( + self.display, + self.window, + self.root, + self.orig_pos.0, + self.orig_pos.1, + ); if self.visible { xlib::XMapWindow(self.display, self.window); } @@ -651,8 +786,13 @@ impl X11Window for X11Client { self.window.x11_class_hint(display) } - fn x11_close(&self, display: *mut xlib::Display, - error_handler: Option c_int>) { + fn x11_close( + &self, + display: *mut xlib::Display, + error_handler: Option< + unsafe extern "C" fn(_: *mut xlib::Display, _: *mut xlib::XErrorEvent) -> c_int, + >, + ) { self.window.x11_close(display, error_handler); } @@ -670,7 +810,11 @@ impl X11Window for X11Client { self.window.x11_get_state(display) } - fn x11_get_text_list_property(&self, display: *mut xlib::Display, property: X11Atom) -> Result> { + fn x11_get_text_list_property( + &self, + display: *mut xlib::Display, + property: X11Atom, + ) -> Result> { self.window.x11_get_text_list_property(display, property) } @@ -686,31 +830,57 @@ impl X11Window for X11Client { self.window.x11_net_wm_state_remove(display, state); } - fn x11_read_property_long(&self, display: *mut xlib::Display, property: X11Atom, prop_type: c_ulong) -> Result> { - self.window.x11_read_property_long(display, property, prop_type) + fn x11_read_property_long( + &self, + display: *mut xlib::Display, + property: X11Atom, + prop_type: c_ulong, + ) -> Result> { + self.window + .x11_read_property_long(display, property, prop_type) } - fn x11_read_property_string(&self, display: *mut xlib::Display, property: X11Atom) -> Result { + fn x11_read_property_string( + &self, + display: *mut xlib::Display, + property: X11Atom, + ) -> Result { self.window.x11_read_property_string(display, property) } - fn x11_replace_property_long(&self, display: *mut xlib::Display, property: X11Atom, prop_type: c_ulong, data: &[c_ulong]) { - self.window.x11_replace_property_long(display, property, prop_type, data); + fn x11_replace_property_long( + &self, + display: *mut xlib::Display, + property: X11Atom, + prop_type: c_ulong, + data: &[c_ulong], + ) { + self.window + .x11_replace_property_long(display, property, prop_type, data); } fn x11_set_state(&self, display: *mut xlib::Display, state: i32) { self.window.x11_set_state(display, state); } - fn x11_set_text_list_property(&self, display: *mut xlib::Display, property: X11Atom, list: &[String]) { - self.window.x11_set_text_list_property(display, property, list); + fn x11_set_text_list_property( + &self, + display: *mut xlib::Display, + property: X11Atom, + list: &[String], + ) { + self.window + .x11_set_text_list_property(display, property, list); } fn x11_dimensions(&self, display: *mut xlib::Display) -> Result { self.frame.x11_dimensions(display) } - fn x11_geometry(&self, display: *mut xlib::Display) -> Result<(u64, i32, i32, u32, u32, u32, u32)> { + fn x11_geometry( + &self, + display: *mut xlib::Display, + ) -> Result<(u64, i32, i32, u32, u32, u32, u32)> { self.frame.x11_geometry(display) } @@ -726,8 +896,15 @@ impl X11Window for X11Client { self.window.x11_map(display); } - fn x11_message(&self, display: *mut xlib::Display, msg_type: atoms::X11Atom, msg_format: c_int, msg_data: xlib::ClientMessageData) { - self.window.x11_message(display, msg_type, msg_format, msg_data) + fn x11_message( + &self, + display: *mut xlib::Display, + msg_type: atoms::X11Atom, + msg_format: c_int, + msg_data: xlib::ClientMessageData, + ) { + self.window + .x11_message(display, msg_type, msg_format, msg_data) } fn x11_supports_protocol(&self, display: *mut xlib::Display, protocol: X11Atom) -> bool { @@ -746,7 +923,10 @@ impl X11Window for X11Client { self.window.x11_wm_name(display) } - fn x11_wm_normal_hints(&self, display: *mut xlib::Display) -> Result<(xlib::XSizeHints, c_long)> { + fn x11_wm_normal_hints( + &self, + display: *mut xlib::Display, + ) -> Result<(xlib::XSizeHints, c_long)> { self.window.x11_wm_normal_hints(display) } } diff --git a/libmars/src/platforms/x11/wm/mod.rs b/libmars/src/platforms/x11/wm/mod.rs index 6c3f66c9..e91f671c 100644 --- a/libmars/src/platforms/x11/wm/mod.rs +++ b/libmars/src/platforms/x11/wm/mod.rs @@ -1,5 +1,5 @@ -use x11::xlib; use std::ffi::*; +use x11::xlib; pub mod backend; mod client; @@ -13,8 +13,12 @@ extern "C" fn on_error(display: *mut xlib::Display, error: *mut xlib::XErrorEven let msg = unsafe { let bufsize = 1024; let mut buf: Vec = vec![0; bufsize]; - xlib::XGetErrorText(display, (*error).error_code.into(), buf.as_mut_ptr(), - (bufsize - 1) as c_int); + xlib::XGetErrorText( + display, + (*error).error_code.into(), + buf.as_mut_ptr(), + (bufsize - 1) as c_int, + ); let msg_cstring = CStr::from_ptr(buf.as_mut_ptr()); msg_cstring.to_str().unwrap().to_owned() // println!("{}", msg); @@ -22,10 +26,26 @@ extern "C" fn on_error(display: *mut xlib::Display, error: *mut xlib::XErrorEven unsafe { match (*error).error_code { - xlib::Success => println!("X11 non-error: {} (request code: {})", msg, (*error).request_code), - xlib::BadMatch => println!("X11 error: {} (request code: {})", msg, (*error).request_code), - xlib::BadWindow => println!("X11 error: {} (request code: {})", msg, (*error).request_code), - _ => panic!("Fatal X11 error: {} (request code: {})", msg, (*error).request_code), + xlib::Success => println!( + "X11 non-error: {} (request code: {})", + msg, + (*error).request_code + ), + xlib::BadMatch => println!( + "X11 error: {} (request code: {})", + msg, + (*error).request_code + ), + xlib::BadWindow => println!( + "X11 error: {} (request code: {})", + msg, + (*error).request_code + ), + _ => panic!( + "Fatal X11 error: {} (request code: {})", + msg, + (*error).request_code + ), } } diff --git a/libmars/src/platforms/x11/wm/unmanaged.rs b/libmars/src/platforms/x11/wm/unmanaged.rs index 75366a3b..cf507456 100644 --- a/libmars/src/platforms/x11/wm/unmanaged.rs +++ b/libmars/src/platforms/x11/wm/unmanaged.rs @@ -1,9 +1,11 @@ -use x11::xlib; use crate::platforms::x11::misc::window::X11Window; +use x11::xlib; #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum UnmanagedType { - Desktop, Dock, Notification, + Desktop, + Dock, + Notification, } pub struct UnmanagedClient { @@ -13,8 +15,16 @@ pub struct UnmanagedClient { } impl UnmanagedClient { - pub fn new(display: *mut xlib::Display, window: xlib::Window, client_type: UnmanagedType) -> Self { - let unmanaged = UnmanagedClient { display, window, client_type }; + pub fn new( + display: *mut xlib::Display, + window: xlib::Window, + client_type: UnmanagedType, + ) -> Self { + let unmanaged = UnmanagedClient { + display, + window, + client_type, + }; window.x11_map(display); unmanaged.restack(); @@ -29,8 +39,12 @@ impl UnmanagedClient { unsafe { use UnmanagedType::*; match self.client_type { - Desktop => { xlib::XLowerWindow(self.display, self.window); }, - Dock | Notification => { xlib::XRaiseWindow(self.display, self.window); }, + Desktop => { + xlib::XLowerWindow(self.display, self.window); + } + Dock | Notification => { + xlib::XRaiseWindow(self.display, self.window); + } } } } @@ -39,5 +53,3 @@ impl UnmanagedClient { self.window } } - - diff --git a/libmars/src/utils/configuration.rs b/libmars/src/utils/configuration.rs index a7265a1b..bdefc69e 100644 --- a/libmars/src/utils/configuration.rs +++ b/libmars/src/utils/configuration.rs @@ -1,9 +1,8 @@ -//! Loading configuration files using [serde_norway]. +//! Loading configuration files using [yaml_serde]. +use serde::{Deserialize, Serialize}; use std::fs; use std::path; -use serde::{Serialize, Deserialize}; - fn deserialize_file Deserialize<'a>>(path: &path::Path) -> Result { let fs_result = fs::read(path); @@ -12,7 +11,7 @@ fn deserialize_file Deserialize<'a>>(path: &path::Path) -> Result return Err((true, e.to_string())), }; - match serde_norway::from_slice(&raw) { + match yaml_serde::from_slice(&raw) { Ok(config) => Ok(config), Err(e) => Err((true, e.to_string())), } @@ -20,7 +19,7 @@ fn deserialize_file Deserialize<'a>>(path: &path::Path) -> Result println!("{}", ser), Err(e) => eprintln!("Error: {}", e), @@ -34,7 +33,10 @@ pub fn read_file Deserialize<'a>>(path: &path::Path) -> Result Deserialize<'a>>(path: &path::Path) -> Result Deserialize<'a>>(config_name: &str, file_name: &str) -> Result { +pub fn read_config_file Deserialize<'a>>( + config_name: &str, + file_name: &str, +) -> Result { let config_dir = xdg::BaseDirectories::with_prefix(config_name); if let Some(path) = config_dir.find_config_file(file_name) { deserialize_file(&path).map_err(|(_, msg)| msg) diff --git a/libmars/src/utils/macros.rs b/libmars/src/utils/macros.rs index dc6b106f..4b1466a0 100644 --- a/libmars/src/utils/macros.rs +++ b/libmars/src/utils/macros.rs @@ -1,4 +1,3 @@ - #[macro_export] macro_rules! count { () => (0usize); diff --git a/mars-relay/src/main.rs b/mars-relay/src/main.rs index 744f4eb5..3ab653e1 100644 --- a/mars-relay/src/main.rs +++ b/mars-relay/src/main.rs @@ -8,10 +8,8 @@ use x11::xlib; use crate::menu::*; - mod menu; - /// Sending commands to marswm and other window managers #[derive(Parser)] #[clap(author, version, about, long_about = None)] @@ -27,15 +25,19 @@ struct Args { } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::Args)] -pub struct Workspace { index: u32 } +pub struct Workspace { + index: u32, +} #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, clap::Args)] -pub struct Status { text: String } +pub struct Status { + text: String, +} #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, clap::Args)] pub struct ModifierShim { #[clap(value_enum)] - modifier: Option + modifier: Option, } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, clap::Subcommand)] @@ -78,12 +80,17 @@ pub enum Command { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] -pub enum Modifier { Set, Unset, Toggle } - +pub enum Modifier { + Set, + Unset, + Toggle, +} impl From for ModifierShim { fn from(value: Modifier) -> ModifierShim { - ModifierShim { modifier: Some(value) } + ModifierShim { + modifier: Some(value), + } } } @@ -97,8 +104,13 @@ impl From for SettingMode { } } -fn handle_window_setting(getter: G, setter: S, controller: &C, window: xlib::Window, opt: ModifierShim) - -> libmars::common::error::Result<()> +fn handle_window_setting( + getter: G, + setter: S, + controller: &C, + window: xlib::Window, + opt: ModifierShim, +) -> libmars::common::error::Result<()> where C: WMController, S: Fn(&C, xlib::Window, SettingMode) -> libmars::common::error::Result<()>, @@ -117,11 +129,13 @@ where } } - impl Command { - fn execute>(&self, controller: &C, window_result: Result, - args: Args) -> Result<(), String> { - + fn execute>( + &self, + controller: &C, + window_result: Result, + args: Args, + ) -> Result<(), String> { if *self == Command::Menu { Self::menu(controller, window_result, args) } else { @@ -129,31 +143,59 @@ impl Command { Command::Activate => controller.activate_window(window_result?), Command::Center => controller.center_window(window_result?), Command::Close => controller.close_window(window_result?), - Command::Fullscreen(mode) => handle_window_setting(C::window_is_fullscreen, C::fullscreen_window, controller, - window_result?, *mode), - Command::Pinned(mode) => handle_window_setting(C::window_is_pinned, C::pin_window, controller, window_result?, *mode), - Command::SendToWorkspace(ws) => controller.send_window_to_workspace(window_result?, ws.index), + Command::Fullscreen(mode) => handle_window_setting( + C::window_is_fullscreen, + C::fullscreen_window, + controller, + window_result?, + *mode, + ), + Command::Pinned(mode) => handle_window_setting( + C::window_is_pinned, + C::pin_window, + controller, + window_result?, + *mode, + ), + Command::SendToWorkspace(ws) => { + controller.send_window_to_workspace(window_result?, ws.index) + } Command::SetStatus(status) => controller.set_status(status.text.to_owned()), Command::SwitchWorkspace(ws) => controller.switch_workspace(ws.index), Command::SwitchWorkspaceNext => Self::switch_workspace_relative(controller, 1), Command::SwitchWorkspacePrev => Self::switch_workspace_relative(controller, -1), - Command::Tiled(mode) => handle_window_setting(C::window_is_tiled, C::tile_window, controller, window_result?, *mode), + Command::Tiled(mode) => handle_window_setting( + C::window_is_tiled, + C::tile_window, + controller, + window_result?, + *mode, + ), Command::Menu => panic!("unhandled command"), }; result.map_err(|e| e.to_string()) } } - fn menu(controller: &impl WMController, window_result: Result, args: Args) - -> Result<(), String> { + fn menu( + controller: &impl WMController, + window_result: Result, + args: Args, + ) -> Result<(), String> { let command = match display_menu() { Ok(cmd) => cmd, - Err(e) => { eprintln!("Error: {}", e); return Err("unable to display menu".to_owned()); }, + Err(e) => { + eprintln!("Error: {}", e); + return Err("unable to display menu".to_owned()); + } }; command.execute(controller, window_result, args) } - fn switch_workspace_relative(controller: &impl WMController, inc: i32) -> Result<(), MarsError> { + fn switch_workspace_relative( + controller: &impl WMController, + inc: i32, + ) -> Result<(), MarsError> { let workspace = controller.current_workspace()?; let nworkspaces = controller.count_workspaces()?; let new_workspace = (workspace + (nworkspaces as i32 + inc) as u32) % nworkspaces; @@ -169,13 +211,15 @@ fn main() { Err(e) => { eprintln!("Unable to initialise X11Controller: {}", e); std::process::exit(1); - }, + } }; let command = args.command.clone(); let window_result = match args.window { Some(window) => Ok(window), - None => controller.get_active_window().map_err(|_| "Unable to get active window".to_string()), + None => controller + .get_active_window() + .map_err(|_| "Unable to get active window".to_string()), }; if let Err(msg) = command.execute(&controller, window_result, args) { eprintln!("Error: {}", msg); diff --git a/mars-relay/src/menu.rs b/mars-relay/src/menu.rs index a15d4e17..00750d43 100644 --- a/mars-relay/src/menu.rs +++ b/mars-relay/src/menu.rs @@ -34,11 +34,8 @@ pub fn display_menu() -> Result { stdin.write_all(string.as_bytes()).unwrap(); }); - - let output = child.wait_with_output() - .map_err(|e| e.to_string())?; - let output = String::from_utf8_lossy(&output.stdout) - .to_string(); + let output = child.wait_with_output().map_err(|e| e.to_string())?; + let output = String::from_utf8_lossy(&output.stdout).to_string(); match output.trim() { "close" => Ok(Command::Close), diff --git a/marsbar/src/config.rs b/marsbar/src/config.rs index 7d1339bd..c7ff31b6 100644 --- a/marsbar/src/config.rs +++ b/marsbar/src/config.rs @@ -1,13 +1,12 @@ use libmars::platforms::x11::draw::widget::*; use libmars::utils::configuration::read_config_file; use libmars::utils::configuration::read_file; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use std::path; use x11::xlib; use crate::tray::*; - const CONFIG_NAME: &str = "marswm"; const CONFIG_FILE: &str = "marsbar.yaml"; @@ -15,8 +14,7 @@ const DEFAULT_FONT: &str = "serif"; const DEFAULT_TEXT_PADDING_HORZ: u32 = 5; const DEFAULT_TEXT_PADDING_VERT: u32 = 0; - -#[derive(Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[serde(default)] pub struct BarStyle { pub background: u64, @@ -28,7 +26,7 @@ pub struct BarStyle { pub status: ContainerWidgetStyle, } -#[derive(Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[serde(default)] pub struct TextWidgetStyle { pub foreground: u64, @@ -37,7 +35,7 @@ pub struct TextWidgetStyle { pub padding_vert: u32, } -#[derive(Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] pub struct ContainerWidgetStyle { pub foreground: u64, pub inner_background: u64, @@ -49,7 +47,7 @@ pub struct ContainerWidgetStyle { pub spacing: u32, } -#[derive(Default,Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Default, Serialize, Deserialize, PartialEq, Debug, Clone)] #[serde(default)] pub struct Configuration { pub status_cmd: Option, @@ -57,7 +55,6 @@ pub struct Configuration { pub style: BarStyle, } - impl Default for BarStyle { fn default() -> Self { BarStyle { @@ -78,31 +75,64 @@ impl Default for TextWidgetStyle { foreground: 0xbcbcbc, background: 0x262626, padding_horz: DEFAULT_TEXT_PADDING_HORZ, - padding_vert: DEFAULT_TEXT_PADDING_VERT + padding_vert: DEFAULT_TEXT_PADDING_VERT, } } } impl ContainerWidgetStyle { - pub fn create_flow_layout_widget(&self, display: *mut xlib::Display, parent: xlib::Window) - -> Result, String> { + pub fn create_flow_layout_widget( + &self, + display: *mut xlib::Display, + parent: xlib::Window, + ) -> Result, String> { let params = X11WidgetParams::new(0, 0, self.padding_horz, self.padding_vert); - X11FlowLayoutWidget::new(display, parent, params, self.spacing, Vec::new(), self.outer_background) - .map_err(|e| e.to_string()) + X11FlowLayoutWidget::new( + display, + parent, + params, + self.spacing, + Vec::new(), + self.outer_background, + ) + .map_err(|e| e.to_string()) } - pub fn create_text_widget(&self, display: *mut xlib::Display, parent: xlib::Window, font: &str) - -> Result { + pub fn create_text_widget( + &self, + display: *mut xlib::Display, + parent: xlib::Window, + font: &str, + ) -> Result { let params = X11WidgetParams::new(0, 0, self.text_padding_horz, self.text_padding_vert); - X11TextWidget::new(display, parent, params, "".to_string(), font, self.foreground, self.inner_background) - .map_err(|e| e.to_string()) + X11TextWidget::new( + display, + parent, + params, + "".to_string(), + font, + self.foreground, + self.inner_background, + ) + .map_err(|e| e.to_string()) } - pub fn create_systray_widget(&self, display: *mut xlib::Display, parent: xlib::Window, parent_height: u32) - -> Result { + pub fn create_systray_widget( + &self, + display: *mut xlib::Display, + parent: xlib::Window, + parent_height: u32, + ) -> Result { let params = X11WidgetParams::new(0, 0, self.padding_horz, self.padding_vert); - SystemTrayWidget::new(display, parent, params, parent_height - 2 * self.spacing, self.padding_horz, self.inner_background) - .map_err(|e| e.to_string()) + SystemTrayWidget::new( + display, + parent, + params, + parent_height - 2 * self.spacing, + self.padding_horz, + self.inner_background, + ) + .map_err(|e| e.to_string()) } fn default_status() -> Self { @@ -133,15 +163,26 @@ impl ContainerWidgetStyle { } impl TextWidgetStyle { - pub fn create_text_widget(&self, display: *mut xlib::Display, parent: xlib::Window, font: &str) - -> Result { + pub fn create_text_widget( + &self, + display: *mut xlib::Display, + parent: xlib::Window, + font: &str, + ) -> Result { let params = X11WidgetParams::new(0, 0, self.padding_horz, self.padding_horz); - X11TextWidget::new(display, parent, params, "".to_string(), font, self.foreground, self.background) - .map_err(|e| e.to_string()) + X11TextWidget::new( + display, + parent, + params, + "".to_string(), + font, + self.foreground, + self.background, + ) + .map_err(|e| e.to_string()) } } - pub fn read_config(overwrite_path: Option) -> Configuration { let result = if let Some(path) = overwrite_path { read_file(&path) @@ -154,7 +195,6 @@ pub fn read_config(overwrite_path: Option) -> Configuration { Err(msg) => { println!("Unable to read configuration: {}", msg); Configuration::default() - }, + } } } - diff --git a/marsbar/src/handlers.rs b/marsbar/src/handlers.rs index b920c3e3..ee50da3d 100644 --- a/marsbar/src/handlers.rs +++ b/marsbar/src/handlers.rs @@ -15,7 +15,6 @@ pub struct WorkspaceEventHandler { workspace_idx: u32, } - impl StatusEventHandler { pub fn new(block: usize, command: String) -> StatusEventHandler { StatusEventHandler { block, command } @@ -25,7 +24,10 @@ impl StatusEventHandler { impl WorkspaceEventHandler { pub fn new(workspace_idx: u32) -> Result { let controller = X11Controller::new()?; - Ok(WorkspaceEventHandler { controller, workspace_idx }) + Ok(WorkspaceEventHandler { + controller, + workspace_idx, + }) } fn cycle_workspace(&self, inc: i32) -> Result<()> { @@ -37,19 +39,26 @@ impl WorkspaceEventHandler { fn move_client(&self) -> Result<()> { let active = self.controller.get_active_window()?; - self.controller.send_window_to_workspace(active, self.workspace_idx) + self.controller + .send_window_to_workspace(active, self.workspace_idx) } } - impl WidgetEventHandler for StatusEventHandler { fn handle_action_event(&self, event: WidgetEvent, already_handled: bool) -> bool { - if already_handled { return true; } + if already_handled { + return true; + } if let WidgetEvent::ButtonPressed(button) = event { let block_var = format!("{}", self.block); let button_var = format!("{}", button); - if let Ok(mut handle) = std::process::Command::new("sh").arg("-c").arg(&self.command) - .env("BLOCK", block_var).env("BUTTON", button_var).spawn() { + if let Ok(mut handle) = std::process::Command::new("sh") + .arg("-c") + .arg(&self.command) + .env("BLOCK", block_var) + .env("BUTTON", button_var) + .spawn() + { std::thread::spawn(move || { let _ignored = handle.wait(); }); @@ -63,7 +72,9 @@ impl WidgetEventHandler for StatusEventHandler { impl WidgetEventHandler for WorkspaceEventHandler { fn handle_action_event(&self, event: WidgetEvent, already_handled: bool) -> bool { - if already_handled { return true; } + if already_handled { + return true; + } if let WidgetEvent::ButtonPressed(button) = event { let result = match button { 1 => self.controller.switch_workspace(self.workspace_idx), @@ -74,7 +85,7 @@ impl WidgetEventHandler for WorkspaceEventHandler { _ => return false, }; - return result.is_ok() + return result.is_ok(); } false } diff --git a/marsbar/src/main.rs b/marsbar/src/main.rs index dc5dca23..08e29d1b 100644 --- a/marsbar/src/main.rs +++ b/marsbar/src/main.rs @@ -1,15 +1,14 @@ #![doc = include_str!("../README.md")] - extern crate x11; use clap::Parser; use libmars::common::*; -use libmars::platforms::x11::misc::atoms::X11Atom::{self, *}; -use libmars::platforms::x11::misc::window::X11Window; use libmars::interfaces::draw::*; -use libmars::platforms::x11::draw::widget::*; use libmars::platforms::x11::draw::canvas::*; +use libmars::platforms::x11::draw::widget::*; +use libmars::platforms::x11::misc::atoms::X11Atom::{self, *}; +use libmars::platforms::x11::misc::window::X11Window; use libmars::utils::configuration::print_config; use std::ffi::*; use std::iter; @@ -23,17 +22,14 @@ use crate::config::*; use crate::handlers::*; use crate::tray::*; - mod config; mod handlers; mod status; mod tray; - const CLASSNAME: &str = "bar"; const WINDOWNAME: &str = "Bar Window"; - /// A simple status bar for marswm #[derive(Parser)] #[clap(author, version, about, long_about = None)] @@ -66,13 +62,23 @@ struct Bar { default_client_event_mask: i64, } - impl Bar { - fn create(display: *mut xlib::Display, dimensions: Dimensions, config: Configuration, - default_client_event_mask: i64, create_tray: bool) -> Result { + fn create( + display: *mut xlib::Display, + dimensions: Dimensions, + config: Configuration, + default_client_event_mask: i64, + create_tray: bool, + ) -> Result { let root = unsafe { xlib::XDefaultRootWindow(display) }; let window_type = Some(NetWMWindowTypeDock); - let window = libmars::platforms::x11::misc::create_window(display, dimensions, CLASSNAME, WINDOWNAME, window_type)?; + let window = libmars::platforms::x11::misc::create_window( + display, + dimensions, + CLASSNAME, + WINDOWNAME, + window_type, + )?; let mut dimensions = dimensions; dimensions.set_h(config.style.height); @@ -82,28 +88,51 @@ impl Bar { } // TODO destroy window on failure - let mut canvas = X11Canvas::new_for_window(display, window) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; - canvas.set_foreground(config.style.background) + let mut canvas = X11Canvas::new_for_window(display, window).inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; + canvas + .set_foreground(config.style.background) .and(canvas.set_background(config.style.background)) .and(canvas.set_font(&config.style.font)) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; - - let workspace_widget = config.style.workspaces.create_flow_layout_widget(display, window)?; - let title_widget = config.style.title.create_text_widget(display, window, &config.style.font)?; - let status_widget = config.style.status.create_flow_layout_widget(display, window)?; + .inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; + + let workspace_widget = config + .style + .workspaces + .create_flow_layout_widget(display, window)?; + let title_widget = + config + .style + .title + .create_text_widget(display, window, &config.style.font)?; + let status_widget = config + .style + .status + .create_flow_layout_widget(display, window)?; let systray = if create_tray { - config.style.status.create_systray_widget(display, window, dimensions.h()).ok() + config + .style + .status + .create_systray_widget(display, window, dimensions.h()) + .ok() } else { None }; - let mut bar = Bar { - display, root, window, - canvas, dimensions, + display, + root, + window, + canvas, + dimensions, config, - workspace_widget, status_widget, systray, title_widget, + workspace_widget, + status_widget, + systray, + title_widget, active_window: None, default_client_event_mask, }; @@ -120,13 +149,15 @@ impl Bar { self.arrange_title(self.get_active_window_title()); // arrange desktop segment - let result = self.root.x11_get_text_list_property(self.display, NetDesktopNames); + let result = self + .root + .x11_get_text_list_property(self.display, NetDesktopNames); let desktop_names = match result { Ok(names) => names, Err(e) => { eprintln!("WARNING: Desktop names not available ({})", e); Vec::new() - }, + } }; self.arrange_workspaces(desktop_names); if let Ok(idx) = self.get_active_workspace() { @@ -154,8 +185,15 @@ impl Bar { if let Some(widget) = self.status_widget.child_mut(i) { widget.set_label(block.to_owned()); } else { - let mut widget = self.config.style.status - .create_text_widget(self.display, self.status_widget.wid(), &self.config.style.font) + let mut widget = self + .config + .style + .status + .create_text_widget( + self.display, + self.status_widget.wid(), + &self.config.style.font, + ) .unwrap(); widget.set_label(block.to_owned()); if let Some(callback) = &self.config.action_cmd { @@ -189,7 +227,10 @@ impl Bar { }; let height_diff = (self.dimensions.h() as i32 - self.status_widget.size().1 as i32) / 2; - let x = self.dimensions.w() as i32 - tray_width as i32 - self.status_widget.size().0 as i32 - height_diff; + let x = self.dimensions.w() as i32 + - tray_width as i32 + - self.status_widget.size().0 as i32 + - height_diff; let y = height_diff; self.status_widget.move_to(x, y); } @@ -223,8 +264,15 @@ impl Bar { max_width = widget.content_size().0 } } else { - let mut widget = self.config.style.workspaces - .create_text_widget(self.display, self.workspace_widget.wid(), &self.config.style.font) + let mut widget = self + .config + .style + .workspaces + .create_text_widget( + self.display, + self.workspace_widget.wid(), + &self.config.style.font, + ) .unwrap(); let event_handler = WorkspaceEventHandler::new(i as u32).unwrap(); @@ -258,12 +306,22 @@ impl Bar { self.workspace_widget.rearrange(); } - fn create_for_monitor(display: *mut xlib::Display, monitor_conf: &MonitorConfig, config: Configuration, - has_tray: bool) -> Result { + fn create_for_monitor( + display: *mut xlib::Display, + monitor_conf: &MonitorConfig, + config: Configuration, + has_tray: bool, + ) -> Result { let mdims = monitor_conf.dimensions(); let mut dimensions = mdims; dimensions.set_h(config.style.height); - Self::create(display, dimensions, config.clone(), xlib::NoEventMask, has_tray) + Self::create( + display, + dimensions, + config.clone(), + xlib::NoEventMask, + has_tray, + ) } fn draw(&mut self) { @@ -277,20 +335,29 @@ impl Bar { let height = self.dimensions.h(); let x = (self.dimensions.x() + self.dimensions.w() as i32) - width as i32; let y = self.dimensions.y(); - self.canvas.fill_rectangle_with(x, y, width, height, self.config.style.status.outer_background); + self.canvas.fill_rectangle_with( + x, + y, + width, + height, + self.config.style.status.outer_background, + ); } self.canvas.flush(); } fn get_status(&self) -> Result { - self.root.x11_read_property_string(self.display, MarsStatus) + self.root + .x11_read_property_string(self.display, MarsStatus) .or_else(|_| self.root.x11_wm_name(self.display)) .map_err(|e| e.to_string()) } fn get_active_workspace(&self) -> Result { - let data = self.root.x11_read_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL) + let data = self + .root + .x11_read_property_long(self.display, NetCurrentDesktop, xlib::XA_CARDINAL) .map_err(|e| e.to_string())?; match data.first() { Some(idx) => Ok(*idx as u32), @@ -299,7 +366,9 @@ impl Bar { } fn get_active_window(&self) -> Option { - let result = self.root.x11_read_property_long(self.display, NetActiveWindow, xlib::XA_WINDOW); + let result = + self.root + .x11_read_property_long(self.display, NetActiveWindow, xlib::XA_WINDOW); let data = match result { Ok(data) => data, Err(_) => return None, @@ -329,26 +398,31 @@ impl Bar { } else if event.any.window == self.window { self.handle_bar_event(event); } else if Some(event.any.window) == self.active_window - && event.get_type() == xlib::PropertyNotify - && event.property.atom == WMName.to_xlib_atom(self.display) { + && event.get_type() == xlib::PropertyNotify + && event.property.atom == WMName.to_xlib_atom(self.display) + { let title = self.get_active_window_title(); self.arrange_title(title); } else if event.get_type() == xlib::ClientMessage - && Some(event.any.window) == self.systray.as_ref().map(|w| w.wid()) - && event.client_message.message_type == NetSystemTrayOpcode.to_xlib_atom(self.display) { + && Some(event.any.window) == self.systray.as_ref().map(|w| w.wid()) + && event.client_message.message_type + == NetSystemTrayOpcode.to_xlib_atom(self.display) + { if let Some(systray) = &mut self.systray { systray.handle_systray_event(event.client_message); self.arrange(); } } else if event.get_type() == xlib::DestroyNotify - && Some(event.destroy_window.event) == self.systray.as_ref().map(|w| w.wid()) { + && Some(event.destroy_window.event) == self.systray.as_ref().map(|w| w.wid()) + { if let Some(systray) = &mut self.systray { systray.handle_icon_destroyed(event.destroy_window); self.arrange(); } } else { let systray_iter = if let Some(systray) = &mut self.systray { - Box::new(iter::once(systray as &mut dyn Widget)) as Box> + Box::new(iter::once(systray as &mut dyn Widget)) + as Box> } else { Box::new(iter::empty()) }; @@ -365,7 +439,9 @@ impl Bar { } fn handle_bar_event(&mut self, event: xlib::XEvent) { - if event.get_type() == xlib::Expose { self.draw() } + if event.get_type() == xlib::Expose { + self.draw() + } } fn handle_root_event(&mut self, event: xlib::XEvent) { @@ -379,32 +455,42 @@ impl Bar { if let Some(window) = self.active_window { // TODO this does NOT work when called from a window manager // directly - xlib::XSelectInput(self.display, window, self.default_client_event_mask); + xlib::XSelectInput( + self.display, + window, + self.default_client_event_mask, + ); } self.active_window = self.get_active_window(); if let Some(window) = self.active_window { - xlib::XSelectInput(self.display, window, self.default_client_event_mask | xlib::PropertyChangeMask); + xlib::XSelectInput( + self.display, + window, + self.default_client_event_mask | xlib::PropertyChangeMask, + ); } } let title = self.get_active_window_title(); self.arrange_title(title); - }, + } NetCurrentDesktop => { let new_idx = match self.get_active_workspace() { Ok(idx) => idx, Err(_) => return, }; self.set_active_workspace(new_idx); - }, + } NetDesktopNames => { - let result = self.root.x11_get_text_list_property(self.display, NetDesktopNames); + let result = self + .root + .x11_get_text_list_property(self.display, NetDesktopNames); let workspace_names = match result { Ok(names) => names, Err(e) => { eprintln!("WARNING: Desktop names not available ({})", e); Vec::new() - }, + } }; self.arrange_workspaces(workspace_names); } @@ -412,7 +498,7 @@ impl Bar { if let Ok(status) = self.get_status() { self.arrange_status(status) } - }, + } _ => (), } }; @@ -423,7 +509,14 @@ impl Bar { self.dimensions.set_pos(monitor_config.dimensions().pos()); self.dimensions.set_w(monitor_config.dimensions().w()); unsafe { - xlib::XMoveResizeWindow(self.display, self.window, self.dimensions.x(), self.dimensions.y(), self.dimensions.w(), self.dimensions.h()); + xlib::XMoveResizeWindow( + self.display, + self.window, + self.dimensions.x(), + self.dimensions.y(), + self.dimensions.w(), + self.dimensions.h(), + ); } self.arrange(); } @@ -449,11 +542,19 @@ impl Bar { fn set_active_workspace(&mut self, new_idx: u32) { for (i, widget) in &mut self.workspace_widget.children_mut().enumerate() { if i as u32 == new_idx { - widget.set_foreground(self.config.style.workspaces.inner_background).unwrap(); - widget.set_background(self.config.style.workspaces.foreground).unwrap(); + widget + .set_foreground(self.config.style.workspaces.inner_background) + .unwrap(); + widget + .set_background(self.config.style.workspaces.foreground) + .unwrap(); } else { - widget.set_foreground(self.config.style.workspaces.foreground).unwrap(); - widget.set_background(self.config.style.workspaces.inner_background).unwrap(); + widget + .set_foreground(self.config.style.workspaces.foreground) + .unwrap(); + widget + .set_background(self.config.style.workspaces.inner_background) + .unwrap(); } } } @@ -461,13 +562,21 @@ impl Bar { fn await_map_notify(&mut self) { libmars::platforms::x11::misc::await_map_notify(self.display, self.window); self.draw(); - println!("Window mapped: 0x{:x}, {:?}", self.window, self.window.x11_dimensions(self.display)); + println!( + "Window mapped: 0x{:x}, {:?}", + self.window, + self.window.x11_dimensions(self.display) + ); } - } -fn eventloop(display: *mut xlib::Display, mut bar: Bar, have_xrandr: bool, - xrr_event_base: i32, status_process: &mut Option) { +fn eventloop( + display: *mut xlib::Display, + mut bar: Bar, + have_xrandr: bool, + xrr_event_base: i32, + status_process: &mut Option, +) { loop { let mut event: MaybeUninit = MaybeUninit::uninit(); unsafe { @@ -516,10 +625,15 @@ fn main() { let (have_xrandr, xrr_event_base, _xrr_error_base) = unsafe { let mut xrr_event_base = 0; let mut xrr_error_base = 0; - let have_xrandr = xrandr::XRRQueryExtension(display, &mut xrr_event_base, &mut xrr_error_base) != 0; + let have_xrandr = + xrandr::XRRQueryExtension(display, &mut xrr_event_base, &mut xrr_error_base) != 0; if have_xrandr { - xrandr::XRRSelectInput(display, xlib::XDefaultRootWindow(display), xrandr::RRCrtcChangeNotifyMask); + xrandr::XRRSelectInput( + display, + xlib::XDefaultRootWindow(display), + xrandr::RRCrtcChangeNotifyMask, + ); } (have_xrandr, xrr_event_base, xrr_error_base) @@ -527,21 +641,35 @@ fn main() { let status_cmd = config.status_cmd.clone(); let monitors = libmars::platforms::x11::misc::query_monitor_config(display, true); - let mut bar = Bar::create_for_monitor(display, monitors.first().unwrap(), config, true).unwrap(); + let mut bar = + Bar::create_for_monitor(display, monitors.first().unwrap(), config, true).unwrap(); bar.await_map_notify(); // spawn status command let mut status_cmd_proc = match &status_cmd { Some(status_cmd) => { - match process::Command::new("sh").arg("-c").arg(status_cmd).spawn() { + match process::Command::new("sh") + .arg("-c") + .arg(status_cmd) + .spawn() + { Ok(proc) => Some(proc), - Err(e) => { eprintln!("WARNING: unable to create child process ({})", e); None }, + Err(e) => { + eprintln!("WARNING: unable to create child process ({})", e); + None + } } - }, + } None => None, }; - eventloop(display, bar, have_xrandr, xrr_event_base, &mut status_cmd_proc); + eventloop( + display, + bar, + have_xrandr, + xrr_event_base, + &mut status_cmd_proc, + ); // clean up if let Some(mut proc) = status_cmd_proc { @@ -554,8 +682,12 @@ extern "C" fn on_error(display: *mut xlib::Display, error: *mut xlib::XErrorEven let msg = unsafe { let bufsize = 1024; let mut buf = vec![0; bufsize]; - xlib::XGetErrorText(display, (*error).error_code.into(), buf.as_mut_ptr(), - (bufsize - 1) as c_int); + xlib::XGetErrorText( + display, + (*error).error_code.into(), + buf.as_mut_ptr(), + (bufsize - 1) as c_int, + ); let msg_cstring = CStr::from_ptr(buf.as_mut_ptr()); msg_cstring.to_str().unwrap().to_owned() // println!("{}", msg); @@ -563,9 +695,21 @@ extern "C" fn on_error(display: *mut xlib::Display, error: *mut xlib::XErrorEven unsafe { match (*error).error_code { - xlib::BadWindow => println!("X11 error: {} (request code: {})", msg, (*error).request_code), - xlib::BadMatch => println!("X11 error: {} (request code: {})", msg, (*error).request_code), - _ => panic!("Fatal X11 error: {} (request code: {})", msg, (*error).request_code), + xlib::BadWindow => println!( + "X11 error: {} (request code: {})", + msg, + (*error).request_code + ), + xlib::BadMatch => println!( + "X11 error: {} (request code: {})", + msg, + (*error).request_code + ), + _ => panic!( + "Fatal X11 error: {} (request code: {})", + msg, + (*error).request_code + ), } } 0 diff --git a/marsbar/src/status.rs b/marsbar/src/status.rs index e69de29b..8b137891 100644 --- a/marsbar/src/status.rs +++ b/marsbar/src/status.rs @@ -0,0 +1 @@ + diff --git a/marsbar/src/tray.rs b/marsbar/src/tray.rs index a974e1a1..bf45bfc0 100644 --- a/marsbar/src/tray.rs +++ b/marsbar/src/tray.rs @@ -1,11 +1,11 @@ extern crate x11; use libmars::common::*; -use libmars::platforms::x11::misc::atoms::X11Atom::*; -use libmars::platforms::x11::misc::window::X11Window; use libmars::interfaces::draw::*; use libmars::platforms::x11::draw::canvas::*; use libmars::platforms::x11::draw::widget::*; +use libmars::platforms::x11::misc::atoms::X11Atom::*; +use libmars::platforms::x11::misc::window::X11Window; use std::cmp; use std::mem::MaybeUninit; use x11::xlib; @@ -29,7 +29,6 @@ const VERSION_MAJOR: u64 = 0; const VERSION_MINOR: u64 = 0; const XEMBED_EMBEDDED_VERSION: u64 = (VERSION_MAJOR << 16) | VERSION_MINOR; - pub struct SystemTrayWidget { display: *mut xlib::Display, tray_icons: Vec, @@ -48,36 +47,60 @@ pub struct SystemTrayWidget { bg_color: u64, } - impl SystemTrayWidget { - pub fn new(display: *mut xlib::Display, parent: xlib::Window, params: X11WidgetParams, height: u32, - ipad: u32, bg_color: u64) -> Result { - if height < 2*params.vpad() { - return Err(format!("Padding bigger than height (h: {}, vpad: {})", height, params.vpad())); + pub fn new( + display: *mut xlib::Display, + parent: xlib::Window, + params: X11WidgetParams, + height: u32, + ipad: u32, + bg_color: u64, + ) -> Result { + if height < 2 * params.vpad() { + return Err(format!( + "Padding bigger than height (h: {}, vpad: {})", + height, + params.vpad() + )); } let outer_dimensions = Dimensions::new(params.x(), params.y(), MIN_SIZE.0, MIN_SIZE.1); let root = unsafe { xlib::XDefaultRootWindow(display) }; let window = create_widget_window(display, parent, outer_dimensions)?; - let mut canvas = X11Canvas::new_for_window(display, window) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; + let mut canvas = X11Canvas::new_for_window(display, window).inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; - canvas.set_foreground(bg_color) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; - canvas.set_background(bg_color) - .inspect_err(|_| unsafe { xlib::XDestroyWindow(display, window); })?; + canvas.set_foreground(bg_color).inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; + canvas.set_background(bg_color).inspect_err(|_| unsafe { + xlib::XDestroyWindow(display, window); + })?; // get required input selections (the default doesn't fit very well) let mask = xlib::StructureNotifyMask | xlib::SubstructureNotifyMask | xlib::ExposureMask; - unsafe { xlib::XSelectInput(display, window, mask); } + unsafe { + xlib::XSelectInput(display, window, mask); + } // configure tray window let data = [_NET_SYSTEM_TRAY_ORIENTATION_HORZ]; - window.x11_replace_property_long(display, NetSystemTrayOrientation, xlib::XA_CARDINAL, &data); + window.x11_replace_property_long( + display, + NetSystemTrayOrientation, + xlib::XA_CARDINAL, + &data, + ); // get tray selection unsafe { - xlib::XSetSelectionOwner(display, NetSystemTray.to_xlib_atom(display), window, xlib::CurrentTime); + xlib::XSetSelectionOwner( + display, + NetSystemTray.to_xlib_atom(display), + window, + xlib::CurrentTime, + ); // check if we got the selection if xlib::XGetSelectionOwner(display, NetSystemTray.to_xlib_atom(display)) != window { @@ -85,19 +108,28 @@ impl SystemTrayWidget { return Err("unable to get system tray selection".to_owned()); } - send_manager_message(display, root, NetSystemTray.to_xlib_atom(display), window, 0, 0); + send_manager_message( + display, + root, + NetSystemTray.to_xlib_atom(display), + window, + 0, + 0, + ); } let widget = SystemTrayWidget { display, tray_icons: Vec::new(), - window, canvas, + window, + canvas, event_handlers: Vec::new(), is_visible: true, - width: height, height, + width: height, + height, min_size: MIN_SIZE, max_size: MAX_SIZE, - icon_width: height - 2*params.vpad(), + icon_width: height - 2 * params.vpad(), ipad, hpad: params.hpad(), vpad: params.vpad(), @@ -124,16 +156,27 @@ impl SystemTrayWidget { let mut swa: xlib::XSetWindowAttributes = MaybeUninit::zeroed().assume_init(); swa.background_pixel = self.bg_color; swa.backing_store = xlib::ParentRelative; - xlib::XChangeWindowAttributes(self.display, tray_icon, xlib::CWBackPixel | xlib::CWBackPixmap, &mut swa); + xlib::XChangeWindowAttributes( + self.display, + tray_icon, + xlib::CWBackPixel | xlib::CWBackPixmap, + &mut swa, + ); // notify window - send_xembed_message(self.display, tray_icon, XEMBED_EMBEDDED_NOTIFY, 0, self.window, XEMBED_EMBEDDED_VERSION); + send_xembed_message( + self.display, + tray_icon, + XEMBED_EMBEDDED_NOTIFY, + 0, + self.window, + XEMBED_EMBEDDED_VERSION, + ); // map window xlib::XMapRaised(self.display, tray_icon); } - tray_icon.x11_set_state(self.display, libmars::platforms::x11::misc::NORMAL_STATE); self.tray_icons.push(tray_icon); @@ -145,7 +188,9 @@ impl SystemTrayWidget { return; } - if event.data.get_long(1) == SYSTEM_TRAY_REQUEST_DOCK { self.dock(event.data.get_long(2) as u64) } + if event.data.get_long(1) == SYSTEM_TRAY_REQUEST_DOCK { + self.dock(event.data.get_long(2) as u64) + } } pub fn handle_icon_destroyed(&mut self, event: xlib::XDestroyWindowEvent) { @@ -158,9 +203,12 @@ impl SystemTrayWidget { for (i, icon) in self.tray_icons.iter().enumerate() { unsafe { - xlib::XMoveWindow(self.display, *icon, - self.hpad as i32 + i as i32 * (self.icon_width + self.ipad) as i32, - self.vpad as i32); + xlib::XMoveWindow( + self.display, + *icon, + self.hpad as i32 + i as i32 * (self.icon_width + self.ipad) as i32, + self.vpad as i32, + ); } } @@ -183,7 +231,7 @@ impl SystemTrayWidget { fn resize_to_content(&mut self) { let nicons = self.tray_icons.len(); self.width = if nicons > 0 { - nicons as u32 * (self.icon_width + self.ipad) - self.ipad + 2*self.hpad + nicons as u32 * (self.icon_width + self.ipad) - self.ipad + 2 * self.hpad } else { self.min_size.0 }; @@ -207,7 +255,6 @@ impl SystemTrayWidget { } } - impl Widget for SystemTrayWidget { fn move_to(&mut self, x: i32, y: i32) { unsafe { @@ -232,7 +279,7 @@ impl Widget for SystemTrayWidget { xlib::ButtonPress => { let button = event.button.button; Some(WidgetEvent::ButtonPressed(button)) - }, + } xlib::Expose => { self.redraw(); None @@ -241,10 +288,11 @@ impl Widget for SystemTrayWidget { }; if let Some(widget_event) = widget_event { - let _handled = self.event_handlers.iter() - .fold(false, { - |already_handled, handler| handler.handle_action_event(widget_event, already_handled) - }); + let _handled = self.event_handlers.iter().fold(false, { + |already_handled, handler| { + handler.handle_action_event(widget_event, already_handled) + } + }); } true } else { @@ -271,8 +319,14 @@ impl Widget for SystemTrayWidget { } } - -fn send_manager_message(display: *mut xlib::Display, root: xlib::Window, selection: u64, window: u64, data0: u64, data1: u64) { +fn send_manager_message( + display: *mut xlib::Display, + root: xlib::Window, + selection: u64, + window: u64, + data0: u64, + data1: u64, +) { let mut data = xlib::ClientMessageData::new(); data.set_long(0, xlib::CurrentTime as i64); data.set_long(1, selection as i64); @@ -284,7 +338,8 @@ fn send_manager_message(display: *mut xlib::Display, root: xlib::Window, selecti type_: xlib::ClientMessage, serial: 0, send_event: xlib::True, - display, window, + display, + window, message_type: Manager.to_xlib_atom(display), format: 32, data, @@ -293,11 +348,24 @@ fn send_manager_message(display: *mut xlib::Display, root: xlib::Window, selecti let mut event = xlib::XEvent::from(ce); unsafe { - xlib::XSendEvent(display, root, xlib::False, xlib::StructureNotifyMask, &mut event); + xlib::XSendEvent( + display, + root, + xlib::False, + xlib::StructureNotifyMask, + &mut event, + ); xlib::XSync(display, xlib::False); } } -fn send_xembed_message(display: *mut xlib::Display, window: xlib::Window, message: u64, detail: u64, data0: u64, data1: u64) { +fn send_xembed_message( + display: *mut xlib::Display, + window: xlib::Window, + message: u64, + detail: u64, + data0: u64, + data1: u64, +) { let mut data = xlib::ClientMessageData::new(); data.set_long(0, xlib::CurrentTime as i64); data.set_long(1, message as i64); @@ -309,7 +377,8 @@ fn send_xembed_message(display: *mut xlib::Display, window: xlib::Window, messag type_: xlib::ClientMessage, serial: 0, send_event: xlib::True, - display, window, + display, + window, message_type: Xembed.to_xlib_atom(display), format: 32, data, diff --git a/marswm/src/attributes.rs b/marswm/src/attributes.rs index 3d8a1447..eb5a3f55 100644 --- a/marswm/src/attributes.rs +++ b/marswm/src/attributes.rs @@ -1,7 +1,6 @@ use libmars::common::Dimensions; -#[derive(PartialEq)] -#[derive(Default)] +#[derive(PartialEq, Default)] pub struct Attributes { pub is_floating: bool, pub is_moving: bool, @@ -9,5 +8,3 @@ pub struct Attributes { pub floating_dimensions: Option, } - - diff --git a/marswm/src/bindings.rs b/marswm/src/bindings.rs index 5cd07fd6..f470a426 100644 --- a/marswm/src/bindings.rs +++ b/marswm/src/bindings.rs @@ -1,19 +1,17 @@ extern crate x11; use libmars::platforms::x11::misc::get_keysym; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::cmp; use std::rc::Rc; -use x11::xlib::{Mod1Mask, Mod4Mask, ShiftMask, ControlMask}; +use x11::xlib::{ControlMask, Mod1Mask, Mod4Mask, ShiftMask}; -use crate::*; use crate::layouts::*; - +use crate::*; pub const DEFAULT_MODKEY: Modifier = Modifier::Mod4; - macro_rules! client_button_binding { ($button:expr, $action:expr $(, ($($add_mods:ident ),*))?) => { ButtonBinding::new(vec![DEFAULT_MODKEY $(, $($add_mods),*)?], $button, vec![Window, Frame], $action) @@ -26,11 +24,10 @@ macro_rules! frame_button_binding { } } - /// Actions for key bindings, button bindings and window rules. /// /// ***Note that the configuration files use `kebab-case` convention for enum variants.*** -#[derive(Serialize,Deserialize,Clone,Debug,PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] // #[serde(tag = "action", content = "arg")] // #[serde(tag = "type")] @@ -97,7 +94,7 @@ pub enum BindingAction { ToggleFullscreen, } -#[derive(Serialize,Deserialize,Clone,Debug,PartialEq,Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub enum Modifier { Mod1, Mod4, @@ -105,7 +102,7 @@ pub enum Modifier { Control, } -#[derive(Serialize,Deserialize,PartialEq,Eq,Debug,Copy,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Copy, Clone)] pub enum Direction { Up, Down, @@ -113,7 +110,7 @@ pub enum Direction { Right, } -#[derive(Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] pub struct KeyBinding { /// list of modifiers that apply to this binding #[serde(default)] @@ -128,7 +125,7 @@ pub struct KeyBinding { action: BindingAction, } -#[derive(Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] pub struct ButtonBinding { /// list of modifiers that apply to this binding modifiers: Vec, @@ -144,91 +141,133 @@ pub struct ButtonBinding { } impl BindingAction { - pub fn execute>(&self, wm: &mut MarsWM, backend: &mut B, - client_option: Option>>) { + pub fn execute>( + &self, + wm: &mut MarsWM, + backend: &mut B, + client_option: Option>>, + ) { use BindingAction::*; match self { - CenterClient => if let Some(client_rc) = client_option { - wm.center_client(backend, client_rc); - }, - ChangeMainRatio(f) => wm.current_workspace_mut(backend).change_main_ratio(*f), - CloseClient => if let Some(client_rc) = client_option { - client_rc.borrow().close(); - }, + CenterClient => { + if let Some(client_rc) = client_option { + wm.center_client(backend, client_rc); + } + } + ChangeMainRatio(f) => wm.current_workspace_mut(backend).change_main_ratio(*f), + CloseClient => { + if let Some(client_rc) = client_option { + client_rc.borrow().close(); + } + } CycleClient(inc) => wm.cycle_client(backend, *inc), CycleLayout => wm.current_workspace_mut(backend).cycle_layout(), CycleMonitor(inc) => wm.cycle_monitor(backend, *inc), CycleWorkspace(inc) => wm.cycle_workspace(backend, *inc), Execute(cmd) => { - if let Ok(mut handle) = std::process::Command::new("sh").arg("-c").arg(cmd).spawn() { + if let Ok(mut handle) = std::process::Command::new("sh").arg("-c").arg(cmd).spawn() + { std::thread::spawn(move || { let _ignored = handle.wait(); }); } - }, + } Exit => { wm.exit(backend); - }, + } FocusDirection(d) => wm.focus_direction(backend, *d), FocusMain => wm.switch_to_main(backend), IncGaps(i) => wm.current_workspace_mut(backend).inc_gaps(*i), IncNMain(i) => wm.current_workspace_mut(backend).inc_nmain(*i), - MouseMove => if let Some(client_rc) = client_option { - backend.mouse_move(wm, client_rc); - wm.current_monitor_mut(backend).restack_current(); - }, - MousePlace => if let Some(client_rc) = client_option { - wm.mouse_place(backend, client_rc); - }, - MouseResize => if let Some(client_rc) = client_option && is_floating!(wm, &client_rc) { - backend.mouse_resize(wm, client_rc); - }, - MouseResizeCentered => if let Some(client_rc) = client_option && is_floating!(wm, &client_rc) { - wm.mouse_resize_centered(backend, client_rc); - }, - MoveMonitor(inc) => if let Some(client_rc) = client_option { - wm.move_client_to_monitor(client_rc, *inc); - }, - MoveWorkspace(ws) => if let Some(client_rc) = client_option { - let ws_index_option = wm.get_monitor_mut(&client_rc) - .and_then(|m| m.workspace(*ws)) - .map(|ws| ws.global_index()); - if let Some(ws_index) = ws_index_option { - wm.move_to_workspace(backend, client_rc, ws_index); + MouseMove => { + if let Some(client_rc) = client_option { + backend.mouse_move(wm, client_rc); + wm.current_monitor_mut(backend).restack_current(); + } + } + MousePlace => { + if let Some(client_rc) = client_option { + wm.mouse_place(backend, client_rc); + } + } + MouseResize => { + if let Some(client_rc) = client_option + && is_floating!(wm, &client_rc) + { + backend.mouse_resize(wm, client_rc); + } + } + MouseResizeCentered => { + if let Some(client_rc) = client_option + && is_floating!(wm, &client_rc) + { + wm.mouse_resize_centered(backend, client_rc); } - }, + } + MoveMonitor(inc) => { + if let Some(client_rc) = client_option { + wm.move_client_to_monitor(client_rc, *inc); + } + } + MoveWorkspace(ws) => { + if let Some(client_rc) = client_option { + let ws_index_option = wm + .get_monitor_mut(&client_rc) + .and_then(|m| m.workspace(*ws)) + .map(|ws| ws.global_index()); + if let Some(ws_index) = ws_index_option { + wm.move_to_workspace(backend, client_rc, ws_index); + } + } + } PreviousWorkspace => wm.switch_prev_workspace(backend), - MoveMain => if let Some(client_rc) = client_option { - wm.current_workspace_mut(backend).move_main(client_rc); - }, + MoveMain => { + if let Some(client_rc) = client_option { + wm.current_workspace_mut(backend).move_main(client_rc); + } + } Restart => wm.restart(backend), SetLayout(layout) => wm.current_workspace_mut(backend).set_layout(*layout), SetStackMode(mode) => wm.current_workspace_mut(backend).set_stack_mode(*mode), - SetStackPosition(position) => wm.current_workspace_mut(backend).set_stack_position(*position), - StackMove(i) => if let Some(client_rc) = client_option { - wm.current_workspace_mut(backend).stack_move(client_rc, *i); - }, + SetStackPosition(position) => wm + .current_workspace_mut(backend) + .set_stack_position(*position), + StackMove(i) => { + if let Some(client_rc) = client_option { + wm.current_workspace_mut(backend).stack_move(client_rc, *i); + } + } SwapDirection(dir) => wm.swap_direction(backend, *dir), SwitchWorkspace(ws) => { - let ws_index_option = wm.current_monitor(backend).workspace(*ws) + let ws_index_option = wm + .current_monitor(backend) + .workspace(*ws) .map(|ws| ws.global_index()); if let Some(ws_index) = ws_index_option { wm.switch_workspace(backend, ws_index); } - }, - ToggleFloating => if let Some(client_rc) = client_option { - wm.toggle_tile_client(backend, client_rc); - }, - ToggleFullscreen => if let Some(client_rc) = client_option { - wm.toggle_fullscreen_client(backend, client_rc); - }, + } + ToggleFloating => { + if let Some(client_rc) = client_option { + wm.toggle_tile_client(backend, client_rc); + } + } + ToggleFullscreen => { + if let Some(client_rc) = client_option { + wm.toggle_fullscreen_client(backend, client_rc); + } + } } } } impl KeyBinding { pub fn new(modifiers: Vec, key: &str, action: BindingAction) -> Self { - KeyBinding { modifiers, key: key.to_owned(), action } + KeyBinding { + modifiers, + key: key.to_owned(), + action, + } } pub fn action(&self) -> BindingAction { @@ -249,8 +288,18 @@ impl KeyBinding { } impl ButtonBinding { - pub fn new(modifiers: Vec, button: u32, targets: Vec, action: BindingAction) -> Self { - ButtonBinding { modifiers, button, targets, action } + pub fn new( + modifiers: Vec, + button: u32, + targets: Vec, + action: BindingAction, + ) -> Self { + ButtonBinding { + modifiers, + button, + targets, + action, + } } pub fn action(&self) -> BindingAction { @@ -287,17 +336,29 @@ impl Modifier { pub fn default_key_bindings(nworkspaces: u32) -> Vec { use BindingAction::*; - use Modifier::*; use Direction::*; + use Modifier::*; let mut bindings = vec![ KeyBinding::new(vec![DEFAULT_MODKEY], "Delete", CloseClient), KeyBinding::new(vec![DEFAULT_MODKEY], "n", CycleLayout), - KeyBinding::new(vec![DEFAULT_MODKEY, Shift], "t", SetLayout(LayoutType::Stack)), - KeyBinding::new(vec![DEFAULT_MODKEY, Control], "t", SetLayout(LayoutType::BottomStack)), + KeyBinding::new( + vec![DEFAULT_MODKEY, Shift], + "t", + SetLayout(LayoutType::Stack), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY, Control], + "t", + SetLayout(LayoutType::BottomStack), + ), KeyBinding::new(vec![DEFAULT_MODKEY], "c", SetLayout(LayoutType::Deck)), KeyBinding::new(vec![DEFAULT_MODKEY], "m", SetLayout(LayoutType::Monocle)), KeyBinding::new(vec![DEFAULT_MODKEY], "t", SetLayout(LayoutType::Dynamic)), - KeyBinding::new(vec![DEFAULT_MODKEY, Shift], "f", SetLayout(LayoutType::Floating)), + KeyBinding::new( + vec![DEFAULT_MODKEY, Shift], + "f", + SetLayout(LayoutType::Floating), + ), KeyBinding::new(vec![DEFAULT_MODKEY], "BackSpace", MoveMain), KeyBinding::new(vec![DEFAULT_MODKEY], "a", IncNMain(1)), KeyBinding::new(vec![DEFAULT_MODKEY], "x", IncNMain(-1)), @@ -317,15 +378,47 @@ pub fn default_key_bindings(nworkspaces: u32) -> Vec { KeyBinding::new(vec![DEFAULT_MODKEY, Shift], "space", ToggleFloating), KeyBinding::new(vec![DEFAULT_MODKEY], "z", CenterClient), KeyBinding::new(vec![DEFAULT_MODKEY], "Tab", PreviousWorkspace), - KeyBinding::new(vec![DEFAULT_MODKEY], "Return", Execute("$TERMINAL".to_owned())), - KeyBinding::new(vec![DEFAULT_MODKEY], "d", Execute("rofi -show drun".to_owned())), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "Return", + Execute("$TERMINAL".to_owned()), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "d", + Execute("rofi -show drun".to_owned()), + ), KeyBinding::new(vec![DEFAULT_MODKEY, Control], "BackSpace", Restart), - KeyBinding::new(vec![DEFAULT_MODKEY], "Up", SetStackPosition(StackPosition::Top)), - KeyBinding::new(vec![DEFAULT_MODKEY], "Right", SetStackPosition(StackPosition::Right)), - KeyBinding::new(vec![DEFAULT_MODKEY], "Down", SetStackPosition(StackPosition::Bottom)), - KeyBinding::new(vec![DEFAULT_MODKEY], "Left", SetStackPosition(StackPosition::Left)), - KeyBinding::new(vec![DEFAULT_MODKEY], "semicolon", SetStackMode(StackMode::Split)), - KeyBinding::new(vec![DEFAULT_MODKEY], "apostrophe", SetStackMode(StackMode::Deck)), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "Up", + SetStackPosition(StackPosition::Top), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "Right", + SetStackPosition(StackPosition::Right), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "Down", + SetStackPosition(StackPosition::Bottom), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "Left", + SetStackPosition(StackPosition::Left), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "semicolon", + SetStackMode(StackMode::Split), + ), + KeyBinding::new( + vec![DEFAULT_MODKEY], + "apostrophe", + SetStackMode(StackMode::Deck), + ), KeyBinding::new(vec![DEFAULT_MODKEY], "Next", CycleMonitor(1)), KeyBinding::new(vec![DEFAULT_MODKEY], "Prior", CycleMonitor(-1)), KeyBinding::new(vec![DEFAULT_MODKEY, Shift], "Next", MoveMonitor(1)), @@ -334,8 +427,16 @@ pub fn default_key_bindings(nworkspaces: u32) -> Vec { for i in 0..cmp::min(nworkspaces, 9) { let key_name = format!("{}", i + 1); - bindings.push(KeyBinding::new(vec!(DEFAULT_MODKEY), &key_name, SwitchWorkspace(i))); - bindings.push(KeyBinding::new(vec!(DEFAULT_MODKEY, Modifier::Shift), &key_name, MoveWorkspace(i))); + bindings.push(KeyBinding::new( + vec![DEFAULT_MODKEY], + &key_name, + SwitchWorkspace(i), + )); + bindings.push(KeyBinding::new( + vec![DEFAULT_MODKEY, Modifier::Shift], + &key_name, + MoveWorkspace(i), + )); } bindings @@ -362,4 +463,3 @@ pub fn default_button_bindings() -> Vec { ]; bindings } - diff --git a/marswm/src/config.rs b/marswm/src/config.rs index 17b30c2a..6ffca40e 100644 --- a/marswm/src/config.rs +++ b/marswm/src/config.rs @@ -1,13 +1,13 @@ -use std::cmp; use libmars::common::*; -use serde::{Serialize, Deserialize}; use libmars::utils::configuration::*; +use serde::{Deserialize, Serialize}; +use std::cmp; use crate::bindings::*; +use crate::layouts::AttachPosition; use crate::layouts::LayoutType; use crate::layouts::StackMode; use crate::layouts::StackPosition; -use crate::layouts::AttachPosition; use crate::rules::*; const BUTTON_BINDINGS_FILE: &str = "buttonbindings.yaml"; @@ -18,8 +18,7 @@ const KEY_BINDINGS_FILE: &str = "keybindings.yaml"; const KEY_BINDINGS_EXT_FILE: &str = "keybindings_ext.yaml"; const RULES_FILE: &str = "rules.yaml"; - -#[derive(Serialize,Deserialize,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] #[serde(default)] pub struct Configuration { /// number of workspaces for primary monitor @@ -41,7 +40,7 @@ pub struct Configuration { pub theming: ThemingConfiguration, } -#[derive(Serialize,Deserialize,PartialEq,Debug,Copy,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Debug, Copy, Clone)] #[serde(default)] pub struct LayoutConfiguration { /// default layout for each workspace @@ -66,7 +65,7 @@ pub struct LayoutConfiguration { pub attach_position: AttachPosition, } -#[derive(Serialize,Deserialize,PartialEq,Eq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] #[serde(default)] pub struct ThemingConfiguration { /// color for active window frame @@ -106,7 +105,7 @@ pub struct ThemingConfiguration { pub font: String, } -#[derive(Serialize,Deserialize,PartialEq,Eq,Debug,Clone)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] #[serde(default)] #[derive(Default)] pub struct NoDecorThemingConfiguration { @@ -120,7 +119,7 @@ pub struct NoDecorThemingConfiguration { pub outer_border_width: u32, } -#[derive(Serialize,Deserialize,Clone,Copy,Debug,PartialEq,Eq)] +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[derive(Default)] pub enum WindowPlacement { @@ -130,7 +129,6 @@ pub enum WindowPlacement { Wherever, } - impl Default for Configuration { fn default() -> Self { Configuration { @@ -177,12 +175,13 @@ impl Default for ThemingConfiguration { } } - - - - impl WindowPlacement { - pub fn calc(&self, client_dimensions: Dimensions, window_area: Dimensions, pointer: (i32, i32)) -> (i32, i32) { + pub fn calc( + &self, + client_dimensions: Dimensions, + window_area: Dimensions, + pointer: (i32, i32), + ) -> (i32, i32) { use WindowPlacement::*; match self { Pointer => { @@ -191,21 +190,26 @@ impl WindowPlacement { y -= (client_dimensions.h() / 2) as i32; x = cmp::max(x, window_area.x()); y = cmp::max(y, window_area.y()); - x = cmp::min(x, window_area.x() + window_area.w() as i32 - client_dimensions.w() as i32); - y = cmp::min(y, window_area.y() + window_area.h() as i32 - client_dimensions.h() as i32); + x = cmp::min( + x, + window_area.x() + window_area.w() as i32 - client_dimensions.w() as i32, + ); + y = cmp::min( + y, + window_area.y() + window_area.h() as i32 - client_dimensions.h() as i32, + ); (x, y) - }, + } Centered => { let x = window_area.center().0 - (client_dimensions.w() as i32 / 2); let y = window_area.center().1 - (client_dimensions.h() as i32 / 2); (x, y) - }, + } Wherever => client_dimensions.pos(), } } } - pub fn read_button_bindings() -> Vec { // read keybindings file let mut button_bindings = match read_config_file(CONFIG_DIR, BUTTON_BINDINGS_FILE) { @@ -213,7 +217,7 @@ pub fn read_button_bindings() -> Vec { Err(msg) => { eprintln!("Unable to read button bindings: {}", msg); default_button_bindings() - }, + } }; // read extended keybindings @@ -221,7 +225,7 @@ pub fn read_button_bindings() -> Vec { Ok(config) => button_bindings.extend(config), Err(msg) => { eprintln!("Unable to read extended button bindings: {}", msg); - }, + } } button_bindings @@ -233,7 +237,7 @@ pub fn read_config() -> Configuration { Err(msg) => { eprintln!("Unable to read configuration: {}", msg); Configuration::default() - }, + } } } @@ -244,7 +248,7 @@ pub fn read_key_bindings(nworkspaces: u32) -> Vec { Err(msg) => { eprintln!("Unable to read key bindings: {}", msg); default_key_bindings(nworkspaces) - }, + } }; // read extended keybindings @@ -252,7 +256,7 @@ pub fn read_key_bindings(nworkspaces: u32) -> Vec { Ok(config) => keybindings.extend(config), Err(msg) => { eprintln!("Unable to read extended key bindings: {}", msg); - }, + } } keybindings @@ -265,7 +269,6 @@ pub fn read_rules() -> Vec { Err(msg) => { eprintln!("Unable to read window rules: {}", msg); Vec::new() - }, + } } } - diff --git a/marswm/src/layouts.rs b/marswm/src/layouts.rs index 9f8cb47d..a23e9468 100644 --- a/marswm/src/layouts.rs +++ b/marswm/src/layouts.rs @@ -1,14 +1,13 @@ use libmars::common::*; use libmars::enum_with_values; use libmars::interfaces::wm::Client; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::rc::Rc; use crate::attributes::*; use crate::config::LayoutConfiguration; - enum_with_values! { #[derive(Serialize,Deserialize,Clone,Copy,Debug,PartialEq,Eq)] #[serde(rename_all = "kebab-case")] @@ -84,14 +83,25 @@ impl> Layout { } } - pub fn apply_layout(&self, win_area: Dimensions, clients: &[Rc>], config: &LayoutConfiguration) { + pub fn apply_layout( + &self, + win_area: Dimensions, + clients: &[Rc>], + config: &LayoutConfiguration, + ) { (self.apply)(win_area, clients, config); } } -fn apply_layout_centered>(win_area: Dimensions, clients: &[Rc>], config: &LayoutConfiguration) { +fn apply_layout_centered>( + win_area: Dimensions, + clients: &[Rc>], + config: &LayoutConfiguration, +) { let mut clients = clients.iter(); - let main_clients: Vec<_> = (&mut clients).take(config.nmain.try_into().unwrap()).collect(); + let main_clients: Vec<_> = (&mut clients) + .take(config.nmain.try_into().unwrap()) + .collect(); let mut stack_clients_0: Vec<_> = clients.collect(); let stack_clients_1 = stack_clients_0.split_off(stack_clients_0.len() / 2); let adjusted_main_ratio = config.main_ratio / (2. - config.main_ratio); @@ -111,7 +121,6 @@ fn apply_layout_centered>(win_area: Dimensions, clients: & (main_width, main_dimensions) }; - let stack_width_0 = (win_area.w() - main_width) / 2; let stack_width_1 = win_area.w() - main_width - stack_width_0; @@ -134,29 +143,70 @@ fn apply_layout_centered>(win_area: Dimensions, clients: & stack_clients_vertically(stack_dimensions_1, stack_clients_1, config.gap_width); } - -fn apply_layout_bottom_stack>(win_area: Dimensions, clients: &[Rc>], config: &LayoutConfiguration) { +fn apply_layout_bottom_stack>( + win_area: Dimensions, + clients: &[Rc>], + config: &LayoutConfiguration, +) { let mut config = *config; config.stack_position = StackPosition::Bottom; config.stack_mode = StackMode::Split; apply_layout_dynamic(win_area, clients, &config); } -fn apply_layout_dynamic>(win_area: Dimensions, clients: &[Rc>], config: &LayoutConfiguration) { +fn apply_layout_dynamic>( + win_area: Dimensions, + clients: &[Rc>], + config: &LayoutConfiguration, +) { let nclients: u32 = clients.len().try_into().unwrap(); let mut clients = clients.iter(); - let main_clients = (&mut clients).take(config.nmain.try_into().unwrap()).collect(); + let main_clients = (&mut clients) + .take(config.nmain.try_into().unwrap()) + .collect(); let stack_clients = clients.collect(); let (areas, swap) = match config.stack_position { - StackPosition::Left => (layout_dimensions_horizontal(win_area, 1.0 - config.main_ratio, config.gap_width, - config.nmain, nclients), true), - StackPosition::Top => (layout_dimensions_vertical(win_area, 1.0 - config.main_ratio, config.gap_width, - config.nmain, nclients), true), - StackPosition::Right => (layout_dimensions_horizontal(win_area, config.main_ratio, config.gap_width, - config.nmain, nclients), false), - StackPosition::Bottom => (layout_dimensions_vertical(win_area, config.main_ratio, config.gap_width, - config.nmain, nclients), false), + StackPosition::Left => ( + layout_dimensions_horizontal( + win_area, + 1.0 - config.main_ratio, + config.gap_width, + config.nmain, + nclients, + ), + true, + ), + StackPosition::Top => ( + layout_dimensions_vertical( + win_area, + 1.0 - config.main_ratio, + config.gap_width, + config.nmain, + nclients, + ), + true, + ), + StackPosition::Right => ( + layout_dimensions_horizontal( + win_area, + config.main_ratio, + config.gap_width, + config.nmain, + nclients, + ), + false, + ), + StackPosition::Bottom => ( + layout_dimensions_vertical( + win_area, + config.main_ratio, + config.gap_width, + config.nmain, + nclients, + ), + false, + ), }; let (main_area, stack_area) = if swap { @@ -169,7 +219,7 @@ fn apply_layout_dynamic>(win_area: Dimensions, clients: &[ match config.stack_position { StackPosition::Left | StackPosition::Right => { stack_clients_vertically(main_area, main_clients, config.gap_width); - }, + } StackPosition::Top | StackPosition::Bottom => { stack_clients_horizontally(main_area, main_clients, config.gap_width); } @@ -180,38 +230,57 @@ fn apply_layout_dynamic>(win_area: Dimensions, clients: &[ StackMode::Split => match config.stack_position { StackPosition::Left | StackPosition::Right => { stack_clients_vertically(stack_area, stack_clients, config.gap_width); - }, + } StackPosition::Top | StackPosition::Bottom => { stack_clients_horizontally(stack_area, stack_clients, config.gap_width); } - } + }, } } -fn apply_layout_stack>(win_area: Dimensions, clients: &[Rc>], config: &LayoutConfiguration) { +fn apply_layout_stack>( + win_area: Dimensions, + clients: &[Rc>], + config: &LayoutConfiguration, +) { let mut config = *config; config.stack_position = StackPosition::Right; config.stack_mode = StackMode::Split; apply_layout_dynamic(win_area, clients, &config); } -fn apply_layout_monocle(win_area: Dimensions, clients: &[Rc>>], _config: &LayoutConfiguration) { +fn apply_layout_monocle( + win_area: Dimensions, + clients: &[Rc>>], + _config: &LayoutConfiguration, +) { let clients = clients.iter().collect(); stack_clients_ontop(win_area, clients); } -fn apply_layout_deck(win_area: Dimensions, clients: &[Rc>>], config: &LayoutConfiguration) { +fn apply_layout_deck( + win_area: Dimensions, + clients: &[Rc>>], + config: &LayoutConfiguration, +) { let mut config = *config; config.stack_position = StackPosition::Right; config.stack_mode = StackMode::Deck; apply_layout_dynamic(win_area, clients, &config); } -fn layout_dimensions_horizontal(win_area: Dimensions, ratio: f32, gap_width: u32, nmain: u32, nclients: u32) -> (Dimensions, Dimensions) { +fn layout_dimensions_horizontal( + win_area: Dimensions, + ratio: f32, + gap_width: u32, + nmain: u32, + nclients: u32, +) -> (Dimensions, Dimensions) { let first_width: u32 = (win_area.w() as f32 * ratio) as u32; let gap_share = (gap_width / 2, gap_width - (gap_width / 2)); - if nmain == 0 { // all windows in stack area + if nmain == 0 { + // all windows in stack area let first_area = Dimensions::new(0, 0, 0, 0); let second_x = win_area.x() + gap_width as i32; let second_y = win_area.y() + gap_width as i32; @@ -219,7 +288,8 @@ fn layout_dimensions_horizontal(win_area: Dimensions, ratio: f32, gap_width: u32 let second_h = win_area.h().saturating_sub(2 * gap_width); let second_area = Dimensions::new(second_x, second_y, second_w, second_h); (first_area, second_area) - } else if nclients <= nmain { // no windows in stack area + } else if nclients <= nmain { + // no windows in stack area let second_area = Dimensions::new(0, 0, 0, 0); let first_x = win_area.x() + gap_width as i32; let first_y = win_area.y() + gap_width as i32; @@ -230,24 +300,37 @@ fn layout_dimensions_horizontal(win_area: Dimensions, ratio: f32, gap_width: u32 } else { let first_x = win_area.x() + gap_width as i32; let first_y = win_area.y() + gap_width as i32; - let first_w = first_width.saturating_sub(gap_width).saturating_sub(gap_share.0); + let first_w = first_width + .saturating_sub(gap_width) + .saturating_sub(gap_share.0); let first_h = win_area.h().saturating_sub(2 * gap_width); let first_area = Dimensions::new(first_x, first_y, first_w, first_h); let second_x = win_area.x() + first_width as i32 + gap_share.0 as i32; let second_y = win_area.y() + gap_width as i32; - let second_w = win_area.w().saturating_sub(first_width).saturating_sub(gap_width).saturating_sub(gap_share.1); + let second_w = win_area + .w() + .saturating_sub(first_width) + .saturating_sub(gap_width) + .saturating_sub(gap_share.1); let second_h = win_area.h().saturating_sub(2 * gap_width); let second_area = Dimensions::new(second_x, second_y, second_w, second_h); (first_area, second_area) } } -fn layout_dimensions_vertical(win_area: Dimensions, ratio: f32, gap_width: u32, nmain: u32, nclients: u32) -> (Dimensions, Dimensions) { +fn layout_dimensions_vertical( + win_area: Dimensions, + ratio: f32, + gap_width: u32, + nmain: u32, + nclients: u32, +) -> (Dimensions, Dimensions) { let first_height: u32 = (win_area.h() as f32 * ratio) as u32; let gap_share = (gap_width / 2, gap_width - (gap_width / 2)); - if nmain == 0 { // all windows in stack area + if nmain == 0 { + // all windows in stack area let first_area = Dimensions::new(0, 0, 0, 0); let second_x = win_area.x() + gap_width as i32; let second_y = win_area.y() + gap_width as i32; @@ -255,7 +338,8 @@ fn layout_dimensions_vertical(win_area: Dimensions, ratio: f32, gap_width: u32, let second_h = win_area.h().saturating_sub(2 * gap_width); let second_area = Dimensions::new(second_x, second_y, second_w, second_h); (first_area, second_area) - } else if nclients <= nmain { // no windows in stack area + } else if nclients <= nmain { + // no windows in stack area let second_area = Dimensions::new(0, 0, 0, 0); let first_x = win_area.x() + gap_width as i32; let first_y = win_area.y() + gap_width as i32; @@ -267,19 +351,29 @@ fn layout_dimensions_vertical(win_area: Dimensions, ratio: f32, gap_width: u32, let first_x = win_area.x() + gap_width as i32; let first_y = win_area.y() + gap_width as i32; let first_w = win_area.w().saturating_sub(2 * gap_width); - let first_h = first_height.saturating_sub(gap_width).saturating_sub(gap_share.0); + let first_h = first_height + .saturating_sub(gap_width) + .saturating_sub(gap_share.0); let first_area = Dimensions::new(first_x, first_y, first_w, first_h); let second_x = win_area.x() + gap_width as i32; let second_y = win_area.y() + first_height as i32 + gap_share.0 as i32; let second_w = win_area.w().saturating_sub(2 * gap_width); - let second_h = win_area.h().saturating_sub(first_height).saturating_sub(gap_width).saturating_sub(gap_share.0); + let second_h = win_area + .h() + .saturating_sub(first_height) + .saturating_sub(gap_width) + .saturating_sub(gap_share.0); let second_area = Dimensions::new(second_x, second_y, second_w, second_h); (first_area, second_area) } } -fn stack_clients_horizontally(area: Dimensions, clients: Vec<&Rc>>>, gap_width: u32) { +fn stack_clients_horizontally( + area: Dimensions, + clients: Vec<&Rc>>>, + gap_width: u32, +) { let nclients: u32 = clients.len().try_into().unwrap(); if nclients == 0 { return; @@ -294,13 +388,21 @@ fn stack_clients_horizontally(area: Dimensions, clients: Vec<&Rc>>>, gap_width: u32) { +fn stack_clients_vertically( + area: Dimensions, + clients: Vec<&Rc>>>, + gap_width: u32, +) { let nclients: u32 = clients.len().try_into().unwrap(); if nclients == 0 { return; @@ -315,7 +417,11 @@ fn stack_clients_vertically(area: Dimensions, clients: Vec<&Rc { $client_rc.borrow().attributes().is_floating - || $wm.get_workspace($client_rc) - .map(|ws| ws.current_layout() == LayoutType::Floating) - .unwrap_or(false) - } + || $wm + .get_workspace($client_rc) + .map(|ws| ws.current_layout() == LayoutType::Floating) + .unwrap_or(false) + }; } diff --git a/marswm/src/main.rs b/marswm/src/main.rs index abd9e9c6..bd11dddb 100644 --- a/marswm/src/main.rs +++ b/marswm/src/main.rs @@ -2,9 +2,9 @@ #![allow(clippy::comparison_chain)] use clap::Parser; -use libmars::utils::configuration::*; use libmars::interfaces::wm::*; use libmars::platforms::x11::wm::backend::X11Backend; +use libmars::utils::configuration::*; use std::cell::RefCell; use std::rc::Rc; @@ -13,7 +13,6 @@ use crate::bindings::*; use crate::config::*; use crate::marswm::*; - mod attributes; mod bindings; mod config; @@ -24,10 +23,8 @@ mod monitor; mod rules; mod workspace; - const DOCS_URL: &str = "https://jzbor.de/marswm"; - /// A dynamic window manager #[derive(Parser)] #[clap(author, version, about, long_about = None)] @@ -65,7 +62,6 @@ pub struct Args { print_rules: bool, } - trait ClientList> { fn attach_client(&mut self, client_rc: Rc>); fn clients(&self) -> Box>> + '_>; @@ -103,12 +99,13 @@ fn main() { let args = Args::parse(); if args.docs { - let result = std::process::Command::new("xdg-open") - .arg(DOCS_URL) - .spawn(); + let result = std::process::Command::new("xdg-open").arg(DOCS_URL).spawn(); match result { Ok(_) => (), - Err(e) => { eprintln!("Error: {}", e); std::process::exit(1); } + Err(e) => { + eprintln!("Error: {}", e); + std::process::exit(1); + } } } else if args.print_default_config { print_config(&Configuration::default()); @@ -133,11 +130,15 @@ fn main() { // run startup script if let Some(startup_cmd) = &config.on_startup - && let Ok(mut handle) = std::process::Command::new("sh").arg("-c").arg(startup_cmd).spawn() { - std::thread::spawn(move || { - let _ignored = handle.wait(); - }); - } + && let Ok(mut handle) = std::process::Command::new("sh") + .arg("-c") + .arg(startup_cmd) + .spawn() + { + std::thread::spawn(move || { + let _ignored = handle.wait(); + }); + } let mut backend = X11Backend::init("marswm").unwrap(); let mut wm = MarsWM::new(&mut backend, config, key_bindings, button_bindings, rules); diff --git a/marswm/src/marswm.rs b/marswm/src/marswm.rs index d63d6327..ddd1298a 100644 --- a/marswm/src/marswm.rs +++ b/marswm/src/marswm.rs @@ -1,6 +1,6 @@ use libmars::common::*; +use libmars::interfaces::wm::{Backend, Client, WindowManager}; use libmars::platforms::x11::misc::WINDOW_MIN_SIZE; -use libmars::interfaces::wm::{ Backend, Client, WindowManager }; use std::cell::RefCell; use std::env; use std::marker::PhantomData; @@ -9,12 +9,11 @@ use std::path::PathBuf; use std::process; use std::rc::Rc; -use crate::*; +use crate::layouts::LayoutType; use crate::monitor::*; use crate::rules::*; use crate::workspace::*; -use crate::layouts::LayoutType; - +use crate::*; pub struct MarsWM> { backend_phantom: PhantomData, @@ -29,8 +28,13 @@ pub struct MarsWM> { } impl> MarsWM { - pub fn new(backend: &mut B, config: Configuration, key_bindings: Vec, - button_bindings: Vec, rules: Vec) -> MarsWM { + pub fn new( + backend: &mut B, + config: Configuration, + key_bindings: Vec, + button_bindings: Vec, + rules: Vec, + ) -> MarsWM { // stores exec path to enable reloading after rebuild // might have security implications let mut wm = MarsWM { @@ -42,11 +46,12 @@ impl> MarsWM { monitors: Vec::new(), key_bindings, button_bindings, - rules + rules, }; let monitor_config = backend.get_monitor_config(); - (&mut wm as &mut dyn WindowManager).update_monitor_config(backend, monitor_config); + (&mut wm as &mut dyn WindowManager) + .update_monitor_config(backend, monitor_config); backend.export_current_workspace(0); backend.handle_existing_windows(&mut wm); @@ -54,11 +59,18 @@ impl> MarsWM { wm } - pub fn apply_window_rules(&self, backend: &mut B, client_rc: Rc>, app_workspace_pref: Option) - -> Option<(u32, Vec, Option)> { - let rules: Vec = self.rules.iter() + pub fn apply_window_rules( + &self, + backend: &mut B, + client_rc: Rc>, + app_workspace_pref: Option, + ) -> Option<(u32, Vec, Option)> { + let rules: Vec = self + .rules + .iter() .filter(|r| r.matches(client_rc.clone())) - .cloned().collect(); + .cloned() + .collect(); let mut actions = vec![]; let mut initial_placement = None; @@ -68,7 +80,6 @@ impl> MarsWM { None => current_workspace, }; - for rule in rules { if rule.ignore_window() { // make the window visible, but do not manage it @@ -116,8 +127,10 @@ impl> MarsWM { let cursor_pos = backend.pointer_pos(); let monitor_by_pointer = self.monitors.iter().find(|m| { let dims = m.config().dimensions(); - dims.x() <= cursor_pos.0 && cursor_pos.0 < dims.x() + (dims.w() as i32) - && dims.y() <= cursor_pos.1 && cursor_pos.1 < dims.y() + (dims.h() as i32) + dims.x() <= cursor_pos.0 + && cursor_pos.0 < dims.x() + (dims.w() as i32) + && dims.y() <= cursor_pos.1 + && cursor_pos.1 < dims.y() + (dims.h() as i32) }); if let Some(monitor) = monitor_by_pointer { @@ -197,8 +210,12 @@ impl> MarsWM { pub fn cycle_workspace(&mut self, backend: &mut B, inc: i32) { let monitor = self.current_monitor(backend); - let cur_workspace_idx = monitor.workspaces().position(|ws| ws == self.current_workspace(backend)).unwrap(); - let new_workspace_idx = monitor.workspace_offset() + ((cur_workspace_idx as i32 + inc) as u32 % monitor.workspace_count()); + let cur_workspace_idx = monitor + .workspaces() + .position(|ws| ws == self.current_workspace(backend)) + .unwrap(); + let new_workspace_idx = monitor.workspace_offset() + + ((cur_workspace_idx as i32 + inc) as u32 % monitor.workspace_count()); self.switch_workspace(backend, new_workspace_idx); } @@ -243,7 +260,9 @@ impl> MarsWM { } pub fn is_tiled(&self, client_rc: &Rc>) -> bool { - let mut tiled_clients = self.monitors.iter() + let mut tiled_clients = self + .monitors + .iter() .flat_map(|m| m.workspaces()) .flat_map(|ws| ws.tiled_clients()); tiled_clients.any(|c| c == client_rc) @@ -253,17 +272,32 @@ impl> MarsWM { self.monitors.iter().find(|m| m.contains(client_rc)) } - pub fn get_monitor_mut(&mut self, client_rc: &Rc>) -> Option<&mut Monitor> { + pub fn get_monitor_mut( + &mut self, + client_rc: &Rc>, + ) -> Option<&mut Monitor> { self.monitors.iter_mut().find(|m| m.contains(client_rc)) } - pub fn get_workspace(&self, client_rc: &Rc>) -> Option<&Workspace> { - return self.monitors.iter().flat_map(|m| m.workspaces()) + pub fn get_workspace( + &self, + client_rc: &Rc>, + ) -> Option<&Workspace> { + return self + .monitors + .iter() + .flat_map(|m| m.workspaces()) .find(|ws| ws.contains(client_rc)); } - pub fn get_workspace_mut(&mut self, client_rc: &Rc>) -> Option<&mut Workspace> { - return self.monitors.iter_mut().flat_map(|m| m.workspaces_mut()) + pub fn get_workspace_mut( + &mut self, + client_rc: &Rc>, + ) -> Option<&mut Workspace> { + return self + .monitors + .iter_mut() + .flat_map(|m| m.workspaces_mut()) .find(|ws| ws.contains(client_rc)); } @@ -274,18 +308,29 @@ impl> MarsWM { process::exit(0); } - pub fn mouse_action_place(_backend: &mut B, wm: &mut Self, client_rc: &Rc>, - orig_client_pos: (i32, i32), _orig_client_size: (u32, u32), delta: (i32, i32)) { + pub fn mouse_action_place( + _backend: &mut B, + wm: &mut Self, + client_rc: &Rc>, + orig_client_pos: (i32, i32), + _orig_client_size: (u32, u32), + delta: (i32, i32), + ) { let dest_x = orig_client_pos.0 + delta.0; let dest_y = orig_client_pos.1 + delta.1; let size = client_rc.borrow().size(); - client_rc.borrow_mut().move_resize(dest_x, dest_y, size.0, size.1); + client_rc + .borrow_mut() + .move_resize(dest_x, dest_y, size.0, size.1); let client_center = client_rc.borrow().center(); if let Some(workspace) = wm.get_workspace_mut(client_rc) { - let other_index_option = workspace.tiled_clients() + let other_index_option = workspace + .tiled_clients() .enumerate() - .find(|(_, c)| *c != client_rc && c.borrow().dimensions().contains_point(client_center)) + .find(|(_, c)| { + *c != client_rc && c.borrow().dimensions().contains_point(client_center) + }) .map(|(i, _)| i); if let Some(index) = other_index_option { workspace.stack_set_pos(client_rc.clone(), index); @@ -294,18 +339,33 @@ impl> MarsWM { } } - pub fn mouse_action_resize_centered(_backend: &mut B, _wm: &mut Self, client_rc: &Rc>, - orig_client_pos: (i32, i32), orig_client_size: (u32, u32), delta: (i32, i32)) { + pub fn mouse_action_resize_centered( + _backend: &mut B, + _wm: &mut Self, + client_rc: &Rc>, + orig_client_pos: (i32, i32), + orig_client_size: (u32, u32), + delta: (i32, i32), + ) { let dest_w = orig_client_size.0 as i32 + 2 * delta.0; let dest_h = orig_client_size.1 as i32 + 2 * delta.1; - let dest_w: u32 = if dest_w < WINDOW_MIN_SIZE as i32 { WINDOW_MIN_SIZE } else { dest_w as u32 }; - let dest_h: u32 = if dest_h < WINDOW_MIN_SIZE as i32 { WINDOW_MIN_SIZE } else { dest_h as u32 }; + let dest_w: u32 = if dest_w < WINDOW_MIN_SIZE as i32 { + WINDOW_MIN_SIZE + } else { + dest_w as u32 + }; + let dest_h: u32 = if dest_h < WINDOW_MIN_SIZE as i32 { + WINDOW_MIN_SIZE + } else { + dest_h as u32 + }; let dest_x: i32 = orig_client_pos.0 - delta.0; let dest_y: i32 = orig_client_pos.1 - delta.1; - client_rc.borrow_mut().move_resize(dest_x, dest_y, dest_w, dest_h); + client_rc + .borrow_mut() + .move_resize(dest_x, dest_y, dest_w, dest_h); } - pub fn mouse_place(&mut self, backend: &mut B, client_rc: Rc>) { let mut client = client_rc.borrow_mut(); let was_fullscreen = client.is_fullscreen(); @@ -325,10 +385,9 @@ impl> MarsWM { ws.restack() } - if was_fullscreen - && let Some(mon) = self.get_monitor(&client_rc) { - client_rc.borrow_mut().set_fullscreen(mon.config()); - } + if was_fullscreen && let Some(mon) = self.get_monitor(&client_rc) { + client_rc.borrow_mut().set_fullscreen(mon.config()); + } } pub fn mouse_resize_centered(&mut self, backend: &mut B, client_rc: Rc>) { @@ -341,15 +400,26 @@ impl> MarsWM { client.raise(); drop(client); - backend.mouse_action(self, client_rc.clone(), 120, Self::mouse_action_resize_centered); + backend.mouse_action( + self, + client_rc.clone(), + 120, + Self::mouse_action_resize_centered, + ); client_rc.borrow_mut().attributes_mut().is_moving = false; self.current_workspace_mut(backend).restack(); } pub fn move_client_to_monitor(&mut self, client_rc: Rc>, inc: i32) { - let client_index_opt = self.get_monitor(&client_rc).and_then(|cm| self.monitors.iter().position(|m| m == cm)); - let client_index = if let Some(ci) = client_index_opt { ci } else { return }; + let client_index_opt = self + .get_monitor(&client_rc) + .and_then(|cm| self.monitors.iter().position(|m| m == cm)); + let client_index = if let Some(ci) = client_index_opt { + ci + } else { + return; + }; let target_index = (client_index as i32 + inc) as usize % self.monitors.len(); self.monitors[client_index].detach_client(&client_rc); @@ -357,7 +427,9 @@ impl> MarsWM { self.monitors[target_index].attach_client(client_rc.clone()); if client_rc.borrow().is_fullscreen() { - client_rc.borrow_mut().set_fullscreen(self.monitors[target_index].config()) + client_rc + .borrow_mut() + .set_fullscreen(self.monitors[target_index].config()) } } @@ -392,8 +464,11 @@ impl> MarsWM { if absolute_idx < self.config.primary_workspaces { (0, absolute_idx) } else { - let mon_idx = 1 + ((absolute_idx - self.config.primary_workspaces) / self.config.secondary_workspaces); - let rel_idx = (absolute_idx - self.config.primary_workspaces) % self.config.secondary_workspaces; + let mon_idx = 1 + + ((absolute_idx - self.config.primary_workspaces) + / self.config.secondary_workspaces); + let rel_idx = + (absolute_idx - self.config.primary_workspaces) % self.config.secondary_workspaces; (mon_idx as usize, rel_idx) } } @@ -425,7 +500,10 @@ impl> MarsWM { } pub fn switch_prev_workspace(&mut self, backend: &mut B) { - let prev_index = self.current_monitor(backend).prev_workspace().global_index(); + let prev_index = self + .current_monitor(backend) + .prev_workspace() + .global_index(); self.switch_workspace(backend, prev_index); } } @@ -436,15 +514,19 @@ impl> WindowManager for MarsWM { } fn active_workspace(&self, backend: &mut B) -> u32 { - self.current_monitor(backend).current_workspace().global_index() + self.current_monitor(backend) + .current_workspace() + .global_index() } fn activate_client(&mut self, backend: &mut B, client_rc: Rc>) { let monitor = self.get_monitor_mut(&client_rc).unwrap(); // switch workspace - let option = monitor.workspaces() - .find(|ws| ws.contains(&client_rc)).map(|ws| ws.global_index()); + let option = monitor + .workspaces() + .find(|ws| ws.contains(&client_rc)) + .map(|ws| ws.global_index()); if let Some(workspace_idx) = option { self.switch_workspace(backend, workspace_idx); @@ -459,8 +541,12 @@ impl> WindowManager for MarsWM { } fn center_client(&mut self, _backend: &mut B, client_rc: Rc>) { - if is_floating!(self, &client_rc) && let Some(mon) = self.get_monitor(&client_rc) { - client_rc.borrow_mut().center_on_screen(mon.config().window_area()); + if is_floating!(self, &client_rc) + && let Some(mon) = self.get_monitor(&client_rc) + { + client_rc + .borrow_mut() + .center_on_screen(mon.config().window_area()); } } @@ -501,7 +587,12 @@ impl> WindowManager for MarsWM { backend.export_active_window(&self.active_client); } - fn fullscreen_client(&mut self, _backend: &mut B, client_rc: Rc>, state: bool) { + fn fullscreen_client( + &mut self, + _backend: &mut B, + client_rc: Rc>, + state: bool, + ) { if let Some(mon) = self.get_monitor_mut(&client_rc) { if state { client_rc.borrow_mut().set_fullscreen(mon.config()); @@ -515,8 +606,14 @@ impl> WindowManager for MarsWM { } } - fn handle_button(&mut self, backend: &mut B, modifiers: u32, button: u32, target: ButtonTarget, - client_option: Option>>) { + fn handle_button( + &mut self, + backend: &mut B, + modifiers: u32, + button: u32, + target: ButtonTarget, + client_option: Option>>, + ) { if let Some(client) = client_option.clone() { if let Some(ws) = self.get_workspace_mut(&client) { ws.raise_client(&client); @@ -526,42 +623,67 @@ impl> WindowManager for MarsWM { }; } - let actions: Vec = self.button_bindings.iter().filter(|bb| bb.matches(modifiers, button, target)) - .map(|kb| kb.action()).collect(); + let actions: Vec = self + .button_bindings + .iter() + .filter(|bb| bb.matches(modifiers, button, target)) + .map(|kb| kb.action()) + .collect(); for action in actions { action.execute(self, backend, client_option.clone()); } } - fn handle_key(&mut self, backend: &mut B, modifiers: u32, key: u32, client_option: Option>>) { - let actions: Vec = self.key_bindings.iter().filter(|kb| kb.matches(modifiers, key)) - .map(|kb| kb.action()).collect(); + fn handle_key( + &mut self, + backend: &mut B, + modifiers: u32, + key: u32, + client_option: Option>>, + ) { + let actions: Vec = self + .key_bindings + .iter() + .filter(|kb| kb.matches(modifiers, key)) + .map(|kb| kb.action()) + .collect(); for action in actions { action.execute(self, backend, client_option.clone()); } } - fn manage(&mut self, backend: &mut B, client_rc: Rc>, workspace_preference: Option) { - let (workspace_idx, actions, initial_placement) - = match self.apply_window_rules(backend, client_rc.clone(), workspace_preference) { - Some(params) => params, - None => return, - }; + fn manage( + &mut self, + backend: &mut B, + client_rc: Rc>, + workspace_preference: Option, + ) { + let (workspace_idx, actions, initial_placement) = + match self.apply_window_rules(backend, client_rc.clone(), workspace_preference) { + Some(params) => params, + None => return, + }; self.clients.push(client_rc.clone()); // attach client to monitor or workspace let (mon, rel_ws) = self.relative_workspace_idx(workspace_idx); - if let Some(workspace) = self.monitors.get_mut(mon).and_then(|m| m.workspace_mut(rel_ws)) { + if let Some(workspace) = self + .monitors + .get_mut(mon) + .and_then(|m| m.workspace_mut(rel_ws)) + { workspace.attach_client(client_rc.clone()); - } else if let Some(monitor) = backend.point_to_monitor(client_rc.borrow().center()) - .and_then(|m| self.monitors.get_mut(m as usize)) { + } else if let Some(monitor) = backend + .point_to_monitor(client_rc.borrow().center()) + .and_then(|m| self.monitors.get_mut(m as usize)) + { monitor.attach_client(client_rc.clone()); } else { - self.current_monitor_mut(backend).attach_client(client_rc.clone()); + self.current_monitor_mut(backend) + .attach_client(client_rc.clone()); } - let mut client = (*client_rc).borrow_mut(); // configure look @@ -570,10 +692,12 @@ impl> WindowManager for MarsWM { client.set_outer_bw(self.config.theming.outer_border_width); client.set_frame_width(self.config.theming.frame_width); if self.config.theming.show_title { - let _ignore_result = client.add_title(&self.config.theming.font, - self.config.theming.title_hpadding, - self.config.theming.title_vpadding, - self.config.theming.active_color); + let _ignore_result = client.add_title( + &self.config.theming.font, + self.config.theming.title_hpadding, + self.config.theming.title_vpadding, + self.config.theming.active_color, + ); } } else { client.set_inner_bw(self.config.theming.no_decoration.inner_border_width); @@ -581,7 +705,6 @@ impl> WindowManager for MarsWM { client.set_frame_width(self.config.theming.no_decoration.frame_width); } - // bind keys and buttons for key_binding in &self.key_bindings { client.bind_key(key_binding.modifiers(), key_binding.key()); @@ -589,7 +712,11 @@ impl> WindowManager for MarsWM { for button_binding in &self.button_bindings { for target in button_binding.targets() { if *target != ButtonTarget::Root { - client.bind_button(button_binding.modifiers(), button_binding.button(), *target); + client.bind_button( + button_binding.modifiers(), + button_binding.button(), + *target, + ); } } } @@ -607,7 +734,11 @@ impl> WindowManager for MarsWM { Some(placement) => placement, None => self.config.initial_placement, }; - let pos = placement.calc(client_rc.borrow().dimensions(), monitor.window_area(), pointer_pos); + let pos = placement.calc( + client_rc.borrow().dimensions(), + monitor.window_area(), + pointer_pos, + ); client_rc.borrow_mut().set_pos(pos); } @@ -628,10 +759,18 @@ impl> WindowManager for MarsWM { backend.export_client_list(clients, clients_stacked); // apply window rule actions - actions.iter().for_each(|a| a.execute(self, backend, Some(client_rc.clone()))) + actions + .iter() + .for_each(|a| a.execute(self, backend, Some(client_rc.clone()))) } - fn move_request(&mut self, _backend: &mut B, client_rc: Rc>, x: i32, y: i32) -> bool { + fn move_request( + &mut self, + _backend: &mut B, + client_rc: Rc>, + x: i32, + y: i32, + ) -> bool { if is_floating!(self, &client_rc) { let mut client = client_rc.borrow_mut(); let (width, height) = client.size(); @@ -642,10 +781,20 @@ impl> WindowManager for MarsWM { } } - fn move_to_workspace(&mut self, backend: &mut B, client_rc: Rc>, workspace_idx: u32) { + fn move_to_workspace( + &mut self, + backend: &mut B, + client_rc: Rc>, + workspace_idx: u32, + ) { let (mon_idx, rel_idx) = self.relative_workspace_idx(workspace_idx); - if self.monitors.get(mon_idx).map(|m| m.workspace(rel_idx)).is_none() { + if self + .monitors + .get(mon_idx) + .map(|m| m.workspace(rel_idx)) + .is_none() + { // avoid loosing windows on invalid indices return; } @@ -656,17 +805,29 @@ impl> WindowManager for MarsWM { }; from_workspace.detach_client(&client_rc); - let to_workspace = match self.monitors.get_mut(mon_idx).and_then(|m| m.workspace_mut(rel_idx)) { + let to_workspace = match self + .monitors + .get_mut(mon_idx) + .and_then(|m| m.workspace_mut(rel_idx)) + { Some(workspace) => workspace, None => panic!("Window is detached but cannot be attached again"), }; to_workspace.attach_client(client_rc.clone()); // adjust position to be on workspace - Self::fix_client_to_area(client_rc.clone(), self.get_monitor_mut(&client_rc).unwrap().window_area()); + Self::fix_client_to_area( + client_rc.clone(), + self.get_monitor_mut(&client_rc).unwrap().window_area(), + ); self.decorate_inactive(client_rc.clone()); - if !self.monitors.iter().map(|m| m.current_workspace()).any(|ws| ws.contains(&client_rc)) { + if !self + .monitors + .iter() + .map(|m| m.current_workspace()) + .any(|ws| ws.contains(&client_rc)) + { client_rc.borrow_mut().hide(); } @@ -676,22 +837,31 @@ impl> WindowManager for MarsWM { backend.export_active_window(&self.active_client); } - fn resize_request(&mut self, _backend: &mut B, client_rc: Rc>, width: u32, height: u32) -> bool { + fn resize_request( + &mut self, + _backend: &mut B, + client_rc: Rc>, + width: u32, + height: u32, + ) -> bool { let window_area = self.get_monitor(&client_rc).map(|m| m.window_area()); let client_is_dialog = client_rc.borrow().is_dialog(); if is_floating!(self, &client_rc) || client_is_dialog { let mut client = client_rc.borrow_mut(); let (x, y) = client.pos(); - let client_was_centered = window_area.map(|a| client.is_centered_on_screen(a)) + let client_was_centered = window_area + .map(|a| client.is_centered_on_screen(a)) .unwrap_or(false); client.move_resize(x, y, width, height); - if client_is_dialog && client_was_centered - && let Some(area) = window_area { - client.center_on_screen(area); - } + if client_is_dialog + && client_was_centered + && let Some(area) = window_area + { + client.center_on_screen(area); + } true } else { @@ -699,7 +869,12 @@ impl> WindowManager for MarsWM { } } - fn set_client_pinned(&mut self, _backend: &mut B, client_rc: Rc>, state: bool) { + fn set_client_pinned( + &mut self, + _backend: &mut B, + client_rc: Rc>, + state: bool, + ) { if let Some(ws) = self.get_workspace_mut(&client_rc) { ws.set_pinned(client_rc, state); } @@ -707,9 +882,10 @@ impl> WindowManager for MarsWM { fn tile_client(&mut self, _backend: &mut B, client_rc: Rc>, state: bool) { if let Some(ws) = self.get_workspace_mut(&client_rc) - && ws.current_layout() != LayoutType::Floating { - ws.set_floating(client_rc, !state); - } + && ws.current_layout() != LayoutType::Floating + { + ws.set_floating(client_rc, !state); + } } fn switch_workspace(&mut self, backend: &mut B, workspace_idx: u32) { @@ -747,9 +923,12 @@ impl> WindowManager for MarsWM { to_workspace.clients().for_each(|c| c.borrow_mut().show()); // select new window to be focused - let new_active = if let Some(client_rc) = to_workspace.clients().find(|c| c.borrow().is_fullscreen()) { - Some(client_rc.clone()) - } else { to_workspace.clients().next().cloned() }; + let new_active = + if let Some(client_rc) = to_workspace.clients().find(|c| c.borrow().is_fullscreen()) { + Some(client_rc.clone()) + } else { + to_workspace.clients().next().cloned() + }; self.focus_client(backend, new_active); backend.export_current_workspace(workspace_idx); @@ -809,10 +988,16 @@ impl> WindowManager for MarsWM { let workspace_offset = if primary { 0 } else { - self.config.primary_workspaces + (i - 1) as u32 * self.config.secondary_workspaces + self.config.primary_workspaces + + (i - 1) as u32 * self.config.secondary_workspaces }; - let monitor = Monitor::new(configs.get(i).unwrap().clone(), &self.config, primary, workspace_offset); + let monitor = Monitor::new( + configs.get(i).unwrap().clone(), + &self.config, + primary, + workspace_offset, + ); self.monitors.push(monitor); } } @@ -823,12 +1008,16 @@ impl> WindowManager for MarsWM { for client_rc in monitor.clients() { Self::fix_client_to_area(client_rc.clone(), window_area); } - } // export desktop settings - let workspace_info = self.monitors.iter() - .flat_map(|m| m.workspaces().map(|ws| (ws.name().to_owned(), m.dimensions(), m.window_area()))) + let workspace_info = self + .monitors + .iter() + .flat_map(|m| { + m.workspaces() + .map(|ws| (ws.name().to_owned(), m.dimensions(), m.window_area())) + }) .collect(); backend.export_workspaces(workspace_info); } diff --git a/marswm/src/monitor.rs b/marswm/src/monitor.rs index 3fd08220..8558aafc 100644 --- a/marswm/src/monitor.rs +++ b/marswm/src/monitor.rs @@ -3,9 +3,9 @@ use libmars::interfaces::wm::Client; use std::cell::RefCell; use std::rc::Rc; -use crate::*; use crate::config::Configuration; use crate::workspace::*; +use crate::*; pub struct Monitor> { config: MonitorConfig, @@ -16,12 +16,22 @@ pub struct Monitor> { } impl> Monitor { - pub fn new(monitor_config: MonitorConfig, config: &Configuration, primary: bool, workspace_offset: u32) - -> Monitor { - + pub fn new( + monitor_config: MonitorConfig, + config: &Configuration, + primary: bool, + workspace_offset: u32, + ) -> Monitor { let workspaces: Vec> = if primary { (0..config.primary_workspaces) - .map(|i| Workspace::new((i + 1).to_string(), workspace_offset + i, monitor_config.window_area(), config.layout)) + .map(|i| { + Workspace::new( + (i + 1).to_string(), + workspace_offset + i, + monitor_config.window_area(), + config.layout, + ) + }) .collect() } else { (0..config.secondary_workspaces) @@ -31,7 +41,12 @@ impl> Monitor { } else { format!("{}:{}", monitor_config.name(), i + 1) }; - Workspace::new(name, workspace_offset + i, monitor_config.window_area(), config.layout) + Workspace::new( + name, + workspace_offset + i, + monitor_config.window_area(), + config.layout, + ) }) .collect() }; @@ -102,11 +117,11 @@ impl> Monitor { self.workspace_offset } - pub fn workspaces(&self) -> Box> + '_>{ + pub fn workspaces(&self) -> Box> + '_> { Box::new(self.workspaces.iter()) } - pub fn workspaces_mut(&mut self) -> Box> + '_>{ + pub fn workspaces_mut(&mut self) -> Box> + '_> { Box::new(self.workspaces.iter_mut()) } } diff --git a/marswm/src/rules.rs b/marswm/src/rules.rs index a49356f3..eb3d2e11 100644 --- a/marswm/src/rules.rs +++ b/marswm/src/rules.rs @@ -1,14 +1,13 @@ -use std::rc::Rc; -use std::cell::RefCell; -use serde::{Serialize, Deserialize}; use libmars::interfaces::wm::Client; +use serde::{Deserialize, Serialize}; +use std::cell::RefCell; +use std::rc::Rc; use crate::attributes::*; use crate::bindings::*; use crate::config::WindowPlacement; - -#[derive(Serialize,Deserialize,Default,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, Default, PartialEq, Debug, Clone)] #[serde(default)] pub struct Rule { identifiers: Identifiers, @@ -27,7 +26,7 @@ pub struct Rule { workspace: Option, } -#[derive(Serialize,Deserialize,Default,PartialEq,Debug,Clone)] +#[derive(Serialize, Deserialize, Default, PartialEq, Debug, Clone)] #[serde(default)] struct Identifiers { /// application name - WM class for X11 (exact match) @@ -65,7 +64,8 @@ impl Rule { impl Identifiers { pub fn matches(&self, client_rc: Rc>>) -> bool { - return (self.application.is_none() || self.application == Some(client_rc.borrow().application())) + return (self.application.is_none() + || self.application == Some(client_rc.borrow().application())) && (self.title.is_none() || self.title == Some(client_rc.borrow().title())); } } diff --git a/marswm/src/workspace.rs b/marswm/src/workspace.rs index b084bb07..be480c19 100644 --- a/marswm/src/workspace.rs +++ b/marswm/src/workspace.rs @@ -5,26 +5,31 @@ use std::cmp; use std::collections::VecDeque; use std::rc::Rc; -use crate::*; use crate::config::LayoutConfiguration; use crate::layouts::*; +use crate::*; #[derive(PartialEq)] pub struct Workspace> { name: String, global_index: u32, - clients: VecDeque>>, // sorted by user - clients_stack: VecDeque>>, // sorted by stacking order + clients: VecDeque>>, // sorted by user + clients_stack: VecDeque>>, // sorted by stacking order win_area: Dimensions, cur_layout: LayoutType, layout_config: LayoutConfiguration, } - impl> Workspace { - pub fn new(name: String, global_index: u32, win_area: Dimensions, layout_config: LayoutConfiguration) -> Workspace { + pub fn new( + name: String, + global_index: u32, + win_area: Dimensions, + layout_config: LayoutConfiguration, + ) -> Workspace { Workspace { - name, global_index, + name, + global_index, clients: VecDeque::new(), clients_stack: VecDeque::new(), win_area, @@ -34,10 +39,17 @@ impl> Workspace { } pub fn apply_layout(&self) { - let tiled_clients: Vec<_> = self.clients.iter() + let tiled_clients: Vec<_> = self + .clients + .iter() .filter(|c| !c.borrow().attributes().is_floating && !c.borrow().is_dialog()) - .cloned().collect(); - Layout::get(self.cur_layout).apply_layout(self.win_area, &tiled_clients, &self.layout_config); + .cloned() + .collect(); + Layout::get(self.cur_layout).apply_layout( + self.win_area, + &tiled_clients, + &self.layout_config, + ); } pub fn change_main_ratio(&mut self, i: f32) { @@ -57,7 +69,10 @@ impl> Workspace { } pub fn cycle_layout(&mut self) { - let cur_idx = LayoutType::VALUES.iter().position(|l| *l == self.cur_layout).unwrap(); + let cur_idx = LayoutType::VALUES + .iter() + .position(|l| *l == self.cur_layout) + .unwrap(); self.cur_layout = LayoutType::VALUES[(cur_idx + 1) % LayoutType::SIZE]; self.apply_layout(); } @@ -82,7 +97,10 @@ impl> Workspace { pub fn inc_gaps(&mut self, i: i32) { let new_gaps = self.layout_config.gap_width as i32 + i; - if new_gaps >= 0 && new_gaps as u32 <= self.win_area.w() / 2 && new_gaps as u32 <= self.win_area.h() / 2 { + if new_gaps >= 0 + && new_gaps as u32 <= self.win_area.w() / 2 + && new_gaps as u32 <= self.win_area.h() / 2 + { self.layout_config.gap_width = new_gaps as u32; self.apply_layout(); } @@ -104,7 +122,10 @@ impl> Workspace { } pub fn last_active_stack(&self) -> Option>> { - self.clients_stack.iter().find(|c| !self.is_main(c)).cloned() + self.clients_stack + .iter() + .find(|c| !self.is_main(c)) + .cloned() } pub fn move_main(&mut self, client_rc: Rc>) { @@ -129,7 +150,11 @@ impl> Workspace { &self.name } - pub fn next_in_direction(&self, client_rc: Rc>, dir: Direction) -> Option>> { + pub fn next_in_direction( + &self, + client_rc: Rc>, + dir: Direction, + ) -> Option>> { use Direction::*; let clients: Vec<_> = self.clients_as_stacked().cloned().collect(); @@ -138,67 +163,66 @@ impl> Workspace { let y_diff = |c: &Rc>| c.borrow().center().1 - client_center.1; let (selected, _) = match dir { - Up => { - clients.iter() - .filter(|c| *c != &client_rc) - .map(|c| (c, y_diff(c))) - .filter(|(c, v)| v.abs() >= x_diff(c).abs()) - .filter(|(_, v)| *v < 0) - .fold((&client_rc, i32::MIN), |(acc_c, acc_d), (cur_c, cur_d)| { - if cur_d > acc_d { - (cur_c, cur_d) - } else { - (acc_c, acc_d) - } - }) - }, - Down => { - clients.iter() - .filter(|c| *c != &client_rc) - .map(|c| (c, y_diff(c))) - .filter(|(c, v)| v.abs() >= x_diff(c).abs()) - .filter(|(_, v)| *v > 0) - .fold((&client_rc, i32::MAX), |(acc_c, acc_d), (cur_c, cur_d)| { - if cur_d < acc_d { - (cur_c, cur_d) - } else { - (acc_c, acc_d) - } - }) - }, - Left => { - clients.iter() - .filter(|c| *c != &client_rc) - .map(|c| (c, x_diff(c))) - .filter(|(c, v)| v.abs() >= y_diff(c).abs()) - .filter(|(_, v)| *v < 0) - .fold((&client_rc, i32::MIN), |(acc_c, acc_d), (cur_c, cur_d)| { - if cur_d > acc_d { - (cur_c, cur_d) - } else { - (acc_c, acc_d) - } - }) - }, - Right => { - clients.iter() - .filter(|c| *c != &client_rc) - .map(|c| (c, x_diff(c))) - .filter(|(c, v)| v.abs() >= y_diff(c).abs()) - .filter(|(_, v)| *v > 0) - .fold((&client_rc, i32::MAX), |(acc_c, acc_d), (cur_c, cur_d)| { - if cur_d < acc_d { - (cur_c, cur_d) - } else { - (acc_c, acc_d) - } - }) - }, + Up => clients + .iter() + .filter(|c| *c != &client_rc) + .map(|c| (c, y_diff(c))) + .filter(|(c, v)| v.abs() >= x_diff(c).abs()) + .filter(|(_, v)| *v < 0) + .fold((&client_rc, i32::MIN), |(acc_c, acc_d), (cur_c, cur_d)| { + if cur_d > acc_d { + (cur_c, cur_d) + } else { + (acc_c, acc_d) + } + }), + Down => clients + .iter() + .filter(|c| *c != &client_rc) + .map(|c| (c, y_diff(c))) + .filter(|(c, v)| v.abs() >= x_diff(c).abs()) + .filter(|(_, v)| *v > 0) + .fold((&client_rc, i32::MAX), |(acc_c, acc_d), (cur_c, cur_d)| { + if cur_d < acc_d { + (cur_c, cur_d) + } else { + (acc_c, acc_d) + } + }), + Left => clients + .iter() + .filter(|c| *c != &client_rc) + .map(|c| (c, x_diff(c))) + .filter(|(c, v)| v.abs() >= y_diff(c).abs()) + .filter(|(_, v)| *v < 0) + .fold((&client_rc, i32::MIN), |(acc_c, acc_d), (cur_c, cur_d)| { + if cur_d > acc_d { + (cur_c, cur_d) + } else { + (acc_c, acc_d) + } + }), + Right => clients + .iter() + .filter(|c| *c != &client_rc) + .map(|c| (c, x_diff(c))) + .filter(|(c, v)| v.abs() >= y_diff(c).abs()) + .filter(|(_, v)| *v > 0) + .fold((&client_rc, i32::MAX), |(acc_c, acc_d), (cur_c, cur_d)| { + if cur_d < acc_d { + (cur_c, cur_d) + } else { + (acc_c, acc_d) + } + }), }; let selected = selected.clone(); if selected == client_rc { - let mut clients: Vec<_> = self.clients().filter(|&c| x_diff(c) == 0 && y_diff(c) == 0).cloned() + let mut clients: Vec<_> = self + .clients() + .filter(|&c| x_diff(c) == 0 && y_diff(c) == 0) + .cloned() .collect(); if dir == Up || dir == Left { clients.reverse(); @@ -207,9 +231,10 @@ impl> Workspace { clients.rotate_left(i + 1); } if let Some(selected) = clients.first() - && selected != &client_rc { - return Some(selected.clone()); - } + && selected != &client_rc + { + return Some(selected.clone()); + } } else { return Some(selected); } @@ -219,7 +244,12 @@ impl> Workspace { pub fn pull_pinned(&mut self) -> Vec>> { let mut vec = Vec::new(); - while let Some(client_rc) = self.clients.iter().find(|c| c.borrow().attributes().is_pinned).cloned() { + while let Some(client_rc) = self + .clients + .iter() + .find(|c| c.borrow().attributes().is_pinned) + .cloned() + { // pull client from clients let index_option = self.clients.iter().position(|c| *c == client_rc); if let Some(index) = index_option { @@ -279,7 +309,8 @@ impl> Workspace { self.apply_layout(); if self.current_layout() != LayoutType::Floating { - self.clients_stack.iter() + self.clients_stack + .iter() .filter(|c| c.borrow().attributes().is_floating) .rev() .for_each(|c| c.borrow().raise()); @@ -306,7 +337,12 @@ impl> Workspace { let mut client = client_rc.borrow_mut(); let dimensions_option = client.attributes_mut().floating_dimensions.take(); if let Some(dimensions) = dimensions_option { - client.move_resize(dimensions.x(), dimensions.y(), dimensions.w(), dimensions.h()); + client.move_resize( + dimensions.x(), + dimensions.y(), + dimensions.w(), + dimensions.h(), + ); } else { client.center_on_screen(self.win_area); } @@ -316,7 +352,7 @@ impl> Workspace { let dimensions = Some(client.dimensions()); client.attributes_mut().floating_dimensions = dimensions; } else { - return; // client already has desired state + return; // client already has desired state } client_rc.borrow().export_tiled(state); @@ -326,7 +362,9 @@ impl> Workspace { pub fn set_pinned(&mut self, client_rc: Rc>, state: bool) { client_rc.borrow_mut().attributes_mut().is_pinned = state; - client_rc.borrow().export_pinned(state, Some(self.global_index)) + client_rc + .borrow() + .export_pinned(state, Some(self.global_index)) } pub fn set_stack_mode(&mut self, mode: StackMode) { @@ -360,15 +398,20 @@ impl> Workspace { pub fn swap_clients(&mut self, client_a: Rc>, client_b: Rc>) { if let Some(pos_a) = self.clients.iter().position(|c| c == &client_a) - && let Some(pos_b) = self.clients.iter().position(|c| c == &client_b) { - self.clients.swap(pos_a, pos_b); - self.apply_layout(); - client_a.borrow().warp_pointer_to_center(); - } + && let Some(pos_b) = self.clients.iter().position(|c| c == &client_b) + { + self.clients.swap(pos_a, pos_b); + self.apply_layout(); + client_a.borrow().warp_pointer_to_center(); + } } pub fn tiled_clients(&self) -> Box>> + '_> { - Box::new(self.clients.iter().filter(|c| !c.borrow().attributes().is_floating)) + Box::new( + self.clients + .iter() + .filter(|c| !c.borrow().attributes().is_floating), + ) } pub fn update_window_area(&mut self, win_area: Dimensions) { @@ -380,7 +423,10 @@ impl> Workspace { impl> ClientList for Workspace { fn attach_client(&mut self, client_rc: Rc>) { client_rc.borrow_mut().export_workspace(self.global_index); - let stack_top = cmp::min(self.clients.len(), self.layout_config.nmain.try_into().unwrap()); + let stack_top = cmp::min( + self.clients.len(), + self.layout_config.nmain.try_into().unwrap(), + ); match self.layout_config.attach_position { AttachPosition::Main => self.clients.push_front(client_rc.clone()), AttachPosition::StackTop => self.clients.insert(stack_top, client_rc.clone()),