← Otto User GuideTop Bar
otto-bar is Otto’s menu bar: a full-width panel along the top edge of the
primary monitor, with frosted-glass blur, rounded bottom corners and a soft
shadow.

Starting it
It is a separate program, not part of the compositor. Start it from your config:
[[exec_once]]
cmd = "otto-bar"
See Autostart for other ways to launch it.
Layout
┌──────────────────────────────────────────────────────────────────────┐
│ Firefox File Edit View Help (island) 🔊 🔋 Mar 23, 21:16│
└──────────────────────────────────────────────────────────────────────┘
← left zone ────────────────► centre ← right zone ───────►
- Left. The focused application’s name in bold, then its global menu.
- Centre. Deliberately empty, leaving room for the Dynamic Island.
- Right. System tray icons, then the keyboard layout, then the battery, then the clock.
The bar reserves its own height as an exclusive zone, so maximized windows and other panels stop below it rather than sliding underneath.
Global application menus
The left zone shows the focused window’s menu (File, Edit, View and so on),
sourced over D-Bus using the com.canonical.dbusmenu protocol. This is the same
mechanism Unity and KDE’s global menu use.
| Action | Effect |
|---|---|
| Click a top-level title | Drop the menu down |
↑ / ↓ | Move through items |
→ / Enter on a submenu | Open it |
← | Back to the parent menu |
Enter | Activate the highlighted item |
Escape | Close |
Hovering a submenu opens it after a short delay (about 300 ms) rather than instantly, so passing over an item on the way somewhere else does not fire it. Exactly one item is highlighted anywhere in the menu tree at a time.
Menu items support labels, icons, keyboard-shortcut hints, separators, checkboxes, radio groups and arbitrarily nested submenus. Disabled items are dimmed and inert.
Click the application’s name for Otto’s own menu for it: Minimise puts the window away in the dock, and Quit ‹App› closes all of the application’s windows, as Quit in the dock does. It is there whether or not the application has menus of its own.
Prefer menus in the window? Turn off Settings ▸ Top bar ▸ Show application
menus, or set show_app_menu = false under [topbar] in
~/.config/otto/config.toml. The bar then shows just the application’s name,
and applications you open afterwards keep their menu bar in their own window.
One already running may need restarting before its menu comes back.
Getting an app to export its menu
Not every application exports a DBusMenu. When one does not, the left zone shows just the application’s name and the app keeps drawing its own menu bar in its window.
- Qt and KDE apps. Run them with KDE’s platform theme
(
plasma-integration,QT_QPA_PLATFORMTHEME=kde). On Wayland they then tell Otto where their menu is, and the bar shows it. Other themes, such asqt5ct, keep the menu in the window. - GTK apps running under XWayland. These export through
appmenu-gtk-module: install it and start the app withGTK_MODULES=appmenu-gtk-moduleandGDK_BACKEND=x11. - GTK apps on Wayland. These do not export a DBusMenu at all; the menu stays in the window.
- Electron and browsers. These mostly do not export menus.
The application name shown comes from the window’s app_id mapped through the
desktop entry database.
System tray
The right zone implements StatusNotifierHost, the modern tray standard
(org.kde.StatusNotifierItem). Any app that registers an SNI icon appears here:
Nextcloud, Telegram, Slack, Steam, KeePassXC, network and volume applets.
| Click | Effect |
|---|---|
| Left | Open the icon’s context menu |
| Right | Activate; usually raises the app’s window |
| Middle | Secondary activate (app-defined) |
Icons are ordered by registration time, newest to the left.
Menus stay current while they are open. When an applet changes its menu (a Wi-Fi scan finding a network, Bluetooth connecting a device), the bar fetches the new one and updates the menu in place, keeping your place in it. If the menu has grown or shrunk it is shown again at its new size, in the same spot.
Legacy XEmbed tray icons (the old X11 system tray) are not supported; that standard has no Wayland equivalent. Apps that only do XEmbed will not appear.
Battery
On a machine with a battery, the bar draws one: an outline that fills with the charge, green until 20%, amber to 10%, red below that. A bolt over it means it is charging; a plug means it is plugged in but not charging, because it is full or held at a charge limit. The percentage is written inside the glyph. The menu says the same in words, with how long until full when UPower has worked it out.
The bar reads UPower itself rather than hosting a tray applet for this. The tray carries an icon and a tooltip, so a percentage published through it would be a percentage nobody can see without hovering.
Clicking it opens the power menu: what the battery is doing, what the CPU is doing, and the power profiles that can be selected.
┌──────────────────────────────────┐
│ Battery 87% — 2:14 remaining │
│ CPU 1.10 GHz average, 3.79 peak │
│ Governor: powersave │
├──────────────────────────────────┤
│ ✓ Power Saver │
│ Balanced │
│ Performance │
├──────────────────────────────────┤
│ Power Settings… │
└──────────────────────────────────┘
Where the profiles come from
The first of these that applies:
[[battery.profiles]]entries from the config file, each a command. When you have written any, they are used even if power-profiles-daemon is running: they are a statement about this machine. They are what to use when something else manages the CPU —auto-cpufreqand power-profiles-daemon conflict, and installing one masks the other. Setprofile_backend = "power-profiles"to prefer the daemon anyway.- power-profiles-daemon, under either of its D-Bus names. This is the usual case. Selecting a profile sets it, and polkit handles the permission.
- Nothing. The menu still lists the kernel’s governors and ticks the live one, greyed out, so it says what the CPU is set to even when it cannot change it.
The CPU numbers are read when the menu opens, not on a timer: scaling_cur_freq
moves faster than anything could usefully display. Everything else follows
along while the menu is open: select a profile and the tick moves once the
switch lands, without reopening.
Settings
# ~/.config/otto/otto-bar.toml
[battery]
show = "auto" # "auto" | true | false
colored = true # false draws the fill in the bar's text colour
percentage = "inside" # "inside" | "beside" | "off"
low_level = 20
critical_level = 10
width = 28
height = 13
# Colours are "#RGB", "#RRGGBB" or "#RRGGBBAA", alpha last as in CSS:
# "#34C75980" is the green at half opacity.
# Up to 1.6.0 eight digits meant "#AARRGGBB": move the alpha pair to the
# end ("#FF34C759" becomes "#34C759FF"), or it reads as another colour.
color_normal = "#34C759"
color_low = "#FF9F0A"
color_critical = "#FF3B30"
color_charging = "#34C759"
update_interval = 10 # seconds
menu = true
show_battery_info = true
show_cpu_info = true
settings_command = "otto-settings"
# Only needed when power-profiles-daemon is not running. `governor` and `epp`
# are optional: they say when the entry is the live one, and an entry that
# states neither is never check-marked.
[[battery.profiles]]
label = "Power Saver"
command = ["pkexec", "cpupower", "frequency-set", "-g", "powersave"]
governor = "powersave"
[[battery.profiles]]
label = "Performance"
command = ["pkexec", "cpupower", "frequency-set", "-g", "performance"]
governor = "performance"
Keyboard layout
With more than one keyboard layout, the bar can show which one is active: a small keycap with the layout’s short name, such as US or IT. It is off by default; turn it on in Settings → Keyboard → Input source → Show in the bar. The switch is only there once a second layout has been added.
Click the keycap for a menu of your layouts, with the active one ticked. Picking one switches to it. Keyboard Settings… at the bottom opens the keyboard settings. The keycap follows every switch, including one made with the layout switch keys.
Clock
The clock is on the far right. Settings ▸ Top bar ▸ Clock turns it on or off and picks its format from a list, each entry showing the current time the way the bar will write it. Both apply at once. With the clock off, the battery and tray move up to the edge.
The same two settings live in Otto’s configuration file, where any chrono strftime format works:
# ~/.config/otto/config.toml
[topbar]
show_clock = true
clock_format = "%a %-d %b %H:%M"
An empty clock_format (the default) falls back to clock_format in the
bar’s own file, and then to your language’s usual format:
# ~/.config/otto/otto-bar.toml
clock_format = "%B %-d, %A %H:%M"
That one renders as March 23, Thursday 21:16. Some other useful formats:
| Format | Renders as |
|---|---|
"%H:%M" | 21:16 |
"%a %d %b %H:%M" | Thu 23 Mar 21:16 |
"%I:%M %p" | 09:16 PM |
"%Y-%m-%d %H:%M:%S" | 2026-03-23 21:16:04 |
New versions
When a newer Otto has been released, the Otto menu (the two dots at the far left) gains New Version Available… at the top, which opens the release page in your browser. There is no notification, and nothing else in the bar changes.
The bar checks a minute after it starts and every six hours after. What it sends is described in Privacy. To turn the check off:
# ~/.config/otto/otto-bar.toml
update_check_url = ""
Configuration
otto-bar has its own config file. The first one that exists and parses is
used — there is no merging, so a system file shadows a user one:
/etc/otto/otto-bar.toml~/.config/otto/otto-bar.toml./otto-bar.toml(development override in the working directory)
clock_format, update_check_url and the [battery] section are the options. Bar height, colours
and blur follow the compositor’s theme.
Theming
The bar follows the system light/dark setting, read from the XDG Settings portal
(org.freedesktop.appearance color-scheme). Change theme_scheme in your Otto
config and the bar re-colours within about a second, no restart needed. See
Theming.
Multi-monitor
The bar appears on the primary monitor only. A reduced clock-and-tray bar for secondary monitors is designed but not implemented.
Troubleshooting
The bar does not appear. Check it is running (pgrep otto-bar) and that it
found the Wayland socket. Run it by hand from a terminal inside the session to
see errors.
No menus for any app. DBusMenu is opt-in per toolkit. See Getting an app to export its menu above.
A tray icon is missing. It is probably XEmbed-only. Check whether the app has an SNI or “AppIndicator” option.
The clock format is ignored. A malformed strftime string falls back to the
next format in line: the bar’s own file, then your language’s. In
otto-bar.toml the key sits at the top level, not in a table; in Otto’s
configuration it goes under [topbar].