Files
omarchy/shell/plugins/bar
Bjarne OeverliandClaude Opus 5 6ee7479879 Stop the layout widget switching a device nobody types on
Clicking the keyboard layout widget switches one device, chosen by
filtering the seat through UNTYPED_KEYBOARDS and then taking whichever
survivor sits furthest through the layout list. That filter has to
recognise every non-keyboard by name, and a laptop registers far more as
a keyboard than it lists.

On a Dell XPS 14, Hyprland reports ten keyboards and one of them is a
keyboard. The filter catches three of the other nine, leaving vendor
hotkey blocks (intel-hid-events, intel-hid-5-button-array,
dell-privacy-driver, dell-wmi-hotkeys) and two HID endpoints ahead of
at-translated-set-2-keyboard, which sorts last. Every click switches
hid-sdw:...-consumer-control instead, so the label cycles convincingly
while typing never changes. Device order is stable across polls, so it
is deterministic rather than a race, and needs no pre-existing bad state.

Switch every keyboard holding the same layout list instead, naming an
absolute index. "next" advances each device from wherever it sits, so a
seat that has already drifted apart stays drifted and merely inverts;
one index converges it in a single click, and a seat in lockstep leaves
the reading nothing to disagree about. Keyboards given their own
kb_layout hold a different list and are left alone, since an index into
this list would not mean the same layout to them.

The evdev KEY bitmap would separate these cleanly - the real keyboard
emits 167 keys, the pseudo-devices at most 19 - but hyprctl devices
reports no capability information, so the switch is taken out from
behind the name filter rather than the filter being lengthened.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 19:47:24 +02:00
..
2026-05-19 10:50:36 +02: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) 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 simple first-party bar widgets with sibling manifests.
  • Feature plugins such as ../panels/audio/, ../panels/network/, ../panels/power/, and ../agents/ provide richer popup bar plugins.
  • The bar receives its config from the host shell as a barConfig property; the host loads it from ~/.config/omarchy/shell.json (or config/omarchy/shell.json when the user has no file).
  • omarchy 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 config/omarchy/shell.json. Once you customize anything via the bar gestures, omarchy bar ..., or by editing shell.json directly, your file is canonical — there is no deep-merge.

The bar is configured directly on the bar itself: drag empty bar space (or click-and-hold) to move the bar to another screen edge, double-left-click empty center-bar space to toggle transparency, and drag widgets to reorder them. The omarchy bar position, omarchy bar transparent, omarchy bar move, and omarchy bar set commands do the same from scripts. Enable or disable widgets with omarchy plugin enable and omarchy plugin disable (widget ids come from omarchy plugin list).

Example shell.json (bar subtree only shown):

{
  "version": 1,
  "bar": {
    "position": "top",
    "transparent": false,
    "centerAnchor": "omarchy.clock",
    "layout": {
      "left": [
        { "id": "omarchy.menu" },
        { "id": "omarchy.spacer", "size": 12 },
        { "id": "omarchy.workspaces" }
      ],
      "center": [
        { "id": "omarchy.media" },
        { "id": "omarchy.clock", "format": "HH:mm" }
      ],
      "right": [
        { "id": "omarchy.audio" },
        { "id": "omarchy.power" }
      ]
    }
  }
}

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

Name What it does Interactions
omarchy.menu Omarchy menu launcher left = menu · right = terminal
omarchy.workspaces Hyprland workspace switcher left = focus workspace
omarchy.clock Date/time label + popup with a month grid, ISO week numbers, and month stepping left = popup · right = cycle label format · middle = timezone selector
omarchy.media MPRIS now-playing — scrolling track + artist, cover-art popup left = play/pause · middle = next · scroll = prev/next · right = popup
omarchy.indicators Manual state indicators left = indicator action
omarchy.system-update Available update indicator left = update
omarchy.tray System tray hover = reveal drawer · right on chevron = manage
omarchy.weather Weather icon + popup with forecast left = popup · right = full notification
omarchy.microphone Mic icon + scroll volume left = mute toggle · middle = audio panel · scroll = source volume

| omarchy.audio | Volume icon + popup with master slider, output-device picker, per-app mixer | left = popup · right = mute · middle = popup · scroll = volume | | omarchy.network | Wi-Fi/Ethernet icon + popup with Wi-Fi scan, signal, connect, DNS provider selection | left = popup | | omarchy.tailscale | Tailscale status, connection switcher, machine browser, and copy actions | left = popup · right = toggle · middle = refresh | | omarchy.agents | AI coding agent limits with pace, today, last week, and all-time model breakdown | left = panel · right = launch agent · middle = next subscription | | omarchy.power | Battery/AC icon + popup with battery stats, power profiles, and system info | left = popup · right = toggle percentage | | omarchy.bluetooth | Bluetooth icon + popup with device list, connect/disconnect, battery | left = popup · right = toggle radio | | omarchy.monitor | Brightness and laptop display controls | left = popup |

The omarchy.indicators widget loads individual bar indicators from indicators/. Omit items (or set it to an empty array) to show all indicators in the default order, or set items to a subset such as ["Dnd", "Reminder", "NightLight"]. Set alwaysShow to true to keep inactive indicators visible instead of revealing them only on hover. Multiple omarchy.indicators instances are allowed, so different sections can show different subsets.

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": "omarchy.tray" },
        { "id": "vpn", "type": "command", "exec": "~/.config/omarchy/bar/scripts/vpn-status", "interval": 5, "tooltip": "VPN", "onClick": "nm-connection-editor" },
        { "id": "omarchy.audio" }
      ]
    }
  }
}

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": "omarchy.audio" }
      ]
    }
  }
}

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 (quote arguments with Util.shellQuote from qs.Commons)
  • bar.showTooltip(target, text) / bar.hideTooltip(target) — shared tooltip popup
  • bar.requestPopout(owner) / bar.releasePopout(owner) — one-popup-at-a-time coordinator

First-party bar widgets are manifest-backed just like third-party widgets. Simple widgets carry sibling manifests such as widgets/Workspaces.manifest.json; richer popup plugins live in feature directories such as ../panels/audio/, ../panels/network/, and ../agents/; and feature plugins such as omarchy.menu and omarchy.media declare their bar-widget entry points in their own manifest.json. Bar layout ids are namespaced, e.g. omarchy.audio, omarchy.network, and omarchy.clock.

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. Rescan, enable, and place third-party plugins with omarchy-shell shell rescanPlugins, omarchy plugin enable, and omarchy bar move.