← Otto Developer Guideotto-bar

User guide: Top Bar
Specs: Top Bar

otto-bar is the strip along the top of the screen: the Otto menu and the focused app’s menus on the left, and the tray, the keyboard layout, the battery and the clock on the right. It lives in components/otto-bar/ and sits in the app layer of architecture.toml, so nothing links it. It runs as its own process, an otto-kit app started by the compositor from an exec_once entry in the shipped config. On the session bus it is both a client of the compositor and the host other apps register their tray icons and menus with.

otto-bar: three layer surfaces on the compositor, watchers on tokio tasks, the tray and app-menu registries it serves

Modules

ModuleWhat it does
main.rsStarts logging, picks the language from the desktop, starts the update check and hands TopBarApp to otto-kit’s AppRunner on a two-worker tokio runtime.
app.rsThe app: creates the surfaces, opens and closes every menu, handles pointer and keyboard input, builds the accessibility tree, and picks up changes from the watchers in on_update.
bar.rsDraws the left panel (Otto mark, app name, menus) and the right panel (tray, layout, battery, clock), packed right to left.
appmenu.rsThe global menu: follows the focused window and serves com.canonical.AppMenu.Registrar.
dbusmenu.rsClient for com.canonical.dbusmenu, used by app menus and tray menus.
tray.rsServes org.kde.StatusNotifierWatcher and follows each registered StatusNotifierItem.
keyboard_layout.rsThe layout indicator and its menu, from GetInputs and InputChanged on org.otto.Shell1.
power.rs, battery.rsBattery state from UPower (sysfs when UPower is absent), CPU frequency and governor from sysfs, power profiles; battery.rs draws the glyph.
clock.rsThe clock, following topbar.show_clock and topbar.clock_format.
logout.rsAsks through org.otto.Dialog1, then sends the compositor its logout command.
update.rsAsks a version endpoint whether a newer release is out, and adds an entry to the Otto menu when it is.
config.rs, settings.rsRead otto-bar.toml; share the value handling for org.otto.Settings.

How it runs

Surfaces. Three wlr-layer-shell surfaces on the top layer. A one-pixel spacer spans the whole top edge and only reserves the exclusive zone that pushes maximised windows down. The left and right panels are corner-anchored and reserve nothing; their material and size animation go through the surface style protocol. Every menu is an xdg_popup on one of the panels, built with otto-kit’s ContextMenu. While a menu is open the panel takes the keyboard exclusively, so the menu can be driven with the arrow keys.

Threads. Drawing and input run on the otto-kit app thread. Each source of state (tray, app menu, power, keyboard layout, clock settings, update check) is a tokio task that writes into a shared static behind a mutex, bumps a generation counter and wakes the app thread. on_update compares the counters and redraws or refreshes an open menu only when one moved. A separate Wayland connection from otto-kit’s focus watcher binds zwlr_foreign_toplevel_manager_v1 for the focused app’s name.

The global menu. appmenu.rs takes the focused window from org.otto.Shell1 (GetTree at start, then WindowChanged) and finds its menu one of three ways: the otto_appmenu entry the compositor records for Wayland Qt apps that speak org_kde_kwin_appmenu, the X11 window id registered with the registrar the bar serves (GTK through appmenu-gtk-module, Qt on xcb), or the process id behind a registration. With topbar.show_app_menu off the bar releases the registrar name, so apps keep their menus in their own windows.

Names it owns. org.kde.StatusNotifierWatcher and com.canonical.AppMenu.Registrar, both requested without allowing replacement. A second bar on the same bus gets neither.

Names it calls.

Files. otto-bar.toml from /etc/otto/, ~/.config/otto/ and the working directory, for the battery and the clock fallback (see the README). The update check keeps its counting state in $XDG_STATE_HOME/otto/update-check.

Dependencies

otto-kit for the runner, surfaces, menus, typography, theme, i18n and the org.otto.* proxies it re-exports from otto-dbus. zbus on tokio for the bus, ureq for the update check, chrono for the clock. The colour scheme reaches it through otto-kit, and the panels repaint in on_theme_changed (see Color Scheme). Both panels publish an accessible tree through otto-kit once an assistive technology attaches (see Accessibility).

Going deeper