# How Does Hyprland Manage State Transitions for Windows?

> Discover how Hyprland manages window state transitions with its signal-driven architecture, immutable snapshots, and animation controllers for atomic and deterministic window management.

- Repository: [Hypr Development/Hyprland](https://github.com/hyprwm/Hyprland)
- Tags: internals
- Published: 2026-07-23

---

**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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspaceStateTracker.cpp)) or **`MonitorStateTracker`** ([`src/state/MonitorStateTracker.cpp`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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:

```cpp
#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:

```bash

# 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:

```lua
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`](https://github.com/hyprwm/Hyprland/blob/main/src/desktop/view/Window.hpp)** – Defines the `CWindow` class and its implemented interfaces (`IView`, `CGeometricMovableAnimated`, `IAlphaModifiable`).
- **[`src/desktop/state/WindowState.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/desktop/state/WindowState.hpp)** – Contains the immutable `CWindowState` structure representing all window properties at a specific moment.
- **[`src/state/WorkspaceStateTracker.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspaceStateTracker.cpp)** – Manages per-workspace window mappings and dispatches state-change requests.
- **[`src/state/MonitorStateTracker.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/MonitorStateTracker.cpp)** – Tracks window assignments to specific monitors and handles monitor-specific state transitions.
- **[`src/desktop/view/animationControllers/WindowAnimationController.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/desktop/view/animationControllers/WindowAnimationController.hpp)** – Interpolates between state snapshots to drive visual animations.
- **[`src/managers/EventManager.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/managers/EventManager.cpp)** – Implements the core publish-subscribe event bus for state-change notifications.
- **[`src/state/WorkspacePlacementController.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/state/WorkspacePlacementController.cpp)** – Finalizes window placement and updates focus/layout after state commits.

## Summary

- **Immutable State Model**: Hyprland uses `CWindowState` snapshots to ensure deterministic state representation without mutation side effects.
- **Centralized Trackers**: `WorkspaceStateTracker` and `MonitorStateTracker` serve as the single source of truth for window assignments, routing all changes through `requestStateChange()`.
- **Event-Driven Architecture**: State transitions emit `CWindowStateChangeEvent` objects through `EventManager`, decoupling logic from rendering.
- **Animated Interpolation**: `CWindowAnimationController` smoothly transitions between old and new states before atomic commitment.
- **Atomic Commitment**: Final state application occurs only after animations complete, ensuring `hyprctl` queries 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`](https://github.com/hyprwm/Hyprland/blob/main/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`.