|
|
|
/*
|
|
|
|
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 <kconfig.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klibloader.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kprotocolmanager.h>
|
|
|
|
#include <kprotocolinfo.h>
|
|
|
|
#include <krun.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <ktempfile.h>
|
|
|
|
#include <kurl.h>
|
|
|
|
|
|
|
|
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
|
|
|
|
#include <kstartupinfo.h> // schroder
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#include "kio/global.h"
|
|
|
|
#include "kio/connection.h"
|
|
|
|
#include "kio/slaveinterface.h"
|
|
|
|
|
|
|
|
#include "klauncher.h"
|
|
|
|
#include "klauncher_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 KIO;
|
|
|
|
|
|
|
|
template class TQPtrList<KLaunchRequest>;
|
|
|
|
template class TQPtrList<IdleSlave>;
|
|
|
|
|
|
|
|
IdleSlave::IdleSlave(KSocket *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);
|
|
|
|
}
|
|
|
|
|
|
|
|
KLauncher::KLauncher(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("klauncher"),
|
|
|
|
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", "klauncher");
|
|
|
|
KTempFile domainname(prefix, TQString::fromLatin1(".slave-socket"));
|
|
|
|
if (domainname.status() != 0)
|
|
|
|
{
|
|
|
|
// Sever error!
|
|
|
|
tqDebug("KLauncher: Fatal error, can't create tempfile!");
|
|
|
|
::exit(1);
|
|
|
|
}
|
|
|
|
mPoolSocketName = domainname.name();
|
|
|
|
#ifdef __CYGWIN__
|
|
|
|
domainname.close();
|
|
|
|
domainname.unlink();
|
|
|
|
#endif
|
|
|
|
mPoolSocket = new KServerSocket(static_cast<const char*>(TQFile::encodeName(mPoolSocketName)));
|
|
|
|
connect(mPoolSocket, TQT_SIGNAL(accepted( KSocket *)),
|
|
|
|
TQT_SLOT(acceptSlave(KSocket *)));
|
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
klauncher_header request_header;
|
|
|
|
request_header.cmd = LAUNCHER_OK;
|
|
|
|
request_header.arg_length = 0;
|
|
|
|
write(tdeinitSocket, &request_header, sizeof(request_header));
|
|
|
|
}
|
|
|
|
|
|
|
|
KLauncher::~KLauncher()
|
|
|
|
{
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KLauncher::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
|
|
|
|
KLauncher::destruct(int exit_code)
|
|
|
|
{
|
|
|
|
if (kapp) ((KLauncher*)kapp)->close();
|
|
|
|
// We don't delete kapp here, that's intentional.
|
|
|
|
::exit(exit_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
KLauncher::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) << "KLauncher: 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) << "KLauncher: 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) << "KLauncher: 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) << "KLauncher: 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) << "KLauncher: Got tdeinit_exec('" << serviceName << "', ...)" << endl;
|
|
|
|
finished = tdeinit_exec(serviceName, urls, envs, startup_id, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdDebug(7016) << "KLauncher: 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) << "KLauncher::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() << "KLauncher::process ---> terminateKDE" << endl;
|
|
|
|
klauncher_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() << "KLauncher::process ---> autoStart" << endl;
|
|
|
|
autoStart(1);
|
|
|
|
replyType = "void";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (fun == "autoStart(int)")
|
|
|
|
{
|
|
|
|
kdDebug() << "KLauncher::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
|
|
|
|
KLauncher::interfaces()
|
|
|
|
{
|
|
|
|
QCStringList ifaces = DCOPObject::interfaces();
|
|
|
|
ifaces += "KLauncher";
|
|
|
|
return ifaces;
|
|
|
|
}
|
|
|
|
|
|
|
|
QCStringList
|
|
|
|
KLauncher::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 KLauncher::setLaunchEnv(const TQCString &name, const TQCString &_value)
|
|
|
|
{
|
|
|
|
TQCString value(_value);
|
|
|
|
if (value.isNull())
|
|
|
|
value = "";
|
|
|
|
klauncher_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
|
|
|
|
KLauncher::slotKDEInitData(int)
|
|
|
|
{
|
|
|
|
klauncher_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 = KLaunchRequest::Running;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case KService::DCOP_Unique:
|
|
|
|
{
|
|
|
|
lastRequest->status = KLaunchRequest::Launching;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case KService::DCOP_Wait:
|
|
|
|
{
|
|
|
|
lastRequest->status = KLaunchRequest::Launching;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case KService::DCOP_Multi:
|
|
|
|
{
|
|
|
|
lastRequest->status = KLaunchRequest::Launching;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lastRequest = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (lastRequest && (request_header.cmd == LAUNCHER_ERROR))
|
|
|
|
{
|
|
|
|
lastRequest->status = KLaunchRequest::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
|
|
|
|
KLauncher::processDied(pid_t pid, long /* exitStatus */)
|
|
|
|
{
|
|
|
|
KLaunchRequest *request = requestList.first();
|
|
|
|
for(; request; request = requestList.next())
|
|
|
|
{
|
|
|
|
if (request->pid == pid)
|
|
|
|
{
|
|
|
|
if (request->dcop_service_type == KService::DCOP_Wait)
|
|
|
|
request->status = KLaunchRequest::Done;
|
|
|
|
else if ((request->dcop_service_type == KService::DCOP_Unique) &&
|
|
|
|
(dcopClient()->isApplicationRegistered(request->dcop_name)))
|
|
|
|
request->status = KLaunchRequest::Running;
|
|
|
|
else
|
|
|
|
request->status = KLaunchRequest::Error;
|
|
|
|
requestDone(request);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KLauncher::slotAppRegistered(const TQCString &appId)
|
|
|
|
{
|
|
|
|
const char *cAppId = appId.data();
|
|
|
|
if (!cAppId) return;
|
|
|
|
|
|
|
|
KLaunchRequest *request = requestList.first();
|
|
|
|
KLaunchRequest *nextRequest;
|
|
|
|
for(; request; request = nextRequest)
|
|
|
|
{
|
|
|
|
nextRequest = requestList.next();
|
|
|
|
if (request->status != KLaunchRequest::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 = KLaunchRequest::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 = KLaunchRequest::Running;
|
|
|
|
requestDone(request);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::requestDone(KLaunchRequest *request)
|
|
|
|
{
|
|
|
|
if ((request->status == KLaunchRequest::Running) ||
|
|
|
|
(request->status == KLaunchRequest::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 )
|
|
|
|
{
|
|
|
|
KStartupInfoId id;
|
|
|
|
id.initId( request->startup_id );
|
|
|
|
KStartupInfo::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
|
|
|
|
KLauncher::requestStart(KLaunchRequest *request)
|
|
|
|
{
|
|
|
|
requestList.append( request );
|
|
|
|
// Send request to tdeinit.
|
|
|
|
klauncher_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
|
|
|
|
KLauncher::exec_blind( const TQCString &name, const TQValueList<TQCString> &arg_list,
|
|
|
|
const TQValueList<TQCString> &envs, const TQCString& startup_id )
|
|
|
|
{
|
|
|
|
KLaunchRequest *request = new KLaunchRequest;
|
|
|
|
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 = KLaunchRequest::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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::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;
|
|
|
|
}
|
|
|
|
KLaunchRequest *request = new KLaunchRequest;
|
|
|
|
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
|
|
|
|
KLauncher::send_service_startup_info( KLaunchRequest *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 // KStartup* 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;
|
|
|
|
KStartupInfoId 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;
|
|
|
|
|
|
|
|
KStartupInfoData 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( KStartupInfoData::Yes );
|
|
|
|
// the rest will be sent by tdeinit
|
|
|
|
KStartupInfo::sendStartupX( dpy, id, data );
|
|
|
|
if( mCached_dpy != dpy && mCached_dpy != NULL )
|
|
|
|
XCloseDisplay( mCached_dpy );
|
|
|
|
mCached_dpy = dpy;
|
|
|
|
return;
|
|
|
|
#else
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KLauncher::cancel_service_startup_info( KLaunchRequest* request, const TQCString& startup_id,
|
|
|
|
const TQValueList<TQCString> &envs )
|
|
|
|
{
|
|
|
|
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
|
|
|
|
//#ifdef Q_WS_X11 // KStartup* 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;
|
|
|
|
KStartupInfoId id;
|
|
|
|
id.initId( startup_id );
|
|
|
|
KStartupInfo::sendFinishX( dpy, id );
|
|
|
|
if( mCached_dpy != dpy && mCached_dpy != NULL )
|
|
|
|
XCloseDisplay( mCached_dpy );
|
|
|
|
mCached_dpy = dpy;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
KLauncher::tdeinit_exec(const TQString &app, const TQStringList &args,
|
|
|
|
const TQValueList<TQCString> &envs, TQCString startup_id, bool wait)
|
|
|
|
{
|
|
|
|
KLaunchRequest *request = new KLaunchRequest;
|
|
|
|
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 != "kbuildsycoca" ) // 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
|
|
|
|
KLauncher::queueRequest(KLaunchRequest *request)
|
|
|
|
{
|
|
|
|
requestQueue.append( request );
|
|
|
|
if (!bProcessingQueue)
|
|
|
|
{
|
|
|
|
bProcessingQueue = true;
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT( slotDequeue() ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KLauncher::slotDequeue()
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
KLaunchRequest *request = requestQueue.take(0);
|
|
|
|
// process request
|
|
|
|
request->status = KLaunchRequest::Launching;
|
|
|
|
requestStart(request);
|
|
|
|
if (request->status != KLaunchRequest::Launching)
|
|
|
|
{
|
|
|
|
// Request handled.
|
|
|
|
requestDone( request );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} while(requestQueue.count());
|
|
|
|
bProcessingQueue = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KLauncher::createArgs( KLaunchRequest *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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::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: "kio_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) << "KLauncher: launching new slave " << _name << " with protocol=" << protocol << endl;
|
|
|
|
if (mSlaveDebug == arg1)
|
|
|
|
{
|
|
|
|
klauncher_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", "kioslave")));
|
|
|
|
name = "valgrind";
|
|
|
|
if (!mSlaveValgrindSkin.isEmpty()) {
|
|
|
|
arg_list.prepend(TQCString("--tool=") + mSlaveValgrindSkin);
|
|
|
|
} else
|
|
|
|
arg_list.prepend("--tool=memcheck");
|
|
|
|
}
|
|
|
|
|
|
|
|
KLaunchRequest *request = new KLaunchRequest;
|
|
|
|
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 = KLaunchRequest::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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::acceptSlave(KSocket *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
|
|
|
|
KLauncher::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
|
|
|
|
KLauncher::slotSlaveGone()
|
|
|
|
{
|
|
|
|
IdleSlave *slave = (IdleSlave *) sender();
|
|
|
|
mSlaveList.removeRef(slave);
|
|
|
|
if ((mSlaveList.count() == 0) && (mTimer.isActive()))
|
|
|
|
{
|
|
|
|
mTimer.stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
KLauncher::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 "klauncher.moc"
|