generic: call klauncher methods asynchronously from KToolInvocation

so that application event processing is not blocked by any
KToolInvocation method, the D-Bus service name and PID return arguments
are not used anyway so removing them

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-12-19 12:41:17 +02:00
parent 809ce8ae90
commit 4fb8a1d674
12 changed files with 243 additions and 419 deletions

View file

@ -342,7 +342,6 @@ install(
NETRootInfo
NETWinInfo
OrgKdeKDirNotifyInterface
OrgKdeKLauncherInterface
ThumbCreator
KCategorizedView
KCategoryDrawer

View file

@ -1 +0,0 @@
#include "../klauncher_iface.h"

View file

@ -160,7 +160,6 @@ set(kdecore_LIB_SRCS
util/kdedmodule.cpp
util/kdevicedatabase.cpp
util/kdeversion.cpp
util/klauncher_iface.cpp
util/kmacroexpander.cpp
util/kpluginfactory.cpp
util/kpluginloader.cpp
@ -300,7 +299,6 @@ install(
util/kde_file.h
util/kdedmodule.h
util/kdevicedatabase.h
util/klauncher_iface.h
util/kmacroexpander.h
util/kpluginfactory.h
util/kpluginloader.h

View file

@ -35,7 +35,34 @@
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnectionInterface>
static inline void printError(const QString& text, QString* error)
#define KTOOLINVOCATION_TIMEOUT 250
#define KTOOLINVOCATION_SLEEPTIME 150
// NOTE: keep in sync with:
// kdelibs/kinit/klauncher_adaptor.h
static inline QString getKLauncherError(const int result, const QString &app)
{
switch (result) {
case -1: {
return i18n("Application service is not valid or does not support multiple files: %1.", app);
}
case -2: {
return i18n("Application not found: %1.", app);
}
case -3: {
return i18n("Application could not be processed: %1.", app);
}
case -4: {
return i18n("Application failed to start: %1.", app);
}
case -5: {
return i18n("D-Bus error occured while starting application: %1.", app);
}
}
return i18n("Unknown KLauncher error for application: %1.", app);
}
static inline void printError(const QString &text, QString *error)
{
if (error)
*error = text;
@ -53,10 +80,12 @@ KToolInvocation::KToolInvocation()
: QObject(0),
klauncherIface(nullptr)
{
klauncherIface = new org::kde::KLauncher(
klauncherIface = new QDBusInterface(
QString::fromLatin1("org.kde.klauncher"),
QString::fromLatin1("/KLauncher"),
QDBusConnection::sessionBus()
QString::fromLatin1("org.kde.KLauncher"),
QDBusConnection::sessionBus(),
this
);
}
@ -67,130 +96,124 @@ KToolInvocation::~KToolInvocation()
void KToolInvocation::setLaunchEnv(const QString &name, const QString &value)
{
self()->klauncherIface->setLaunchEnv(name, value);
self()->klauncherIface->asyncCall(QString::fromLatin1("setLaunchEnv"), name, value);
}
int KToolInvocation::startServiceInternal(const char *_function,
const QString& name, const QStringList &URLs,
QString *error, QString *serviceName, qint64 *pid,
const QByteArray& startup_id, bool noWait,
const QString& workdir)
const QString &name, const QStringList &URLs,
QString *error,
const QByteArray &startup_id, bool noWait,
const QString &workdir)
{
QString function = QString::fromLatin1(_function);
QDBusMessage msg = QDBusMessage::createMethodCall(
klauncherIface->service(),
klauncherIface->path(),
klauncherIface->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, s.size());
#else
msg << QStringList();
msg << QString();
#endif
if( !function.startsWith( QLatin1String("kdeinit_exec") ) )
msg << noWait;
QByteArray asn = startup_id;
emit kapplication_hook(envs, asn);
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;
QDBusPendingReply<int> reply;
if (qstrcmp(_function, "kdeinit_exec_with_workdir") == 0) {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, QString::fromLatin1(asn, asn.size()), workdir
);
} else if (qstrcmp(_function, "start_service_by_desktop_name") == 0 || qstrcmp(_function, "start_service_by_desktop_path") == 0) {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, QString::fromLatin1(asn, asn.size()), noWait
);
} else {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, QString::fromLatin1(asn, asn.size())
);
}
kDebug() << "Waiting for klauncher call to finish" << function;
while (!reply.isFinished()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, KTOOLINVOCATION_TIMEOUT);
QThread::msleep(KTOOLINVOCATION_SLEEPTIME);
}
kDebug() << "Done waiting for klauncher call to finish" << function;
if (!reply.isValid()) {
printError(
i18n("KLauncher error: %1.", reply.error().message()),
error
);
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).toLongLong();
return reply.arguments().at(0).toInt();
const int result = reply.value();
if (result < 0) {
printError(
getKLauncherError(result, name),
error
);
// compat
return -result;
} else if (result != 0) {
printError(
i18n("Application failed to start: %1.", name),
error
);
}
return result;
}
int
KToolInvocation::startServiceByDesktopPath( const QString& name, const QString &URL,
QString *error, QString *serviceName,
qint64 *pid, const QByteArray& startup_id, bool noWait )
int KToolInvocation::startServiceByDesktopPath(const QString &name, const QString &URL,
QString *error,
const QByteArray &startup_id, bool noWait)
{
QStringList URLs;
if (!URL.isEmpty())
URLs.append(URL);
return self()->startServiceInternal("start_service_by_desktop_path",
name, URLs, error, serviceName, pid, startup_id, noWait);
name, URLs, error, startup_id, noWait);
}
int
KToolInvocation::startServiceByDesktopPath( const QString& name, const QStringList &URLs,
QString *error, QString *serviceName, qint64 *pid,
const QByteArray& startup_id, bool noWait )
int KToolInvocation::startServiceByDesktopPath(const QString &name, const QStringList &URLs,
QString *error,
const QByteArray &startup_id, bool noWait)
{
return self()->startServiceInternal("start_service_by_desktop_path",
name, URLs, error, serviceName, pid, startup_id, noWait);
name, URLs, error, startup_id, noWait);
}
int
KToolInvocation::startServiceByDesktopName( const QString& name, const QString &URL,
QString *error, QString *serviceName, qint64 *pid,
const QByteArray& startup_id, bool noWait )
int KToolInvocation::startServiceByDesktopName(const QString& name, const QString &URL,
QString *error,
const QByteArray &startup_id, bool noWait)
{
QStringList URLs;
if (!URL.isEmpty())
URLs.append(URL);
return self()->startServiceInternal("start_service_by_desktop_name",
name, URLs, error, serviceName, pid, startup_id, noWait);
name, URLs, error, startup_id, noWait);
}
int
KToolInvocation::startServiceByDesktopName( const QString& name, const QStringList &URLs,
QString *error, QString *serviceName, qint64 *pid,
const QByteArray& startup_id, bool noWait )
int KToolInvocation::startServiceByDesktopName(const QString &name, const QStringList &URLs,
QString *error,
const QByteArray &startup_id, bool noWait)
{
return self()->startServiceInternal("start_service_by_desktop_name",
name, URLs, error, serviceName, pid, startup_id, noWait);
name, URLs, error, startup_id, noWait);
}
int
KToolInvocation::kdeinitExec( const QString& name, const QStringList &args,
QString *error, qint64 *pid, const QByteArray& startup_id )
int KToolInvocation::kdeinitExec(const QString &name, const QStringList &args,
QString *error,
const QByteArray &startup_id)
{
return self()->startServiceInternal("kdeinit_exec",
name, args, error, 0, pid, startup_id, false);
name, args, error, startup_id, false);
}
int
KToolInvocation::kdeinitExecWait( const QString& name, const QStringList &args,
QString *error, qint64 *pid, const QByteArray& startup_id )
int KToolInvocation::kdeinitExecWait(const QString &name, const QStringList &args,
QString *error,
const QByteArray &startup_id)
{
return self()->startServiceInternal("kdeinit_exec_wait",
name, args, error, 0, pid, startup_id, false);
name, args, error, startup_id, false);
}
void KToolInvocation::invokeHelp( const QString& anchor,
const QString& _appname,
const QByteArray& startup_id )
void KToolInvocation::invokeHelp(const QString &anchor,
const QString &_appname,
const QByteArray &startup_id)
{
KUrl url;
QString appname;
@ -219,12 +242,12 @@ void KToolInvocation::invokeHelp( const QString& anchor,
invokeBrowser(url.url());
}
void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray& startup_id)
void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray &startup_id)
{
invokeMailer(address, QString(), subject, QString(), QStringList(), startup_id );
}
void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments )
void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments)
{
QString address = mailtoURL.path();
QString subject;

View file

@ -26,11 +26,10 @@
#define KTOOLINVOCATION_H
#include <kdecore_export.h>
#include <klauncher_iface.h>
#include <QtCore/qstringlist.h>
#include <QStringList>
#include <QDBusInterface>
class OrgKdeKLauncherInterface;
class KUrl;
/**
@ -91,9 +90,9 @@ public Q_SLOTS:
* "" ( empty string ) is the default
*/
static void invokeHelp( const QString& anchor = QString(),
const QString& appname = QString(),
const QByteArray& startup_id = QByteArray());
static void invokeHelp(const QString &anchor = QString(),
const QString &appname = QString(),
const QByteArray &startup_id = QByteArray());
/**
* Convenience method; invokes the standard email application.
@ -103,8 +102,8 @@ public Q_SLOTS:
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
*/
static void invokeMailer( const QString &address, const QString &subject,
const QByteArray& startup_id = QByteArray() );
static void invokeMailer(const QString &address, const QString &subject,
const QByteArray &startup_id = QByteArray());
/**
* Invokes the standard email application.
@ -115,8 +114,8 @@ public Q_SLOTS:
* @param allowAttachments whether attachments specified in mailtoURL should be honoured.
The default is false; do not honor requests for attachments.
*/
static void invokeMailer( const KUrl &mailtoURL, const QByteArray& startup_id = QByteArray(),
bool allowAttachments = false );
static void invokeMailer(const KUrl &mailtoURL, const QByteArray &startup_id = QByteArray(),
bool allowAttachments = false );
/**
* Convenience method; invokes the standard email application.
@ -132,9 +131,9 @@ public Q_SLOTS:
* "" ( empty string ) is the default
*/
static void invokeMailer(const QString &to, const QString &cc,
const QString &subject, const QString &body,
const QStringList &attachURLs = QStringList(),
const QByteArray& startup_id = QByteArray() );
const QString &subject, const QString &body,
const QStringList &attachURLs = QStringList(),
const QByteArray &startup_id = QByteArray());
/**
* Invokes the user's preferred browser.
@ -150,8 +149,8 @@ public Q_SLOTS:
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
*/
static void invokeBrowser( const QString &url,
const QByteArray& startup_id = QByteArray() );
static void invokeBrowser(const QString &url,
const QByteArray &startup_id = QByteArray());
/**
* Invokes the standard terminal application.
@ -164,7 +163,7 @@ public Q_SLOTS:
* @since 4.1
*/
static void invokeTerminal(const QString &command,
const QString& workdir = QString(),
const QString &workdir = QString(),
const QByteArray &startup_id = "");
public:
@ -186,20 +185,14 @@ public:
* @param error On failure, @p error contains a description of the error
* that occurred. If the pointer is 0, the argument will be
* ignored
* @param serviceName On success, @p serviceName contains the DCOP name
* under which this service is available. If empty, the service does
* not provide DCOP services. If the pointer is 0 the argument
* will be ignored
* @param pid On success, the process id of the new service will be written
* here. If the pointer is 0, the argument will be ignored.
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
* @param noWait if set, the function does not wait till the service is running.
* @return an error code indicating success (== 0) or failure (> 0).
*/
static int startServiceByDesktopPath( const QString& name, const QString &URL,
QString *error=0, QString *serviceName=0, qint64 *pid = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false );
static int startServiceByDesktopPath(const QString &name, const QString &URL,
QString *error = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false);
/**
* Starts a service based on the desktop path of the service.
@ -209,20 +202,15 @@ public:
* @param URLs if not empty these URLs will be passed to the service
* @param error On failure, @p error contains a description of the error
* that occurred. If the pointer is 0, the argument will be
* ignored * @param serviceName On success, @p serviceName contains the DCOP name
* under which this service is available. If empty, the service does
* not provide DCOP services. If the pointer is 0 the argument
* will be ignored
* @param pid On success, the process id of the new service will be written
* here. If the pointer is 0, the argument will be ignored.
* ignored
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
* @param noWait if set, the function does not wait till the service is running.
* @return an error code indicating success (== 0) or failure (> 0).
*/
static int startServiceByDesktopPath( const QString& name, const QStringList &URLs=QStringList(),
QString *error=0, QString *serviceName=0, qint64 *pid = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false );
static int startServiceByDesktopPath(const QString &name, const QStringList &URLs = QStringList(),
QString *error = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false);
/**
* Starts a service based on the desktop name of the service.
@ -233,20 +221,14 @@ public:
* @param error On failure, @p error contains a description of the error
* that occurred. If the pointer is 0, the argument will be
* ignored
* @param serviceName On success, @p serviceName contains the D-Bus service name
* under which this service is available. If empty, the service does
* not provide D-Bus services. If the pointer is 0 the argument
* will be ignored
* @param pid On success, the process id of the new service will be written
* here. If the pointer is 0, the argument will be ignored.
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
* @param noWait if set, the function does not wait till the service is running.
* @return an error code indicating success (== 0) or failure (> 0).
*/
static int startServiceByDesktopName( const QString& name, const QString &URL,
QString *error=0, QString *serviceName=0, qint64 *pid = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false );
static int startServiceByDesktopName(const QString &name, const QString &URL,
QString *error = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false);
/**
* Starts a service based on the desktop name of the service.
@ -257,20 +239,14 @@ public:
* @param error On failure, @p error contains a description of the error
* that occurred. If the pointer is 0, the argument will be
* ignored
* @param serviceName On success, @p serviceName contains the D-Bus service name
* under which this service is available. If empty, the service does
* not provide D-Bus services. If the pointer is 0 the argument
* will be ignored
* @param pid On success, the process id of the new service will be written
* here. If the pointer is 0, the argument will be ignored.
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
* @param noWait if set, the function does not wait till the service is running.
* @return an error code indicating success (== 0) or failure (> 0).
*/
static int startServiceByDesktopName( const QString& name, const QStringList &URLs=QStringList(),
QString *error=0, QString *serviceName=0, qint64 *pid = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false );
static int startServiceByDesktopName(const QString &name, const QStringList &URLs = QStringList(),
QString *error = 0,
const QByteArray &startup_id = QByteArray(), bool noWait = false);
/**
* Starts a program via kdeinit.
@ -283,14 +259,12 @@ public:
* @param error On failure, @p error contains a description of the error
* that occurred. If the pointer is 0, the argument will be
* ignored
* @param pid On success, the process id of the new service will be written
* here. If the pointer is 0, the argument will be ignored.
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
* @return an error code indicating success (== 0) or failure (> 0).
*/
static int kdeinitExec( const QString& name, const QStringList &args=QStringList(),
QString *error=0, qint64 *pid = 0, const QByteArray& startup_id = QByteArray() );
static int kdeinitExec( const QString& name, const QStringList &args = QStringList(),
QString *error = 0, const QByteArray &startup_id = QByteArray());
/**
* Starts a program via kdeinit and wait for it to finish.
@ -303,21 +277,19 @@ public:
* @param error On failure, @p error contains a description of the error
* that occurred. If the pointer is 0, the argument will be
* ignored
* @param pid On success, the process id of the new service will be written
* here. If the pointer is 0, the argument will be ignored.
* @param startup_id for app startup notification, "0" for none,
* "" ( empty string ) is the default
* @return an error code indicating success (== 0) or failure (> 0).
*/
static int kdeinitExecWait( const QString& name, const QStringList &args=QStringList(),
QString *error=0, qint64 *pid = 0, const QByteArray& startup_id = QByteArray() );
static int kdeinitExecWait(const QString& name, const QStringList &args = QStringList(),
QString *error = 0, const QByteArray &startup_id = QByteArray());
Q_SIGNALS:
/**
* Hook for KApplication in kdeui
* @internal
*/
void kapplication_hook(QStringList& env , QByteArray& startup_id);
void kapplication_hook(QStringList &env , QByteArray &startup_id);
private:
/**
@ -325,11 +297,11 @@ private:
*/
int startServiceInternal(const char *_function,
const QString& name, const QStringList &URLs,
QString *error, QString *serviceName, qint64 *pid,
const QByteArray& startup_id, bool noWait,
const QString& workdir = QString());
QString *error,
const QByteArray &startup_id, bool noWait,
const QString &workdir = QString());
org::kde::KLauncher *klauncherIface;
QDBusInterface *klauncherIface;
};
#endif

