You are not logged in.

#1 2024-09-12 04:58:19

r.chaffee53
Member
Registered: 2023-08-02
Posts: 123

Basic Introduction to jgmenu on BL Boron

Part 1 - Basic Introduction

A very basic introduction to jgmenu.

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.

The included version is packaged for Bunsenlabs, and the source code 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:

___________________________________ _ ___________________________________


Creating New Menus

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

Menu
Terminal,x-terminal-emulator
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

MfM2yti.pnggaaRsRhm.png

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

Menu,,system-file-manager

and run it with

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

Now it looks like:

MfM2yti.pngrdWjpgFm.png


Add 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:

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

^tag(terminal)
Terminal,x-terminal-emulator
lxterminal,lxterminal
terminator,terminator

^tag(editors)
Geany,geany
Medit,medit
Gedit,gedit

And you get this:

MfM2yti.pngmFLRMX9m.png

___________________________________ _ ___________________________________



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:

#!/bin/bash
##
## xkb-pipemenu

KBINDS="$HOME/.xbindkeysrc"
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 '#'
            continue
        elif [[ ${line} = \"* ]];then
            CMD=$(echo "${line}" | sed -e 's/"//g') # remove double-quotes
            CMD_ARR+=("${line}")
        else                                        # swap 'Mod4' for 'Super'
            KB=$(echo "${line}" | sed -e 's/Mod4/Super/' -e 's/ //g')
            KB_ARR+=("${KB}")
        fi
    fi
done < "${KBINDS}"

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

Run it with:

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

MfM2yti.pngx8PbatXm.png

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:

^sep(Keybinds)
Keybinds,^pipe(xkb-pipemenu)

MfM2yti.pngkfX5CPsm.png

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

This now looks like:

MfM2yti.pngvIjv9F9m.png

___________________________________ _ ___________________________________



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
fi

/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:

#!/bin/bash
##
## 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
fi

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"

jgmenuEnd

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)
^sep(Keybinds)
Run commands,^pipe(xkb-pipemenu)

^tag(terminal)
x-terminal-emulator,x-terminal-emulator
Terminator,terminator
lxterminal,lxterminal

^tag(editor)
Geany,geany
Medit,medit
Gedit,gedit

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       = pointer
position_mode       = center
...
#font                = Sans 10
font                = Monospace 10
...
#color_title_fg = #f7f7f7 100
color_title_fg = #53a0b3 100

Run this with

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

MfM2yti.pngmc6B2JMm.png]

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:

    ^tag(terminal)
    ^sep(Terminal commands)
    Default,x-terminal-emulator
    Terminator,terminator
    lxterminal,lxterminal

    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 ##################################################
    ^tag(terminal)
        ^sep(Terminal commands)
        Default,x-terminal-emulator
        Terminator,terminator
        lxterminal,lxterminal
    ### END TERMINALS ######################################################

    And even this works smile

    ^tag(terminal)
        ^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:

    Reloads,^checkout(reloads)
  • Add this section in the '^tags' area of prepend.csv.

    ^tag(reloads)
    ^sep(Reloads)
    Openbox,openbox --reconfigure
    Conky,bl-conky-session
    Tint2,bl-tint2restart

    MfM2yti.pngebtjbG7m.png


  • 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:

    ^tag(lx-apps)
    My_App,~/bin/my-app

    MfM2yti.pngYE7VWe0m.png

___________________________________ _ ___________________________________


Part 5 - Example Menus

Screenshots Menu, activated by the PrintScreen Key

In .xbindkeysrc, add:

# Screenshots menu
"jgmenu --simple --csv-file='.config/jgmenu/scrots.csv'"
    Print
#scrots.csv
^sep(Screenshots)

scrot,^checkout(scrot)
xfce4-screenshooter
^sep()
Screenshots directory,^pipe(jgmenu_run ob --cmd="bl-places-pipemenu ~/Pictures/screenshots")

^tag(scrot)
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'

Comment out the xfce4-screenshotter or you will get both. I run this on my daily driver in addition to the useful options available from the Main Menu.

MfM2yti.png        6iigsWzm.png



Create a jgmenu for your .bash_aliases.

A tutorial on creating a script that parses your .bash_aliases, and outputs each section into a submenu can be found in the Scripts, Tutorials & Tips section of the forum, here. It can be run from a Tint2 executor or button.

MfM2yti.png        QmMTc1ym.jpeg


___________________________________ _ ___________________________________

This introduction is an updated version of the excellent work by @damo - here.
We all stand on the shoulders of others.

Comments can be made here.

Last edited by r.chaffee53 (2024-10-11 19:02:29)

Offline

Board footer

Powered by FluxBB