├── LICENSE ├── README.md └── xscreenrotater /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Brodie Robertson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Xscreenrotater is a simple script with a simple goal, to rotate your X11 display. 3 | 4 | Inspired by this blog post from 2021 https://sprocketfox.io/xssfox/2021/12/02/xrandr/ 5 |
6 | 7 | ## Dependencies 8 | 9 | * Python3 10 | * An X11 Server 11 | * Xrandr 12 | 13 | ## Installation 14 | 15 | Clone the repo `git clone https://github.com/BrodieRobertson/xscreenrotater.git`. 16 | 17 | Make it executable `chmod +x xscreenrotater`. 18 | 19 | Add it to your path if you want to. 20 | 21 | ## FAQ 22 | 23 | ### How do I find the name of my display? 24 | 25 | Run Xrandr, look for the monitor your want to rotate. 26 | 27 | ### Does this work on Wayland? 28 | 29 | No. 30 | 31 | ### Will this damage my computer? 32 | 33 | Maybe, I wouldn't suggest running it for long, after a short while it causes my display to flicker. 34 | 35 | ### Isn't this basically malware? 36 | 37 | Yes. 38 | -------------------------------------------------------------------------------- /xscreenrotater: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Rotates your X11 display, the standard operation mode will continuously rotate the display but 5 | specific rotations can also be set 6 | """ 7 | 8 | import os 9 | import sys 10 | import math 11 | import time 12 | import argparse 13 | 14 | 15 | def get_args(): 16 | """Parse and get the arguments.""" 17 | 18 | # Initialize the parser. 19 | parser = argparse.ArgumentParser( 20 | prog="Xscreenrotater", 21 | description="This script will rotate your X11 screen until you tell it to stop, " 22 | + "this is basically malware, please don't come to me if you break your PC.", 23 | ) 24 | 25 | # Add -d/--display argument to set the display. 26 | parser.add_argument( 27 | "-d", 28 | "--display", 29 | help="Which X11 display should be rotated.", 30 | metavar="DISPLAY", 31 | required=True, 32 | ) 33 | 34 | # Add -l/--left_shift argument to set the left shift. 35 | parser.add_argument( 36 | "-l", 37 | "--left_shift", 38 | help="Amount to horizontally shift the display, defaults to 0.", 39 | type=float, 40 | default=0, 41 | metavar="X", 42 | ) 43 | 44 | # Add -u/--up_shift argument to set the vertical shift. 45 | parser.add_argument( 46 | "-u", 47 | "--up_shift", 48 | help="Amount to vertically shift the display, defaults to 0.", 49 | type=float, 50 | default=0, 51 | metavar="Y", 52 | ) 53 | 54 | # Add -s/--sleep_amount argument to set the sleep time. 55 | parser.add_argument( 56 | "-s", 57 | "--sleep_amount", 58 | help="How long to wait until the next rotation is done, DON'T SET IT TO 0." 59 | + "defaults to 5", 60 | type=float, 61 | default=5, 62 | metavar="SECONDS", 63 | ) 64 | 65 | # Add -e/--degrees argument for the degrees it starts at. 66 | parser.add_argument( 67 | "-e", 68 | "--degrees", 69 | help="How many degrees should the script start at, defaults to 0.", 70 | metavar="DEGREES", 71 | default=0, 72 | ) 73 | 74 | # Add -t/--times argument for the times the screen rotates. 75 | parser.add_argument( 76 | "-t", 77 | "--times", 78 | help="How many times should the screen rotate, defaults to infinite.", 79 | metavar="TIMES", 80 | default=math.inf, 81 | type=int, 82 | ) 83 | 84 | # Add -sd/--set_degrees argument to set a display to a fixed rotation. 85 | parser.add_argument( 86 | "-sd", 87 | "--set_degrees", 88 | help="Sets the display back to specified rotation.", 89 | metavar="DEGREES", 90 | type=float, 91 | ) 92 | 93 | # Add -sl/--set_left_shift argument to set a display to a fixed left shift. 94 | parser.add_argument( 95 | "-sl", 96 | "--set_left_shift", 97 | help="Sets the display back to specified left shift.", 98 | metavar="X", 99 | type=int, 100 | ) 101 | 102 | # Add -su/--set_up_shift argument to set a display to a fixed vertical shift. 103 | parser.add_argument( 104 | "-su", 105 | "--set_up_shift", 106 | help="Sets the display back to specified vertical shift.", 107 | metavar="Y", 108 | type=int, 109 | ) 110 | 111 | # Parse the args. 112 | args = parser.parse_args() 113 | 114 | # Check if the sleep arg is valid, if not, exit with error. 115 | if args.sleep_amount <= 0: 116 | print("Please don't set the sleep amount to 0 or negative value.") 117 | sys.exit(1) 118 | 119 | return args 120 | 121 | 122 | def generate_xrandr(display, degrees, left_shift, up_shift): 123 | """Generate the xrandr command.""" 124 | radians = math.radians(degrees) 125 | return ( 126 | f"xrandr --output {display} --transform {math.cos(radians)},{-math.sin(radians)},{left_shift}," 127 | + f"{math.sin(radians)},{math.cos(radians)},{up_shift},0,0,1" 128 | ) 129 | 130 | 131 | def main(): 132 | """Do the thing.""" 133 | # Get the args. 134 | args = get_args() 135 | 136 | # Set some default values. 137 | display = args.display 138 | degrees = 0 139 | left_shift = 0 140 | up_shift = 0 141 | 142 | # Set values if not set they have one set from args. 143 | if args.set_degrees is not None: 144 | degrees = args.set_degrees 145 | if args.set_left_shift is not None: 146 | left_shift = args.set_left_shift 147 | if args.set_up_shift is not None: 148 | up_shift = args.set_up_shift 149 | 150 | # If -sd, -sl and -su are not set, do the rotation thing using the args, 151 | # else, do the rotation thing using default values/-sd value. 152 | if args.set_degrees is None and args.set_left_shift is None and args.set_up_shift is None: 153 | left_shift = args.left_shift 154 | up_shift = args.up_shift 155 | # DO NOT SET THIS TO 0! 156 | sleep_amount = args.sleep_amount 157 | count = args.degrees 158 | times = args.times 159 | while count < times: 160 | os.system(generate_xrandr(display, count, left_shift, up_shift)) 161 | count += 1 162 | time.sleep(sleep_amount) 163 | else: 164 | os.system(generate_xrandr(display, degrees, left_shift, up_shift)) 165 | 166 | 167 | if __name__ == "__main__": 168 | main() --------------------------------------------------------------------------------