View file

@ -206,7 +206,7 @@ void KToolInvocation::invokeMailer(const QString &to, const QString &cc,
QString error;
// TODO this should check if cmd has a .desktop file, and use data from it, together
// with sending more ASN data
if (kdeinitExec(cmd, cmdTokens, &error, NULL, startup_id ))
if (kdeinitExec(cmd, cmdTokens, &error, startup_id ))
{
KMessage::message(KMessage::Error,
i18n("Could not launch the mail client:\n\n%1", error),
@ -253,7 +253,7 @@ void KToolInvocation::invokeBrowser( const QString &url, const QByteArray& start
if (service) {
kDebug() << "Starting service" << service->entryPath();
if (startServiceByDesktopPath(service->entryPath(), args,
&error, 0, 0, startup_id)) {
&error, startup_id)) {
KMessage::message(KMessage::Error,
// TODO: i18n("Could not launch %1:\n\n%2", exe, error),
i18n("Could not launch the browser:\n\n%1", error),
@ -266,8 +266,7 @@ void KToolInvocation::invokeBrowser( const QString &url, const QByteArray& start
const KService::Ptr htmlApp = KMimeTypeTrader::self()->preferredService(QLatin1String("text/html"));
if (htmlApp) {
QString error;
qint64 pid = 0;
int err = startServiceByDesktopPath(htmlApp->entryPath(), url, &error, 0, &pid, startup_id);
int err = startServiceByDesktopPath(htmlApp->entryPath(), url, &error, startup_id);
if (err != 0) {
KMessage::message(KMessage::Error,
// TODO: i18n("Could not launch %1:\n\n%2", htmlApp->exec(), error),
@ -287,7 +286,7 @@ void KToolInvocation::invokeBrowser( const QString &url, const QByteArray& start
}
kDebug(180) << "Using" << exe << "to open" << url;
if (kdeinitExec(exe, args, &error, NULL, startup_id ))
if (kdeinitExec(exe, args, &error, startup_id ))
{
KMessage::message(KMessage::Error,
// TODO: i18n("Could not launch %1:\n\n%2", exe, error),
@ -325,7 +324,7 @@ void KToolInvocation::invokeTerminal(const QString &command,
QString error;
if (self()->startServiceInternal("kdeinit_exec_with_workdir",
cmd, cmdTokens, &error, 0, NULL, startup_id, false, workdir)) {
cmd, cmdTokens, &error, startup_id, false, workdir)) {
KMessage::message(KMessage::Error,
i18n("Could not launch the terminal client:\n\n%1", error),
i18n("Could not launch Terminal Client"));

View file

@ -1,28 +0,0 @@
/*
* This file was generated by dbusxml2cpp version 0.6
* Command line was: dbusxml2cpp -p klauncher_iface -m ../kinit/org.kde.KLauncher.xml
*
* dbusxml2cpp is Copyright (C) 2006 Trolltech AS. All rights reserved.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "klauncher_iface.h"
/*
* Implementation of interface class OrgKdeKLauncherInterface
*/
OrgKdeKLauncherInterface::OrgKdeKLauncherInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
OrgKdeKLauncherInterface::~OrgKdeKLauncherInterface()
{
}
#include "moc_klauncher_iface.cpp"

View file

@ -1,141 +0,0 @@
/*
* This file was generated by dbusxml2cpp version 0.6
* Command line was: dbusxml2cpp -p klauncher_iface -m ../kinit/org.kde.KLauncher.xml
*
* dbusxml2cpp is Copyright (C) 2006 Trolltech AS. All rights reserved.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
/*
KDE5:
This is a manual copy of an automatically generated file, and the output from dbusxml2cpp
can change between dbusxml2cpp versions. This is currently no binary compatible
with what dbusxml2cpp generates these days, so if something else autogenerates the interface,
there will be crashes on systems with no symbol visibility (happened in ksmserver).
Either dbusxml2cpp should be fixed or this should be removed from kdelibs.
*/
#ifndef KLAUNCHER_IFACE_H_84591156096727
#define KLAUNCHER_IFACE_H_84591156096727
#include <kdecore_export.h>
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QDBusAbstractInterface>
#include <QtDBus/QDBusReply>
/*
* Proxy class for interface org.kde.KLauncher
*/
class KDECORE_EXPORT OrgKdeKLauncherInterface: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.kde.KLauncher"; }
public:
OrgKdeKLauncherInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
~OrgKdeKLauncherInterface();
public Q_SLOTS: // METHODS
inline QDBusReply<void> autoStart()
{
QList<QVariant> argumentList;
return callWithArgumentList(QDBus::Block, QLatin1String("autoStart"), argumentList);
}
inline QDBusReply<void> autoStart(int phase)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(phase);
return callWithArgumentList(QDBus::Block, QLatin1String("autoStart"), argumentList);
}
inline QDBusReply<void> exec_blind(const QString &name, const QStringList &arg_list)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(name) << qVariantFromValue(arg_list);
return callWithArgumentList(QDBus::Block, QLatin1String("exec_blind"), argumentList);
}
inline QDBusReply<int> kdeinit_exec(const QString &app, const QStringList &args, const QStringList &env, const QString &startup_id, QString &dbusServiceName, QString &error, qint64 &pid)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(app) << qVariantFromValue(args) << qVariantFromValue(env) << qVariantFromValue(startup_id);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("kdeinit_exec"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) {
dbusServiceName = qdbus_cast<QString>(reply.arguments().at(1));
error = qdbus_cast<QString>(reply.arguments().at(2));
pid = qdbus_cast<qint64>(reply.arguments().at(3));
}
return reply;
}
inline QDBusReply<int> kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString &startup_id, QString &dbusServiceName, QString &error, qint64 &pid)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(app) << qVariantFromValue(args) << qVariantFromValue(env) << qVariantFromValue(startup_id);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("kdeinit_exec_wait"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) {
dbusServiceName = qdbus_cast<QString>(reply.arguments().at(1));
error = qdbus_cast<QString>(reply.arguments().at(2));
pid = qdbus_cast<qint64>(reply.arguments().at(3));
}
return reply;
}
inline QDBusReply<void> setLaunchEnv(const QString &name, const QString &value)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(name) << qVariantFromValue(value);
return callWithArgumentList(QDBus::Block, QLatin1String("setLaunchEnv"), argumentList);
}
inline QDBusReply<int> start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, QString &dbusServiceName, QString &error, qint64 &pid)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(serviceName) << qVariantFromValue(urls) << qVariantFromValue(envs) << qVariantFromValue(startup_id) << qVariantFromValue(blind);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("start_service_by_desktop_name"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) {
dbusServiceName = qdbus_cast<QString>(reply.arguments().at(1));
error = qdbus_cast<QString>(reply.arguments().at(2));
pid = qdbus_cast<qint64>(reply.arguments().at(3));
}
return reply;
}
inline QDBusReply<int> start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, QString &dbusServiceName, QString &error, qint64 &pid)
{
QList<QVariant> argumentList;
argumentList << qVariantFromValue(serviceName) << qVariantFromValue(urls) << qVariantFromValue(envs) << qVariantFromValue(startup_id) << qVariantFromValue(blind);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QLatin1String("start_service_by_desktop_path"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == 4) {
dbusServiceName = qdbus_cast<QString>(reply.arguments().at(1));
error = qdbus_cast<QString>(reply.arguments().at(2));
pid = qdbus_cast<qint64>(reply.arguments().at(3));
}
return reply;
}
Q_SIGNALS: // SIGNALS
void autoStart0Done();
void autoStart1Done();
void autoStart2Done();
};
namespace org {
namespace kde {
typedef ::OrgKdeKLauncherInterface KLauncher;
}
}
#endif

View file

@ -26,7 +26,7 @@ set(klauncher_SRCS
${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml
)
# The adaptor is manually edited, generate the xml from it.
# Generate the xml from the adaptor.
qt4_generate_dbus_interface(klauncher_adaptor.h org.kde.KLauncher.xml)
add_executable(klauncher4 ${klauncher_SRCS})
@ -40,8 +40,6 @@ kde4_add_dbus_service(org.kde.klauncher.service.in)
install(TARGETS klauncher4 DESTINATION ${KDE4_BIN_INSTALL_DIR})
########### install files ###############
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/org.kde.KLauncher.xml

View file

@ -90,7 +90,7 @@ void KLauncherAdaptor::autoStart(int phase)
);
}
kDebug() << "autostart, phase" << phase;
kDebug() << "autostart phase" << phase;
foreach(const QString &it, m_autostart) {
KAutostart kautostart(it);
if (!kautostart.autostarts(QString::fromLatin1("KDE"), KAutostart::CheckAll)) {
@ -148,16 +148,16 @@ void KLauncherAdaptor::exec_blind(const QString &name, const QStringList &arg_li
QProcess::startDetached(envexe, envargs);
}
int KLauncherAdaptor::kdeinit_exec(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
int KLauncherAdaptor::kdeinit_exec(const QString &app, const QStringList &args, const QStringList &envs, const QString& startup_id)
{
return kdeinit_exec_with_workdir(app, args, QDir::currentPath(), env, startup_id, msg, dbusServiceName, error, pid);
return kdeinit_exec_with_workdir(app, args, envs, startup_id, QDir::currentPath());
}
int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id)
{
int result = kdeinit_exec(app, args, env, startup_id, msg, dbusServiceName, error, pid);
QMutexLocker locker(&m_mutex);
qint64 pid = 0;
int result = startProgram(app, args, envs, startup_id, QDir::currentPath(), pid);
if (result != KLauncherAdaptor::NoError) {
return result;
}
@ -171,61 +171,11 @@ int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &a
return result;
}
int KLauncherAdaptor::kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QString& workdir, const QStringList &env, const QString& startup_id,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
int KLauncherAdaptor::kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir)
{
const QString appexe = findExe(app);
if (appexe.isEmpty()) {
error = i18n("Could not find: %1", app);
return KLauncherAdaptor::FindError;
}
QProcess* process = new QProcess(this);
connect(process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStateChanged(QProcess::ProcessState)));
connect(process, SIGNAL(finished(int)), this, SLOT(slotProcessFinished(int)));
m_processes.append(process);
QProcessEnvironment processenv = m_environment;
foreach (const QString &it, env) {
const int equalindex = it.indexOf(QLatin1Char('='));
if (equalindex <= 0) {
kWarning() << "invalid environment variable" << it;
continue;
}
const QString environmentvar = it.mid(0, equalindex);
const QString environmentvalue = it.mid(equalindex + 1, it.size() - equalindex - 1);
kDebug() << "adding to environment" << environmentvar << environmentvalue;
processenv.insert(environmentvar, environmentvalue);
}
process->setProcessEnvironment(processenv);
process->setWorkingDirectory(workdir);
kDebug() << "starting" << appexe << args << env;
// either start_service_by_desktop_path() or this method send ASN
if (!startup_id.isEmpty()) {
Q_ASSERT(m_kstartupinfoid.none() == true);
m_kstartupinfoid = KStartupInfoId();
m_kstartupinfodata = KStartupInfoData();
m_kstartupinfoid.initId(startup_id.toLatin1());
m_kstartupinfodata.setBin(QFileInfo(appexe).fileName());
m_kstartupinfodata.setDescription(i18n("Launching %1", m_kstartupinfodata.bin()));
sendSIStart();
}
process->start(appexe, args);
while (process->state() == QProcess::Starting) {
QApplication::processEvents(QEventLoop::AllEvents, s_eventstime);
QThread::msleep(s_sleeptime);
}
if (process->error() == QProcess::FailedToStart || process->error() == QProcess::Crashed) {
sendSIFinish();
error = i18n("Could not start: %1", appexe);
return KLauncherAdaptor::ExecError;
}
if (!startup_id.isEmpty()) {
sendSIFinish();
}
error.clear();
pid = process->pid();
return KLauncherAdaptor::NoError;
QMutexLocker locker(&m_mutex);
qint64 pid = 0;
return startProgram(app, args, envs, startup_id, workdir, pid);
}
void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value)
@ -238,33 +188,32 @@ void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value)
m_environment.insert(name, value);
}
int KLauncherAdaptor::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
int KLauncherAdaptor::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind)
{
KService::Ptr kservice = KService::serviceByDesktopName(serviceName);
if (!kservice) {
error = i18n("Invalid service name: %1", serviceName);
kWarning() << "invalid service name" << serviceName;
return KLauncherAdaptor::ServiceError;
}
return start_service_by_desktop_path(kservice->entryPath(), urls, envs, startup_id, blind, msg, dbusServiceName, error, pid);
return start_service_by_desktop_path(kservice->entryPath(), urls, envs, startup_id, blind);
}
int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind,
const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid)
int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind)
{
QMutexLocker locker(&m_mutex);
KService::Ptr kservice = KService::serviceByStorageId(serviceName);
if (!kservice) {
error = i18n("Invalid service path: %1", serviceName);
kWarning() << "invalid service path" << serviceName;
return KLauncherAdaptor::ServiceError;
}
const KService::DBusStartupType dbusstartuptype = kservice->dbusStartupType();
dbusServiceName = kservice->property(QString::fromLatin1("X-DBUS-ServiceName"), QVariant::String).toString();
QString dbusServiceName = kservice->property(QString::fromLatin1("X-DBUS-ServiceName"), QVariant::String).toString();
// any unique Katana application/service checks if another instance is running, if it is
// already running starting it may raise its window instead (if it uses KUniqueApplication)
if (dbusstartuptype == KService::DBusUnique && !dbusServiceName.startsWith(QLatin1String("org.kde."))) {
QDBusReply<bool> sessionreply = m_dbusconnectioninterface->isServiceRegistered(dbusServiceName);
if (!sessionreply.isValid()) {
error = i18n("Invalid D-Bus reply for: %1", dbusServiceName);
kWarning() << "invalid D-Bus reply for" << dbusServiceName;
return KLauncherAdaptor::DBusError;
}
if (sessionreply.value() == true) {
@ -274,12 +223,12 @@ int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName,
}
if (urls.size() > 1 && !kservice->allowMultipleFiles()) {
// TODO: start multiple instances for each URL
error = i18n("Service does not support multiple files: %1", serviceName);
kWarning() << "service does not support multiple files" << serviceName;
return KLauncherAdaptor::ServiceError;
}
QStringList programandargs = KRun::processDesktopExec(*kservice, urls);
if (programandargs.isEmpty()) {
error = i18n("Could not process service: %1", kservice->entryPath());
kWarning() << "could not process service" << kservice->entryPath();
return KLauncherAdaptor::ArgumentsError;
}
kDebug() << "starting" << kservice->entryPath() << urls << blind << dbusServiceName;
@ -302,7 +251,8 @@ int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName,
} else {
kDebug() << "no ASN for" << kservice->entryPath();
}
int result = kdeinit_exec(program, programargs, envs, QString(), msg, dbusServiceName, error, pid);
qint64 pid = 0;
int result = startProgram(program, programargs, envs, QString(), QDir::currentPath(), pid);
if (result != KLauncherAdaptor::NoError) {
// sendSIFinish() is called on exec error
return result;
@ -328,7 +278,6 @@ int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName,
if (!sessionreply.isValid()) {
kWarning() << "invalid D-Bus reply for" << dbusServiceName;
sendSIFinish();
error = i18n("Invalid D-Bus reply for: %1", dbusServiceName);
return KLauncherAdaptor::DBusError;
}
// the service unregistered
@ -398,6 +347,60 @@ QString KLauncherAdaptor::findExe(const QString &app) const
return KStandardDirs::findExe(app, environmentpath);
}
int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir, qint64 &pid)
{
const QString appexe = findExe(app);
if (appexe.isEmpty()) {
kWarning() << "could not find" << app;
return KLauncherAdaptor::FindError;
}
QProcess* process = new QProcess(this);
connect(process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStateChanged(QProcess::ProcessState)));
connect(process, SIGNAL(finished(int)), this, SLOT(slotProcessFinished(int)));
m_processes.append(process);
QProcessEnvironment processenv = m_environment;
foreach (const QString &env, envs) {
const int equalindex = env.indexOf(QLatin1Char('='));
if (equalindex <= 0) {
kWarning() << "invalid environment variable" << env;
continue;
}
const QString environmentvar = env.mid(0, equalindex);
const QString environmentvalue = env.mid(equalindex + 1, env.size() - equalindex - 1);
kDebug() << "adding to environment" << environmentvar << environmentvalue;
processenv.insert(environmentvar, environmentvalue);
}
process->setProcessEnvironment(processenv);
process->setWorkingDirectory(workdir);
kDebug() << "starting" << appexe << args << envs;
if (!startup_id.isEmpty()) {
Q_ASSERT(m_kstartupinfoid.none() == true);
m_kstartupinfoid = KStartupInfoId();
m_kstartupinfodata = KStartupInfoData();
m_kstartupinfoid.initId(startup_id.toLatin1());
m_kstartupinfodata.setBin(QFileInfo(appexe).fileName());
m_kstartupinfodata.setDescription(i18n("Launching %1", m_kstartupinfodata.bin()));
sendSIStart();
}
process->start(appexe, args);
while (process->state() == QProcess::Starting) {
QApplication::processEvents(QEventLoop::AllEvents, s_eventstime);
QThread::msleep(s_sleeptime);
}
if (process->error() == QProcess::FailedToStart || process->error() == QProcess::Crashed) {
sendSIFinish();
kWarning() << "could not start" << appexe;
return KLauncherAdaptor::ExecError;
}
if (!startup_id.isEmpty()) {
sendSIFinish();
}
pid = process->pid();
return KLauncherAdaptor::NoError;
}
void KLauncherAdaptor::sendSIStart() const
{
if (m_kstartupinfoid.none()) {

View file

@ -25,6 +25,7 @@
#include <QDBusMessage>
#include <QDBusConnectionInterface>
#include <QProcess>
#include <QMutex>
// #define KLAUNCHER_DEBUG
@ -36,11 +37,11 @@ class KLauncherAdaptor: public QDBusAbstractAdaptor
public:
enum KLauncherError {
NoError = 0,
ServiceError = 1,
FindError = 2,
ArgumentsError = 3,
ExecError = 4,
DBusError = 5
ServiceError = -1,
FindError = -2,
ArgumentsError = -3,
ExecError = -4,
DBusError = -5
};
KLauncherAdaptor(QObject *parent);
@ -56,11 +57,11 @@ public Q_SLOTS:
// used by KToolInvocation
void setLaunchEnv(const QString &name, const QString &value);
int kdeinit_exec(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QString& workdir, const QStringList &env, const QString& startup_id, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg, QString &dbusServiceName, QString &error, qint64 &pid);
int kdeinit_exec(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id);
int kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id);
int kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir);
int start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind);
int start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind);
// for debugging
#ifdef KLAUNCHER_DEBUG
@ -78,10 +79,12 @@ private Q_SLOTS:
private:
QString findExe(const QString &app) const;
int startProgram(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir, qint64 &pid);
void sendSIStart() const;
void sendSIChange();
void sendSIFinish();
QMutex m_mutex;
QProcessEnvironment m_environment;
QDBusConnectionInterface* m_dbusconnectioninterface;
KStartupInfoId m_kstartupinfoid;

View file

@ -944,7 +944,6 @@ bool KRun::run(const KService& _service, const KUrl::List& _urls, QWidget* windo
const KUrl::List urls = resolveURLs(_urls, _service);
QString error;
qint64 pid = 0;
QByteArray myasn = asn;
// startServiceByDesktopPath() doesn't take QWidget*, add it to the startup info now
@ -962,8 +961,8 @@ bool KRun::run(const KService& _service, const KUrl::List& _urls, QWidget* windo
}
int i = KToolInvocation::startServiceByDesktopPath(
_service.entryPath(), urls.toStringList(), &error, 0L, &pid, myasn
);
_service.entryPath(), urls.toStringList(), &error, myasn
);
if (i != 0) {
kDebug(7010) << error;