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/mod.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/mod.rs')
| -rw-r--r-- | crates/core/src/manager/mod.rs | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/crates/core/src/manager/mod.rs b/crates/core/src/manager/mod.rs new file mode 100644 index 0000000..91df887 --- /dev/null +++ b/crates/core/src/manager/mod.rs @@ -0,0 +1,163 @@ +use crate::geometry::Rect; +use crate::layout::{Layout, MasterStackLayout, NoOpLayout, TilingConfig}; +use crate::monitor::{Monitor, MonitorId}; +use crate::placement::{PlacementConfig, SmartPlacement, MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH}; +use crate::rules::WindowRule; +use crate::theme::ThemeConfig; +use crate::window::{ResizeEdge, TitlebarHit, Window, WindowId, RESIZE_MARGIN}; +use crate::workspace::{Workspace, WorkspaceId}; +use std::collections::HashMap; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Direction { + Left, + Right, + Up, + Down, +} + +struct DragState { + window: WindowId, + start_x: i32, + start_y: i32, + orig: Rect, +} + +struct ResizeState { + window: WindowId, + edge: ResizeEdge, + start_x: i32, + start_y: i32, + orig: Rect, +} + +/// The platform-independent core of srdwm: owns window/workspace/monitor +/// state and layout policy. Backends (X11, Wayland, ...) drive this via +/// `add_window`/`remove_window`/input events, and apply the `Rect`s it +/// computes back onto real surfaces. +pub struct WindowManager { + windows: HashMap<WindowId, Window>, + order: Vec<WindowId>, + focused: Option<WindowId>, + monitors: Vec<Monitor>, + workspaces: Vec<Workspace>, + current_workspace: WorkspaceId, + /// Whichever workspace was current immediately before the current one + /// became current - see `switch_workspace`'s doc comment. + previous_workspace: WorkspaceId, + /// Read from `workspace.auto_back_and_forth`. When set, switching to + /// the workspace that's already active switches to `previous_workspace` + /// instead - sway's `workspace_auto_back_and_forth` behavior, a quick + /// "jump back to whatever I was just on" toggle on a single keybinding. + pub auto_back_and_forth: bool, + next_workspace_id: WorkspaceId, + next_window_id: WindowId, + layouts: HashMap<String, Box<dyn Layout>>, + pub tiling: TilingConfig, + pub placement: PlacementConfig, + /// Whether geometry changes made via `toggle_maximize`/`toggle_fullscreen` + /// should be animated. Read from `general.animations`; a backend's open + /// animation is gated on this too, since core has no notion of "open". + pub animations_enabled: bool, + /// Tween duration in milliseconds, read from `general.animation_duration`. + pub animation_duration_ms: u32, + /// Whether windows get a drop shadow. Read from `general.shadows`. A + /// maximized or fullscreen window never gets one regardless of this -- + /// see the Wayland backend's shadow render call site - so this only + /// ever turns it off entirely, not on for those. + pub shadows_enabled: bool, + /// Width, in pixels, of the resize grab band along a window's edges, + /// read from `general.resize_margin`. See [`crate::window::RESIZE_MARGIN`]'s + /// doc comment for the default and why it's what it is. + pub resize_margin: i32, + /// Whether a decorated window's content rounds its bottom two corners + /// to match the titlebar's own curve (an undecorated/CSD window rounds + /// all four). Read from `general.rounded_corners` - `None` when the + /// user's config never touched that key at all (deliberately *not* + /// defaulted in `crates/config`, unlike every other `general.*` key), + /// so each backend can fall back to its own default rather than one + /// baked in here: GLES/winit defaults on, udev/Pixman defaults off + /// (an untested-on-real-hardware per-frame CPU cost for content that + /// 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>, + /// Default decoration colours and border width, read from `theme.colors.*`/ + /// `theme.decorations.*`. See `ThemeConfig`'s own doc comment. + pub theme: ThemeConfig, + drag: Option<DragState>, + resize: Option<ResizeState>, + rules: Vec<WindowRule>, + /// Windows a client-close was requested for, drained once per tick by + /// `main.rs`'s event loop and forwarded to `Platform::close`. Needed + /// because `WindowManager` is platform-agnostic and has no way to send + /// a client its close request directly - see `close_window`. + close_requests: Vec<WindowId>, +} + +impl Default for WindowManager { + fn default() -> Self { + Self::new() + } +} + +impl WindowManager { + pub fn new() -> Self { + let mut layouts: HashMap<String, Box<dyn Layout>> = HashMap::new(); + layouts.insert("tiling".into(), Box::new(MasterStackLayout)); + layouts.insert("dynamic".into(), Box::new(NoOpLayout("dynamic"))); + layouts.insert("floating".into(), Box::new(NoOpLayout("floating"))); + + Self { + windows: HashMap::new(), + order: Vec::new(), + focused: None, + monitors: Vec::new(), + workspaces: vec![Workspace::new(0, "1", "dynamic")], + current_workspace: 0, + previous_workspace: 0, + auto_back_and_forth: false, + next_workspace_id: 1, + next_window_id: 1, + layouts, + tiling: TilingConfig::default(), + placement: PlacementConfig::default(), + animations_enabled: true, + animation_duration_ms: 200, + shadows_enabled: true, + resize_margin: RESIZE_MARGIN, + rounded_corners_enabled: None, + theme: ThemeConfig::default(), + drag: None, + resize: None, + rules: Vec::new(), + close_requests: Vec::new(), + } + } + + /// Registers a window rule; on every subsequent `add_window`, the first + /// rule whose matcher matches the new window has its actions applied. + pub fn add_rule(&mut self, rule: WindowRule) { + self.rules.push(rule); + } + + pub fn register_layout(&mut self, name: impl Into<String>, layout: Box<dyn Layout>) { + self.layouts.insert(name.into(), layout); + } + + pub fn available_layouts(&self) -> Vec<&str> { + self.layouts.keys().map(String::as_str).collect() + } + +} + +mod dragresize; +mod focus; +mod hittest; +mod layout; +mod monitors; +mod windows; +mod winops; +mod workspaces; + +#[cfg(test)] +mod tests; |