diff --git a/src/common/dbus/org.kde.ActivityManager.Application.xml b/src/common/dbus/org.kde.ActivityManager.Application.xml new file mode 100644 index 00000000..fc4a36b5 --- /dev/null +++ b/src/common/dbus/org.kde.ActivityManager.Application.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/lib/core/CMakeLists.txt b/src/lib/core/CMakeLists.txt index f7636a85..356b7c98 100644 --- a/src/lib/core/CMakeLists.txt +++ b/src/lib/core/CMakeLists.txt @@ -1,150 +1,157 @@ # vim:set softtabstop=3 shiftwidth=3 tabstop=3 expandtab: # ======================================================= # Now that we finished with the boilerplate, start # with the library definition set ( KActivities_LIB_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Activities.cpp consumer.cpp controller.cpp info.cpp resourceinstance.cpp mainthreadexecutor_p.cpp manager_p.cpp activitiescache_p.cpp debug_p.cpp ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/utils/dbusfuture_p.cpp version.cpp ) set_source_files_properties ( ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Activities.xml PROPERTIES INCLUDE ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Activities.h ) qt5_add_dbus_interface ( KActivities_LIB_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Activities.xml activities_interface ) qt5_add_dbus_interface ( KActivities_LIB_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Resources.xml resources_interface ) qt5_add_dbus_interface ( KActivities_LIB_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Features.xml features_interface ) qt5_add_dbus_interface ( KActivities_LIB_SRCS ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.ResourcesLinking.xml resources_linking_interface ) +qt5_add_dbus_interface ( + KActivities_LIB_SRCS + + ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src/common/dbus/org.kde.ActivityManager.Application.xml + application_interface + ) + add_library ( KF5Activities SHARED ${KActivities_LIB_SRCS} ) add_library (KF5::Activities ALIAS KF5Activities) include_directories ( ${KACTIVITIES_CURRENT_ROOT_SOURCE_DIR}/src ${KDBusAddons_INCLUDE_DIR} ${Boost_INCLUDE_DIR} ) set_target_properties ( KF5Activities PROPERTIES VERSION ${KACTIVITIES_VERSION_STRING} SOVERSION ${KACTIVITIES_SOVERSION} EXPORT_NAME Activities ) target_link_libraries ( KF5Activities PUBLIC Qt5::Core PRIVATE Qt5::DBus KF5::DBusAddons ) target_include_directories ( KF5Activities INTERFACE "$" ) # install generate_export_header (KF5Activities BASE_NAME KActivities) ecm_generate_headers ( KActivities_CamelCase_HEADERS HEADER_NAMES Consumer Controller Info ResourceInstance Version PREFIX KActivities REQUIRED_HEADERS KActivities_HEADERS ) install ( FILES ${KActivities_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KActivities/KActivities COMPONENT Devel ) install ( FILES ${KActivities_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kactivities_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KActivities/kactivities COMPONENT Devel ) install ( TARGETS KF5Activities EXPORT KF5ActivitiesLibraryTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} ) if (NOT WIN32) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/libKActivities.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libKActivities.pc ) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/libKActivities.pc DESTINATION ${KDE_INSTALL_LIBDIR}/pkgconfig ) endif () include (ECMGeneratePriFile) ecm_generate_pri_file ( BASE_NAME KActivities LIB_NAME KF5Activities DEPS "KDBusAddons" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KActivities ) install ( FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR} ) diff --git a/src/lib/core/manager_p.cpp b/src/lib/core/manager_p.cpp index 8ee766f1..e0276973 100644 --- a/src/lib/core/manager_p.cpp +++ b/src/lib/core/manager_p.cpp @@ -1,183 +1,179 @@ /* * Copyright (C) 2010, 2011, 2012, 2013, 2014 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 Lesser General Public License for more details * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "manager_p.h" #include #include #include #include #include #include "debug_p.h" #include "mainthreadexecutor_p.h" #include "common/dbus/common.h" #include "utils/dbusfuture_p.h" #include "utils/continue_with.h" #include "version.h" namespace KActivities { Manager *Manager::s_instance = Q_NULLPTR; Manager::Manager() : QObject() , m_watcher(KAMD_DBUS_SERVICE, QDBusConnection::sessionBus()) + , m_service(new KAMD_DBUS_CLASS_INTERFACE(Application, Application, this)) , m_activities(new KAMD_DBUS_CLASS_INTERFACE(Activities, Activities, this)) , m_resources(new KAMD_DBUS_CLASS_INTERFACE(Resources, Resources, this)) , m_resourcesLinking(new KAMD_DBUS_CLASS_INTERFACE(Resources/Linking, ResourcesLinking, this)) , m_features(new KAMD_DBUS_CLASS_INTERFACE(Features, Features, this)) , m_serviceRunning(false) { connect(&m_watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &Manager::serviceOwnerChanged); if (isServiceRunning()) { serviceOwnerChanged(KAMD_DBUS_SERVICE, QString(), KAMD_DBUS_SERVICE); } } Manager *Manager::self() { static std::mutex singleton; std::lock_guard singleton_lock(singleton); if (!s_instance) { runInMainThread([] () { // check if the activity manager is already running if (!Manager::isServiceRunning()) { #if defined(QT_DEBUG) QLoggingCategory::setFilterRules(QStringLiteral("org.kde.kactivities.lib.core.debug=true")); qCDebug(KAMD_CORELIB) << "Should we start the daemon?"; if (!QCoreApplication::instance() ->property("org.kde.KActivities.core.disableAutostart") .toBool()) { qCDebug(KAMD_CORELIB) << "Starting the activity manager daemon"; QProcess::startDetached(QStringLiteral("kactivitymanagerd")); } #else QProcess::startDetached(QStringLiteral("kactivitymanagerd")); #endif } // creating a new instance of the class Manager::s_instance = new Manager(); }); } return s_instance; } bool Manager::isServiceRunning() { return (s_instance ? s_instance->m_serviceRunning : true) && QDBusConnection::sessionBus().interface()->isServiceRegistered(KAMD_DBUS_SERVICE); } void Manager::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner) { Q_UNUSED(oldOwner); if (serviceName == KAMD_DBUS_SERVICE) { m_serviceRunning = !newOwner.isEmpty(); emit serviceStatusChanged(m_serviceRunning); if (m_serviceRunning) { - QDBusInterface service(KAMD_DBUS_SERVICE, - "/ActivityManager", - "org.kde.ActivityManager.Application", - QDBusConnection::sessionBus(), - Q_NULLPTR); - using namespace kamd::utils; + continue_with( - DBusFuture::asyncCall(&service, "serviceVersion"), + DBusFuture::fromReply(m_service->serviceVersion()), [this] (const optional_view &serviceVersion) { // Test whether the service is older than the library. // If it is, we need to end this if (!serviceVersion.is_initialized()) { qWarning() << "KActivities: FATAL ERROR: Failed to contact the activity manager daemon"; m_serviceRunning = false; return; } auto split = serviceVersion->split('.'); QList version; const int requiredVersion[] = { KACTIVITIES_VERSION_MAJOR, KACTIVITIES_VERSION_MINOR, KACTIVITIES_VERSION_RELEASE }; std::transform( split.cbegin(), split.cend(), std::back_inserter(version), [] (const QString &component) { return component.toInt(); }); // if required version is greater than the current version if (std::lexicographical_compare( version.cbegin(), version.cend(), std::begin(requiredVersion), std::end(requiredVersion) )) { QString libraryVersion = QString::number(requiredVersion[0]) + '.' + QString::number(requiredVersion[1]) + '.' + QString::number(requiredVersion[2]); qDebug() << "KActivities service version: " << serviceVersion.get(); qDebug() << "KActivities library version: " << libraryVersion; qFatal("KActivities: FATAL ERROR: The service is older than the library"); } }); } } } Service::Activities *Manager::activities() { return self()->m_activities; } Service::Resources *Manager::resources() { return self()->m_resources; } Service::ResourcesLinking *Manager::resourcesLinking() { return self()->m_resourcesLinking; } Service::Features *Manager::features() { return self()->m_features; } } // namespace KActivities diff --git a/src/lib/core/manager_p.h b/src/lib/core/manager_p.h index 6579e286..73170be1 100644 --- a/src/lib/core/manager_p.h +++ b/src/lib/core/manager_p.h @@ -1,74 +1,76 @@ /* * Copyright (C) 2010, 2011, 2012, 2013, 2014 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 Lesser General Public License for more details * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef ACTIVITIES_MANAGER_P #define ACTIVITIES_MANAGER_P #include +#include "application_interface.h" #include "activities_interface.h" #include "resources_interface.h" #include "resources_linking_interface.h" #include "features_interface.h" #include namespace Service = org::kde::ActivityManager; namespace KActivities { class Manager : public QObject { Q_OBJECT public: static Manager *self(); static bool isServiceRunning(); static Service::Activities *activities(); static Service::Resources *resources(); static Service::ResourcesLinking *resourcesLinking(); static Service::Features *features(); public Q_SLOTS: void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner); Q_SIGNALS: void serviceStatusChanged(bool status); private: Manager(); QDBusServiceWatcher m_watcher; static Manager *s_instance; + Service::Application *const m_service; Service::Activities *const m_activities; Service::Resources *const m_resources; Service::ResourcesLinking *const m_resourcesLinking; Service::Features *const m_features; bool m_serviceRunning; friend class ManagerInstantiator; }; } // namespace KActivities #endif // ACTIVITIES_MANAGER_P diff --git a/src/service/Application.h b/src/service/Application.h index c63a96ef..43961470 100644 --- a/src/service/Application.h +++ b/src/service/Application.h @@ -1,70 +1,71 @@ /* * Copyright (C) 2012 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef APPLICATION_H #define APPLICATION_H // Qt #include // Utils #include class Resources; class Activities; class Features; /** * Main application object * This can *not* be a QGuiApplication because * we need KWindowSystem widgets. */ class Application : public QApplication { Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.ActivityManager.Application") public: Application(int &argc, char **argv); virtual ~Application(); virtual int newInstance(); // static Application * self(); // static void quit(); Resources &resources() const; Activities &activities() const; Features &features() const; public Q_SLOTS: void quit(); QString serviceVersion() const; bool loadPlugin(const QString &plugin); private Q_SLOTS: void init(); void loadPlugins(); private: D_PTR; friend int main(int, char**); }; #endif // APPLICATION_H diff --git a/src/utils/dbusfuture_p.h b/src/utils/dbusfuture_p.h index 56d75670..e9dcf8b5 100644 --- a/src/utils/dbusfuture_p.h +++ b/src/utils/dbusfuture_p.h @@ -1,165 +1,176 @@ /* * Copyright (C) 2013 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * This program 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 General Public License for more details * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef ACTIVITIES_DBUSFUTURE_P_H #define ACTIVITIES_DBUSFUTURE_P_H #include #include #include #include #include #include #include #include "debug_p.h" namespace DBusFuture { namespace detail { //_ template class DBusCallFutureInterface : public QObject, public QFutureInterface<_Result> { public: DBusCallFutureInterface(QDBusPendingReply<_Result> reply) : reply(reply), replyWatcher(Q_NULLPTR) { } ~DBusCallFutureInterface() { delete replyWatcher; } void callFinished(); QFuture<_Result> start() { replyWatcher = new QDBusPendingCallWatcher(reply); QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, [this] () { callFinished(); }); this->reportStarted(); if (reply.isFinished()) { this->callFinished(); } return this->future(); } private: QDBusPendingReply<_Result> reply; QDBusPendingCallWatcher * replyWatcher; }; template void DBusCallFutureInterface<_Result>::callFinished() { deleteLater(); if (!reply.isError()) { this->reportResult(reply.value()); } this->reportFinished(); } template <> void DBusCallFutureInterface::callFinished(); template class ValueFutureInterface : public QObject, QFutureInterface<_Result> { public: ValueFutureInterface(const _Result & value) : value(value) { } QFuture<_Result> start() { auto future = this->future(); this->reportResult(value); this->reportFinished(); deleteLater(); return future; } private: _Result value; }; template <> class ValueFutureInterface : public QObject, QFutureInterface { public: ValueFutureInterface(); QFuture start(); // { // auto future = this->future(); // this->reportFinished(); // deleteLater(); // return future; // } }; } //^ namespace detail template QFuture<_Result> asyncCall(QDBusAbstractInterface *interface, const QString &method, const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant()) { using namespace detail; auto callFutureInterface = new DBusCallFutureInterface <_Result>(interface->asyncCall(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); return callFutureInterface->start(); } template QFuture<_Result> fromValue(const _Result & value) { using namespace detail; auto valueFutureInterface = new ValueFutureInterface<_Result>(value); return valueFutureInterface->start(); } +template +QFuture<_Result> +fromReply(const QDBusPendingReply<_Result> &reply) +{ + using namespace detail; + + auto callFutureInterface = new DBusCallFutureInterface<_Result>(reply); + + return callFutureInterface->start(); +} + QFuture fromVoid(); } // namespace DBusFuture #endif /* DBUSFUTURE_P_H */