00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
00042 #include <qtimer.h>
00043 #include <qwindowsystem_qws.h>
00044 #include <qmessagebox.h>
00045 #include <qfileinfo.h>
00046
00047
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
00124
00125 void AppLauncher::newQcopChannel(const QString& channelName)
00126 {
00127
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)" ) {
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
00181 QCString channel = "QPE/Application/";
00182 channel += appName.latin1();
00183
00184
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
00224 if ( appKillerBox && appName == appKillerName ) {
00225
00226
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
00240
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 )
00267 return;
00268
00269 appKillerName = it.key();
00270 killTimer( id );
00271 waitingHeartbeat.remove( it );
00272
00273
00274
00275
00276
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
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
00323
00324
00325
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
00344
00345
00346
00347 bool preloadDisabled = FALSE;
00348 if ( !DocumentList::appLnkSet ) return;
00349 const AppLnk* app = DocumentList::appLnkSet->findExec( appName );
00350 if ( !app ) return;
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
00362 if ( exitStatus ) {
00363 QCopEnvelope e("QPE/System", "notBusy(QString)");
00364 e << app->exec();
00365 }
00366
00367
00368
00369
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 ) {
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
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
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;
00461 #endif
00462 return TRUE;
00463 }
00464 }
00465 }
00466
00467
00468 QStringList list = QStringList::split(QRegExp(" *"),c);
00469 QString ap=list[0];
00470
00471 if ( ap == "suspend" ) {
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
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
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) )
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
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
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
00653
00654
00655
00656
00657
00658
00659
00660
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
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
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