diff options
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; |