KIO

dbusactivationrunner.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2020-2021 David Redondo <kde@david-redondo.de>
4
5 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#include "dbusactivationrunner_p.h"
9
10#include "kiogui_debug.h"
11#include <KWindowSystem>
12
13#include <QDBusConnection>
14#include <QDBusConnectionInterface>
15#include <QDBusMessage>
16#include <QDBusPendingCallWatcher>
17#include <QTimer>
18
19bool DBusActivationRunner::activationPossible(const KService::Ptr service, KIO::ApplicationLauncherJob::RunFlags flags, const QString &suggestedFileName)
20{
21 if (!service->isApplication()) {
22 return false;
23 }
24 if (service->property<bool>(QStringLiteral("DBusActivatable"))) {
25 if (service->desktopEntryName().count(QLatin1Char('.')) < 2) {
26 qCWarning(KIO_GUI) << "Cannot activate" << service->desktopEntryName() << "doesn't have enough '.' for a well-formed service name";
27 return false;
28 }
29 if (!suggestedFileName.isEmpty()) {
30 qCDebug(KIO_GUI) << "Cannot activate" << service->desktopEntryName() << "because suggestedFileName is set";
31 return false;
32 }
34 qCDebug(KIO_GUI) << "Cannot activate" << service->desktopEntryName() << "because DeleteTemporaryFiles is set";
35 return false;
36 }
37 return true;
38 }
39 return false;
40}
41
42DBusActivationRunner::DBusActivationRunner(const QString &action)
43 : KProcessRunner()
44 , m_actionName(action)
45{
46}
47
48void DBusActivationRunner::startProcess()
49{
50 // DBusActivatable as per https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
51 const QString objectPath = QStringLiteral("/%1").arg(m_desktopName).replace(QLatin1Char('.'), QLatin1Char('/')).replace(QLatin1Char('-'), QLatin1Char('_'));
52 const QString interface = QStringLiteral("org.freedesktop.Application");
53 QDBusMessage message;
54 if (m_urls.isEmpty()) {
55 if (m_actionName.isEmpty()) {
56 message = QDBusMessage::createMethodCall(m_desktopName, objectPath, interface, QStringLiteral("Activate"));
57 } else {
58 message = QDBusMessage::createMethodCall(m_desktopName, objectPath, interface, QStringLiteral("ActivateAction"));
59 message << m_actionName << QVariantList();
60 }
61 } else {
62 message = QDBusMessage::createMethodCall(m_desktopName, objectPath, interface, QStringLiteral("Open"));
63 message << QUrl::toStringList(m_urls);
64 }
66#if HAVE_X11
67 message << QVariantMap{{QStringLiteral("desktop-startup-id"), m_startupId.id()}};
68#endif
70 message << QVariantMap{{QStringLiteral("activation-token"), m_process->processEnvironment().value(QStringLiteral("XDG_ACTIVATION_TOKEN"))}};
71 }
72 auto call = QDBusConnection::sessionBus().asyncCall(message);
73 auto activationWatcher = new QDBusPendingCallWatcher(call, this);
74 connect(activationWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
75 watcher->deleteLater();
76 if (watcher->isError()) {
77 Q_EMIT error(watcher->error().message());
78 terminateStartupNotification();
79 m_finished = true;
80 deleteLater();
81 return;
82 }
83 auto call = QDBusConnection::sessionBus().interface()->asyncCall(QStringLiteral("GetConnectionUnixProcessID"), m_desktopName);
84 auto pidWatcher = new QDBusPendingCallWatcher(call, this);
85 connect(pidWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) {
86 m_finished = true;
87 QDBusPendingReply<uint> reply = *watcher;
88 if (reply.isError()) {
89 Q_EMIT error(watcher->error().message());
90 terminateStartupNotification();
91 } else {
92 Q_EMIT processStarted(reply.value());
93 }
94 deleteLater();
95 });
96 });
97}
98
99bool DBusActivationRunner::waitForStarted(int timeout)
100{
101 if (m_finished) {
102 return m_pid != 0;
103 }
104
105 QEventLoop loop;
106 bool success = false;
107 connect(this, &KProcessRunner::processStarted, [&loop, &success]() {
108 loop.quit();
109 success = true;
110 });
111 connect(this, &KProcessRunner::error, &loop, &QEventLoop::quit);
112 QTimer::singleShot(timeout, &loop, &QEventLoop::quit);
113 loop.exec();
114 return success;
115}
116
117#include "moc_dbusactivationrunner_p.cpp"
@ DeleteTemporaryFiles
the URLs passed to the service will be deleted when it exits (if the URLs are local files)
QString desktopEntryName() const
T property(const QString &name) const
bool isApplication() const
static bool isPlatformX11()
static bool isPlatformWayland()
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QDBusPendingCall asyncCall(const QString &method, Args &&... args)
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout) const const
QDBusConnectionInterface * interface() const const
QDBusConnection sessionBus()
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
void finished(QDBusPendingCallWatcher *self)
bool isError() const const
typename Select< 0 >::Type value() const const
int exec(ProcessEventsFlags flags)
void quit()
void deleteLater()
qsizetype count() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QStringList toStringList(const QList< QUrl > &urls, FormattingOptions options)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:58:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.