250 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
		
			Executable File
		
	
	
	
	
 | 
						|
#!/usr/bin/env bash
 | 
						|
 | 
						|
# This script defines just a mode for rofi instead of being a self-contained
 | 
						|
# executable that launches rofi by itself. This makes it more flexible than
 | 
						|
# running rofi inside this script as now the user can call rofi as one pleases.
 | 
						|
# For instance:
 | 
						|
#
 | 
						|
#   rofi -show powermenu -modi powermenu:./rofi-power-menu
 | 
						|
#
 | 
						|
# See README.md for more information.
 | 
						|
#
 | 
						|
# https://pictogrammers.com/library/mdi/
 | 
						|
 | 
						|
set -e
 | 
						|
set -u
 | 
						|
 | 
						|
# All supported choices
 | 
						|
all=(shutdown reboot suspend hibernate logout lockscreen)
 | 
						|
 | 
						|
# By default, show all (i.e., just copy the array)
 | 
						|
show=("${all[@]}")
 | 
						|
 | 
						|
declare -A texts
 | 
						|
texts[lockscreen]="lock screen"
 | 
						|
texts[switchuser]="switch user"
 | 
						|
texts[logout]="log out"
 | 
						|
texts[suspend]="suspend"
 | 
						|
texts[hibernate]="hibernate"
 | 
						|
texts[reboot]="reboot"
 | 
						|
texts[shutdown]="shut down"
 | 
						|
 | 
						|
declare -A icons
 | 
						|
icons[lockscreen]=""
 | 
						|
icons[switchuser]=""
 | 
						|
icons[logout]=""
 | 
						|
icons[suspend]=""
 | 
						|
icons[hibernate]=""
 | 
						|
icons[reboot]=""
 | 
						|
icons[shutdown]=""
 | 
						|
icons[cancel]=""
 | 
						|
 | 
						|
declare -A actions
 | 
						|
actions[lockscreen]="loginctl lock-session ${XDG_SESSION_ID-}"
 | 
						|
#actions[switchuser]="???"
 | 
						|
actions[logout]="loginctl terminate-session ${XDG_SESSION_ID-}"
 | 
						|
actions[suspend]="systemctl suspend"
 | 
						|
actions[hibernate]="systemctl hibernate"
 | 
						|
actions[reboot]="systemctl reboot"
 | 
						|
actions[shutdown]="systemctl poweroff"
 | 
						|
 | 
						|
# By default, ask for confirmation for actions that are irreversible
 | 
						|
confirmations=(reboot shutdown logout suspend hibernate lockscreen)
 | 
						|
 | 
						|
# By default, no dry run
 | 
						|
dryrun=false
 | 
						|
showsymbols=true
 | 
						|
 | 
						|
function check_valid {
 | 
						|
    option="$1"
 | 
						|
    shift 1
 | 
						|
    for entry in "${@}"
 | 
						|
    do
 | 
						|
        if [ -z "${actions[$entry]+x}" ]
 | 
						|
        then
 | 
						|
            echo "Invalid choice in $1: $entry" >&2
 | 
						|
            exit 1
 | 
						|
        fi
 | 
						|
    done
 | 
						|
}
 | 
						|
 | 
						|
# Parse command-line options
 | 
						|
parsed=$(getopt --options=h --longoptions=help,dry-run,confirm:,choices:,choose:,symbols,no-symbols --name "$0" -- "$@")
 | 
						|
if [ $? -ne 0 ]; then
 | 
						|
    echo 'Terminating...' >&2
 | 
						|
    exit 1
 | 
						|
fi
 | 
						|
eval set -- "$parsed"
 | 
						|
unset parsed
 | 
						|
