Files
omarchycn/default/quickshell/omarchy-shell/plugins/bar
Ryan Hughes d73690b945 Unified cursor chrome across DNS pills and wifi rows
The wifi panel now has full keyboard nav over both sections:
  h/l            walk the DNS provider pills
  j/k            walk the wifi network list (j from DNS drops into the
                 list; k from the top row goes back to DNS)
  Enter/Space    apply the highlighted DNS provider / connect to the
                 highlighted wifi network
  Esc            close the panel

Single-cursor model. The visible cursor lives at the panel root via
focusSection + dnsIndex + selectedIndex. Mouse hover doesn't draw its
own highlight — onContainsMouseChanged on each row/pill MOVES the
cursor instead. Mouse leaving doesn't clear it (the cursor stays where
attention was last; subsequent j/k pick up from there). Last action
wins, whether mouse or keyboard.

New Common.CursorSurface holds the shared chrome (fill + 1px border +
fade) and is the base for both NetworkRow and the new local
DnsProviderPill. Items pass only hasCursor + current and let the
surface render. Contract: items never read containsMouse for visuals.
That's what guarantees exactly one highlight on screen at any time.

DnsProviderPill replaces Common.PillButton for the DNS row because
PillButton's hover > active > background cascade fights the
single-cursor model — its built-in hover would draw a parallel
highlight on whatever pill the pointer is parked on, even after the
cursor moved elsewhere. PillButton stays where it fits (refresh icon,
other bar widgets) and is unchanged here.
2026-05-17 20:15:00 -04:00
..

Omarchy bar

This is the Quickshell implementation of the Omarchy status bar. It is shipped as a first-party plugin of omarchy-shell, the long-running shell host. The bar is mounted at startup and lives inside the shell for its whole session.

  • manifest.json declares the plugin (id: omarchy.bar, kind: bar, activation: persistent) and points at Bar.qml as the entry point.
  • Bar.qml is Omarchy-owned bar engine code, loaded by the omarchy-shell host. Users should not edit it directly.
  • widgets/ holds first-party widgets — modular, interactive components shipped with Omarchy.
  • common/ holds shared QML helpers (buttons, sliders, popup cards).
  • The bar receives its config from the host shell as a barConfig property; the host loads it from ~/.config/omarchy/shell.json (or shell-defaults.json when the user has no file).
  • omarchy-style-bar-position updates only the user shell.json file.

Customizing

The bar config lives under the bar: key of ~/.config/omarchy/shell.json. Out of the box the shell uses shell-defaults.json. Once you customize anything via omarchy launch bar settings or by editing shell.json directly, your file is canonical — there is no deep-merge.

Launch the visual editor with omarchy launch bar settings (or run omarchy-launch-bar-settings) to reorder widgets, add/remove them, and tweak per-widget options without editing JSON by hand. You can also right-click empty space to the left or right of the centered clock to open it; double-left-click the same empty space to toggle bar transparency.

Example shell.json (bar subtree only shown):

{
  "version": 1,
  "bar": {
    "position": "top",
    "transparent": false,
    "centerAnchor": "calendar",
    "layout": {
      "left": [
        { "id": "omarchy" },
        { "id": "spacer", "size": 12 },
        { "id": "workspaces" }
      ],
      "center": [
        { "id": "media" },
        { "id": "calendar", "format": "HH:mm" }
      ],
      "right": [
        { "id": "audioPanel" },
        { "id": "battery" }
      ]
    }
  }
}

centerAnchor pins one center module to the exact horizontal/vertical center and flanks others around it. Set to an empty string to disable anchoring (the center list is centered as a group).

Module catalogue

First-party interactive widgets (in widgets/)

