File indexing completed on 2024-06-23 05:07:15

0001 /*
0002     SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include <QCommandLineParser>
0010 #include <QDBusConnection>
0011 #include <QDBusError>
0012 #include <QLoggingCategory>
0013 #include <QObject>
0014 
0015 #include <memory>
0016 
0017 class QCoreApplication;
0018 class QApplication;
0019 class QGuiApplication;
0020 
0021 /**
0022  * D-Bus session bus monitoring and command line handling.
0023  */
0024 class AkApplicationBase : public QObject
0025 {
0026     Q_OBJECT
0027 public:
0028     ~AkApplicationBase() override;
0029     void parseCommandLine();
0030     void setDescription(const QString &desc);
0031 
0032     void addCommandLineOptions(const QCommandLineOption &option);
0033     void addPositionalCommandLineOption(const QString &name, const QString &description = QString(), const QString &syntax = QString());
0034     const QCommandLineParser &commandLineArguments() const
0035     {
0036         return mCmdLineParser;
0037     }
0038 
0039     void printUsage() const;
0040 
0041     /** Returns the AkApplication instance */
0042     static AkApplicationBase *instance();
0043 
0044     /** Forward to Q[Core]Application for convenience. */
0045     int exec();
0046 
0047 protected:
0048     AkApplicationBase(std::unique_ptr<QCoreApplication> app, const QLoggingCategory &loggingCategory);
0049     void init();
0050 
0051     std::unique_ptr<QCoreApplication> mApp;
0052 
0053 private Q_SLOTS:
0054     void pollSessionBus() const;
0055 
0056 private:
0057     QString mInstanceId;
0058     const QLoggingCategory &mLoggingCategory;
0059     static AkApplicationBase *sInstance;
0060 
0061     QCommandLineParser mCmdLineParser;
0062 };
0063 
0064 template<typename T>
0065 class AkApplicationImpl : public AkApplicationBase
0066 {
0067 public:
0068     AkApplicationImpl(int &argc, char **argv, const QLoggingCategory &loggingCategory = *QLoggingCategory::defaultCategory())
0069         : AkApplicationBase(std::make_unique<T>(argc, argv), loggingCategory)
0070     {
0071         init();
0072     }
0073 };
0074 
0075 template<typename T>
0076 class AkUniqueApplicationImpl : public AkApplicationBase
0077 {
0078 public:
0079     AkUniqueApplicationImpl(int &argc, char **argv, const QString &serviceName, const QLoggingCategory &loggingCategory = *QLoggingCategory::defaultCategory())
0080         : AkApplicationBase(std::make_unique<T>(argc, argv), loggingCategory)
0081     {
0082         registerUniqueServiceOrTerminate(serviceName, loggingCategory);
0083         init();
0084     }
0085 
0086 private:
0087     void registerUniqueServiceOrTerminate(const QString &serviceName, const QLoggingCategory &log)
0088     {
0089         auto bus = QDBusConnection::sessionBus();
0090         if (!bus.isConnected()) {
0091             qCCritical(log, "Session bus not found. Is DBus running?");
0092             exit(1);
0093         }
0094 
0095         if (!bus.registerService(serviceName)) {
0096             // We couldn't register. Most likely, it's already running.
0097             const QString lastError = bus.lastError().message();
0098             if (lastError.isEmpty()) {
0099                 qCInfo(log, "Service %s already registered, terminating now.", qUtf8Printable(serviceName));
0100                 exit(0); // already running, so it's OK. Terminate now.
0101             } else {
0102                 qCCritical(log, "Unable to register service as %s due to an error: %s", qUtf8Printable(serviceName), qUtf8Printable(lastError));
0103                 exit(1); // :(
0104             }
0105         }
0106     }
0107 };
0108 
0109 /**
0110  * Returns the contents of @p name environment variable if it is defined,
0111  * or @p defaultValue otherwise.
0112  */
0113 QString akGetEnv(const char *name, const QString &defaultValue = QString());
0114 
0115 using AkCoreApplication = AkApplicationImpl<QCoreApplication>;
0116 using AkApplication = AkApplicationImpl<QApplication>;
0117 using AkGuiApplication = AkApplicationImpl<QGuiApplication>;
0118 using AkUniqueGuiApplication = AkUniqueApplicationImpl<QGuiApplication>;