avoid needless list construction
[lilass.git] / gui.py
1 # DSL - easy Display Setup for Laptops
2 # Copyright (C) 2012 Ralf Jung <post@ralfj.de>
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 # This file abstracts GUI stuff away, so that the actual dsl.py does not have to deal with it
19 import sys
20
21 '''
22 This module implements two functions:
23
24 def error(message):
25         This function displays the error message to the user in some appropriate fassion
26
27 def setup(internalResolutions, externalResolutions):
28         Both arguments are lists of (width, height) tuples of resolutions. You can use dsl.res2user to obtain a user-readable representation of a resolution tuple.
29         The user should be asked about his display setup preferences.
30         The function returns None if the user cancelled, and an instance of dsl.ScreenSetup otherwise.
31 '''
32 import subprocess, collections
33
34 # Qt frontend
35 class QtFrontend:
36         def __init__(self):
37                 from PyQt4 import QtGui
38                 self.app = QtGui.QApplication(sys.argv)
39                 print("Qt loaded")
40         
41         def error(self, message):
42                 from PyQt4 import QtGui
43                 QtGui.QMessageBox.critical(None, 'Fatal error', message)
44         
45         def setup(self, internalResolutions, externalResolutions):
46                 from qt_dialogue import PositionSelection
47                 return PositionSelection(internalResolutions, externalResolutions).run()
48         
49         @staticmethod
50         def isAvailable():
51                 try:
52                         import PyQt4
53                         return True
54                 except ImportError:
55                         return False
56
57
58 # Zenity frontend
59 class ZenityFrontend:
60         def error(message):
61                 '''Displays a fatal error to the user'''
62                 subprocess.check_call(["zenity", "--error", "--text="+message])
63         
64         def setup(self, internalResolutions, externalResolutions):
65                 from zenity_dialogue import run
66                 run(internalResolutions, externalResolutions)
67         
68         @staticmethod
69         def isAvailable():
70                 try:
71                         from dsl import processOutputIt
72                         processOutputIt("zenity", "--version")
73                         return True
74                 except Exception:
75                         return False
76
77
78 # CLI frontend
79 class CLIFrontend:
80         def error(self, message):
81                 print(message, file=sys.stderr)
82         
83         def setup(self, internalResolutions, externalResolutions):
84                 raise Exception("Choosing the setup interactively is not supported with the CLI frontend")
85         
86         @staticmethod
87         def isAvailable():
88                 return True
89
90 # list of available frontends
91 frontends = collections.OrderedDict()
92 frontends["qt"] = QtFrontend
93 frontends["zenity"] = ZenityFrontend
94 frontends["cli"] = CLIFrontend
95
96 # get a frontend
97 def getFrontend(name = None):
98         # by name
99         if name is not None:
100                 if name in frontends:
101                         if frontends[name].isAvailable():
102                                 return frontends[name]() # call constructor
103                 # frontend not found or not available
104                 raise Exception("Frontend %s not found or not available" % name)
105         # auto-detect
106         for frontend in frontends.values():
107                 if frontend.isAvailable():
108                         return frontend() # call constructor
109         raise Exception("No frontend is available - this should not happen")