You are not logged in.

#1 2020-02-26 23:48:32

Registered: 2015-08-20
Posts: 6,720

Basic Introduction to jgmenu on BL Lithium

Part 1 - Basic Introduction

A very basic introduction to jgmenu, and Creating a new menu

A simple, independent and contemporary-looking X11 menu, designed for scripting, ricing and tweaking.

It is hackable and has a simple code base. It does not depend on any toolkits such as GTK and Qt, but uses cairo and pango to render the menu.

It can optionally use some appearance settings from XSettings, tint2 and GTK.

It can display the following types of menu (or any combination of):

    bespoke menu using a jgmenu flavoured CSV format
    application menu (XDG compatible) with localisation support
    pipe menus
    openbox XML menu including openbox pipe-menus

It has UTF-8 search support.

It is packaged for Bunsenlabs, but the sourcecode can be found here:


Tutorials and manpages

The manpages are some of the best you will see, and have pretty much everything you need.
Kudos to @malm smile

The main ones needed are:

man jgmenu
man jgmenututorial

A full list of Tutorials can also read here:


Simple static menu

The elementary structure is comma-separated, and can be piped into jgmenu, via a command, heredoc, or from file. Each entry consists of one or more of:

    Description,command,icon,working directory,metadata

Heredoc syntax and use is covered in man jgmenututorial, so I will concentrate on using a csv file here, with jgmenu --simple to read menu items from stdin.

Create mymenu.csv, containing

Web Browser,x-www-browser
File Manager,bl-file-manager
Text Editor,bl-text-editor
Media Player,bl-media-player

Show the menu in the centre of the desktop with:

cat mymenu.csv | jgmenu --simple --center


Notice that "Menu" doesn't run a command when clicked, but the items do.

You can have some fun with icons as well, by using the third field. Either set the size in the config file (see later) or use --icon-size=<size> in the command. Try changing the first item in mymenu.csv to


and run it with

cat mymenu.csv | jgmenu --simple --center --icon-size=16

Now it looks like uhcsMphm.jpg

Sub Menus

To build submenus we use mainly ^sep, ^checkout and ^tag markup syntax.

  • sep()  Define a separator. If an inner value is provided, the separator will appear as a title. If no inner value is provided, the separator will simply be a horizontal line.

  • ^tag() Define the beginning of a new menu structure node.

  • ^checkout() Open the tag specified by the inner value as a submenu in a new window.

Edit mymenu.csv to look like:

Terminal Emulators,^checkout(terminal)
Text Editors,^checkout(editors)




Part 2 - A dynamic menu

You can feed the output of a pipemenu directly to jgmenu. This example parses an example .xbindkeysrc, and sends the run commands keybinds to be displayed by jgmenu:

## xkb-pipemenu

declare -a KB_ARR
declare -a CMD_ARR

echo "^sep(Keybinds for running commands)"
echo "Run commands,^checkout(run_commands)"
echo "^tag(run_commands)"

