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