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>$is_running_icon </span><span>$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 '&gt;' -f 4 | cut -d '&lt;' -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&gt;/dev/null)
        if [ "$is_disposable" = "True" ]; then
            echo -e "<span>\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 '&gt;' -f 4 | cut -d '&lt;' -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