File indexing completed on 2024-04-21 03:53:54

0001 /*
0002     This file is part of libkdbusaddons
0003 
0004     SPDX-FileCopyrightText: 2011 David Faure <faure@kde.org>
0005     SPDX-FileCopyrightText: 2011 Kevin Ottens <ervin@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0008 */
0009 
0010 #ifndef KDBUSSERVICE_H
0011 #define KDBUSSERVICE_H
0012 
0013 #include <QObject>
0014 #include <QUrl>
0015 #include <memory>
0016 
0017 #include <kdbusaddons_export.h>
0018 
0019 class KDBusServicePrivate;
0020 
0021 /**
0022  * @class KDBusService kdbusservice.h <KDBusService>
0023  *
0024  * KDBusService takes care of registering the current process with D-Bus.
0025  *
0026  * This registers the application at a predictable location on D-Bus, registers
0027  * the QCoreApplication (or subclass) object at /MainApplication, and
0028  * assists in implementing the application side of D-Bus activation from
0029  * the <a
0030  * href="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html">Desktop
0031  * Entry Specification</a>.
0032  *
0033  * An application can either work in Multiple mode or Unique mode.
0034  *
0035  * In Multiple mode, the application can be launched many times.  The service
0036  * name in the D-Bus registration will contain the PID to distinguish the
0037  * various instances; for example: <tt>org.kde.konqueror-12345</tt>.
0038  *
0039  * In Unique mode, only one instance of this application can ever run.
0040  * The first instance of the application registers with D-Bus without the PID,
0041  * and any attempt to run the application again will cause the
0042  * activateRequested() signal to be emitted in the already-running instance; the
0043  * duplicate instance will then quit. The exit value can be set by the already
0044  * running instance with setExitValue(), the default value is @c 0.
0045  *
0046  * Unique-mode applications should usually delay parsing command-line arguments
0047  * until after creating a KDBusService object; that way they know they are the
0048  * original instance of the application.
0049  *
0050  * Applications that set the D-Bus activation entry (DBusActivatable=true) in
0051  * their desktop files will use Unique mode and connect to the signals emitted
0052  * by this class.
0053  * Note that the D-Bus interface is exported for Multiple-mode applications as
0054  * well, so it also makes sense for such applications to connect to the signals
0055  * emitted by this class.
0056  *
0057  * @note In order to avoid a race, the application should export its objects to
0058  * D-Bus before allowing the event loop to run (for example, by calling
0059  * QCoreApplication::exec()).  Otherwise, the application will appear on the bus
0060  * before its objects are accessible via D-Bus, which could be a problem for
0061  * other applications or scripts which start the application in order to talk
0062  * D-Bus to it immediately.
0063  *
0064  * Example usage:
0065  *
0066  * @code
0067      QApplication app(argc, argv);
0068      app.setApplicationName("kuiserver");
0069      app.setOrganizationDomain("kde.org");
0070      // Create your D-Bus objects here
0071      // ...
0072      KDBusService service(KDBusService::Unique);
0073      // If this point is reached, this is the only running instance
0074      // i.e. org.kde.kuiserver has been registered
0075      return app.exec();
0076  * @endcode
0077  *
0078  * @since 5.0
0079  */
0080 class KDBUSADDONS_EXPORT KDBusService : public QObject
0081 {
0082     Q_OBJECT
0083 
0084 public:
0085     /**
0086      * Options to control the behaviour of KDBusService
0087      * @see StartupOptions
0088      */
0089     enum StartupOption {
0090         /**
0091          * Indicates that only one instance of this application should ever exist.
0092          *
0093          * Cannot be combined with @c Multiple.
0094          */
0095         Unique = 1,
0096         /**
0097          * Indicates that multiple instances of the application may exist.
0098          *
0099          * Cannot be combined with @c Unique.  This is the default.
0100          */
0101         Multiple = 2,
0102         /** Indicates that the application should not exit if it failed to
0103          * register with D-Bus.
0104          *
0105          * If not set, KDBusService will quit the application if it failed to
0106          * register the service with D-Bus or a @c Unique instance can not be
0107          * activated. A @c Multiple instance will exit with error code @c 1.
0108          * The exit value of a @c Unique instance can be set from the running
0109          * instance with setExitValue(), the default value is @c 0.
0110          */
0111         NoExitOnFailure = 4,
0112         /**
0113          * Indicates that if there's already a unique service running, to be quit and replaced
0114          * with our own.
0115          *
0116          * If exported, it will try first quitting the service calling @c org.qtproject.Qt.QCoreApplication.quit,
0117          * which is exported by KDBusService by default.
0118          *
0119          * @since 5.65
0120          */
0121         Replace = 8
0122     };
0123     Q_ENUM(StartupOption)
0124 
0125     /**
0126      * Stores a combination of #StartupOption values.
0127      */
0128     Q_DECLARE_FLAGS(StartupOptions, StartupOption)
0129     Q_FLAG(StartupOptions)
0130 
0131     /**
0132      * Tries to register the current process to D-Bus at an address based on the
0133      * application name and organization domain.
0134      *
0135      * The D-Bus service name is the reversed organization domain, followed by
0136      * the application name.  If @p options includes the @c Multiple flag, the
0137      * application PID will be appended.  For example,
0138      * @code
0139      * app.setApplicationName("kuiserver");
0140      * app.setOrganizationDomain("kde.org");
0141      * @endcode
0142      * will make KDBusService register as @c org.kde.kuiserver in @c Unique
0143      * mode, and @c org.kde.kuiserver-1234 (if the process has PID @c 1234) in
0144      * @c Multiple mode.
0145      */
0146     explicit KDBusService(StartupOptions options = Multiple, QObject *parent = nullptr);
0147 
0148     /**
0149      * Destroys this object (but does not unregister the application).
0150      *
0151      * Deleting this object before unregister() is called (either manually or
0152      * because QCoreApplication::aboutToQuit() was emitted) could confuse
0153      * clients, who will see the service on the bus but will be unable to use
0154      * the activation methods.
0155      */
0156     ~KDBusService() override;
0157 
0158     /**
0159      * Returns true if the D-Bus registration succeeded.
0160      *
0161      * Note that this is only useful when specifying the option NoExitOnFailure.
0162      * Otherwise, the simple fact that this process is still running indicates
0163      * that the registration succeeded.
0164      */
0165     bool isRegistered() const;
0166 
0167     /**
0168      * Returns the name of the D-Bus service registered by this class.
0169      * Mostly useful when using the option Multiple.
0170      * @since 5.33
0171      */
0172     QString serviceName() const;
0173 
0174     /**
0175      * Returns the error message from the D-Bus registration if it failed.
0176      *
0177      * Note that this is only useful when specifying the option NoExitOnFailure.
0178      * Otherwise the process has quit by the time you can get a chance to call this.
0179      */
0180     QString errorMessage() const;
0181 
0182     /**
0183      * Sets the exit value to be used for a duplicate instance.
0184      *
0185      * If this is a @c Unique application, a slot connected to
0186      * activateRequested() can use this to specify a non-zero exit value for the
0187      * duplicate instance.  This would typically be done if invalid command-line
0188      * arguments are passed.
0189      *
0190      * Note that this will only work if the signal-slot connection type is
0191      * Qt::DirectConnection.
0192      *
0193      * @param value  The exit value for the duplicate instance.
0194      */
0195     void setExitValue(int value);
0196 
0197 Q_SIGNALS:
0198     /**
0199      * Signals that the application is to be activated.
0200      *
0201      * If this is a @c Unique application, when KDBusService is constructed in
0202      * subsequent instances of the application (ie: when the executable is run
0203      * when an instance is already running), it will cause this signal to be
0204      * emitted in the already-running instance (with the arguments passed to the
0205      * duplicate instance), and the duplicate instance will then exit.
0206      *
0207      * If this application's desktop file indicates that it supports D-Bus
0208      * activation (DBusActivatable=true), a command launcher may also call the Activate()
0209      * D-Bus method to trigger this signal. In this case, @p args will be empty.
0210      *
0211      * In single-window applications, the connected signal should typically
0212      * raise the window.
0213      *
0214      * @param arguments  The arguments the executable was called with, starting with the executable file name.
0215      *                   See QCoreApplication::arguments().
0216      *                   This can also be empty.
0217      *
0218      * A typical implementation of the signal handler would be:
0219      * @code
0220      *    if (!arguments.isEmpty()) {
0221      *        commandLineParser->parse(arguments); // same QCommandLineParser instance as the one used in main()
0222      *        handleCmdLine(workingDirectory); // shared method with main(), which uses commandLineParser to handle options and positional arguments
0223      *    }
0224      * @endcode
0225      *
0226      * For GUI applications, the handler also needs to deal with any platform-specific startup ids
0227      * and make sure the mainwindow is shown as well as request its activation from the window manager.
0228      * For X11, KDBusService makes the id for the Startup Notification protocol available
0229      * from QX11Info::nextStartupId(), if there is one.
0230      * For Wayland, KDBusService provides the token for the XDG Activation protocol in the
0231      * "XDG_ACTIVATION_TOKEN" environment variable and unsets it again after the signal, if there is one.
0232      * The util method @c KWindowSystem::updateStartupId(QWindow *window) (since KF 5.91) takes care of that.
0233      * A typical implementation in the signal handler would be:
0234      * @code
0235      *    mainWindow->show();
0236      *    KWindowSystem::updateStartupId(mainWindow->windowHandle());
0237      *    mainWindow->raise();
0238      *    KWindowSystem::activateWindow(mainWindow->windowHandle());
0239      * @endcode
0240      *
0241      * If you're using the builtin handling of @c --help and @c --version in QCommandLineParser,
0242      * you should call parser.process(arguments) before creating the KDBusService instance,
0243      * since parse() doesn't handle those (and exiting the already-running instance would be wrong anyway).
0244      *
0245      * @see setExitValue()
0246      */
0247     void activateRequested(const QStringList &arguments, const QString &workingDirectory);
0248 
0249     /**
0250      * Signals that one or more files should be opened in the application.
0251      *
0252      * This signal is emitted to request handling of the respective method of the D-Bus activation.
0253      * For GUI applications, the signal handler also needs to deal with any platform-specific startup ids
0254      * and make sure the mainwindow is shown as well as request its activation from the window manager.
0255      * See documentation of activateRequested(const QStringList &arguments, const QString &)
0256      * for details.
0257      *
0258      * @param uris  The URLs of the files to open.
0259      */
0260     void openRequested(const QList<QUrl> &uris);
0261 
0262     /**
0263      * Signals that an application action should be triggered.
0264      *
0265      * This signal is emitted to request handling of the respective method of the D-Bus activation.
0266      * For GUI applications, the signal handler also needs to deal with any platform-specific startup ids
0267      * and make sure the mainwindow is shown as well as request its activation from the window manager.
0268      * See documentation of activateRequested(const QStringList &arguments, const QString &)
0269      * for details.
0270      *
0271      * See the desktop entry specification for more information about action activation.
0272      */
0273     void activateActionRequested(const QString &actionName, const QVariant &parameter);
0274 
0275 public Q_SLOTS:
0276     /**
0277      * Unregister from D-Bus.
0278      *
0279      * This is called automatically when the application is about to quit, to
0280      * make sure it doesn't keep receiving calls to its D-Bus interface while it
0281      * is doing final cleanups.
0282      */
0283     void unregister();
0284 
0285 private:
0286     // fdo.Application spec
0287     KDBUSADDONS_NO_EXPORT void Activate(const QVariantMap &platform_data);
0288     KDBUSADDONS_NO_EXPORT void Open(const QStringList &uris, const QVariantMap &platform_data);
0289     KDBUSADDONS_NO_EXPORT void ActivateAction(const QString &action_name, const QVariantList &maybeParameter, const QVariantMap &platform_data);
0290     friend class KDBusServiceAdaptor;
0291 
0292     // org.kde.KDBusService
0293     KDBUSADDONS_NO_EXPORT int CommandLine(const QStringList &arguments, const QString &workingDirectory, const QVariantMap &platform_data);
0294     friend class KDBusServiceExtensionsAdaptor;
0295 
0296 private:
0297     std::unique_ptr<KDBusServicePrivate> const d;
0298 };
0299 
0300 Q_DECLARE_OPERATORS_FOR_FLAGS(KDBusService::StartupOptions)
0301 
0302 #endif /* KDBUSSERVICE_H */