summaryrefslogtreecommitdiff
path: root/kdecore/kernel/ktoolinvocation.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
committerChristian Mollekopf <chrigi_1@fastmail.fm>2012-06-25 18:42:22 (GMT)
commit43d35cfb36c924eede624f4a5c2fcb0dd7d698b6 (patch)
treeb7ac13bcf009d94cabb4c5afeee0825a4ce9da67 /kdecore/kernel/ktoolinvocation.cpp
parentbf385f44f99d73263b1787daac7423599e69f024 (diff)
downloadlibcalendaring-43d35cfb36c924eede624f4a5c2fcb0dd7d698b6.tar.gz
kdecore import
commit 557c1267cbb5e352e1487c3dd468cd4a4cb63254 Merge: aed99b0 387e3c3 Author: David Faure <faure@kde.org> Date: Thu Jun 14 17:56:59 2012 +0200 Merge remote-tracking branch 'origin/KDE/4.8'
Diffstat (limited to 'kdecore/kernel/ktoolinvocation.cpp')
-rw-r--r--kdecore/kernel/ktoolinvocation.cpp396
1 files changed, 396 insertions, 0 deletions
diff --git a/kdecore/kernel/ktoolinvocation.cpp b/kdecore/kernel/ktoolinvocation.cpp
new file mode 100644
index 0000000..73c8bc0
--- /dev/null
+++ b/kdecore/kernel/ktoolinvocation.cpp
@@ -0,0 +1,396 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
+ Copyright (C) 2006 Thiago Macieira <thiago@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 as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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.
+*/
+
+#include "ktoolinvocation.h"
+#include "klauncher_iface.h"
+#include "kdebug.h"
+#include "kglobal.h"
+#include "kstandarddirs.h"
+#include "kcomponentdata.h"
+#include "kurl.h"
+#include "kmessage.h"
+#include "kservice.h"
+#include <klockfile.h>
+#include <klocale.h>
+
+#include <QMutex>
+#include <QMutexLocker>
+#include <QCoreApplication>
+#include <QThread>
+
+#include <errno.h>
+
+
+KToolInvocation *KToolInvocation::self()
+{
+ K_GLOBAL_STATIC(KToolInvocation, s_self)
+ return s_self;
+}
+
+KToolInvocation::KToolInvocation() : QObject(0), d(0)
+{
+}
+
+KToolInvocation::~KToolInvocation()
+{
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(org::kde::KLauncher, klauncherIface,
+ (QString::fromLatin1("org.kde.klauncher"), QString::fromLatin1("/KLauncher"), QDBusConnection::sessionBus()))
+
+org::kde::KLauncher *KToolInvocation::klauncher()
+{
+ if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"))) {
+ kDebug(180) << "klauncher not running... launching kdeinit";
+ KToolInvocation::startKdeinit();
+ }
+ return ::klauncherIface();
+}
+
+static void printError(const QString& text, QString* error)
+{
+ if (error)
+ *error = text;
+ else
+ kError() << text << endl;
+}
+
+bool KToolInvocation::isMainThreadActive(QString* error)
+{
+ if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread())
+ {
+ printError(i18n("Function must be called from the main thread."), error);
+ return false;
+ }
+
+ return true;
+}
+
+int KToolInvocation::startServiceInternal(const char *_function,
+ const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait,
+ const QString& workdir)
+{
+ QString function = QLatin1String(_function);
+ org::kde::KLauncher *launcher = KToolInvocation::klauncher();
+ QDBusMessage msg = QDBusMessage::createMethodCall(launcher->service(),
+ launcher->path(),
+ launcher->interface(),
+ function);
+ msg << _name << URLs;
+ if (function == QLatin1String("kdeinit_exec_with_workdir"))
+ msg << workdir;
+#ifdef Q_WS_X11
+ // make sure there is id, so that user timestamp exists
+ QStringList envs;
+ QByteArray s = startup_id;
+ emit kapplication_hook(envs, s);
+ msg << envs;
+ msg << QString::fromLatin1(s);
+#else
+ msg << QStringList();
+ msg << QString();
+#endif
+ if( !function.startsWith( QLatin1String("kdeinit_exec") ) )
+ msg << noWait;
+
+ QDBusMessage reply = QDBusConnection::sessionBus().call(msg, QDBus::Block, INT_MAX);
+ if ( reply.type() != QDBusMessage::ReplyMessage )
+ {
+ QDBusReply<QString> replyObj(reply);
+ if (replyObj.error().type() == QDBusError::NoReply) {
+ printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name), error);
+ } else {
+ const QString rpl = reply.arguments().count() > 0 ? reply.arguments().at(0).toString() : reply.errorMessage();
+ printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n",function, rpl), error);
+ }
+ //qDebug() << reply;
+ return EINVAL;
+ }
+
+ if (noWait)
+ return 0;
+
+ Q_ASSERT(reply.arguments().count() == 4);
+ if (serviceName)
+ *serviceName = reply.arguments().at(1).toString();
+ if (error)
+ *error = reply.arguments().at(2).toString();
+ if (pid)
+ *pid = reply.arguments().at(3).toInt();
+ return reply.arguments().at(0).toInt();
+}
+
+#ifndef KDE_NO_DEPRECATED
+int
+KToolInvocation::startServiceByName( const QString& _name, const QString &URL,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return self()->startServiceInternal("start_service_by_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+#endif
+
+#ifndef KDE_NO_DEPRECATED
+int
+KToolInvocation::startServiceByName( const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("start_service_by_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+#endif
+
+int
+KToolInvocation::startServiceByDesktopPath( const QString& _name, const QString &URL,
+ QString *error, QString *serviceName,
+ int *pid, const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return self()->startServiceInternal("start_service_by_desktop_path",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::startServiceByDesktopPath( const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("start_service_by_desktop_path",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::startServiceByDesktopName( const QString& _name, const QString &URL,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ QStringList URLs;
+ if (!URL.isEmpty())
+ URLs.append(URL);
+ return self()->startServiceInternal("start_service_by_desktop_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::startServiceByDesktopName( const QString& _name, const QStringList &URLs,
+ QString *error, QString *serviceName, int *pid,
+ const QByteArray& startup_id, bool noWait )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("start_service_by_desktop_name",
+ _name, URLs, error, serviceName, pid, startup_id, noWait);
+}
+
+int
+KToolInvocation::kdeinitExec( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QByteArray& startup_id )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("kdeinit_exec",
+ name, args, error, 0, pid, startup_id, false);
+}
+
+
+int
+KToolInvocation::kdeinitExecWait( const QString& name, const QStringList &args,
+ QString *error, int *pid, const QByteArray& startup_id )
+{
+ if (!isMainThreadActive(error))
+ return EINVAL;
+
+ return self()->startServiceInternal("kdeinit_exec_wait",
+ name, args, error, 0, pid, startup_id, false);
+}
+
+void KToolInvocation::invokeHelp( const QString& anchor,
+ const QString& _appname,
+ const QByteArray& startup_id )
+{
+ if (!isMainThreadActive())
+ return;
+
+ KUrl url;
+ QString appname;
+ QString docPath;
+ if (_appname.isEmpty()) {
+ appname = QCoreApplication::instance()->applicationName();
+ } else
+ appname = _appname;
+
+ KService::Ptr service(KService::serviceByDesktopName(appname));
+ if (service) {
+ docPath = service->docPath();
+ }
+
+ if (!docPath.isEmpty()) {
+ url = KUrl(KUrl("help:/"), docPath);
+ } else {
+ url = QString::fromLatin1("help:/%1/index.html").arg(appname);
+ }
+
+ if (!anchor.isEmpty()) {
+ url.addQueryItem(QString::fromLatin1("anchor"), anchor);
+ }
+
+ // launch a browser for URIs not handled by khelpcenter
+ // (following KCMultiDialog::slotHelpClicked())
+ if (!(url.protocol() == QLatin1String("help") || url.protocol() == QLatin1String("man") || url.protocol() == QLatin1String("info"))) {
+ invokeBrowser(url.url());
+ return;
+ }
+
+ QDBusInterface *iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
+ QLatin1String("/KHelpCenter"),
+ QLatin1String("org.kde.khelpcenter.khelpcenter"),
+ QDBusConnection::sessionBus());
+ if ( !iface->isValid() )
+ {
+ QString error;
+#ifdef Q_WS_WIN
+ // startServiceByDesktopName() does not work yet; KRun:processDesktopExec returned 'KRun: syntax error in command "khelpcenter %u" , service "KHelpCenter" '
+ if (kdeinitExec(QLatin1String("khelpcenter"), QStringList() << url.url(), &error, 0, startup_id))
+#else
+ if (startServiceByDesktopName(QLatin1String("khelpcenter"), url.url(), &error, 0, 0, startup_id, false))
+#endif
+ {
+ KMessage::message(KMessage::Error,
+ i18n("Could not launch the KDE Help Center:\n\n%1", error),
+ i18n("Could not Launch Help Center"));
+ delete iface;
+ return;
+ }
+
+ delete iface;
+ iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
+ QLatin1String("/KHelpCenter"),
+ QLatin1String("org.kde.khelpcenter.khelpcenter"),
+ QDBusConnection::sessionBus());
+ }
+
+ iface->call(QString::fromLatin1("openUrl"), url.url(), startup_id );
+ delete iface;
+}
+
+void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray& startup_id)
+{
+ if (!isMainThreadActive())
+ return;
+
+ invokeMailer(address, QString(), QString(), subject, QString(), QString(),
+ QStringList(), startup_id );
+}
+
+void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments )
+{
+ if (!isMainThreadActive())
+ return;
+
+ QString address = mailtoURL.path();
+ QString subject;
+ QString cc;
+ QString bcc;
+ QString body;
+
+ const QStringList queries = mailtoURL.query().mid(1).split(QLatin1Char('&'));
+ const QChar comma = QChar::fromLatin1(',');
+ QStringList attachURLs;
+ for (QStringList::ConstIterator it = queries.begin(); it != queries.end(); ++it)
+ {
+ QString q = (*it).toLower();
+ if (q.startsWith(QLatin1String("subject=")))
+ subject = KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
+ else
+ if (q.startsWith(QLatin1String("cc=")))
+ cc = cc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): cc + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
+ else
+ if (q.startsWith(QLatin1String("bcc=")))
+ bcc = bcc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(4).toLatin1()): bcc + comma + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
+ else
+ if (q.startsWith(QLatin1String("body=")))
+ body = KUrl::fromPercentEncoding((*it).mid(5).toLatin1());
+ else
+ if (allowAttachments && q.startsWith(QLatin1String("attach=")))
+ attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(7).toLatin1()));
+ else
+ if (allowAttachments && q.startsWith(QLatin1String("attachment=")))
+ attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(11).toLatin1()));
+ else
+ if (q.startsWith(QLatin1String("to=")))
+ address = address.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): address + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
+ }
+
+ invokeMailer( address, cc, bcc, subject, body, QString(), attachURLs, startup_id );
+}
+
+void KToolInvocation::startKdeinit()
+{
+ KComponentData inst( "startkdeinitlock" );
+ KLockFile lock( KStandardDirs::locateLocal("tmp", QString::fromLatin1("startkdeinitlock"), inst ));
+ if( lock.lock( KLockFile::NoBlockFlag ) != KLockFile::LockOK ) {
+ lock.lock();
+ if( QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher")))
+ return; // whoever held the lock has already started it
+ }
+ // Try to launch kdeinit.
+ QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4"));
+ if (srv.isEmpty())
+ return;
+// this is disabled because we are in kdecore
+// const bool gui = qApp && qApp->type() != QApplication::Tty;
+// if ( gui )
+// qApp->setOverrideCursor( Qt::WaitCursor );
+ QStringList args;
+#ifndef Q_WS_WIN
+ args += QString::fromLatin1("--suicide");
+#endif
+ QProcess::execute(srv, args);
+// if ( gui )
+// qApp->restoreOverrideCursor();
+}
+
+#include "ktoolinvocation.moc"