oMenu
A minimal auto-hiding dock and app launcher for Omarchy, built on Quickshell — a shelf for launching apps when your hands want a mouse instead of a keybind, with a built-in app launcher three keystrokes away.
It runs by three rules:
Show up only when there's something to do. Visibility follows your workspace: empty workspace → oMenu is visible, windows present → it hides. Fully event-driven — Hyprland tells it what changed, it never polls. Hovering the bottom edge reveals it at any time.
Never disturb the layout. No exclusive zone by default, no layout negotiation. Panels don't jump, maximized windows don't shrink — nothing on your screen ever moves because of this dock. (If you want the reserved space, it's a toggle.)
Hold only what you put on it. Running-but-unpinned apps never appear on their own, so every icon sits exactly where you left it until you move it. On a tiling desktop your workspaces already are the running-app list — this is just a shelf for the moments when you'd rather click than type.
Features
- Auto-hide with two modes — Smart hide (event-driven workspace tracking) or Always visible, with an optional reserve space so tiled windows stop above oMenu
- App launcher — every installed app in a slim, settings-styled menu: live search, arrow-key navigation,
Enterto launch, and a power button that summons the Omarchy system menu (lock / logout / reboot / shutdown) - Super key toggle — open and close the launcher with the Super key alone (combos unaffected)
- Drag from launcher to dock — drag any app straight onto the bar; an insertion caret shows where it will land
- Right-click everywhere — new window / quit / unpin / change icon on tiles; pin-unpin straight from the launcher rows
- Change icon — per-app icon override: theme name, absolute path, or the system file picker (XDG portal, out-of-process)
- Minimize to scratchpad — clicking a running app sends it to
special:omenu_minimize; click again to restore - Hover window list — apps with 2+ windows pop a picker
- Gmail unread badge — counts
Inbox (N)window titles via Hyprland events, no polling - Drag reorder with persistent order
- Live settings panel — icon size, spacing, hover grow, edge gap, running dot, launcher on/off, visibility mode, reserve space, show-on-empty, reset
- Theme-independent icons — a built-in icon-name → file index that works even when your icon theme setting is broken
- IPC —
toggleLauncher/isOpenfor scripting
Install (Omarchy)
omarchy plugin add https://github.com/iaeluk/iaeluk.omenu.git --enable
That clones the plugin into ~/.config/omarchy/plugins/iaeluk.omenu and starts it. Verify with omarchy plugin list — it should show up as iaeluk.omenu, enabled.
Optional: open the launcher with the Super key
Add to ~/.config/hypr/bindings.lua:
-- Toggle the oMenu launcher with the Super key alone. Fires on
-- release, so Super-based combos (SUPER+E etc.) are unaffected.
o.bind("SUPER + SUPER_L", "Toggle oMenu launcher",
"qs -p /usr/share/omarchy/shell ipc call iaeluk.omenu toggleLauncher", { release = true })
Then hyprctl reload. Press Super to open the launcher, Super again (or Esc, or a click outside) to close it.
Removal
omarchy plugin remove iaeluk.omenu
That disables and removes the plugin. State under ~/.local/state/omarchy/iaeluk.omenu/ (pins, order, hidden, settings, icon overrides) is left in place unless you remove it yourself — delete that folder for a complete cleanup.
Using oMenu
| Interaction | Result |
|---|---|
| Click an icon | Launch, focus, or minimize/restore (see below) |
| Right-click an icon | New window · Quit (if running) · Unpin · Change icon |
| Right-click empty bar | Pin a running app · Settings |
| Hover an icon with 2+ windows | Pick which window to focus |
| Hover the bottom edge | Reveal a hidden oMenu |
| Drag an icon sideways | Reorder (order persists) |
| Super (optional binding) | Toggle the app launcher |
Click behavior: not running → launch; running on the current workspace → minimize to the special:omenu_minimize scratchpad; minimized there → restore and focus; on another workspace → focus. Per-app minimizable: false always focuses instead.
The launcher
The 4-dot button at the left end of the bar (drag it anywhere among the icons — its slot persists) opens a slim menu listing every installed desktop entry, name-sorted:
- Type to filter — the field starts focused; results narrow live
- ↑ / ↓ move the selection, Enter launches it, Esc closes
- Right-click a row → Pin to oMenu / Unpin from oMenu (the dock updates live)
- Drag a row onto the bar → the app pins at the insertion caret
- Click a row (or
Enter) to launch viagtk-launch, which honorsTerminal=trueand desktop field codes - Power button (right of All apps) — opens the Omarchy system menu (lock / logout / reboot / shutdown), the same one bound to
SUPER + ESC
Toggle the button on/off in Settings → Enable launcher.
Settings
Open with right-click on empty bar → Settings. Everything applies live and persists:
| Setting | Default | Effect |
|---|---|---|
| Visibility | Smart hide | Smart hide: workspace-driven. Always visible: never auto-hides |
| Reserve space for windows | off | Always-visible only: tiled windows stop above oMenu |
| Icon size | 54 px | 32–96 px |
| Icon hover grow | 18 % | 0 (off)–40 %; icons scale up on hover without reflow |
| Icon spacing | 12 px | 0–48 px |
| Edge gap | 6 px | Distance from the screen's bottom edge, 0–24 px |
| Show on empty workspace | on | Smart-hide only: when off, oMenu also hides on empty workspaces (reveal on hover) |
| Show running dot | on | The running indicator under icons |
| Enable launcher | on | The launcher button on the bar |
| Reset to defaults | — | Restores every value above |
Changing icons
Right-click an icon → Change icon:
- Type a theme icon name (
firefox-symbolic) or an absolute path (/home/you/AppImages/.icons/app.png) - The folder button opens the system file chooser (XDG portal, runs out-of-process)
- The preview updates live; Save applies instantly
- An empty field reverts to the app's default
.desktopicon
Overrides persist in icon-overrides.json and survive re-pins and restarts. All icons resolve through a theme-independent file index first, so oMenu renders correctly even when the system icon theme setting is missing or broken.
State
Everything oMenu owns lives in ~/.local/state/omarchy/iaeluk.omenu/:
| File | Purpose |
|---|---|
pins.json |
Pinned apps (written by the pin CLI, watched by oMenu) |
order.json |
Drag order (includes the launcher button's slot) |
hidden.json |
Config apps removed from oMenu |
settings.json |
Settings panel values |
icon-overrides.json |
Per-app icon overrides |
Delete the folder for a factory reset.
Pin from the command line
bin/iaeluk-omenu-pin <desktop-id> Pin an app
bin/iaeluk-omenu-pin --unpin <id|name> Unpin an app
bin/iaeluk-omenu-pin --pin-window <class> Pin a running window's app
bin/iaeluk-omenu-pin --toggle <id> Pin if absent, unpin if present
bin/iaeluk-omenu-pin --list List pinned apps
bin/iaeluk-omenu-pin --help Everything it can do
Pins land in state/pins.json; oMenu watches the file, so icons appear instantly.
IPC
qs -p /usr/share/omarchy/shell ipc call iaeluk.omenu toggleLauncher
qs -p /usr/share/omarchy/shell ipc call iaeluk.omenu isOpen
Requirements
- Omarchy (Hyprland 0.56+, Quickshell)
jq(for the pin CLI)
Troubleshooting
- Blank icons — your active icon theme may be missing or broken (
gsettings get org.gnome.desktop.interface icon-themevs what's in/usr/share/icons/). oMenu's built-in file index usually renders everything anyway; fixing the theme setting helps the rest of your desktop. - Super key already bound — if another binding claims bare Super, unbind it first (
hl.unbind(...)inbindings.lua). - Two oMenu instances running — the plugin owns the
iaeluk-omenulayer namespace; make sure only one copy is installed.
Project structure
├── Omenu.qml entrypoint, one OmenuPanel per screen
├── OmenuPanel.qml dock UI, launcher, menus, settings, icon dialog
├── manifest.json Omarchy plugin manifest (id: iaeluk.omenu)
├── bin/
│ ├── iaeluk-omenu-pin pin/unpin CLI (sole writer of pin state)
│ └── icon-picker/ one-shot file chooser (out-of-process)
└── config/
├── OmenuApps.qml default app list
├── UserConfig.qml your personal config (gitignored)
└── UserConfig.example.qml