rename tool to DSL: Display Setup for Laptops
[lilass.git] / dsl.py
1 #!/usr/bin/python
2 # DSL - easy Display Setup for Laptops
3
4 import sys, re, subprocess
5 from PyQt4 import QtGui
6 from selector_window import PositionSelection
7 app = QtGui.QApplication(sys.argv)
8
9 def getXrandrInformation():
10         p = subprocess.Popen(["xrandr", "-q"], stdout=subprocess.PIPE)
11         connectors = {} # map of connector names to a list of resolutions
12         connector = None # current connector
13         for line in p.stdout:
14                 # new connector?
15                 m = re.search(r'^([\w]+) connected ', line)
16                 if m is not None:
17                         connector = m.groups()[0]
18                         assert connector not in connectors
19                         connectors[connector] = []
20                         continue
21                 # new resolution?
22                 m = re.search(r'^   ([\d]+)x([\d]+) +', line)
23                 if m is not None:
24                         assert connector is not None
25                         connectors[connector].append((int(m.groups()[0]), int(m.groups()[1])))
26         p.communicate()
27         if p.returncode != 0: raise Exception("Querying xrandr for data failed")
28         return connectors
29
30 def res2xrandr(res):
31         (w, h) = res
32         return str(w)+'x'+str(h)
33
34 def res2user(res):
35         (w, h) = res
36         # get ratio
37         ratio = int(round(16.0*h/w))
38         if ratio == 12: # 16:12 = 4:3
39                 strRatio = '4:3'
40         elif ratio == 13: # 16:12.8 = 5:4
41                 strRatio = '5:4'
42         else: # let's just hope this will never be 14 or more...
43                 strRatio = '16:%d' % ratio
44         return '%dx%d (%s)' %(w, h, strRatio)
45
46 # Check screen setup
47 internalName = "LVDS1"
48 externalNames = ["HDMI1", "DP1", "VGA1"]
49 connectors = getXrandrInformation()
50 internalResolutions = connectors[internalName] # there must be a screen assoicated to the internal connector
51 externalName = None # *the* external connector which is actually used
52 externalResolutions = None # resultions of the external connector
53 args = {} # maps connector names to xrand arguments
54
55 # look for enabled external screen, disable all the others
56 for name in externalNames:
57         if externalResolutions is None and name in connectors:
58                 externalName = name
59                 externalResolutions = connectors[name]
60         else:
61                 args[name] = ["--off"]
62
63 # Check what to do
64 if externalName is not None: # we need to ask what to do
65         extPosition = PositionSelection(externalName, map(res2user, internalResolutions), map(res2user, externalResolutions))
66         extPosition.exec_()
67         if not extPosition.result(): sys.exit(1) # the user canceled
68         extResolution = res2xrandr(externalResolutions[extPosition.extResolutions.currentIndex()])
69         intResolution = res2xrandr(internalResolutions[extPosition.intResolutions.currentIndex()])
70         # build command-line
71         args[externalName] = ["--mode", extResolution] # we definitely want an external screen
72         if extPosition.extOnly.isChecked():
73                 args[internalName] = ["--off"]
74                 args[externalName] += ["--primary"]
75         else:
76                 # there are two screens
77                 args[internalName] = ["--mode", intResolution]
78                 if extPosition.posLeft.isChecked():
79                         args[externalName] += ["--left-of", internalName]
80                 else:
81                         args[externalName] += ["--right-of", internalName]
82                 if extPosition.primExt.isChecked():
83                         args[externalName] += ["--primary"]
84                 else:
85                         args[internalName] += ["--primary"]
86 else:
87         args[internalName] = ["--mode", res2xrandr(internalResolutions[0]), "--primary"]
88 # and do it
89 call = ["xrandr"]
90 for name in args:
91         call += ["--output", name] + args[name]
92 print "Call that will be made:",call
93 subprocess.check_call(call)