Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

applauncher.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002 ** Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of the Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 #ifndef QTOPIA_INTERNAL_PRELOADACCESS
00022 #define QTOPIA_INTERNAL_PRELOADACCESS
00023 #endif
00024 #ifndef QTOPIA_INTERNAL_FILEOPERATIONS
00025 #define QTOPIA_INTERNAL_FILEOPERATIONS
00026 #endif
00027 #ifndef QTOPIA_PROGRAM_MONITOR
00028 #define QTOPIA_PROGRAM_MONITOR
00029 #endif
00030 
00031 #include "applauncher.h"
00032 #include "documentlist.h"
00033 
00034 /* OPIE */
00035 #include <opie2/odebug.h>
00036 #include <opie2/oglobal.h>
00037 #include <qtopia/qcopenvelope_qws.h>
00038 #include <qtopia/qpeapplication.h>
00039 using namespace Opie::Core;
00040 
00041 /* QT */
00042 #include <qtimer.h>
00043 #include <qwindowsystem_qws.h>
00044 #include <qmessagebox.h>
00045 #include <qfileinfo.h>
00046 
00047 /* STD */
00048 #include <sys/stat.h>
00049 #include <sys/wait.h>
00050 #include <sys/file.h>
00051 #include <unistd.h>
00052 #include <sys/time.h>
00053 #include <sys/resource.h>
00054 #include <errno.h>
00055 #include <signal.h>
00056 #include <sys/types.h>
00057 #include <stdlib.h>
00058 
00059 const int AppLauncher::RAISE_TIMEOUT_MS = 5000;
00060 
00061 //---------------------------------------------------------------------------
00062 
00063 static AppLauncher* appLauncherPtr;
00064 
00065 const int appStopEventID = 1290;
00066 
00067 class AppStoppedEvent : public QCustomEvent
00068 {
00069 public:
00070     AppStoppedEvent(int pid, int status)
00071         : QCustomEvent( appStopEventID ), mPid(pid), mStatus(status) { }
00072 
00073     int pid() { return mPid; }
00074     int status() { return mStatus; }
00075 
00076 private:
00077     int mPid, mStatus;
00078 };
00079 
00080 AppLauncher::AppLauncher(QObject *parent, const char *name)
00081     : QObject(parent, name), qlPid(0), qlReady(FALSE),
00082       appKillerBox(0)
00083 {
00084     connect(qwsServer, SIGNAL(newChannel(const QString&)), this, SLOT(newQcopChannel(const QString&)));
00085     connect(qwsServer, SIGNAL(removedChannel(const QString&)), this, SLOT(removedQcopChannel(const QString&)));
00086     QCopChannel* channel = new QCopChannel( "QPE/System", this );
00087     connect( channel, SIGNAL(received(const QCString&,const QByteArray&)),
00088              this, SLOT(received(const QCString&,const QByteArray&)) );
00089 
00090     channel = new QCopChannel( "QPE/Server", this );
00091     connect( channel, SIGNAL(received(const QCString&,const QByteArray&)),
00092              this, SLOT(received(const QCString&,const QByteArray&)) );
00093 
00094 #ifndef Q_OS_WIN32
00095     signal(SIGCHLD, signalHandler);
00096 #else
00097     runningAppsProc.setAutoDelete( TRUE );
00098 #endif
00099     QString tmp = qApp->argv()[0];
00100     int pos = tmp.findRev('/');
00101     if ( pos > -1 )
00102         tmp = tmp.mid(++pos);
00103     runningApps[::getpid()] = tmp;
00104 
00105     appLauncherPtr = this;
00106 
00107     QTimer::singleShot( 1000, this, SLOT(createQuickLauncher()) );
00108 }
00109 
00110 AppLauncher::~AppLauncher()
00111 {
00112     appLauncherPtr = 0;
00113 #ifndef Q_OS_WIN32
00114     signal(SIGCHLD, SIG_DFL);
00115 #endif
00116     if ( qlPid ) {
00117         int status;
00118 	::kill( qlPid, SIGTERM );
00119         waitpid( qlPid, &status, 0 );
00120     }
00121 }
00122 
00123 /*  We use the QCopChannel of the app as an indicator of when it has been launched
00124     so that we can disable the busy indicators */
00125 void AppLauncher::newQcopChannel(const QString& channelName)
00126 {
00127 //  odebug << "channel " << channelName.data() << " added" << oendl;
00128     QString prefix("QPE/Application/");
00129     if (channelName.startsWith(prefix)) {
00130         {
00131             QCopEnvelope e("QPE/System", "newChannel(QString)");
00132             e << channelName;
00133         }
00134         QString appName = channelName.mid(prefix.length());
00135         if ( appName != "quicklauncher" ) {
00136             emit connected( appName );
00137             QCopEnvelope e("QPE/System", "notBusy(QString)");
00138             e << appName;
00139         }
00140     } else if (channelName.startsWith("QPE/QuickLauncher-")) {
00141     odebug << "Registered " << channelName << "" << oendl;
00142         int pid = channelName.mid(18).toInt();
00143         if (pid == qlPid)
00144             qlReady = TRUE;
00145     }
00146 }
00147 
00148 void AppLauncher::removedQcopChannel(const QString& channelName)
00149 {
00150     if (channelName.startsWith("QPE/Application/")) {
00151         QCopEnvelope e("QPE/System", "removedChannel(QString)");
00152         e << channelName;
00153     }
00154 }
00155 
00156 void AppLauncher::received(const QCString& msg, const QByteArray& data)
00157 {
00158     QDataStream stream( data, IO_ReadOnly );
00159     if ( msg == "execute(QString)" ) {
00160         QString t;
00161         stream >> t;
00162         if ( !executeBuiltin( t, QString::null ) )
00163             execute(t, QString::null);
00164     } else if ( msg == "execute(QString,QString)" ) {
00165         QString t,d;
00166         stream >> t >> d;
00167         if ( !executeBuiltin( t, d ) )
00168             execute( t, d );
00169     } else if ( msg == "processQCop(QString)" ) { // from QPE/Server
00170         QString t;
00171         stream >> t;
00172         if ( !executeBuiltin( t, QString::null ) )
00173             execute( t, QString::null, TRUE);
00174     } else if ( msg == "raise(QString)" ) {
00175         QString appName;
00176         stream >> appName;
00177 
00178         if ( !executeBuiltin( appName, QString::null ) ) {
00179             if ( !waitingHeartbeat.contains( appName ) && appKillerName != appName ) {
00180         //odebug << "Raising: " << appName << "" << oendl;
00181                 QCString channel = "QPE/Application/";
00182                 channel += appName.latin1();
00183 
00184                 // Need to lock it to avoid race conditions with QPEApplication::processQCopFile
00185                 QFile f("/tmp/qcop-msg-" + appName);
00186                 if ( f.open(IO_WriteOnly | IO_Append) ) {
00187 #ifndef Q_OS_WIN32
00188                     flock(f.handle(), LOCK_EX);
00189 #endif
00190                     QDataStream ds(&f);
00191                     QByteArray b;
00192                     QDataStream bstream(b, IO_WriteOnly);
00193                     ds << channel << QCString("raise()") << b;
00194                     f.flush();
00195 #ifndef Q_OS_WIN32
00196                     flock(f.handle(), LOCK_UN);
00197 #endif
00198                     f.close();
00199                 }
00200                 bool alreadyRunning = isRunning( appName );
00201                 if ( execute(appName, QString::null) ) {
00202                     int id = startTimer(RAISE_TIMEOUT_MS + alreadyRunning?2000:0);
00203                     waitingHeartbeat.insert( appName, id );
00204                 }
00205             }
00206         }
00207     } else if ( msg == "sendRunningApps()" ) {
00208         QStringList apps;
00209         QMap<int,QString>::Iterator it;
00210         for( it = runningApps.begin(); it != runningApps.end(); ++it )
00211             apps.append( *it );
00212         QCopEnvelope e( "QPE/Desktop", "runningApps(QStringList)" );
00213         e << apps;
00214     } else if ( msg == "appRaised(QString)" ) {
00215         QString appName;
00216         stream >> appName;
00217     odebug << "Got a heartbeat from " << appName << "" << oendl;
00218         QMap<QString,int>::Iterator it = waitingHeartbeat.find(appName);
00219         if ( it != waitingHeartbeat.end() ) {
00220             killTimer( *it );
00221             waitingHeartbeat.remove(it);
00222         }
00223         // Check to make sure we're not waiting on user input...
00224         if ( appKillerBox && appName == appKillerName ) {
00225             // If we are, we kill the dialog box, and the code waiting on the result
00226             // will clean us up (basically the user said "no").
00227             delete appKillerBox;
00228             appKillerBox = 0;
00229             appKillerName = QString::null;
00230         }
00231     }
00232 }
00233 
00234 void AppLauncher::signalHandler(int)
00235 {
00236 #ifndef Q_OS_WIN32
00237     int status;
00238     pid_t pid = waitpid(-1, &status, WNOHANG);
00239 /*    if (pid == 0 || &status == 0 ) {
00240     odebug << "hmm, could not get return value from signal" << oendl;
00241     }
00242 */
00243     QApplication::postEvent(appLauncherPtr, new AppStoppedEvent(pid, status) );
00244 #else
00245     odebug << "Unhandled signal see by AppLauncher::signalHandler(int)" << oendl;
00246 #endif
00247 }
00248 
00249 bool AppLauncher::event(QEvent *e)
00250 {
00251     if ( e->type() == appStopEventID ) {
00252         AppStoppedEvent *ae = (AppStoppedEvent *) e;
00253         sigStopped(ae->pid(), ae->status() );
00254         return TRUE;
00255     }
00256 
00257     return QObject::event(e);
00258 }
00259 
00260 void AppLauncher::timerEvent( QTimerEvent *e )
00261 {
00262     int id = e->timerId();
00263     QMap<QString,int>::Iterator it;
00264     for ( it = waitingHeartbeat.begin(); it != waitingHeartbeat.end(); ++it ) {
00265         if ( *it == id ) {
00266             if ( appKillerBox ) // we're already dealing with one
00267                 return;
00268 
00269             appKillerName = it.key();
00270             killTimer( id );
00271             waitingHeartbeat.remove( it );
00272 
00273         // odebug << "Checking in on " << appKillerName << "" << oendl;
00274 
00275             // We store this incase the application responds while we're
00276             // waiting for user input so we know not to delete ourselves.
00277             appKillerBox = new QMessageBox(tr("Application Problem"),
00278                     tr("<p>%1 is not responding.</p>").arg(appKillerName) +
00279                     tr("<p>Would you like to force the application to exit?</p>"),
00280                     QMessageBox::Warning, QMessageBox::Yes,
00281                     QMessageBox::No | QMessageBox::Default,
00282                     QMessageBox::NoButton);
00283             if (appKillerBox->exec() == QMessageBox::Yes) {
00284         // odebug << "Killing the app!!! Bwuhahahaha!" << oendl;
00285                 int pid = pidForName(appKillerName);
00286                 if ( pid > 0 )
00287                     kill( pid );
00288             }
00289             appKillerName = QString::null;
00290             delete appKillerBox;
00291             appKillerBox = 0;
00292             return;
00293         }
00294     }
00295 
00296     QObject::timerEvent( e );
00297 }
00298 
00299 #ifndef Q_OS_WIN32
00300 void AppLauncher::sigStopped(int sigPid, int sigStatus)
00301 {
00302     int exitStatus = 0;
00303 
00304     bool crashed = WIFSIGNALED(sigStatus);
00305     if ( !crashed ) {
00306         if ( WIFEXITED(sigStatus) )
00307             exitStatus = WEXITSTATUS(sigStatus);
00308     } else {
00309         exitStatus  = WTERMSIG(sigStatus);
00310     }
00311 
00312     QMap<int,QString>::Iterator it = runningApps.find( sigPid );
00313     if ( it == runningApps.end() ) {
00314         if ( sigPid == qlPid ) {
00315         odebug << "quicklauncher stopped" << oendl;
00316             qlPid = 0;
00317             qlReady = FALSE;
00318             QFile::remove("/tmp/qcop-msg-quicklauncher" );
00319             QTimer::singleShot( 2000, this, SLOT(createQuickLauncher()) );
00320         }
00321 /*
00322         if ( sigPid == -1 )
00323         odebug << "non-qtopia application exited (disregarded)" << oendl;
00324         else
00325         odebug << "==== no pid matching " << sigPid << " in list, definite bug" << oendl;
00326 */
00327         return;
00328     }
00329     QString appName = *it;
00330     runningApps.remove(it);
00331 
00332     QMap<QString,int>::Iterator hbit = waitingHeartbeat.find(appName);
00333     if ( hbit != waitingHeartbeat.end() ) {
00334         killTimer( *hbit );
00335         waitingHeartbeat.remove( hbit );
00336     }
00337     if ( appName == appKillerName ) {
00338         appKillerName = QString::null;
00339         delete appKillerBox;
00340         appKillerBox = 0;
00341     }
00342 
00343     /* we must disable preload for an app that crashes as the system logic relies on preloaded apps
00344        actually being loaded.  If eg. the crash happened in the constructor, we can't automatically reload
00345        the app (withouth some timeout value for eg. 3 tries (which I think is a bad solution)
00346     */
00347     bool preloadDisabled = FALSE;
00348     if ( !DocumentList::appLnkSet ) return;
00349     const AppLnk* app = DocumentList::appLnkSet->findExec( appName );
00350     if ( !app ) return; // QCop messages processed to slow?
00351     if ( crashed && app->isPreloaded() ) {
00352         Config cfg("Launcher");
00353         cfg.setGroup("Preload");
00354         QStringList apps = cfg.readListEntry("Apps",',');
00355         QString exe = app->exec();
00356         apps.remove(exe);
00357         cfg.writeEntry("Apps",apps,',');
00358         preloadDisabled = TRUE;
00359     }
00360 
00361     // clean up
00362     if ( exitStatus ) {
00363         QCopEnvelope e("QPE/System", "notBusy(QString)");
00364         e << app->exec();
00365     }
00366 /*
00367     // debug info
00368     for (it = runningApps.begin(); it != runningApps.end(); ++it) {
00369     odebug << "running according to internal list: " << (*it).data() << ", with pid " << it.key() << "" << oendl;
00370     }
00371 */
00372 
00373 #ifdef QTOPIA_PROGRAM_MONITOR
00374     if ( crashed ) {
00375         QString sig;
00376         switch( exitStatus ) {
00377             case SIGABRT: sig = "SIGABRT"; break;
00378             case SIGALRM: sig = "SIGALRM"; break;
00379             case SIGBUS: sig = "SIGBUS"; break;
00380             case SIGFPE: sig = "SIGFPE"; break;
00381             case SIGHUP: sig = "SIGHUP"; break;
00382             case SIGILL: sig = "SIGILL"; break;
00383             case SIGKILL: sig = "SIGKILL"; break;
00384             case SIGPIPE: sig = "SIGPIPE"; break;
00385             case SIGQUIT: sig = "SIGQUIT"; break;
00386             case SIGSEGV: sig = "SIGSEGV"; break;
00387             case SIGTERM: sig = "SIGTERM"; break;
00388             case SIGTRAP: sig = "SIGTRAP"; break;
00389             default: sig = QString("Unkown %1").arg(exitStatus);
00390         }
00391         if ( preloadDisabled )
00392             sig += tr("<qt><p>Fast loading has been disabled for this application.  Tap and hold the application icon to reenable it.</qt>");
00393 
00394         QString str = tr("<qt><b>%1</b> was terminated due to signal code %2</qt>").arg( app->name() ).arg( sig );
00395         QMessageBox::information(0, tr("Application terminated"), str );
00396     } else {
00397         if ( exitStatus == 255 ) {  //could not find app (because global returns -1)
00398             QMessageBox::information(0, tr("Application not found"), tr("<qt>Could not locate application <b>%1</b></qt>").arg( app->exec() ) );
00399         } else  {
00400             QFileInfo fi(QString::fromLatin1("/tmp/qcop-msg-") + appName);
00401             if ( fi.exists() && fi.size() ) {
00402                 emit terminated(sigPid, appName);
00403                 owarn << "Re executing obmitted for " << appName << "" << oendl;
00404 //              execute( appName, QString::null );
00405                 return;
00406             }
00407         }
00408     }
00409 
00410 #endif
00411 
00412     emit terminated(sigPid, appName);
00413 }
00414 #else
00415 void AppLauncher::sigStopped(int sigPid, int sigStatus)
00416 {
00417     odebug << "Unhandled signal : AppLauncher::sigStopped(int sigPid, int sigStatus)" << oendl;
00418 }
00419 #endif // Q_OS_WIN32
00420 
00421 bool AppLauncher::isRunning(const QString &app)
00422 {
00423     for (QMap<int,QString>::ConstIterator it = runningApps.begin(); it != runningApps.end(); ++it) {
00424         if ( *it == app ) {
00425 #ifdef Q_OS_UNIX
00426             pid_t t = ::__getpgid( it.key() );
00427             if ( t == -1 ) {
00428         odebug << "appLauncher bug, " << app.data() << " believed running, but pid " << it.key() << " is not existing" << oendl;
00429                 runningApps.remove( it.key() );
00430                 return FALSE;
00431             }
00432 #endif
00433             return TRUE;
00434         }
00435     }
00436 
00437     return FALSE;
00438 }
00439 
00440 bool AppLauncher::executeBuiltin(const QString &c, const QString &document)
00441 {
00442     Global::Command* builtin = OGlobal::builtinCommands();
00443     QGuardedPtr<QWidget> *running = OGlobal::builtinRunning();
00444 
00445     // Attempt to execute the app using a builtin class for the app
00446     if (builtin) {
00447         for (int i = 0; builtin[i].file; i++) {
00448             if ( builtin[i].file == c ) {
00449                 if ( running[i] ) {
00450                     if ( !document.isNull() && builtin[i].documentary )
00451                         Global::setDocument(running[i], document);
00452                     running[i]->raise();
00453                     running[i]->show();
00454                     running[i]->setActiveWindow();
00455                 } else {
00456                     running[i] = builtin[i].func( builtin[i].maximized );
00457                 }
00458 #ifndef QT_NO_COP
00459                 QCopEnvelope e("QPE/System", "notBusy(QString)" );
00460                 e << c; // that was quick ;-)
00461 #endif
00462                 return TRUE;
00463             }
00464         }
00465     }
00466 
00467     // Convert the command line in to a list of arguments
00468     QStringList list = QStringList::split(QRegExp("  *"),c);
00469     QString ap=list[0];
00470 
00471     if ( ap == "suspend" ) { // No tr
00472         QWSServer::processKeyEvent( 0xffff, Qt::Key_F34, FALSE, TRUE, FALSE );
00473         return TRUE;
00474     }
00475 
00476     return FALSE;
00477 }
00478 
00479 bool AppLauncher::execute(const QString &c, const QString &docParam, bool noRaise)
00480 {
00481     owarn << "AppLauncher::execute '" <<  c << "' '" <<  docParam << "'" << oendl;
00482     // Convert the command line in to a list of arguments
00483     QStringList list = QStringList::split(QRegExp("  *"),c);
00484     QStringList arglist = QStringList::split(QRegExp("  *"),docParam);
00485     for ( QStringList::Iterator it = arglist.begin(); it != arglist.end(); ++it )
00486         list.append( *it );
00487 
00488     QString appName = list[0];
00489     if ( isRunning(appName) ) {
00490         QCString channel = "QPE/Application/";
00491         channel += appName.latin1();
00492 
00493         // Need to lock it to avoid race conditions with QPEApplication::processQCopFile
00494         QFile f(QString::fromLatin1("/tmp/qcop-msg-") + appName);
00495         if ( !noRaise && f.open(IO_WriteOnly | IO_Append) ) {
00496 #ifndef Q_OS_WIN32
00497             flock(f.handle(), LOCK_EX);
00498 #endif
00499 
00500             QDataStream ds(&f);
00501             QByteArray b;
00502             QDataStream bstream(b, IO_WriteOnly);
00503             if ( !f.size() ) {
00504                 ds << channel << QCString("raise()") << b;
00505                 if ( !waitingHeartbeat.contains( appName ) && appKillerName != appName ) {
00506                     int id = startTimer(RAISE_TIMEOUT_MS);
00507                     waitingHeartbeat.insert( appName, id );
00508                 }
00509             }
00510             if ( !docParam.isEmpty() ) {
00511                 bstream << docParam;
00512                 ds << channel << QCString("setDocument(QString)") << b;
00513             }
00514 
00515             f.flush();
00516 #ifndef Q_OS_WIN32
00517             flock(f.handle(), LOCK_UN);
00518 #endif
00519             f.close();
00520         }
00521         if ( QCopChannel::isRegistered(channel) ) // avoid unnecessary warnings
00522             QCopChannel::send(channel,"QPEProcessQCop()");
00523 
00524         return TRUE;
00525     }
00526 
00527 #ifdef QT_NO_QWS_MULTIPROCESS
00528     QMessageBox::warning( 0, tr("Error"), tr("<qt>Could not find the application %1</qt>").arg(c),
00529         tr("OK"), 0, 0, 0, 1 );
00530 #else
00531 
00532     QStrList slist;
00533     unsigned j;
00534     for ( j = 0; j < list.count(); j++ )
00535         slist.append( list[j].utf8() );
00536 
00537     const char **args = new const char *[slist.count() + 1];
00538     for ( j = 0; j < slist.count(); j++ )
00539         args[j] = slist.at(j);
00540     args[j] = NULL;
00541 
00542 #ifndef Q_OS_WIN32
00543 #ifdef Q_OS_MACX
00544     if ( qlPid && qlReady && QFile::exists( QPEApplication::qpeDir()+"plugins/application/lib"+args[0] + ".dylib" ) ) {
00545 #else
00546     if ( qlPid && qlReady && QFile::exists( QPEApplication::qpeDir()+"plugins/application/lib"+args[0] + ".so" ) ) {
00547 #endif /* Q_OS_MACX */
00548     odebug << "Quick launching: " << args[0] << "" << oendl;
00549         if ( getuid() == 0 )
00550             setpriority( PRIO_PROCESS, qlPid, 0 );
00551         QCString qlch("QPE/QuickLauncher-");
00552         qlch += QString::number(qlPid);
00553         QCopEnvelope env( qlch, "execute(QStrList)" );
00554         env << slist;
00555         runningApps[qlPid] = QString(args[0]);
00556         emit launched(qlPid, QString(args[0]));
00557         QCopEnvelope e("QPE/System", "busy()");
00558         qlPid = 0;
00559         qlReady = FALSE;
00560         QTimer::singleShot( getuid() == 0 ? 800 : 1500, this, SLOT(createQuickLauncher()) );
00561     } else {
00562         int pid = ::vfork();
00563         if ( !pid ) {
00564             for ( int fd = 3; fd < 100; fd++ )
00565                 ::close( fd );
00566             ::setpgid( ::getpid(), ::getppid() );
00567             // Try bindir first, so that foo/bar works too
00568             ::execv( QPEApplication::qpeDir()+"bin/"+args[0], (char * const *)args );
00569             ::execvp( args[0], (char * const *)args );
00570             _exit( -1 );
00571         }
00572 
00573         runningApps[pid] = QString(args[0]);
00574         emit launched(pid, QString(args[0]));
00575         QCopEnvelope e("QPE/System", "busy()");
00576     }
00577 #else
00578     QProcess *proc = new QProcess(this);
00579     if (proc){
00580         for (int i=0; i < slist.count(); i++)
00581             proc->addArgument(args[i]);
00582         connect(proc, SIGNAL(processExited()), this, SLOT(processExited()));
00583         if (!proc->start()){
00584         odebug << "Unable to start application " << args[0] << "" << oendl;
00585         }else{
00586             PROCESS_INFORMATION *procInfo = (PROCESS_INFORMATION *)proc->processIdentifier();
00587             if (procInfo){
00588                 DWORD pid = procInfo->dwProcessId;
00589                 runningApps[pid] = QString(args[0]);
00590                 runningAppsProc.append(proc);
00591                 emit launched(pid, QString(args[0]));
00592                 QCopEnvelope e("QPE/System", "busy()");
00593             }else{
00594         odebug << "Unable to read process inforation #1 for " << args[0] << "" << oendl;
00595             }
00596         }
00597     }else{
00598     odebug << "Unable to create process for application " << args[0] << "" << oendl;
00599         return FALSE;
00600     }
00601 #endif
00602 #endif //QT_NO_QWS_MULTIPROCESS
00603 
00604     delete [] args;
00605     return TRUE;
00606 }
00607 
00608 void AppLauncher::kill( int pid )
00609 {
00610 #ifndef Q_OS_WIN32
00611     ::kill( pid, SIGTERM );
00612 #else
00613     for ( QProcess *proc = runningAppsProc.first(); proc; proc = runningAppsProc.next() ) {
00614         if ( proc->processIdentifier() == pid ) {
00615             proc->kill();
00616             break;
00617         }
00618     }
00619 #endif
00620 }
00621 
00622 int AppLauncher::pidForName( const QString &appName )
00623 {
00624     int pid = -1;
00625 
00626     QMap<int, QString>::Iterator it;
00627     for (it = runningApps.begin(); it!= runningApps.end(); ++it) {
00628         if (*it == appName) {
00629             pid = it.key();
00630             break;
00631         }
00632     }
00633 
00634     return pid;
00635 }
00636 
00637 void AppLauncher::createQuickLauncher()
00638 {
00639     static bool disabled = FALSE;
00640     if (disabled)
00641         return;
00642 
00643     qlReady = FALSE;
00644     qlPid = ::vfork();
00645     if ( !qlPid ) {
00646         char **args = new char *[2];
00647         args[0] = "quicklauncher";
00648         args[1] = 0;
00649         for ( int fd = 3; fd < 100; fd++ )
00650             ::close( fd );
00651         ::setpgid( ::getpid(), ::getppid() );
00652         // Try bindir first, so that foo/bar works too
00653         /*
00654          * LD_BIND_NOW will change the behaviour of ld.so and dlopen
00655          * RTLD_LAZY will be made RTLD_NOW which leads to problem
00656          * with miscompiled libraries... if LD_BIND_NOW is set.. there
00657          * is no way back.. We will wait for numbers from TT to see
00658          * if using LD_BIND_NOW is worth it - zecke
00659          */
00660 //      setenv( "LD_BIND_NOW", "1", 1 );
00661         ::execv( QPEApplication::qpeDir()+"bin/quicklauncher", args );
00662         ::execvp( "quicklauncher", args );
00663         delete []args;
00664         disabled = TRUE;
00665         _exit( -1 );
00666     } else if ( qlPid == -1 ) {
00667         qlPid = 0;
00668     } else {
00669         if ( getuid() == 0 )
00670             setpriority( PRIO_PROCESS, qlPid, 19 );
00671     }
00672 }
00673 
00674 // Used only by Win32
00675 void AppLauncher::processExited()
00676 {
00677 #ifdef Q_OS_WIN32
00678     odebug << "AppLauncher::processExited()" << oendl;
00679     bool found = FALSE;
00680     QProcess *proc = (QProcess *) sender();
00681     if (!proc){
00682     odebug << "Interanl error NULL proc" << oendl;
00683         return;
00684     }
00685 
00686     QString appName = proc->arguments()[0];
00687     odebug << "Removing application " << appName << "" << oendl;
00688     runningAppsProc.remove(proc);
00689 
00690     QMap<QString,int>::Iterator hbit = waitingHeartbeat.find(appName);
00691     if ( hbit != waitingHeartbeat.end() ) {
00692         killTimer( *hbit );
00693         waitingHeartbeat.remove( hbit );
00694     }
00695     if ( appName == appKillerName ) {
00696         appKillerName = QString::null;
00697         delete appKillerBox;
00698         appKillerBox = 0;
00699     }
00700 
00701     // Search for the app to find its PID
00702     QMap<int, QString>::Iterator it;
00703     for (it = runningApps.begin(); it!= runningApps.end(); ++it){
00704         if (it.data() == appName){
00705             found = TRUE;
00706             break;
00707         }
00708     }
00709 
00710     if (found){
00711         emit terminated(it.key(), it.data());
00712         runningApps.remove(it.key());
00713     }else{
00714     odebug << "Internal error application " << appName << " not listed as running" << oendl;
00715     }
00716 
00717 #endif
00718 }
00719 

Generated on Sat Nov 5 16:15:29 2005 for OPIE by  doxygen 1.4.2