Name What it does Interactions
media MPRIS now-playing — scrolling track + artist, cover-art popup left = play/pause · middle = next · scroll = prev/next · right = popup
audioPanel Volume icon + popup with master slider, output-device picker, per-app mixer left = popup · right = mute · middle = audio TUI · scroll = volume
networkPanel Wi-Fi/Ethernet icon + popup with Wi-Fi scan, signal, connect, DNS provider selection left = popup · right = nmtui
bluetoothPanel Bluetooth icon + popup with device list, connect/disconnect, battery left = popup · right = toggle radio · middle = bluetoothctl TUI
calendar Clock + popup with month-grid calendar left = popup · right = tz selector
notificationCenter Bell with badge + popup with recent notifications, DND toggle left = popup · right = toggle DND
systemStats Inline CPU + memory sparklines, popup with detail left = popup · right = terminal
weatherFlyout Weather icon + popup with forecast left = popup · right = full notification
idleInhibitor Coffee-cup that toggles omarchy-toggle-idle left = toggle
microphone Mic icon + scroll volume left = mute toggle · middle = audio TUI · scroll = source volume

Built-in legacy modules (in shell.qml)

omarchy, workspaces, clock, weather, update, voxtype, screenRecording, idle, notifications, tray, bluetooth, network, audio, cpu, battery.

These remain available — set them in layout to use them instead of the richer widget versions.

Orientation

All widgets work in top, bottom, left, and right positions. Popups anchor on the side opposite the bar edge, sliding into the workspace. Vertical bars use 28px width; widgets that show text fall back to compact icon-only forms (e.g. media hides its scrolling label).

Custom user modules

The schema accepts arbitrary module ids that you provide. Set type to command for shell-driven output or qml for a custom QML widget. Both still go under bar.layout.<section> in shell.json.

Command module:

{
  "version": 1,
  "bar": {
    "layout": {
      "right": [
        { "id": "tray" },
        { "id": "vpn", "type": "command", "exec": "~/.config/omarchy/bar/scripts/vpn-status", "interval": 5, "tooltip": "VPN", "onClick": "nm-connection-editor" },
        { "id": "audioPanel" }
      ]
    }
  }
}

The command may print plain text or Waybar-style JSON, for example:

{"text":"󰌆","tooltip":"Work VPN","class":"active"}

QML module:

{
  "version": 1,
  "bar": {
    "layout": {
      "right": [
        { "id": "gpu", "type": "qml" },
        { "id": "audioPanel" }
      ]
    }
  }
}

Then create ~/.config/omarchy/bar/modules/gpu.qml. If you want to store it elsewhere, add a source path.

Custom QML modules should be an Item with implicitWidth and implicitHeight. They may optionally define these properties, which the bar fills after loading:

import QtQuick

Item {
  property var bar
  property string moduleName
  property var settings

  implicitWidth: 28
  implicitHeight: bar ? bar.barSize : 26

  Text {
    anchors.centerIn: parent
    text: "GPU"
    color: bar ? bar.foreground : "white"
    font.family: bar ? bar.fontFamily : "monospace"
    font.pixelSize: 12
  }

  MouseArea {
    anchors.fill: parent
    onClicked: if (bar) bar.run("omarchy-launch-or-focus-tui btop")
  }
}

Bar properties available to widgets

Widgets receive bar (the shell root), moduleName (string), and settings (object) injected at load time. The bar exposes:

  • bar.foreground, bar.background, bar.urgent — theme colors (live-updated)
  • bar.fontFamily — current monospace family
  • bar.position"top" | "bottom" | "left" | "right"
  • bar.vertical — boolean shortcut
  • bar.barSize — 26 horizontal / 28 vertical
  • bar.run(command) — fire-and-forget bash exec
  • bar.shellQuote(value) — safe shell-quote a string
  • bar.showTooltip(target, text) / bar.hideTooltip(target) — shared tooltip popup
  • bar.requestPopout(owner) / bar.releasePopout(owner) — one-popup-at-a-time coordinator

First-party widgets live in widgets/<name>.qml and are picked up by the shell's BarWidgetRegistry at startup; reference one by id in any layout list.

Third-party widgets ship as separate plugins under ~/.config/omarchy/plugins/<plugin-id>/ with their own manifest.json declaring kinds: ["bar-widget"] and a barWidget entry point. See ../../README.md for the manifest schema. Enable or rescan third-party plugins with omarchy-shell-ipc shell setPluginEnabled and omarchy-shell-ipc shell rescanPlugins.