labwc-menu(5)

πŸ’– labwc-menu(5) β€” the menu file, explained bestie to bestie πŸ’–

okay so this is the manual page for labwc-menu, aka the file formats manual for labwc menus. grab a snack, we're learning how menus work πŸ“


✨ NAME ✨

labwc β€” the menu file. yeah, that's it, that's the name. short and iconic πŸ’…


πŸ¦‹ DESCRIPTION πŸ¦‹

Static menus are built based on the menu.xml file, which lives at "~/.config/labwc" and in the equivalent XDG Base Directories. that's the whole vibe β€” you write XML, labwc gives you a menu. no cap ✨


πŸŽ€ SYNTAX πŸŽ€

first things first: the menu file must be entirely enclosed within <openbox_menu> and </openbox_menu> tags. like, the whole thing. do not skip this, bestie, it's not optional πŸ™ˆ

inside those tags, menus are specified as follows:

<!-- A toplevel menu -->
<menu id="external_menu_settings" label="External Settings" icon="preferences-other">
  <item label="Display setting">
    <action name="Execute" command="wdisplays" />
  </item>
</menu>

<!-- Another toplevel menu -->
<menu id="">

  <!-- A menu entry with an action, for example to execute an application -->
  <item label="" icon="">
    <action></action>
  </item>

  <!-- A submenu defined elsewhere, uses external label and icon attributes -->
  <menu id="external_menu_settings" />

  <!-- Horizontal line -->
  <separator />

  <!-- An inline submenu -->
  <menu id="" label="" icon="">
    ...some content...
  </menu>

  <!-- Title -->
  <separator label="" />

  <!-- Pipemenu -->
  <menu id="" label="" icon="" execute="COMMAND" />

</menu>

okay now let's break down every single attribute because we don't skip anything in this house πŸ‘‘

Defines a menu tree. each menu must be given an id, which is a unique identifier of the menu. this id is how you refer to the menu in a ShowMenu action. the default identifiers are lowkey important, so:

  • "root-menu" β€” for the root window context menu πŸ‘‘
  • "client-menu" β€” for a window's titlebar context menu
  • "client-list-combined-menu" β€” for a list of all windows across all workspaces. will change focus to the app that gets selected, or go to a workspace without activating any app if "Go there" is selected.
  • "client-send-to-menu" β€” shows all workspaces and sends the current window to that workspace when selected.

this one is a link to a submenu defined elsewhere (by a <menu id=""> at toplevel). so instead of copy-pasting your whole submenu, you just point at it. slay πŸ’…

The title of the menu, shown in its parent. a label must be given when defining a menu unless it is the topmost menu element.

little note: Openbox requires a label="" defined for topmost elements too, but for simplicity labwc handles these with or without the label attribute. so you're covered either way 🫢

An icon to be rendered, shown in its parent. this argument is optional. see menu.item.icon for further details. ⭐

The visible name of the menu item. that's the text your eyeballs see. simple as πŸŽ€

The name of an icon to be rendered in front of the menu entry. this attribute is optional. the name follows naming conventions of "Icon=" entries in .desktop files.

if you use it, it is recommended to use the name of the icon only rather than a full path. why? because this ensures the icon will be looked up in the scale of the output where the menu is rendered. so like, icon="vlc" is suggested over using icon="/usr/share/icons/hicolor/16x16/apps/vlc.png". trust, the short version is the moment ✨

See labwc-actions(5).

note: XML CDATA is supported for this node in order to maintain compatibility with obmenu-generator. iykyk 😌

Horizontal line. that's it. that's the whole thing. aesthetic divider energy πŸŽ€

In a "separator" element, the label attribute transforms the separator from a horizontal line to a menu title (heading) with the text specified by label in it. so it's giving line β†’ glow-up β†’ heading πŸ’…

Command to execute for pipe menu. see details below πŸ‘‡


🌈 PIPE MENUS 🌈

Pipe menus are menus generated dynamically based on the output of scripts or binaries. they're so-called because the output of the executable is piped to the labwc menu. literally the name is the explanation, love that for us 🫢

For any <menu id="" label="" execute="COMMAND" /> entry in menu.xml, the COMMAND will be executed the first time the item is selected (for example by cursor or keyboard input). the XML output of the command will be parsed and shown as a submenu. the content of pipemenus is cached until the whole menu (not just the pipemenu) is closed. πŸ”₯

The content of the output must be entirely enclosed within <openbox_pipe_menu> tags. inside these, menus are specified in the same way as static (normal) menus, for example:

<openbox_pipe_menu>
  <item label="Terminal">
    <action name="Execute" command="xterm" />
  </item>
</openbox_pipe_menu>

Inline submenus and nested pipemenus are supported. icon behavior, we love to see it πŸ‘‘

important: it is the responsibility of the pipemenu executable to ensure that ID attributes are unique. duplicates are ignored. that's on you, bestie, not on labwc πŸ’€

When writing pipe menu scripts, make sure to escape XML special characters such as "&" (&amp;), "<" (&lt;), and ">" (&gt;). do not skip this or your menu will simply not parse and you will be sad 😭

A pipemenu can also be used to define the toplevel <menu> element. in this case the entire menu.xml file would be reduced to something like this (replacing obmenu-generator with the menu generator of your choice):

<?xml version="1.0"?>
<openbox_menu>
  <menu id="root-menu" label="" execute="obmenu-generator" />
</openbox_menu>

one file, one line of menu, whole tree generated dynamically. main character energy fr fr ⭐


πŸ’œ ACCELERATORS / MNEMONICS πŸ’œ

Menu accelerators are one-letter mnemonics to quickly select/exec items from the current menu. keyboard girlies stay winning ⌨️

For each menu item, the accelerator is defined as the first character of the item label, converted to lowercase. A different accelerator can be explicitly defined in menu.xml with the special '_' character before the target letter. Accelerators can be any unicode character and are not limited to ASCII. A usual underscore can be shown by duplicating it. 🌸

If the menu only contains a single instance of the pressed accelerator the item will be executed directly. Otherwise, all matching items are cycled through. so no ambiguity, no drama πŸ’…

Example: the accelerator for an item with the label "e_Macs" is 'm'.


🧚 LOCALISATION 🧚

Available localisation for the default "client-menu" is only shown if no "client-menu" is present in menu.xml. Any menu definition in menu.xml is interpreted as a user-override. so if you wrote your own, yours wins, periodt πŸ‘‘


πŸ¦‹ SEE ALSO πŸ¦‹

go read those too, bestie, they're all part of the same aesthetic ✨


okay that's the whole page!! this was labwc-menu(5), dated 2026-08-22, and it ate, no crumbs πŸ’…πŸ«Ά go build a menu that's as cute as you are πŸ’–

πŸ“¦ where this page comes from