Files
omarchycn/shell/plugins/bar
e1d0c4e0a8 Ship the keyboard layout widget on the bar and make clicking it work (#6659)
* Hide the keyboard layout widget on a single-layout install

There is nothing to read or switch when only one layout is configured, so the
label is noise on the bar most people have. Hide it until the keyboard reports
more than one, and keep showing it on a Hyprland that doesn't report the list
at all rather than hiding the widget everywhere.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Put the keyboard layout widget on the bar by default

The widget hides itself unless the active keyboard has more than one layout,
so shipping it costs a single-layout machine nothing and saves everyone else
from finding it in the plugin list. Sit it just right of the clock, and add it
to existing bars the way the agents widget was added, leaving a curated bar
and a disabled widget alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Cycle the layout with the hyprctl command that exists

switchxkblayout is a hyprctl command, not a dispatcher, so sending it over the
dispatch socket only produced a Lua syntax error and clicking the widget did
nothing. Run it instead, against the keyboard the label was read from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Add an idempotent bar add command

Nothing put a widget on the bar without going through the running shell:
plugin enable and bar move both forward to it over IPC, which a migration
cannot rely on. Add writes the config file the way position and transparent
already do, and leaves a widget that is already on the bar where the user put
it, so callers can ask for it repeatedly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Put the keyboard layout widget on bars through the bar CLI

The hand-written jq was a normalizer, a presence check and a splice for what
is now one command that carries all three.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Keep bar add from writing a bar the shell was not reading

The shell takes a user shell.json only when it parses, says version 1, and
carries a bar layout, and does not deep-merge; anything else leaves the
shipped defaults on screen. Reading and writing the user file regardless
turned a config holding nothing but an idle timeout into a bar holding
nothing but the new widget, and made an unparsable one abort the migration
chain on every update. Work against whichever layout is actually in effect,
seeding the defaults before placing a widget they do not already carry.

A malformed hand-installed manifest fails the whole plugin catalog, which was
enough to refuse a first-party widget, so treat an unreadable catalog as no
answer rather than a no. Leave a widget listed in disabledPlugins off the bar
instead of writing a layout entry the registry refuses to load, and re-check
presence inside the mutation so two adds cannot both miss it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Read a widget's default bar section in one place

cmd_defaults spelled out the same "defaultSection, or center when it is
missing or not a section" rule that the add path already asks for by name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Rename bar add to bar put

'omarchy plugin add' installs a plugin and 'omarchy bar add' placed one that
was already installed, which is too much meaning for one verb.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Place a newly added bar widget with bar put

plugin add reached the bar through plugin enable, which forwards to the
running shell, so it first had to poll until the shell noticed the clone and
then failed outright when no shell was there to ask. Putting a widget on the
bar is a config edit, so do that directly and leave plugin enable to the
plugins that need registering rather than placing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Put bar widgets through the shell instead of the config file

Placing a widget existed twice: once in PluginRegistry, which the shell uses
and owns the config it holds in memory, and once as jq against shell.json.
The second was there so migrations could run without a shell, which they do
not need to: the Quattro upgrade hands over the shipped shell.json before it
runs any, and every other path runs inside a session with a shell up. Ask the
shell, and say so and carry on when there is none to ask.

putBarWidget enables only what is not already on the bar, which is what a
caller that cannot know whether it ran before needs, and is the one thing the
existing enable path would not do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 19:38:46 +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 · right = nmtui | | 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 = refresh · 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 · middle = bluetoothctl TUI | | 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
  • 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 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. Older UpperCamelCase ids such as AudioPanel and Clock are migrated forward; new configs should use the namespaced ids.

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.