diff options
| author | srdusr <[email protected]> | 2024-07-11 14:17:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2024-07-11 14:17:00 +0200 |
| commit | 86b557a6c0baa4146b30712d8b7633f1b9b46d43 (patch) | |
| tree | 96ab749c728ac11c2851ea361c6fda63990e588f /crates/core/src/manager/layout.rs | |
| parent | 68b645b43e19330474ff106ce5c88dab520d7417 (diff) | |
| download | srdwm-86b557a6c0baa4146b30712d8b7633f1b9b46d43.tar.gz srdwm-86b557a6c0baa4146b30712d8b7633f1b9b46d43.zip | |
Split crates/core/src/manager.rs (2048 lines) into manager/
Pure reorganization, no behavior change - verified by diffing the
function-name set before/after (identical 130 functions) plus a full
cargo test pass. WindowManager's struct/field definitions, Default,
new(), and the three trivial constructors (add_rule/register_layout/
available_layouts) stay in mod.rs; the rest of the single ~950-line
impl block is split into one file per the section comments the file
already had (monitors, windows, focus, winops, hittest, dragresize,
workspaces, layout). Three methods called across section boundaries
(monitor_for, windows_on_workspace, cycle_focus) went from private to
pub(super) - Rust's privacy model doesn't let sibling submodules see
each other's private items, only a defining module's own descendants.
The ~1000-line test module moves to manager/tests.rs unsplit: its
helpers (wm_with_monitor, two_monitors, monitor_with_dock) are shared
across tests for every section, so splitting further would mean
duplicating them or adding another shared-support file for little
benefit.
Diffstat (limited to 'crates/core/src/manager/layout.rs')
| -rw-r--r-- | crates/core/src/manager/layout.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/crates/core/src/manager/layout.rs b/crates/core/src/manager/layout.rs new file mode 100644 index 0000000..002d0aa --- /dev/null +++ b/crates/core/src/manager/layout.rs @@ -0,0 +1,67 @@ +//! Layout selection and running a workspace's active layout to produce final geometries. +//! Split out of the original single `manager.rs` - see `super` (`mod.rs`) for +//! `WindowManager`'s field definitions; everything here is plain `impl WindowManager` +//! methods, unchanged from before the split. + +use super::*; + +impl WindowManager { + // ---- Layout ----------------------------------------------------------- + + pub fn set_layout(&mut self, workspace: WorkspaceId, layout_name: impl Into<String>) { + let layout_name = layout_name.into(); + if let Some(w) = self.workspaces.iter_mut().find(|w| w.id == workspace) { + w.layout = layout_name; + } + } + + pub fn layout_name(&self, workspace: WorkspaceId) -> Option<&str> { + self.workspace(workspace).map(|w| w.layout.as_str()) + } + + /// Recomputes geometry for all non-floating, non-minimized windows on + /// `workspace`, grouped by the monitor each window is assigned to, and + /// applies the results in place. Returns the changed `(id, Rect)` pairs + /// so a backend can push them to real surfaces. + pub fn arrange_workspace(&mut self, workspace: WorkspaceId) -> Vec<(WindowId, Rect)> { + let Some(layout_name) = self.workspace(workspace).map(|w| w.layout.clone()) else { + return Vec::new(); + }; + let Some(layout) = self.layouts.get(&layout_name) else { + log::warn!("unknown layout '{layout_name}' for workspace {workspace}"); + return Vec::new(); + }; + + // Grouped via `self.order` (insertion/stacking order), not + // `self.windows.values()`: HashMap iteration order is randomized + // per-process, which would make master/stack assignment reshuffle + // unpredictably every time this runs (it runs on every window + // create/destroy/keybinding). + let mut by_monitor: HashMap<MonitorId, Vec<WindowId>> = HashMap::new(); + for &id in &self.order { + let Some(w) = self.windows.get(&id) else { continue }; + // Fullscreen windows own their whole monitor, so tiling must + // leave them alone, exactly as it does floating ones. + if w.workspace == workspace && !w.minimized && !w.floating && !w.fullscreen { + by_monitor.entry(w.monitor).or_default().push(id); + } + } + + let mut monitor_ids: Vec<MonitorId> = by_monitor.keys().copied().collect(); + monitor_ids.sort_unstable(); + + let mut changes = Vec::new(); + for monitor_id in monitor_ids { + let ids = &by_monitor[&monitor_id]; + let Some(monitor) = self.monitor_for(monitor_id).cloned() else { continue }; + let placements = layout.arrange(ids, &monitor, &self.tiling); + for (id, rect) in placements { + if let Some(w) = self.windows.get_mut(&id) { + w.geometry = rect; + } + changes.push((id, rect)); + } + } + changes + } +} |