From ce869b104ed2272f9970e37374e4391c77c7cb56 Mon Sep 17 00:00:00 2001 From: mickeyl Date: Thu, 03 Jun 2004 15:05:06 +0000 Subject: add the actual python quicklauncher server --- 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 @@ +#!/usr/bin/env python +# -*- coding: iso8859-15 -*- +#--------------------------------------------------------------------------------------------------# +""" M i c k e y ' s + P y t h o n + Q u i c k l a u n c h e r + + =. Copyright (C) 2004 Michael Lauer + .=l. +           .>+-= + _;:,     .>    :=|. This program is free software; you can +.> <`_,   >  .   <= redistribute it and/or modify it under +:`=1 )Y*s>-.--   : the terms of the GNU General Public +.="- .-=="i,     .._ License as published by the Free Software + - .   .-<_>     .<> Foundation; either version 2 of the License, +     ._= =}       : or (at your option) any later version. +    .%`+i>       _;_. +    .i_,=:_.      -`: PARTICULAR PURPOSE. See the GNU +..}^=.=       =       ; General Public License for more +++=   -.     .`     .: details. + :     =  ...= . :.=- + -.   .:....=;==+<; You should have received a copy of the +  -_. . .   )=.  = GNU General Public License along with +    --        :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Purpose: This module is + +At the moment, it is optimized for PyQt. Feel free to port it to PyGtk or other modules. + +""" + +#--------------------------------------------------------------------------------------------------# +__version__ = "0.0.1" +__author__ = "Michael 'Mickey' Lauer " +__license__ = "GPL" +#--------------------------------------------------------------------------------------------------# +try: + from qtpe import QPEApplication as ApplicationBase +except ImportError: + from qt import QApplication as ApplicationBase + +import sys, os + +# +# Note: Feel free to add other modules to accellerate the startup of your Application. +from qt import * +import qt +# + +# +# FIXME: use the ELAN common debug framework +# +def TRACE( *args ): + for arg in args: + sys.stderr.write( "%s - " % arg ) + sys.stderr.write( "\n" ) +TERROR = TDEBUG = TINFO = TWARN = TRACE + +#--------------------------------------------------------------------------------------------------# +class QuicklauncherServer( ApplicationBase ): + """The Quicklauncher Server loads other Python Applications as plugins. + + The Quicklauncher server is the one and only Python process in the system. + It also is the creator of the one and only Qt application object, no matter + if it is a QPEApplication or a QApplication. + + Quicklauncher server and clients communicate via a FIFO (named pipe), this enables + us to write clients as easy as the following example: + + #!/bin/sh + echo /path/to/your/python/script.py >/tmp/mickeys-quicklauncher-$USER + """ + + + def __init__( self, name = "/tmp/mickeys-quicklauncher-%s" % os.getenv( "USER") ): + """Initialize the Quicklauncher & setup the FIFO.""" + ApplicationBase.__init__( self, sys.argv[1:] ) + try: + os.mkfifo( name ) + except OSError, reason: + pass + self.socketNotifier = None + self.fileno = 0 + self.name = name + self.reopenFifo() + self.sendToApplet( "setOnline()" ) + self.sendToApplet( "test(QString,int)", "Hallo", 20 ) + + def __del__( self ): + """Delete the FIFO if present.""" + os.unlink( self.name ) + self.sendCommand( "setOffline()" ) + + def sendToApplet( self, command, *params ): + TDEBUG( self, "sending to applet: '%s' '%s'" % ( command, params ) ) + cmdline = 'qcop "QPE/PyLauncher" "%s"' % command + for param in params: + cmdline += ' "%s"' % param + TDEBUG( self, "calling '%s'" % cmdline ) + os.system( cmdline ) + + def reopenFifo( self ): + """Close and reopen the FIFO. Setup a QSocketNotifier to get the + Qt event loop notifying us when someone is requesting an application start.""" + del self.socketNotifier + os.close( self.fileno ) + self.fileno = os.open( self.name, os.O_RDONLY|os.O_NONBLOCK ) + TDEBUG( self, "created communication fifo '%s'" % self.name ) + self.socketNotifier = qt.QSocketNotifier( self.fileno, qt.QSocketNotifier.Read ) + qt.QObject.connect( self.socketNotifier, qt.SIGNAL( "activated(int)" ), self.slotHandleMessage ) + + def run( self ): + """Register socket notifier and start main loop""" + TDEBUG( self, "---> entering main loop." ) + try: + self.exec_loop() + except Exception, reason: + TERROR( self, "Exception during main loop: '%s'" % reason ) + self.quit() + TDEBUG( self, "<--- returned from main loop." ) + + def slotHandleMessage( self, fileno ): + """Called by the main loop when there is incoming data at the FIFO.""" + TDEBUG( self, "handle message called." ) + scriptName = os.read( self.fileno, 1000 ).strip() + garbage = os.read( self.fileno, -1 ) + if scriptName.startswith( "quit" ): + self.quit() + TDEBUG( self, "Module to launch = '%s'" % ( scriptName ) ) + self.reopenFifo() + # + # Remove QApplication from the namespace and inject our substitute + # + global QApplication + QApplication = QuickApplication + qt.QApplication = QuickApplication + + modulename = self.importModule( scriptName ) + module = sys.modules[modulename] + + def importModule( self, name ): + """Import a module by pathname and return the module name.""" + dirname, modulename = os.path.dirname( name ), os.path.basename( name ) + sys.path.append( dirname ) + try: + if modulename[-3:] == ".py": + modulename = modulename[:-3] + module = __import__( modulename ) + except ImportError, reason: + TERROR( self, "Can't import '%s' (%s)" % ( modulename, reason ) ) + else: + TDEBUG( self, "Module '%s' been imported = %s" % ( modulename, module ) ) + return modulename + +#--------------------------------------------------------------------------------------------------# +class QuickApplication( object ): + """This class acts as proxy for the real Q[PE]Application class. + This way we keep the system state sane by only allowing one application object, + which is the one the server already created for us.""" + + def __getattribute__( self, attr ): + """Mimick a simply attribute resolution order: + First, look in the application object (the server in this case). + Second, hand lookup over to the built-in object base class.""" + #print "__getattribute__", attr + return getattr( server, attr, None ) or object.__getattribute__( self, attr ) + +#--------------------------------------------------------------------------------------------------# + +if __name__ == "__main__": + print >>sys.stdout, "Mickey's Quicklauncher Version %s booting..." % ( __version__ ) + server = QuicklauncherServer() + 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 @@ +#!/usr/bin/env python +# -*- coding: iso8859-15 -*- +#--------------------------------------------------------------------------------------------------# +from qt import * +import sys +#--------------------------------------------------------------------------------------------------# +class MyApplication( QApplication ): + + def __init__( self, argv ): + QApplication.__init__( self, [] ) + self.b = QPushButton( """This is an example application using Mickey's +fascinating Python Quicklaunch technology! +Close me to quit this application.""", None ) + self.b.show() + self.setMainWidget( self.b ) +#--------------------------------------------------------------------------------------------------# + +if __name__ == "__main__": + print "Standalone!" +else: + print "Quickapp!" + + app = MyApplication( sys.argv ) + app.exec_loop() -- cgit v0.9.0.2