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.


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

sudo make install

I choose to build from source because it allows me to theme on the fly.


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:


cat <<EOF | xmenu | sh &
	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

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.


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:

type = custom/script
click-left = /home/gideon/dotfiles/dotfiles/scripts/
click-right = /home/gideon/dotfiles/dotfiles/scripts/
exec = /home/gideon/.config/polybar/scripts/
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 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.


while true; do
  echo 
  sleep 30 &

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

  • -i tells xmenu to remove the space for icons
  • -p tells xmenu to use a specific position
  • 0x25 the coordinates that place xmenu below my bar (25px down)
  • :1 on screen one


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
				Notes		urxvt -e nvim $HOME/School/CS/145/
				Notes		urxvt -e nvim $HOME/School/CS/241/notes
				Notes		urxvt -e nvim $HOME/School/CS/247/notes
					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
				Notes		urxvt -e nvim $HOME/School/CS/301/notes
					Theory of Computation		zathura $HOME/School/CS/301/TheoryOfComputation.pdf
					Book of Proof		zathura $HOME/School/CS/301/Main.pdf
				Notes		urxvt -e nvim $HOME/School/CS/305/
				Textbook		zathura $HOME/School/CS/305/textbook.pdf
				Notes		urxvt -e nvim $HOME/School/CS/330/
				Notes		urxvt -e nvim $HOME/School/CS/347/
				Textbook		zathura $HOME/School/CS/347/textbook.pdf
				Notes		urxvt -e nvim $HOME/School/CS/367/
				Textbook		zathura $HOME/School/CS/367/textbook.pdf
				Notes		urxvt -e nvim $HOME/School/CS/461/
				Textbook		zathura $HOME/School/CS/461/textbook.pdf
				Notes		urxvt -e nvim $HOME/School/CS/474/
	 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
		 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	urxvt -e	urxvt -e
			unimatrix	urxvt -e unimatrix -l Gg
			asciiquarium	urxvt -e asciiquarium	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/
		 Notifications	urxvt -e nvim $CONFIGDIR/wal/templates/dunstrc
		 Smartphone	kdeconnect-settings --style gtk2
		 Sound	pavucontrol
		 Shell
			fish	urxvt -e nvim $CONFIGDIR/fish/
				Web Config	fish -c fish_config
			bash	urxvt -e nvim $HOME/.bashrc
		 polybar
			config	urxvt -e nvim $CONFIGDIR/polybar/config	urxvt -e nvim $CONFIGDIR/polybar/scripts/
		 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
			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
			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/
	 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

Feel free to take inspiration!


Good job for making it this far. If you followed along, you should have a desktop environment agnostic menu utility with infinite potential!