1 /* This file is part of the KDE libraries
2 Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
3 Copyright (C) 2006 Thiago Macieira <thiago@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 as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "ktoolinvocation.h"
22 #include "klauncher_iface.h"
25 #include "kstandarddirs.h"
26 #include "kcomponentdata.h"
30 #include <klockfile.h>
34 #include <QMutexLocker>
35 #include <QCoreApplication>
41 KToolInvocation
*KToolInvocation::self()
43 K_GLOBAL_STATIC(KToolInvocation
, s_self
)
47 KToolInvocation::KToolInvocation() : QObject(0), d(0)
51 KToolInvocation::~KToolInvocation()
55 Q_GLOBAL_STATIC_WITH_ARGS(org::kde::KLauncher
, klauncherIface
,
56 ("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus()))
58 org::kde::KLauncher
*KToolInvocation::klauncher()
60 if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ) )
62 kDebug() << "klauncher not running... launching kdeinit";
63 KToolInvocation::startKdeinit();
65 return ::klauncherIface();
68 static void printError(const QString
& text
, QString
* error
)
73 kError() << text
<< endl
;
76 bool KToolInvocation::isMainThreadActive(QString
* error
)
78 if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread())
80 printError(i18n("Function must be called from the main thread."), error
);
87 int KToolInvocation::startServiceInternal(const char *_function
,
88 const QString
& _name
, const QStringList
&URLs
,
89 QString
*error
, QString
*serviceName
, int *pid
,
90 const QByteArray
& startup_id
, bool noWait
,
91 const QString
& workdir
)
93 QString function
= QLatin1String(_function
);
94 org::kde::KLauncher
*launcher
= KToolInvocation::klauncher();
95 QDBusMessage msg
= QDBusMessage::createMethodCall(launcher
->service(),
97 launcher
->interface(),
100 if (function
== QLatin1String("kdeinit_exec_with_workdir"))
103 // make sure there is id, so that user timestamp exists
105 QByteArray s
= startup_id
;
106 emit
kapplication_hook(envs
, s
);
110 msg
<< QStringList();
113 if( !function
.startsWith( QLatin1String("kdeinit_exec") ) )
116 QDBusMessage reply
= QDBusConnection::sessionBus().call(msg
);
117 if ( reply
.type() != QDBusMessage::ReplyMessage
)
119 QDBusReply
<QString
> replyObj(reply
);
120 if (replyObj
.error().type() == QDBusError::NoReply
) {
121 printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name
), error
);
123 const QString rpl
= reply
.arguments().count() > 0 ? reply
.arguments().at(0).toString() : reply
.errorMessage();
124 printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n",function
, rpl
), error
);
133 Q_ASSERT(reply
.arguments().count() == 4);
135 *serviceName
= reply
.arguments().at(1).toString();
137 *error
= reply
.arguments().at(2).toString();
139 *pid
= reply
.arguments().at(3).toInt();
140 return reply
.arguments().at(0).toInt();
144 KToolInvocation::startServiceByName( const QString
& _name
, const QString
&URL
,
145 QString
*error
, QString
*serviceName
, int *pid
,
146 const QByteArray
& startup_id
, bool noWait
)
148 if (!isMainThreadActive(error
))
154 return self()->startServiceInternal("start_service_by_name",
155 _name
, URLs
, error
, serviceName
, pid
, startup_id
, noWait
);
159 KToolInvocation::startServiceByName( const QString
& _name
, const QStringList
&URLs
,
160 QString
*error
, QString
*serviceName
, int *pid
,
161 const QByteArray
& startup_id
, bool noWait
)
163 if (!isMainThreadActive(error
))
166 return self()->startServiceInternal("start_service_by_name",
167 _name
, URLs
, error
, serviceName
, pid
, startup_id
, noWait
);
171 KToolInvocation::startServiceByDesktopPath( const QString
& _name
, const QString
&URL
,
172 QString
*error
, QString
*serviceName
,
173 int *pid
, const QByteArray
& startup_id
, bool noWait
)
175 if (!isMainThreadActive(error
))
181 return self()->startServiceInternal("start_service_by_desktop_path",
182 _name
, URLs
, error
, serviceName
, pid
, startup_id
, noWait
);
186 KToolInvocation::startServiceByDesktopPath( const QString
& _name
, const QStringList
&URLs
,
187 QString
*error
, QString
*serviceName
, int *pid
,
188 const QByteArray
& startup_id
, bool noWait
)
190 if (!isMainThreadActive(error
))
193 return self()->startServiceInternal("start_service_by_desktop_path",
194 _name
, URLs
, error
, serviceName
, pid
, startup_id
, noWait
);
198 KToolInvocation::startServiceByDesktopName( const QString
& _name
, const QString
&URL
,
199 QString
*error
, QString
*serviceName
, int *pid
,
200 const QByteArray
& startup_id
, bool noWait
)
202 if (!isMainThreadActive(error
))
208 return self()->startServiceInternal("start_service_by_desktop_name",
209 _name
, URLs
, error
, serviceName
, pid
, startup_id
, noWait
);
213 KToolInvocation::startServiceByDesktopName( const QString
& _name
, const QStringList
&URLs
,
214 QString
*error
, QString
*serviceName
, int *pid
,
215 const QByteArray
& startup_id
, bool noWait
)
217 if (!isMainThreadActive(error
))
220 return self()->startServiceInternal("start_service_by_desktop_name",
221 _name
, URLs
, error
, serviceName
, pid
, startup_id
, noWait
);
225 KToolInvocation::kdeinitExec( const QString
& name
, const QStringList
&args
,
226 QString
*error
, int *pid
, const QByteArray
& startup_id
)
228 if (!isMainThreadActive(error
))
231 return self()->startServiceInternal("kdeinit_exec",
232 name
, args
, error
, 0, pid
, startup_id
, false);
237 KToolInvocation::kdeinitExecWait( const QString
& name
, const QStringList
&args
,
238 QString
*error
, int *pid
, const QByteArray
& startup_id
)
240 if (!isMainThreadActive(error
))
243 return self()->startServiceInternal("kdeinit_exec_wait",
244 name
, args
, error
, 0, pid
, startup_id
, false);
247 void KToolInvocation::invokeHelp( const QString
& anchor
,
248 const QString
& _appname
,
249 const QByteArray
& startup_id
)
251 if (!isMainThreadActive())
257 if (_appname
.isEmpty()) {
258 appname
= QCoreApplication::instance()->applicationName();
262 KService::Ptr
service(KService::serviceByDesktopName(appname
));
264 docPath
= service
->docPath();
267 if (!docPath
.isEmpty()) {
268 url
= KUrl(KUrl("help:/"), docPath
);
270 url
= QString("help:/%1/index.html").arg(appname
);
273 if (!anchor
.isEmpty()) {
274 url
.addQueryItem("anchor", anchor
);
277 // launch a browser for URIs not handled by khelpcenter
278 // (following KCMultiDialog::slotHelpClicked())
279 if (!(url
.protocol() == "help" || url
.protocol() == "man" || url
.protocol() == "info")) {
280 invokeBrowser(url
.url());
284 QDBusInterface
*iface
= new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
285 QLatin1String("/KHelpCenter"),
286 QLatin1String("org.kde.khelpcenter.khelpcenter"),
287 QDBusConnection::sessionBus());
288 if ( !iface
->isValid() )
292 // startServiceByDesktopName() does not work yet; KRun:processDesktopExec returned 'KRun: syntax error in command "khelpcenter %u" , service "KHelpCenter" '
293 if (kdeinitExec( "khelpcenter", QStringList() << url
.url(), &error
, 0, startup_id
))
295 if (startServiceByDesktopName("khelpcenter", url
.url(), &error
, 0, 0, startup_id
, false))
298 KMessage::message(KMessage::Error
,
299 i18n("Could not launch the KDE Help Center:\n\n%1", error
),
300 i18n("Could not Launch Help Center"));
305 iface
= new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
306 QLatin1String("/KHelpCenter"),
307 QLatin1String("org.kde.khelpcenter.khelpcenter"),
308 QDBusConnection::sessionBus());
311 iface
->call("openUrl", url
.url(), startup_id
);
315 void KToolInvocation::invokeMailer(const QString
&address
, const QString
&subject
, const QByteArray
& startup_id
)
317 if (!isMainThreadActive())
320 invokeMailer(address
, QString(), QString(), subject
, QString(), QString(),
321 QStringList(), startup_id
);
324 void KToolInvocation::invokeMailer(const KUrl
&mailtoURL
, const QByteArray
& startup_id
, bool allowAttachments
)
326 if (!isMainThreadActive())
329 QString address
= KUrl::fromPercentEncoding(mailtoURL
.path().toLatin1()), subject
, cc
, bcc
, body
;
330 const QStringList queries
= mailtoURL
.query().mid(1).split( '&');
331 QStringList attachURLs
;
332 for (QStringList::ConstIterator it
= queries
.begin(); it
!= queries
.end(); ++it
)
334 QString q
= (*it
).toLower();
335 if (q
.startsWith("subject="))
336 subject
= KUrl::fromPercentEncoding((*it
).mid(8).toLatin1());
338 if (q
.startsWith("cc="))
339 cc
= cc
.isEmpty()? KUrl::fromPercentEncoding((*it
).mid(3).toLatin1()): cc
+ ',' + KUrl::fromPercentEncoding((*it
).mid(3).toLatin1());
341 if (q
.startsWith("bcc="))
342 bcc
= bcc
.isEmpty()? KUrl::fromPercentEncoding((*it
).mid(4).toLatin1()): bcc
+ ',' + KUrl::fromPercentEncoding((*it
).mid(4).toLatin1());
344 if (q
.startsWith("body="))
345 body
= KUrl::fromPercentEncoding((*it
).mid(5).toLatin1());
347 if (allowAttachments
&& q
.startsWith("attach="))
348 attachURLs
.push_back(KUrl::fromPercentEncoding((*it
).mid(7).toLatin1()));
350 if (allowAttachments
&& q
.startsWith("attachment="))
351 attachURLs
.push_back(KUrl::fromPercentEncoding((*it
).mid(11).toLatin1()));
353 if (q
.startsWith("to="))
354 address
= address
.isEmpty()? KUrl::fromPercentEncoding((*it
).mid(3).toLatin1()): address
+ ',' + KUrl::fromPercentEncoding((*it
).mid(3).toLatin1());
357 invokeMailer( address
, cc
, bcc
, subject
, body
, QString(), attachURLs
, startup_id
);
360 void KToolInvocation::startKdeinit()
362 KComponentData
inst( "startkdeinitlock" );
363 KLockFile
lock( KStandardDirs::locateLocal( "tmp", "startkdeinitlock", inst
));
364 if( lock
.lock( KLockFile::NoBlockFlag
) != KLockFile::LockOK
) {
366 if( QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ))
367 return; // whoever held the lock has already started it
369 // Try to launch kdeinit.
370 QString srv
= KStandardDirs::findExe(QLatin1String("kdeinit4"));
373 // this is disabled because we are in kdecore
374 // const bool gui = qApp && qApp->type() != QApplication::Tty;
376 // qApp->setOverrideCursor( Qt::WaitCursor );
381 QProcess::execute(srv
, args
);
383 // qApp->restoreOverrideCursor();
386 #include "ktoolinvocation.moc"