xmenu: Desktop Agnostic Menu Utility
  
  
  Introduction⌗
In the past, I have detailed some of the helper programs I use with the i3 window manager. I have a new one, something that is actually really helpful for my workflow.
So far, my workflow has been entirely keyboard driven. But that doesn’t mean I hate the mouse. I really hate switching between the keyboard and mouse. So if I am just using the
mouse to click youtube videos or play a game, why would I want to reach for the keyboard to bring up rofi?
That’s where xmenu comes in. xmenu gives you the openbox style menu that can be navigated with either the keyboard or the mouse.
Installation⌗
Since I run arch, I was able to grab the xmenu program off of the AUR with
yay -Syu xmenu
Otherwise you can clone the repository, enter it, and
make
sudo make install
I choose to build from source because it allows me to theme on the fly.
Usage⌗
The beauty of xmenu is that it works like dmenu or rofi, and takes its options from STDIN.
This means that by default, xmenu does nothing. When we want to invoke it, we would pipe in the options we want, usually through a bash script for convenience.
For example, to create the example in the above gif, simply use this script:
#!/bin/sh
cat <<EOF | xmenu | sh &
Applications
	IMG:./icons/web.png	Web Browser	firefox
	IMG:./icons/gimp.png	Image editor	gimp
Terminal (xterm)	xterm
Terminal (urxvt)	urxvt
Terminal (st)		st
Shutdown		poweroff
Reboot			reboot
EOF
Each value is separated by the TAB character. On the left is the name to be displayed, and then one tab over is the command/script to be run if that option is selected.
You can make nested menus by indenting another tab, and line breaks with empty lines. Note that nested line breaks need the appropriate number of tabs at the beginning of the line followed by nothing.
Theming⌗
If you know anything about me, it’s that I will not be happy with that lame white menu. Inside the xmenu directory, we can find a file called config.h.
This file defines all of the colors and styles used by xmenu. Changing this file requires a rebuild of xmenu.
So I created a pywal template for the config.h file.
static struct Config config = {{
	/* font */
  .font = "HackNerdFont:size=9,FontAwesome:size=9,FontAwesomeBrands:size=11",
	/* colors */
	.background_color = "{background}",
	.foreground_color = "{foreground}",
	.selbackground_color = "{background}",
	.selforeground_color = "{color2}",
	.separator_color = "{color4}",
	.border_color = "{color5}",
	/* sizes in pixels */
	.width_pixels = 130,        /* minimum width of a menu */
	.height_pixels = 25,        /* height of a single menu item */
	.border_pixels = 1,         /* menu border */
	.separator_pixels = 3,      /* space around separator */
	.gap_pixels = 0,            /* gap between menus */
	/*
	 * The variables below cannot be set by X resources.
	 * Their values must be less than .height_pixels.
	 */
	/* geometry of the right-pointing isoceles triangle for submenus */
	.triangle_width = 4,
	.triangle_height = 7,
	/* the icon size is equal to .height_pixels - .iconpadding * 2 */
	.iconpadding = 2,
	/* area around the icon, the triangle and the separator */
	.horzpadding = 10,
}};
Every time wal is run, a new file is created in ~/.cache/wal/. I symlink this file to the location xmenu, and rebuild it every time I change theme.
ln -s /home/gideon/.cache/wal/xmenu-config.h /home/gideon/Programs/xmenu/config.h
I use my own theming tool chameleon to handle themes. If chameleon detects xmenu on your system, it will attempt to rebuild it on the
fly.
Look at these colors!!
polybar integration⌗
I use i3, which doesn’t exactly have a built in mechanism for “right click desktop menu”. The author of xmenu has another tool, xclickroot which helps with this.
However, since my windows are tiled, I rarely see the desktop anyways. That is why I integrated xmenu into my polybar like a traditional start menu!
In my polybar config, I have the following module:
[module/xmenu-left]
type = custom/script
click-left = /home/gideon/dotfiles/dotfiles/scripts/xmenu-left-monitor.sh
click-right = /home/gideon/dotfiles/dotfiles/scripts/xmenu-left-monitor.sh
exec = /home/gideon/.config/polybar/scripts/xmenu-button.sh
format-foreground = ${colors.color4}
tail = true
interval = 90
I have three almost identical modules, one for each of my monitors. The reason for this is that each monitor calls a different xmenu script, which tells xmenu to position
itself below the bar of that display.
The script xmenu-button.sh is dead simple, and can remain consistent across all modules if you like. It simply echoes out the character you want to click on in polybar.
#!/usr/bin/sh
while true; do
  echo 
  sleep 30 &
  wait
