How Does Hyprland Manage State Transitions for Windows?
Hyprland employs a signal-driven architecture using immutable state snapshots, dedicated state trackers, and animation controllers to ensure atomic and deterministic window state transitions across workspaces and monitors.
Managing window state transitions in a dynamic Wayland compositor requires rigorous coordination between user input, logical state, and visual output. In the Hyprland repository, this complexity is abstracted into a modular pipeline where every visual change is backed by an immutable state object. The system guarantees consistency by routing all modifications through centralized state trackers that emit events, drive animations, and commit final states atomically.
The Core Architecture: CWindow and CWindowState
The foundation of Hyprland's state management rests on two primary components: the window object itself and its immutable state representation.
The CWindow Object
Each X11 or Wayland surface is encapsulated by a CWindow instance defined in src/desktop/view/Window.hpp. This class implements several critical interfaces—IView, CGeometricMovableAnimated, and IAlphaModifiable—which grant it capabilities for geometry manipulation, animation support, and opacity control. Rather than storing mutable properties directly, CWindow delegates state authority to external trackers, ensuring that its internal representation remains synchronized with the compositor's global state.
Immutable State Snapshots
Window properties such as size, position, monitor assignment, workspace ID, and opacity are stored in CWindowState, located in src/desktop/state/WindowState.hpp. This structure acts as an immutable snapshot; whenever a property changes, the system generates a new CWindowState instance rather than mutating the existing one. This functional approach eliminates race conditions and allows the animation system to interpolate between distinct, well-defined states without side effects.
The State Transition Pipeline
When a user initiates an action—such as moving a window to another workspace or toggling fullscreen—Hyprland executes a five-phase pipeline to transition from the current state to the target state.
1. Requesting Changes via State Trackers
State modifications originate at the WorkspaceStateTracker (src/state/WorkspaceStateTracker.cpp) or MonitorStateTracker (src/state/MonitorStateTracker.cpp). These trackers maintain authoritative maps of windows to their current states for each workspace and monitor. When a CWindow method such as setFullscreen() or moveToWorkspace() is invoked, it delegates to the tracker's requestStateChange() method, passing the window reference and the desired transition type (e.g., WindowStateChange::MOVE).
2. Event Propagation Through the Event Bus
Upon receiving a request, the tracker instantiates a CWindowStateChangeEvent and publishes it through Hyprland's internal event bus managed by EventManager (src/managers/EventManager.cpp). This publish-subscribe mechanism decouples state logic from visual rendering, allowing multiple subsystems—including layout managers, focus controllers, and animation handlers—to react to the same state transition without direct dependencies.
3. Animation Interpolation
The CWindowAnimationController (src/desktop/view/animationControllers/WindowAnimationController.hpp) subscribes to state-change events and manages the visual transition between the old and new CWindowState snapshots. By interpolating geometry and opacity values frame-by-frame, the controller drives smooth animations—such as fade-ins, slide transitions, and resize effects—while updating the OpenGL renderer each frame. This ensures that the visual presentation never diverges from the underlying logical state.
4. Committing the Final State
Once the animation concludes, the new CWindowState is committed to the tracker, replacing the previous snapshot atomically. The WorkspacePlacementController (src/state/WorkspacePlacementController.cpp) then finalizes the placement by updating focus stacks, recalculating split layouts, and ensuring the window is correctly assigned to its target monitor. This commit phase guarantees that queries via hyprctl reflect the definitive state only after all visual transitions complete.
Practical Implementation Examples
The following examples demonstrate how to trigger and observe state transitions programmatically and via command-line interfaces.
Programmatic Window Movement (C++)
To move a window between workspaces while ensuring proper state tracking:
#include <hyprland/src/desktop/view/Window.hpp>
#include <hyprland/src/state/WorkspaceStateTracker.hpp>
// Assuming `window` is a valid CWindow* and `targetWorkspace` is a CWorkspace*
window->setFullscreen(false); // Exit fullscreen if needed
window->moveToWorkspace(targetWorkspace->id()); // Request workspace switch
WindowStateTracker::get()->requestStateChange(window, WindowStateChange::MOVE);
Command-Line State Transitions (Bash)
Use hyprctl to dispatch state changes that follow the same pipeline:
# Move the active window to workspace 3
hyprctl dispatch movetoworkspace 3
# Toggle fullscreen for the focused window
hyprctl dispatch fullscreen
Observing Transitions via Event Hooks (Lua)
Listen to state-change events to execute custom logic during transitions:
hypr.on("windowStateChange", function(window, oldState, newState)
hypr.notify("Window " .. window:title() .. " moved from " ..
oldState:workspace() .. " to " .. newState:workspace())
end)
Key Source Files and Their Roles
Understanding the following files is essential for modifying or debugging Hyprland's state management behavior:
src/desktop/view/Window.hpp– Defines theCWindowclass and its implemented interfaces (IView,CGeometricMovableAnimated,IAlphaModifiable).src/desktop/state/WindowState.hpp– Contains the immutableCWindowStatestructure representing all window properties at a specific moment.src/state/WorkspaceStateTracker.cpp– Manages per-workspace window mappings and dispatches state-change requests.src/state/MonitorStateTracker.cpp– Tracks window assignments to specific monitors and handles monitor-specific state transitions.src/desktop/view/animationControllers/WindowAnimationController.hpp– Interpolates between state snapshots to drive visual animations.src/managers/EventManager.cpp– Implements the core publish-subscribe event bus for state-change notifications.src/state/WorkspacePlacementController.cpp– Finalizes window placement and updates focus/layout after state commits.
Summary
- Immutable State Model: Hyprland uses
CWindowStatesnapshots to ensure deterministic state representation without mutation side effects. - Centralized Trackers:
WorkspaceStateTrackerandMonitorStateTrackerserve as the single source of truth for window assignments, routing all changes throughrequestStateChange(). - Event-Driven Architecture: State transitions emit
CWindowStateChangeEventobjects throughEventManager, decoupling logic from rendering. - Animated Interpolation:
CWindowAnimationControllersmoothly transitions between old and new states before atomic commitment. - Atomic Commitment: Final state application occurs only after animations complete, ensuring
hyprctlqueries and internal logic remain synchronized.
Frequently Asked Questions
How does Hyprland ensure window states remain consistent during rapid user actions?
Hyprland achieves consistency by treating CWindowState objects as immutable snapshots stored in centralized trackers. When rapid actions occur, each generates a distinct state-change event queued through the EventManager, preventing race conditions. The system processes these sequentially, with the CWindowAnimationController interpolating between well-defined states rather than applying partial updates.
What triggers a window state transition in Hyprland?
State transitions are triggered by three primary sources: user input handled through hyprctl dispatchers, direct API calls to CWindow methods like moveToWorkspace() or setFullscreen(), and internal layout manager requests. All sources ultimately invoke WorkspaceStateTracker::requestStateChange(), ensuring uniform handling regardless of origin.
Can custom animations be defined for specific window state transitions?
Yes. The CWindowAnimationController in src/desktop/view/animationControllers/WindowAnimationController.hpp listens for CWindowStateChangeEvent objects and determines interpolation strategies based on the transition type and window properties. Developers can extend this controller to implement custom easing functions or duration logic by modifying how the controller calculates intermediate frames between old and new CWindowState snapshots.
Where does Hyprland store the authoritative state for window geometry and workspace assignment?
Authoritative state resides in the WorkspaceStateTracker and MonitorStateTracker instances, which maintain maps of window pointers to their current CWindowState objects. While CWindow provides the interface for requesting changes, the trackers hold the ground truth, committing new states only after animations complete via the WorkspacePlacementController.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →