EDIT: Whole post has been edited to add the new really functional version.
So I recently installed i3wm in my Qubes desktop because it feels better for me.
I've coded a bash script to help me organize the rofi menu, because dmenu sucks for me.
In dom0:
- Install rofi in dom0 with sudo qubes-dom0-update rofi
- Create the folder ~/.config/rofi
- Create the file rofi_qubes_os_menu.sh inside with this content:
#!/bin/bash
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
chmod u+x ~/.config/rofi/rofi_qubes_os_menu.sh~/.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.shNow 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
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.