├── .gitignore ├── LICENSE ├── Makefile ├── NOTICE ├── README ├── README.md ├── xrasengan └── xrasengan_complete /.gitignore: -------------------------------------------------------------------------------- 1 | # Editor backups # 2 | *~ 3 | \#*# 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT := xrasengan 2 | BIN := /usr/bin 3 | COMPLETE:= $(PROJECT)_complete 4 | COMPPATH:= /usr/share/bash-completion/completions 5 | 6 | .PHONY: install 7 | 8 | install: 9 | @echo \* Installing 10 | sudo cp $(PROJECT) $(BIN) 11 | sudo chmod 755 $(BIN)/$(PROJECT) 12 | sudo cp $(COMPLETE) $(COMPPATH)/$(PROJECT) 13 | sudo chmod 644 $(COMPPATH)/$(PROJECT) 14 | @echo \* Done 15 | @echo \* For help: xrasengan --help 16 | 17 | uninstall: 18 | @echo \* Uninstalling 19 | sudo rm $(BIN)/$(PROJECT) 20 | sudo rm $(COMPPATH)/$(PROJECT) 21 | @echo \* Done 22 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2014 Geyslan G. Bem 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | See README.md 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | xrasengan 2 | ========= 3 | 4 | An xrandr wrapper to make your multi-monitor setup easier 5 | 6 | Installation/Uninstallation 7 | --------------------------- 8 | 9 | `make install` 10 | 11 | `make uninstall` 12 | 13 | If not root, you will need do it as a sudo user. 14 | 15 | 16 | Usage 17 | ----- 18 | 19 | `xrasengan --force --on DisplayPort-0 --off HDMI-0` 20 | 21 | `xrasengan --list-all` 22 | 23 | `xrasengan --list-connected` 24 | 25 | `xrasengan --clone HDMI-0` 26 | 27 | `xrasengan -c DisplayPort-0 HDMI-0` 28 | 29 | `xrasengan -tral` - try that before through your displayport monitor out the window 30 | 31 | 32 | See all options through: 33 | ------------------------ 34 | 35 | `xrasengan --help` 36 | 37 | `xrasengan --h` 38 | -------------------------------------------------------------------------------- /xrasengan: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # -*- mode: sh -*- 4 | 5 | # 6 | # Copyright 2014 Geyslan G. Bem 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | # 22 | # xrasengan - An xrandr wrapper to make your multi-monitor setup easier 23 | # 24 | 25 | script=xrasengan 26 | xrandr=$(which xrandr 2> /dev/null) 27 | awk=$(which awk 2> /dev/null) 28 | who=$(which who 2> /dev/null) 29 | unxrandr=$(which unxrandr 2> /dev/null) 30 | notifier=$(which notify-send 2> /dev/null) 31 | force="" 32 | display=$DISPLAY 33 | 34 | set_display() { 35 | if ! [[ $display ]]; then 36 | local tty 37 | local pids 38 | tty=$(cat /sys/class/tty/tty0/active) 39 | pids=$(ps u | $awk "/$tty/ { print \$2 }") 40 | 41 | for pid in $pids 42 | do 43 | display=$($awk -v RS='\0' -F= "/DISPLAY/ { print \$2 }" /proc/"$pid"/environ 2>/dev/null) 44 | [[ "$display" != "" ]] && break 45 | done 46 | fi 47 | } 48 | set_display 49 | 50 | notify() { 51 | $notifier "$@" 52 | } 53 | 54 | if ! [ -x "$notifier" ] || [ "$display" == "" ]; then 55 | notifier="echo" 56 | else 57 | notifier="$notifier -i video-display $script" 58 | fi 59 | 60 | if ! [[ $display ]]; then 61 | notify "display was not found" 62 | exit 2 63 | fi 64 | 65 | if ! [ -x "$xrandr" ]; then 66 | notify "$script uses xrandr. Please, install it" 67 | exit 2 68 | fi 69 | xrandr="$xrandr -d $display" 70 | 71 | 72 | if ! [ -x "$awk" ]; then 73 | notify "$script uses awk. Please, install it" 74 | exit 2 75 | fi 76 | 77 | if ! [ -x "$who" ]; then 78 | notify "$script uses who. Please, install it" 79 | exit 2 80 | fi 81 | 82 | if ! [ -x "$unxrandr" ]; then 83 | notify "$script uses unxrandr that is part of arandr. Please, install it" 84 | exit 2 85 | fi 86 | 87 | error_clone="clone option demands one or two outputs 88 | When one: all connected outputs will be a clone of the informed output 89 | $0 --clone HDMI-0 90 | 91 | When two: the second output will be a clone of the first 92 | $0 -c HDMI-0 HDMI-1" 93 | 94 | error_turn_on="turn-on option demands one or two arguments 95 | When one: the informed output will be turned on with xrandr --auto option 96 | $0 --turn-on HDMI-0 97 | When two: the informed output will be turned on with the informed --mode 98 | $0 -on DisplayPort-0 1920x1080" 99 | 100 | error_turn_off="turn-off option demands one argument 101 | The informed output will be turned off with xrandr --off option 102 | $0 --turn-off HDMI-0 103 | Or 104 | $0 -off DisplayPort-0" 105 | 106 | error_left="left option demands two arguments 107 | First is the base output, second is the one to be on the left side of the base output 108 | Here, HDMI-0 is the base and DVI-1 the left 109 | $0 --left HDMI-0 DVI-1" 110 | 111 | error_right="right option demands two arguments 112 | First is the base output, second is the one to be on the right side of the base output 113 | Here, HDMI-0 is the base and DVI-1 the right 114 | $0 --right HDMI-0 DVI-1" 115 | 116 | error_above="above option demands two arguments 117 | First is the base output, second is the one to be on the above side of the base output 118 | Here, HDMI-0 is the base and DVI-1 the above 119 | $0 --above HDMI-0 DVI-1" 120 | 121 | error_below="below option demands two arguments 122 | First is the base output, second is the one to be on the below side of the base output 123 | Here, HDMI-0 is the base and DVI-1 the below 124 | $0 --below HDMI-0 DVI-1" 125 | 126 | error_primary="primary option demands one argument 127 | The informed output will be set as primary with xrandr --primary option 128 | $0 --primary HDMI-0 129 | or 130 | $0 -p DisplayPort-0" 131 | 132 | invalid_argument() { 133 | notify "$@" 134 | exit 22 135 | } 136 | 137 | list_contains() { 138 | local list=$1 139 | local value=$2 140 | 141 | for word in $list; do 142 | [ "$word" == "$value" ] && return 0 143 | done 144 | return 1 145 | } 146 | 147 | workaround() { 148 | # Workaround to turn on connected outputs that may be in suspend mode 149 | # and hence shown as disconnected 150 | local seconds=$1 151 | 152 | $xrandr 1> /dev/null 153 | sleep "$seconds" 154 | $xrandr 1> /dev/null 155 | } 156 | 157 | update_outputs_all() { 158 | if ! [[ $force ]]; then 159 | outputs_all=$($xrandr | $awk "/connected/ { print \$1 }") 160 | return 161 | fi 162 | 163 | workaround 3 164 | outputs_all=$($xrandr | $awk "/connected/ { print \$1 }") 165 | } 166 | 167 | update_outputs_all_num() { 168 | outputs_all_num=$(echo "$outputs_all" | wc -w) 169 | } 170 | 171 | update_outputs_connected() { 172 | outputs_connected=$($xrandr | $awk "/ connected/ { print \$1 }") 173 | } 174 | 175 | update_outputs_active() { 176 | outputs_active=$($xrandr | $awk "/mm$/ { print \$1 }") 177 | } 178 | 179 | update_outputs_active_num() { 180 | outputs_active_num=$(echo "$outputs_active" | wc -w) 181 | } 182 | 183 | update_outputs_disconnected() { 184 | outputs_disconnected=$($xrandr | $awk "/disconnected/ { print \$1 }") 185 | } 186 | 187 | is_mode_available() { 188 | if ! [ "$1" ] || ! [ "$2" ]; then 189 | invalid_argument "${FUNCNAME[0]}: needs two arguments (output and mode)" 190 | fi 191 | 192 | local output=$1 193 | local modes 194 | modes=$($xrandr | $awk '/'"$output"'/{f=1;next} !/^ /{f=0} f {print $1}') 195 | 196 | if ! list_contains "$modes" "$2"; then 197 | return 1 198 | else 199 | return 0 200 | fi 201 | } 202 | 203 | check_output_valid() { 204 | if ! [ "$1" ]; then 205 | invalid_argument "${FUNCNAME[0]}: needs one argument" 206 | fi 207 | 208 | if ! list_contains "$outputs_all" "$1"; then 209 | return 1 210 | else 211 | return 0 212 | fi 213 | } 214 | 215 | check_output_connected() { 216 | if ! [ "$1" ]; then 217 | invalid_argument "${FUNCNAME[0]}: needs one argument" 218 | fi 219 | 220 | if ! check_output_valid "$1"; then 221 | invalid_argument "$1 is not a valid output" 222 | fi 223 | 224 | if ! list_contains "$outputs_connected" "$1"; then 225 | return 1 226 | else 227 | return 0 228 | fi 229 | } 230 | 231 | check_output_active() { 232 | if ! [ "$1" ]; then 233 | invalid_argument "${FUNCNAME[0]}: needs one argument" 234 | fi 235 | 236 | if ! check_output_connected "$1"; then 237 | invalid_argument "$1 is not a connected output" 238 | fi 239 | 240 | if ! list_contains "$outputs_active" "$1"; then 241 | return 1 242 | else 243 | return 0 244 | fi 245 | } 246 | 247 | clone() { 248 | if [ $# -eq 0 ] || [ $# -gt 2 ]; then 249 | invalid_argument "$error_clone" 250 | fi 251 | 252 | check_output_active "$1" 253 | 254 | if [ "$2" ]; then 255 | check_output_connected "$2" 256 | $xrandr --output "$2" --auto --same-as "$1" --auto 257 | else 258 | $xrandr --output "$1" --primary 259 | for output in $outputs_connected 260 | do 261 | if [ "$output" != "$1" ]; then 262 | $xrandr --output "$output" --auto --same-as "$1" --auto 263 | fi 264 | done 265 | fi 266 | } 267 | 268 | turn_on() { 269 | if [ $# -eq 0 ] || [ $# -gt 2 ]; then 270 | invalid_argument "$error_turn_on" 271 | fi 272 | 273 | check_output_active "$1" 274 | 275 | if [ "$2" ]; then 276 | if ! is_mode_available "$1" "$2"; then 277 | invalid_argument "$2 is not an available mode for $1 output" 278 | fi 279 | $xrandr --output "$1" --mode "$2" --auto 280 | else 281 | $xrandr --output "$1" --auto 282 | fi 283 | } 284 | 285 | turn_off() { 286 | if [ $# -ne 1 ]; then 287 | invalid_argument "$error_turn_off" 288 | fi 289 | 290 | if ! check_output_active "$1"; then 291 | invalid_argument "$1 is already an inactive output" 292 | fi 293 | 294 | if [ "$outputs_active_num" -eq 1 ]; then 295 | invalid_argument "$1 is the unique active output. It's impossible to turn it off" 296 | fi 297 | 298 | $xrandr --output "$1" --off 299 | } 300 | 301 | left() { 302 | if [ $# -ne 2 ]; then 303 | invalid_argument "$error_left" 304 | fi 305 | 306 | if ! check_output_active "$1"; then 307 | invalid_argument "$1 is not an active output" 308 | fi 309 | 310 | check_output_connected "$2" 311 | $xrandr --output "$2" --auto --left-of "$1" --auto 312 | } 313 | 314 | right() { 315 | if [ $# -ne 2 ]; then 316 | invalid_argument "$error_right" 317 | fi 318 | 319 | if ! check_output_active "$1"; then 320 | invalid_argument "$1 is not an active output" 321 | fi 322 | 323 | check_output_connected "$2" 324 | $xrandr --output "$2" --auto --right-of "$1" --auto 325 | } 326 | 327 | above() { 328 | if [ $# -ne 2 ]; then 329 | invalid_argument "$error_above" 330 | fi 331 | 332 | if ! check_output_active "$1"; then 333 | invalid_argument "$1 is not an active output" 334 | fi 335 | 336 | check_output_connected "$2" 337 | $xrandr --output "$2" --auto --above "$1" --auto 338 | } 339 | 340 | below() { 341 | if [ $# -ne 2 ]; then 342 | invalid_argument "$error_below" 343 | fi 344 | 345 | if ! check_output_active "$1"; then 346 | invalid_argument "$1 is not an active output" 347 | fi 348 | 349 | check_output_connected "$2" 350 | $xrandr --output "$2" --auto --below "$1" --auto 351 | } 352 | 353 | primary() { 354 | if [ $# -ne 1 ]; then 355 | invalid_argument "$error_primary" 356 | fi 357 | 358 | if ! check_output_active "$1"; then 359 | invalid_argument "$1 is not an active output" 360 | fi 361 | 362 | $xrandr --output "$1" --primary 363 | } 364 | 365 | try_reload_current_layout() { 366 | local command="" 367 | 368 | command=$(DISPLAY=$display $unxrandr) 369 | 370 | workaround 3 371 | 372 | if ! [[ $command ]]; then 373 | notify "$unxrandr could not retrieve current layout" 374 | exit 2 375 | fi 376 | 377 | command="$xrandr ${command/xrandr/}" 378 | 379 | $command 380 | 381 | ret=$? 382 | if ! [ $ret == 0 ]; then 383 | notify "ERROR in $command (RETURN VALUE: $ret)" 384 | exit 22 385 | fi 386 | } 387 | 388 | usage() { 389 | echo "usage: $script [options] 390 | where options are: 391 | --help or -h 392 | --force or -f (workaround to turn on suspended outputs; will hang for 3 seconds) 393 | --force-only or -fo (same as --force/-fo but as a single option) 394 | --try-reload-active-layout or -tral (uses force and unxrandr) 395 | --list-all or -la 396 | --list-connected or -lc 397 | --list-active or -lac 398 | --list-disconnected or -ld 399 | --clone or -c 400 | --turn-on or -on 401 | --turn-off or -off 402 | --left or -l 403 | --right or -r 404 | --above or -a 405 | --below or -b 406 | --primary or -p " 407 | } 408 | 409 | 410 | if [[ $# -eq 0 ]] || list_contains "$*" "--help" || list_contains "$*" "-h"; then 411 | usage 412 | exit 0 413 | fi 414 | 415 | if list_contains "$*" "--force" || list_contains "$*" "-f"; then 416 | set -- ${@/--force/} 417 | set -- ${@/-f/} 418 | force="force"; 419 | if [[ $# -eq 0 ]]; then 420 | usage 421 | exit 0 422 | fi 423 | fi 424 | 425 | if list_contains "$*" "--force-only" || list_contains "$*" "-fo"; then 426 | set -- ${@/--force-only/} 427 | set -- ${@/-fo/} 428 | force="force" 429 | if [[ $# -gt 0 ]]; then 430 | usage 431 | exit 0 432 | fi 433 | 434 | workaround 3 435 | notify "successful force" 436 | exit 0 437 | fi 438 | 439 | if list_contains "$*" "--try-reload-active-layout" || list_contains "$*" "-tral"; then 440 | set -- ${@/--try-reload-active-layout/} 441 | set -- ${@/-tral/} 442 | 443 | if [[ $# -gt 0 ]]; then 444 | usage 445 | exit 0 446 | fi 447 | 448 | try_reload_current_layout 449 | notify "current layout reloaded" 450 | exit 0 451 | fi 452 | 453 | 454 | 455 | update_outputs_all 456 | update_outputs_all_num 457 | update_outputs_connected 458 | update_outputs_disconnected 459 | 460 | if [ "$outputs_all_num" -eq 1 ]; then 461 | notify "You have only one output! $script can't do nothing for you! 462 | For more options use xrandr. Bye!" 463 | exit 0 464 | fi 465 | 466 | while [[ $# -ge 1 ]] 467 | do 468 | key="$1" 469 | shift 470 | 471 | update_outputs_active 472 | update_outputs_active_num 473 | 474 | case $key in 475 | --list-all | -la) 476 | echo "$outputs_all" 477 | ;; 478 | --list-connected | -lc) 479 | echo "$outputs_connected" 480 | ;; 481 | --list-active | -lac) 482 | echo "$outputs_active" 483 | ;; 484 | --list-disconnected | -ld) 485 | echo "$outputs_disconnected" 486 | ;; 487 | --clone | -c) 488 | if [[ $2 ]] && ! [[ $2 == -* ]]; then 489 | clone "$1" "$2" 490 | notify "$2 is clone of $1" 491 | shift 492 | else 493 | clone "$1" 494 | notify "$1 cloned" 495 | fi 496 | shift 497 | ;; 498 | --turn-on | -on) 499 | if [[ $2 ]] && ! [[ $2 == -* ]]; then 500 | turn_on "$1" "$2" 501 | notify "$1 turned on with mode $2" 502 | shift 503 | else 504 | turn_on "$1" 505 | notify "$1 turned on" 506 | fi 507 | shift 508 | ;; 509 | --turn-off | -off) 510 | turn_off "$1" 511 | notify "$1 turned off" 512 | shift 513 | ;; 514 | --left | -l) 515 | left "$1" "$2" 516 | notify "$2 is on left of $1" 517 | shift 2 518 | ;; 519 | --right | -r) 520 | right "$1" "$2" 521 | notify "$2 is on right of $1" 522 | shift 2 523 | ;; 524 | --above | -a) 525 | above "$1" "$2" 526 | notify "$2 is above of $1" 527 | shift 2 528 | ;; 529 | --below | -b) 530 | below "$1" "$2" 531 | notify "$2 is below of $1" 532 | shift 2 533 | ;; 534 | --primary | -p) 535 | primary "$1" 536 | notify "$1 set as primary" 537 | shift 538 | ;; 539 | *) 540 | usage 541 | break 542 | ;; 543 | esac 544 | done 545 | 546 | -------------------------------------------------------------------------------- /xrasengan_complete: -------------------------------------------------------------------------------- 1 | # -*- mode: sh -*- 2 | 3 | # 4 | # Copyright 2015 Geyslan G. Bem 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | # 20 | # xrasengan bash completion 21 | # 22 | 23 | #!/bin/bash 24 | 25 | list_contains() { 26 | local list=$1 27 | local value=$2 28 | 29 | for word in $list; do 30 | [[ $word == "$value" ]] && return 0 31 | done 32 | return 1 33 | } 34 | 35 | update_outputs_connected() { 36 | if ! [[ $force ]]; then 37 | OPTS="$(xrandr | awk '/ connected/ {print $1}')" 38 | return 39 | fi 40 | 41 | # Workaround to turn on connected outputs that may be in suspend mode 42 | # and hence shown as disconnected 43 | local times=2 44 | local seconds=1 45 | 46 | while [ $times -gt 0 ]; do 47 | xrandr 1> /dev/null 48 | sleep $seconds 49 | let times-=1 50 | done 51 | OPTS="$(xrandr | awk '/ connected/ {print $1}')" 52 | } 53 | 54 | update_outputs_connected_inactive() { 55 | OPTS="$(xrandr | awk '/ connected/ && /\)$/ {print $1}')" 56 | } 57 | 58 | update_outputs_active() { 59 | OPTS="$(xrandr | awk '/mm$/ {print $1}')" 60 | } 61 | 62 | update_output_modes() { 63 | local output="$1" 64 | OPTS="$(xrandr | awk '/'$output'/ {f=1;next} !/^ /{f=0} f {print $1}')" 65 | } 66 | 67 | _xrasengan() 68 | { 69 | local cur prev prev_prev OPTS 70 | COMREPLY=() 71 | cur="${COMP_WORDS[COMP_CWORD]}" 72 | prev="${COMP_WORDS[COMP_CWORD-1]}" 73 | prev_prev="${COMP_WORDS[COMP_CWORD-2]}" 74 | 75 | if list_contains "${COMP_WORDS[*]}" "--force" || list_contains "${COMP_WORDS[*]}" "-f"; then 76 | force="force" 77 | else 78 | force="" 79 | fi 80 | 81 | case $cur in 82 | --*) 83 | OPTS=$(echo "--force --force-only --try-reload-active-layout --help --list-all --list-connected --list-active --list-disconnected --clone --turn-on --turn-off --left --right --above --below --primary" | sort) 84 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) 85 | return 0 86 | ;; 87 | -*) 88 | OPTS=$(echo "-f -fo -tral -h -la -lc -lac -ld -c -on -off -l -r -a -b -p" | sort) 89 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) 90 | return 0 91 | ;; 92 | 93 | esac 94 | 95 | update_outputs_connected 96 | 97 | case $prev in 98 | --clone | -c | --turn-off | -off | --left | -l | --right | -r | --above | -a | --below | -b | --primary | -p) 99 | update_outputs_active 100 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) 101 | return 0 102 | ;; 103 | --turn-on | -on) 104 | update_outputs_connected_inactive 105 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) 106 | return 0 107 | ;; 108 | 109 | esac 110 | 111 | case $prev_prev in 112 | --clone | -c | --left | -l | --right | -r | --above | -a | --below | -b) 113 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) 114 | return 0 115 | ;; 116 | --turn-on | -on) 117 | update_output_modes "$prev" 118 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") ) 119 | return 0 120 | ;; 121 | esac 122 | 123 | } 124 | complete -F _xrasengan xrasengan 125 | 126 | --------------------------------------------------------------------------------