Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
6.9 KiB

  1. #!/usr/bin/env bash
  2. # _ _ _ _ _ _
  3. # __| |_ __ ___ ___ _ __ _ _ | |__ | |_ _ ___| |_ ___ ___ | |_ | |__
  4. # / _` | '_ ` _ \ / _ \ '_ \| | | |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __|| '_ \
  5. # | (_| | | | | | | __/ | | | |_| |_____| |_) | | |_| | __/ || (_) | (_) | |_ | | | |
  6. # \__,_|_| |_| |_|\___|_| |_|\__,_| |_.__/|_|\__,_|\___|\__\___/ \___/ \__||_| |_|
  7. #
  8. # Author: Nick Clyde (clydedroid)
  9. # dmenu support by: Layerex
  10. #
  11. # A script that generates a dmenu menu that uses bluetoothctl to
  12. # connect to bluetooth devices and display status info.
  13. #
  14. # Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu)
  15. # Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl)
  16. #
  17. # Depends on:
  18. # Arch repositories: dmenu, bluez-utils (contains bluetoothctl)
  19. # Checks if bluetooth controller is powered on
  20. power_on() {
  21. if bluetoothctl show | grep -q "Powered: yes"; then
  22. return 0
  23. else
  24. return 1
  25. fi
  26. }
  27. # Toggles power state
  28. toggle_power() {
  29. if power_on; then
  30. bluetoothctl power off
  31. else
  32. bluetoothctl power on
  33. fi
  34. }
  35. # Checks if controller is scanning for new devices
  36. scan_on() {
  37. if bluetoothctl show | grep -q "Discovering: yes"; then
  38. echo "Scan: on"
  39. return 0
  40. else
  41. echo "Scan: off"
  42. return 1
  43. fi
  44. }
  45. # Toggles scanning state
  46. toggle_scan() {
  47. if scan_on; then
  48. kill $(pgrep -f "bluetoothctl scan on")
  49. bluetoothctl scan off
  50. else
  51. bluetoothctl scan on &
  52. fi
  53. }
  54. # Checks if controller is able to pair to devices
  55. pairable_on() {
  56. if bluetoothctl show | grep -q "Pairable: yes"; then
  57. echo "Pairable: on"
  58. return 0
  59. else
  60. echo "Pairable: off"
  61. return 1
  62. fi
  63. }
  64. # Toggles pairable state
  65. toggle_pairable() {
  66. if pairable_on; then
  67. bluetoothctl pairable off
  68. else
  69. bluetoothctl pairable on
  70. fi
  71. }
  72. # Checks if controller is discoverable by other devices
  73. discoverable_on() {
  74. if bluetoothctl show | grep -q "Discoverable: yes"; then
  75. echo "Discoverable: on"
  76. return 0
  77. else
  78. echo "Discoverable: off"
  79. return 1
  80. fi
  81. }
  82. # Toggles discoverable state
  83. toggle_discoverable() {
  84. if discoverable_on; then
  85. bluetoothctl discoverable off
  86. else
  87. bluetoothctl discoverable on
  88. fi
  89. }
  90. # Checks if a device is connected
  91. device_connected() {
  92. device_info=$(bluetoothctl info "$1")
  93. if echo "$device_info" | grep -q "Connected: yes"; then
  94. return 0
  95. else
  96. return 1
  97. fi
  98. }
  99. # Toggles device connection
  100. toggle_connection() {
  101. if device_connected $1; then
  102. bluetoothctl disconnect $1
  103. else
  104. bluetoothctl connect $1
  105. fi
  106. }
  107. # Checks if a device is paired
  108. device_paired() {
  109. device_info=$(bluetoothctl info "$1")
  110. if echo "$device_info" | grep -q "Paired: yes"; then
  111. echo "Paired: yes"
  112. return 0
  113. else
  114. echo "Paired: no"
  115. return 1
  116. fi
  117. }
  118. # Toggles device paired state
  119. toggle_paired() {
  120. if device_paired $1; then
  121. bluetoothctl remove $1
  122. else
  123. bluetoothctl pair $1
  124. fi
  125. }
  126. # Checks if a device is trusted
  127. device_trusted() {
  128. device_info=$(bluetoothctl info "$1")
  129. if echo "$device_info" | grep -q "Trusted: yes"; then
  130. echo "Trusted: yes"
  131. return 0
  132. else
  133. echo "Trusted: no"
  134. return 1
  135. fi
  136. }
  137. # Toggles device connection
  138. toggle_trust() {
  139. if device_trusted $1; then
  140. bluetoothctl untrust $1
  141. else
  142. bluetoothctl trust $1
  143. fi
  144. }
  145. # Prints a short string with the current bluetooth status
  146. # Useful for status bars like polybar, etc.
  147. print_status() {
  148. if power_on; then
  149. printf ''
  150. mapfile -t paired_devices < <(bluetoothctl paired-devices | grep Device | cut -d ' ' -f 2)
  151. counter=0
  152. for device in "${paired_devices[@]}"; do
  153. if device_connected $device; then
  154. device_alias=$(bluetoothctl info $device | grep "Alias" | cut -d ' ' -f 2-)
  155. if [ $counter -gt 0 ]; then
  156. printf ", %s" "$device_alias"
  157. else
  158. printf " %s" "$device_alias"
  159. fi
  160. ((counter++))
  161. fi
  162. done
  163. if [ $counter -eq 0 ]; then
  164. printf " On"
  165. fi
  166. else
  167. echo " Off"
  168. fi
  169. }
  170. # A submenu for a specific device that allows connecting, pairing, and trusting
  171. device_menu() {
  172. device=$1
  173. # Get device name and mac address
  174. device_name=$(echo $device | cut -d ' ' -f 3-)
  175. mac=$(echo $device | cut -d ' ' -f 2)
  176. # Build options
  177. if device_connected $mac; then
  178. connected="Connected: yes"
  179. else
  180. connected="Connected: no"
  181. fi
  182. paired=$(device_paired $mac)
  183. trusted=$(device_trusted $mac)
  184. options="$connected\n$paired\n$trusted"
  185. # Open dmenu menu, read chosen option
  186. chosen="$(echo -e "$options" | $dmenu_command "$device_name")"
  187. # Match chosen option to command
  188. case $chosen in
  189. "")
  190. echo "No option chosen."
  191. ;;
  192. $connected)
  193. toggle_connection $mac
  194. ;;
  195. $paired)
  196. toggle_paired $mac
  197. ;;
  198. $trusted)
  199. toggle_trust $mac
  200. ;;
  201. esac
  202. }
  203. # Opens a dmenu menu with current bluetooth status and options to connect
  204. show_menu() {
  205. # Get menu options
  206. if power_on; then
  207. power="Power: on"
  208. # Human-readable names of devices, one per line
  209. # If scan is off, will only list paired devices
  210. devices=$(bluetoothctl devices | grep Device | cut -d ' ' -f 3-)
  211. # Get controller flags
  212. scan=$(scan_on)
  213. pairable=$(pairable_on)
  214. discoverable=$(discoverable_on)
  215. divider="---------"
  216. # Options passed to dmenu
  217. options="$devices\n$divider\n$power\n$scan\n$pairable\n$discoverable"
  218. else
  219. power="Power: off"
  220. options="$power"
  221. fi
  222. # Open dmenu menu, read chosen option
  223. chosen="$(echo -e "$options" | $dmenu_command "Bluetooth")"
  224. # Match chosen option to command
  225. case $chosen in
  226. "" | $divider)
  227. echo "No option chosen."
  228. ;;
  229. $power)
  230. toggle_power
  231. ;;
  232. $scan)
  233. toggle_scan
  234. ;;
  235. $discoverable)
  236. toggle_discoverable
  237. ;;
  238. $pairable)
  239. toggle_pairable
  240. ;;
  241. *)
  242. device=$(bluetoothctl devices | grep "$chosen")
  243. # Open a submenu if a device is selected
  244. if [[ $device ]]; then device_menu "$device"; fi
  245. ;;
  246. esac
  247. }
  248. # dmenu command to pipe into, can add any options here
  249. dmenu_command="dmenu -z 1900 -x 10 -y 10 -i -p"
  250. case "$1" in
  251. --status)
  252. print_status
  253. ;;
  254. *)
  255. show_menu
  256. ;;
  257. esac