summaryrefslogtreecommitdiffstats
path: root/tdeinit/tdelauncher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdeinit/tdelauncher.cpp')
-rw-r--r--tdeinit/tdelauncher.cpp1421
1 files changed, 1421 insertions, 0 deletions
diff --git a/tdeinit/tdelauncher.cpp b/tdeinit/tdelauncher.cpp
new file mode 100644
index 000000000..f7ca08678
--- /dev/null
+++ b/tdeinit/tdelauncher.cpp
@@ -0,0 +1,1421 @@
+/*
+ This file is part of the KDE libraries
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include <tqfile.h>
+
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <klibloader.h>
+#include <tdelocale.h>
+#include <tdeprotocolmanager.h>
+#include <kprotocolinfo.h>
+#include <krun.h>
+#include <kstandarddirs.h>
+#include <tdetempfile.h>
+#include <kurl.h>
+
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+#include <tdestartupinfo.h> // schroder
+#endif
+
+
+#include "tdeio/global.h"
+#include "tdeio/connection.h"
+#include "tdeio/slaveinterface.h"
+
+#include "tdelauncher.h"
+#include "tdelauncher_cmds.h"
+
+//#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+#ifdef Q_WS_X11
+//#undef K_WS_QTONLY
+#include <X11/Xlib.h> // schroder
+#endif
+
+// Dispose slaves after being idle for SLAVE_MAX_IDLE seconds
+#define SLAVE_MAX_IDLE 30
+
+using namespace TDEIO;
+
+template class TQPtrList<TDELaunchRequest>;
+template class TQPtrList<IdleSlave>;
+
+IdleSlave::IdleSlave(TDESocket *socket)
+{
+ mConn.init(socket);
+ mConn.connect(this, TQT_SLOT(gotInput()));
+ mConn.send( CMD_SLAVE_STATUS );
+ mPid = 0;
+ mBirthDate = time(0);
+ mOnHold = false;
+}
+
+void
+IdleSlave::gotInput()
+{
+ int cmd;
+ TQByteArray data;
+ if (mConn.read( &cmd, data) == -1)
+ {
+ // Communication problem with slave.
+ kdError(7016) << "SlavePool: No communication with slave." << endl;
+ delete this;
+ }
+ else if (cmd == MSG_SLAVE_ACK)
+ {
+ delete this;
+ }
+ else if (cmd != MSG_SLAVE_STATUS)
+ {
+ kdError(7016) << "SlavePool: Unexpected data from slave." << endl;
+ delete this;
+ }
+ else
+ {
+ TQDataStream stream( data, IO_ReadOnly );
+ pid_t pid;
+ TQCString protocol;
+ TQString host;
+ TQ_INT8 b;
+ stream >> pid >> protocol >> host >> b;
+// Overload with (bool) onHold, (KURL) url.
+ if (!stream.atEnd())
+ {
+ KURL url;
+ stream >> url;
+ mOnHold = true;
+ mUrl = url;
+ }
+
+ mPid = pid;
+ mConnected = (b != 0);
+ mProtocol = protocol;
+ mHost = host;
+ emit statusUpdate(this);
+ }
+}
+
+void
+IdleSlave::connect(const TQString &app_socket)
+{
+ TQByteArray data;
+ TQDataStream stream( data, IO_WriteOnly);
+ stream << app_socket;
+ mConn.send( CMD_SLAVE_CONNECT, data );
+ // Timeout!
+}
+
+void
+IdleSlave::reparseConfiguration()
+{
+ mConn.send( CMD_REPARSECONFIGURATION );
+}
+
+bool
+IdleSlave::match(const TQString &protocol, const TQString &host, bool connected)
+{
+ if (mOnHold) return false;
+ if (protocol != mProtocol) return false;
+ if (host.isEmpty()) return true;
+ if (host != mHost) return false;
+ if (!connected) return true;
+ if (!mConnected) return false;
+ return true;
+}
+
+bool
+IdleSlave::onHold(const KURL &url)
+{
+ if (!mOnHold) return false;
+ return (url == mUrl);
+}
+
+int
+IdleSlave::age(time_t now)
+{
+ return (int) difftime(now, mBirthDate);
+}
+
+TDELauncher::TDELauncher(int _tdeinitSocket, bool new_startup)
+// : TDEApplication( false, false ), // No Styles, No GUI
+ : TDEApplication( false, true ), // TQClipboard tries to construct a QWidget so a GUI is technically needed, even though it is not used
+ DCOPObject("tdelauncher"),
+ tdeinitSocket(_tdeinitSocket), mAutoStart( new_startup ),
+ dontBlockReading(false), newStartup( new_startup )
+{
+#ifdef Q_WS_X11
+ mCached_dpy = NULL;
+#endif
+ connect(&mAutoTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotAutoStart()));
+ requestList.setAutoDelete(true);
+ mSlaveWaitRequest.setAutoDelete(true);
+ dcopClient()->setNotifications( true );
+ connect(dcopClient(), TQT_SIGNAL( applicationRegistered( const TQCString &)),
+ this, TQT_SLOT( slotAppRegistered( const TQCString &)));
+ dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateKDE()",
+ objId(), "terminateKDE()", false );
+
+ TQString prefix = locateLocal("socket", "tdelauncher");
+ KTempFile domainname(prefix, TQString::fromLatin1(".slave-socket"));
+ if (domainname.status() != 0)
+ {
+ // Sever error!
+ tqDebug("TDELauncher: Fatal error, can't create tempfile!");
+ ::exit(1);
+ }
+ mPoolSocketName = domainname.name();
+#ifdef __CYGWIN__
+ domainname.close();
+ domainname.unlink();
+#endif
+ mPoolSocket = new TDEServerSocket(static_cast<const char*>(TQFile::encodeName(mPoolSocketName)));
+ connect(mPoolSocket, TQT_SIGNAL(accepted( TDESocket *)),
+ TQT_SLOT(acceptSlave(TDESocket *)));
+
+ connect(&mTimer, TQT_SIGNAL(timeout()), TQT_SLOT(idleTimeout()));
+
+ tdeinitNotifier = new TQSocketNotifier(tdeinitSocket, TQSocketNotifier::Read);
+ connect(tdeinitNotifier, TQT_SIGNAL( activated( int )),
+ this, TQT_SLOT( slotKDEInitData( int )));
+ tdeinitNotifier->setEnabled( true );
+ lastRequest = 0;
+ bProcessingQueue = false;
+
+ mSlaveDebug = getenv("TDE_SLAVE_DEBUG_WAIT");
+ if (!mSlaveDebug.isEmpty())
+ {
+ tqWarning("Klauncher running in slave-debug mode for slaves of protocol '%s'", mSlaveDebug.data());
+ }
+ mSlaveValgrind = getenv("TDE_SLAVE_VALGRIND");
+ if (!mSlaveValgrind.isEmpty())
+ {
+ mSlaveValgrindSkin = getenv("TDE_SLAVE_VALGRIND_SKIN");
+ tqWarning("Klauncher running slaves through valgrind for slaves of protocol '%s'", mSlaveValgrind.data());
+ }
+ tdelauncher_header request_header;
+ request_header.cmd = LAUNCHER_OK;
+ request_header.arg_length = 0;
+ write(tdeinitSocket, &request_header, sizeof(request_header));
+}
+
+TDELauncher::~TDELauncher()
+{
+ close();
+}
+
+void TDELauncher::close()
+{
+ if (!mPoolSocketName.isEmpty())
+ {
+ TQCString filename = TQFile::encodeName(mPoolSocketName);
+ unlink(filename.data());
+ }
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+//#ifdef Q_WS_X11
+ if( mCached_dpy != NULL )
+ XCloseDisplay( mCached_dpy );
+#endif
+}
+
+void
+TDELauncher::destruct(int exit_code)
+{
+ if (kapp) ((TDELauncher*)kapp)->close();
+ // We don't delete kapp here, that's intentional.
+ ::exit(exit_code);
+}
+
+bool
+TDELauncher::process(const TQCString &fun, const TQByteArray &data,
+ TQCString &replyType, TQByteArray &replyData)
+{
+ if ((fun == "exec_blind(TQCString,TQValueList<TQCString>)")
+ || (fun == "exec_blind(TQCString,TQValueList<TQCString>,TQValueList<TQCString>,TQCString)"))
+ {
+ TQDataStream stream(data, IO_ReadOnly);
+ replyType = "void";
+ TQCString name;
+ TQValueList<TQCString> arg_list;
+ TQCString startup_id = "0";
+ TQValueList<TQCString> envs;
+ stream >> name >> arg_list;
+ if( fun == "exec_blind(TQCString,TQValueList<TQCString>,TQValueList<TQCString>,TQCString)" )
+ stream >> envs >> startup_id;
+ kdDebug(7016) << "TDELauncher: Got exec_blind('" << name << "', ...)" << endl;
+ exec_blind( name, arg_list, envs, startup_id);
+ return true;
+ }
+ if ((fun == "start_service_by_name(TQString,TQStringList)") ||
+ (fun == "start_service_by_desktop_path(TQString,TQStringList)")||
+ (fun == "start_service_by_desktop_name(TQString,TQStringList)")||
+ (fun == "tdeinit_exec(TQString,TQStringList)") ||
+ (fun == "tdeinit_exec_wait(TQString,TQStringList)") ||
+ (fun == "start_service_by_name(TQString,TQStringList,TQValueList<TQCString>,TQCString)") ||
+ (fun == "start_service_by_desktop_path(TQString,TQStringList,TQValueList<TQCString>,TQCString)")||
+ (fun == "start_service_by_desktop_name(TQString,TQStringList,TQValueList<TQCString>,TQCString)") ||
+ (fun == "start_service_by_name(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)") ||
+ (fun == "start_service_by_desktop_path(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)")||
+ (fun == "start_service_by_desktop_name(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)") ||
+ (fun == "tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>)") ||
+ (fun == "tdeinit_exec_wait(TQString,TQStringList,TQValueList<TQCString>)") ||
+ (fun == "tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>,TQCString)") ||
+ (fun == "tdeinit_exec_wait(TQString,TQStringList,TQValueList<TQCString>,TQCString)"))
+ {
+ TQDataStream stream(data, IO_ReadOnly);
+ bool bNoWait = false;
+ TQString serviceName;
+ TQStringList urls;
+ TQValueList<TQCString> envs;
+ TQCString startup_id = "";
+ DCOPresult.result = -1;
+ DCOPresult.dcopName = 0;
+ DCOPresult.error = TQString::null;
+ DCOPresult.pid = 0;
+ stream >> serviceName >> urls;
+ if ((fun == "start_service_by_name(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)") ||
+ (fun == "start_service_by_desktop_path(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)")||
+ (fun == "start_service_by_desktop_name(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)"))
+ stream >> envs >> startup_id >> bNoWait;
+ else if ((fun == "start_service_by_name(TQString,TQStringList,TQValueList<TQCString>,TQCString)") ||
+ (fun == "start_service_by_desktop_path(TQString,TQStringList,TQValueList<TQCString>,TQCString)")||
+ (fun == "start_service_by_desktop_name(TQString,TQStringList,TQValueList<TQCString>,TQCString)"))
+ stream >> envs >> startup_id;
+ else if ((fun == "tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>)") ||
+ (fun == "tdeinit_exec_wait(TQString,TQStringList,TQValueList<TQCString>)"))
+ stream >> envs;
+ else if ((fun == "tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>,TQCString)") ||
+ (fun == "tdeinit_exec_wait(TQString,TQStringList,TQValueList<TQCString>,TQCString)"))
+ stream >> envs >> startup_id;
+ bool finished;
+ if (strncmp(fun, "start_service_by_name(", 22) == 0)
+ {
+ kdDebug(7016) << "TDELauncher: Got start_service_by_name('" << serviceName << "', ...)" << endl;
+ finished = start_service_by_name(serviceName, urls, envs, startup_id, bNoWait);
+ }
+ else if (strncmp(fun, "start_service_by_desktop_path(", 30) == 0)
+ {
+ kdDebug(7016) << "TDELauncher: Got start_service_by_desktop_path('" << serviceName << "', ...)" << endl;
+ finished = start_service_by_desktop_path(serviceName, urls, envs, startup_id, bNoWait);
+ }
+ else if (strncmp(fun, "start_service_by_desktop_name(", 30) == 0)
+ {
+ kdDebug(7016) << "TDELauncher: Got start_service_by_desktop_name('" << serviceName << "', ...)" << endl;
+ finished = start_service_by_desktop_name(serviceName, urls, envs, startup_id, bNoWait );
+ }
+ else if ((fun == "tdeinit_exec(TQString,TQStringList)")
+ || (fun == "tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>)")
+ || (fun == "tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>,TQCString)"))
+ {
+ kdDebug(7016) << "TDELauncher: Got tdeinit_exec('" << serviceName << "', ...)" << endl;
+ finished = tdeinit_exec(serviceName, urls, envs, startup_id, false);
+ }
+ else
+ {
+ kdDebug(7016) << "TDELauncher: Got tdeinit_exec_wait('" << serviceName << "', ...)" << endl;
+ finished = tdeinit_exec(serviceName, urls, envs, startup_id, true);
+ }
+ if (!finished)
+ {
+ replyType = "serviceResult";
+ TQDataStream stream2(replyData, IO_WriteOnly);
+ stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid;
+ }
+ return true;
+ }
+ else if (fun == "requestSlave(TQString,TQString,TQString)")
+ {
+ TQDataStream stream(data, IO_ReadOnly);
+ TQString protocol;
+ TQString host;
+ TQString app_socket;
+ stream >> protocol >> host >> app_socket;
+ replyType = "TQString";
+ TQString error;
+ pid_t pid = requestSlave(protocol, host, app_socket, error);
+ TQDataStream stream2(replyData, IO_WriteOnly);
+ stream2 << pid << error;
+ return true;
+ }
+ else if (fun == "requestHoldSlave(KURL,TQString)")
+ {
+ TQDataStream stream(data, IO_ReadOnly);
+ KURL url;
+ TQString app_socket;
+ stream >> url >> app_socket;
+ replyType = "pid_t";
+ pid_t pid = requestHoldSlave(url, app_socket);
+ TQDataStream stream2(replyData, IO_WriteOnly);
+ stream2 << pid;
+ return true;
+ }
+ else if (fun == "waitForSlave(pid_t)")
+ {
+ TQDataStream stream(data, IO_ReadOnly);
+ pid_t pid;
+ stream >> pid;
+ waitForSlave(pid);
+ replyType = "void";
+ return true;
+
+ }
+ else if (fun == "setLaunchEnv(TQCString,TQCString)")
+ {
+ TQDataStream stream(data, IO_ReadOnly);
+ TQCString name;
+ TQCString value;
+ stream >> name >> value;
+ setLaunchEnv(name, value);
+ replyType = "void";
+ return true;
+ }
+ else if (fun == "reparseConfiguration()")
+ {
+ TDEGlobal::config()->reparseConfiguration();
+ kdDebug(7016) << "TDELauncher::process : reparseConfiguration" << endl;
+ KProtocolManager::reparseConfiguration();
+ IdleSlave *slave;
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ slave->reparseConfiguration();
+ replyType = "void";
+ return true;
+ }
+ else if (fun == "terminateKDE()")
+ {
+ ::signal( SIGHUP, SIG_IGN);
+ ::signal( SIGTERM, SIG_IGN);
+ kdDebug() << "TDELauncher::process ---> terminateKDE" << endl;
+ tdelauncher_header request_header;
+ request_header.cmd = LAUNCHER_TERMINATE_KDE;
+ request_header.arg_length = 0;
+ write(tdeinitSocket, &request_header, sizeof(request_header));
+ destruct(0);
+ }
+ else if (fun == "autoStart()")
+ {
+ kdDebug() << "TDELauncher::process ---> autoStart" << endl;
+ autoStart(1);
+ replyType = "void";
+ return true;
+ }
+ else if (fun == "autoStart(int)")
+ {
+ kdDebug() << "TDELauncher::process ---> autoStart(int)" << endl;
+ TQDataStream stream(data, IO_ReadOnly);
+ int phase;
+ stream >> phase;
+ autoStart(phase);
+ replyType = "void";
+ return true;
+ }
+
+ if (DCOPObject::process(fun, data, replyType, replyData))
+ {
+ return true;
+ }
+ kdWarning(7016) << "Got unknown DCOP function: " << fun << endl;
+ return false;
+}
+
+QCStringList
+TDELauncher::interfaces()
+{
+ QCStringList ifaces = DCOPObject::interfaces();
+ ifaces += "TDELauncher";
+ return ifaces;
+}
+
+QCStringList
+TDELauncher::functions()
+{
+ QCStringList funcs = DCOPObject::functions();
+ funcs << "void exec_blind(TQCString,TQValueList<TQCString>)";
+ funcs << "void exec_blind(TQCString,TQValueList<TQCString>,TQValueList<TQCString>,TQCString)";
+ funcs << "serviceResult start_service_by_name(TQString,TQStringList)";
+ funcs << "serviceResult start_service_by_desktop_path(TQString,TQStringList)";
+ funcs << "serviceResult start_service_by_desktop_name(TQString,TQStringList)";
+ funcs << "serviceResult tdeinit_exec(TQString,TQStringList)";
+ funcs << "serviceResult tdeinit_exec_wait(TQString,TQStringList)";
+ funcs << "serviceResult start_service_by_name(TQString,TQStringList,TQValueList<TQCString>,TQCString)";
+ funcs << "serviceResult start_service_by_desktop_path(TQString,TQStringList,TQValueList<TQCString>,TQCString)";
+ funcs << "serviceResult start_service_by_desktop_name(TQString,TQStringList,TQValueList<TQCString>,TQCString)";
+ funcs << "serviceResult start_service_by_name(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)";
+ funcs << "serviceResult start_service_by_desktop_path(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)";
+ funcs << "serviceResult start_service_by_desktop_name(TQString,TQStringList,TQValueList<TQCString>,TQCString,bool)";
+ funcs << "serviceResult tdeinit_exec(TQString,TQStringList,TQValueList<TQCString>)";
+ funcs << "serviceResult tdeinit_exec_wait(TQString,TQStringList,TQValueList<TQCString>)";
+ funcs << "TQString requestSlave(TQString,TQString,TQString)";
+ funcs << "pid_t requestHoldSlave(KURL,TQString)";
+ funcs << "void waitForSlave(pid_t)";
+ funcs << "void setLaunchEnv(TQCString,TQCString)";
+ funcs << "void reparseConfiguration()";
+// funcs << "void terminateKDE()";
+ funcs << "void autoStart()";
+ funcs << "void autoStart(int)";
+ return funcs;
+}
+
+void TDELauncher::setLaunchEnv(const TQCString &name, const TQCString &_value)
+{
+ TQCString value(_value);
+ if (value.isNull())
+ value = "";
+ tdelauncher_header request_header;
+ TQByteArray requestData(name.length()+value.length()+2);
+ memcpy(requestData.data(), name.data(), name.length()+1);
+ memcpy(requestData.data()+name.length()+1, value.data(), value.length()+1);
+ request_header.cmd = LAUNCHER_SETENV;
+ request_header.arg_length = requestData.size();
+ write(tdeinitSocket, &request_header, sizeof(request_header));
+ write(tdeinitSocket, requestData.data(), request_header.arg_length);
+}
+
+/*
+ * Read 'len' bytes from 'sock' into buffer.
+ * returns -1 on failure, 0 on no data.
+ */
+static int
+read_socket(int sock, char *buffer, int len)
+{
+ ssize_t result;
+ int bytes_left = len;
+ while ( bytes_left > 0)
+ {
+ result = read(sock, buffer, bytes_left);
+ if (result > 0)
+ {
+ buffer += result;
+ bytes_left -= result;
+ }
+ else if (result == 0)
+ return -1;
+ else if ((result == -1) && (errno != EINTR))
+ return -1;
+ }
+ return 0;
+}
+
+
+void
+TDELauncher::slotKDEInitData(int)
+{
+ tdelauncher_header request_header;
+ TQByteArray requestData;
+ if( dontBlockReading )
+ {
+ // in case we get a request to start an application and data arrive
+ // to tdeinitSocket at the same time, requestStart() will already
+ // call slotKDEInitData(), so we must check there's still something
+ // to read, otherwise this would block
+ fd_set in;
+ timeval tm = { 0, 0 };
+ FD_ZERO ( &in );
+ FD_SET( tdeinitSocket, &in );
+ select( tdeinitSocket + 1, &in, 0, 0, &tm );
+ if( !FD_ISSET( tdeinitSocket, &in ))
+ return;
+ }
+ dontBlockReading = false;
+ int result = read_socket(tdeinitSocket, (char *) &request_header,
+ sizeof( request_header));
+ if (result == -1)
+ {
+ kdDebug() << "Exiting on read_socket errno: " << errno << endl;
+ ::signal( SIGHUP, SIG_IGN);
+ ::signal( SIGTERM, SIG_IGN);
+ destruct(255); // Exit!
+ }
+ requestData.resize(request_header.arg_length);
+ result = read_socket(tdeinitSocket, (char *) requestData.data(),
+ request_header.arg_length);
+
+ if (request_header.cmd == LAUNCHER_DIED)
+ {
+ long *request_data;
+ request_data = (long *) requestData.data();
+ processDied(request_data[0], request_data[1]);
+ return;
+ }
+ if (lastRequest && (request_header.cmd == LAUNCHER_OK))
+ {
+ long *request_data;
+ request_data = (long *) requestData.data();
+ lastRequest->pid = (pid_t) (*request_data);
+ kdDebug(7016) << lastRequest->name << " (pid " << lastRequest->pid <<
+ ") up and running." << endl;
+ switch(lastRequest->dcop_service_type)
+ {
+ case KService::DCOP_None:
+ {
+ lastRequest->status = TDELaunchRequest::Running;
+ break;
+ }
+
+ case KService::DCOP_Unique:
+ {
+ lastRequest->status = TDELaunchRequest::Launching;
+ break;
+ }
+
+ case KService::DCOP_Wait:
+ {
+ lastRequest->status = TDELaunchRequest::Launching;
+ break;
+ }
+
+ case KService::DCOP_Multi:
+ {
+ lastRequest->status = TDELaunchRequest::Launching;
+ break;
+ }
+ }
+ lastRequest = 0;
+ return;
+ }
+ if (lastRequest && (request_header.cmd == LAUNCHER_ERROR))
+ {
+ lastRequest->status = TDELaunchRequest::Error;
+ if (!requestData.isEmpty())
+ lastRequest->errorMsg = TQString::fromUtf8((char *) requestData.data());
+ lastRequest = 0;
+ return;
+ }
+
+ kdWarning(7016) << "Unexpected command from KDEInit (" << (unsigned int) request_header.cmd
+ << ")" << endl;
+}
+
+void
+TDELauncher::processDied(pid_t pid, long /* exitStatus */)
+{
+ TDELaunchRequest *request = requestList.first();
+ for(; request; request = requestList.next())
+ {
+ if (request->pid == pid)
+ {
+ if (request->dcop_service_type == KService::DCOP_Wait)
+ request->status = TDELaunchRequest::Done;
+ else if ((request->dcop_service_type == KService::DCOP_Unique) &&
+ (dcopClient()->isApplicationRegistered(request->dcop_name)))
+ request->status = TDELaunchRequest::Running;
+ else
+ request->status = TDELaunchRequest::Error;
+ requestDone(request);
+ return;
+ }
+ }
+}
+
+void
+TDELauncher::slotAppRegistered(const TQCString &appId)
+{
+ const char *cAppId = appId.data();
+ if (!cAppId) return;
+
+ TDELaunchRequest *request = requestList.first();
+ TDELaunchRequest *nextRequest;
+ for(; request; request = nextRequest)
+ {
+ nextRequest = requestList.next();
+ if (request->status != TDELaunchRequest::Launching)
+ continue;
+
+ // For unique services check the requested service name first
+ if ((request->dcop_service_type == KService::DCOP_Unique) &&
+ ((appId == request->dcop_name) ||
+ dcopClient()->isApplicationRegistered(request->dcop_name)))
+ {
+ request->status = TDELaunchRequest::Running;
+ requestDone(request);
+ continue;
+ }
+
+ const char *rAppId = request->dcop_name.data();
+ if (!rAppId) continue;
+
+ int l = strlen(rAppId);
+ if ((strncmp(rAppId, cAppId, l) == 0) &&
+ ((cAppId[l] == '\0') || (cAppId[l] == '-')))
+ {
+ request->dcop_name = appId;
+ request->status = TDELaunchRequest::Running;
+ requestDone(request);
+ continue;
+ }
+ }
+}
+
+void
+TDELauncher::autoStart(int phase)
+{
+ if( mAutoStart.phase() >= phase )
+ return;
+ mAutoStart.setPhase(phase);
+ if( newStartup )
+ {
+ if (phase == 0)
+ mAutoStart.loadAutoStartList();
+ }
+ else
+ {
+ if (phase == 1)
+ mAutoStart.loadAutoStartList();
+ }
+ mAutoTimer.start(0, true);
+}
+
+void
+TDELauncher::slotAutoStart()
+{
+ KService::Ptr s;
+ do
+ {
+ TQString service = mAutoStart.startService();
+ if (service.isEmpty())
+ {
+ // Done
+ if( !mAutoStart.phaseDone())
+ {
+ mAutoStart.setPhaseDone();
+ // Emit signal
+ if( newStartup )
+ {
+ TQCString autoStartSignal;
+ autoStartSignal.sprintf( "autoStart%dDone()", mAutoStart.phase());
+ emitDCOPSignal(autoStartSignal, TQByteArray());
+ }
+ else
+ {
+ TQCString autoStartSignal( "autoStartDone()" );
+ int phase = mAutoStart.phase();
+ if ( phase > 1 )
+ autoStartSignal.sprintf( "autoStart%dDone()", phase );
+ emitDCOPSignal(autoStartSignal, TQByteArray());
+ }
+ }
+ return;
+ }
+ s = new KService(service);
+ }
+ while (!start_service(s, TQStringList(), TQValueList<TQCString>(), "0", false, true));
+ // Loop till we find a service that we can start.
+}
+
+void
+TDELauncher::requestDone(TDELaunchRequest *request)
+{
+ if ((request->status == TDELaunchRequest::Running) ||
+ (request->status == TDELaunchRequest::Done))
+ {
+ DCOPresult.result = 0;
+ DCOPresult.dcopName = request->dcop_name;
+ DCOPresult.error = TQString::null;
+ DCOPresult.pid = request->pid;
+ }
+ else
+ {
+ DCOPresult.result = 1;
+ DCOPresult.dcopName = "";
+ DCOPresult.error = i18n("KDEInit could not launch '%1'.").arg(TQString(request->name));
+ if (!request->errorMsg.isEmpty())
+ DCOPresult.error += ":\n" + request->errorMsg;
+ DCOPresult.pid = 0;
+
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+//#ifdef Q_WS_X11
+ if (!request->startup_dpy.isEmpty())
+ {
+ Display* dpy = NULL;
+ if( (mCached_dpy != NULL) &&
+ (request->startup_dpy == XDisplayString( mCached_dpy )))
+ dpy = mCached_dpy;
+ if( dpy == NULL )
+ dpy = XOpenDisplay( request->startup_dpy );
+ if( dpy )
+ {
+ TDEStartupInfoId id;
+ id.initId( request->startup_id );
+ TDEStartupInfo::sendFinishX( dpy, id );
+ if( mCached_dpy != dpy && mCached_dpy != NULL )
+ XCloseDisplay( mCached_dpy );
+ mCached_dpy = dpy;
+ }
+ }
+#endif
+ }
+
+ if (request->autoStart)
+ {
+ mAutoTimer.start(0, true);
+ }
+
+ if (request->transaction)
+ {
+ TQByteArray replyData;
+ TQCString replyType;
+ replyType = "serviceResult";
+ TQDataStream stream2(replyData, IO_WriteOnly);
+ stream2 << DCOPresult.result << DCOPresult.dcopName << DCOPresult.error << DCOPresult.pid;
+ dcopClient()->endTransaction( request->transaction,
+ replyType, replyData);
+ }
+ requestList.removeRef( request );
+}
+
+void
+TDELauncher::requestStart(TDELaunchRequest *request)
+{
+ requestList.append( request );
+ // Send request to tdeinit.
+ tdelauncher_header request_header;
+ TQByteArray requestData;
+ int length = 0;
+ length += sizeof(long); // Nr of. Args
+ length += request->name.length() + 1; // Cmd
+ for(TQValueList<TQCString>::Iterator it = request->arg_list.begin();
+ it != request->arg_list.end();
+ it++)
+ {
+ length += (*it).length() + 1; // Args...
+ }
+ length += sizeof(long); // Nr of. envs
+ for(TQValueList<TQCString>::ConstIterator it = request->envs.begin();
+ it != request->envs.end();
+ it++)
+ {
+ length += (*it).length() + 1; // Envs...
+ }
+ length += sizeof( long ); // avoid_loops
+#ifdef Q_WS_X11
+ bool startup_notify = !request->startup_id.isNull() && request->startup_id != "0";
+ if( startup_notify )
+ length += request->startup_id.length() + 1;
+#endif
+ if (!request->cwd.isEmpty())
+ length += request->cwd.length() + 1;
+
+ requestData.resize( length );
+
+ char *p = requestData.data();
+ long l = request->arg_list.count()+1;
+ memcpy(p, &l, sizeof(long));
+ p += sizeof(long);
+ strcpy(p, request->name.data());
+ p += strlen(p) + 1;
+ for(TQValueList<TQCString>::Iterator it = request->arg_list.begin();
+ it != request->arg_list.end();
+ it++)
+ {
+ strcpy(p, (*it).data());
+ p += strlen(p) + 1;
+ }
+ l = request->envs.count();
+ memcpy(p, &l, sizeof(long));
+ p += sizeof(long);
+ for(TQValueList<TQCString>::ConstIterator it = request->envs.begin();
+ it != request->envs.end();
+ it++)
+ {
+ strcpy(p, (*it).data());
+ p += strlen(p) + 1;
+ }
+ l = 0; // avoid_loops, always false here
+ memcpy(p, &l, sizeof(long));
+ p += sizeof(long);
+#ifdef Q_WS_X11
+ if( startup_notify )
+ {
+ strcpy(p, request->startup_id.data());
+ p += strlen( p ) + 1;
+ }
+#endif
+ if (!request->cwd.isEmpty())
+ {
+ strcpy(p, request->cwd.data());
+ p += strlen( p ) + 1;
+ }
+#ifdef Q_WS_X11
+ request_header.cmd = startup_notify ? LAUNCHER_EXT_EXEC : LAUNCHER_EXEC_NEW;
+#else
+ request_header.cmd = LAUNCHER_EXEC_NEW;
+#endif
+ request_header.arg_length = length;
+ write(tdeinitSocket, &request_header, sizeof(request_header));
+ write(tdeinitSocket, requestData.data(), request_header.arg_length);
+
+ // Wait for pid to return.
+ lastRequest = request;
+ dontBlockReading = false;
+ do {
+ slotKDEInitData( tdeinitSocket );
+ }
+ while (lastRequest != 0);
+ dontBlockReading = true;
+}
+
+void
+TDELauncher::exec_blind( const TQCString &name, const TQValueList<TQCString> &arg_list,
+ const TQValueList<TQCString> &envs, const TQCString& startup_id )
+{
+ TDELaunchRequest *request = new TDELaunchRequest;
+ request->autoStart = false;
+ request->name = name;
+ request->arg_list = arg_list;
+ request->dcop_name = 0;
+ request->dcop_service_type = KService::DCOP_None;
+ request->pid = 0;
+ request->status = TDELaunchRequest::Launching;
+ request->transaction = 0; // No confirmation is send
+ request->envs = envs;
+ // Find service, if any - strip path if needed
+ KService::Ptr service = KService::serviceByDesktopName( name.mid( name.findRev( '/' ) + 1 ));
+ if (service != NULL)
+ send_service_startup_info( request, service,
+ startup_id, TQValueList< TQCString >());
+ else // no .desktop file, no startup info
+ cancel_service_startup_info( request, startup_id, envs );
+
+ requestStart(request);
+ // We don't care about this request any longer....
+ requestDone(request);
+}
+
+
+bool
+TDELauncher::start_service_by_name(const TQString &serviceName, const TQStringList &urls,
+ const TQValueList<TQCString> &envs, const TQCString& startup_id, bool blind)
+{
+ KService::Ptr service = 0;
+ // Find service
+ service = KService::serviceByName(serviceName);
+ if (!service)
+ {
+ DCOPresult.result = ENOENT;
+ DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
+ cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
+ return false;
+ }
+ return start_service(service, urls, envs, startup_id, blind);
+}
+
+bool
+TDELauncher::start_service_by_desktop_path(const TQString &serviceName, const TQStringList &urls,
+ const TQValueList<TQCString> &envs, const TQCString& startup_id, bool blind)
+{
+ KService::Ptr service = 0;
+ // Find service
+ if (serviceName[0] == '/')
+ {
+ // Full path
+ service = new KService(serviceName);
+ }
+ else
+ {
+ service = KService::serviceByDesktopPath(serviceName);
+ }
+ if (!service)
+ {
+ DCOPresult.result = ENOENT;
+ DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
+ cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
+ return false;
+ }
+ return start_service(service, urls, envs, startup_id, blind);
+}
+
+bool
+TDELauncher::start_service_by_desktop_name(const TQString &serviceName, const TQStringList &urls,
+ const TQValueList<TQCString> &envs, const TQCString& startup_id, bool blind)
+{
+ KService::Ptr service = 0;
+ // Find service
+ service = KService::serviceByDesktopName(serviceName);
+ if (!service)
+ {
+ DCOPresult.result = ENOENT;
+ DCOPresult.error = i18n("Could not find service '%1'.").arg(serviceName);
+ cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
+ return false;
+ }
+ return start_service(service, urls, envs, startup_id, blind);
+}
+
+bool
+TDELauncher::start_service(KService::Ptr service, const TQStringList &_urls,
+ const TQValueList<TQCString> &envs, const TQCString& startup_id, bool blind, bool autoStart)
+{
+ TQStringList urls = _urls;
+ if (!service->isValid())
+ {
+ DCOPresult.result = ENOEXEC;
+ DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath());
+ cancel_service_startup_info( NULL, startup_id, envs ); // cancel it if any
+ return false;
+ }
+ TDELaunchRequest *request = new TDELaunchRequest;
+ request->autoStart = autoStart;
+
+ if ((urls.count() > 1) && !service->allowMultipleFiles())
+ {
+ // We need to launch the application N times. That sucks.
+ // We ignore the result for application 2 to N.
+ // For the first file we launch the application in the
+ // usual way. The reported result is based on this
+ // application.
+ TQStringList::ConstIterator it = urls.begin();
+ for(++it;
+ it != urls.end();
+ ++it)
+ {
+ TQStringList singleUrl;
+ singleUrl.append(*it);
+ TQCString startup_id2 = startup_id;
+ if( !startup_id2.isEmpty() && startup_id2 != "0" )
+ startup_id2 = "0"; // can't use the same startup_id several times
+ start_service( service, singleUrl, envs, startup_id2, true);
+ }
+ TQString firstURL = *(urls.begin());
+ urls.clear();
+ urls.append(firstURL);
+ }
+ createArgs(request, service, urls);
+
+ // We must have one argument at least!
+ if (!request->arg_list.count())
+ {
+ DCOPresult.result = ENOEXEC;
+ DCOPresult.error = i18n("Service '%1' is malformatted.").arg(service->desktopEntryPath());
+ delete request;
+ cancel_service_startup_info( NULL, startup_id, envs );
+ return false;
+ }
+
+ request->name = request->arg_list.first();
+ request->arg_list.remove(request->arg_list.begin());
+
+ request->dcop_service_type = service->DCOPServiceType();
+
+ if ((request->dcop_service_type == KService::DCOP_Unique) ||
+ (request->dcop_service_type == KService::DCOP_Multi))
+ {
+ TQVariant v = service->property("X-DCOP-ServiceName");
+ if (v.isValid())
+ request->dcop_name = v.toString().utf8();
+ if (request->dcop_name.isEmpty())
+ {
+ request->dcop_name = TQFile::encodeName(KRun::binaryName(service->exec(), true));
+ }
+ }
+
+ request->pid = 0;
+ request->transaction = 0;
+ request->envs = envs;
+ send_service_startup_info( request, service, startup_id, envs );
+
+ // Request will be handled later.
+ if (!blind && !autoStart)
+ {
+ request->transaction = dcopClient()->beginTransaction();
+ }
+ queueRequest(request);
+ return true;
+}
+
+void
+TDELauncher::send_service_startup_info( TDELaunchRequest *request, KService::Ptr service, const TQCString& startup_id,
+ const TQValueList<TQCString> &envs )
+{
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+//#ifdef Q_WS_X11 // TDEStartup* isn't implemented for Qt/Embedded yet
+ request->startup_id = "0";
+ if( startup_id == "0" )
+ return;
+ bool silent;
+ TQCString wmclass;
+ if( !KRun::checkStartupNotify( TQString::null, service, &silent, &wmclass ))
+ return;
+ TDEStartupInfoId id;
+ id.initId( startup_id );
+ const char* dpy_str = NULL;
+ for( TQValueList<TQCString>::ConstIterator it = envs.begin();
+ it != envs.end();
+ ++it )
+ if( strncmp( *it, "DISPLAY=", 8 ) == 0 )
+ dpy_str = static_cast< const char* >( *it ) + 8;
+ Display* dpy = NULL;
+ if( dpy_str != NULL && mCached_dpy != NULL
+ && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 )
+ dpy = mCached_dpy;
+ if( dpy == NULL )
+ dpy = XOpenDisplay( dpy_str );
+ request->startup_id = id.id();
+ if( dpy == NULL )
+ {
+ cancel_service_startup_info( request, startup_id, envs );
+ return;
+ }
+
+ request->startup_dpy = dpy_str;
+
+ TDEStartupInfoData data;
+ data.setName( service->name());
+ data.setIcon( service->icon());
+ data.setDescription( i18n( "Launching %1" ).arg( service->name()));
+ if( !wmclass.isEmpty())
+ data.setWMClass( wmclass );
+ if( silent )
+ data.setSilent( TDEStartupInfoData::Yes );
+ // the rest will be sent by tdeinit
+ TDEStartupInfo::sendStartupX( dpy, id, data );
+ if( mCached_dpy != dpy && mCached_dpy != NULL )
+ XCloseDisplay( mCached_dpy );
+ mCached_dpy = dpy;
+ return;
+#else
+ return;
+#endif
+}
+
+void
+TDELauncher::cancel_service_startup_info( TDELaunchRequest* request, const TQCString& startup_id,
+ const TQValueList<TQCString> &envs )
+{
+#if defined Q_WS_X11 && ! defined K_WS_QTONLY
+//#ifdef Q_WS_X11 // TDEStartup* isn't implemented for Qt/Embedded yet
+ if( request != NULL )
+ request->startup_id = "0";
+ if( !startup_id.isEmpty() && startup_id != "0" )
+ {
+ const char* dpy_str = NULL;
+ for( TQValueList<TQCString>::ConstIterator it = envs.begin();
+ it != envs.end();
+ ++it )
+ if( strncmp( *it, "DISPLAY=", 8 ) == 0 )
+ dpy_str = static_cast< const char* >( *it ) + 8;
+ Display* dpy = NULL;
+ if( dpy_str != NULL && mCached_dpy != NULL
+ && qstrcmp( dpy_str, XDisplayString( mCached_dpy )) == 0 )
+ dpy = mCached_dpy;
+ if( dpy == NULL )
+ dpy = XOpenDisplay( dpy_str );
+ if( dpy == NULL )
+ return;
+ TDEStartupInfoId id;
+ id.initId( startup_id );
+ TDEStartupInfo::sendFinishX( dpy, id );
+ if( mCached_dpy != dpy && mCached_dpy != NULL )
+ XCloseDisplay( mCached_dpy );
+ mCached_dpy = dpy;
+ }
+#endif
+}
+
+bool
+TDELauncher::tdeinit_exec(const TQString &app, const TQStringList &args,
+ const TQValueList<TQCString> &envs, TQCString startup_id, bool wait)
+{
+ TDELaunchRequest *request = new TDELaunchRequest;
+ request->autoStart = false;
+
+ for(TQStringList::ConstIterator it = args.begin();
+ it != args.end();
+ it++)
+ {
+ TQString arg = *it;
+ request->arg_list.append(arg.local8Bit());
+ }
+
+ request->name = app.local8Bit();
+
+ if (wait)
+ request->dcop_service_type = KService::DCOP_Wait;
+ else
+ request->dcop_service_type = KService::DCOP_None;
+ request->dcop_name = 0;
+ request->pid = 0;
+#ifdef Q_WS_X11
+ request->startup_id = startup_id;
+#endif
+ request->envs = envs;
+ if( app != "tdebuildsycoca" ) // avoid stupid loop
+ {
+ // Find service, if any - strip path if needed
+ KService::Ptr service = KService::serviceByDesktopName( app.mid( app.findRev( '/' ) + 1 ));
+ if (service != NULL)
+ send_service_startup_info( request, service,
+ startup_id, TQValueList< TQCString >());
+ else // no .desktop file, no startup info
+ cancel_service_startup_info( request, startup_id, envs );
+ }
+ request->transaction = dcopClient()->beginTransaction();
+ queueRequest(request);
+ return true;
+}
+
+void
+TDELauncher::queueRequest(TDELaunchRequest *request)
+{
+ requestQueue.append( request );
+ if (!bProcessingQueue)
+ {
+ bProcessingQueue = true;
+ TQTimer::singleShot(0, this, TQT_SLOT( slotDequeue() ));
+ }
+}
+
+void
+TDELauncher::slotDequeue()
+{
+ do {
+ TDELaunchRequest *request = requestQueue.take(0);
+ // process request
+ request->status = TDELaunchRequest::Launching;
+ requestStart(request);
+ if (request->status != TDELaunchRequest::Launching)
+ {
+ // Request handled.
+ requestDone( request );
+ continue;
+ }
+ } while(requestQueue.count());
+ bProcessingQueue = false;
+}
+
+void
+TDELauncher::createArgs( TDELaunchRequest *request, const KService::Ptr service ,
+ const TQStringList &urls)
+{
+ TQStringList params = KRun::processDesktopExec(*service, urls, false);
+
+ for(TQStringList::ConstIterator it = params.begin();
+ it != params.end(); ++it)
+ {
+ request->arg_list.append((*it).local8Bit());
+ }
+ request->cwd = TQFile::encodeName(service->path());
+}
+
+///// IO-Slave functions
+
+pid_t
+TDELauncher::requestHoldSlave(const KURL &url, const TQString &app_socket)
+{
+ IdleSlave *slave;
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ {
+ if (slave->onHold(url))
+ break;
+ }
+ if (slave)
+ {
+ mSlaveList.removeRef(slave);
+ slave->connect(app_socket);
+ return slave->pid();
+ }
+ return 0;
+}
+
+
+pid_t
+TDELauncher::requestSlave(const TQString &protocol,
+ const TQString &host,
+ const TQString &app_socket,
+ TQString &error)
+{
+ IdleSlave *slave;
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ {
+ if (slave->match(protocol, host, true))
+ break;
+ }
+ if (!slave)
+ {
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ {
+ if (slave->match(protocol, host, false))
+ break;
+ }
+ }
+ if (!slave)
+ {
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ {
+ if (slave->match(protocol, TQString::null, false))
+ break;
+ }
+ }
+ if (slave)
+ {
+ mSlaveList.removeRef(slave);
+ slave->connect(app_socket);
+ return slave->pid();
+ }
+
+ TQString _name = KProtocolInfo::exec(protocol);
+ if (_name.isEmpty())
+ {
+ error = i18n("Unknown protocol '%1'.\n").arg(protocol);
+ return 0;
+ }
+
+ TQCString name = _name.latin1(); // ex: "tdeio_ftp"
+ TQCString arg1 = protocol.latin1();
+ TQCString arg2 = TQFile::encodeName(mPoolSocketName);
+ TQCString arg3 = TQFile::encodeName(app_socket);
+ TQValueList<TQCString> arg_list;
+ arg_list.append(arg1);
+ arg_list.append(arg2);
+ arg_list.append(arg3);
+
+// kdDebug(7016) << "TDELauncher: launching new slave " << _name << " with protocol=" << protocol << endl;
+ if (mSlaveDebug == arg1)
+ {
+ tdelauncher_header request_header;
+ request_header.cmd = LAUNCHER_DEBUG_WAIT;
+ request_header.arg_length = 0;
+ write(tdeinitSocket, &request_header, sizeof(request_header));
+ }
+ if (mSlaveValgrind == arg1)
+ {
+ arg_list.prepend(TQFile::encodeName(KLibLoader::findLibrary(name)));
+ arg_list.prepend(TQFile::encodeName(locate("exe", "tdeioslave")));
+ name = "valgrind";
+ if (!mSlaveValgrindSkin.isEmpty()) {
+ arg_list.prepend(TQCString("--tool=") + mSlaveValgrindSkin);
+ } else
+ arg_list.prepend("--tool=memcheck");
+ }
+
+ TDELaunchRequest *request = new TDELaunchRequest;
+ request->autoStart = false;
+ request->name = name;
+ request->arg_list = arg_list;
+ request->dcop_name = 0;
+ request->dcop_service_type = KService::DCOP_None;
+ request->pid = 0;
+#ifdef Q_WS_X11
+ request->startup_id = "0";
+#endif
+ request->status = TDELaunchRequest::Launching;
+ request->transaction = 0; // No confirmation is send
+ requestStart(request);
+ pid_t pid = request->pid;
+
+// kdDebug(7016) << "Slave launched, pid = " << pid << endl;
+
+ // We don't care about this request any longer....
+ requestDone(request);
+ if (!pid)
+ {
+ error = i18n("Error loading '%1'.\n").arg(TQString(name));
+ }
+ return pid;
+}
+
+void
+TDELauncher::waitForSlave(pid_t pid)
+{
+ IdleSlave *slave;
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ {
+ if (slave->pid() == pid)
+ return; // Already here.
+ }
+ SlaveWaitRequest *waitRequest = new SlaveWaitRequest;
+ waitRequest->transaction = dcopClient()->beginTransaction();
+ waitRequest->pid = pid;
+ mSlaveWaitRequest.append(waitRequest);
+}
+
+void
+TDELauncher::acceptSlave(TDESocket *slaveSocket)
+{
+ IdleSlave *slave = new IdleSlave(slaveSocket);
+ // Send it a SLAVE_STATUS command.
+ mSlaveList.append(slave);
+ connect(slave, TQT_SIGNAL(destroyed()), this, TQT_SLOT(slotSlaveGone()));
+ connect(slave, TQT_SIGNAL(statusUpdate(IdleSlave *)),
+ this, TQT_SLOT(slotSlaveStatus(IdleSlave *)));
+ if (!mTimer.isActive())
+ {
+ mTimer.start(1000*10);
+ }
+}
+
+void
+TDELauncher::slotSlaveStatus(IdleSlave *slave)
+{
+ SlaveWaitRequest *waitRequest = mSlaveWaitRequest.first();
+ while(waitRequest)
+ {
+ if (waitRequest->pid == slave->pid())
+ {
+ TQByteArray replyData;
+ TQCString replyType;
+ replyType = "void";
+ dcopClient()->endTransaction( waitRequest->transaction, replyType, replyData);
+ mSlaveWaitRequest.removeRef(waitRequest);
+ waitRequest = mSlaveWaitRequest.current();
+ }
+ else
+ {
+ waitRequest = mSlaveWaitRequest.next();
+ }
+ }
+}
+
+void
+TDELauncher::slotSlaveGone()
+{
+ IdleSlave *slave = (IdleSlave *) sender();
+ mSlaveList.removeRef(slave);
+ if ((mSlaveList.count() == 0) && (mTimer.isActive()))
+ {
+ mTimer.stop();
+ }
+}
+
+void
+TDELauncher::idleTimeout()
+{
+ bool keepOneFileSlave=true;
+ time_t now = time(0);
+ IdleSlave *slave;
+ for(slave = mSlaveList.first(); slave; slave = mSlaveList.next())
+ {
+ if ((slave->protocol()=="file") && (keepOneFileSlave))
+ keepOneFileSlave=false;
+ else if (slave->age(now) > SLAVE_MAX_IDLE)
+ {
+ // killing idle slave
+ delete slave;
+ }
+ }
+}
+
+#include "tdelauncher.moc"