Revert "made aspect ratio accurate"
[lilass.git] / screen.py
index b0c657737403be53b1a05ec7b4edef227b76f19c..6ba9418ae39058429b092aa4e1a646d91582e489 100644 (file)
--- a/screen.py
+++ b/screen.py
@@ -18,7 +18,6 @@
 
 import re, subprocess
 from enum import Enum
 
 import re, subprocess
 from enum import Enum
-from fractions import Fraction
 
 ## utility functions
 
 
 ## utility functions
 
@@ -45,8 +44,10 @@ class RelativeScreenPosition(Enum):
     def __init__(self, text):
         # auto numbering
         cls = self.__class__
     def __init__(self, text):
         # auto numbering
         cls = self.__class__
-        self._value_ = len(cls.__members__)
+        self._value_ = len(cls.__members__) + 1
         self.text = text
         self.text = text
+    def __str__(self):
+        return self.text
 
 class Resolution:
     '''Represents a resolution of a screen'''
 
 class Resolution:
     '''Represents a resolution of a screen'''
@@ -54,6 +55,24 @@ class Resolution:
         self.width = width
         self.height = height
     
         self.width = width
         self.height = height
     
+    @classmethod
+    def fromDatabase(cls, dbstr):
+        if dbstr is None:
+            return None
+        parts = dbstr.split("x")
+        if len(parts) != 2:
+            raise ValueError(xrandrstr)
+        return Resolution(*map(int,parts))
+    
+    def forDatabase(self):
+        return str(self.width)+'x'+str(self.height)
+    
+    def forXrandr(self):
+        return self.forDatabase()
+    
+    def toTuple(self):
+        return (self.width, self.height)
+    
     def __eq__(self, other):
         if not isinstance(other, Resolution):
             return False
     def __eq__(self, other):
         if not isinstance(other, Resolution):
             return False
@@ -67,8 +86,13 @@ class Resolution:
     
     def __str__(self):
         # get ratio
     
     def __str__(self):
         # get ratio
-        ratio = Fraction(self.width, self.height) # automatically divides by the gcd
-        strRatio = "%d:%d" % (ratio.numerator, ratio.denominator)
+        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
         return '%dx%d (%s)' %(self.width, self.height, strRatio)
     
     def __repr__(self):
         return '%dx%d (%s)' %(self.width, self.height, strRatio)
     
     def __repr__(self):
@@ -76,9 +100,6 @@ class Resolution:
     
     def pixelCount(self):
         return self.width * self.height
     
     def pixelCount(self):
         return self.width * self.height
-    
-    def forXrandr(self):
-        return str(self.width)+'x'+str(self.height)
 
 
 class ScreenSetup:
 
 
 class ScreenSetup:
@@ -119,6 +140,13 @@ class ScreenSetup:
                 RelativeScreenPosition.MIRROR: '--same-as',
             }[self.relPosition], intName]
         return args
                 RelativeScreenPosition.MIRROR: '--same-as',
             }[self.relPosition], intName]
         return args
+    
+    def __str__(self):
+        if self.intResolution is None:
+            return "External display only, at "+str(self.extResolution)
+        if self.extResolution is None:
+            return "Internal display only, at "+str(self.intResolution)
+        return "External display %s at %s %s internal display %s at %s" % ("(primary)" if self.extIsPrimary else "", str(self.extResolution), str(self.relPosition), "" if self.extIsPrimary else "(primary)", str(self.intResolution))
 
 class Connector:
     def __init__(self, name=None):
 
 class Connector:
     def __init__(self, name=None):
@@ -126,6 +154,8 @@ class Connector:
         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
         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
+        self.__lastResolution = None
+        self.hasLastResolution = False
     
     def __str__(self):
         return str(self.name)
     
     def __str__(self):
         return str(self.name)
@@ -133,6 +163,20 @@ class Connector:
     def __repr__(self):
         return """<Connector "%s" EDID="%s" resolutions="%s">""" % (str(self.name), str(self.edid), ", ".join(str(r) for r in self.getResolutionList()))
     
     def __repr__(self):
         return """<Connector "%s" EDID="%s" resolutions="%s">""" % (str(self.name), str(self.edid), ", ".join(str(r) for r in self.getResolutionList()))
     
+    def __setLastRes(self, res):
+        # res == None means this display was last switched off
+        if res is not None and not res in self._resolutions:
+            raise ValueError("Resolution "+res+" not available for "+self.name+".")
+        self.__lastResolution = res
+        self.hasLastResolution = True
+    
+    def __getLastRes(self):
+        if not self.hasLastResolution:
+            raise ValueError("Connector %s has no last known resolution." % self.name)
+        return self.__lastResolution
+    
+    lastResolution = property(__getLastRes, __setLastRes)
+    
     def isConnected(self):
         assert (self.edid is None) == (len(self._resolutions)==0)
         return self.edid is not None
     def isConnected(self):
         assert (self.edid is None) == (len(self._resolutions)==0)
         return self.edid is not None
@@ -148,7 +192,7 @@ class Connector:
             self.edid += s
     
     def getResolutionList(self):
             self.edid += s
     
     def getResolutionList(self):
-        return sorted(self._resolutions, key=lambda r: (0 if r==self.preferredResolution else 1, -r.pixelCount()))
+        return sorted(self._resolutions, key=lambda r: (0 if self.hasLastResolution and r==self.lastResolution else 1, 0 if r==self.preferredResolution else 1, -r.pixelCount()))
 
 class ScreenSituation:
     connectors = [] # contains all the Connector objects
 
 class ScreenSituation:
     connectors = [] # contains all the Connector objects
@@ -177,6 +221,7 @@ class ScreenSituation:
         if self.internalConnector == self.externalConnector:
             raise Exception("Internal and external connector are the same. This must not happen. Please fix ~/.dsl.conf.");
         print("Detected external connector:",self.externalConnector)
         if self.internalConnector == self.externalConnector:
             raise Exception("Internal and external connector are the same. This must not happen. Please fix ~/.dsl.conf.");
         print("Detected external connector:",self.externalConnector)
+        # self.lastSetup is left uninitialized so you can't access it before trying a lookup in the database
     
     # Run xrandr and fill the dict of connector names mapped to lists of available resolutions.
     def _getXrandrInformation(self):
     
     # Run xrandr and fill the dict of connector names mapped to lists of available resolutions.
     def _getXrandrInformation(self):
@@ -262,3 +307,19 @@ class ScreenSituation:
             call += ["--output", name] + connectorArgs[name]
         return call
 
             call += ["--output", name] + connectorArgs[name]
         return call
 
+    def fetchDBInfo(self, db):
+        if self.externalConnector and self.externalConnector.edid:
+            self.lastSetup = db.getConfig(self.externalConnector.edid) # may also return None
+        else:
+            self.lastSetup = None
+        if self.lastSetup:
+            print("SETUP FOUND", self.lastSetup)
+            self.externalConnector.lastResolution = self.lastSetup.extResolution
+            self.internalConnector.lastResolution = self.lastSetup.intResolution
+        else:
+            print("NO SETUP FOUND")
+    
+    def putDBInfo(self, db, setup):
+        if not self.externalConnector or not self.externalConnector.edid:
+            return
+        db.putConfig(self.externalConnector.edid, setup)