1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Workspace hierarchy — monitors, workspaces, and the scrolling/floating split.
//!
//! Everything that sits *above* the pure layout math in the [`layout`](crate::layout)
//! module. Models a niri-style virtual desktop stack: a [`Monitor`] owns one or
//! more [`Workspace`]s, and a workspace owns exactly one [`ScrollingSpace`] (tiled
//! windows on an infinite horizontal canvas) plus one [`FloatingSpace`] (non-tiled
//! windows in literal pixel coordinates).
//!
//! # Vertical scrolling between workspaces
//!
//! The horizontal scrolling inside a [`ScrollingSpace`] (left/right across columns)
//! has a vertical analogue: workspaces stacked "above" and "below" the active one,
//! switched the same way columns scroll. `switch-workspace` and `move-to-workspace`
//! animate a vertical-packing switch (see the daemon dispatch module); only
//! `swap-workspace` remains a stub pending its own animation model.
//!
//! # What lives here vs. what doesn't
//!
//! A workspace never touches Win32 or the registry directly. The daemon
//! ([`FlowWM`](crate::daemon::FlowWM)) is the only thing
//! that shuttles windows between the
//! [`WindowRegistry`](crate::registry::WindowRegistry) and the active workspace's
//! [`ScrollingSpace`]. IPC plumbing and window-event hooks remain direct fields of
//! [`FlowWM`](crate::daemon::FlowWM), not of the workspace.
//!
//! See the developer guide's *Workspace Hierarchy* chapter
//! (`docs/src/dev-guide/workspace.md`) for the hierarchy diagram and the roadmap
//! for multi-monitor support.
use ;
pub use FloatingSpace;
pub use Monitor;
pub use ScrollingSpace;
pub use workspace_y_offset;
/// Stable, IPC-friendly identifier for a workspace.
///
/// Workspaces are numbered with a plain `u32`, mirroring how niri and most
/// Wayland compositors expose workspace ids over IPC. The id is **stable**:
/// it does not change when workspaces are reordered or swapped, so clients
/// can key on it safely. The [`FlowWM`](crate::daemon::FlowWM)
/// assigns ids at creation time and never reuses them within a session.
///
/// # Serialisation
///
/// `WorkspaceId` is `#[serde(transparent)]`, so it serialises as a bare
/// integer — e.g. `3` rather than `{"workspace_id": 3}`. This keeps the IPC
/// message shape small and matches the `u32` payloads of the
/// `switch-workspace` / `swap-workspace` / `move-to-workspace` commands.
///
/// ```
/// # use flow_wm::workspace::WorkspaceId;
/// let id = WorkspaceId(7);
/// assert_eq!(id.0, 7);
/// ```
;
/// One virtual desktop: a tiling half and a floating half.
///
/// A [`Workspace`] is the niri-style "virtual desktop" unit: the thing the
/// user switches between by scrolling vertically. Each workspace is fully
/// independent — it owns its own tiled windows (in the [`ScrollingSpace`])
/// and its own floating windows (in the [`FloatingSpace`]). Only one
/// workspace per monitor is visible at a time (the monitor's active
/// workspace); the rest are parked "above" or "below", ready to scroll into
/// view.
///
/// # Two Coordinate Spaces
///
/// The two halves share a monitor but use **different coordinate spaces**:
///
/// - [`ScrollingSpace`] runs windows through the virtual → actual projection
/// pipeline (an infinite horizontal canvas clipped to the work area).
/// - [`FloatingSpace`] keeps each window at the literal on-screen rectangle
/// the user dragged it to (or a centered default when first floated).
///
/// Because the two spaces never interact at the layout level, splitting them
/// keeps the tiling math pure and leaves room for floating-window logic to
/// grow independently. The daemon always consults the **active** workspace of
/// the **active** monitor — see
/// [`FlowWM::active_workspace`](crate::daemon::FlowWM).