1 // The MIT License (MIT)
2 //
3 // Copyright (c) Itay Grudev 2015 - 2020
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 
23 //
24 //  W A R N I N G !!!
25 //  -----------------
26 //
27 // This is a modified version of SingleApplication,
28 // The original version is at:
29 //
30 // https://github.com/itay-grudev/SingleApplication
31 //
32 //
33 
34 #ifndef SINGLECOREAPPLICATION_H
35 #define SINGLECOREAPPLICATION_H
36 
37 #include <QtGlobal>
38 #include <QCoreApplication>
39 #include <QFlags>
40 #include <QByteArray>
41 
42 class SingleCoreApplicationPrivate;
43 
44 /**
45  * @brief The SingleCoreApplication class handles multiple instances of the same Application
46  * @see QCoreApplication
47  */
48 class SingleCoreApplication : public QCoreApplication {
49   Q_OBJECT
50 
51   typedef QCoreApplication app_t;
52 
53  public:
54   /**
55    * @brief Mode of operation of SingleCoreApplication.
56    * Whether the block should be user-wide or system-wide and whether the
57    * primary instance should be notified when a secondary instance had been
58    * started.
59    * @note Operating system can restrict the shared memory blocks to the same
60    * user, in which case the User/System modes will have no effect and the
61    * block will be user wide.
62    * @enum
63    */
64   enum Mode {
65     User = 1 << 0,
66     System = 1 << 1,
67     SecondaryNotification = 1 << 2,
68     ExcludeAppVersion = 1 << 3,
69     ExcludeAppPath = 1 << 4
70   };
71   Q_DECLARE_FLAGS(Options, Mode)
72 
73   /**
74    * @brief Intitializes a SingleCoreApplication instance with argc command line
75    * arguments in argv
76    * @arg {int &} argc - Number of arguments in argv
77    * @arg {const char *[]} argv - Supplied command line arguments
78    * @arg {bool} allowSecondary - Whether to start the instance as secondary
79    * if there is already a primary instance.
80    * @arg {Mode} mode - Whether for the SingleCoreApplication block to be applied
81    * User wide or System wide.
82    * @arg {int} timeout - Timeout to wait in milliseconds.
83    * @note argc and argv may be changed as Qt removes arguments that it
84    * recognizes
85    * @note Mode::SecondaryNotification only works if set on both the primary
86    * instance and the secondary instance.
87    * @note The timeout is just a hint for the maximum time of blocking
88    * operations. It does not guarantee that the SingleCoreApplication
89    * initialisation will be completed in given time, though is a good hint.
90    * Usually 4*timeout would be the worst case (fail) scenario.
91    */
92   explicit SingleCoreApplication(int &argc, char *argv[], const bool allowSecondary = false, const Options options = Mode::User, const int timeout = 1000);
93   ~SingleCoreApplication() override;
94 
95   /**
96    * @brief Returns if the instance is the primary instance
97    * @returns {bool}
98    */
99   bool isPrimary();
100 
101   /**
102    * @brief Returns if the instance is a secondary instance
103    * @returns {bool}
104    */
105   bool isSecondary();
106 
107   /**
108    * @brief Returns a unique identifier for the current instance
109    * @returns {qint32}
110    */
111   quint32 instanceId();
112 
113   /**
114    * @brief Returns the process ID (PID) of the primary instance
115    * @returns {qint64}
116    */
117   qint64 primaryPid();
118 
119   /**
120    * @brief Returns the username of the user running the primary instance
121    * @returns {QString}
122    */
123   QString primaryUser();
124 
125   /**
126    * @brief Returns the username of the current user
127    * @returns {QString}
128    */
129   QString currentUser();
130 
131   /**
132    * @brief Sends a message to the primary instance. Returns true on success.
133    * @param {int} timeout - Timeout for connecting
134    * @returns {bool}
135    * @note sendMessage() will return false if invoked from the primary
136    * instance.
137    */
138   bool sendMessage(const QByteArray &message, const int timeout = 1000);
139 
140  signals:
141   void instanceStarted();
142   void receivedMessage(quint32 instanceId, QByteArray message);
143 
144  private:
145   SingleCoreApplicationPrivate *d_ptr;
146   Q_DECLARE_PRIVATE(SingleCoreApplication)
147   void abortSafely();
148 };
149 
150 Q_DECLARE_OPERATORS_FOR_FLAGS(SingleCoreApplication::Options)
151 
152 #endif  // SINGLECOREAPPLICATION_H
153