File indexing completed on 2022-11-29 13:02:28

0001 /*
0002     SPDX-FileCopyrightText: 2010-2016 Ivan Cukic <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "manager_p.h"
0008 
0009 #include <mutex>
0010 #include <optional>
0011 
0012 #include <QCoreApplication>
0013 #include <QDBusConnection>
0014 #include <QFutureWatcher>
0015 #include <QFutureWatcherBase>
0016 
0017 #include "debug_p.h"
0018 #include "mainthreadexecutor_p.h"
0019 
0020 #include "common/dbus/common.h"
0021 #include "utils/continue_with.h"
0022 #include "utils/dbusfuture_p.h"
0023 #include "version.h"
0024 
0025 namespace KActivities
0026 {
0027 Manager *Manager::s_instance = nullptr;
0028 
0029 Manager::Manager()
0030     : QObject()
0031     , m_watcher(KAMD_DBUS_SERVICE, QDBusConnection::sessionBus())
0032     , m_service(new KAMD_DBUS_CLASS_INTERFACE("/", Application, this))
0033     , m_activities(new KAMD_DBUS_CLASS_INTERFACE("Activities", Activities, this))
0034     , m_resources(new KAMD_DBUS_CLASS_INTERFACE("Resources", Resources, this))
0035     , m_resourcesLinking(new KAMD_DBUS_CLASS_INTERFACE("Resources/Linking", ResourcesLinking, this))
0036     , m_features(new KAMD_DBUS_CLASS_INTERFACE("Features", Features, this))
0037     , m_serviceRunning(false)
0038 {
0039     connect(&m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &Manager::serviceOwnerChanged);
0040 
0041     if (isServiceRunning()) {
0042         serviceOwnerChanged(KAMD_DBUS_SERVICE, QString(), KAMD_DBUS_SERVICE);
0043     }
0044 }
0045 
0046 Manager *Manager::self()
0047 {
0048     static std::mutex singleton;
0049     std::lock_guard<std::mutex> singleton_lock(singleton);
0050 
0051     if (!s_instance) {
0052         runInMainThread([]() {
0053             // check if the activity manager is already running
0054             if (!Manager::isServiceRunning()) {
0055                 bool disableAutolaunch = QCoreApplication::instance()->property("org.kde.KActivities.core.disableAutostart").toBool();
0056 
0057                 qCDebug(KAMD_CORELIB) << "Should we start the daemon?";
0058                 // start only if not disabled and we have a dbus connection at all
0059                 if (!disableAutolaunch && QDBusConnection::sessionBus().interface()) {
0060                     qCDebug(KAMD_CORELIB) << "Starting the activity manager daemon";
0061                     auto busInterface = QDBusConnection::sessionBus().interface();
0062                     busInterface->asyncCall(QStringLiteral("StartServiceByName"), KAMD_DBUS_SERVICE, uint(0));
0063                 }
0064             }
0065 
0066             // creating a new instance of the class
0067             Manager::s_instance = new Manager();
0068         });
0069     }
0070 
0071     return s_instance;
0072 }
0073 
0074 bool Manager::isServiceRunning()
0075 {
0076     return (s_instance ? s_instance->m_serviceRunning : true) && QDBusConnection::sessionBus().interface()
0077         && QDBusConnection::sessionBus().interface()->isServiceRegistered(KAMD_DBUS_SERVICE);
0078 }
0079 
0080 void Manager::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
0081 {
0082     Q_UNUSED(oldOwner);
0083 
0084     if (serviceName == KAMD_DBUS_SERVICE) {
0085         m_serviceRunning = !newOwner.isEmpty();
0086         Q_EMIT serviceStatusChanged(m_serviceRunning);
0087 
0088         if (m_serviceRunning) {
0089             using namespace kamd::utils;
0090 
0091             continue_with(DBusFuture::fromReply(m_service->serviceVersion()), [this](const std::optional<QString> &serviceVersion) {
0092                 // Test whether the service is older than the library.
0093                 // If it is, we need to end this
0094 
0095                 if (!serviceVersion.has_value()) {
0096                     qWarning() << "KActivities: FATAL ERROR: Failed to contact the activity manager daemon";
0097                     m_serviceRunning = false;
0098                     return;
0099                 }
0100 
0101                 auto split = serviceVersion->split(QLatin1Char('.'));
0102                 QList<int> version;
0103 
0104                 // We require kactivitymanagerd version to be at least the
0105                 // one before the repository split
0106                 const int requiredVersion[] = {6, 2, 0};
0107 
0108                 std::transform(split.cbegin(), split.cend(), std::back_inserter(version), [](const QString &component) {
0109                     return component.toInt();
0110                 });
0111 
0112                 // if required version is greater than the current version
0113                 if (std::lexicographical_compare(version.cbegin(), version.cend(), std::begin(requiredVersion), std::end(requiredVersion))) {
0114                     QString libraryVersion = QString::number(requiredVersion[0]) + QLatin1Char('.') + QString::number(requiredVersion[1]) + QLatin1Char('.')
0115                         + QString::number(requiredVersion[2]);
0116 
0117                     qDebug() << "KActivities service version: " << serviceVersion.value();
0118                     qDebug() << "KActivities library version: " << libraryVersion;
0119                     qFatal("KActivities: FATAL ERROR: The service is older than the library");
0120                 }
0121             });
0122         }
0123     }
0124 }
0125 
0126 Service::Activities *Manager::activities()
0127 {
0128     return self()->m_activities;
0129 }
0130 
0131 Service::Resources *Manager::resources()
0132 {
0133     return self()->m_resources;
0134 }
0135 
0136 Service::ResourcesLinking *Manager::resourcesLinking()
0137 {
0138     return self()->m_resourcesLinking;
0139 }
0140 
0141 Service::Features *Manager::features()
0142 {
0143     return self()->m_features;
0144 }
0145 
0146 } // namespace KActivities