done
You can slap pretty much anything in there, but I like to use FontAwesome icons because that’s what the rest of my bar uses.
My config⌗
Here is the ENTIRE xmenu script I have at the moment for my bars. Note the invocation of xmenu.
xmenu -i -p 0x25:1
-itellsxmenuto remove the space for icons-ptellsxmenuto use a specific position0x25the coordinates that place xmenu below my bar (25px down):1on screen one
#!/bin/sh
COLORSCRIPTSDIR=$HOME/Programs/color-scripts/color-scripts
CONFIGDIR=$HOME/dotfiles/dotfiles/config/
cat <<EOF | xmenu -i -p 0x25:1 | sh &
 Applications
	 Firefox	firefox
	 Terminal	urxvt
	 Files	thunar
	
	 School
		 canvas-tui 		urxvt -e canvas-tui
		 Zotero 		zotero
		 CS
			145
				Notes		urxvt -e nvim $HOME/School/CS/145/notes.java
			241
				Notes		urxvt -e nvim $HOME/School/CS/241/notes
			247
				Notes		urxvt -e nvim $HOME/School/CS/247/notes
				Books
					Susheel's notes		zathura $HOME/School/CS/247/CSCI247_CourseNotes.pdf
					Intel manual		zathura $HOME/School/CS/247/intel.pdf
					C Programming Language		zathura $HOME/School/CS/247/the_c_programming_language_2.pdf
			301
				Notes		urxvt -e nvim $HOME/School/CS/301/notes
				Books
					Theory of Computation		zathura $HOME/School/CS/301/TheoryOfComputation.pdf
					Book of Proof		zathura $HOME/School/CS/301/Main.pdf
			305
				Notes		urxvt -e nvim $HOME/School/CS/305/notes.md
				Textbook		zathura $HOME/School/CS/305/textbook.pdf
			330
				Notes		urxvt -e nvim $HOME/School/CS/330/notes.md
			347
				Notes		urxvt -e nvim $HOME/School/CS/347/notes.md
				Textbook		zathura $HOME/School/CS/347/textbook.pdf
			367
				Notes		urxvt -e nvim $HOME/School/CS/367/notes.md
				Textbook		zathura $HOME/School/CS/367/textbook.pdf
			461
				Notes		urxvt -e nvim $HOME/School/CS/461/notes.md
				Textbook		zathura $HOME/School/CS/461/textbook.pdf
			474
				Notes		urxvt -e nvim $HOME/School/CS/474/notes.md
	 Comms
		Discord (GUI)		discord
		Discord (cordless)		urxvt -e cordless
		 Email (Neomutt)		urxvt -e neomutt
		 IRC (weechat)		urxvt -e weechat
		 SMS (kde-connect)		kdeconnect-sms --style gtk2
		 Slack 	slack
		 Signal (GUI)		signal-desktop
		 Telegram (GUI)		telegram-desktop
		 Telegram (nctelegram)		nctelegram
	 Finance
		 Crypto (TUI)		urxvt -e cointop
		 Stocks (TUI)		urxvt -e mop
		 Stonks (CLI)		urxvt -e mop
	 Utilities
		 Calculator (TUI)		urxvt -e qalq
		 Calculator (GUI)		qalculate-gtk
		 Calendar (khal)		urxvt -e khal interactive
		 Color Picker		gpick
		 Map (TUI)		urxvt -e mapscii
		
		 System
			 Keyboard (Corsair)		ckb-next
			 Fonts 	gucharmap
			 Smartphone (kdeconnect)		kdeconnect-app --style gtk2
			 Docker (lazydocker)		urxvt -e lazydocker
			 Kill Window	xkill
			 Screen Recording (OBS)		obs
			 Screenshot
				GUI	flameshot gui
				All Displays	flameshot screen -d 5000 -n 3 -p $HOME/Photos/screenshots
				Middle Display	flameshot screen -d 5000 -n 0 -p $HOME/Photos/screenshots
				Right Display	flameshot screen -d 5000 -n 1 -p $HOME/Photos/screenshots
				Left Display	flameshot screen -d 5000 -n 2 -p $HOME/Photos/screenshots
		 Personal
			 Nextcloud		nextcloud --style gtk2
			 Passwords (keepassxc)		keepassxc --style gtk2
			 Keys (Seahorse)		seahorse
		 Theming
			lxappearance 	lxappearance
			GTK (oomox) 	oomox-gui
			Qt (qt5ct) 	qt5ct --style gtk2
			WPGTK 	wpg
		 Monitors
			System (ytop)		urxvt -e ytop
			System (bashtop)		urxvt -e bashtop
			System (glances)		urxvt -e glances
			
			Disk Usage (GUI)		baobab
			Disk Usage (TUI)		urxvt -e ncdu
			IO (iotop)		urxvt -e iotop
			
			Kernel (kmon)		urxvt -e kmon
			Nvidia GPU (nvtop)		urxvt -e nvtop
			Power (powertop)		urxvt -e powertop
			
			DNS (dnstop)		urxvt -e powertop
			Network Usage (jnettop)		urxvt -e jnettop
			Network Load (nload)		urxvt -e nload
			Bandwidth (bmon)		urxvt -e bmon
			Media Server		urxvt -e jellyfinips.sh
		 Media
			 EasyTag		easytag
	 Entertainment
		 Media
			 Podcasts (castero)	castero
			 RSS (newsboat)	newsboat
			 Reddit (tuir)	tuir
			 Music (cmus)	cmus
			 Spotify (GUI)	spotify
			 Spotify (spotifytui)	spt
			Soulseek (Nicotine+)	nicotine
		 Games
			 Steam	steam
			Itch	itch
			Lutris	lutris
			Tetris	tetris
			Solitaire	ttysolitaire
			Battleship	bs
			Minecraft	minecraft-launcher
			Dopewars	dopewars
		 Misc
			Color Scripts
				alpha	urxvt -e sh -c '$COLORSCRIPTSDIR/alpha; read'
				arch	urxvt -e sh -c '$COLORSCRIPTSDIR/arch; read'
				bars	urxvt -e sh -c '$COLORSCRIPTSDIR/bars; read'
				blocks2	urxvt -e sh -c '$COLORSCRIPTSDIR/blocks2; read'
				bloks	urxvt -e sh -c '$COLORSCRIPTSDIR/bloks; read'
				colorbars	urxvt -e sh -c '$COLORSCRIPTSDIR/colorbars; read'
				colortest	urxvt -e sh -c '$COLORSCRIPTSDIR/colortest; read'
				colortest-slim	urxvt -e sh -c '$COLORSCRIPTSDIR/colortest-slim; colortest'
				colorview	urxvt -e sh -c '$COLORSCRIPTSDIR/colorview; read'
				crunch	urxvt -e sh -c '$COLORSCRIPTSDIR/crunch; read'
				crunchbang	urxvt -e sh -c '$COLORSCRIPTSDIR/crunchbang; read'
				crunchbang-mini	urxvt -e sh -c '$COLORSCRIPTSDIR/crunchbang-mini; read'
				darthvader	urxvt -e sh -c '$COLORSCRIPTSDIR/darthvader; read'
				dna	urxvt -e sh -c '$COLORSCRIPTSDIR/dna; read'
				dotx	urxvt -e sh -c '$COLORSCRIPTSDIR/dna; read'
				elfman	urxvt -e sh -c '$COLORSCRIPTSDIR/elfman; read'
				faces	urxvt -e sh -c '$COLORSCRIPTSDIR/faces; read'
				fade	urxvt -e sh -c '$COLORSCRIPTSDIR/fade; read'
				ghosts	urxvt -e sh -c '$COLORSCRIPTSDIR/ghosts; read'
				guns	urxvt -e sh -c '$COLORSCRIPTSDIR/guns; read'
				hex	urxvt -e sh -c '$COLORSCRIPTSDIR/hex; read'
				hex-block	urxvt -e sh -c '$COLORSCRIPTSDIR/hex-block; read'
				illumina	urxvt -e sh -c '$COLORSCRIPTSDIR/illumina; read'
				jangofett	urxvt -e sh -c '$COLORSCRIPTSDIR/jangofett; read'
				monster	urxvt -e sh -c '$COLORSCRIPTSDIR/monster; read'
				mouseface	urxvt -e sh -c '$COLORSCRIPTSDIR/mouseface; read'
				pacman	urxvt -e sh -c '$COLORSCRIPTSDIR/pacman; read'
				panes	urxvt -e sh -c '$COLORSCRIPTSDIR/panes; read'
				pinguco	urxvt -e sh -c '$COLORSCRIPTSDIR/pinguco; read'
				pipes1	urxvt -e sh -c '$COLORSCRIPTSDIR/pipes1; read'
				pipes2	urxvt -e sh -c '$COLORSCRIPTSDIR/pipes2; read'
				pipes2-slim	urxvt -e sh -c '$COLORSCRIPTSDIR/pipes2-slim; read'
				pukeskull	urxvt -e sh -c '$COLORSCRIPTSDIR/pukeskull; read'
				rails	urxvt -e sh -c '$COLORSCRIPTSDIR/rails; read'
				rally-x	urxvt -e sh -c '$COLORSCRIPTSDIR/rally-x; read'
				rupees	urxvt -e sh -c '$COLORSCRIPTSDIR/rupees; read'
				space-invaders	urxvt -e sh -c '$COLORSCRIPTSDIR/space-invaders; read'
				spectrum	urxvt -e sh -c '$COLORSCRIPTSDIR/spectrum; read'
				square	urxvt -e sh -c '$COLORSCRIPTSDIR/square; read'
				tanks	urxvt -e sh -c '$COLORSCRIPTSDIR/tanks; read'
				thebat	urxvt -e sh -c '$COLORSCRIPTSDIR/thebat; read'
				thebat2	urxvt -e sh -c '$COLORSCRIPTSDIR/thebat2; read'
				tiefighter1-no-invo	urxvt -e sh -c '$COLORSCRIPTSDIR/tiefighter1-no-invo; read'
				tiefighter2	urxvt -e sh -c '$COLORSCRIPTSDIR/tiefighter2; read'
				zwaves	urxvt -e sh -c '$COLORSCRIPTSDIR/zwaves; read'
			cava	urxvt -e cava
			pipes.sh	urxvt -e pipes.sh
			rain.sh	urxvt -e rain.sh
			unimatrix	urxvt -e unimatrix -l Gg
			asciiquarium	urxvt -e asciiquarium
			bonsai.sh	urxvt -e bonsai -l -i -T
			eDEX-UI		sh -c (cd $HOME/Programs/edex-ui/ ; npm start)
	 Science
		 Astronomy
			Celestia	celestia
		 Biology
			Pymol		pymol
		 Chemistry
			ptable	urxvt -e ptable
			chemtool	chemtool
		 Math
			Desmos	desmos
			Geogebra	geogebra
		Anki		anki
	 Development
		 IDEs
			Neovim	urxvt -e nvim
			VS Code	code
			Dr. Racket	drracket
		 Github (TUI)	urxvt -e github
		bitwise	bitwise
		Github Activity (TUI)	urxvt -e sh -c 'ghcal --no-ansi ; read'
		QDbusViewer	qdbusviewer --style gtk2	
 Configs
	 System
		 i3	urxvt -e nvim $CONFIGDIR/i3/config
		 Start Menu	urxvt -e nvim $HOME/dotfiles/dotfiles/scripts/xmenu.sh
		 Notifications	urxvt -e nvim $CONFIGDIR/wal/templates/dunstrc
		 Smartphone	kdeconnect-settings --style gtk2
		 Sound	pavucontrol
		 Shell
			fish
				config.fish	urxvt -e nvim $CONFIGDIR/fish/config.fish
				Web Config	fish -c fish_config
			bash	urxvt -e nvim $HOME/.bashrc
		 polybar
			config	urxvt -e nvim $CONFIGDIR/polybar/config
			launch.sh	urxvt -e nvim $CONFIGDIR/polybar/scripts/launch.sh
		 rofi
			config	urxvt -e nvim $CONFIGDIR/rofi/config
			template	urxvt -e nvim $CONFIGDIR/wal/templates/custom-rofi.rasi
		 Utilities
			 khard	urxvt -e nvim $CONFIGDIR/khard/khard.conf
			 khal	urxvt -e nvim $CONFIGDIR/khal/config
			 vdirsyncer	urxvt -e nvim $CONFIGDIR/vdirsyncer/config
		 .Xresources	urxvt -e nvim $HOME/.Xresources
	 User
		ranger	urxvt -e nvim $CONFIGDIR/ranger/rc.conf
		newsboat	urxvt -e nvim $CONFIGDIR/newsboat/config
		neomutt
			neomuttrc	urxvt -e nvim $CONFIGDIR/neomutt/neomuttrc
			colors	urxvt -e nvim $CONFIGDIR/neomutt/colors
			settings	urxvt -e nvim $CONFIGDIR/neomutt/settings
			mappings	urxvt -e nvim $CONFIGDIR/neomutt/mappings
			mailcap	urxvt -e nvim $CONFIGDIR/neomutt/mailcap
		neovim
			coc-settings	urxvt -e nvim $HOME/.config/nvim/coc-settings.json
			functions	urxvt -e nvim $HOME/.config/nvim/configs/functions.vim
			main	urxvt -e nvim $HOME/.config/nvim/configs/main.vim
			mappings	urxvt -e nvim $HOME/.config/nvim/configs/mappings.vim
			plugin-settings	urxvt -e nvim $HOME/.config/nvim/configs/plugin-settings.vim
			plugins	urxvt -e nvim $HOME/.config/nvim/configs/plugin.vim
		neofetch	urxvt -e nvim $CONFIGDIR/neofetch/config.conf
		htop	urxvt -e nvim $CONFIGDIR/htop/htoprc
		s-tui	urxvt -e nvim $CONFIGDIR/s-tui/s-tui.conf
		spicetify	urxvt -e nvim $CONFIGDIR/spicetify/config.ini
		stonks	urxvt -e nvim $CONFIGDIR/stonks.yml
 System
	 Refresh i3		i3-msg restart
	 Refresh polybar		pkill -9 polybar ; $CONFIGDIR/polybar/scripts/launch.sh
	
	 Logout	i3-nagbar -t warning -m 'Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'
	 Shutdown		poweroff
	 Reboot			reboot
EOF
Feel free to take inspiration!
Conclusion⌗
Good job for making it this far. If you followed along, you should have a desktop environment agnostic menu utility with infinite potential!