File indexing completed on 2024-05-19 05:52:41

0001 // The MIT License (MIT)
0002 //
0003 // Copyright (c) Itay Grudev 2015 - 2018
0004 //
0005 // Permission is hereby granted, free of charge, to any person obtaining a copy
0006 // of this software and associated documentation files (the "Software"), to deal
0007 // in the Software without restriction, including without limitation the rights
0008 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0009 // copies of the Software, and to permit persons to whom the Software is
0010 // furnished to do so, subject to the following conditions:
0011 //
0012 // The above copyright notice and this permission notice shall be included in
0013 // all copies or substantial portions of the Software.
0014 //
0015 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0018 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0021 // THE SOFTWARE.
0022 
0023 #pragma once
0024 
0025 #include <QtCore/QtGlobal>
0026 #include <QtNetwork/QLocalSocket>
0027 
0028 #ifndef QAPPLICATION_CLASS
0029   #define QAPPLICATION_CLASS QCoreApplication
0030 #endif
0031 
0032 #include QT_STRINGIFY(QAPPLICATION_CLASS)
0033 
0034 class SingleApplicationPrivate;
0035 
0036 /**
0037  * @brief The SingleApplication class handles multiple instances of the same
0038  * Application
0039  * @see QCoreApplication
0040  */
0041 class SingleApplication : public QAPPLICATION_CLASS
0042 {
0043     Q_OBJECT
0044 
0045     using app_t = QAPPLICATION_CLASS;
0046 
0047 public:
0048     /**
0049      * @brief Mode of operation of SingleApplication.
0050      * Whether the block should be user-wide or system-wide and whether the
0051      * primary instance should be notified when a secondary instance had been
0052      * started.
0053      * @note Operating system can restrict the shared memory blocks to the same
0054      * user, in which case the User/System modes will have no effect and the
0055      * block will be user wide.
0056      * @enum
0057      */
0058     enum Mode {
0059         User                    = 1 << 0,
0060         System                  = 1 << 1,
0061         SecondaryNotification   = 1 << 2,
0062         ExcludeAppVersion       = 1 << 3,
0063         ExcludeAppPath          = 1 << 4
0064     };
0065     Q_DECLARE_FLAGS(Options, Mode)
0066 
0067     /**
0068      * @brief Intitializes a SingleApplication instance with argc command line
0069      * arguments in argv
0070      * @arg {int &} argc - Number of arguments in argv
0071      * @arg {const char *[]} argv - Supplied command line arguments
0072      * @arg {bool} allowSecondary - Whether to start the instance as secondary
0073      * if there is already a primary instance.
0074      * @arg {Mode} mode - Whether for the SingleApplication block to be applied
0075      * User wide or System wide.
0076      * @arg {int} timeout - Timeout to wait in milliseconds.
0077      * @note argc and argv may be changed as Qt removes arguments that it
0078      * recognizes
0079      * @note Mode::SecondaryNotification only works if set on both the primary
0080      * instance and the secondary instance.
0081      * @note The timeout is just a hint for the maximum time of blocking
0082      * operations. It does not guarantee that the SingleApplication
0083      * initialisation will be completed in given time, though is a good hint.
0084      * Usually 4*timeout would be the worst case (fail) scenario.
0085      * @see See the corresponding QAPPLICATION_CLASS constructor for reference
0086      */
0087     explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000, const QString &userData = {} );
0088     ~SingleApplication() override;
0089 
0090     /**
0091      * @brief Returns if the instance is the primary instance
0092      * @returns {bool}
0093      */
0094     bool isPrimary() const;
0095 
0096     /**
0097      * @brief Returns if the instance is a secondary instance
0098      * @returns {bool}
0099      */
0100     bool isSecondary() const;
0101 
0102     /**
0103      * @brief Returns a unique identifier for the current instance
0104      * @returns {qint32}
0105      */
0106     quint32 instanceId() const;
0107 
0108     /**
0109      * @brief Returns the process ID (PID) of the primary instance
0110      * @returns {qint64}
0111      */
0112     qint64 primaryPid() const;
0113 
0114     /**
0115      * @brief Returns the username of the user running the primary instance
0116      * @returns {QString}
0117      */
0118     QString primaryUser() const;
0119 
0120     /**
0121      * @brief Returns the username of the current user
0122      * @returns {QString}
0123      */
0124     QString currentUser() const;
0125 
0126     /**
0127      * @brief Mode of operation of sendMessage.
0128      * @enum
0129      */
0130     enum SendMode {
0131         NonBlocking,  /** Do not wait for the primary instance termination and return immediately */
0132         BlockUntilPrimaryExit,  /** Wait until the primary instance is terminated */
0133     };
0134 
0135     /**
0136      * @brief Sends a message to the primary instance. Returns true on success.
0137      * @param {int} timeout - Timeout for connecting
0138      * @param {SendMode} sendMode - Mode of operation.
0139      * @returns {bool}
0140      * @note sendMessage() will return false if invoked from the primary
0141      * instance.
0142      */
0143     bool sendMessage( const QByteArray &message, int timeout = 100, SendMode sendMode = NonBlocking );
0144 
0145     /**
0146      * @brief Get the set user data.
0147      * @returns {QStringList}
0148      */
0149     QStringList userData() const;
0150 
0151 Q_SIGNALS:
0152     void instanceStarted();
0153     void receivedMessage( quint32 instanceId, QByteArray message );
0154 
0155 private:
0156     SingleApplicationPrivate *d_ptr;
0157     Q_DECLARE_PRIVATE(SingleApplication)
0158     void abortSafely();
0159 };
0160 
0161 Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
0162