CRITICAL: - Re-inject working entry into the settings form every time the dialog opens. Previously the Loader's onLoaded only fires when the sourceComponent identity changes, so reopening the dialog on the same widget id (or on a second instance of the same id, e.g. two spacers) showed stale field values. - 'Add widget' menu and the centerAnchor dropdown both read draft.layout[section] without depending on the section array identity. Mutating the array in place did not invalidate those bindings, so the menu would show a stale availability list and let non-spacer widgets be added twice. Layout mutations now replace the whole object so any binding that reads it re-evaluates. WARNINGS: - Save now writes only the diff against the merged defaults so future bar-defaults changes are not silently shadowed by a stale snapshot. - FileView onFileChanged handlers simplified to a single reload() — the explicit second loader call was duplicating loadConfig and bumping barConfigSerial twice per change (visible flicker). - userFile onLoaded ignores reloads while the user has an unsaved working draft so external edits during editing do not clobber the in-progress state. - SpinBox forms switched from onValueChanged to onValueModified so the initial-value bind no longer fires fieldChanged. - Hyprland window-rule sizes aligned with the FloatingWindow implicitWidth/Height values (720 main, 380 dialog). - omarchy-launch-bar-settings falls back to initialTitle when focusing, so a dialog that has not yet had its title applied still surfaces the existing instance.
Omarchy bar
This is the Quickshell implementation of the Omarchy status bar.
shell.qmlis Omarchy-owned bar engine code. Users should not edit it directly.bar-defaults.jsonis the Omarchy-owned default layout and module settings.widgets/holds first-party widgets — modular, interactive components shipped with Omarchy.common/holds shared QML helpers (buttons, sliders, popup cards).- User overrides live in
~/.config/omarchy/bar.jsonand are merged over defaults at runtime. omarchy-style-bar-positionupdates only the user override file.
Customizing
The bar reads ~/.local/share/omarchy/default/quickshell/bar/bar-defaults.json, then deep-merges ~/.config/omarchy/bar.json on top of it. Each layout.{left,center,right} entry is an object: at minimum { "id": "<widget>" }, plus any inline settings the widget reads.
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.
Example bar.json:
{
"position": "top",
"centerAnchor": "calendar",
"layout": {
"left": [
{ "id": "omarchy" },
{ "id": "spacer", "size": 12 },
{ "id": "workspacesPro" }
],
"center": [
{ "id": "media" },
{ "id": "calendar", "format": "HH:mm" }
],
"right": [
{ "id": "systemStats" },
{ "id": "audioPanel" },
{ "id": "battery" },
{ "id": "controlCenter" },
{ "id": "powerMenu" }
]
}
}
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 | 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 |
brightness |
Brightness slider + scroll | scroll = adjust · left = popup · middle = reset to 80% |
powerProfile |
Current power profile + popup picker | left = popup |
systemStats |
Inline CPU + memory sparklines, popup with detail | left = popup · right = terminal |
weatherFlyout |
Weather icon + popup with forecast | left = popup · right = full notification |
workspacesPro |
Animated focus indicator that slides between workspaces | left = focus · right = move window · scroll = cycle |
powerMenu |
Power icon → popup with lock/suspend/log out/reboot/shutdown | left = popup |
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.
Command module:
{
"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:
{
"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 familybar.position—"top" | "bottom" | "left" | "right"bar.vertical— boolean shortcutbar.barSize— 26 horizontal / 28 verticalbar.run(command)— fire-and-forget bash execbar.shellQuote(value)— safe shell-quote a stringbar.showTooltip(target, text)/bar.hideTooltip(target)— shared tooltip popupbar.requestPopout(owner)/bar.releasePopout(owner)— one-popup-at-a-time coordinator
Drop new widgets into widgets/<name>.qml, add the name to the firstPartyWidgets registry in shell.qml, and reference it by name in any layout list.