Dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

209 lines
6.8 KiB

#!/usr/bin/env python3
import subprocess
from PyQt5 import QtCore, QtDBus, QtWidgets
from PyQt5.QtCore import pyqtSignal as Signal, pyqtSlot as Slot, pyqtProperty as Property, Q_CLASSINFO
KSCREEN_OUTPUT = "DSI-1"
XINPUT_TOUCH = "silead_ts"
IIO_BUSNAME = "net.hadess.SensorProxy"
IIO_OBJPATH = "/net/hadess/SensorProxy"
IIO_TO_KSCREEN = {
"normal": "none",
"right-up": "right",
"left-up": "left",
"bottom-up": "inverted"
}
# DBus
class DISensorProxy(QtDBus.QDBusAbstractInterface):
HasAccelerometerChanged = Signal(bool)
@Property(bool, notify=HasAccelerometerChanged)
def HasAccelerometer(self):
return self.property("HasAccelerometer")
AccelerometerOrientationChanged = Signal(str)
@Property(str, notify=AccelerometerOrientationChanged)
def AccelerometerOrientation(self) -> str:
return self.property("AccelerometerOrientation")
def ClaimAccelerometer(self):
self.call("ClaimAccelerometer")
def ReleaseAccelerometer(self):
self.call("ReleaseAccelerometer")
@Slot(QtDBus.QDBusMessage)
def _on_properties_changed(self, msg):
intf, updated, invald = msg.arguments()
updated = dict(updated)
if "HasAccelerometer" in updated:
self.HasAccelerometerChanged.emit(updated["HasAccelerometerChanged"])
if "AccelerometerOrientation" in updated:
self.AccelerometerOrientationChanged.emit(updated["AccelerometerOrientation"])
def __init__(self, service, path, connection, parent=None):
super().__init__(service, path, "net.hadess.SensorProxy", connection, parent)
if not connection.connect(service, path, "org.freedesktop.DBus.Properties",
"PropertiesChanged", ["net.hadess.SensorProxy"], "sa{sv}as",
self._on_properties_changed):
raise RuntimeError("Could not connect to PropertiesChanged")
class DARotated(QtDBus.QDBusAbstractAdaptor):
Q_CLASSINFO("D-Bus Interface", "me.sodimm.oro.Rotated")
def __init__(self, app):
super().__init__(app)
self.app = app
app.orientationChanged.connect(self.ScreenTurned)
ScreenTurned = Signal(str)
@Property(str)
def Orientation(self):
return self.app.orientation
@Property(bool)
def AutoTurn(self):
return self.app.turn_enabled
@AutoTurn.write
def AutoTurn(self, val):
self.app.set_turn_enabled(val)
@Slot(str, result=bool)
def Turn(self, orientation):
if orientation in ("none", "right", "left", "inverted"):
self.app.turn_screen(orientation)
return True
return False
@Slot()
def Quit(self):
self.app.qapp.quit()
# App Logic
class Main(QtCore.QObject):
def __init__(self, argv):
super().__init__()
#self.qapp = QtCore.QCoreApplication(argv)
self.qapp = QtWidgets.QApplication(argv)
self.qapp.setApplicationName("iio-rotated")
self.qapp.setApplicationDisplayName("Screen Rotation")
# TODO: Figure out initial orientation
self.orientation = None
self.turn_enabled = True
# Turning
orientationChanged = Signal(str)
def turn_screen(self, orientation):
"""
Turn the Display into a different orientation
@param orientation The KScreen orientation (none|right|left|inverted)
"""
subprocess.check_call(["kscreen-doctor", "output.%s.rotation.%s" % (KSCREEN_OUTPUT, orientation)])
subprocess.check_call(["xinput", "--map-to-output", XINPUT_TOUCH, KSCREEN_OUTPUT])
self.orientation = orientation
self.orientationChanged.emit(orientation)
# Auto-Turning
def on_device_turned(self, direction):
print("Device Turned", direction)
if self.turn_enabled:
self.turn_screen(IIO_TO_KSCREEN[direction])
def set_turn_enabled(self, v):
self.turn_enabled = v
self.turn_enabled_changed.emit(v)
turn_enabled_changed = Signal(bool)
def on_systray_clicked(self, reason):
print("Activated", reason)
# TODO: this should change the Icon
#if reason == QtWidgets.QSystemTrayIcon.Trigger:
# self.set_turn_enabled(not self.turn_enabled)
# Main
def main(self):
# Set up Session Bus
self.session_bus = QtDBus.QDBusConnection.sessionBus()
if not self.session_bus.isConnected():
raise RuntimeError("Not connected to Session Bus")
if not self.session_bus.registerService("me.sodimm.oro.Rotated"):
raise RuntimeError("Could not register D-Bus Service. Maybe another instance is already running")
self.adaptor = DARotated(self)
self.session_bus.registerObject("/Rotated", self)
# Connect to System Bus
self.system_bus = QtDBus.QDBusConnection.systemBus()
if not self.system_bus.isConnected():
raise RuntimeError("Not connected to System Bus")
# Look for iio-sensor-proxy
iio = DISensorProxy(IIO_BUSNAME, IIO_OBJPATH, self.system_bus)
if not iio.HasAccelerometer:
raise RuntimeError("No accelerometer reported")
# Set up System Tray Icon
# TODO: Directly work with StatusNotifierItem API?
self.systray = QtWidgets.QSystemTrayIcon(self)
#self.systray.setToolTip("Screen Orientation")
self.menu = QtWidgets.QMenu()
action = self.menu.addAction("Auto-Turn")
action.setCheckable(True)
action.setChecked(self.turn_enabled)
self.turn_enabled_changed.connect(lambda v, action=action: action.setChecked(v))
action.triggered.connect(lambda c: self.set_turn_enabled(c))
self.menu.addSeparator()
for label, direction in (("Normal", "none"),
("Anti-CW", "right"),
("Clockwise", "left"),
("Upside-Down", "inverted")):
action = self.menu.addAction("Turn %s" % label)
action.triggered.connect(lambda *a, d=direction: self.turn_screen(d))
action.setEnabled(not self.turn_enabled)
self.turn_enabled_changed.connect(lambda v, action=action: action.setEnabled(not v))
self.menu.addSeparator()
action = self.menu.addAction("Quit")
action.triggered.connect(self.qapp.quit)
self.systray.setContextMenu(self.menu)
self.systray.activated.connect(self.on_systray_clicked)
self.systray.show()
# Run
iio.ClaimAccelerometer()
iio.AccelerometerOrientationChanged.connect(self.on_device_turned)
try:
self.qapp.exec()
finally:
iio.ReleaseAccelerometer()
if __name__ == "__main__":
import sys
Main(sys.argv).main()