Skip to content

IPC Events ​

📖

Problem ​

Beyond workspaces and active windows, your shell may need to react to arbitrary Hyprland events: window title changes, monitor hotplugs, window opens/closes, fullscreen state changes, or urgent hints. The Hyprland singleton covers common cases, but you may need raw event access for custom behavior.

Naive Approach ​

Listen to everything with a generic hyprctl poll loop. Filter events by parsing jq output. Fragile, slow, and misses transient events that occur between polls.

MentalModel ​

💡Mental Model

Hyprland's IPC socket emits a continuous stream of event lines. Each line has the format event>>payload. Quickshell wraps this as a signal-based API. Think of it as an event bus — you subscribe to specific event names and get notified synchronously when they occur.

Idea ​

Quickshell's Hyprland singleton provides a socketEvent signal that fires for every IPC event. Connect to it with a handler that filters by event name. The event name and payload are passed as strings.

Build It ​

qml
import Quickshell
import Quickshell.Hyprland

Item {
  Connections {
    target: Hyprland

    function onSocketEvent(event: string, payload: string) {
      switch (event) {
        case "openwindow":
          console.log(`Window opened: ${payload}`)
          break
        case "closewindow":
          console.log(`Window closed: ${payload}`)
          break
        case "windowtitle":
          console.log(`Title changed: ${payload}`)
          break
        case "fullscreen":
          console.log(`Fullscreen toggled: ${payload}`)
          break
        case "monitoradded":
          console.log(`Monitor plugged in: ${payload}`)
          break
        case "monitorremoved":
          console.log(`Monitor removed: ${payload}`)
          break
      }
    }
  }
}

BuildIt Breakdown ​

socketEvent fires for every raw IPC line from Hyprland. The event parameter is the event type (e.g., openwindow). The payload is the rest of the line — typically comma-separated values like windowAddress,workspaceId,windowClass,windowTitle. This is a firehose; filter aggressively to avoid performance issues in hot paths like windowtitle which fires on every keystroke in a terminal.

Improve It ​

Create typed wrapper signals. Build a HyprlandEvent QML singleton that parses payloads into structured objects. Use Connections with enabled: false and toggle it only when needed. Debounce high-frequency events with a Timer.

CommonMistake ​

⚠️Common Mistake

Processing every event synchronously inside onSocketEvent. A rapid-fire event like windowtitle (fires per-keystroke) can block the UI thread. Offload heavy work to a Timer callback that batches events.

Under the Hood ​

🔧Under the Hood

Hyprland's event socket is .socket2.sock — a UNIX socket that writes one line per event. Quickshell uses a QSocketNotifier to read from it asynchronously. When data is available, it reads all buffered lines and emits socketEvent for each one. This means multiple events may arrive in a single read cycle if they queued up. The notifier operates at the event loop level and does not block the UI thread during reads.

Exercises ​

⭐Exercise

Log all openwindow events to see what payloads arrive.

⭐Exercise

Build a toast notification that shows when a window opens or closes.

⭐Exercise

Create a full event debugger panel that shows the last 50 IPC events with timestamps.

Recap ​

✅What You've Learned

Built with VitePress. Licensed under MIT.