allow to select frontend via command-line; add a GUI-less frontend for scripted actions
[lilass.git] / gui.py
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.
 '''
        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)
        
                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()
                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 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")