# khtml Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kjavaappletserver.cpp

    00001 /* This file is part of the KDE project
    00002  *
    00003  * Copyright (C) 2000 Richard Moore <rich@kde.org>
    00004  *               2000 Wynn Wilkes <wynnw@caldera.com>
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the GNU Library General Public
    00008  * License as published by the Free Software Foundation; either
    00009  * version 2 of the License, or (at your option) any later version.
    00010  *
    00011  * This library is distributed in the hope that it will be useful,
    00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00014  * Library General Public License for more details.
    00015  *
    00016  * You should have received a copy of the GNU Library General Public License
    00017  * along with this library; see the file COPYING.LIB.  If not, write to
    00018  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00019  * Boston, MA 02111-1307, USA.
    00020  */
    00021
    00022 #include <config.h>
    00023 #include "kjavaappletserver.h"
    00024 #include "kjavaappletcontext.h"
    00025 #include "kjavaprocess.h"
    00026 #include "kjavadownloader.h"
    00027
    00028 #include <kdebug.h>
    00029 #include <kconfig.h>
    00030 #include <klocale.h>
    00031 #include <kparts/browserextension.h>
    00032 #include <kapplication.h>
    00033 #include <kstandarddirs.h>
    00034
    00035 #include <kio/job.h>
    00036 #include <kio/kprotocolmanager.h>
    00037
    00038 #include <qtimer.h>
    00039 #include <qguardedptr.h>
    00040 #include <qdir.h>
    00041
    00042 #include <stdlib.h>
    00043 #include <assert.h>
    00044
    00045 #define KJAS_CREATE_CONTEXT    (char)1
    00046 #define KJAS_DESTROY_CONTEXT   (char)2
    00047 #define KJAS_CREATE_APPLET     (char)3
    00048 #define KJAS_DESTROY_APPLET    (char)4
    00049 #define KJAS_START_APPLET      (char)5
    00050 #define KJAS_STOP_APPLET       (char)6
    00051 #define KJAS_INIT_APPLET       (char)7
    00052 #define KJAS_SHOW_DOCUMENT     (char)8
    00053 #define KJAS_SHOW_URLINFRAME   (char)9
    00054 #define KJAS_SHOW_STATUS       (char)10
    00055 #define KJAS_RESIZE_APPLET     (char)11
    00056 #define KJAS_GET_URLDATA       (char)12
    00057 #define KJAS_URLDATA           (char)13
    00058 #define KJAS_SHUTDOWN_SERVER   (char)14
    00059 #define KJAS_JAVASCRIPT_EVENT   (char)15
    00060 #define KJAS_GET_MEMBER        (char)16
    00061 #define KJAS_CALL_MEMBER       (char)17
    00062 #define KJAS_PUT_MEMBER        (char)18
    00063 #define KJAS_DEREF_OBJECT      (char)19
    00064 #define KJAS_AUDIOCLIP_PLAY    (char)20
    00065 #define KJAS_AUDIOCLIP_LOOP    (char)21
    00066 #define KJAS_AUDIOCLIP_STOP    (char)22
    00067 #define KJAS_APPLET_STATE      (char)23
    00068 #define KJAS_APPLET_FAILED     (char)24
    00069
    00070
    00071 class JSStackNode {
    00072 public:
    00073     JSStackNode() : ready(false) {}
    00074     bool ready;
    00075     QStringList args;
    00076     int size;
    00077 };
    00078
    00079 // For future expansion
    00080 class KJavaAppletServerPrivate
    00081 {
    00082 friend class KJavaAppletServer;
    00083 private:
    00084    int counter;
    00085    int ticketcounter;
    00086    QMap< int, QGuardedPtr<KJavaAppletContext> > contexts;
    00087    QString appletLabel;
    00088    QMap< int, JSStackNode* > jsstack;
    00089    bool javaProcessFailed;
    00090 };
    00091
    00092 static KJavaAppletServer* self = 0;
    00093
    00094 KJavaAppletServer::KJavaAppletServer()
    00095 {
    00096     d = new KJavaAppletServerPrivate;
    00097     d->ticketcounter = 0;
    00098     process = new KJavaProcess();
    00099
    00100     connect( process, SIGNAL(received(const QByteArray&)),
    00101              this,    SLOT(slotJavaRequest(const QByteArray&)) );
    00102
    00103     setupJava( process );
    00104
    00105     if( process->startJava() ) {
    00106         d->appletLabel = i18n( "Loading Applet" );
    00107         d->javaProcessFailed = false;
    00108     }
    00109     else {
    00110         d->appletLabel = i18n( "Error: java executable not found" );
    00111         d->javaProcessFailed = true;
    00112     }
    00113 }
    00114
    00115 KJavaAppletServer::~KJavaAppletServer()
    00116 {
    00117     quit();
    00118
    00119     delete process;
    00120     delete d;
    00121 }
    00122
    00123 QString KJavaAppletServer::getAppletLabel()
    00124 {
    00125     if( self )
    00126         return self->appletLabel();
    00127     else
    00128         return QString::null;
    00129 }
    00130
    00131 QString KJavaAppletServer::appletLabel()
    00132 {
    00133     return d->appletLabel;
    00134 }
    00135
    00136 KJavaAppletServer* KJavaAppletServer::allocateJavaServer()
    00137 {
    00138    if( self == 0 )
    00139    {
    00140       self = new KJavaAppletServer();
    00141       self->d->counter = 0;
    00142    }
    00143
    00144    self->d->counter++;
    00145    return self;
    00146 }
    00147
    00148 void KJavaAppletServer::freeJavaServer()
    00149 {
    00150     self->d->counter--;
    00151
    00152     if( self->d->counter == 0 )
    00153     {
    00154         //instead of immediately quitting here, set a timer to kill us
    00155         //if there are still no servers- give us one minute
    00156         //this is to prevent repeated loading and unloading of the jvm
    00157         KConfig config( "konquerorrc", true );
    00158         config.setGroup( "Java/JavaScript Settings" );
    00159         if( config.readBoolEntry( "ShutdownAppletServer", true )  )
    00160         {
    00161             int value = config.readNumEntry( "AppletServerTimeout", 60 );
    00162             QTimer::singleShot( value*1000, self, SLOT( checkShutdown() ) );
    00163         }
    00164     }
    00165 }
    00166
    00167 void KJavaAppletServer::checkShutdown()
    00168 {
    00169     if( self->d->counter == 0 )
    00170     {
    00171         delete self;
    00172         self = 0;
    00173     }
    00174 }
    00175
    00176 void KJavaAppletServer::setupJava( KJavaProcess *p )
    00177 {
    00178     KConfig config ( "konquerorrc", true );
    00179     config.setGroup( "Java/JavaScript Settings" );
    00180
    00181     QString jvm_path = "java";
    00182
    00183     QString jPath = config.readPathEntry( "JavaPath" );
    00184     if ( !jPath.isEmpty() && jPath != "java" )
    00185     {
    00186         // Cut off trailing slash if any
    00187         if( jPath[jPath.length()-1] == '/' )
    00188             jPath.remove(jPath.length()-1, 1);
    00189
    00190         QDir dir( jPath );
    00191         if( dir.exists( "bin/java" ) )
    00192         {
    00193             jvm_path = jPath + "/bin/java";
    00194         }
    00195         else if (dir.exists( "/jre/bin/java" ) )
    00196         {
    00197             jvm_path = jPath + "/jre/bin/java";
    00198         }
    00199         else if( QFile::exists(jPath) )
    00200         {
    00201             //check here to see if they entered the whole path the java exe
    00202             jvm_path = jPath;
    00203         }
    00204     }
    00205
    00206     //check to see if jvm_path is valid and set d->appletLabel accordingly
    00207     p->setJVMPath( jvm_path );
    00208
    00209     // Prepare classpath variable
    00210     QString kjava_class = locate("data", "kjava/kjava.jar");
    00211     kdDebug(6100) << "kjava_class = " << kjava_class << endl;
    00212     if( kjava_class.isNull() ) // Should not happen
    00213         return;
    00214
    00215     QDir dir( kjava_class );
    00216     dir.cdUp();
    00217     kdDebug(6100) << "dir = " << dir.absPath() << endl;
    00218
    00219     QStringList entries = dir.entryList( "*.jar" );
    00220     kdDebug(6100) << "entries = " << entries.join( ":" ) << endl;
    00221
    00222     QString classes;
    00223     for( QStringList::Iterator it = entries.begin();
    00224          it != entries.end(); it++ )
    00225     {
    00226         if( !classes.isEmpty() )
    00227             classes += ":";
    00228         classes += dir.absFilePath( *it );
    00229     }
    00230     p->setClasspath( classes );
    00231
    00232     // Fix all the extra arguments
    00233     QString extraArgs = config.readEntry( "JavaArgs" );
    00234     p->setExtraArgs( extraArgs );
    00235
    00236     if( config.readBoolEntry( "ShowJavaConsole", false) )
    00237     {
    00238         p->setSystemProperty( "kjas.showConsole", QString::null );
    00239     }
    00240
    00241     if( config.readBoolEntry( "UseSecurityManager", true ) )
    00242     {
    00243         QString class_file = locate( "data", "kjava/kjava.policy" );
    00244         p->setSystemProperty( "java.security.policy", class_file );
    00245
    00246         p->setSystemProperty( "java.security.manager",
    00247                               "org.kde.kjas.server.KJASSecurityManager" );
    00248     }
    00249
    00250     //check for http proxies...
    00251     if( KProtocolManager::useProxy() )
    00252     {
    00253         // only proxyForURL honours automatic proxy scripts
    00254         // we do not know the applet url here so we just use a dummy url
    00255         // this is a workaround for now
    00256         // FIXME
    00257         KURL dummyURL( "http://www.kde.org/" );
    00258         QString httpProxy = KProtocolManager::proxyForURL(dummyURL);
    00259         kdDebug(6100) << "httpProxy is " << httpProxy << endl;
    00260
    00261         KURL url( httpProxy );
    00262         p->setSystemProperty( "http.proxyHost", url.host() );
    00263         p->setSystemProperty( "http.proxyPort", QString::number( url.port() ) );
    00264     }
    00265
    00266     //set the main class to run
    00267     p->setMainClass( "org.kde.kjas.server.Main" );
    00268 }
    00269
    00270 void KJavaAppletServer::createContext( int contextId, KJavaAppletContext* context )
    00271 {
    00272 //    kdDebug(6100) << "createContext: " << contextId << endl;
    00273     if ( d->javaProcessFailed ) return;
    00274
    00275     d->contexts.insert( contextId, context );
    00276
    00277     QStringList args;
    00278     args.append( QString::number( contextId ) );
    00279     process->send( KJAS_CREATE_CONTEXT, args );
    00280 }
    00281
    00282 void KJavaAppletServer::destroyContext( int contextId )
    00283 {
    00284 //    kdDebug(6100) << "destroyContext: " << contextId << endl;
    00285     if ( d->javaProcessFailed ) return;
    00286     d->contexts.remove( contextId );
    00287
    00288     QStringList args;
    00289     args.append( QString::number( contextId ) );
    00290     process->send( KJAS_DESTROY_CONTEXT, args );
    00291 }
    00292
    00293 bool KJavaAppletServer::createApplet( int contextId, int appletId,
    00294                              const QString & name, const QString & clazzName,
    00295                              const QString & baseURL, const QString & user,
    00296                              const QString & password, const QString & authname,
    00297                              const QString & codeBase, const QString & jarFile,
    00298                              QSize size, const QMap<QString,QString>& params,
    00299                              const QString & windowTitle )
    00300 {
    00301 //    kdDebug(6100) << "createApplet: contextId = " << contextId     << endl
    00302 //              << "              appletId  = " << appletId      << endl
    00303 //              << "              name      = " << name          << endl
    00304 //              << "              clazzName = " << clazzName     << endl
    00305 //              << "              baseURL   = " << baseURL       << endl
    00306 //              << "              codeBase  = " << codeBase      << endl
    00307 //              << "              jarFile   = " << jarFile       << endl
    00308 //              << "              width     = " << size.width()  << endl
    00309 //              << "              height    = " << size.height() << endl;
    00310
    00311     if ( d->javaProcessFailed ) return false;
    00312
    00313     QStringList args;
    00314     args.append( QString::number( contextId ) );
    00315     args.append( QString::number( appletId ) );
    00316
    00317     //it's ok if these are empty strings, I take care of it later...
    00318     args.append( name );
    00319     args.append( clazzName );
    00320     args.append( baseURL );
    00321     args.append( user );
    00322     args.append( password );
    00323     args.append( authname );
    00324     args.append( codeBase );
    00325     args.append( jarFile );
    00326
    00327     args.append( QString::number( size.width() ) );
    00328     args.append( QString::number( size.height() ) );
    00329
    00330     args.append( windowTitle );
    00331
    00332     //add on the number of parameter pairs...
    00333     int num = params.count();
    00334     QString num_params = QString("%1").arg( num, 8 );
    00335     args.append( num_params );
    00336
    00337     QMap< QString, QString >::ConstIterator it;
    00338
    00339     for( it = params.begin(); it != params.end(); ++it )
    00340     {
    00341         args.append( it.key() );
    00342         args.append( it.data() );
    00343     }
    00344
    00345     process->send( KJAS_CREATE_APPLET, args );
    00346
    00347     return true;
    00348 }
    00349
    00350 void KJavaAppletServer::initApplet( int contextId, int appletId )
    00351 {
    00352     if ( d->javaProcessFailed ) return;
    00353     QStringList args;
    00354     args.append( QString::number( contextId ) );
    00355     args.append( QString::number( appletId ) );
    00356
    00357     process->send( KJAS_INIT_APPLET, args );
    00358 }
    00359
    00360 void KJavaAppletServer::destroyApplet( int contextId, int appletId )
    00361 {
    00362     if ( d->javaProcessFailed ) return;
    00363     QStringList args;
    00364     args.append( QString::number(contextId) );
    00365     args.append( QString::number(appletId) );
    00366
    00367     process->send( KJAS_DESTROY_APPLET, args );
    00368 }
    00369
    00370 void KJavaAppletServer::startApplet( int contextId, int appletId )
    00371 {
    00372     if ( d->javaProcessFailed ) return;
    00373     QStringList args;
    00374     args.append( QString::number(contextId) );
    00375     args.append( QString::number(appletId) );
    00376
    00377     process->send( KJAS_START_APPLET, args );
    00378 }
    00379
    00380 void KJavaAppletServer::stopApplet( int contextId, int appletId )
    00381 {
    00382     if ( d->javaProcessFailed ) return;
    00383     QStringList args;
    00384     args.append( QString::number(contextId) );
    00385     args.append( QString::number(appletId) );
    00386
    00387     process->send( KJAS_STOP_APPLET, args );
    00388 }
    00389
    00390 void KJavaAppletServer::sendURLData( const QString& loaderID,
    00391                                      const QString& url,
    00392                                      const QByteArray& data )
    00393 {
    00394     QStringList args;
    00395     args.append( loaderID );
    00396     args.append( url );
    00397
    00398     process->send( KJAS_URLDATA, args, data );
    00399
    00400 }
    00401
    00402 void KJavaAppletServer::quit()
    00403 {
    00404     QStringList args;
    00405
    00406     process->send( KJAS_SHUTDOWN_SERVER, args );
    00407 }
    00408
    00409 void KJavaAppletServer::slotJavaRequest( const QByteArray& qb )
    00410 {
    00411     // qb should be one command only without the length string,
    00412     // we parse out the command and it's meaning here...
    00413     QString cmd;
    00414     QStringList args;
    00415     int index = 0;
    00416     int qb_size = qb.size();
    00417
    00418     //get the command code
    00419     char cmd_code = qb[ index++ ];
    00420     ++index; //skip the next sep
    00421
    00422     //get contextID
    00423     QString contextID;
    00424     while( qb[index] != 0 && index < qb_size )
    00425     {
    00426         contextID += qb[ index++ ];
    00427     }
    00428     ++index; //skip the sep
    00429
    00430     //now parse out the arguments
    00431     while( index < qb_size )
    00432     {
    00433         QString tmp;
    00434         while( qb[index] != 0 )
    00435             tmp += qb[ index++ ];
    00436
    00437         kdDebug(6100) << "KJavaAppletServer::slotJavaRequest: "<< tmp << endl;
    00438         args.append( tmp );
    00439
    00440         ++index; //skip the sep
    00441     }
    00442     //here I should find the context and call the method directly
    00443     //instead of emitting signals
    00444     switch( cmd_code )
    00445     {
    00446         case KJAS_SHOW_DOCUMENT:
    00447             cmd = QString::fromLatin1( "showdocument" );
    00448             break;
    00449
    00450         case KJAS_SHOW_URLINFRAME:
    00451             cmd = QString::fromLatin1( "showurlinframe" );
    00452             break;
    00453
    00454         case KJAS_SHOW_STATUS:
    00455             cmd = QString::fromLatin1( "showstatus" );
    00456             break;
    00457
    00458         case KJAS_RESIZE_APPLET:
    00459             cmd = QString::fromLatin1( "resizeapplet" );
    00460             break;
    00461
    00462         case KJAS_GET_URLDATA:
    00463             //here we need to get some data for a class loader and send it back...
    00464             kdDebug(6100) << "GetURLData from classloader: "<< contextID
    00465                           << " for url: " << args[0] << endl;
    00466             break;
    00467         case KJAS_JAVASCRIPT_EVENT:
    00468             cmd = QString::fromLatin1( "JS_Event" );
    00469             kdDebug(6100) << "Javascript request: "<< contextID
    00470                           << " code: " << args[0] << endl;
    00471             break;
    00472         case KJAS_GET_MEMBER:
    00473         case KJAS_PUT_MEMBER:
    00474         case KJAS_CALL_MEMBER: {
    00475             int ticket = args[0].toInt();
    00476             QMap<int, JSStackNode*>::iterator it = d->jsstack.find(ticket);
    00477             if (it != d->jsstack.end()) {
    00478                 kdDebug(6100) << "slotJavaRequest: " << ticket << endl;
    00479                 args.pop_front();
    00480                 it.data()->args = args;
    00481                 it.data()->ready = true;
    00482                 process->syncCommandReceived(ticket);
    00483             } else
    00484                 kdDebug(6100) << "Error: Missed return member data" << endl;
    00485             return;
    00486         }
    00487         case KJAS_AUDIOCLIP_PLAY:
    00488             cmd = QString::fromLatin1( "audioclip_play" );
    00489             kdDebug(6100) << "Audio Play: url=" << args[0] << endl;
    00490             break;
    00491         case KJAS_AUDIOCLIP_LOOP:
    00492             cmd = QString::fromLatin1( "audioclip_loop" );
    00493             kdDebug(6100) << "Audio Loop: url=" << args[0] << endl;
    00494             break;
    00495         case KJAS_AUDIOCLIP_STOP:
    00496             cmd = QString::fromLatin1( "audioclip_stop" );
    00497             kdDebug(6100) << "Audio Stop: url=" << args[0] << endl;
    00498             break;
    00499         case KJAS_APPLET_STATE:
    00500             kdDebug(6100) << "Applet State Notification for Applet " << args[0] << ". New state=" << args[1] << endl;
    00501             cmd = QString::fromLatin1( "AppletStateNotification" );
    00502             break;
    00503         case KJAS_APPLET_FAILED:
    00504             kdDebug(6100) << "Applet " << args[0] << " Failed: " << args[1] << endl;
    00505             cmd = QString::fromLatin1( "AppletFailed" );
    00506             break;
    00507         default:
    00508             return;
    00509             break;
    00510     }
    00511
    00512     if( cmd_code == KJAS_GET_URLDATA )
    00513     {
    00514         new KJavaDownloader( contextID, args[0] );
    00515     }
    00516     else
    00517     {
    00518         bool ok;
    00519         int contextID_num = contextID.toInt( &ok );
    00520
    00521         if( !ok )
    00522         {
    00523             kdError(6100) << "could not parse out contextID to call command on" << endl;
    00524             return;
    00525         }
    00526
    00527         KJavaAppletContext* context = d->contexts[ contextID_num ];
    00528         if( context )
    00529             context->processCmd( cmd, args );
    00530         else if (cmd != "AppletStateNotification")
    00531             kdError(6100) << "no context object for this id" << endl;
    00532     }
    00533 }
    00534
    00535 bool KJavaAppletServer::getMember(int contextId, int appletId, const unsigned long objid, const QString & name, int & type, unsigned long & rid, QString & value) {
    00536     QStringList args;
    00537     int ticket = d->ticketcounter++;
    00538     args.append( QString::number(contextId) );
    00539     args.append( QString::number(appletId) );
    00540     args.append( QString::number(ticket) );
    00541     args.append( QString::number(objid) );
    00542     args.append( name );
    00543
    00544     JSStackNode * frame = new JSStackNode;
    00545     d->jsstack.insert(ticket, frame);
    00546     kdDebug(6100) << "KJavaAppletServer::getMember " << name << " " << ticket << endl;
    00547     process->sendSync( ticket, KJAS_GET_MEMBER, args );
    00548
    00549     bool retval = frame->ready;
    00550     if (retval && frame->args.count() == 3) {
    00551         type = frame->args[0].toInt(&retval);
    00552         if (retval && type >= 0) {
    00553             rid = frame->args[1].toInt(&retval);
    00554             value = frame->args[2];
    00555         } else
    00556             retval = false;
    00557     } else {
    00558         kdError(6100) << "getMember: " << (retval ? "args ":"timeout ") << ticket << endl;
    00559     }
    00560
    00561     d->jsstack.erase(ticket);
    00562     delete frame;
    00563
    00564     return retval;
    00565 }
    00566
    00567 bool KJavaAppletServer::putMember(int contextId, int appletId, const unsigned long objid, const QString & name, const QString & value) {
    00568     QStringList args;
    00569     int ticket = d->ticketcounter++;
    00570     args.append( QString::number(contextId) );
    00571     args.append( QString::number(appletId) );
    00572     args.append( QString::number(ticket) );
    00573     args.append( QString::number(objid) );
    00574     args.append( name );
    00575     args.append( value );
    00576
    00577     JSStackNode * frame = new JSStackNode;
    00578     d->jsstack.insert(ticket, frame);
    00579     kdDebug(6100) << "KJavaAppletServer::putMember " << name << " " << ticket << endl;
    00580
    00581     process->sendSync( ticket, KJAS_PUT_MEMBER, args );
    00582
    00583     bool retval = frame->ready;
    00584     if (retval) {
    00585         retval = frame->args[0].toInt(&retval);
    00586     } else {
    00587         kdError(6100) << "putMember: timeout" << endl;
    00588     }
    00589
    00590     d->jsstack.erase(ticket);
    00591     delete frame;
    00592
    00593     return retval;
    00594 }
    00595
    00596 bool KJavaAppletServer::callMember(int contextId, int appletId, const unsigned long objid, const QString & name, const QStringList & fargs, int & type, unsigned long & rid, QString & value) {
    00597     QStringList args;
    00598     int ticket = d->ticketcounter++;
    00599     args.append( QString::number(contextId) );
    00600     args.append( QString::number(appletId) );
    00601     args.append( QString::number(ticket) );
    00602     args.append( QString::number(objid) );
    00603     args.append( name );
    00604     for (QStringList::const_iterator it = fargs.begin(); it != fargs.end(); it++)
    00605         args.append(*it);
    00606
    00607     JSStackNode * frame = new JSStackNode;
    00608     d->jsstack.insert(ticket, frame);
    00609
    00610     kdDebug(6100) << "KJavaAppletServer::callMember " << name << " " << ticket << endl;
    00611     process->sendSync( ticket, KJAS_CALL_MEMBER, args );
    00612
    00613     bool retval = frame->ready;
    00614     if (retval) {
    00615         type = frame->args[0].toInt(&retval);
    00616         if (retval && type > -1) {
    00617             rid = frame->args[1].toInt(&retval);
    00618             if (retval)
    00619                 value = frame->args[2];
    00620         } else
    00621             retval = false;
    00622     } else {
    00623         kdError(6100) << "callMember: timeout return data" << endl;
    00624     }
    00625
    00626     d->jsstack.erase(ticket);
    00627     delete frame;
    00628
    00629     return retval;
    00630 }
    00631
    00632 void KJavaAppletServer::derefObject(int contextId, int appletId, const unsigned long objid) {
    00633     QStringList args;
    00634     args.append( QString::number(contextId) );
    00635     args.append( QString::number(appletId) );
    00636     args.append( QString::number(objid) );
    00637
    00638     process->send( KJAS_DEREF_OBJECT, args );
    00639 }
    00640 #include "kjavaappletserver.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:11 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001