HOW-TO: Rofi - XFCE-like menu revisions

Go back to topic: HOW-TO: Rofi - XFCE-like menu

  1. v4 anchor; v4 full version
  2. v3 anchor; v3 full version
  3. v2 anchor; v2 full version

Revision #4

Edited on
2026-04-13
Edited by user
tnt

Revision #3

Edited on
2026-04-12
Edited by user
tnt
- Give it execution permissions: `chmod u+x ~/.config/rofi/rofi_qubes_os_menu.sh`
- If use clicks away from rofi: Exit rofi- If use clicks away from rofi: Exit rofi This rofi menu tries to be somewhat similar to the one we have in XFCE. You can view AppVMs, disposable VMs, etc... Spawn apps inside them, start those machines when they are not running, shutdown/kill them when they are running, open their settings, etc... Also, running VMs appear in bold text so you know wether they are running or not. Also, a circle icon at the left of the VM appears with the color it has been assigned, so everything is easier to do in this menu. You will also have a menu for dom0 apps. Some back buttons and an exit button has been added, so you can navigate easily through the menu.

Revision #2

Edited on
2026-04-12
Edited by user
tnt
EDIT: Whole post has been edited to add the new really functional version.
I've coded some shitty bash scripts to help me organize the rofi menu, because dmenu sucks for me. It's still buggy because is just a vague idea of what i want to do, but the base is here and maybe somebody get's an idea to customize it and make it a stable piece of code for their use case. I've coded a bash script to help me organize the rofi menu, because dmenu sucks for me.
- Create the folder `~/rofi_qubes_appmenu` - Create these files inside that folder: main_menu.sh - Create the folder `~/.config/rofi` - Create the file `rofi_qubes_os_menu.sh` inside with this content:
# Get a list of all available qubes VMs qubes=$(ls -la ~/.local/share/applications/ | grep "org.qubes-os.qubes-vm-settings.*" | cut -d '.' -f 4 | cut -b 2- | sed -r 's/_d/-/g') # Open a VM menu. There, it is possible to select one of them chosen=$(echo -e "Exit\ndom0\n$qubes" | rofi -dmenu -p "Select qube") # Run an app menu of that qube VM #~/rofi_qubes_appmenu/app_menu.sh $chosen if [ "$chosen" = "Exit" ]; then exit elif [ "$chosen" = "dom0" ]; then ~/rofi_qubes_appmenu/dom0_menu.sh else #ls ~/.local/share/applications/org.qubes-os.vm._$chosen.* | rofi -show drun ~/rofi_qubes_appmenu/app_menu.sh $chosen fi app_menu () { qube_name="$1" running_status="$2" last_qube_menu="$3" # Create an option to boot/shutdown/kill VM if [ "$running_status" = "bold" ]; then change_status_option='Shutdown\nKill' else change_status_option='Power on' fi # Rebuild the name format used by the .desktop files qube=$(echo "$qube_name" | sed -r 's/-/_d/g') # Get the name of available apps apps=$(grep -h "^Name=" ~/.local/share/applications/org.qubes-os.vm._$qube.* | sed 's/^Name=//') # Let the user select the app. Also, make a settings option available chosen=$(echo -e "Back\n$apps\n$change_status_option\nSettings" | rofi -dmenu -p "$1 - Select app") if [ "$chosen" = "Back" ]; then show_qubes "$last_qube_menu" elif [ "$chosen" = "Power on" ]; then qvm-start $qube_name elif [ "$chosen" = "Shutdown" ]; then qvm-shutdown $qube_name elif [ "$chosen" = "Kill" ]; then qvm-kill $qube_name elif [ "$chosen" = "Settings" ]; then exo-open ~/.local/share/applications/org.qubes-os.qubes-vm-settings._$qube.desktop else $(grep -h "^Exec=" $(grep -rl "^Name=$chosen" ~/.local/share/applications/org.qubes-os.vm._$qube.* | head -n1) | sed 's/^Exec=//') fi } show_qubes () { # Get a list of all available qubes VMs options=$(qvm-ls --fields NAME,STATE,CLASS,LABEL,PROVIDES_NETWORK --raw-data | grep "$1" | \ while IFS='|' read -r name state class label net; do if [ "$state" = "Halted" ]; then is_running_weight="normal" is_running_icon="\U25C9" else is_running_weight="bold" is_running_icon="\U25CF" fi echo -e "<span foreground='$label'>$is_running_icon </span><span weight='$is_running_weight'>$name</span>" done) chosen=$(echo -e "<span>Back</span>\n$options" | rofi -dmenu -markup-rows -p "Select qube") # Depending on the chosen one, do things if [ "$chosen" = "<span>Back</span>" ]; then main_menu else app_menu $(echo -e "$chosen" | cut -d '>' -f 4 | cut -d '<' -f 1) $(echo -e "$chosen" | cut -d "'" -f 4) "$1" fi } disp_app_menu () { # Rebuild the name format used by the .desktop files qube=$(echo "$1" | sed -r 's/-/_d/g') # Get the name of available apps apps=$(grep -h "^Name=" ~/.local/share/applications/org.qubes-os.dispvm._$qube.* | sed 's/^Name=//') # Let the user select the app. Also, make a settings option available chosen=$(echo -e "Back\n$apps\nSettings" | rofi -dmenu -p "$1 - Select app") if [[ "$chosen" = "Back" ]]; then show_disp elif [[ "$chosen" = "Settings" ]]; then exo-open ~/.local/share/applications/org.qubes-os.qubes-vm-settings._$qube.desktop else $(grep -h "^Exec=" $(grep -rl "^Name=$chosen" ~/.local/share/applications/org.qubes-os.dispvm._$qube.* | head -n1) | sed 's/^Exec=//') fi } show_disp () { # Get a list of all available AppVMs that do not provide network (candidates for Diposable VMs) options=$(qvm-ls --fields NAME,CLASS,LABEL,PROVIDES_NETWORK --raw-data | grep "|AppVM|.*|False$" | \ while IFS='|' read -r name class label net; do is_disposable=$(qvm-prefs "$name" template_for_dispvms 2>/dev/null) if [ "$is_disposable" = "True" ]; then echo -e "<span foreground='$label'>\U25CF </span><span>$name</span>" fi done) chosen=$(echo -e "<span>Back</span>\n$options" | rofi -dmenu -markup-rows -p "Select qube") # Depending on the chosen one, do things if [ "$chosen" = "<span>Back</span>" ]; then main_menu else disp_app_menu $(echo -e "$chosen" | cut -d '>' -f 4 | cut -d '<' -f 1) fi } dom0_menu () { # Get the name of available apps apps=$(grep -h "^Name=" /usr/share/applications/* | sed 's/^Name=//') # Let the user select the app. Also, make a settings option available chosen=$(echo -e "Back\n$apps" | rofi -dmenu -p "dom0 - Select app") if [ "$chosen" = "Back" ]; then main_menu else $(grep -h "^Exec=" $(grep -rl "^Name=$chosen" /usr/share/applications/ | head -n1) | sed 's/^Exec=//') fi } main_menu () { chosen=$(echo -e "Exit\nApp VMs\nActive Disposable VMs\nSpawn disposable VM\nStandalone VMs\nTemplates\nServices\ndom0" | rofi -dmenu -markup-rows -p "Select option") if [ "$chosen" = "Exit" ]; then exit elif [ "$chosen" = "dom0" ]; then dom0_menu elif [ "$chosen" = "Services" ]; then show_qubes '|True$' elif [ "$chosen" = "Templates" ]; then show_qubes '|TemplateVM|.*|False$' elif [ "$chosen" = "Standalone VMs" ]; then show_qubes '|StandaloneVM|.*|False$' elif [ "$chosen" = "Active Disposable VMs" ]; then show_qubes '|DispVM|.*|False$' elif [ "$chosen" = "Spawn disposable VM" ]; then show_disp elif [ "$chosen" = "App VMs" ]; then show_qubes '|AppVM|.*|False$' # User presses Esc or clicks away #elif [ $? -eq 1 ]; then # exit fi } main_menu
app_menu.sh ```bash #!/bin/bash # Rebuild the name format used by the .desktop files qube=$(echo "$1" | sed -r 's/-/_d/g') # Get the name of available apps apps=$(grep -h "^Name=" ~/.local/share/applications/org.qubes-os.vm._$qube.* | sed 's/^Name=//') # Let the user select the app. Also, make a settings option available chosen=$(echo -e "Back\n$apps\nSettings" | rofi -dmenu -p "$1 - Select app") if [ "$chosen" = "Back" ]; then ~/rofi_qubes_appmenu/main_menu.sh elif [ "$chosen" = "Settings" ]; then exo-open ~/.local/share/applications/org.qubes-os.qubes-vm-settings._$qube.desktop else #exo-open $(ls ~/.local/share/applications/org.qubes-os.vm._$qube.* | grep $chosen.desktop) #grep -h "^Exec=" $(grep -rl "^Name=$1: $chosen" ~/.local/share/applications/org.qubes-os.vm._$qube.* | head -n1) | sed 's/^Exec=//' $(grep -h "^Exec=" $(grep -rl "^Name=$chosen" ~/.local/share/applications/org.qubes-os.vm._$qube.* | head -n1) | sed 's/^Exec=//') fi ``` disposable_menu.sh ```bash #!/bin/bash # Rebuild the name format used by the .desktop files qube=$(echo "$1" | sed -r 's/-/_d/g') # Get the name of available apps apps=$(grep -h "^Name=" ~/.local/share/applications/org.qubes-os.dispvm._$qube.* | sed 's/^Name=//') # Let the user select the app. Also, make a settings option available chosen=$(echo -e "$apps\nSettings" | rofi -dmenu -p "$1 - Select app") if [[ "$chosen" = "Settings" ]] then exo-open ~/.local/share/applications/org.qubes-os.qubes-vm-settings._$qube.desktop else #exo-open $(ls ~/.local/share/applications/org.qubes-os.vm._$qube.* | grep $chosen.desktop) #grep -h "^Exec=" $(grep -rl "^Name=$1: $chosen" ~/.local/share/applications/org.qubes-os.vm._$qube.* | head -n1) | sed 's/^Exec=//' $(grep -h "^Exec=" $(grep -rl "^Name=$chosen" ~/.local/share/applications/org.qubes-os.dispvm._$qube.* | head -n1) | sed 's/^Exec=//') fi ``` - Last, create a keybind in `~/.config/i3/config` to launch rofi (or replace the one used by dmenu). Example: `bindsym $mod+d exec --no-startup-id ~/rofi_qubes_appmenu/main_menu.sh` Notes: I haven't implemented the disposable_menu.sh yet, so it wont be used from the keybind. This means you are not spawning dispXXX from the rofi menu, but a default-dvm qube. My temporal workaround is to launch from dom0 `~/rofi_qubes_appmenu/disposable_menu.sh default-dvm`. The idea behind this config was to have a menu a little bit more similar to the one I had in XFCE, which i loved, but being easier to use with only the keyboard. Anyways, this is probably a waste of time and default rofi -drun is easier than getting things over-complicated (and i think i will end up doing this), but anyway, if this is useful for somebody that's great- Last, create a keybind in `~/.config/i3/config` to launch rofi (or replace the one used by dmenu). Example: `bindsym $mod+d exec --no-startup-id ~/.config/rofi/rofi_qubes_os_menu.sh` Now everything works perfectly. It's only left to do this things: - If user presses "Esc": go back to the previous section - If use clicks away from rofi: Exit rofi