HOW-TO: Rofi - XFCE-like menu

Original forum link
https://forum.qubes-os.org/t/40543
Original poster
tnt
Created at
2026-04-08 22:53:53
Last wiki edit
2026-04-13 09:30:13
Revisions
3 revisions
Posts count
2
Likes count
0

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

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

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.