├── 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()
--------------------------------------------------------------------------------