X-Git-Url: https://git.ralfj.de/lilass.git/blobdiff_plain/de5f47a5737abe797a32747f23210623cf068787..53c8405139ffdc848753335f50b6b746a7bafcb5:/screen.py?ds=inline diff --git a/screen.py b/screen.py index 26ffddb..b0c6577 100644 --- a/screen.py +++ b/screen.py @@ -18,6 +18,7 @@ import re, subprocess from enum import Enum +from fractions import Fraction ## utility functions @@ -47,7 +48,6 @@ class RelativeScreenPosition(Enum): self._value_ = len(cls.__members__) self.text = text - class Resolution: '''Represents a resolution of a screen''' def __init__(self, width, height): @@ -62,20 +62,21 @@ class Resolution: def __ne__(self, other): return not self.__eq__(other) + def __hash__(self): + return hash(("Resolution",self.width,self.height)) + def __str__(self): # get ratio - ratio = int(round(16.0*self.height/self.width)) - if ratio == 12: # 16:12 = 4:3 - strRatio = '4:3' - elif ratio == 13: # 16:12.8 = 5:4 - strRatio = '5:4' - else: # let's just hope this will never be 14 or more... - strRatio = '16:%d' % ratio + ratio = Fraction(self.width, self.height) # automatically divides by the gcd + strRatio = "%d:%d" % (ratio.numerator, ratio.denominator) return '%dx%d (%s)' %(self.width, self.height, strRatio) def __repr__(self): return 'screen.Resolution('+self.forXrandr()+')' + def pixelCount(self): + return self.width * self.height + def forXrandr(self): return str(self.width)+'x'+str(self.height) @@ -120,25 +121,34 @@ class ScreenSetup: return args class Connector: - name = None # connector name, e.g. "HDMI1" - edid = None # EDID string for the connector, or None if disconnected - resolutions = [] # list of Resolution objects, empty if disconnected - def __init__(self, name=None): - self.name = name + self.name = name # connector name, e.g. "HDMI1" + self.edid = None # EDID string for the connector, or None if disconnected + self._resolutions = set() # list of Resolution objects, empty if disconnected + self.preferredResolution = None + def __str__(self): return str(self.name) + + def __repr__(self): + return """""" % (str(self.name), str(self.edid), ", ".join(str(r) for r in self.getResolutionList())) + def isConnected(self): - assert (self.edid is None) == (len(self.resolutions)==0) + assert (self.edid is None) == (len(self._resolutions)==0) return self.edid is not None + def addResolution(self, resolution): assert isinstance(resolution, Resolution) - self.resolutions.append(resolution) + self._resolutions.add(resolution) + def appendToEdid(self, s): if self.edid is None: self.edid = s else: self.edid += s + + def getResolutionList(self): + return sorted(self._resolutions, key=lambda r: (0 if r==self.preferredResolution else 1, -r.pixelCount())) class ScreenSituation: connectors = [] # contains all the Connector objects @@ -151,6 +161,9 @@ class ScreenSituation: just choose any remaining connector.''' # which connectors are there? self._getXrandrInformation() + for c in self.connectors: + print(repr(c)) + print() # figure out which is the internal connector self.internalConnector = self._findAvailableConnector(internalConnectorNames) if self.internalConnector is None: @@ -159,7 +172,7 @@ class ScreenSituation: # and the external one if externalConnectorNames is None: externalConnectorNames = map(lambda c: c.name, self.connectors) - externalConnectorNames = filter(lambda name: name != self.internalConnector.name, externalConnectorNames) + externalConnectorNames = set(filter(lambda name: name != self.internalConnector.name, externalConnectorNames)) self.externalConnector = self._findAvailableConnector(externalConnectorNames) if self.internalConnector == self.externalConnector: raise Exception("Internal and external connector are the same. This must not happen. Please fix ~/.dsl.conf."); @@ -196,6 +209,8 @@ class ScreenSituation: resolution = Resolution(int(m.group(1)), int(m.group(2))) assert connector is not None connector.addResolution(resolution) + if '+preferred' in line: + connector.preferredResolution = resolution continue # EDID? m = re.search(r'^\s*EDID:\s*$', line) @@ -204,7 +219,7 @@ class ScreenSituation: continue # unknown line # not fatal, e.g. xrandr shows strange stuff when a display is enabled, but not connected - print("Warning: Unknown xrandr line %s" % line) + #print("Warning: Unknown xrandr line %s" % line) # return the first available connector from those listed in , skipping disabled connectors def _findAvailableConnector(self, tryConnectorNames): @@ -214,20 +229,20 @@ class ScreenSituation: # return available internal resolutions def internalResolutions(self): - return self.internalConnector.resolutions + return self.internalConnector.getResolutionList() # return available external resolutions (or None, if there is no external screen connected) def externalResolutions(self): if self.externalConnector is None: return None - return self.externalConnector.resolutions + return self.externalConnector.getResolutionList() # return resolutions available for both internal and external screen def commonResolutions(self): internalRes = self.internalResolutions() externalRes = self.externalResolutions() assert externalRes is not None - return [res for res in externalRes if res in internalRes] + return sorted(set(externalRes).intersection(internalRes), key=lambda r: -r.pixelCount()) # compute the xrandr call def forXrandr(self, setup):