srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/core/src/manager/layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/core/src/manager/layout.rs')
-rw-r--r--crates/core/src/manager/layout.rs67
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
+ }
+}