-rwxr-xr-x | noncore/tools/pyquicklauncher/quicklauncher.py | 182 | ||||
-rwxr-xr-x | noncore/tools/pyquicklauncher/testapp.py | 24 |
2 files changed, 206 insertions, 0 deletions
diff --git a/noncore/tools/pyquicklauncher/quicklauncher.py b/noncore/tools/pyquicklauncher/quicklauncher.py new file mode 100755 index 0000000..9a4985f --- a/dev/null +++ b/noncore/tools/pyquicklauncher/quicklauncher.py | |||
@@ -0,0 +1,182 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # -*- coding: iso8859-15 -*- | ||
3 | #--------------------------------------------------------------------------------------------------# | ||
4 | """ M i c k e y ' s | ||
5 | P y t h o n | ||
6 | Q u i c k l a u n c h e r | ||
7 | |||
8 | =. Copyright (C) 2004 Michael Lauer | ||
9 | .=l. <mickey@tm.informatik.uni-frankfurt.de> | ||
10 | .>+-= | ||
11 | _;:, .> :=|. This program is free software; you can | ||
12 | .> <`_, > . <= redistribute it and/or modify it under | ||
13 | :`=1 )Y*s>-.-- : the terms of the GNU General Public | ||
14 | .="- .-=="i, .._ License as published by the Free Software | ||
15 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
16 | ._= =} : or (at your option) any later version. | ||
17 | .%`+i> _;_. | ||
18 | .i_,=:_. -<s. This program is distributed in the hope that | ||
19 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
20 | : .. .:, . . . without even the implied warranty of | ||
21 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
22 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
23 | ..}^=.= = ; General Public License for more | ||
24 | ++= -. .` .: details. | ||
25 | : = ...= . :.=- | ||
26 | -. .:....=;==+<; You should have received a copy of the | ||
27 | -_. . . )=. = GNU General Public License along with | ||
28 | -- :-=` this library; see the file COPYING.LIB. | ||
29 | If not, write to the Free Software Foundation, | ||
30 | Inc., 59 Temple Place - Suite 330, | ||
31 | Boston, MA 02111-1307, USA. | ||
32 | |||
33 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | ||
34 | |||
35 | Purpose: This module is | ||
36 | |||
37 | At the moment, it is optimized for PyQt. Feel free to port it to PyGtk or other modules. | ||
38 | |||
39 | """ | ||
40 | |||
41 | #--------------------------------------------------------------------------------------------------# | ||
42 | __version__ = "0.0.1" | ||
43 | __author__ = "Michael 'Mickey' Lauer <mickey@tm.informatik.uni-frankfurt.de>" | ||
44 | __license__ = "GPL" | ||
45 | #--------------------------------------------------------------------------------------------------# | ||
46 | try: | ||
47 | from qtpe import QPEApplication as ApplicationBase | ||
48 | except ImportError: | ||
49 | from qt import QApplication as ApplicationBase | ||
50 | |||
51 | import sys, os | ||
52 | |||
53 | # <MODULE PRELOAD SECTION> | ||
54 | # Note: Feel free to add other modules to accellerate the startup of your Application. | ||
55 | from qt import * | ||
56 | import qt | ||
57 | # </MODULE PRELOAD SECTION> | ||
58 | |||
59 | # | ||
60 | # FIXME: use the ELAN common debug framework | ||
61 | # | ||
62 | def TRACE( *args ): | ||
63 | for arg in args: | ||
64 | sys.stderr.write( "%s - " % arg ) | ||
65 | sys.stderr.write( "\n" ) | ||
66 | TERROR = TDEBUG = TINFO = TWARN = TRACE | ||
67 | |||
68 | #--------------------------------------------------------------------------------------------------# | ||
69 | class QuicklauncherServer( ApplicationBase ): | ||
70 | """The Quicklauncher Server loads other Python Applications as plugins. | ||
71 | |||
72 | The Quicklauncher server is the one and only Python process in the system. | ||
73 | It also is the creator of the one and only Qt application object, no matter | ||
74 | if it is a QPEApplication or a QApplication. | ||
75 | |||
76 | Quicklauncher server and clients communicate via a FIFO (named pipe), this enables | ||
77 | us to write clients as easy as the following example: | ||
78 | |||
79 | #!/bin/sh | ||
80 | echo /path/to/your/python/script.py >/tmp/mickeys-quicklauncher-$USER | ||
81 | """ | ||
82 | |||
83 | |||
84 | def __init__( self, name = "/tmp/mickeys-quicklauncher-%s" % os.getenv( "USER") ): | ||
85 | """Initialize the Quicklauncher & setup the FIFO.""" | ||
86 | ApplicationBase.__init__( self, sys.argv[1:] ) | ||
87 | try: | ||
88 | os.mkfifo( name ) | ||
89 | except OSError, reason: | ||
90 | pass | ||
91 | self.socketNotifier = None | ||
92 | self.fileno = 0 | ||
93 | self.name = name | ||
94 | self.reopenFifo() | ||
95 | self.sendToApplet( "setOnline()" ) | ||
96 | self.sendToApplet( "test(QString,int)", "Hallo", 20 ) | ||
97 | |||
98 | def __del__( self ): | ||
99 | """Delete the FIFO if present.""" | ||
100 | os.unlink( self.name ) | ||
101 | self.sendCommand( "setOffline()" ) | ||
102 | |||
103 | def sendToApplet( self, command, *params ): | ||
104 | TDEBUG( self, "sending to applet: '%s' '%s'" % ( command, params ) ) | ||
105 | cmdline = 'qcop "QPE/PyLauncher" "%s"' % command | ||
106 | for param in params: | ||
107 | cmdline += ' "%s"' % param | ||
108 | TDEBUG( self, "calling '%s'" % cmdline ) | ||
109 | os.system( cmdline ) | ||
110 | |||
111 | def reopenFifo( self ): | ||
112 | """Close and reopen the FIFO. Setup a QSocketNotifier to get the | ||
113 | Qt event loop notifying us when someone is requesting an application start.""" | ||
114 | del self.socketNotifier | ||
115 | os.close( self.fileno ) | ||
116 | self.fileno = os.open( self.name, os.O_RDONLY|os.O_NONBLOCK ) | ||
117 | TDEBUG( self, "created communication fifo '%s'" % self.name ) | ||
118 | self.socketNotifier = qt.QSocketNotifier( self.fileno, qt.QSocketNotifier.Read ) | ||
119 | qt.QObject.connect( self.socketNotifier, qt.SIGNAL( "activated(int)" ), self.slotHandleMessage ) | ||
120 | |||
121 | def run( self ): | ||
122 | """Register socket notifier and start main loop""" | ||
123 | TDEBUG( self, "---> entering main loop." ) | ||
124 | try: | ||
125 | self.exec_loop() | ||
126 | except Exception, reason: | ||
127 | TERROR( self, "Exception during main loop: '%s'" % reason ) | ||
128 | self.quit() | ||
129 | TDEBUG( self, "<--- returned from main loop." ) | ||
130 | |||
131 | def slotHandleMessage( self, fileno ): | ||
132 | """Called by the main loop when there is incoming data at the FIFO.""" | ||
133 | TDEBUG( self, "handle message called." ) | ||
134 | scriptName = os.read( self.fileno, 1000 ).strip() | ||
135 | garbage = os.read( self.fileno, -1 ) | ||
136 | if scriptName.startswith( "quit" ): | ||
137 | self.quit() | ||
138 | TDEBUG( self, "Module to launch = '%s'" % ( scriptName ) ) | ||
139 | self.reopenFifo() | ||
140 | # | ||
141 | # Remove QApplication from the namespace and inject our substitute | ||
142 | # | ||
143 | global QApplication | ||
144 | QApplication = QuickApplication | ||
145 | qt.QApplication = QuickApplication | ||
146 | |||
147 | modulename = self.importModule( scriptName ) | ||
148 | module = sys.modules[modulename] | ||
149 | |||
150 | def importModule( self, name ): | ||
151 | """Import a module by pathname and return the module name.""" | ||
152 | dirname, modulename = os.path.dirname( name ), os.path.basename( name ) | ||
153 | sys.path.append( dirname ) | ||
154 | try: | ||
155 | if modulename[-3:] == ".py": | ||
156 | modulename = modulename[:-3] | ||
157 | module = __import__( modulename ) | ||
158 | except ImportError, reason: | ||
159 | TERROR( self, "Can't import '%s' (%s)" % ( modulename, reason ) ) | ||
160 | else: | ||
161 | TDEBUG( self, "Module '%s' been imported = %s" % ( modulename, module ) ) | ||
162 | return modulename | ||
163 | |||
164 | #--------------------------------------------------------------------------------------------------# | ||
165 | class QuickApplication( object ): | ||
166 | """This class acts as proxy for the real Q[PE]Application class. | ||
167 | This way we keep the system state sane by only allowing one application object, | ||
168 | which is the one the server already created for us.""" | ||
169 | |||
170 | def __getattribute__( self, attr ): | ||
171 | """Mimick a simply attribute resolution order: | ||
172 | First, look in the application object (the server in this case). | ||
173 | Second, hand lookup over to the built-in object base class.""" | ||
174 | #print "__getattribute__", attr | ||
175 | return getattr( server, attr, None ) or object.__getattribute__( self, attr ) | ||
176 | |||
177 | #--------------------------------------------------------------------------------------------------# | ||
178 | |||
179 | if __name__ == "__main__": | ||
180 | print >>sys.stdout, "Mickey's Quicklauncher Version %s booting..." % ( __version__ ) | ||
181 | server = QuicklauncherServer() | ||
182 | server.run() | ||
diff --git a/noncore/tools/pyquicklauncher/testapp.py b/noncore/tools/pyquicklauncher/testapp.py new file mode 100755 index 0000000..8345193 --- a/dev/null +++ b/noncore/tools/pyquicklauncher/testapp.py | |||
@@ -0,0 +1,24 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # -*- coding: iso8859-15 -*- | ||
3 | #--------------------------------------------------------------------------------------------------# | ||
4 | from qt import * | ||
5 | import sys | ||
6 | #--------------------------------------------------------------------------------------------------# | ||
7 | class MyApplication( QApplication ): | ||
8 | |||
9 | def __init__( self, argv ): | ||
10 | QApplication.__init__( self, [] ) | ||
11 | self.b = QPushButton( """This is an example application using Mickey's | ||
12 | fascinating Python Quicklaunch technology! | ||
13 | Close me to quit this application.""", None ) | ||
14 | self.b.show() | ||
15 | self.setMainWidget( self.b ) | ||
16 | #--------------------------------------------------------------------------------------------------# | ||
17 | |||
18 | if __name__ == "__main__": | ||
19 | print "Standalone!" | ||
20 | else: | ||
21 | print "Quickapp!" | ||
22 | |||
23 | app = MyApplication( sys.argv ) | ||
24 | app.exec_loop() | ||