+# for auto-config: common names of internal connectors
+commonInternalConnectorNames = ['LVDS', 'LVDS0', 'LVDS1', 'LVDS-0', 'LVDS-1']
+
+# this is as close as one can get to an enum in Python
+class RelativeScreenPosition:
+ LEFT = 0
+ RIGHT = 1
+ EXTERNAL_ONLY = 2
+
+# storing what's necessary for screen setup
+class ScreenSetup:
+ def __init__(self, relPosition, intResolution, extResolution, extIsPrimary = False):
+ '''relPosition must be one of the RelativeScreenPosition members, the resolutions must be (width, height) pairs'''
+ self.relPosition = relPosition
+ self.intResolution = intResolution # value doesn't matter if the internal screen is disabled
+ self.extResolution = extResolution
+ self.extIsPrimary = extIsPrimary or self.relPosition == RelativeScreenPosition.EXTERNAL_ONLY # external is always primary if it is the only one
+
+ def getInternalArgs(self):
+ if self.relPosition == RelativeScreenPosition.EXTERNAL_ONLY:
+ return ["--off"]
+ args = ["--mode", res2xrandr(self.intResolution)] # set internal screen to desired resolution
+ if not self.extIsPrimary:
+ args.append('--primary')
+ return args
+
+ def getExternalArgs(self, intName):
+ args = ["--mode", res2xrandr(self.extResolution)] # set external screen to desired resolution
+ if self.extIsPrimary:
+ args.append('--primary')
+ if self.relPosition == RelativeScreenPosition.LEFT:
+ args += ['--left-of', intName]
+ elif self.relPosition == RelativeScreenPosition.RIGHT:
+ args += ['--right-of', intName]
+ return args
+
+# Load a section-less config file: maps parameter names to space-separated lists of strings (with shell quotation)
+def loadConfigFile(file):
+ import shlex
+ result = {}
+ if not os.path.exists(file):
+ return result # no config file
+ # read config file
+ linenr = 0
+ with open(file) as file:
+ for line in file:
+ linenr += 1
+ line = line.strip()
+ if not len(line) or line.startswith("#"): continue # skip empty and comment lines
+ try:
+ # parse line
+ pos = line.index("=") # will raise exception when substring is not found
+ curKey = line[:pos].strip()
+ result[curKey] = shlex.split(line[pos+1:]) # shlex.split also strips
+ except Exception:
+ raise Exception("Invalid config, line %d: Error parsing line (may be a quoting issue)." % linenr)
+ # add some convencience get functions
+ return result
+
+# Run xrandr and return a dict of output names mapped to lists of available resolutions, each being a (width, height) pair.
+# An empty list indicates that the connector is disabled.