srdusr
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-08-24 09:11:00 +0200
committersrdusr <[email protected]>2024-08-24 09:11:00 +0200
commitadc1a56982c70c06a0f8549c2c1b3bddd17930c2 (patch)
tree16cba43721238f88a25b8fd3cadfe3382c399fab
parent281378656bdf9520e5f89d31864b9b2f822d4e3e (diff)
downloadsrdwm-adc1a56982c70c06a0f8549c2c1b3bddd17930c2.tar.gz
srdwm-adc1a56982c70c06a0f8549c2c1b3bddd17930c2.zip
Implement general.focus_follows_mouse/auto_raise; remove the rest as dead
Auditing "clicking behavior and basics": general.focus_follows_mouse, general.mouse_follows_focus, general.auto_raise, general.auto_focus, the entire window.* namespace (8 more keys, a full duplicate of the same four plus remember_position/size/state), and general. smart_placement/border_width were all seeded into default_config() and documented in DEFAULTS.md, but none were read anywhere - srd.set()/ srd.get() on any of them silently succeeded while doing nothing. focus_follows_mouse is real, well-defined, and directly relevant to clicking basics - implemented it plus auto_raise (raise, not just focus, on hover) rather than just deleting the promise like the others. WindowManager gained focus_follows_mouse/auto_raise bools, wired from apply_general_settings the same way every other general.* flag is. handle_pointer_position now tracks whichever window (content or decoration) is under the pointer and, when the setting is on and that differs from the currently-focused window, focuses it through the same focus_window() free function every click-driven focus change already uses (real keyboard focus, not just core state) - skipped entirely while dragging/resizing or over a layer-shell surface, so the pointer sweeping over other windows mid-drag or hovering a bar can't steal focus from what's actually being manipulated. mouse_follows_focus (pointer warp on keybinding-driven focus change) and auto_focus (no clear distinct meaning beyond click-to-focus) stay unimplemented and are now undocumented rather than promised.
-rw-r--r--crates/config/src/engine/support.rs24
-rw-r--r--crates/core/src/manager/mod.rs13
-rw-r--r--crates/srdwm/src/main.rs4
-rw-r--r--crates/wayland/src/input.rs32
-rw-r--r--docs/DEFAULTS.md31
5 files changed, 79 insertions, 25 deletions
diff --git a/crates/config/src/engine/support.rs b/crates/config/src/engine/support.rs
index 7b42f53..9346499 100644
--- a/crates/config/src/engine/support.rs
+++ b/crates/config/src/engine/support.rs
@@ -152,9 +152,12 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> {
// apart from "user explicitly chose a value" and hand the *unset* case
// to whichever backend ends up connecting instead of deciding for it.
set("general.focus_follows_mouse", Bool(false));
- set("general.mouse_follows_focus", Bool(true));
set("general.auto_raise", Bool(false));
- set("general.auto_focus", Bool(true));
+ // `mouse_follows_focus` (warp the pointer to match a keybinding-driven
+ // focus change, the reverse of the two above) and `auto_focus` (no
+ // clear distinct meaning found beyond what plain click-to-focus already
+ // does) are deliberately not seeded - neither is implemented, same
+ // reasoning as `workspace.auto_switch`'s own absence.
set("monitor.primary_layout", String("dynamic".into()));
set("monitor.secondary_layout", String("tiling".into()));
@@ -166,14 +169,15 @@ pub(super) fn default_config() -> HashMap<String, ConfigValue> {
// "this monitor's workspace count" describe a design that doesn't
// exist. `workspace.count` is the one knob that actually does anything.
- set("window.focus_follows_mouse", Bool(false));
- set("window.mouse_follows_focus", Bool(true));
- set("window.auto_raise", Bool(false));
- set("window.auto_focus", Bool(true));
- set("window.raise_on_focus", Bool(true));
- set("window.remember_position", Bool(true));
- set("window.remember_size", Bool(true));
- set("window.remember_state", Bool(true));
+ // The `window.*` namespace this codebase's own `docs/DEFAULTS.md`
+ // documented (focus_follows_mouse/mouse_follows_focus/auto_raise/
+ // auto_focus/raise_on_focus/remember_position/remember_size/
+ // remember_state) was a full, entirely unimplemented duplicate of
+ // `general.*`'s own focus keys plus three genuinely unbuilt
+ // per-app-window-state-persistence features - removed rather than
+ // seeded, same reasoning as everything else in this comment block.
+ // `general.focus_follows_mouse`/`general.auto_raise` above are the
+ // real, working versions of the one pair that *is* implemented.
set("workspace.count", Number(10.0));
set("workspace.names", List(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"].map(|s| s.to_string()).to_vec()));
diff --git a/crates/core/src/manager/mod.rs b/crates/core/src/manager/mod.rs
index 609b87f..6285736 100644
--- a/crates/core/src/manager/mod.rs
+++ b/crates/core/src/manager/mod.rs
@@ -86,6 +86,17 @@ pub struct WindowManager {
/// redraws constantly - see `crates/wayland/src/rounded_corners.rs`).
/// `Some(_)` only when the user explicitly set it, and wins either way.
pub rounded_corners_enabled: Option<bool>,
+ /// Whether hovering a window (no click needed) focuses it, read from
+ /// `general.focus_follows_mouse`. Off by default - matches
+ /// `general.focus_follows_mouse`'s own documented default, and every
+ /// desktop's convention of click-to-focus unless a user explicitly
+ /// opts into the classic X11 sloppy-focus behaviour.
+ pub focus_follows_mouse: bool,
+ /// Whether hover-driven focus (above) also raises the window, not just
+ /// focuses it - read from `general.auto_raise`. Meaningless (never
+ /// consulted) while `focus_follows_mouse` is off, since a plain click
+ /// already raises unconditionally regardless of this.
+ pub auto_raise: bool,
/// Default decoration colours and border width, read from `theme.colors.*`/
/// `theme.decorations.*`. See `ThemeConfig`'s own doc comment.
pub theme: ThemeConfig,
@@ -131,6 +142,8 @@ impl WindowManager {
shadows_enabled: true,
resize_margin: RESIZE_MARGIN,
rounded_corners_enabled: None,
+ focus_follows_mouse: false,
+ auto_raise: false,
theme: ThemeConfig::default(),
drag: None,
resize: None,
diff --git a/crates/srdwm/src/main.rs b/crates/srdwm/src/main.rs
index 336bb2e..5c2bfea 100644
--- a/crates/srdwm/src/main.rs
+++ b/crates/srdwm/src/main.rs
@@ -155,6 +155,8 @@ fn apply_general_settings(engine: &Engine, wm: &Rc<RefCell<WindowManager>>) {
// - see `WindowManager::rounded_corners_enabled`'s doc comment for why
// this can't just be `get_bool(..., true)` like every other flag here.
let rounded_corners = engine.get("general.rounded_corners").and_then(|v| v.as_bool());
+ let focus_follows_mouse = engine.get_bool("general.focus_follows_mouse", false);
+ let auto_raise = engine.get_bool("general.auto_raise", false);
// Only the three `theme.*` keys with an unambiguous, already-rendered
// counterpart are wired - see `srdwm_core::ThemeConfig`'s doc comment.
@@ -185,6 +187,8 @@ fn apply_general_settings(engine: &Engine, wm: &Rc<RefCell<WindowManager>>) {
wm.shadows_enabled = shadows;
wm.resize_margin = resize_margin;
wm.rounded_corners_enabled = rounded_corners;
+ wm.focus_follows_mouse = focus_follows_mouse;
+ wm.auto_raise = auto_raise;
wm.theme = theme;
wm.auto_back_and_forth = engine.get_bool("workspace.auto_back_and_forth", false);
}
diff --git a/crates/wayland/src/input.rs b/crates/wayland/src/input.rs
index 264c986..4b98a8a 100644
--- a/crates/wayland/src/input.rs
+++ b/crates/wayland/src/input.rs
@@ -133,6 +133,12 @@ pub(crate) fn handle_pointer_position(state: &mut CompState, pos: Point<f64, Log
let hit = state.wm.borrow().hit_test(pos.x as i32, pos.y as i32);
let under = state.space.element_under(pos).map(|(w, loc)| (w.clone(), loc));
let over_content = under.is_some();
+ // Whichever core window the pointer is over right now, decoration or
+ // content, for `general.focus_follows_mouse` below - `None` while over
+ // a layer-shell surface or bare desktop, same as everything else here.
+ let hovered_id = hit
+ .map(|(id, _)| id)
+ .or_else(|| under.as_ref().and_then(|(window, _)| dwindow_wl_surface(window)).and_then(|s| state.surface_to_id.get(&s).copied()));
let Some(pointer) = state.seat.get_pointer() else { return };
if let Some((surface, loc)) = layer_hit {
@@ -198,7 +204,33 @@ pub(crate) fn handle_pointer_position(state: &mut CompState, pos: Point<f64, Log
wm.update_resize(pos.x as i32, pos.y as i32);
}
let focused = wm.focused_id();
+ // `general.focus_follows_mouse`: hovering a *different* window focuses
+ // it, no click needed - classic X11 sloppy focus. Gated on `hit`/
+ // `under` actually landing on a window (not a layer surface or bare
+ // desktop) and on not already being mid-drag/resize, where the pointer
+ // sweeps over unrelated windows constantly and none of that should
+ // steal focus from whatever's actually being dragged. `hovered_id !=
+ // focused` both skips redundant work on every one of the many motion
+ // events a stationary pointer over an already-focused window still
+ // generates, and is what makes `auto_raise` (below) only fire on an
+ // actual focus change rather than every motion tick too.
+ let focus_follow_target =
+ (wm.focus_follows_mouse && !dragging_or_resizing && !over_layer_surface).then_some(hovered_id).flatten().filter(|id| Some(*id) != focused);
+ if let Some(id) = focus_follow_target {
+ if wm.auto_raise {
+ // `raise_window` alone here, not `focus_window` - the actual
+ // core + real Wayland/X11 keyboard focus change happens once,
+ // below, through the same `focus_window` free function every
+ // click-driven focus change already goes through (sets real
+ // keyboard focus too, which `WindowManager::focus_window`
+ // alone does not).
+ wm.raise_window(id);
+ }
+ }
drop(wm);
+ if let Some(id) = focus_follow_target {
+ focus_window(state, id);
+ }
if dragging_or_resizing {
if let Some(id) = focused {
state.sync_geometry(id);
diff --git a/docs/DEFAULTS.md b/docs/DEFAULTS.md
index 972e330..4b4e195 100644
--- a/docs/DEFAULTS.md
+++ b/docs/DEFAULTS.md
@@ -8,19 +8,23 @@ This document describes all default configuration values and available options f
### Global Settings (`general.*`)
```lua
srd.set("general.default_layout", "dynamic") -- Default: "dynamic"
-srd.set("general.smart_placement", true) -- Default: true
srd.set("general.window_gap", 8) -- Default: 8
-srd.set("general.border_width", 2) -- Default: 2
srd.set("general.animations", true) -- Default: true
srd.set("general.animation_duration", 200) -- Default: 200ms
srd.set("general.shadows", true) -- Default: true
srd.set("general.resize_margin", 6) -- Default: 6px
srd.set("general.rounded_corners", true) -- Default: true on GLES/winit, false on udev/Pixman (opt-in there)
-srd.set("general.focus_follows_mouse", false) -- Default: false
-srd.set("general.mouse_follows_focus", true) -- Default: true
-srd.set("general.auto_raise", false) -- Default: false
-srd.set("general.auto_focus", true) -- Default: true
+srd.set("general.focus_follows_mouse", false) -- Default: false - hover a window to focus it, no click needed
+srd.set("general.auto_raise", false) -- Default: false - also raise on hover-focus, not just focus
```
+`general.smart_placement`/`general.border_width` are not listed: neither
+is implemented - new-window placement always uses smart placement
+unconditionally (no toggle exists), and the real, working border-width
+setting is `theme.decorations.border.width` below.
+`general.mouse_follows_focus` (warp the pointer to match a keybinding-
+driven focus change) and `general.auto_focus` (no clear distinct meaning
+found beyond what plain click-to-focus already does) aren't implemented
+either.
### Monitor Settings (`monitor.*`)
```lua
@@ -34,15 +38,12 @@ workspace"/"this monitor's workspace count" to configure. `workspace.count`
below is the actual knob.
### Window Behavior (`window.*`)
-```lua
-srd.set("window.focus_follows_mouse", false) -- Default: false
-srd.set("window.mouse_follows_focus", true) -- Default: true
-srd.set("window.auto_raise", false) -- Default: false
-srd.set("window.auto_focus", true) -- Default: true
-srd.set("window.raise_on_focus", true) -- Default: true
-srd.set("window.remember_position", true) -- Default: true
-srd.set("window.remember_size", true) -- Default: true
-srd.set("window.remember_state", true) -- Default: true
+Not implemented: this whole namespace duplicated `general.*`'s own focus
+keys (see above for the two of those that are real) plus three genuinely
+unbuilt per-app-window-state-persistence keys (`remember_position`/
+`remember_size`/`remember_state` - no window remembers anything about a
+previous run; every new window starts at a hardcoded size, see
+`crates/wayland/src/xwayland.rs`/`state/lifecycle.rs`'s `new_managed_window`).
```
### Workspace Settings (`workspace.*`)