Skip to content

Workspaces

📖

Problem

Hyprland organizes windows into virtual workspaces. Your shell needs to know which workspaces exist, which is active, and what windows they contain. Without this, you cannot build a workspace switcher, show workspace indicators, or implement scratchpad behavior.

Naive Approach

Poll hyprctl workspaces every second with a Timer. This works but wastes CPU, introduces latency, and misses rapid changes. The output is plain text you must parse every cycle.

MentalModel

💡Mental Model

A workspace is a numbered container mapped to a virtual desktop. Hyprland maintains a list of these containers internally. The Hyprland singleton in Quickshell mirrors this list as a reactive model. When a workspace is created, destroyed, or focused, Hyprland emits an event and the model updates automatically.

Think of it like a ListView model — it has count, individual items, and notifies listeners on change.

Idea

Quickshell's Hyprland singleton provides workspaces — a model of HyprlandWorkspace objects. Each object exposes id, name, monitor, windows, isActive, and more. You bind directly to these properties without polling.

Build It

qml
import Quickshell
import Quickshell.Hyprland

Column {
  Repeater {
    model: Hyprland.workspaces

    delegate: Rectangle {
      width: 40
      height: 40
      color: modelData.isActive ? "#5294e2" : "#333333"

      Text {
        anchors.centerIn: parent
        text: modelData.id
        color: "#ffffff"
      }

      MouseArea {
        anchors.fill: parent
        onClicked: Hyprland.dispatch("workspace", modelData.id)
      }
    }
  }
}

BuildIt Breakdown

Hyprland.workspaces is a live model — when a workspace is added or removed, the Repeater updates automatically. modelData gives each delegate its corresponding HyprlandWorkspace. The isActive property determines the active workspace. Hyprland.dispatch() sends a Hyprland socket command — same as hyprctl dispatch workspace 5.

Improve It

Filter out empty workspaces by binding visible: modelData.windows > 0. Sort workspaces using a SortProxyModel. Add window count badges. Animate the active indicator with a NumberAnimation on color.

CommonMistake

⚠️Common Mistake

Assuming workspaces returns a flat list you can index by ID. Workspace IDs may be non-contiguous (you can skip from workspace 1 to 5). Always treat the model as an ordered list, not an array with ID-based indices.

Under the Hood

🔧Under the Hood

Hyprland exposes a UNIX socket at $XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock. The Hyprland singleton opens this socket and listens for workspace events using a QSocketNotifier. When an event arrives, it issues hyprctl workspaces -j once and updates the model. This is far more efficient than periodic polling because the OS wakes your process only when data changes.

Exercises

Exercise

Create a vertical workspace bar that highlights the active workspace and switches on click.

Exercise

Add a window counter badge to each workspace indicator. Show the count of windows per workspace.

Exercise

Build a workspace preview — on hover, show miniature window thumbnails for each workspace using hyprctl clients -j parsed into a custom model.

Recap

What You've Learned

Built with VitePress. Licensed under MIT.