File indexing completed on 2024-05-05 12:18:41
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2020-2021 David Redondo <kde@david-redondo.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "dbusactivationrunner_p.h" 0009 0010 #include "kiogui_debug.h" 0011 #include <KWindowSystem> 0012 0013 #ifndef Q_OS_ANDROID 0014 #include <QDBusConnection> 0015 #include <QDBusConnectionInterface> 0016 #include <QDBusMessage> 0017 #include <QDBusPendingCallWatcher> 0018 #endif 0019 #include <QTimer> 0020 0021 bool DBusActivationRunner::activationPossible(const KService::Ptr service, KIO::ApplicationLauncherJob::RunFlags flags, const QString &suggestedFileName) 0022 { 0023 #if defined Q_OS_UNIX && !defined Q_OS_ANDROID 0024 if (!service->isApplication()) { 0025 return false; 0026 } 0027 if (service->property(QStringLiteral("DBusActivatable"), QMetaType::Bool).toBool()) { 0028 if (service->menuId().count(QLatin1Char('.')) < 3) { 0029 qCWarning(KIO_GUI) << "Cannot activate" << service->menuId() << "doesn't have enough '.' for a well-formed service name"; 0030 return false; 0031 } 0032 if (!suggestedFileName.isEmpty()) { 0033 qCDebug(KIO_GUI) << "Cannot activate" << service->desktopEntryName() << "because suggestedFileName is set"; 0034 return false; 0035 } 0036 if (flags & KIO::ApplicationLauncherJob::DeleteTemporaryFiles) { 0037 qCDebug(KIO_GUI) << "Cannot activate" << service->desktopEntryName() << "because DeleteTemporaryFiles is set"; 0038 return false; 0039 } 0040 return true; 0041 } 0042 #endif 0043 return false; 0044 } 0045 0046 DBusActivationRunner::DBusActivationRunner(const QString &action) 0047 : KProcessRunner() 0048 , m_actionName(action) 0049 { 0050 } 0051 0052 void DBusActivationRunner::startProcess() 0053 { 0054 #ifndef Q_OS_ANDROID 0055 // DBusActivatable as per https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus 0056 const QString objectPath = QStringLiteral("/%1").arg(m_desktopName).replace(QLatin1Char('.'), QLatin1Char('/')).replace(QLatin1Char('-'), QLatin1Char('_')); 0057 const QString interface = QStringLiteral("org.freedesktop.Application"); 0058 QDBusMessage message; 0059 if (m_urls.isEmpty()) { 0060 if (m_actionName.isEmpty()) { 0061 message = QDBusMessage::createMethodCall(m_desktopName, objectPath, interface, QStringLiteral("Activate")); 0062 } else { 0063 message = QDBusMessage::createMethodCall(m_desktopName, objectPath, interface, QStringLiteral("ActivateAction")); 0064 message << m_actionName << QVariantList(); 0065 } 0066 } else { 0067 message = QDBusMessage::createMethodCall(m_desktopName, objectPath, interface, QStringLiteral("Open")); 0068 message << QUrl::toStringList(m_urls); 0069 } 0070 if (KWindowSystem::isPlatformX11()) { 0071 message << QVariantMap{{QStringLiteral("desktop-startup-id"), m_startupId.id()}}; 0072 } else if (KWindowSystem::isPlatformWayland()) { 0073 message << QVariantMap{{QStringLiteral("activation-token"), m_process->processEnvironment().value(QStringLiteral("XDG_ACTIVATION_TOKEN"))}}; 0074 } 0075 auto call = QDBusConnection::sessionBus().asyncCall(message); 0076 auto activationWatcher = new QDBusPendingCallWatcher(call, this); 0077 connect(activationWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0078 watcher->deleteLater(); 0079 if (watcher->isError()) { 0080 Q_EMIT error(watcher->error().message()); 0081 terminateStartupNotification(); 0082 m_finished = true; 0083 deleteLater(); 0084 return; 0085 } 0086 auto call = QDBusConnection::sessionBus().interface()->asyncCall(QStringLiteral("GetConnectionUnixProcessID"), m_desktopName); 0087 auto pidWatcher = new QDBusPendingCallWatcher(call, this); 0088 connect(pidWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0089 m_finished = true; 0090 QDBusPendingReply<uint> reply = *watcher; 0091 if (reply.isError()) { 0092 Q_EMIT error(watcher->error().message()); 0093 terminateStartupNotification(); 0094 } else { 0095 Q_EMIT processStarted(reply.value()); 0096 } 0097 deleteLater(); 0098 }); 0099 }); 0100 #endif 0101 } 0102 0103 bool DBusActivationRunner::waitForStarted(int timeout) 0104 { 0105 #ifndef Q_OS_ANDROID 0106 if (m_finished) { 0107 return m_pid != 0; 0108 } 0109 0110 QEventLoop loop; 0111 bool success = false; 0112 connect(this, &KProcessRunner::processStarted, [&loop, &success]() { 0113 loop.quit(); 0114 success = true; 0115 }); 0116 connect(this, &KProcessRunner::error, &loop, &QEventLoop::quit); 0117 QTimer::singleShot(timeout, &loop, &QEventLoop::quit); 0118 loop.exec(); 0119 return success; 0120 #else 0121 return false; 0122 #endif 0123 } 0124 0125 #include "moc_dbusactivationrunner_p.cpp"