rofi-power-menu 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #!/usr/bin/env bash
  2. # This script defines just a mode for rofi instead of being a self-contained
  3. # executable that launches rofi by itself. This makes it more flexible than
  4. # running rofi inside this script as now the user can call rofi as one pleases.
  5. # For instance:
  6. #
  7. # rofi -show powermenu -modi powermenu:./rofi-power-menu
  8. #
  9. # See README.md for more information.
  10. set -e
  11. set -u
  12. # All supported choices
  13. all=(logout reboot shutdown)
  14. # By default, show all (i.e., just copy the array)
  15. show=("${all[@]}")
  16. declare -A texts
  17. texts[switchuser]="switch user"
  18. texts[logout]="log out"
  19. texts[reboot]="reboot"
  20. texts[shutdown]="shut down"
  21. declare -A icons
  22. icons[switchuser]=""
  23. icons[logout]="󰍃"
  24. icons[reboot]="󱞳"
  25. icons[shutdown]="󰤆"
  26. icons[cancel]="󱫀"
  27. declare -A actions
  28. actions[switchuser]="???"
  29. actions[logout]="openbox --exit"
  30. actions[reboot]="reboot"
  31. actions[shutdown]="poweroff"
  32. # By default, ask for confirmation for actions that are irreversible
  33. confirmations=(reboot shutdown)
  34. # By default, no dry run
  35. dryrun=false
  36. showsymbols=true
  37. showtext=true
  38. function check_valid {
  39. option="$1"
  40. shift 1
  41. for entry in "${@}"
  42. do
  43. if [ -z "${actions[$entry]+x}" ]
  44. then
  45. echo "Invalid choice in $1: $entry" >&2
  46. exit 1
  47. fi
  48. done
  49. }
  50. # Parse command-line options
  51. parsed=$(getopt --options=h --longoptions=help,dry-run,confirm:,choices:,choose:,symbols,no-symbols,text,no-text,symbols-font: --name "$0" -- "$@")
  52. if [ $? -ne 0 ]; then
  53. echo 'Terminating...' >&2
  54. exit 1
  55. fi
  56. eval set -- "$parsed"
  57. unset parsed
  58. while true; do
  59. case "$1" in
  60. "-h"|"--help")
  61. echo "rofi-power-menu - a power menu mode for Rofi"
  62. echo
  63. echo "Usage: rofi-power-menu [--choices CHOICES] [--confirm CHOICES]"
  64. echo " [--choose CHOICE] [--dry-run] [--symbols|--no-symbols]"
  65. echo
  66. echo "Use with Rofi in script mode. For instance, to ask for shutdown or reboot:"
  67. echo
  68. echo " rofi -show menu -modi \"menu:rofi-power-menu --choices=shutdown/reboot\""
  69. echo
  70. echo "Available options:"
  71. echo " --dry-run Don't perform the selected action but print it to stderr."
  72. echo " --choices CHOICES Show only the selected choices in the given order. Use /"
  73. echo " as the separator. Available choices are lockscreen,"
  74. echo " logout,suspend, hibernate, reboot and shutdown. By"
  75. echo " default, all available choices are shown."
  76. echo " --confirm CHOICES Require confirmation for the gives choices only. Use / as"
  77. echo " the separator. Available choices are lockscreen, logout,"
  78. echo " suspend, hibernate, reboot and shutdown. By default, only"
  79. echo " irreversible actions logout, reboot and shutdown require"
  80. echo " confirmation."
  81. echo " --choose CHOICE Preselect the given choice and only ask for a"
  82. echo " confirmation (if confirmation is set to be requested). It"
  83. echo " is strongly recommended to combine this option with"
  84. echo " --confirm=CHOICE if the choice wouldn't require"
  85. echo " confirmation by default. Available choices are"
  86. echo " lockscreen, logout, suspend, hibernate, reboot and"
  87. echo " shutdown."
  88. echo " --[no-]symbols Show Unicode symbols or not. Requires a font with support"
  89. echo " for the symbols. Use, for instance, fonts from the"
  90. echo " Nerdfonts collection. By default, they are shown"
  91. echo " --[no-]text Show text description or not."
  92. echo " --symbols-font FONT Use the given font for symbols. By default, the symbols"
  93. echo " use the same font as the text. That font is configured"
  94. echo " with rofi."
  95. echo " -h,--help Show this help text."
  96. exit 0
  97. ;;
  98. "--dry-run")
  99. dryrun=true
  100. shift 1
  101. ;;
  102. "--confirm")
  103. IFS='/' read -ra confirmations <<< "$2"
  104. check_valid "$1" "${confirmations[@]}"
  105. shift 2
  106. ;;
  107. "--choices")
  108. IFS='/' read -ra show <<< "$2"
  109. check_valid "$1" "${show[@]}"
  110. shift 2
  111. ;;
  112. "--choose")
  113. # Check that the choice is valid
  114. check_valid "$1" "$2"
  115. selectionID="$2"
  116. shift 2
  117. ;;
  118. "--symbols")
  119. showsymbols=true
  120. shift 1
  121. ;;
  122. "--no-symbols")
  123. showsymbols=false
  124. shift 1
  125. ;;
  126. "--text")
  127. showtext=true
  128. shift 1
  129. ;;
  130. "--no-text")
  131. showtext=false
  132. shift 1
  133. ;;
  134. "--symbols-font")
  135. symbols_font="$2"
  136. shift 2
  137. ;;
  138. "--")
  139. shift
  140. break
  141. ;;
  142. *)
  143. echo "Internal error" >&2
  144. exit 1
  145. ;;
  146. esac
  147. done
  148. if [ "$showsymbols" = "false" -a "$showtext" = "false" ]
  149. then
  150. echo "Invalid options: cannot have --no-symbols and --no-text enabled at the same time." >&2
  151. exit 1
  152. fi
  153. # Define the messages after parsing the CLI options so that it is possible to
  154. # configure them in the future.
  155. function write_message {
  156. if [ -z ${symbols_font+x} ];
  157. then
  158. icon="<span font_size=\"medium\">$1</span>"
  159. else
  160. icon="<span font=\"${symbols_font}\" font_size=\"medium\">$1</span>"
  161. fi
  162. text="<span font_size=\"medium\">$2</span>"
  163. if [ "$showsymbols" = "true" ]
  164. then
  165. if [ "$showtext" = "true" ]
  166. then
  167. echo -n "$icon $text"
  168. else
  169. echo -n "$icon"
  170. fi
  171. else
  172. echo -n "$text"
  173. fi
  174. }
  175. function print_selection {
  176. echo -e "$1" | $(read -r -d '' entry; echo "echo $entry")
  177. }
  178. declare -A messages
  179. declare -A confirmationMessages
  180. for entry in "${all[@]}"
  181. do
  182. messages[$entry]=$(write_message "${icons[$entry]}" "${texts[$entry]^}")
  183. done
  184. for entry in "${all[@]}"
  185. do
  186. confirmationMessages[$entry]=$(write_message "${icons[$entry]}" "Yes, ${texts[$entry]}")
  187. done
  188. confirmationMessages[cancel]=$(write_message "${icons[cancel]}" "No, cancel")
  189. if [ $# -gt 0 ]
  190. then
  191. # If arguments given, use those as the selection
  192. selection="${@}"
  193. else
  194. # Otherwise, use the CLI passed choice if given
  195. if [ -n "${selectionID+x}" ]
  196. then
  197. selection="${messages[$selectionID]}"
  198. fi
  199. fi
  200. # Don't allow custom entries
  201. echo -e "\0no-custom\x1ftrue"
  202. # Use markup
  203. echo -e "\0markup-rows\x1ftrue"
  204. if [ -z "${selection+x}" ]
  205. then
  206. echo -e "\0prompt\x1fPower menu"
  207. for entry in "${show[@]}"
  208. do
  209. echo -e "${messages[$entry]}\0icon\x1f${icons[$entry]}"
  210. done
  211. else
  212. for entry in "${show[@]}"
  213. do
  214. if [ "$selection" = "$(print_selection "${messages[$entry]}")" ]
  215. then
  216. # Check if the selected entry is listed in confirmation requirements
  217. for confirmation in "${confirmations[@]}"
  218. do
  219. if [ "$entry" = "$confirmation" ]
  220. then
  221. # Ask for confirmation
  222. echo -e "\0prompt\x1fAre you sure"
  223. echo -e "${confirmationMessages[$entry]}\0icon\x1f${icons[$entry]}"
  224. echo -e "${confirmationMessages[cancel]}\0icon\x1f${icons[cancel]}"
  225. exit 0
  226. fi
  227. done
  228. # If not, then no confirmation is required, so mark confirmed
  229. selection=$(print_selection "${confirmationMessages[$entry]}")
  230. fi
  231. if [ "$selection" = "$(print_selection "${confirmationMessages[$entry]}")" ]
  232. then
  233. if [ $dryrun = true ]
  234. then
  235. # Tell what would have been done
  236. echo "Selected: $entry" >&2
  237. else
  238. # Perform the action
  239. ${actions[$entry]}
  240. fi
  241. exit 0
  242. fi
  243. if [ "$selection" = "$(print_selection "${confirmationMessages[cancel]}")" ]
  244. then
  245. # Do nothing
  246. exit 0
  247. fi
  248. done
  249. # The selection didn't match anything, so raise an error
  250. echo "Invalid selection: $selection" >&2
  251. exit 1
  252. fi