2 This file is part of the KDE libraries
3 Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "klauncher.h"
21 #include "klauncher_cmds.h"
22 #include "klauncher_adaptor.h"
34 #include <kstartupinfo.h>
38 #include <QtCore/QFile>
43 #include <klibloader.h>
45 #include <kprotocolmanager.h>
46 #include <kprotocolinfo.h>
48 #include <kstandarddirs.h>
49 #include <ktemporaryfile.h>
52 #include <kio/global.h>
53 #include <kio/connection.h>
54 #include <kio/slaveinterface.h>
56 // Dispose slaves after being idle for SLAVE_MAX_IDLE seconds
57 #define SLAVE_MAX_IDLE 30
59 // #define KLAUNCHER_VERBOSE_OUTPUT
63 IdleSlave::IdleSlave(QObject
*parent
)
66 QObject::connect(&mConn
, SIGNAL(readyRead()), this, SLOT(gotInput()));
67 // Send it a SLAVE_STATUS command.
68 mConn
.send( CMD_SLAVE_STATUS
);
74 template<int T
> struct PIDType
{ typedef pid_t PID_t
; } ;
75 template<> struct PIDType
<2> { typedef qint16 PID_t
; } ;
76 template<> struct PIDType
<4> { typedef qint32 PID_t
; } ;
83 if (mConn
.read( &cmd
, data
) == -1)
85 // Communication problem with slave.
86 kError(7016) << "SlavePool: No communication with slave." << endl
;
89 else if (cmd
== MSG_SLAVE_ACK
)
93 else if (cmd
!= MSG_SLAVE_STATUS
)
95 kError(7016) << "SlavePool: Unexpected data from slave." << endl
;
100 QDataStream
stream( data
);
101 PIDType
<sizeof(pid_t
)>::PID_t stream_pid
;
106 stream
>> stream_pid
>> protocol
>> host
>> b
;
108 // Overload with (bool) onHold, (KUrl) url.
118 mConnected
= (b
!= 0);
119 mProtocol
= QString::fromLatin1(protocol
);
121 emit
statusUpdate(this);
126 IdleSlave::connect(const QString
&app_socket
)
129 QDataStream
stream( &data
, QIODevice::WriteOnly
);
130 stream
<< app_socket
;
131 mConn
.send( CMD_SLAVE_CONNECT
, data
);
136 IdleSlave::reparseConfiguration()
138 mConn
.send( CMD_REPARSECONFIGURATION
);
142 IdleSlave::match(const QString
&protocol
, const QString
&host
, bool needConnected
)
144 if (mOnHold
|| protocol
!= mProtocol
) {
147 if (host
.isEmpty()) {
150 return (host
== mHost
) && (!needConnected
|| mConnected
);
154 IdleSlave::onHold(const KUrl
&url
)
156 if (!mOnHold
) return false;
157 return (url
== mUrl
);
161 IdleSlave::age(time_t now
)
163 return (int) difftime(now
, mBirthDate
);
166 static KLauncher
* g_klauncher_self
;
168 KLauncher::KLauncher(int _kdeinitSocket
)
170 kdeinitSocket(_kdeinitSocket
), dontBlockReading(false)
175 Q_ASSERT( g_klauncher_self
== NULL
);
176 g_klauncher_self
= this;
178 mAutoTimer
.setSingleShot(true);
179 new KLauncherAdaptor(this);
180 QDBusConnection::sessionBus().registerObject("/KLauncher", this); // same as ktoolinvocation.cpp
182 connect(&mAutoTimer
, SIGNAL(timeout()), this, SLOT(slotAutoStart()));
183 connect(QDBusConnection::sessionBus().interface(),
184 SIGNAL(serviceOwnerChanged(QString
,QString
,QString
)),
185 SLOT(slotNameOwnerChanged(QString
,QString
,QString
)));
187 mConnectionServer
.listenForRemote();
188 connect(&mConnectionServer
, SIGNAL(newConnection()), SLOT(acceptSlave()));
189 if (!mConnectionServer
.isListening())
192 qDebug("KLauncher: Fatal error, can't create tempfile!");
196 connect(&mTimer
, SIGNAL(timeout()), SLOT(idleTimeout()));
199 kdeinitNotifier
= new QSocketNotifier(kdeinitSocket
, QSocketNotifier::Read
);
200 connect(kdeinitNotifier
, SIGNAL( activated( int )),
201 this, SLOT( slotKDEInitData( int )));
202 kdeinitNotifier
->setEnabled( true );
205 bProcessingQueue
= false;
207 mSlaveDebug
= QString::fromLocal8Bit(qgetenv("KDE_SLAVE_DEBUG_WAIT"));
208 if (!mSlaveDebug
.isEmpty())
210 qWarning("Klauncher running in slave-debug mode for slaves of protocol '%s'", qPrintable(mSlaveDebug
));
212 mSlaveValgrind
= QString::fromLocal8Bit(qgetenv("KDE_SLAVE_VALGRIND"));
213 if (!mSlaveValgrind
.isEmpty())
215 mSlaveValgrindSkin
= QString::fromLocal8Bit(qgetenv("KDE_SLAVE_VALGRIND_SKIN"));
216 qWarning("Klauncher running slaves through valgrind for slaves of protocol '%s'", qPrintable(mSlaveValgrind
));
219 kDebug(7016) << "LAUNCHER_OK";
221 klauncher_header request_header
;
222 request_header
.cmd
= LAUNCHER_OK
;
223 request_header
.arg_length
= 0;
224 write(kdeinitSocket
, &request_header
, sizeof(request_header
));
228 KLauncher::~KLauncher()
231 g_klauncher_self
= NULL
;
234 void KLauncher::close()
237 if( mCached_dpy
!= NULL
)
239 XCloseDisplay( mCached_dpy
);
246 KLauncher::destruct()
248 if (g_klauncher_self
)
249 g_klauncher_self
->close();
250 // We don't delete the app here, that's intentional.
254 void KLauncher::setLaunchEnv(const QString
&name
, const QString
&value
)
259 klauncher_header request_header
;
260 QByteArray requestData
;
261 requestData
.append(name
.toLocal8Bit()).append('\0').append(value
.toLocal8Bit()).append('\0');
262 request_header
.cmd
= LAUNCHER_SETENV
;
263 request_header
.arg_length
= requestData
.size();
264 write(kdeinitSocket
, &request_header
, sizeof(request_header
));
265 write(kdeinitSocket
, requestData
.data(), request_header
.arg_length
);
271 * Read 'len' bytes from 'sock' into buffer.
272 * returns -1 on failure, 0 on no data.
275 read_socket(int sock
, char *buffer
, int len
)
278 int bytes_left
= len
;
279 while ( bytes_left
> 0)
281 result
= read(sock
, buffer
, bytes_left
);
285 bytes_left
-= result
;
287 else if (result
== 0)
289 else if ((result
== -1) && (errno
!= EINTR
))
297 KLauncher::slotKDEInitData(int)
299 klauncher_header request_header
;
300 QByteArray requestData
;
301 if( dontBlockReading
)
303 // in case we get a request to start an application and data arrive
304 // to kdeinitSocket at the same time, requestStart() will already
305 // call slotKDEInitData(), so we must check there's still something
306 // to read, otherwise this would block
308 timeval tm
= { 0, 0 };
310 FD_SET( kdeinitSocket
, &in
);
311 select( kdeinitSocket
+ 1, &in
, 0, 0, &tm
);
312 if( !FD_ISSET( kdeinitSocket
, &in
))
315 dontBlockReading
= false;
316 int result
= read_socket(kdeinitSocket
, (char *) &request_header
,
317 sizeof( request_header
));
320 kDebug(7016) << "Exiting on read_socket errno:" << errno
;
321 KDE_signal( SIGHUP
, SIG_IGN
);
322 KDE_signal( SIGTERM
, SIG_IGN
);
325 requestData
.resize(request_header
.arg_length
);
326 result
= read_socket(kdeinitSocket
, (char *) requestData
.data(),
327 request_header
.arg_length
);
329 processRequestReturn(request_header
.cmd
,requestData
);
334 void KLauncher::processRequestReturn(int status
, const QByteArray
&requestData
)
336 if (status
== LAUNCHER_CHILD_DIED
)
339 request_data
= (long *) requestData
.data();
340 processDied(request_data
[0], request_data
[1]);
343 if (lastRequest
&& (status
== LAUNCHER_OK
))
346 request_data
= (long *) requestData
.data();
347 lastRequest
->pid
= (pid_t
) (*request_data
);
348 kDebug(7016).nospace() << lastRequest
->name
<< " (pid " << lastRequest
->pid
<<
350 switch(lastRequest
->dbus_startup_type
)
352 case KService::DBusNone
:
353 lastRequest
->status
= KLaunchRequest::Running
;
355 case KService::DBusUnique
:
356 case KService::DBusWait
:
357 case KService::DBusMulti
:
358 lastRequest
->status
= KLaunchRequest::Launching
;
364 if (lastRequest
&& (status
== LAUNCHER_ERROR
))
366 lastRequest
->status
= KLaunchRequest::Error
;
367 kDebug(7016) << lastRequest
->name
<< " failed." << endl
;
368 if (!requestData
.isEmpty())
369 lastRequest
->errorMsg
= QString::fromUtf8((char *) requestData
.data());
374 kWarning(7016)<< "Unexpected request return" << (unsigned int) status
;
378 KLauncher::processDied(pid_t pid
, long exitStatus
)
380 #ifdef KLAUNCHER_VERBOSE_OUTPUT
381 kDebug(7016) << pid
<< "exitStatus=" << exitStatus
;
383 Q_UNUSED(exitStatus
);
384 // We should probably check the exitStatus for the uniqueapp case?
386 foreach (KLaunchRequest
*request
, requestList
)
388 #ifdef KLAUNCHER_VERBOSE_OUTPUT
389 kDebug(7016) << " had pending request" << request
->pid
;
391 if (request
->pid
== pid
)
393 if (request
->dbus_startup_type
== KService::DBusWait
)
394 request
->status
= KLaunchRequest::Done
;
395 else if ((request
->dbus_startup_type
== KService::DBusUnique
)
396 && QDBusConnection::sessionBus().interface()->isServiceRegistered(request
->dbus_name
))
397 request
->status
= KLaunchRequest::Running
;
399 request
->status
= KLaunchRequest::Error
;
400 #ifdef KLAUNCHER_VERBOSE_OUTPUT
401 kDebug(7016) << pid
<< "died, requestDone. status=" << request
->status
;
403 requestDone(request
);
407 #ifdef KLAUNCHER_VERBOSE_OUTPUT
408 kDebug(7016) << "found no pending requests for PID" << pid
;
412 static bool matchesPendingRequest(const QString
& appId
, const QString
& pendingAppId
)
414 // appId just registered, e.g. org.koffice.kword-12345
415 // Let's see if this is what pendingAppId (e.g. org.koffice.kword or *.kword) was waiting for.
417 const QString newAppId
= appId
.left(appId
.lastIndexOf('-')); // strip out the -12345 if present.
419 //kDebug() << "appId=" << appId << "newAppId=" << newAppId << "pendingAppId=" << pendingAppId;
421 if (pendingAppId
.startsWith("*.")) {
422 const QString pendingName
= pendingAppId
.mid(2);
423 const QString appName
= newAppId
.mid(newAppId
.lastIndexOf('.')+1);
424 //kDebug() << "appName=" << appName;
425 return appName
== pendingName
;
428 return newAppId
== pendingAppId
;
432 KLauncher::slotNameOwnerChanged(const QString
&appId
, const QString
&oldOwner
,
433 const QString
&newOwner
)
436 if (appId
.isEmpty() || newOwner
.isEmpty())
439 #ifdef KLAUNCHER_VERBOSE_OUTPUT
440 kDebug(7016) << "new app" << appId
;
442 foreach (KLaunchRequest
*request
, requestList
)
444 if (request
->status
!= KLaunchRequest::Launching
)
447 // For unique services check the requested service name first
448 if ((request
->dbus_startup_type
== KService::DBusUnique
) &&
449 ((appId
== request
->dbus_name
) ||
450 QDBusConnection::sessionBus().interface()->isServiceRegistered(request
->dbus_name
)))
452 #ifdef KLAUNCHER_VERBOSE_OUTPUT
453 kDebug(7016) << "ok, request (for unique app) done";
455 request
->status
= KLaunchRequest::Running
;
456 requestDone(request
);
460 const QString rAppId
= request
->dbus_name
;
461 #ifdef KLAUNCHER_VERBOSE_OUTPUT
462 kDebug(7016) << "had pending request" << rAppId
;
464 if (rAppId
.isEmpty())
467 if (matchesPendingRequest(appId
, rAppId
)) {
468 #ifdef KLAUNCHER_VERBOSE_OUTPUT
469 kDebug(7016) << "ok, request done";
471 request
->dbus_name
= appId
;
472 request
->status
= KLaunchRequest::Running
;
473 requestDone(request
);
480 KLauncher::autoStart(int phase
)
482 if( mAutoStart
.phase() >= phase
)
484 mAutoStart
.setPhase(phase
);
486 mAutoStart
.loadAutoStartList();
491 KLauncher::slotAutoStart()
496 QString service
= mAutoStart
.startService();
497 if (service
.isEmpty())
500 if( !mAutoStart
.phaseDone())
502 mAutoStart
.setPhaseDone();
503 switch( mAutoStart
.phase())
506 emit
autoStart0Done();
509 emit
autoStart1Done();
512 emit
autoStart2Done();
518 s
= new KService(service
);
520 while (!start_service(s
, QStringList(), QStringList(), "0", false, true, QDBusMessage()));
521 // Loop till we find a service that we can start.
525 KLauncher::requestDone(KLaunchRequest
*request
)
527 if ((request
->status
== KLaunchRequest::Running
) ||
528 (request
->status
== KLaunchRequest::Done
))
530 requestResult
.result
= 0;
531 requestResult
.dbusName
= request
->dbus_name
;
532 requestResult
.error
= "";
533 requestResult
.pid
= request
->pid
;
537 requestResult
.result
= 1;
538 requestResult
.dbusName
= "";
539 requestResult
.error
= i18n("KDEInit could not launch '%1'.", request
->name
);
540 if (!request
->errorMsg
.isEmpty())
541 requestResult
.error
+= ":\n" + request
->errorMsg
;
542 requestResult
.pid
= 0;
545 if (!request
->startup_dpy
.isEmpty())
548 if( (mCached_dpy
!= NULL
) &&
549 (request
->startup_dpy
== XDisplayString( mCached_dpy
)))
552 dpy
= XOpenDisplay( request
->startup_dpy
.toLocal8Bit() );
556 id
.initId( request
->startup_id
.toLocal8Bit() );
557 KStartupInfo::sendFinishX( dpy
, id
);
558 if( mCached_dpy
!= dpy
&& mCached_dpy
!= NULL
)
559 XCloseDisplay( mCached_dpy
);
566 if (request
->autoStart
)
571 if (request
->transaction
.type() != QDBusMessage::InvalidMessage
)
573 if ( requestResult
.dbusName
.isNull() ) // null strings can't be sent
574 requestResult
.dbusName
= "";
575 Q_ASSERT( !requestResult
.error
.isNull() );
576 PIDType
<sizeof(pid_t
)>::PID_t stream_pid
= requestResult
.pid
;
577 QDBusConnection::sessionBus().send(request
->transaction
.createReply(QVariantList() << requestResult
.result
578 << requestResult
.dbusName
579 << requestResult
.error
582 #ifdef KLAUNCHER_VERBOSE_OUTPUT
583 kDebug(7016) << "removing done request" << request
->name
<< "PID" << request
->pid
;
586 requestList
.removeAll( request
);
590 static void appendLong(QByteArray
&ba
, long l
)
592 const int sz
= ba
.size();
593 ba
.resize(sz
+ sizeof(long));
594 memcpy(ba
.data() + sz
, &l
, sizeof(long));
598 KLauncher::requestStart(KLaunchRequest
*request
)
601 requestList
.append( request
);
602 lastRequest
= request
;
604 KProcess
*process
= new KProcess
;
605 process
->setOutputChannelMode(KProcess::MergedChannels
);
606 connect(process
,SIGNAL(readyReadStandardOutput()),this, SLOT(slotGotOutput()) );
607 connect(process
,SIGNAL(finished(int, QProcess::ExitStatus
)),this, SLOT(slotFinished(int, QProcess::ExitStatus
)) );
608 request
->process
= process
;
610 // process.setEnvironment(envlist);
612 foreach (const QString
&arg
, request
->arg_list
)
615 process
->setProgram(request
->name
,args
);
618 if (!process
->waitForStarted())
620 processRequestReturn(LAUNCHER_ERROR
,"");
624 request
->pid
= process
->pid();
625 QByteArray
data((char *)&request
->pid
, sizeof(int));
626 processRequestReturn(LAUNCHER_OK
,data
);
631 requestList
.append( request
);
632 // Send request to kdeinit.
633 klauncher_header request_header
;
634 QByteArray requestData
;
635 requestData
.reserve(1024);
637 appendLong(requestData
, request
->arg_list
.count() + 1);
638 requestData
.append(request
->name
.toLocal8Bit());
639 requestData
.append('\0');
640 foreach (const QString
&arg
, request
->arg_list
)
641 requestData
.append(arg
.toLocal8Bit()).append('\0');
642 appendLong(requestData
, request
->envs
.count());
643 foreach (const QString
&env
, request
->envs
)
644 requestData
.append(env
.toLocal8Bit()).append('\0');
645 appendLong(requestData
, 0); // avoid_loops, always false here
647 bool startup_notify
= !request
->startup_id
.isNull() && request
->startup_id
!= "0";
649 requestData
.append(request
->startup_id
.toLocal8Bit()).append('\0');
651 if (!request
->cwd
.isEmpty())
652 requestData
.append(request
->cwd
.toLocal8Bit()).append('\0');
655 request_header
.cmd
= startup_notify
? LAUNCHER_EXT_EXEC
: LAUNCHER_EXEC_NEW
;
657 request_header
.cmd
= LAUNCHER_EXEC_NEW
;
659 request_header
.arg_length
= requestData
.length();
660 write(kdeinitSocket
, &request_header
, sizeof(request_header
));
661 write(kdeinitSocket
, requestData
.data(), requestData
.length());
663 // Wait for pid to return.
664 lastRequest
= request
;
665 dontBlockReading
= false;
667 slotKDEInitData( kdeinitSocket
);
669 while (lastRequest
!= 0);
670 dontBlockReading
= true;
674 void KLauncher::exec_blind(const QString
&name
, const QStringList
&arg_list
, const QStringList
&envs
, const QString
&startup_id
)
676 KLaunchRequest
*request
= new KLaunchRequest
;
677 request
->autoStart
= false;
678 request
->name
= name
;
679 request
->arg_list
= arg_list
;
680 request
->dbus_startup_type
= KService::DBusNone
;
682 request
->status
= KLaunchRequest::Launching
;
683 request
->envs
= envs
;
684 // Find service, if any - strip path if needed
685 KService::Ptr service
= KService::serviceByDesktopName( name
.mid( name
.lastIndexOf( '/' ) + 1 ));
687 send_service_startup_info( request
, service
, startup_id
, QStringList());
688 else // no .desktop file, no startup info
689 cancel_service_startup_info( request
, startup_id
, envs
);
691 requestStart(request
);
692 // We don't care about this request any longer....
693 requestDone(request
);
699 KLauncher::start_service_by_name(const QString
&serviceName
, const QStringList
&urls
,
700 const QStringList
&envs
, const QString
& startup_id
, bool blind
, const QDBusMessage
&msg
)
702 KService::Ptr service
;
704 service
= KService::serviceByName(serviceName
);
707 requestResult
.result
= ENOENT
;
708 requestResult
.error
= i18n("Could not find service '%1'.", serviceName
);
709 cancel_service_startup_info( NULL
, startup_id
, envs
); // cancel it if any
712 return start_service(service
, urls
, envs
, startup_id
, blind
, false, msg
);
716 KLauncher::start_service_by_desktop_path(const QString
&serviceName
, const QStringList
&urls
,
717 const QStringList
&envs
, const QString
& startup_id
, bool blind
, const QDBusMessage
&msg
)
719 KService::Ptr service
;
721 if (QFileInfo(serviceName
).isAbsolute() )
724 service
= new KService(serviceName
);
728 service
= KService::serviceByDesktopPath(serviceName
);
732 requestResult
.result
= ENOENT
;
733 requestResult
.error
= i18n("Could not find service '%1'.", serviceName
);
734 cancel_service_startup_info( NULL
, startup_id
, envs
); // cancel it if any
737 return start_service(service
, urls
, envs
, startup_id
, blind
, false, msg
);
741 KLauncher::start_service_by_desktop_name(const QString
&serviceName
, const QStringList
&urls
,
742 const QStringList
&envs
, const QString
& startup_id
, bool blind
, const QDBusMessage
&msg
)
744 KService::Ptr service
= KService::serviceByDesktopName(serviceName
);
747 requestResult
.result
= ENOENT
;
748 requestResult
.error
= i18n("Could not find service '%1'.", serviceName
);
749 cancel_service_startup_info( NULL
, startup_id
, envs
); // cancel it if any
752 return start_service(service
, urls
, envs
, startup_id
, blind
, false, msg
);
756 KLauncher::start_service(KService::Ptr service
, const QStringList
&_urls
,
757 const QStringList
&envs
, const QString
&startup_id
,
758 bool blind
, bool autoStart
, const QDBusMessage
&msg
)
760 QStringList urls
= _urls
;
761 if (!service
->isValid())
763 requestResult
.result
= ENOEXEC
;
764 requestResult
.error
= i18n("Service '%1' is malformatted.", service
->entryPath());
765 cancel_service_startup_info( NULL
, startup_id
, envs
); // cancel it if any
768 KLaunchRequest
*request
= new KLaunchRequest
;
769 request
->autoStart
= autoStart
;
771 if ((urls
.count() > 1) && !service
->allowMultipleFiles())
773 // We need to launch the application N times. That sucks.
774 // We ignore the result for application 2 to N.
775 // For the first file we launch the application in the
776 // usual way. The reported result is based on this
778 QStringList::ConstIterator it
= urls
.constBegin();
780 it
!= urls
.constEnd();
783 QStringList singleUrl
;
784 singleUrl
.append(*it
);
785 QString startup_id2
= startup_id
;
786 if( !startup_id2
.isEmpty() && startup_id2
!= "0" )
787 startup_id2
= "0"; // can't use the same startup_id several times
788 start_service( service
, singleUrl
, envs
, startup_id2
, true, false, msg
);
790 QString firstURL
= *(urls
.begin());
792 urls
.append(firstURL
);
794 createArgs(request
, service
, urls
);
796 // We must have one argument at least!
797 if (!request
->arg_list
.count())
799 requestResult
.result
= ENOEXEC
;
800 requestResult
.error
= i18n("Service '%1' is malformatted.", service
->entryPath());
802 cancel_service_startup_info( NULL
, startup_id
, envs
);
806 request
->name
= request
->arg_list
.takeFirst();
808 if (request
->name
.endsWith("/kioexec")) {
809 // Special case for kioexec; if createArgs said we were going to use it,
810 // then we have to expect a kioexec-PID, not a org.kde.finalapp...
811 // Testcase: konqueror www.kde.org, RMB on link, open with, kruler.
813 request
->dbus_startup_type
= KService::DBusMulti
;
814 request
->dbus_name
= "org.kde.kioexec";
816 request
->dbus_startup_type
= service
->dbusStartupType();
818 if ((request
->dbus_startup_type
== KService::DBusUnique
) ||
819 (request
->dbus_startup_type
== KService::DBusMulti
)) {
820 const QVariant v
= service
->property("X-DBUS-ServiceName");
822 request
->dbus_name
= v
.toString().toUtf8();
824 if (request
->dbus_name
.isEmpty()) {
825 request
->dbus_name
= "*." + QFile::encodeName(KRun::binaryName(service
->exec(), true));
831 request
->envs
= envs
;
832 send_service_startup_info( request
, service
, startup_id
, envs
);
834 // Request will be handled later.
835 if (!blind
&& !autoStart
)
837 msg
.setDelayedReply(true);
838 request
->transaction
= msg
;
840 queueRequest(request
);
845 KLauncher::send_service_startup_info( KLaunchRequest
*request
, KService::Ptr service
, const QString
& startup_id
,
846 const QStringList
&envs
)
849 request
->startup_id
= "0";
850 if( startup_id
== "0" )
854 if( !KRun::checkStartupNotify( QString(), service
.data(), &silent
, &wmclass
))
857 id
.initId( startup_id
.toLatin1() );
859 foreach (const QString
&env
, envs
) {
860 if (env
.startsWith(QLatin1String("DISPLAY=")))
861 dpy_str
= env
.mid(8);
864 if( !dpy_str
.isEmpty() && mCached_dpy
!= NULL
865 && dpy_str
!= QLatin1String(XDisplayString(mCached_dpy
)) )
868 dpy
= XOpenDisplay( dpy_str
.toLatin1().constData() );
869 request
->startup_id
= id
.id();
872 cancel_service_startup_info( request
, startup_id
, envs
);
876 request
->startup_dpy
= dpy_str
;
878 KStartupInfoData data
;
879 data
.setName( service
->name());
880 data
.setIcon( service
->icon());
881 data
.setDescription( i18n( "Launching %1" , service
->name()));
882 if( !wmclass
.isEmpty())
883 data
.setWMClass( wmclass
);
885 data
.setSilent( KStartupInfoData::Yes
);
886 // the rest will be sent by kdeinit
887 KStartupInfo::sendStartupX( dpy
, id
, data
);
888 if( mCached_dpy
!= dpy
&& mCached_dpy
!= NULL
)
889 XCloseDisplay( mCached_dpy
);
898 KLauncher::cancel_service_startup_info( KLaunchRequest
* request
, const QString
& startup_id
,
899 const QStringList
&envs
)
902 if( request
!= NULL
)
903 request
->startup_id
= "0";
904 if( !startup_id
.isEmpty() && startup_id
!= "0" )
907 foreach (const QString
&env
, envs
) {
908 if (env
.startsWith(QLatin1String("DISPLAY=")))
909 dpy_str
= env
.mid(8);
912 if( !dpy_str
.isEmpty() && mCached_dpy
!= NULL
913 && dpy_str
!= QLatin1String(XDisplayString( mCached_dpy
)) )
916 dpy
= XOpenDisplay( dpy_str
.toLatin1().constData() );
920 id
.initId( startup_id
.toLatin1() );
921 KStartupInfo::sendFinishX( dpy
, id
);
922 if( mCached_dpy
!= dpy
&& mCached_dpy
!= NULL
)
923 XCloseDisplay( mCached_dpy
);
930 KLauncher::kdeinit_exec(const QString
&app
, const QStringList
&args
,
931 const QString
& workdir
, const QStringList
&envs
,
932 const QString
&startup_id
, bool wait
, const QDBusMessage
&msg
)
934 KLaunchRequest
*request
= new KLaunchRequest
;
935 request
->autoStart
= false;
937 for(QStringList::ConstIterator it
= args
.begin();
942 request
->arg_list
.append(arg
.toLocal8Bit());
945 request
->name
= app
.toLocal8Bit();
948 request
->dbus_startup_type
= KService::DBusWait
;
950 request
->dbus_startup_type
= KService::DBusNone
;
953 request
->startup_id
= startup_id
;
955 request
->envs
= envs
;
956 request
->cwd
= workdir
;
957 if( !app
.endsWith("kbuildsycoca4") ) // avoid stupid loop
959 // Find service, if any - strip path if needed
960 KService::Ptr service
= KService::serviceByDesktopName( app
.mid( app
.lastIndexOf( '/' ) + 1 ));
962 send_service_startup_info( request
, service
,
963 startup_id
, QStringList());
964 else // no .desktop file, no startup info
965 cancel_service_startup_info( request
, startup_id
, envs
);
967 msg
.setDelayedReply(true);
968 request
->transaction
= msg
;
969 queueRequest(request
);
974 KLauncher::queueRequest(KLaunchRequest
*request
)
976 requestQueue
.append( request
);
977 if (!bProcessingQueue
)
979 bProcessingQueue
= true;
980 QTimer::singleShot(0, this, SLOT( slotDequeue() ));
985 KLauncher::slotDequeue()
988 KLaunchRequest
*request
= requestQueue
.takeFirst();
990 request
->status
= KLaunchRequest::Launching
;
991 requestStart(request
);
992 if (request
->status
!= KLaunchRequest::Launching
)
995 #ifdef KLAUNCHER_VERBOSE_OUTPUT
996 kDebug(7016) << "Request handled already";
998 requestDone( request
);
1001 } while(requestQueue
.count());
1002 bProcessingQueue
= false;
1006 KLauncher::createArgs( KLaunchRequest
*request
, const KService::Ptr service
,
1007 const QStringList
&urls
)
1009 const QStringList params
= KRun::processDesktopExec(*service
, urls
);
1011 for(QStringList::ConstIterator it
= params
.begin();
1012 it
!= params
.end(); ++it
)
1014 request
->arg_list
.append(*it
);
1016 request
->cwd
= service
->path();
1019 ///// IO-Slave functions
1022 KLauncher::requestHoldSlave(const KUrl
&url
, const QString
&app_socket
)
1024 IdleSlave
*slave
= 0;
1025 foreach (IdleSlave
*p
, mSlaveList
)
1035 mSlaveList
.removeAll(slave
);
1036 slave
->connect(app_socket
);
1037 return slave
->pid();
1044 KLauncher::requestSlave(const QString
&protocol
,
1045 const QString
&host
,
1046 const QString
&app_socket
,
1049 IdleSlave
*slave
= 0;
1050 foreach (IdleSlave
*p
, mSlaveList
)
1052 if (p
->match(protocol
, host
, true))
1060 foreach (IdleSlave
*p
, mSlaveList
)
1062 if (p
->match(protocol
, host
, false))
1071 foreach (IdleSlave
*p
, mSlaveList
)
1073 if (p
->match(protocol
, QString(), false))
1082 mSlaveList
.removeAll(slave
);
1083 slave
->connect(app_socket
);
1084 return slave
->pid();
1087 QString name
= KProtocolInfo::exec(protocol
);
1090 error
= i18n("Unknown protocol '%1'.\n", protocol
);
1094 QStringList arg_list
;
1097 arg_list
<< protocol
;
1098 arg_list
<< mConnectionServer
.address();
1099 arg_list
<< app_socket
;
1100 name
= KStandardDirs::findExe("kioslave");
1102 QString arg1
= protocol
;
1103 QString arg2
= mConnectionServer
.address();
1104 QString arg3
= app_socket
;
1105 arg_list
.append(arg1
);
1106 arg_list
.append(arg2
);
1107 arg_list
.append(arg3
);
1110 kDebug(7016) << "KLauncher: launching new slave " << name
<< " with protocol=" << protocol
1111 << " args=" << arg_list
<< endl
;
1114 if (mSlaveDebug
== arg1
)
1116 klauncher_header request_header
;
1117 request_header
.cmd
= LAUNCHER_DEBUG_WAIT
;
1118 request_header
.arg_length
= 0;
1119 write(kdeinitSocket
, &request_header
, sizeof(request_header
));
1121 if (mSlaveValgrind
== arg1
)
1123 arg_list
.prepend(QFile::encodeName(KLibLoader::findLibrary(name
.toLocal8Bit())));
1124 arg_list
.prepend(QFile::encodeName(KStandardDirs::locate("exe", "kioslave")));
1126 if (!mSlaveValgrindSkin
.isEmpty()) {
1127 arg_list
.prepend(QLatin1String("--tool=") + mSlaveValgrindSkin
);
1129 arg_list
.prepend(QLatin1String("--tool=memcheck"));
1132 KLaunchRequest
*request
= new KLaunchRequest
;
1133 request
->autoStart
= false;
1134 request
->name
= name
;
1135 request
->arg_list
= arg_list
;
1136 request
->dbus_startup_type
= KService::DBusNone
;
1139 request
->startup_id
= "0";
1141 request
->status
= KLaunchRequest::Launching
;
1142 requestStart(request
);
1143 pid_t pid
= request
->pid
;
1145 // kDebug(7016) << "Slave launched, pid = " << pid;
1147 // We don't care about this request any longer....
1148 requestDone(request
);
1151 error
= i18n("Error loading '%1'.\n", name
);
1157 KLauncher::waitForSlave(int pid
, const QDBusMessage
&msg
)
1159 foreach (IdleSlave
*slave
, mSlaveList
)
1161 if (slave
->pid() == static_cast<pid_t
>(pid
))
1162 return; // Already here.
1164 SlaveWaitRequest
*waitRequest
= new SlaveWaitRequest
;
1165 msg
.setDelayedReply(true);
1166 waitRequest
->transaction
= msg
;
1167 waitRequest
->pid
= static_cast<pid_t
>(pid
);
1168 mSlaveWaitRequest
.append(waitRequest
);
1172 KLauncher::acceptSlave()
1174 IdleSlave
*slave
= new IdleSlave(this);
1175 mConnectionServer
.setNextPendingConnection(&slave
->mConn
);
1176 mSlaveList
.append(slave
);
1177 connect(slave
, SIGNAL(destroyed()), this, SLOT(slotSlaveGone()));
1178 connect(slave
, SIGNAL(statusUpdate(IdleSlave
*)),
1179 this, SLOT(slotSlaveStatus(IdleSlave
*)));
1180 if (!mTimer
.isActive())
1182 mTimer
.start(1000*10);
1187 KLauncher::slotSlaveStatus(IdleSlave
*slave
)
1189 QMutableListIterator
<SlaveWaitRequest
*> it(mSlaveWaitRequest
);
1192 SlaveWaitRequest
*waitRequest
= it
.next();
1193 if (waitRequest
->pid
== slave
->pid())
1195 QDBusConnection::sessionBus().send(waitRequest
->transaction
.createReply());
1203 KLauncher::slotSlaveGone()
1205 IdleSlave
*slave
= (IdleSlave
*) sender();
1206 mSlaveList
.removeAll(slave
);
1207 if ((mSlaveList
.count() == 0) && (mTimer
.isActive()))
1214 KLauncher::idleTimeout()
1216 bool keepOneFileSlave
=true;
1217 time_t now
= time(0);
1218 foreach (IdleSlave
*slave
, mSlaveList
)
1220 if ((slave
->protocol()=="file") && (keepOneFileSlave
))
1221 keepOneFileSlave
=false;
1222 else if (slave
->age(now
) > SLAVE_MAX_IDLE
)
1224 // killing idle slave
1230 void KLauncher::reparseConfiguration()
1232 KProtocolManager::reparseConfiguration();
1233 foreach (IdleSlave
*slave
, mSlaveList
)
1234 slave
->reparseConfiguration();
1239 KLauncher::slotGotOutput()
1241 KProcess
*p
= static_cast<KProcess
*>(sender());
1242 QByteArray _stdout
= p
->readAllStandardOutput();
1243 kDebug(7016) << _stdout
.data();
1247 KLauncher::slotFinished(int exitCode
, QProcess::ExitStatus exitStatus
)
1249 KProcess
*p
= static_cast<KProcess
*>(sender());
1250 kDebug(7016) << "process finished exitcode=" << exitCode
<< "exitStatus=" << exitStatus
;
1252 foreach (KLaunchRequest
*request
, requestList
)
1254 if (request
->process
== p
)
1256 #ifdef KLAUNCHER_VERBOSE_OUTPUT
1257 kDebug(7016) << "found KProcess, request done";
1259 if (exitCode
== 0 && exitStatus
== QProcess::NormalExit
)
1260 request
->status
= KLaunchRequest::Done
;
1262 request
->status
= KLaunchRequest::Error
;
1263 requestDone(request
);
1264 request
->process
= 0;
1271 #include "klauncher.moc"