mirror of
https://github.com/ralsina/xrandroll.git
synced 2024-11-24 12:02:23 +00:00
README
This commit is contained in:
parent
6c62d979c8
commit
680a350007
23
README.md
Normal file
23
README.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# RandRoll
|
||||||
|
|
||||||
|
None of the existing display configuration tools does what I think is "the right thing".
|
||||||
|
So I went and wrote one.
|
||||||
|
|
||||||
|
## The Right Thing
|
||||||
|
|
||||||
|
* Don't start from a stored config, use xrandr to read the systems' current state
|
||||||
|
* Allow creating "profiles" that will get applied smartly (not there yet)
|
||||||
|
* Generate a xrandr invocation to reflect the desired configuration
|
||||||
|
* Allow per-monitor scaling
|
||||||
|
* Allow arbitrary monitor positioning
|
||||||
|
* Implement "scale everything so all the pixels are the same size" (not done yet)
|
||||||
|
|
||||||
|
## To try:
|
||||||
|
|
||||||
|
If you have PySide2: `python main.py` in the folder where main.py is located.
|
||||||
|
|
||||||
|
## TODO:
|
||||||
|
|
||||||
|
* Implement other things
|
||||||
|
* Make it a proper app, with installation and whatnot
|
||||||
|
* Forget about it forever
|
40
main.py
40
main.py
@ -1,8 +1,9 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PySide2.QtCore import QFile, QObject, Slot
|
from PySide2.QtCore import QFile, QObject
|
||||||
from PySide2.QtUiTools import QUiLoader
|
from PySide2.QtUiTools import QUiLoader
|
||||||
from PySide2.QtWidgets import QApplication, QGraphicsScene
|
from PySide2.QtWidgets import QApplication, QGraphicsScene
|
||||||
|
|
||||||
@ -11,19 +12,20 @@ from monitor_item import MonitorItem
|
|||||||
|
|
||||||
def gen_xrandr_from_data(data):
|
def gen_xrandr_from_data(data):
|
||||||
"""Takes monitor data and generates a xrandr command line."""
|
"""Takes monitor data and generates a xrandr command line."""
|
||||||
cli = ['xrandr']
|
cli = ["xrandr"]
|
||||||
for name, mon in data.items():
|
for name, mon in data.items():
|
||||||
cli.append(f'--output {name}')
|
cli.append(f"--output {name}")
|
||||||
cli.append(f'--pos {int(mon["pos_x"])}x{int(mon["pos_y"])}')
|
cli.append(f'--pos {int(mon["pos_x"])}x{int(mon["pos_y"])}')
|
||||||
cli.append(f'--mode {mon["current_mode"]}')
|
cli.append(f'--mode {mon["current_mode"]}')
|
||||||
mod_x, mod_y = [int(n) for n in mon['current_mode'].split('x')]
|
mod_x, mod_y = [int(n) for n in mon["current_mode"].split("x")]
|
||||||
cli.append(f'--scale {mon["res_x"]/mod_x}x{mon["res_y"]/mod_y}')
|
cli.append(f'--scale {mon["res_x"]/mod_x}x{mon["res_y"]/mod_y}')
|
||||||
if mon['primary']:
|
if mon["primary"]:
|
||||||
cli.append('--primary')
|
cli.append("--primary")
|
||||||
if not mon['enabled']:
|
if not mon["enabled"]:
|
||||||
cli.append('--off')
|
cli.append("--off")
|
||||||
|
|
||||||
|
return " ".join(cli)
|
||||||
|
|
||||||
return ' '.join(cli)
|
|
||||||
|
|
||||||
def parse_monitor(line):
|
def parse_monitor(line):
|
||||||
parts = line.split()
|
parts = line.split()
|
||||||
@ -68,6 +70,7 @@ class Window(QObject):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.ui = ui
|
self.ui = ui
|
||||||
ui.show()
|
ui.show()
|
||||||
|
self.ui.setWindowTitle('Display Configuration')
|
||||||
self.ui.screenCombo.currentTextChanged.connect(self.monitor_selected)
|
self.ui.screenCombo.currentTextChanged.connect(self.monitor_selected)
|
||||||
self.xrandr_info = {}
|
self.xrandr_info = {}
|
||||||
self.get_xrandr_info()
|
self.get_xrandr_info()
|
||||||
@ -92,7 +95,7 @@ class Window(QObject):
|
|||||||
|
|
||||||
def do_apply(self):
|
def do_apply(self):
|
||||||
cli = gen_xrandr_from_data(self.xrandr_info)
|
cli = gen_xrandr_from_data(self.xrandr_info)
|
||||||
print(cli)
|
subprocess.check_call(shlex.split(cli))
|
||||||
|
|
||||||
def fill_ui(self):
|
def fill_ui(self):
|
||||||
"""Load data from xrandr and setup the whole thing."""
|
"""Load data from xrandr and setup the whole thing."""
|
||||||
@ -114,13 +117,17 @@ class Window(QObject):
|
|||||||
mode = self.ui.modes.currentText()
|
mode = self.ui.modes.currentText()
|
||||||
if not mode:
|
if not mode:
|
||||||
return
|
return
|
||||||
print(f'Changing {mon} to {mode}')
|
print(f"Changing {mon} to {mode}")
|
||||||
self.xrandr_info[mon]['current_mode'] = mode
|
self.xrandr_info[mon]["current_mode"] = mode
|
||||||
mode_x, mode_y = mode.split('x')
|
mode_x, mode_y = mode.split("x")
|
||||||
# use resolution via scaling
|
# use resolution via scaling
|
||||||
self.xrandr_info[mon]['res_x'] = int(int(mode_x) * self.ui.horizontalScale.value() / 100)
|
self.xrandr_info[mon]["res_x"] = int(
|
||||||
self.xrandr_info[mon]['res_y'] = int(int(mode_y) * self.ui.verticalScale.value() / 100)
|
int(mode_x) * self.ui.horizontalScale.value() / 100
|
||||||
self.xrandr_info[mon]['item'].update_visuals(self.xrandr_info[mon])
|
)
|
||||||
|
self.xrandr_info[mon]["res_y"] = int(
|
||||||
|
int(mode_y) * self.ui.verticalScale.value() / 100
|
||||||
|
)
|
||||||
|
self.xrandr_info[mon]["item"].update_visuals(self.xrandr_info[mon])
|
||||||
|
|
||||||
def monitor_moved(self):
|
def monitor_moved(self):
|
||||||
"Update xrandr_info with new monitor positions"
|
"Update xrandr_info with new monitor positions"
|
||||||
@ -221,7 +228,6 @@ class Window(QObject):
|
|||||||
self.mode_changed() # Not really, but it's the same thing
|
self.mode_changed() # Not really, but it's the same thing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
16
main.ui
16
main.ui
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>Dialog</class>
|
<class>Main</class>
|
||||||
<widget class="QDialog" name="Dialog">
|
<widget class="QDialog" name="Main">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@ -169,6 +169,9 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="resetButton">
|
<widget class="QPushButton" name="resetButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reset to initial configuration</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Reset</string>
|
<string>Reset</string>
|
||||||
</property>
|
</property>
|
||||||
@ -189,6 +192,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="okButton">
|
<widget class="QPushButton" name="okButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Apply configuration and close</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Ok</string>
|
<string>Ok</string>
|
||||||
</property>
|
</property>
|
||||||
@ -196,6 +202,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="applyButton">
|
<widget class="QPushButton" name="applyButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Apply configuration</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Apply</string>
|
<string>Apply</string>
|
||||||
</property>
|
</property>
|
||||||
@ -203,6 +212,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="cancelButton">
|
<widget class="QPushButton" name="cancelButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Close without applying configuration</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Cancel</string>
|
<string>Cancel</string>
|
||||||
</property>
|
</property>
|
||||||
|
Loading…
Reference in New Issue
Block a user