Commit b22c0511d5af
tarball12 files changed+75-55
@@ -98,8 +98,8 @@ impl Default for Decoration {
9898
fn default() -> Self {9999
Self {100100
border: 2,101
- focused: Color([0.53, 0.75, 0.82, 1.0]),102
- unfocused: Color([0.23, 0.26, 0.32, 1.0]),101
+ focused: Color::rgb(0x88, 0xbf, 0xd1),102
+ unfocused: Color::rgb(0x3b, 0x42, 0x52),103103
}104104
}105105
}@@ -108,6 +108,12 @@ impl Default for Decoration {
108108
#[derive(Debug, Clone, Copy, PartialEq)]109109
pub struct Color(pub [f32; 4]);110110
111
+impl Color {112
+ pub const fn rgb(r: u8, g: u8, b: u8) -> Self {113
+ Self([r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, 1.0])114
+ }115
+}116
+111117
impl<'de> Deserialize<'de> for Color {112118
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {113119
let s = String::deserialize(d)?;@@ -199,6 +205,15 @@ pub struct Mods {
199205
}200206
201207
impl Mods {208
+ pub fn has(&self, m: Modifier) -> bool {209
+ match m {210
+ Modifier::Super => self.logo,211
+ Modifier::Alt => self.alt,212
+ Modifier::Ctrl => self.ctrl,213
+ Modifier::Shift => self.shift,214
+ }215
+ }216
+202217
fn set(&mut self, m: Modifier) {203218
match m {204219
Modifier::Super => self.logo = true,@@ -411,9 +426,18 @@ fn parse_bind(combo: &str, words: Words, mod_key: Modifier) -> Result<Bind, Erro
411426
412427
#[cfg(test)]413428
mod tests {429
+ use super::*;430
+431
+ /// default.toml documents the defaults for users, and the Default impls432
+ /// apply them to sections a user config leaves out. They must agree.414433
#[test]415
- fn the_default_config_parses() {416
- let c = super::Config::parse(super::DEFAULT).unwrap();434
+ fn default_toml_states_the_defaults() {435
+ let c = Config::parse(DEFAULT).unwrap();436
+ assert_eq!(c.general, General::default());437
+ assert_eq!(c.output, Outputs::default());438
+ assert_eq!(c.decoration, Decoration::default());439
+ assert_eq!(c.animation, Animation::default());440
+ assert_eq!(c.keyboard, Keyboard::default());417441
assert!(c.binds.len() > 40);418442
}419443
}@@ -9,4 +9,5 @@ publish.workspace = true
99
workspace = true1010
1111
[dependencies]12
+monolith-layout = { workspace = true, features = ["serde"] }1213
serde.workspace = true@@ -25,21 +25,7 @@ pub fn socket_path() -> Option<PathBuf> {
2525
socket_path_for(&std::env::var("WAYLAND_DISPLAY").ok()?)2626
}2727
28
-#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]29
-#[serde(rename_all = "kebab-case")]30
-pub enum Dir {31
- Left,32
- Right,33
- Up,34
- Down,35
-}36
-37
-#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]38
-#[serde(rename_all = "kebab-case")]39
-pub enum Axis {40
- Horizontal,41
- Vertical,42
-}28
+pub use monolith_layout::{Axis, Dir};4329
4430
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Default)]4531
#[serde(rename_all = "kebab-case")]@@ -8,8 +8,12 @@ publish.workspace = true
88
[lints]99
workspace = true1010
11
+[features]12
+serde = ["dep:serde"]13
+1114
[dependencies]1215
monolith-planner.workspace = true16
+serde = { workspace = true, optional = true }1317
slotmap.workspace = true1418
1519
[dev-dependencies]@@ -6,6 +6,8 @@ use std::hash::Hash;
66
new_key_type! { pub struct NodeId; }77
88
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]9
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]10
+#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]911
pub enum Axis {1012
Horizontal,1113
Vertical,@@ -21,6 +23,8 @@ impl Axis {
2123
}2224
2325
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]26
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]27
+#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]2428
pub enum Dir {2529
Left,2630
Right,@@ -1,7 +1,7 @@
11
use crate::state::State;22
use monolith_config::{Config, Mods, MoveMode};33
use monolith_ipc::Command;4
-use monolith_layout::{Axis, Dir, ExpandScope, WindowId};4
+use monolith_layout::{ExpandScope, WindowId};55
use smithay::input::keyboard::{Keysym, ModifiersState, xkb};66
use std::process::Stdio;77
@@ -26,12 +26,7 @@ impl Binds {
2626
2727
/// Matches on the unshifted keysyms so `Mod+Shift+1` means the 1 key.2828
pub fn find(&self, mods: &ModifiersState, syms: &[Keysym]) -> Option<Command> {29
- let held = Mods {30
- logo: mods.logo,31
- alt: mods.alt,32
- ctrl: mods.ctrl,33
- shift: mods.shift,34
- };29
+ let held = held(mods);3530
self.03631
.iter()3732
.find(|(m, sym, _)| *m == held && syms.contains(sym))@@ -39,12 +34,13 @@ impl Binds {
3934
}4035
}4136
42
-fn dir(d: monolith_ipc::Dir) -> Dir {43
- match d {44
- monolith_ipc::Dir::Left => Dir::Left,45
- monolith_ipc::Dir::Right => Dir::Right,46
- monolith_ipc::Dir::Up => Dir::Up,47
- monolith_ipc::Dir::Down => Dir::Down,37
+/// The config's view of what smithay reports held.38
+pub fn held(mods: &ModifiersState) -> Mods {39
+ Mods {40
+ logo: mods.logo,41
+ alt: mods.alt,42
+ ctrl: mods.ctrl,43
+ shift: mods.shift,4844
}4945
}5046
@@ -69,26 +65,22 @@ impl State {
6965
Command::Quit => self.core.signal.stop(),7066
Command::Reload => self.reload()?,7167
Command::Focus { dir: d } => {72
- self.wm.layout.focus_dir(dir(d));68
+ self.wm.layout.focus_dir(d);7369
}7470
Command::Move { dir: d } if merge => {75
- self.wm.layout.merge_window(dir(d));71
+ self.wm.layout.merge_window(d);7672
}7773
Command::Move { dir: d } => {78
- self.wm.layout.move_window(dir(d));74
+ self.wm.layout.move_window(d);7975
}8076
Command::MoveContainer { dir: d } => {81
- self.wm.layout.move_container(dir(d));77
+ self.wm.layout.move_container(d);8278
}8379
Command::Maximize => {8480
self.wm.layout.expand(ExpandScope::All);8581
}8682
Command::InvertMove => self.input.move_inverted = !inverted,8783
Command::Resize { axis, delta } => {88
- let axis = match axis {89
- monolith_ipc::Axis::Horizontal => Axis::Horizontal,90
- monolith_ipc::Axis::Vertical => Axis::Vertical,91
- };9284
self.wm.layout.resize(axis, delta);9385
}9486
Command::Expand { scope } => {@@ -130,7 +122,7 @@ impl State {
130122
self.wm.layout.reorder_tag(t, index);131123
}132124
Command::FocusOutput { dir: d } => {133
- if let Some(o) = output.and_then(|o| self.wm.layout.output_towards(o, dir(d))) {125
+ if let Some(o) = output.and_then(|o| self.wm.layout.output_towards(o, d)) {134126
self.wm.layout.set_active_output(o);135127
if let Some(w) = self.wm.layout.focused_on(o) {136128
self.wm.layout.focus(w);@@ -140,7 +132,7 @@ impl State {
140132
Command::SendToOutput { dir: d } => {141133
if let (Some(w), Some(o)) = (142134
focused,143
- output.and_then(|o| self.wm.layout.output_towards(o, dir(d))),135
+ output.and_then(|o| self.wm.layout.output_towards(o, d)),144136
) {145137
self.wm.layout.send_to_output(w, o);146138
}@@ -786,9 +786,7 @@ fn clamp(
786786
state: &State,787787
pos: Point<f64, smithay::utils::Logical>,788788
) -> Point<f64, smithay::utils::Logical> {789
- let inside = |a: &Rect, p: Point<f64, smithay::utils::Logical>| {790
- p.x >= a.x && p.y >= a.y && p.x < a.right() && p.y < a.bottom()791
- };789
+ let inside = |a: &Rect, p: Point<f64, smithay::utils::Logical>| a.contains(p.x, p.y);792790
let areas: Vec<Rect> = state.wm.layout.outputs().map(|(_, o)| o.area).collect();793791
if areas.iter().any(|a| inside(a, pos)) {794792
return pos;@@ -36,8 +36,9 @@ pub fn compose(
3636
) -> Vec<Draw> {3737
let mut elements = Vec::new();3838
if cursor && let Some(area) = ctx.wm.layout.output(o).map(|out| out.area) {39
- let local = ctx.input.pointer_pos - Point::from((area.x, area.y));40
- if local.x >= 0.0 && local.y >= 0.0 && local.x < area.w && local.y < area.h {39
+ let pos = ctx.input.pointer_pos;40
+ if area.contains(pos.x, pos.y) {41
+ let local = pos - Point::from((area.x, area.y));4142
elements.extend(ctx.input.cursor.elements(4243
ctx.renderer,4344
&ctx.input.cursor_status,@@ -2,7 +2,6 @@
22
//! into these calls, with pointer positions in global logical coordinates.33
44
use crate::state::State;5
-use monolith_config::Modifier;65
use monolith_layout::{Rect, WindowId};76
use smithay::backend::input::{ButtonState, InputTime, KeyState};87
use smithay::backend::session::Session;@@ -184,12 +183,7 @@ fn start_drag(state: &mut State, button: u32) -> bool {
184183
.seat185184
.get_keyboard()186185
.map(|k| k.modifier_state())187
- .is_some_and(|m| match state.settings.config.general.mod_key {188
- Modifier::Super => m.logo,189
- Modifier::Alt => m.alt,190
- Modifier::Ctrl => m.ctrl,191
- Modifier::Shift => m.shift,192
- });186
+ .is_some_and(|m| crate::commands::held(&m).has(state.settings.config.general.mod_key));193187
let Some(id) = state.wm.layout.focused() else {194188
return false;195189
};@@ -179,7 +179,7 @@ fn snapshot(state: &State) -> monolith_ipc::State {
179179
.map(|w| (w.app_id.clone(), w.title.clone()))180180
.unwrap_or_default();181181
monolith_ipc::Window {182
- id: slotmap::Key::data(&id).as_ffi(),182
+ id: crate::wm::key(id),183183
app_id,184184
title,185185
tag: l@@ -45,6 +45,11 @@ pub struct WindowState {
4545
pub title: String,4646
}4747
48
+/// The id clients see for a window, stable for its lifetime.49
+pub fn key(id: WindowId) -> u64 {50
+ slotmap::Key::data(&id).as_ffi()51
+}52
+4853
/// Asks a window to close, through xdg-shell or X11.4954
pub fn close(window: &Window) {5055
match (window.toplevel(), window.x11_surface()) {@@ -115,6 +120,12 @@ impl Wm {
115120
}116121
}117122
123
+ /// The window a client named by `key`, if it still exists.124
+ pub fn by_key(&self, key: u64) -> Option<WindowId> {125
+ let id = WindowId::from(slotmap::KeyData::from_ffi(key));126
+ self.windows.contains_key(id).then_some(id)127
+ }128
+118129
pub fn id_of(&self, surface: &WlSurface) -> Option<WindowId> {119130
self.by_surface.get(surface).copied()120131
}@@ -21,6 +21,11 @@ impl Rect {
2121
self.y + self.h2222
}2323
24
+ /// Whether the point lies inside, counting the left and top edges only.25
+ pub fn contains(&self, x: f64, y: f64) -> bool {26
+ x >= self.x && y >= self.y && x < self.right() && y < self.bottom()27
+ }28
+2429
pub fn center_x(&self) -> f64 {2530
self.x + self.w / 2.02631
}