00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 #include <config.h>
00021 #endif
00022
00023 #include <stdio.h>
00024 #include <unistd.h>
00025 #include <stdlib.h>
00026 #include <errno.h>
00027 #include <signal.h>
00028 #include <sys/time.h>
00029
00030 #include <qfile.h>
00031
00032 #include <kconfig.h>
00033 #include <kdebug.h>
00034 #include <klibloader.h>
00035 #include <klocale.h>
00036 #include <kprotocolmanager.h>
00037 #include <kprotocolinfo.h>
00038 #include <krun.h>
00039 #include <kstandarddirs.h>
00040 #include <ktempfile.h>
00041 #include <kurl.h>
00042
00043 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00044 #include <kstartupinfo.h>
00045 #endif
00046
00047
00048 #include "kio/global.h"
00049 #include "kio/connection.h"
00050 #include "kio/slaveinterface.h"
00051
00052 #include "klauncher.h"
00053 #include "klauncher_cmds.h"
00054
00055
00056 #ifdef Q_WS_X11
00057
00058 #include <X11/Xlib.h>
00059 #endif
00060
00061
00062 #define SLAVE_MAX_IDLE 30
00063
00064 using namespace KIO;
00065
00066 template class QPtrList<KLaunchRequest>;
00067 template class QPtrList<IdleSlave>;
00068
00069 IdleSlave::IdleSlave(KSocket *socket)
00070 {
00071 mConn.init(socket);
00072 mConn.connect(this, SLOT(gotInput()));
00073 mConn.send( CMD_SLAVE_STATUS );
00074 mPid = 0;
00075 mBirthDate = time(0);
00076 mOnHold = false;
00077 }
00078
00079 void
00080 IdleSlave::gotInput()
00081 {
00082 int cmd;
00083 QByteArray data;
00084 if (mConn.read( &cmd, data) == -1)
00085 {
00086
00087 kdError(7016) << "SlavePool: No communication with slave." << endl;
00088 delete this;
00089 }
00090 else if (cmd == MSG_SLAVE_ACK)
00091 {
00092 delete this;
00093 }
00094 else if (cmd != MSG_SLAVE_STATUS)
00095 {
00096 kdError(7016) << "SlavePool: Unexpected data from slave." << endl;
00097 delete this;
00098 }
00099 else
00100 {
00101 QDataStream stream( data, IO_ReadOnly );
00102 pid_t pid;
00103 QCString protocol;
00104 QString host;
00105 Q_INT8 b;
00106 stream >> pid >> protocol >> host >> b;
00107
00108 if (!stream.atEnd())
00109 {
00110 KURL url;
00111 stream >> url;
00112 mOnHold = true;
00113 mUrl = url;
00114 }
00115
00116 mPid = pid;
00117 mConnected = (b != 0);
00118 mProtocol = protocol;
00119 mHost = host;
00120 emit statusUpdate(this);
00121 }
00122 }
00123
00124 void
00125 IdleSlave::connect(const QString &app_socket)
00126 {
00127 QByteArray data;
00128 QDataStream stream( data, IO_WriteOnly);
00129 stream << app_socket;
00130 mConn.send( CMD_SLAVE_CONNECT, data );
00131
00132 }
00133
00134 void
00135 IdleSlave::reparseConfiguration()
00136 {
00137 mConn.send( CMD_REPARSECONFIGURATION );
00138 }
00139
00140 bool
00141 IdleSlave::match(const QString &protocol, const QString &host, bool connected)
00142 {
00143 if (mOnHold) return false;
00144 if (protocol != mProtocol) return false;
00145 if (host.isEmpty()) return true;
00146 if (host != mHost) return false;
00147 if (!connected) return true;
00148 if (!mConnected) return false;
00149 return true;
00150 }
00151
00152 bool
00153 IdleSlave::onHold(const KURL &url)
00154 {
00155 if (!mOnHold) return false;
00156 return (url == mUrl);
00157 }
00158
00159 int
00160 IdleSlave::age(time_t now)
00161 {
00162 return (int) difftime(now, mBirthDate);
00163 }
00164
00165 KLauncher::KLauncher(int _kdeinitSocket)
00166 : KApplication( false, false ),
00167 DCOPObject("klauncher"),
00168 kdeinitSocket(_kdeinitSocket), dontBlockReading(false)
00169 {
00170 #ifdef Q_WS_X11
00171 mCached_dpy = NULL;
00172 #endif
00173 connect(&mAutoTimer, SIGNAL(timeout()), this, SLOT(slotAutoStart()));
00174 requestList.setAutoDelete(true);
00175 mSlaveWaitRequest.setAutoDelete(true);
00176 dcopClient()->setNotifications( true );
00177 connect(dcopClient(), SIGNAL( applicationRegistered( const QCString &)),
00178 this, SLOT( slotAppRegistered( const QCString &)));
00179 dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateKDE()",
00180 objId(), "terminateKDE()", false );
00181
00182 QString prefix = locateLocal("socket", "klauncher");
00183 KTempFile domainname(prefix, QString::fromLatin1(".slave-socket"));
00184 if (domainname.status() != 0)
00185 {
00186
00187 qDebug("KLauncher: Fatal error, can't create tempfile!");
00188 ::exit(1);
00189 }
00190 mPoolSocketName = domainname.name();
00191 #ifdef __CYGWIN__
00192 domainname.close();
00193 domainname.unlink();
00194 #endif
00195 mPoolSocket = new KServerSocket(QFile::encodeName(mPoolSocketName));
00196 connect(mPoolSocket, SIGNAL(accepted( KSocket *)),
00197 SLOT(acceptSlave(KSocket *)));
00198
00199 connect(&mTimer, SIGNAL(timeout()), SLOT(idleTimeout()));
00200
00201 kdeinitNotifier = new QSocketNotifier(kdeinitSocket, QSocketNotifier::Read);
00202 connect(kdeinitNotifier, SIGNAL( activated( int )),
00203 this, SLOT( slotKDEInitData( int )));
00204 kdeinitNotifier->setEnabled( true );
00205 lastRequest = 0;
00206 bProcessingQueue = false;
00207
00208 mSlaveDebug = getenv("KDE_SLAVE_DEBUG_WAIT");
00209 if (!mSlaveDebug.isEmpty())
00210 {
00211 qWarning("Klauncher running in slave-debug mode for slaves of protocol '%s'", mSlaveDebug.data());
00212 }
00213 mSlaveValgrind = getenv("KDE_SLAVE_VALGRIND");
00214 if (!mSlaveValgrind.isEmpty())
00215 {
00216 mSlaveValgrindSkin = getenv("KDE_SLAVE_VALGRIND_SKIN");
00217 qWarning("Klauncher running slaves through valgrind for slaves of protocol '%s'", mSlaveValgrind.data());
00218 }
00219 klauncher_header request_header;
00220 request_header.cmd = LAUNCHER_OK;
00221 request_header.arg_length = 0;
00222 write(kdeinitSocket, &request_header, sizeof(request_header));
00223 }
00224
00225 KLauncher::~KLauncher()
00226 {
00227 close();
00228 }
00229
00230 void KLauncher::close()
00231 {
00232 if (!mPoolSocketName.isEmpty())
00233 {
00234 QCString filename = QFile::encodeName(mPoolSocketName);
00235 unlink(filename.data());
00236 }
00237 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00238
00239 if( mCached_dpy != NULL )
00240 XCloseDisplay( mCached_dpy );
00241 #endif
00242 }
00243
00244 void
00245 KLauncher::destruct(int exit_code)
00246 {
00247 if (kapp) ((KLauncher*)kapp)->close();
00248
00249 ::exit(exit_code);
00250 }
00251
00252 bool
00253 KLauncher::process(const QCString &fun, const QByteArray &data,
00254 QCString &replyType, QByteArray &replyData)
00255 {
00256 if ((fun == "exec_blind(QCString,QValueList<QCString>)")
00257 || (fun == "exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)"))
00258 {
00259 QDataStream stream(data, IO_ReadOnly);
00260 replyType = "void";
00261 QCString name;
00262 QValueList<QCString> arg_list;
00263 QCString startup_id = "0";
00264 QValueList<QCString> envs;
00265 stream >> name >> arg_list;
00266 if( fun == "exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)" )
00267 stream >> envs >> startup_id;
00268 kdDebug(7016) << "KLauncher: Got exec_blind('" << name << "', ...)" << endl;
00269 exec_blind( name, arg_list, envs, startup_id);
00270 return true;
00271 }
00272 if ((fun == "start_service_by_name(QString,QStringList)") ||
00273 (fun == "start_service_by_desktop_path(QString,QStringList)")||
00274 (fun == "start_service_by_desktop_name(QString,QStringList)")||
00275 (fun == "kdeinit_exec(QString,QStringList)") ||
00276 (fun == "kdeinit_exec_wait(QString,QStringList)") ||
00277 (fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)") ||
00278 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)")||
00279 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)") ||
00280 (fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)") ||
00281 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)")||
00282 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)") ||
00283 (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") ||
00284 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)") ||
00285 (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)") ||
00286 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)"))
00287 {
00288 QDataStream stream(data, IO_ReadOnly);
00289 bool bNoWait = false;
00290 QString serviceName;
00291 QStringList urls;
00292 QValueList<QCString> envs;
00293 QCString startup_id = "";
00294 DCOPresult.result = -1;
00295 DCOPresult.dcopName = 0;
00296 DCOPresult.error = QString::null;
00297 DCOPresult.pid = 0;
00298 stream >> serviceName >> urls;
00299 if ((fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)") ||
00300 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)")||
00301 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)"))
00302 stream >> envs >> startup_id >> bNoWait;
00303 else if ((fun == "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)") ||
00304 (fun == "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)")||
00305 (fun == "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)"))
00306 stream >> envs >> startup_id;
00307 else if ((fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)") ||
00308 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)"))
00309 stream >> envs;
00310 else if ((fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)") ||
00311 (fun == "kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)"))
00312 stream >> envs >> startup_id;
00313 bool finished;
00314 if (strncmp(fun, "start_service_by_name(", 22) == 0)
00315 {
00316 kdDebug(7016) << "KLauncher: Got start_service_by_name('" << serviceName << "', ...)" << endl;
00317 finished = start_service_by_name(serviceName, urls, envs, startup_id, bNoWait);
00318 }
00319 else if (strncmp(fun, "start_service_by_desktop_path(", 30) == 0)
00320 {
00321 kdDebug(7016) << "KLauncher: Got start_service_by_desktop_path('" << serviceName << "', ...)" << endl;
00322 finished = start_service_by_desktop_path(serviceName, urls, envs, startup_id, bNoWait);
00323 }
00324 else if (strncmp(fun, "start_service_by_desktop_name(", 30) == 0)
00325 {
00326 kdDebug(7016) << "KLauncher: Got start_service_by_desktop_name('" << serviceName << "', ...)" << endl;
00327 finished = start_service_by_desktop_name(serviceName, urls, envs, startup_id, bNoWait );
00328 }
00329 else if ((fun == "kdeinit_exec(QString,QStringList)")
00330 || (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>)")
00331 || (fun == "kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)"))
00332 {
00333 kdDebug(7016) << "KLauncher: Got kdeinit_exec('" << serviceName << "', ...)" << endl;
00334 finished = kdeinit_exec(serviceName, urls, envs, startup_id, false);
00335 }
00336 else
00337 {
00338 kdDebug(7016) << "KLauncher: Got kdeinit_exec_wait('" << serviceName << "', ...)" << endl;
00339 finished = kdeinit_exec(serviceName, urls, envs, startup_id, true);
00340 }
00341 if (!finished)
00342 {
00343 replyType = "serviceResult";
00344 QDataStream stream2(replyData, IO_WriteOnly);
00345 stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid;
00346 }
00347 return true;
00348 }
00349 else if (fun == "requestSlave(QString,QString,QString)")
00350 {
00351 QDataStream stream(data, IO_ReadOnly);
00352 QString protocol;
00353 QString host;
00354 QString app_socket;
00355 stream >> protocol >> host >> app_socket;
00356 replyType = "QString";
00357 QString error;
00358 pid_t pid = requestSlave(protocol, host, app_socket, error);
00359 QDataStream stream2(replyData, IO_WriteOnly);
00360 stream2 << pid << error;
00361 return true;
00362 }
00363 else if (fun == "requestHoldSlave(KURL,QString)")
00364 {
00365 QDataStream stream(data, IO_ReadOnly);
00366 KURL url;
00367 QString app_socket;
00368 stream >> url >> app_socket;
00369 replyType = "pid_t";
00370 pid_t pid = requestHoldSlave(url, app_socket);
00371 QDataStream stream2(replyData, IO_WriteOnly);
00372 stream2 << pid;
00373 return true;
00374 }
00375 else if (fun == "waitForSlave(pid_t)")
00376 {
00377 QDataStream stream(data, IO_ReadOnly);
00378 pid_t pid;
00379 stream >> pid;
00380 waitForSlave(pid);
00381 replyType = "void";
00382 return true;
00383
00384 }
00385 else if (fun == "setLaunchEnv(QCString,QCString)")
00386 {
00387 QDataStream stream(data, IO_ReadOnly);
00388 QCString name;
00389 QCString value;
00390 stream >> name >> value;
00391 setLaunchEnv(name, value);
00392 replyType = "void";
00393 return true;
00394 }
00395 else if (fun == "reparseConfiguration()")
00396 {
00397 KGlobal::config()->reparseConfiguration();
00398 kdDebug(7016) << "KLauncher::process : reparseConfiguration" << endl;
00399 KProtocolManager::reparseConfiguration();
00400 IdleSlave *slave;
00401 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
00402 slave->reparseConfiguration();
00403 replyType = "void";
00404 return true;
00405 }
00406 else if (fun == "terminateKDE()")
00407 {
00408 ::signal( SIGHUP, SIG_IGN);
00409 ::signal( SIGTERM, SIG_IGN);
00410 kdDebug() << "KLauncher::process ---> terminateKDE" << endl;
00411 klauncher_header request_header;
00412 request_header.cmd = LAUNCHER_TERMINATE_KDE;
00413 request_header.arg_length = 0;
00414 write(kdeinitSocket, &request_header, sizeof(request_header));
00415 destruct(0);
00416 }
00417 else if (fun == "autoStart()")
00418 {
00419 kdDebug() << "KLauncher::process ---> autoStart" << endl;
00420 autoStart(1);
00421 replyType = "void";
00422 return true;
00423 }
00424 else if (fun == "autoStart(int)")
00425 {
00426 kdDebug() << "KLauncher::process ---> autoStart(int)" << endl;
00427 QDataStream stream(data, IO_ReadOnly);
00428 int phase;
00429 stream >> phase;
00430 autoStart(phase);
00431 replyType = "void";
00432 return true;
00433 }
00434
00435 if (DCOPObject::process(fun, data, replyType, replyData))
00436 {
00437 return true;
00438 }
00439 kdWarning(7016) << "Got unknown DCOP function: " << fun << endl;
00440 return false;
00441 }
00442
00443 QCStringList
00444 KLauncher::interfaces()
00445 {
00446 QCStringList ifaces = DCOPObject::interfaces();
00447 ifaces += "KLauncher";
00448 return ifaces;
00449 }
00450
00451 QCStringList
00452 KLauncher::functions()
00453 {
00454 QCStringList funcs = DCOPObject::functions();
00455 funcs << "void exec_blind(QCString,QValueList<QCString>)";
00456 funcs << "void exec_blind(QCString,QValueList<QCString>,QValueList<QCString>,QCString)";
00457 funcs << "serviceResult start_service_by_name(QString,QStringList)";
00458 funcs << "serviceResult start_service_by_desktop_path(QString,QStringList)";
00459 funcs << "serviceResult start_service_by_desktop_name(QString,QStringList)";
00460 funcs << "serviceResult kdeinit_exec(QString,QStringList)";
00461 funcs << "serviceResult kdeinit_exec_wait(QString,QStringList)";
00462 funcs << "serviceResult start_service_by_name(QString,QStringList,QValueList<QCString>,QCString)";
00463 funcs << "serviceResult start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString)";
00464 funcs << "serviceResult start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString)";
00465 funcs << "serviceResult start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)";
00466 funcs << "serviceResult start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)";
00467 funcs << "serviceResult start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)";
00468 funcs << "serviceResult kdeinit_exec(QString,QStringList,QValueList<QCString>)";
00469 funcs << "serviceResult kdeinit_exec_wait(QString,QStringList,QValueList<QCString>)";
00470 funcs << "QString requestSlave(QString,QString,QString)";
00471 funcs << "pid_t requestHoldSlave(KURL,QString)";
00472 funcs << "void waitForSlave(pid_t)";
00473 funcs << "void setLaunchEnv(QCString,QCString)";
00474 funcs << "void reparseConfiguration()";
00475
00476 funcs << "void autoStart()";
00477 funcs << "void autoStart(int)";
00478 return funcs;
00479 }
00480
00481 void KLauncher::setLaunchEnv(const QCString &name, const QCString &_value)
00482 {
00483 QCString value(_value);
00484 if (value.isNull())
00485 value = "";
00486 klauncher_header request_header;
00487 QByteArray requestData(name.length()+value.length()+2);
00488 memcpy(requestData.data(), name.data(), name.length()+1);
00489 memcpy(requestData.data()+name.length()+1, value.data(), value.length()+1);
00490 request_header.cmd = LAUNCHER_SETENV;
00491 request_header.arg_length = requestData.size();
00492 write(kdeinitSocket, &request_header, sizeof(request_header));
00493 write(kdeinitSocket, requestData.data(), request_header.arg_length);
00494 }
00495
00496
00497
00498
00499
00500 static int
00501 read_socket(int sock, char *buffer, int len)
00502 {
00503 ssize_t result;
00504 int bytes_left = len;
00505 while ( bytes_left > 0)
00506 {
00507 result = read(sock, buffer, bytes_left);
00508 if (result > 0)
00509 {
00510 buffer += result;
00511 bytes_left -= result;
00512 }
00513 else if (result == 0)
00514 return -1;
00515 else if ((result == -1) && (errno != EINTR))
00516 return -1;
00517 }
00518 return 0;
00519 }
00520
00521
00522 void
00523 KLauncher::slotKDEInitData(int)
00524 {
00525 klauncher_header request_header;
00526 QByteArray requestData;
00527 if( dontBlockReading )
00528 {
00529
00530
00531
00532
00533 fd_set in;
00534 timeval tm = { 0, 0 };
00535 FD_ZERO ( &in );
00536 FD_SET( kdeinitSocket, &in );
00537 select( kdeinitSocket + 1, &in, 0, 0, &tm );
00538 if( !FD_ISSET( kdeinitSocket, &in ))
00539 return;
00540 }
00541 dontBlockReading = false;
00542 int result = read_socket(kdeinitSocket, (char *) &request_header,
00543 sizeof( request_header));
00544 if (result == -1)
00545 {
00546 kdDebug() << "Exiting on read_socket errno: " << errno << endl;
00547 ::signal( SIGHUP, SIG_IGN);
00548 ::signal( SIGTERM, SIG_IGN);
00549 destruct(255);
00550 }
00551 requestData.resize(request_header.arg_length);
00552 result = read_socket(kdeinitSocket, (char *) requestData.data(),
00553 request_header.arg_length);
00554
00555 if (request_header.cmd == LAUNCHER_DIED)
00556 {
00557 long *request_data;
00558 request_data = (long *) requestData.data();
00559 processDied(request_data[0], request_data[1]);
00560 return;
00561 }
00562 if (lastRequest && (request_header.cmd == LAUNCHER_OK))
00563 {
00564 long *request_data;
00565 request_data = (long *) requestData.data();
00566 lastRequest->pid = (pid_t) (*request_data);
00567 kdDebug(7016) << lastRequest->name << " (pid " << lastRequest->pid <<
00568 ") up and running." << endl;
00569 switch(lastRequest->dcop_service_type)
00570 {
00571 case KService::DCOP_None:
00572 {
00573 lastRequest->status = KLaunchRequest::Running;
00574 break;
00575 }
00576
00577 case KService::DCOP_Unique:
00578 {
00579 lastRequest->status = KLaunchRequest::Launching;
00580 break;
00581 }
00582
00583 case KService::DCOP_Wait:
00584 {
00585 lastRequest->status = KLaunchRequest::Launching;
00586 break;
00587 }
00588
00589 case KService::DCOP_Multi:
00590 {
00591 lastRequest->status = KLaunchRequest::Launching;
00592 break;
00593 }
00594 }
00595 lastRequest = 0;
00596 return;
00597 }
00598 if (lastRequest && (request_header.cmd == LAUNCHER_ERROR))
00599 {
00600 lastRequest->status = KLaunchRequest::Error;
00601 if (!requestData.isEmpty())
00602 lastRequest->errorMsg = QString::fromUtf8((char *) requestData.data());
00603 lastRequest = 0;
00604 return;
00605 }
00606
00607 kdWarning(7016) << "Unexpected command from KDEInit (" << (unsigned int) request_header.cmd
00608 << ")" << endl;
00609 }
00610
00611 void
00612 KLauncher::processDied(pid_t pid, long )
00613 {
00614 KLaunchRequest *request = requestList.first();
00615 for(; request; request = requestList.next())
00616 {
00617 if (request->pid == pid)
00618 {
00619 if (request->dcop_service_type == KService::DCOP_Wait)
00620 request->status = KLaunchRequest::Done;
00621 else if ((request->dcop_service_type == KService::DCOP_Unique) &&
00622 (dcopClient()->isApplicationRegistered(request->dcop_name)))
00623 request->status = KLaunchRequest::Running;
00624 else
00625 request->status = KLaunchRequest::Error;
00626 requestDone(request);
00627 return;
00628 }
00629 }
00630 }
00631
00632 void
00633 KLauncher::slotAppRegistered(const QCString &appId)
00634 {
00635 const char *cAppId = appId.data();
00636 if (!cAppId) return;
00637
00638 KLaunchRequest *request = requestList.first();
00639 KLaunchRequest *nextRequest;
00640 for(; request; request = nextRequest)
00641 {
00642 nextRequest = requestList.next();
00643 if (request->status != KLaunchRequest::Launching)
00644 continue;
00645
00646
00647 if ((request->dcop_service_type == KService::DCOP_Unique) &&
00648 ((appId == request->dcop_name) ||
00649 dcopClient()->isApplicationRegistered(request->dcop_name)))
00650 {
00651 request->status = KLaunchRequest::Running;
00652 requestDone(request);
00653 continue;
00654 }
00655
00656 const char *rAppId = request->dcop_name.data();
00657 if (!rAppId) continue;
00658
00659 int l = strlen(rAppId);
00660 if ((strncmp(rAppId, cAppId, l) == 0) &&
00661 ((cAppId[l] == '\0') || (cAppId[l] == '-')))
00662 {
00663 request->dcop_name = appId;
00664 request->status = KLaunchRequest::Running;
00665 requestDone(request);
00666 continue;
00667 }
00668 }
00669 }
00670
00671 void
00672 KLauncher::autoStart(int phase)
00673 {
00674 if( mAutoStart.phase() >= phase )
00675 return;
00676 mAutoStart.setPhase(phase);
00677 if (phase == 1)
00678 mAutoStart.loadAutoStartList();
00679 mAutoTimer.start(0, true);
00680 }
00681
00682 void
00683 KLauncher::slotAutoStart()
00684 {
00685 KService::Ptr s;
00686 do
00687 {
00688 QString service = mAutoStart.startService();
00689 if (service.isEmpty())
00690 {
00691
00692 if( !mAutoStart.phaseDone())
00693 {
00694 mAutoStart.setPhaseDone();
00695
00696 QCString autoStartSignal( "autoStartDone()" );
00697 int phase = mAutoStart.phase();
00698 if ( phase > 1 )
00699 autoStartSignal.sprintf( "autoStart%dDone()", phase );
00700 emitDCOPSignal(autoStartSignal, QByteArray());
00701 }
00702 return;
00703 }
00704 s = new KService(service);
00705 }
00706 while (!start_service(s, QStringList(), QValueList<QCString>(), "0", false, true));
00707
00708 }
00709
00710 void
00711 KLauncher::requestDone(KLaunchRequest *request)
00712 {
00713 if ((request->status == KLaunchRequest::Running) ||
00714 (request->status == KLaunchRequest::Done))
00715 {
00716 DCOPresult.result = 0;
00717 DCOPresult.dcopName = request->dcop_name;
00718 DCOPresult.error = QString::null;
00719 DCOPresult.pid = request->pid;
00720 }
00721 else
00722 {
00723 DCOPresult.result = 1;
00724 DCOPresult.dcopName = "";
00725 DCOPresult.error = i18n("KDEInit could not launch '%1'.").arg(request->name);
00726 if (!request->errorMsg.isEmpty())
00727 DCOPresult.error += ":\n" + request->errorMsg;
00728 DCOPresult.pid = 0;
00729
00730 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00731
00732 if (!request->startup_dpy.isEmpty())
00733 {
00734 Display* dpy = NULL;
00735 if( (mCached_dpy != NULL) &&
00736 (request->startup_dpy == XDisplayString( mCached_dpy )))
00737 dpy = mCached_dpy;
00738 if( dpy == NULL )
00739 dpy = XOpenDisplay( request->startup_dpy );
00740 if( dpy )
00741 {
00742 KStartupInfoId id;
00743 id.initId( request->startup_id );
00744 KStartupInfo::sendFinishX( dpy, id );
00745 if( mCached_dpy != dpy && mCached_dpy != NULL )
00746 XCloseDisplay( mCached_dpy );
00747 mCached_dpy = dpy;
00748 }
00749 }
00750 #endif
00751 }
00752
00753 if (request->autoStart)
00754 {
00755 mAutoTimer.start(0, true);
00756 }
00757
00758 if (request->transaction)
00759 {
00760 QByteArray replyData;
00761 QCString replyType;
00762 replyType = "serviceResult";
00763 QDataStream stream2(replyData, IO_WriteOnly);
00764 stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid;
00765 dcopClient()->endTransaction( request->transaction,
00766 replyType, replyData);
00767 }
00768 requestList.removeRef( request );
00769 }
00770
00771 void
00772 KLauncher::requestStart(KLaunchRequest *request)
00773 {
00774 requestList.append( request );
00775
00776 klauncher_header request_header;
00777 QByteArray requestData;
00778 int length = 0;
00779 length += sizeof(long);
00780 length += request->name.length() + 1;
00781 for(QValueList<QCString>::Iterator it = request->arg_list.begin();
00782 it != request->arg_list.end();
00783 it++)
00784 {
00785 length += (*it).length() + 1;
00786 }
00787 length += sizeof(long);
00788 for(QValueList<QCString>::ConstIterator it = request->envs.begin();
00789 it != request->envs.end();
00790 it++)
00791 {
00792 length += (*it).length() + 1;
00793 }
00794 length += sizeof( long );
00795 #ifdef Q_WS_X11
00796 bool startup_notify = !request->startup_id.isNull() && request->startup_id != "0";
00797 if( startup_notify )
00798 length += request->startup_id.length() + 1;
00799 #endif
00800 if (!request->cwd.isEmpty())
00801 length += request->cwd.length() + 1;
00802
00803 requestData.resize( length );
00804
00805 char *p = requestData.data();
00806 long l = request->arg_list.count()+1;
00807 memcpy(p, &l, sizeof(long));
00808 p += sizeof(long);
00809 strcpy(p, request->name.data());
00810 p += strlen(p) + 1;
00811 for(QValueList<QCString>::Iterator it = request->arg_list.begin();
00812 it != request->arg_list.end();
00813 it++)
00814 {
00815 strcpy(p, (*it).data());
00816 p += strlen(p) + 1;
00817 }
00818 l = request->envs.count();
00819 memcpy(p, &l, sizeof(long));
00820 p += sizeof(long);
00821 for(QValueList<QCString>::ConstIterator it = request->envs.begin();
00822 it != request->envs.end();
00823 it++)
00824 {
00825 strcpy(p, (*it).data());
00826 p += strlen(p) + 1;
00827 }
00828 l = 0;
00829 memcpy(p, &l, sizeof(long));
00830 p += sizeof(long);
00831 #ifdef Q_WS_X11
00832 if( startup_notify )
00833 {
00834 strcpy(p, request->startup_id.data());
00835 p += strlen( p ) + 1;
00836 }
00837 #endif
00838 if (!request->cwd.isEmpty())
00839 {
00840 strcpy(p, request->cwd.data());
00841 p += strlen( p ) + 1;
00842 }
00843 #ifdef Q_WS_X11
00844 request_header.cmd = startup_notify ? LAUNCHER_EXT_EXEC : LAUNCHER_EXEC_NEW;
00845 #else
00846 request_header.cmd = LAUNCHER_EXEC_NEW;
00847 #endif
00848 request_header.arg_length = length;
00849 write(kdeinitSocket, &request_header, sizeof(request_header));
00850 write(kdeinitSocket, requestData.data(), request_header.arg_length);
00851
00852
00853 lastRequest = request;
00854 dontBlockReading = false;
00855 do {
00856 slotKDEInitData( kdeinitSocket );
00857 }
00858 while (lastRequest != 0);
00859 dontBlockReading = true;
00860 }
00861
00862 void
00863 KLauncher::exec_blind( const QCString &name, const QValueList<QCString> &arg_list,
00864 const QValueList<QCString> &envs, const QCString& startup_id )
00865 {
00866 KLaunchRequest *request = new KLaunchRequest;
00867 request->autoStart = false;
00868 request->name = name;
00869 request->arg_list = arg_list;
00870 request->dcop_name = 0;
00871 request->dcop_service_type = KService::DCOP_None;
00872 request->pid = 0;
00873 request->status = KLaunchRequest::Launching;
00874 request->transaction = 0;
00875 request->envs = envs;
00876
00877 KService::Ptr service = KService::serviceByDesktopName( name.mid( name.findRev( '/' ) + 1 ));
00878 if (service != NULL)
00879 send_service_startup_info( request, service,
00880 startup_id, QValueList< QCString >());
00881 else
00882 cancel_service_startup_info( request, startup_id, envs );
00883
00884 requestStart(request);
00885
00886 requestDone(request);
00887 }
00888
00889
00890 bool
00891 KLauncher::start_service_by_name(const QString &serviceName, const QStringList &urls,
00892 const QValueList<QCString> &envs, const QCString& startup_id, bool blind)
00893 {
00894 KService::Ptr service = 0;
00895
00896 service = KService::serviceByName(serviceName);
00897 if (!service)
00898 {
00899 DCOPresult.result = ENOENT;
00900 DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
00901 cancel_service_startup_info( NULL, startup_id, envs );
00902 return false;
00903 }
00904 return start_service(service, urls, envs, startup_id, blind);
00905 }
00906
00907 bool
00908 KLauncher::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls,
00909 const QValueList<QCString> &envs, const QCString& startup_id, bool blind)
00910 {
00911 KService::Ptr service = 0;
00912
00913 if (serviceName[0] == '/')
00914 {
00915
00916 service = new KService(serviceName);
00917 }
00918 else
00919 {
00920 service = KService::serviceByDesktopPath(serviceName);
00921 }
00922 if (!service)
00923 {
00924 DCOPresult.result = ENOENT;
00925 DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
00926 cancel_service_startup_info( NULL, startup_id, envs );
00927 return false;
00928 }
00929 return start_service(service, urls, envs, startup_id, blind);
00930 }
00931
00932 bool
00933 KLauncher::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls,
00934 const QValueList<QCString> &envs, const QCString& startup_id, bool blind)
00935 {
00936 KService::Ptr service = 0;
00937
00938 service = KService::serviceByDesktopName(serviceName);
00939 if (!service)
00940 {
00941 DCOPresult.result = ENOENT;
00942 DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
00943 cancel_service_startup_info( NULL, startup_id, envs );
00944 return false;
00945 }
00946 return start_service(service, urls, envs, startup_id, blind);
00947 }
00948
00949 bool
00950 KLauncher::start_service(KService::Ptr service, const QStringList &_urls,
00951 const QValueList<QCString> &envs, const QCString& startup_id, bool blind, bool autoStart)
00952 {
00953 QStringList urls = _urls;
00954 if (!service->isValid())
00955 {
00956 DCOPresult.result = ENOEXEC;
00957 DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath());
00958 cancel_service_startup_info( NULL, startup_id, envs );
00959 return false;
00960 }
00961 KLaunchRequest *request = new KLaunchRequest;
00962 request->autoStart = autoStart;
00963
00964 if ((urls.count() > 1) && !service->allowMultipleFiles())
00965 {
00966
00967
00968
00969
00970
00971 QStringList::ConstIterator it = urls.begin();
00972 for(++it;
00973 it != urls.end();
00974 ++it)
00975 {
00976 QStringList singleUrl;
00977 singleUrl.append(*it);
00978 QCString startup_id2 = startup_id;
00979 if( !startup_id2.isEmpty() && startup_id2 != "0" )
00980 startup_id2 = "0";
00981 start_service( service, singleUrl, envs, startup_id2, true);
00982 }
00983 QString firstURL = *(urls.begin());
00984 urls.clear();
00985 urls.append(firstURL);
00986 }
00987 createArgs(request, service, urls);
00988
00989
00990 if (!request->arg_list.count())
00991 {
00992 DCOPresult.result = ENOEXEC;
00993 DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath());
00994 delete request;
00995 cancel_service_startup_info( NULL, startup_id, envs );
00996 return false;
00997 }
00998
00999 request->name = request->arg_list.first();
01000 request->arg_list.remove(request->arg_list.begin());
01001
01002 request->dcop_service_type = service->DCOPServiceType();
01003
01004 if ((request->dcop_service_type == KService::DCOP_Unique) ||
01005 (request->dcop_service_type == KService::DCOP_Multi))
01006 {
01007 QVariant v = service->property("X-DCOP-ServiceName");
01008 if (v.isValid())
01009 request->dcop_name = v.toString().utf8();
01010 if (request->dcop_name.isEmpty())
01011 {
01012 request->dcop_name = QFile::encodeName(KRun::binaryName(service->exec(), true));
01013 }
01014 }
01015
01016 request->pid = 0;
01017 request->transaction = 0;
01018 request->envs = envs;
01019 send_service_startup_info( request, service, startup_id, envs );
01020
01021
01022 if (!blind && !autoStart)
01023 {
01024 request->transaction = dcopClient()->beginTransaction();
01025 }
01026 queueRequest(request);
01027 return true;
01028 }
01029
01030 void
01031 KLauncher::send_service_startup_info( KLaunchRequest *request, KService::Ptr service, const QCString& startup_id,
01032 const QValueList<QCString> &envs )
01033 {
01034 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
01035
01036 request->startup_id = "0";
01037 if( startup_id == "0" )
01038 return;
01039 bool silent;
01040 QCString wmclass;
01041 if( !KRun::checkStartupNotify( QString::null, service, &silent, &wmclass ))
01042 return;
01043 KStartupInfoId id;
01044 id.initId( startup_id );
01045 const char* dpy_str = NULL;
01046 for( QValueList<QCString>::ConstIterator it = envs.begin();
01047 it != envs.end();
01048 ++it )
01049 if( strncmp( *it, "DISPLAY=", 8 ) == 0 )
01050 dpy_str = static_cast< const char* >( *it ) + 8;
01051 Display* dpy = NULL;
01052 if( dpy_str != NULL && mCached_dpy != NULL
01053 && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 )
01054 dpy = mCached_dpy;
01055 if( dpy == NULL )
01056 dpy = XOpenDisplay( dpy_str );
01057 request->startup_id = id.id();
01058 if( dpy == NULL )
01059 {
01060 cancel_service_startup_info( request, startup_id, envs );
01061 return;
01062 }
01063
01064 request->startup_dpy = dpy_str;
01065
01066 KStartupInfoData data;
01067 data.setName( service->name());
01068 data.setIcon( service->icon());
01069 data.setDescription( i18n( "Launching %1" ).arg( service->name()));
01070 if( !wmclass.isEmpty())
01071 data.setWMClass( wmclass );
01072 if( silent )
01073 data.setSilent( KStartupInfoData::Yes );
01074
01075 KStartupInfo::sendStartupX( dpy, id, data );
01076 if( mCached_dpy != dpy && mCached_dpy != NULL )
01077 XCloseDisplay( mCached_dpy );
01078 mCached_dpy = dpy;
01079 return;
01080 #else
01081 return;
01082 #endif
01083 }
01084
01085 void
01086 KLauncher::cancel_service_startup_info( KLaunchRequest* request, const QCString& startup_id,
01087 const QValueList<QCString> &envs )
01088 {
01089 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
01090
01091 if( request != NULL )
01092 request->startup_id = "0";
01093 if( !startup_id.isEmpty() && startup_id != "0" )
01094 {
01095 const char* dpy_str = NULL;
01096 for( QValueList<QCString>::ConstIterator it = envs.begin();
01097 it != envs.end();
01098 ++it )
01099 if( strncmp( *it, "DISPLAY=", 8 ) == 0 )
01100 dpy_str = static_cast< const char* >( *it ) + 8;
01101 Display* dpy = NULL;
01102 if( dpy_str != NULL && mCached_dpy != NULL
01103 && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 )
01104 dpy = mCached_dpy;
01105 if( dpy == NULL )
01106 dpy = XOpenDisplay( dpy_str );
01107 if( dpy == NULL )
01108 return;
01109 KStartupInfoId id;
01110 id.initId( startup_id );
01111 KStartupInfo::sendFinishX( dpy, id );
01112 if( mCached_dpy != dpy && mCached_dpy != NULL )
01113 XCloseDisplay( mCached_dpy );
01114 mCached_dpy = dpy;
01115 }
01116 #endif
01117 }
01118
01119 bool
01120 KLauncher::kdeinit_exec(const QString &app, const QStringList &args,
01121 const QValueList<QCString> &envs, QCString startup_id, bool wait)
01122 {
01123 KLaunchRequest *request = new KLaunchRequest;
01124 request->autoStart = false;
01125
01126 for(QStringList::ConstIterator it = args.begin();
01127 it != args.end();
01128 it++)
01129 {
01130 QString arg = *it;
01131 request->arg_list.append(arg.local8Bit());
01132 }
01133
01134 request->name = app.local8Bit();
01135
01136 if (wait)
01137 request->dcop_service_type = KService::DCOP_Wait;
01138 else
01139 request->dcop_service_type = KService::DCOP_None;
01140 request->dcop_name = 0;
01141 request->pid = 0;
01142 #ifdef Q_WS_X11
01143 request->startup_id = startup_id;
01144 #endif
01145 request->envs = envs;
01146 if( app != "kbuildsycoca" )
01147 {
01148
01149 KService::Ptr service = KService::serviceByDesktopName( app.mid( app.findRev( '/' ) + 1 ));
01150 if (service != NULL)
01151 send_service_startup_info( request, service,
01152 startup_id, QValueList< QCString >());
01153 else
01154 cancel_service_startup_info( request, startup_id, envs );
01155 }
01156 request->transaction = dcopClient()->beginTransaction();
01157 queueRequest(request);
01158 return true;
01159 }
01160
01161 void
01162 KLauncher::queueRequest(KLaunchRequest *request)
01163 {
01164 requestQueue.append( request );
01165 if (!bProcessingQueue)
01166 {
01167 bProcessingQueue = true;
01168 QTimer::singleShot(0, this, SLOT( slotDequeue() ));
01169 }
01170 }
01171
01172 void
01173 KLauncher::slotDequeue()
01174 {
01175 do {
01176 KLaunchRequest *request = requestQueue.take(0);
01177
01178 request->status = KLaunchRequest::Launching;
01179 requestStart(request);
01180 if (request->status != KLaunchRequest::Launching)
01181 {
01182
01183 requestDone( request );
01184 continue;
01185 }
01186 } while(requestQueue.count());
01187 bProcessingQueue = false;
01188 }
01189
01190 void
01191 KLauncher::createArgs( KLaunchRequest *request, const KService::Ptr service ,
01192 const QStringList &urls)
01193 {
01194 QStringList params = KRun::processDesktopExec(*service, urls, false);
01195
01196 for(QStringList::ConstIterator it = params.begin();
01197 it != params.end(); ++it)
01198 {
01199 request->arg_list.append((*it).local8Bit());
01200 }
01201 request->cwd = QFile::encodeName(service->path());
01202 }
01203
01205
01206 pid_t
01207 KLauncher::requestHoldSlave(const KURL &url, const QString &app_socket)
01208 {
01209 IdleSlave *slave;
01210 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01211 {
01212 if (slave->onHold(url))
01213 break;
01214 }
01215 if (slave)
01216 {
01217 mSlaveList.removeRef(slave);
01218 slave->connect(app_socket);
01219 return slave->pid();
01220 }
01221 return 0;
01222 }
01223
01224
01225 pid_t
01226 KLauncher::requestSlave(const QString &protocol,
01227 const QString &host,
01228 const QString &app_socket,
01229 QString &error)
01230 {
01231 IdleSlave *slave;
01232 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01233 {
01234 if (slave->match(protocol, host, true))
01235 break;
01236 }
01237 if (!slave)
01238 {
01239 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01240 {
01241 if (slave->match(protocol, host, false))
01242 break;
01243 }
01244 }
01245 if (!slave)
01246 {
01247 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01248 {
01249 if (slave->match(protocol, QString::null, false))
01250 break;
01251 }
01252 }
01253 if (slave)
01254 {
01255 mSlaveList.removeRef(slave);
01256 slave->connect(app_socket);
01257 return slave->pid();
01258 }
01259
01260 QString _name = KProtocolInfo::exec(protocol);
01261 if (_name.isEmpty())
01262 {
01263 error = i18n("Unknown protocol '%1'.\n").arg(protocol);
01264 return 0;
01265 }
01266
01267 QCString name = _name.latin1();
01268 QCString arg1 = protocol.latin1();
01269 QCString arg2 = QFile::encodeName(mPoolSocketName);
01270 QCString arg3 = QFile::encodeName(app_socket);
01271 QValueList<QCString> arg_list;
01272 arg_list.append(arg1);
01273 arg_list.append(arg2);
01274 arg_list.append(arg3);
01275
01276
01277 if (mSlaveDebug == arg1)
01278 {
01279 klauncher_header request_header;
01280 request_header.cmd = LAUNCHER_DEBUG_WAIT;
01281 request_header.arg_length = 0;
01282 write(kdeinitSocket, &request_header, sizeof(request_header));
01283 }
01284 if (mSlaveValgrind == arg1)
01285 {
01286 arg_list.prepend(QFile::encodeName(KLibLoader::findLibrary(name)));
01287 arg_list.prepend(QFile::encodeName(locate("exe", "kioslave")));
01288 name = "valgrind";
01289 if (!mSlaveValgrindSkin.isEmpty()) {
01290 arg_list.prepend(QCString("--tool=") + mSlaveValgrindSkin);
01291 } else
01292 arg_list.prepend("--tool=addrcheck");
01293 }
01294
01295 KLaunchRequest *request = new KLaunchRequest;
01296 request->autoStart = false;
01297 request->name = name;
01298 request->arg_list = arg_list;
01299 request->dcop_name = 0;
01300 request->dcop_service_type = KService::DCOP_None;
01301 request->pid = 0;
01302 #ifdef Q_WS_X11
01303 request->startup_id = "0";
01304 #endif
01305 request->status = KLaunchRequest::Launching;
01306 request->transaction = 0;
01307 requestStart(request);
01308 pid_t pid = request->pid;
01309
01310
01311
01312
01313 requestDone(request);
01314 if (!pid)
01315 {
01316 error = i18n("Error loading '%1'.\n").arg(name);
01317 }
01318 return pid;
01319 }
01320
01321 void
01322 KLauncher::waitForSlave(pid_t pid)
01323 {
01324 IdleSlave *slave;
01325 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01326 {
01327 if (slave->pid() == pid)
01328 return;
01329 }
01330 SlaveWaitRequest *waitRequest = new SlaveWaitRequest;
01331 waitRequest->transaction = dcopClient()->beginTransaction();
01332 waitRequest->pid = pid;
01333 mSlaveWaitRequest.append(waitRequest);
01334 }
01335
01336 void
01337 KLauncher::acceptSlave(KSocket *slaveSocket)
01338 {
01339 IdleSlave *slave = new IdleSlave(slaveSocket);
01340
01341 mSlaveList.append(slave);
01342 connect(slave, SIGNAL(destroyed()), this, SLOT(slotSlaveGone()));
01343 connect(slave, SIGNAL(statusUpdate(IdleSlave *)),
01344 this, SLOT(slotSlaveStatus(IdleSlave *)));
01345 if (!mTimer.isActive())
01346 {
01347 mTimer.start(1000*10);
01348 }
01349 }
01350
01351 void
01352 KLauncher::slotSlaveStatus(IdleSlave *slave)
01353 {
01354 SlaveWaitRequest *waitRequest = mSlaveWaitRequest.first();
01355 while(waitRequest)
01356 {
01357 if (waitRequest->pid == slave->pid())
01358 {
01359 QByteArray replyData;
01360 QCString replyType;
01361 replyType = "void";
01362 dcopClient()->endTransaction( waitRequest->transaction, replyType, replyData);
01363 mSlaveWaitRequest.removeRef(waitRequest);
01364 waitRequest = mSlaveWaitRequest.current();
01365 }
01366 else
01367 {
01368 waitRequest = mSlaveWaitRequest.next();
01369 }
01370 }
01371 }
01372
01373 void
01374 KLauncher::slotSlaveGone()
01375 {
01376 IdleSlave *slave = (IdleSlave *) sender();
01377 mSlaveList.removeRef(slave);
01378 if ((mSlaveList.count() == 0) && (mTimer.isActive()))
01379 {
01380 mTimer.stop();
01381 }
01382 }
01383
01384 void
01385 KLauncher::idleTimeout()
01386 {
01387 bool keepOneFileSlave=true;
01388 time_t now = time(0);
01389 IdleSlave *slave;
01390 for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
01391 {
01392 if ((slave->protocol()=="file") && (keepOneFileSlave))
01393 keepOneFileSlave=false;
01394 else if (slave->age(now) > SLAVE_MAX_IDLE)
01395 {
01396
01397 delete slave;
01398 }
01399 }
01400 }
01401
01402 #include "klauncher.moc"