while true; do
 | 
						|
    case "$1" in
 | 
						|
        "-h"|"--help")
 | 
						|
            echo "rofi-power-menu - a power menu mode for Rofi"
 | 
						|
            echo
 | 
						|
            echo "Usage: rofi-power-menu [--choices CHOICES] [--confirm CHOICES]"
 | 
						|
            echo "                       [--choose CHOICE] [--dry-run] [--symbols|--no-symbols]"
 | 
						|
            echo
 | 
						|
            echo "Use with Rofi in script mode. For instance, to ask for shutdown or reboot:"
 | 
						|
            echo
 | 
						|
            echo "  rofi -show menu -modi \"menu:rofi-power-menu --choices=shutdown/reboot\""
 | 
						|
            echo
 | 
						|
            echo "Available options:"
 | 
						|
            echo "  --dry-run          Don't perform the selected action but print it to stderr."
 | 
						|
            echo "  --choices CHOICES  Show only the selected choices in the given order. Use / "
 | 
						|
            echo "                     as the separator. Available choices are lockscreen, logout,"
 | 
						|
            echo "                     suspend, hibernate, reboot and shutdown. By default, all"
 | 
						|
            echo "                     available choices are shown."
 | 
						|
            echo "  --confirm CHOICES  Require confirmation for the gives choices only. Use / as"
 | 
						|
            echo "                     the separator. Available choices are lockscreen, logout,"
 | 
						|
            echo "                     suspend, hibernate, reboot and shutdown. By default, only"
 | 
						|
            echo "                     irreversible actions logout, reboot and shutdown require"
 | 
						|
            echo "                     confirmation."
 | 
						|
            echo "  --choose CHOICE    Preselect the given choice and only ask for a confirmation"
 | 
						|
            echo "                     (if confirmation is set to be requested). It is strongly"
 | 
						|
            echo "                     recommended to combine this option with --confirm=CHOICE"
 | 
						|
            echo "                     if the choice wouldn't require confirmation by default."
 | 
						|
            echo "                     Available choices are lockscreen, logout, suspend,"
 | 
						|
            echo "                     hibernate, reboot and shutdown."
 | 
						|
            echo "  --[no-]symbols     Show Unicode symbols or not. Requires a font with support"
 | 
						|
            echo "                     for the symbols. Use, for instance, fonts from the"
 | 
						|
            echo "                     Nerdfonts collection. By default, they are shown"
 | 
						|
            echo "  -h,--help          Show this help text."
 | 
						|
            exit 0
 | 
						|
            ;;
 | 
						|
        "--dry-run")
 | 
						|
            dryrun=true
 | 
						|
            shift 1
 | 
						|
            ;;
 | 
						|
        "--confirm")
 | 
						|
            IFS='/' read -ra confirmations <<< "$2"
 | 
						|
            check_valid "$1" "${confirmations[@]}"
 | 
						|
            shift 2
 | 
						|
            ;;
 | 
						|
        "--choices")
 | 
						|
            IFS='/' read -ra show <<< "$2"
 | 
						|
            check_valid "$1" "${show[@]}"
 | 
						|
            shift 2
 | 
						|
            ;;
 | 
						|
        "--choose")
 | 
						|
            # Check that the choice is valid
 | 
						|
            check_valid "$1" "$2"
 | 
						|
            selectionID="$2"
 | 
						|
            shift 2
 | 
						|
            ;;
 | 
						|
        "--symbols")
 | 
						|
            showsymbols=true
 | 
						|
            shift 1
 | 
						|
            ;;
 | 
						|
        "--no-symbols")
 | 
						|
            showsymbols=false
 | 
						|
            shift 1
 | 
						|
            ;;
 | 
						|
        "--")
 | 
						|
            shift
 | 
						|
            break
 | 
						|
            ;;
 | 
						|
        *)
 | 
						|
            echo "Internal error" >&2
 | 
						|
            exit 1
 | 
						|
            ;;
 | 
						|
    esac
 | 
						|
done
 | 
						|
 | 
						|
# Define the messages after parsing the CLI options so that it is possible to
 | 
						|
# configure them in the future.
 | 
						|
 | 
						|
