allow to select frontend via command-line; add a GUI-less frontend for scripted actions
authorRalf Jung <post@ralfj.de>
Wed, 14 Nov 2012 14:00:13 +0000 (15:00 +0100)
committerRalf Jung <post@ralfj.de>
Wed, 14 Nov 2012 14:00:13 +0000 (15:00 +0100)
dsl.py
gui.py

diff --git a/dsl.py b/dsl.py
index d13d0a0f8dc058c008fe2e12dbc7393624cb242b..b4f77bf413391f2bf4b7e01d835c80b76b695299 100755 (executable)
--- a/dsl.py
+++ b/dsl.py
@@ -17,7 +17,8 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 import argparse, sys, os, re, subprocess
-import gui
+from gui import getFrontend
+frontend = getFrontend("cli") # the fallback, until we got a proper frontend. This is guaranteed to be available.
 
 # for auto-config: common names of internal connectors
 commonInternalConnectorNames = ['LVDS', 'LVDS0', 'LVDS1', 'LVDS-0', 'LVDS-1']
@@ -182,11 +183,17 @@ if __name__ == "__main__":
        try:
                # parse command-line arguments
                parser = argparse.ArgumentParser(description='easy Display Setup for Laptops')
+               parser.add_argument("-f, --frontend",
+                                                       dest="frontend",
+                                                       help="The frontend to be used for user interaction")
                parser.add_argument("-r, --relative-position",
                                                        dest="rel_position", choices=('left', 'right', 'external-only'),
                                                        help="Position of external screen relative to internal one")
                cmdArgs = parser.parse_args()
                
+               # load frontend
+               frontend = getFrontend(cmdArgs.frontend)
+               
                # load connectors and classify them
                connectors = getXrandrInformation()
                (internalConnector, externalConnectors) = classifyConnectors(connectors)
@@ -212,7 +219,7 @@ if __name__ == "__main__":
                                setup = ScreenSetup(relPosition, connectors[internalConnector][0], connectors[usedExternalConnector][0]) # use default resolutions
                        else:
                                # use GUI
-                               setup = gui.setup(connectors[internalConnector], connectors[usedExternalConnector])
+                               setup = frontend.setup(connectors[internalConnector], connectors[usedExternalConnector])
                        if setup is None: sys.exit(1) # the user canceled
                        # apply it
                        connectorArgs[internalConnector] = setup.getInternalArgs()
@@ -228,5 +235,5 @@ if __name__ == "__main__":
                print "Call that will be made:",call
                subprocess.check_call(call)
        except Exception as e:
-               gui.error(str(e))
+               frontend.error(str(e))
                raise
diff --git a/gui.py b/gui.py
index 6dabe0f048df2f0e47bc8dfa363a785bcc3266f2..a87b82f1d69bec3302e07e950ccb5ca5da56aca4 100644 (file)
--- a/gui.py
+++ b/gui.py
@@ -29,42 +29,81 @@ def setup(internalResolutions, externalResolutions):
        The user should be asked about his display setup preferences.
        The function returns None if the user cancelled, and an instance of dsl.ScreenSetup otherwise.
 '''
+import subprocess, collections
 
-# frontend detectors
-def qtAvailable():
-       try:
-               import PyQt4
-               return True
-       except ImportError:
-               return False
-
-def zenityAvailable():
-       try:
-               from dsl import processOutputIt
-               processOutputIt("zenity", "--version")
-               return True
-       except Exception:
-               return False
-
-# actual frontends
-if qtAvailable():
-       from PyQt4 import QtGui
-       from qt_dialogue import PositionSelection
-       app = QtGui.QApplication(sys.argv)
+# Qt frontend
+class QtFrontend:
+       def __init__(self):
+               from PyQt4 import QtGui
+               self.app = QtGui.QApplication(sys.argv)
+               print "Qt loaded"
        
-       def error(message):
+       def error(self, message):
+               from PyQt4 import QtGui
                QtGui.QMessageBox.critical(None, 'Fatal error', message)
        
-       def setup(internalResolutions, externalResolutions):
+       def setup(self, internalResolutions, externalResolutions):
+               from qt_dialogue import PositionSelection
                return PositionSelection(internalResolutions, externalResolutions).run()
-
-elif zenityAvailable():
-       import subprocess
-       from zenity_dialogue import run as setup # this provides the setup function
        
+       @staticmethod
+       def isAvailable():
+               try:
+                       import PyQt4
+                       return True
+               except ImportError:
+                       return False
+
+
+# Zenity frontend
+class ZenityFrontend:
        def error(message):
                '''Displays a fatal error to the user'''
                subprocess.check_call(["zenity", "--error", "--text="+message])
+       
+       def setup(self, internalResolutions, externalResolutions):
+               from zenity_dialogue import run
+               run(internalResolutions, externalResolutions)
+       
+       @staticmethod
+       def isAvailable():
+               try:
+                       from dsl import processOutputIt
+                       processOutputIt("zenity", "--version")
+                       return True
+               except Exception:
+                       return False
+
+
+# CLI frontend
+class CLIFrontend:
+       def error(self, message):
+               print >> sys.stderr, message
+       
+       def setup(self, internalResolutions, externalResolutions):
+               raise Exception("Choosing the setup interactively is not supported with the CLI frontend")
+       
+       @staticmethod
+       def isAvailable():
+               return True
+
+# list of available frontends
+frontends = collections.OrderedDict()
+frontends["qt"] = QtFrontend
+frontends["zenity"] = ZenityFrontend
+frontends["cli"] = CLIFrontend
 
-else:
-       print >> sys.stderr, 'No GUI frontend available, please make sure PyQt4 or Zenity is installed'
+# get a frontend
+def getFrontend(name = None):
+       # by name
+       if name is not None:
+               if name in frontends:
+                       if frontends[name].isAvailable():
+                               return frontends[name]() # call constructor
+               # frontend not found or not available
+               raise Exception("Frontend %s not found or not available" % name)
+       # auto-detect
+       for frontend in frontends.values():
+               if frontend.isAvailable():
+                       return frontend() # call constructor
+       raise Exception("No frontend is available - this should not happen")