This commit is contained in:
Roberto Alsina 2020-01-31 19:17:50 -03:00
parent 6c62d979c8
commit 680a350007
3 changed files with 60 additions and 19 deletions

23
README.md Normal file
View 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
View File

@ -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
View File

@ -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>