#!/usr/bin/env bash #-*-coding:utf-8 -*- #Auto updated? # Yes #File: # powermenu #Author: # The-Repo-Club [wayne6324@gmail.com] #Github: # https://github.com/The-Repo-Club/ # #Created: # Wed 07 December 2022, 11:01:52 PM [GMT] #Modified: # Sat 02 September 2023, 12:11:51 AM [GMT+1] # #Description: # 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 -config ~/.config/rofi/powermenu.rasi # #Dependencies: # # # shellcheck disable=all if [ -z "${ROFI_OUTSIDE}" ]; then echo "run this script in rofi". exit fi 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[logout]="log out" texts[suspend]="suspend" texts[hibernate]="hibernate" texts[reboot]="reboot" texts[shutdown]="shut down" declare -A icons icons[lockscreen]="" icons[logout]="󰍃" icons[suspend]="󰒲" icons[hibernate]="󰋊" icons[reboot]="󰜉" icons[shutdown]="󰐥" icons[cancel]="" declare -A actions actions[lockscreen]="loginctl lock-session" actions[logout]="pkill -KILL -u ${USER}" 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) # By default, no dry run dryrun=false showsymbols=true getuptime() { state=$(uptime | sed -E 's/^[^,]*up *//; s/mins/minutes/; s/hrs?/hours/; s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/; s/^1 hours/1 hour/; s/ 1 hours/ 1 hour/; s/min,/minutes,/; s/ 0 minutes,/ less than a minute,/; s/ 1 minutes/ 1 minute/; s/ / /; s/, *[[:digit:]]* users?.*//') } function check_valid { option="$1" shift 1 for entry in "${@}"; do if [ -z "${actions[$entry]+x}" ]; then echo "Invalid choice in $option: $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="$1" text="$2" 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" echo -e "\0markup-rows\x1ftrue" if [ -z "${selection+x}" ]; then getuptime echo -e "\0prompt\x1fPower Menu" echo -en "\0message\x1fUptime :: ${state^}\n" 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