File indexing completed on 2024-05-12 05:29:22
0001 /* 0002 * SPDX-FileCopyrightText: 2010-2016 Ivan Cukic <ivan.cukic@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 // Self 0008 #include "Application.h" 0009 #include <kactivities-features.h> 0010 0011 // Qt 0012 #include <QDBusConnection> 0013 #include <QDBusConnectionInterface> 0014 #include <QDBusServiceWatcher> 0015 #include <QThread> 0016 0017 // KDE 0018 #include <KCrash> 0019 #include <KPluginMetaData> 0020 #include <kdbusservice.h> 0021 #include <ksharedconfig.h> 0022 0023 // Boost and utils 0024 #include <boost/range/adaptor/filtered.hpp> 0025 #include <boost/range/adaptor/transformed.hpp> 0026 #include <utils/d_ptr_implementation.h> 0027 0028 // System 0029 #include <functional> 0030 #include <memory> 0031 #include <signal.h> 0032 #include <stdlib.h> 0033 0034 // Local 0035 #include "Activities.h" 0036 #include "Config.h" 0037 #include "DebugApplication.h" 0038 #include "Features.h" 0039 #include "Plugin.h" 0040 #include "Resources.h" 0041 #include "common/dbus/common.h" 0042 0043 namespace 0044 { 0045 QList<QThread *> s_moduleThreads; 0046 } 0047 0048 // Runs a QObject inside a QThread 0049 0050 template<typename T> 0051 T *runInQThread() 0052 { 0053 T *object = new T(); 0054 0055 class Thread : public QThread 0056 { 0057 public: 0058 Thread(T *ptr = nullptr) 0059 : QThread() 0060 , object(ptr) 0061 { 0062 } 0063 0064 void run() override 0065 { 0066 std::unique_ptr<T> o(object); 0067 exec(); 0068 } 0069 0070 private: 0071 T *object; 0072 0073 } *thread = new Thread(object); 0074 0075 s_moduleThreads << thread; 0076 0077 object->moveToThread(thread); 0078 thread->start(); 0079 0080 return object; 0081 } 0082 0083 class Application::Private 0084 { 0085 public: 0086 Private() 0087 { 0088 } 0089 0090 bool loadPlugin(const KPluginMetaData &plugin); 0091 0092 Resources *resources; 0093 Activities *activities; 0094 Features *features; 0095 0096 QStringList pluginIds; 0097 QList<Plugin *> plugins; 0098 0099 static Application *s_instance; 0100 }; 0101 0102 Application *Application::Private::s_instance = nullptr; 0103 0104 Application::Application(int &argc, char **argv) 0105 : QApplication(argc, argv) 0106 { 0107 } 0108 0109 void Application::init() 0110 { 0111 // KAMD is a daemon, if it crashes it is not a problem as 0112 // long as it restarts properly 0113 // TODO: Restart on crash 0114 // KCrash::setFlags(KCrash::AutoRestart); 0115 d->resources = runInQThread<Resources>(); 0116 d->activities = runInQThread<Activities>(); 0117 d->features = runInQThread<Features>(); 0118 /* d->config */ new Config(this); // this does not need a separate thread 0119 0120 QMetaObject::invokeMethod(this, "loadPlugins", Qt::QueuedConnection); 0121 0122 QDBusConnection::sessionBus().registerObject(QStringLiteral("/ActivityManager"), this, QDBusConnection::ExportAllSlots); 0123 0124 if (!QDBusConnection::sessionBus().registerService(KAMD_DBUS_SERVICE)) { 0125 QCoreApplication::exit(EXIT_SUCCESS); 0126 } 0127 } 0128 0129 bool Application::Private::loadPlugin(const KPluginMetaData &plugin) 0130 { 0131 if (!plugin.isValid()) { 0132 qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] plugin offer not valid"; 0133 return false; 0134 } 0135 0136 if (pluginIds.contains(plugin.pluginId())) { 0137 qCDebug(KAMD_LOG_APPLICATION) << "[ OK ] already loaded: " << plugin.pluginId(); 0138 return true; 0139 } 0140 0141 const auto result = KPluginFactory::instantiatePlugin<Plugin>(plugin); 0142 0143 if (!result) { 0144 qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] Could not load plugin:" << plugin.pluginId() << result.errorText; 0145 return false; 0146 } 0147 0148 auto pluginInstance = result.plugin; 0149 0150 auto &modules = Module::get(); 0151 0152 bool success = pluginInstance->init(modules); 0153 0154 if (success) { 0155 pluginIds << plugin.pluginId(); 0156 plugins << pluginInstance; 0157 0158 qCDebug(KAMD_LOG_APPLICATION) << "[ OK ] loaded: " << plugin.pluginId(); 0159 return true; 0160 } else { 0161 qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] init: " << plugin.pluginId(); 0162 // TODO: Show a notification for a plugin that failed to load 0163 delete pluginInstance; 0164 return false; 0165 } 0166 } 0167 0168 void Application::loadPlugins() 0169 { 0170 using namespace std::placeholders; 0171 0172 const auto offers = KPluginMetaData::findPlugins(QStringLiteral(KAMD_PLUGIN_DIR), {}, KPluginMetaData::AllowEmptyMetaData); 0173 qCDebug(KAMD_LOG_APPLICATION) << "Found" << offers.size() << "enabled plugins:"; 0174 0175 for (const auto &offer : offers) { 0176 d->loadPlugin(offer); 0177 } 0178 } 0179 0180 bool Application::loadPlugin(const QString &pluginId) 0181 { 0182 auto offer = KPluginMetaData::findPluginById(QStringLiteral(KAMD_PLUGIN_DIR), pluginId, KPluginMetaData::AllowEmptyMetaData); 0183 if (!offer.isValid()) { 0184 qCWarning(KAMD_LOG_APPLICATION) << "[ FAILED ] not found: " << pluginId; 0185 return false; 0186 } 0187 0188 return d->loadPlugin(offer); 0189 } 0190 0191 Application::~Application() 0192 { 0193 qCDebug(KAMD_LOG_APPLICATION) << "Cleaning up..."; 0194 0195 // Waiting for the threads to finish 0196 for (const auto thread : s_moduleThreads) { 0197 thread->quit(); 0198 thread->wait(); 0199 0200 delete thread; 0201 } 0202 0203 // Deleting plugin objects 0204 for (const auto plugin : d->plugins) { 0205 delete plugin; 0206 } 0207 0208 Private::s_instance = nullptr; 0209 } 0210 0211 int Application::newInstance() 0212 { 0213 // We don't want to show the mainWindow() 0214 return 0; 0215 } 0216 0217 Activities &Application::activities() const 0218 { 0219 return *d->activities; 0220 } 0221 0222 Resources &Application::resources() const 0223 { 0224 return *d->resources; 0225 } 0226 0227 // void Application::quit() 0228 // { 0229 // if (Private::s_instance) { 0230 // Private::s_instance->exit(); 0231 // delete Private::s_instance; 0232 // } 0233 // } 0234 0235 void Application::quit() 0236 { 0237 QApplication::quit(); 0238 } 0239 0240 #include "Version.h" 0241 QString Application::serviceVersion() const 0242 { 0243 return KACTIVITIES_VERSION_STRING; 0244 } 0245 0246 int main(int argc, char **argv) 0247 { 0248 // Disable session management for this process 0249 qunsetenv("SESSION_MANAGER"); 0250 0251 QGuiApplication::setDesktopSettingsAware(false); 0252 0253 Application application(argc, argv); 0254 application.setApplicationName(QStringLiteral("ActivityManager")); 0255 application.setOrganizationDomain(QStringLiteral("kde.org")); 0256 0257 KCrash::initialize(); 0258 0259 application.init(); 0260 0261 return application.exec(); 0262 } 0263 0264 QStringList Application::loadedPlugins() const 0265 { 0266 return d->pluginIds; 0267 } 0268 0269 #include "moc_Application.cpp"