Build an Openbox Application Menu with obamenu
By the end, Openbox will have an Applications menu generated from the .desktop files installed on your system. You will keep the generator in your home directory, add it to menu.xml, and know where to look when an application or icon is missing.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 15 minutes for a first setup. You need a working Openbox session, a text editor, and permission to read the application directories. The examples below do not require elevated privileges. Only the optional system-wide installation step uses sudo.
Checkpoint 1: confirm the installed behaviour
The installed package on the machine used for this guide is Ubuntu's openbox 3.6.1-12build5, and its obamenu script identifies itself as version 1.1.7. Check your own package before relying on these defaults:
dpkg-query -W -f='${Package} ${Version}\n' openbox
command -v obamenu
head -n 8 "$(command -v obamenu)"
obamenu has no command-line options or parameters. Running it prints an Openbox pipe-menu document on standard output:
obamenu | sed -n '1,12p'
On this installation the output begins with an XML declaration and an <openbox_pipe_menu> root element, followed by menus such as Development, Graphics, Internet, System and Utilities when matching applications are installed. Empty categories are omitted. Your list will differ because it is built from the .desktop files present on your system.
Checkpoint 2: make a user-owned copy
The configuration is a short section inside the Python script, not a separate configuration file. Do not edit /usr/bin/obamenu in place unless you deliberately want a package-managed file changed. A package upgrade can replace it. Keep a reversible, user-owned copy instead:
mkdir -p "$HOME/bin"
install -m 755 "$(command -v obamenu)" "$HOME/bin/obamenu"
cp "$HOME/bin/obamenu" "$HOME/bin/obamenu.bak"
editor "$HOME/bin/obamenu"
If the copy does not work, undo it with rm "$HOME/bin/obamenu" and use the packaged command again. That removes only the copy you created; it does not touch the system script.
At the top of the copy, the user configuration includes settings like these. Adjust values to suit your machine rather than copying the sample terminal name blindly:
applications_dirs = ("/usr/share/applications", )
image_dir_base = "/usr/share"
icon_Theme = "Humanity"
image_cat_prefix = "applications-"
application_groups = ("Office", "Development", "Graphics", "Internet",
"Games", "System", "Multimedia", "Utilities", "Settings")
group_aliases = {"Audio":"Multimedia", "AudioVideo":"Multimedia",
"Network":"Internet", "Game":"Games", "Utility":"Utilities",
"GTK":"", "GNOME":""}
ignoreList = ("evince-previewer", "feh")
terminal_string = "x-terminal-emulator -e"
simpleOBheader = False
applications_dirs is a tuple of directories containing desktop files. Add a second directory with a trailing comma, for example ("/usr/share/applications", "/opt/example/share/applications", ). The script only scans the directory entries it is given; it does not recursively search every subdirectory.
application_groups controls both which categories are accepted and their order. A category not in this tuple produces no menu entry. group_aliases maps category names found in desktop files to your chosen groups. Mapping a category to an empty string hides it. This is useful for noisy categories, but a careless alias can make an application appear to vanish.
ignoreList contains desktop file names without the .desktop suffix. The shipped script checks whether each ignored name occurs in the desktop file path, so use a distinctive name. terminal_string is prepended when a desktop file declares Terminal=true. It must be a command that accepts the application command after its terminal option.
Icons are a separate concern. Application icon names are looked up below /usr/share/pixmaps, while category icons are looked up below /usr/share/icons/<theme>/categories/24/. If a desktop file names an icon that is stored elsewhere, the menu entry can still work but show no icon. The manpage recommends placing a symbolic link in the pixmaps directory rather than making the generator search an entire icon tree. Creating links there requires sudo and changes system state, so verify the target first:
find /usr/share/icons -name 'example.*' -print
ls -l /usr/share/pixmaps/example.*
Do not create a link until you have identified the exact target. If you later need to undo one, remove only the link you created, for example sudo rm /usr/share/pixmaps/example.svg. Never use that command against a regular icon file.
Checkpoint 3: test the customised generator
Save the script, then run it directly. Redirecting to a temporary file makes the XML easier to inspect without changing Openbox:
"$HOME/bin/obamenu" > "$HOME/obamenu-test.xml"
head -n 3 "$HOME/obamenu-test.xml"
grep -E '^<(menu|item)\b' "$HOME/obamenu-test.xml" | head
You should see the pipe-menu root and at least one <menu> if the application directory contains usable, categorised desktop files. A completely empty result below the root usually means the selected categories do not match the desktop files, or that your extra directory is wrong. Check a real desktop file with:
sed -n '1,100p' /usr/share/applications/example.desktop
Look for Type=Application, a Categories= line matching one of your groups or aliases, and an Exec= line. obamenu removes a final desktop-file field placeholder such as %f from the command. It does not turn arbitrary shell syntax into a shell script, so keep commands simple and test unusual launchers independently.
Checkpoint 4: attach it to Openbox
Openbox reads menus from its configured menu file, normally $HOME/.config/openbox/menu.xml. Back it up before editing. This is a reversible configuration change, but a malformed XML file can leave the menu unavailable until it is restored:
mkdir -p "$HOME/.config/openbox"
cp "$HOME/.config/openbox/menu.xml" "$HOME/.config/openbox/menu.xml.bak"
editor "$HOME/.config/openbox/menu.xml"
Inside an existing <menu>, add a submenu whose execute attribute names the user-owned generator. Use an absolute path so Openbox does not depend on the session's PATH:
<menu id="desktop-app-menu"
label="Applications"
execute="/home/REPLACE_WITH_YOUR_LOGIN/bin/obamenu" />
Place that menu inside the top-level menu structure used by your current configuration. Do not paste the generator's generated XML into menu.xml; the execute attribute tells Openbox to run the command and parse its output as a pipe menu. The generated document already supplies the pipe-menu root and closing element.
Reload Openbox from its normal menu or with your existing reload shortcut. Then open Applications. If it does not appear, first run the exact command from the execute attribute in a terminal and check that it is executable:
test -x "$HOME/bin/obamenu" && echo executable
"$HOME/bin/obamenu" > /tmp/obamenu-output.xml
sed -n '1,8p' /tmp/obamenu-output.xml
For a broken menu file, restore the backup and reload Openbox:
cp "$HOME/.config/openbox/menu.xml.bak" "$HOME/.config/openbox/menu.xml"
Common traps
- Expecting flags: obamenu accepts no options. Configuration belongs in the script copy.
- Editing the wrong copy: the menu must execute the path you customised, not necessarily
/usr/bin/obamenu. - Missing categories: categories are case-sensitive strings in the script. An alias to an empty string deliberately hides an application.
- Missing icons: application icon names are not searched across the whole icon theme tree. Check
/usr/share/pixmapsand the configured category theme. - Terminal applications opening incorrectly: check
terminal_stringand the desktop file'sTerminal=true. The configured terminal command must accept the generated command. - Stale output: the menu is generated when Openbox invokes it. Re-run the generator and reload Openbox after changing the script or desktop files.
Done means
obamenuruns without options and prints an Openbox pipe-menu document.- Your menu points to an executable, user-owned copy of the generator.
- At least one expected application appears under the intended category.
- Terminal applications use the configured terminal command.
- You have backups of both the script copy and
menu.xml, with a tested restore command.