rotate-screen 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. #!/bin/sh
  2. #
  3. # One-shot automatic screen rotation
  4. #
  5. # If the attached keyboard is switched off, whenever the tablet is
  6. # rotated, it is best to put this command into the panel, because
  7. # hotkeys do not work.
  8. #
  9. # On Cinnamon, the 'Command Launcher' add-on can be used with the
  10. # following settings:
  11. # Panel Icon: rotation-allowed-symbolic
  12. # Tooltip: Set screen rotation
  13. # Keyboard shortcut: unassigned | unassigned
  14. # Show notification on completion: NO
  15. # Command: rotate-screen
  16. # Run as root: NO
  17. # Run in alternate directory: NO
  18. #
  19. # A possible .desktop file can look like this:
  20. # [Desktop Entry]
  21. # Encoding=UTF-8
  22. # Version=1.0
  23. # Name=Rotate
  24. # Comment=Rotate Screen
  25. # Type=Application
  26. # Exec=rotate-screen
  27. # Icon=rotation-allowed-symbolic
  28. # Terminal=false
  29. # Categories=Settings
  30. # StartupNotify=true
  31. # and could be saved in ~/.local/share/applications/rotate-screen.desktop
  32. #
  33. #
  34. # Anchestors and ideas:
  35. # mildmojo
  36. # https://gist.github.com/mildmojo/48e9025070a2ba40795c
  37. # mbinnun:
  38. # https://gist.github.com/mildmojo/48e9025070a2ba40795c#gistcomment-2694429
  39. # frgomes:
  40. # https://github.com/frgomes/bash-scripts/blob/develop/bin/rotate
  41. #
  42. #
  43. # MIT License
  44. #
  45. # Copyright (c) 2021 Stephan Helma
  46. #
  47. # Permission is hereby granted, free of charge, to any person obtaining a copy
  48. # of this software and associated documentation files (the "Software"), to deal
  49. # in the Software without restriction, including without limitation the rights
  50. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  51. # copies of the Software, and to permit persons to whom the Software is
  52. # furnished to do so, subject to the following conditions:
  53. #
  54. # The above copyright notice and this permission notice shall be included in all
  55. # copies or substantial portions of the Software.
  56. #
  57. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  58. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  59. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  60. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  61. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  62. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  63. # SOFTWARE.
  64. GDBUS=gdbus
  65. XINPUT=xinput
  66. XRANDR=xrandr
  67. usage () {
  68. # Display the usage
  69. #
  70. # No options
  71. cat <<EOF
  72. $(basename $0) [-h|--help] [screen|next|previous|normal|left|inverted|right]
  73. Rotate the screen and all pointing devices (touchscreens, pens, touchpads, ...)
  74. The script can handle the following typical use cases:
  75. 1. One-shot rotation (automatic detection):
  76. You hold the device in the new orientation desired and invoke this script.
  77. The screen and all pointing devices rotate.
  78. Usage:
  79. - Disable automatic screen rotation in the settings for your desktop
  80. environment.
  81. - Hold the device in the new orientation and call this script with "$0".
  82. Pre-requisites:
  83. Programs: $GDBUS, $XINPUT, $XRANDR
  84. Hardware: Accelerometer
  85. Package: iio-sensor-proxy
  86. 2. Automatic screen rotation, but pointing devices do not rotate:
  87. The orientation of the screen is set by the desktop environment, but the
  88. pointing devices are not.
  89. Usage:
  90. - Enable automatic screen rotation in the settings for your desktop
  91. environment.
  92. - Hold the device in the new orientation and call this script with
  93. "$0 screen".
  94. Pre-requisites:
  95. Programs: $XINPUT, $XRANDR
  96. Hardware: --
  97. Package: --
  98. 3. Cycle through screen rotations:
  99. The orientation of the screen is cycled through normal -> left -> inverted
  100. -> right -> normal (option "next") or in reversed order (option "previous")
  101. with each call of this script.
  102. Usage:
  103. - Disable automatic screen rotation in the settings for your desktop
  104. environment.
  105. - Call this script with "$0 next|previous".
  106. Pre-requisites:
  107. Programs: $XINPUT, $XRANDR
  108. Hardware: --
  109. Package: --
  110. 4. One-shot rotation (manual):
  111. Independent of the actual orientation of the device, the orientation is
  112. set to the given orientation.
  113. Usage:
  114. - Disable automatic screen rotation in the settings for your desktop
  115. environment.
  116. - Call this script with "$0 normal|inverted|left|right".
  117. Pre-requisites:
  118. Programs: $XINPUT, $XRANDR
  119. Hardware: --
  120. Package: --
  121. Note:
  122. Sometimes not all pointing devices are rotated. The reason is, that the
  123. pointing device was not active at the time of rotation, as can happen with
  124. e.g. bluetooth pens. In that case simply call the script again with the
  125. same parameter.
  126. Parameters:
  127. -h, --help Display this help and exit.
  128. screen, next, normal, left, inverted, right
  129. The new orientation (optional). The default behaviour (no
  130. option) is to use the orientation from the built-in
  131. accelerometer. If 'screen' is given, use the screen's
  132. current orientation. 'next' will switch to the next
  133. orientation and any other option switches to the specified
  134. orientation, regardless of the device's or the screen's
  135. actual orientation.
  136. EOF
  137. }
  138. check_commands () {
  139. # Check for commands needed
  140. #
  141. # $1: The required orientation
  142. if test $1 = auto; then
  143. GDBUS=$(which $GDBUS)
  144. if test -z $GDBUS; then
  145. echo "Command 'gdbus' not found."
  146. exit 10
  147. fi
  148. fi
  149. XINPUT=$(which $XINPUT)
  150. if test -z $XINPUT; then
  151. echo "Command 'xinput' not found."
  152. exit 11
  153. fi
  154. XRANDR=$(which $XRANDR)
  155. if test -z $XRANDR; then
  156. echo "Command 'xrandr' not found."
  157. exit 12
  158. fi
  159. }
  160. get_dbus_orientation () {
  161. # Get the orientation from the DBus
  162. #
  163. # No options.
  164. # DBus to query to get the current orientation
  165. DBUS="--system --dest net.hadess.SensorProxy --object-path /net/hadess/SensorProxy"
  166. # Check, if DBus is available
  167. ORIENTATION=$($GDBUS call $DBUS \
  168. --method org.freedesktop.DBus.Properties.Get \
  169. net.hadess.SensorProxy HasAccelerometer)
  170. if test $? != 0; then
  171. echo $ORIENTATION
  172. echo " (Is the 'iio-sensor-proxy' package installed and enabled?)"
  173. exit 20
  174. elif test "$ORIENTATION" != "(<true>,)"; then
  175. echo "No sensor available!"
  176. echo " (Does the computer has a hardware accelerometer?)"
  177. exit 21
  178. fi
  179. # Get the orientation from the DBus
  180. ORIENTATION=$($GDBUS call $DBUS \
  181. --method org.freedesktop.DBus.Properties.Get \
  182. net.hadess.SensorProxy AccelerometerOrientation)
  183. # Release the DBus
  184. $GDBUS call --system $DBUS --method net.hadess.SensorProxy.ReleaseAccelerometer > /dev/null
  185. # Normalize the orientation
  186. case $ORIENTATION in
  187. "(<'normal'>,)")
  188. ORIENTATION=normal
  189. ;;
  190. "(<'bottom-up'>,)")
  191. ORIENTATION=inverted
  192. ;;
  193. "(<'left-up'>,)")
  194. ORIENTATION=left
  195. ;;
  196. "(<'right-up'>,)")
  197. ORIENTATION=right
  198. ;;
  199. *)
  200. echo "Orientation $ORIENTATION unknown!"
  201. echo " (Known orientations are: normal, bottom-up, left-up and right-up.)"
  202. exit 22
  203. esac
  204. # Return the orientation found
  205. echo $ORIENTATION
  206. }
  207. get_screen_orientation () {
  208. # Get the orientation from the current screen orientation
  209. #
  210. # $1: The screen
  211. ORIENTATION=$($XRANDR --current --verbose | grep $1 | cut --delimiter=" " -f6)
  212. case $ORIENTATION in
  213. normal|inverted|left|right)
  214. ;;
  215. *)
  216. echo "Current screen orientation $ORIENTATION unknown!"
  217. exit 23
  218. ;;
  219. esac
  220. # Return the orientation found
  221. echo $ORIENTATION
  222. }
  223. do_rotate () {
  224. # Rotate screen and pointers
  225. #
  226. # $1: The requested mode (only "screen" gets a special treatment)
  227. # $2: The new orientation
  228. # $3: The screen to rotate
  229. # $4-: The pointers to rotate
  230. TRANSFORM='Coordinate Transformation Matrix'
  231. MODE=$1
  232. shift
  233. ORIENTATION=$1
  234. shift
  235. # Rotate the screen
  236. if test $MODE != screen; then
  237. # Only rotate it, if we have not got the orientation from the screen
  238. $XRANDR --output $1 --rotate $ORIENTATION
  239. fi
  240. shift
  241. # Rotate all pointers
  242. while test $# -gt 0; do
  243. case $ORIENTATION in
  244. normal)
  245. $XINPUT set-prop $1 "$TRANSFORM" 1 0 0 0 1 0 0 0 1
  246. ;;
  247. inverted)
  248. $XINPUT set-prop $1 "$TRANSFORM" -1 0 1 0 -1 1 0 0 1
  249. ;;
  250. left)
  251. $XINPUT set-prop $1 "$TRANSFORM" 0 -1 1 1 0 0 0 0 1
  252. ;;
  253. right)
  254. $XINPUT set-prop $1 "$TRANSFORM" 0 1 0 -1 0 1 0 0 1
  255. ;;
  256. esac
  257. shift
  258. done
  259. }
  260. # Process the command line options
  261. MODE=auto
  262. while true; do
  263. case $1 in
  264. -h|--help)
  265. usage
  266. exit
  267. ;;
  268. *)
  269. if test $# -eq 0; then
  270. break
  271. fi
  272. MODE=$1
  273. shift
  274. ;;
  275. esac
  276. done
  277. # Check, if all commands, which are needed, are available
  278. check_commands $MODE
  279. # Get the display
  280. XDISPLAY=$($XRANDR --current --verbose | grep primary | cut --delimiter=" " -f1)
  281. # Get the tablet's orientation
  282. case $MODE in
  283. auto)
  284. ORIENTATION=$(get_dbus_orientation)
  285. ret=$?
  286. if test $ret != 0; then
  287. echo $ORIENTATION
  288. echo "(To use this script, supply the orientation normal, inverted, left or right on the command line.)"
  289. exit $ret
  290. fi
  291. ;;
  292. screen)
  293. ORIENTATION=$(get_screen_orientation $XDISPLAY)
  294. ret=$?
  295. if test $ret != 0; then
  296. echo $ORIENTATION
  297. exit $ret
  298. fi
  299. ;;
  300. next)
  301. ORIENTATION=$(get_screen_orientation $XDISPLAY)
  302. ret=$?
  303. if test $ret != 0; then
  304. echo $ORIENTATION
  305. exit $ret
  306. fi
  307. case $ORIENTATION in
  308. normal)
  309. ORIENTATION=left
  310. ;;
  311. left)
  312. ORIENTATION=inverted
  313. ;;
  314. inverted)
  315. ORIENTATION=right
  316. ;;
  317. right)
  318. ORIENTATION=normal
  319. ;;
  320. *)
  321. ORIENTATION=normal
  322. ;;
  323. esac
  324. ;;
  325. previous)
  326. ORIENTATION=$(get_screen_orientation $XDISPLAY)
  327. ret=$?
  328. if test $ret != 0; then
  329. echo $ORIENTATION
  330. exit $ret
  331. fi
  332. case $ORIENTATION in
  333. normal)
  334. ORIENTATION=right
  335. ;;
  336. left)
  337. ORIENTATION=normal
  338. ;;
  339. inverted)
  340. ORIENTATION=left
  341. ;;
  342. right)
  343. ORIENTATION=inverted
  344. ;;
  345. *)
  346. ORIENTATION=normal
  347. ;;
  348. esac
  349. ;;
  350. normal|inverted|left|right)
  351. ORIENTATION=$MODE
  352. ;;
  353. *)
  354. echo "Unknown command line parameter orientation $MODE"
  355. exit 1
  356. esac
  357. # Get all pointers
  358. POINTERS=$($XINPUT | grep slave | grep pointer | sed -e 's/^.*id=\([[:digit:]]\+\).*$/\1/')
  359. # Rotate the screen and pointers
  360. echo "Rotate display $XDISPLAY to $ORIENTATION orientation (Pointers: $(echo $POINTERS | sed 's/\n/ /g'))"
  361. do_rotate $MODE $ORIENTATION $XDISPLAY $POINTERS