• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..19-Nov-2021-

.github/H19-Nov-2021-5946

examples/H19-Nov-2021-837417

.gitignoreH A D19-Nov-2021363 1716

CHANGELOG.mdH A D19-Nov-20218.1 KiB302205

LICENSEH A D19-Nov-20211.2 KiB2519

README.mdH A D19-Nov-20219.4 KiB305220

SingleApplicationH A D19-Nov-202131 21

Windows.mdH A D19-Nov-20211.4 KiB4737

singleapplication.cppH A D19-Nov-20218.9 KiB272145

singleapplication.hH A D19-Nov-20215.2 KiB15542

singleapplication.priH A D19-Nov-2021386 2116

singleapplication_p.cppH A D19-Nov-202115.4 KiB530384

singleapplication_p.hH A D19-Nov-20213.6 KiB11069

README.md

1SingleApplication
2=================
3[![CI](https://github.com/itay-grudev/SingleApplication/workflows/CI:%20Build%20Test/badge.svg)](https://github.com/itay-grudev/SingleApplication/actions)
4
5This is a replacement of the QtSingleApplication for `Qt5` and `Qt6`.
6
7Keeps the Primary Instance of your Application and kills each subsequent
8instances. It can (if enabled) spawn secondary (non-related to the primary)
9instances and can send data to the primary instance from secondary instances.
10
11Usage
12-----
13
14The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
15class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
16default). Further usage is similar to the use of the `Q[Core|Gui]Application`
17classes.
18
19You can use the library as if you use any other `QCoreApplication` derived
20class:
21
22```cpp
23#include <QApplication>
24#include <SingleApplication.h>
25
26int main( int argc, char* argv[] )
27{
28    SingleApplication app( argc, argv );
29
30    return app.exec();
31}
32```
33
34To include the library files I would recommend that you add it as a git
35submodule to your project. Here is how:
36
37```bash
38git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
39```
40
41**Qmake:**
42
43Then include the `singleapplication.pri` file in your `.pro` project file.
44
45```qmake
46include(singleapplication/singleapplication.pri)
47DEFINES += QAPPLICATION_CLASS=QApplication
48```
49
50**CMake:**
51
52Then include the subdirectory in your `CMakeLists.txt` project file.
53
54```cmake
55set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
56add_subdirectory(src/third-party/singleapplication)
57target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
58```
59
60
61The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
62instance of your Application is your Primary Instance. It would check if the
63shared memory block exists and if not it will start a `QLocalServer` and listen
64for connections. Each subsequent instance of your application would check if the
65shared memory block exists and if it does, it will connect to the QLocalServer
66to notify the primary instance that a new instance had been started, after which
67it would terminate with status code `0`. In the Primary Instance
68`SingleApplication` would emit the `instanceStarted()` signal upon detecting
69that a new instance had been started.
70
71The library uses `stdlib` to terminate the program with the `exit()` function.
72
73Also don't forget to specify which `QCoreApplication` class your app is using if it
74is not `QCoreApplication` as in examples above.
75
76The `Instance Started` signal
77-----------------------------
78
79The SingleApplication class implements a `instanceStarted()` signal. You can
80bind to that signal to raise your application's window when a new instance had
81been started, for example.
82
83```cpp
84// window is a QWindow instance
85QObject::connect(
86    &app,
87    &SingleApplication::instanceStarted,
88    &window,
89    &QWindow::raise
90);
91```
92
93Using `SingleApplication::instance()` is a neat way to get the
94`SingleApplication` instance for binding to it's signals anywhere in your
95program.
96
97__Note:__ On Windows the ability to bring the application windows to the
98foreground is restricted. See [Windows specific implementations](Windows.md)
99for a workaround and an example implementation.
100
101
102Secondary Instances
103-------------------
104
105If you want to be able to launch additional Secondary Instances (not related to
106your Primary Instance) you have to enable that with the third parameter of the
107`SingleApplication` constructor. The default is `false` meaning no Secondary
108Instances. Here is an example of how you would start a Secondary Instance send
109a message with the command line arguments to the primary instance and then shut
110down.
111
112```cpp
113int main(int argc, char *argv[])
114{
115    SingleApplication app( argc, argv, true );
116
117    if( app.isSecondary() ) {
118        app.sendMessage(  app.arguments().join(' ')).toUtf8() );
119        app.exit( 0 );
120    }
121
122    return app.exec();
123}
124```
125
126*__Note:__ A secondary instance won't cause the emission of the
127`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
128details.*
129
130You can check whether your instance is a primary or secondary with the following
131methods:
132
133```cpp
134app.isPrimary();
135// or
136app.isSecondary();
137```
138
139*__Note:__ If your Primary Instance is terminated a newly launched instance
140will replace the Primary one even if the Secondary flag has been set.*
141
142Examples
143--------
144
145There are three examples provided in this repository:
146
147* Basic example that prevents a secondary instance from starting [`examples/basic`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/basic)
148* An example of a graphical application raising it's parent window [`examples/calculator`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/calculator)
149* A console application sending the primary instance it's command line parameters [`examples/sending_arguments`](https://github.com/itay-grudev/SingleApplication/tree/master/examples/sending_arguments)
150
151API
152---
153
154### Members
155
156```cpp
157SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100, QString userData = QString() )
158```
159
160Depending on whether `allowSecondary` is set, this constructor may terminate
161your app if there is already a primary instance running. Additional `Options`
162can be specified to set whether the SingleApplication block should work
163user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
164used to notify the primary instance whenever a secondary instance had been
165started (disabled by default). `timeout` specifies the maximum time in
166milliseconds to wait for blocking operations. Setting `userData` provides additional data that will isolate this instance from other instances that do not have the same (or any) user data set.
167
168*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
169recognizes.*
170
171*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
172and the secondary instance.*
173
174*__Note:__ Operating system can restrict the shared memory blocks to the same
175user, in which case the User/System modes will have no effect and the block will
176be user wide.*
177
178---
179
180```cpp
181bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
182```
183
184Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
185in milliseconds for blocking functions
186
187---
188
189```cpp
190bool SingleApplication::isPrimary()
191```
192
193Returns if the instance is the primary instance.
194
195---
196
197```cpp
198bool SingleApplication::isSecondary()
199```
200Returns if the instance is a secondary instance.
201
202---
203
204```cpp
205quint32 SingleApplication::instanceId()
206```
207
208Returns a unique identifier for the current instance.
209
210---
211
212```cpp
213qint64 SingleApplication::primaryPid()
214```
215
216Returns the process ID (PID) of the primary instance.
217
218---
219
220```cpp
221QString SingleApplication::primaryUser()
222```
223
224Returns the username the primary instance is running as.
225
226---
227
228```cpp
229QString SingleApplication::currentUser()
230```
231
232Returns the username the current instance is running as.
233
234### Signals
235
236```cpp
237void SingleApplication::instanceStarted()
238```
239
240Triggered whenever a new instance had been started, except for secondary
241instances if the `Mode::SecondaryNotification` flag is not specified.
242
243---
244
245```cpp
246void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message )
247```
248
249Triggered whenever there is a message received from a secondary instance.
250
251---
252
253### Flags
254
255```cpp
256enum SingleApplication::Mode
257```
258
259*   `Mode::User` - The SingleApplication block should apply user wide. This adds
260    user specific data to the key used for the shared memory and server name.
261    This is the default functionality.
262*   `Mode::System` – The SingleApplication block applies system-wide.
263*   `Mode::SecondaryNotification` – Whether to trigger `instanceStarted()` even
264    whenever secondary instances are started.
265*   `Mode::ExcludeAppPath` – Excludes the application path from the server name
266    (and memory block) hash.
267*   `Mode::ExcludeAppVersion` – Excludes the application version from the server
268    name (and memory block) hash.
269
270*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
271and the secondary instance.*
272
273*__Note:__ Operating system can restrict the shared memory blocks to the same
274user, in which case the User/System modes will have no effect and the block will
275be user wide.*
276
277---
278
279Versioning
280----------
281
282Each major version introduces either very significant changes or is not
283backwards compatible with the previous version. Minor versions only add
284additional features, bug fixes or performance improvements and are backwards
285compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for
286more details.
287
288Implementation
289--------------
290
291The library is implemented with a QSharedMemory block which is thread safe and
292guarantees a race condition will not occur. It also uses a QLocalSocket to
293notify the main process that a new instance had been spawned and thus invoke the
294`instanceStarted()` signal and for messaging the primary instance.
295
296Additionally the library can recover from being forcefully killed on *nix
297systems and will reset the memory block given that there are no other
298instances running.
299
300License
301-------
302This library and it's supporting documentation are released under
303`The MIT License (MIT)` with the exception of the Qt calculator examples which
304is distributed under the BSD license.
305