function write_message {
 | 
						|
    icon="<span font_size=\"medium\">$1</span>"
 | 
						|
    text="<span font_size=\"medium\">$2</span>"
 | 
						|
    if [ "$showsymbols" = "true" ]
 | 
						|
    then
 | 
						|
        echo -n "\u200e$icon \u2068$text\u2069"
 | 
						|
    else
 | 
						|
        echo -n "$text"
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
function print_selection {
 | 
						|
    echo -e "$1" | $(read -r -d '' entry; echo "echo $entry")
 | 
						|
}
 | 
						|
 | 
						|
declare -A messages
 | 
						|
declare -A confirmationMessages
 | 
						|
for entry in "${all[@]}"
 | 
						|
do
 | 
						|
    messages[$entry]=$(write_message "${icons[$entry]}" "${texts[$entry]^}")
 | 
						|
done
 | 
						|
for entry in "${all[@]}"
 | 
						|
do
 | 
						|
    confirmationMessages[$entry]=$(write_message "${icons[$entry]}" "Yes, ${texts[$entry]}")
 | 
						|
done
 | 
						|
confirmationMessages[cancel]=$(write_message "${icons[cancel]}" "No, cancel")
 | 
						|
 | 
						|
if [ $# -gt 0 ]
 | 
						|
then
 | 
						|
    # If arguments given, use those as the selection
 | 
						|
    selection="${@}"
 | 
						|
else
 | 
						|
    # Otherwise, use the CLI passed choice if given
 | 
						|
    if [ -n "${selectionID+x}" ]
 | 
						|
    then
 | 
						|
        selection="${messages[$selectionID]}"
 | 
						|
    fi
 | 
						|
fi
 | 
						|
 | 
						|
# Don't allow custom entries
 | 
						|
echo -e "\0no-custom\x1ftrue"
 | 
						|
# Use markup
 | 
						|
echo -e "\0markup-rows\x1ftrue"
 | 
						|
 | 
						|
if [ -z "${selection+x}" ]
 | 
						|
then
 | 
						|
    echo -e "\0prompt\x1f⏻"
 | 
						|
    for entry in "${show[@]}"
 | 
						|
    do
 | 
						|
        echo -e "${messages[$entry]}\0icon\x1f${icons[$entry]}"
 | 
						|
    done
 | 
						|
else
 | 
						|
    for entry in "${show[@]}"
 | 
						|
    do
 | 
						|
        if [ "$selection" = "$(print_selection "${messages[$entry]}")" ]
 | 
						|
        then
 | 
						|
            # Check if the selected entry is listed in confirmation requirements
 | 
						|
            for confirmation in "${confirmations[@]}"
 | 
						|
            do
 | 
						|
                if [ "$entry" = "$confirmation" ]
 | 
						|
                then
 | 
						|
                    # Ask for confirmation
 | 
						|
                    echo -e "\0prompt\x1fAre you sure"
 | 
						|
                    echo -e "${confirmationMessages[$entry]}\0icon\x1f${icons[$entry]}"
 | 
						|
                    echo -e "${confirmationMessages[cancel]}\0icon\x1f${icons[cancel]}"
 | 
						|
                    exit 0
 | 
						|
                fi
 | 
						|
            done
 | 
						|
            # If not, then no confirmation is required, so mark confirmed
 | 
						|
            selection=$(print_selection "${confirmationMessages[$entry]}")
 | 
						|
        fi
 | 
						|
        if [ "$selection" = "$(print_selection "${confirmationMessages[$entry]}")" ]
 | 
						|
        then
 | 
						|
            if [ $dryrun = true ]
 | 
						|
            then
 | 
						|
                # Tell what would have been done
 | 
						|
                echo "Selected: $entry" >&2
 | 
						|
            else
 | 
						|
                # Perform the action
 | 
						|
                ${actions[$entry]}
 | 
						|
            fi
 | 
						|
            exit 0
 | 
						|
        fi
 | 
						|
        if [ "$selection" = "$(print_selection "${confirmationMessages[cancel]}")" ]
 | 
						|
        then
 | 
						|
            # Do nothing
 | 
						|
            exit 0
 | 
						|
        fi
 | 
						|
    done
 | 
						|
    # The selection didn't match anything, so raise an error
 | 
						|
    echo "Invalid selection: $selection" >&2
 | 
						|
    exit 1
 | 
						|
fi
 |