while read -r line;do
    if [[ -n $line ]];then              # line isn't empty
        if [[ ${line} = \#* ]];then     # skip lines starting with '#'
        elif [[ ${line} = \"* ]];then
            CMD=$(echo "${line}" | sed -e 's/"//g') # remove double-quotes
        else                                        # swap 'Mod4' for 'Super'
            KB=$(echo "${line}" | sed -e 's/Mod4/Super/' -e 's/ //g')
done < "${KBINDS}"

for c in "${KB_ARR[@]}";do
    curr_item=$(printf "%-18s %s" "${KB_ARR[$i]}" "${CMD_ARR[$i]}")
    echo "${curr_item}"

Run it with:

xkb-pipemenu | jgmenu --simple
jgmenu --simple --csv-cmd=xkb-pipemenu


Let's add it to mymenu, using the ^pipe() syntax:
First, comment out these lines in xkb-pipemenu

#echo "Run commands,^checkout(run_commands)"
#echo "^tag(run_commands)"

And add these lines to your menu, before the "^tags" sections:



Try adding those lines to ~/.config/jgmenu/prepend.csv, to show in the main menu wink

This now looks like hCYUklom.jpg


Part 3 -Bunsenlabs helper functions for scripting menus

BL helpfully provides some functions which can be sourced by scripts. These include some shorthand for jgmenu code, and can be utilised by adding this to any script that sends output to jgmenu:

BL_COMMON_LIBDIR="/usr/lib/bunsen/common"   # source jgmenu helper functions

if ! . "$BL_COMMON_LIBDIR/bl-include.cfg" 2> /dev/null; then
    echo $"Error: Failed to locate bl-include.cfg in $BL_COMMON_LIBDIR" >&2
    exit 1

/usr/lib/bunsen/common/bl-include.cfg has...

# Put an item in the root menu or any submenu.
# Usage: jgmenuItem tag label command
# Tag 'root' indicates root menu item.

# Add a separator.
# Usage: jgmenuSeparator tag [label]

# Put a checkout() for a submenu in the root menu or any submenu.
# Usage jgmenuSubmenu tag(parentmenu) tag(submenu) label

# Print root menu, then submenus.
# jgmenuEnd

So, my-pipemenu might look like this:

## my-pipemenu

BL_COMMON_LIBDIR="/usr/lib/bunsen/common"   # source jgmenu helper functions

if ! . "$BL_COMMON_LIBDIR/bl-include.cfg" 2> /dev/null; then
    echo $"Error: Failed to locate bl-include.cfg in $BL_COMMON_LIBDIR" >&2
    exit 1

jgmenuSeparator 'root' "Main Menu"
jgmenuSubmenu 'root' "terminal" "Terminal Emulators"
jgmenuSubmenu 'root' "editor" "Text Editors"
jgmenuSeparator 'root' "Keybinds"
jgmenuItem 'root' "Run commands" "^pipe(xkb-pipemenu)"

jgmenuItem "terminal" "x-terminal-emulator" "x-terminal-emulator"
jgmenuItem "terminal" "Terminator" "terminator"
jgmenuItem "terminal" "lxterminal" "lxterminal"

jgmenuItem "editor" "Geany" "geany"
jgmenuItem "editor" "Medit" "medit"
jgmenuItem "editor" "Gedit" "gedit"


This is the equivalent of directing the following textfile to jgmenu.
(See Part 4 - jgmenu Configs later)

^sep(Main Menu)
Terminal Emulators,^checkout(terminal)
Text Editors,^checkout(editor)
Run commands,^pipe(xkb-pipemenu)



Run it with the command...

jgmenu --simple --csv-cmd=xkb-pipemenu

One big advantage of using this approach is that I find it makes it easier to use variables in the script. See the first script in Part 5 for an example of a dynamic menu using variables, as well as the dynamic menu in Part 2 earlier.


Part 4 - jgmenu Configs

The main menu settings are in ~/.config/jgmenu/jgmenurc, and any jgmenu will use it by default unless othewise specified. This means that you can set a different font or colours, for example, either in jgmenurc, or have a specific rc file for your menu.

For our menu, we can copy jgmenurc and call it eg my-jgmenurc
Let's change the font, separator colour and position for our bespoke menu:

#position_mode       = center
position_mode       = pointer
#font                = Sans 10
font                = Monospace 10
#color_title_fg = #d3dae3 100
color_title_fg = #cc666a 100

Run this with

my-pipemenu | jgmenu --simple --config-file='~/.config/jgmenu/my-jgmenurc'


jgmenu csv files

jgmenu can populate a menu from a csv file:

jgmenu --simple --csv-file='/path/to/csv-file.csv'

So you can run the main menu with:

jgmenu --simple --csv-file='~/.config/jgmenu/prepend.csv'

(The jgmenu_run command does all that automatically of course wink )

Converting the pipemenu output to a csv file

The pipemenu output contains a bunch of '"""' characters to be parsed by jgmenu, but they can be got rid of with a sed command. Redirect the script output to a csv file using:

my-pipemenu | sed  's/"""//g' > ~/.config/jgmenu/mymenu.csv

Now the personalised menu can be run using the --csv-file= script arg:

jgmenu --simple --csv-file='~/.config/jgmenu/mymenu.csv' \ --config-file='~/.config/jgmenu/my-jgmenurc'

Sourcing csv files
Existing csv files containing all the necessary markup can be sourced by a menu. This avoids code duplication, and means that any future edits will apply anywhere that the markup is used.

The main menu displays markup from prepend.csv, which contains the line

. /usr/share/bunsen/configs/menu-includes/help-menu

If you open that file you see all the code which is displayed in the main menu called by ^checkout(bl-help-menu), ie everything that would be shown under '^tag(bl-help-menu)'.

NB A .csv filename ending isn't strictly necessary, but helps human eyes to keep track of things wink

A note about indenting and layout

  • Position:
    The submenu ^tag(name) sections can be in any order, as long as they follow the higher menu ^checkout()'s. They will be displayed in the order of ^checkout(), not their order in the file.

    Empty lines are also allowed, as are commented lines. A '#' must be the first character on a commented line.

  • Indenting:
    The csv generators and helper commands output csv like this:

    ^sep(Terminal commands)

    However, jgmenu can cope with indenting to improve readability. Whitespace at left/right of all fields is removed, which allows CSV data to be indented or aligned without affecting the content.
    For example, indented and commented as I prefer, keeping each section together:

    ### TERMINALS submenu ##################################################
        ^sep(Terminal commands)
    ### END TERMINALS ######################################################

    And even this works smile

        ^sep(Terminal commands)
            Default,        x-terminal-emulator
            Terminator,     terminator
            lxterminal,     lxterminal
Editing the Main menu

The menu csv file used by jgmenu is ~/.config/jgmenu/prepend.csv. This is also accessible from Menu -> Preferences -> jgmenu -> Edit Menu Content.

Let's say you like tweaking Conky, Tint2 and various Openbox settings, and would like to quickly refresh after editing a config. You could add often-used commands directly to the main menu as follows:

  • Add this line where you want it to appear:

  • Add this section in the '^tags' area of prepend.csv.

    Openbox,openbox --reconfigure


  • Perhaps you want a favorite app to appear at the top of your Applications submenu, or you have something that doesn't have a .desktop file, so it doesn't show up in the list. Add the command to the lx-apps tag:




Part 5 - Example menus in use
  • Scripts, Tutorials & Tips > jgmenu for bash_aliases
    The script parses your .bash_aliases, and outputs each section into a submenu. It can be run from a Tint2 executor or button.

  • Screenshots menu, attached to PrintScreen key

    In .xbindkeysrc, add:

    # Screenshots menu
    "jgmenu --simple --csv-file='.config/jgmenu/scrots.csv'"
    Screenshots directory,^pipe(jgmenu_run ob --cmd="bl-places-pipemenu ~/Pictures/screenshots")
    scrot Now,scrot ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png -e 'bl-image-viewer ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png'
    scrot In 5 secs...,scrot -d 5 ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png -e 'bl-image-viewer ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png'
    scrot In 10 secs...,scrot -d 10 ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png -e 'bl-image-viewer ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png'
    scrot Select Area,scrot -s ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png -e 'bl-image-viewer ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png'
    scrot Current Focus,scrot -u ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png -e 'bl-image-viewer ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png'
    scrot Multi-Monitor,scrot -m ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png -e 'bl-image-viewer ~/Pictures/screenshots/%F-%H-%M-%S_scrot.png'


Last edited by damo (2020-02-29 11:26:49)

Be Excellent to Each Other...
The Bunsenlabs Lithium Desktop » Here
FORUM RULES and posting guidelines «» Help page for forum post formatting
Artwork on DeviantArt  «» BunsenLabs on DeviantArt


Board footer

Powered by FluxBB