2015-02-27 03:00:11 +08:00
|
|
|
|
SingleApplication
|
|
|
|
|
=================
|
|
|
|
|
|
2015-11-05 00:30:30 +08:00
|
|
|
|
This is a replacement of the QSingleApplication for `Qt5`.
|
2015-02-27 03:37:30 +08:00
|
|
|
|
|
2016-05-05 03:40:03 +08:00
|
|
|
|
Keeps the Primary Instance of your Application and kills each subsequent
|
2016-08-10 09:42:46 +08:00
|
|
|
|
instances. It can (if enabled) spawn secondary (non-related to the primary)
|
|
|
|
|
instances and can send data to the primary instance from secondary instances.
|
2015-02-27 03:15:26 +08:00
|
|
|
|
|
|
|
|
|
Usage
|
|
|
|
|
-----
|
|
|
|
|
|
2016-05-05 03:40:03 +08:00
|
|
|
|
The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
|
2016-05-10 00:05:58 +08:00
|
|
|
|
class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
|
|
|
|
|
default). Further usage is similar to the use of the `Q[Core|Gui]Application`
|
|
|
|
|
classes.
|
2016-05-05 03:40:03 +08:00
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
|
|
|
|
|
instance of your Application is your Primary Instance. It would check if the
|
2016-08-10 10:24:46 +08:00
|
|
|
|
shared memory block exists and if not it will start a `QLocalServer` and listen
|
|
|
|
|
for connections. Each subsequent instance of your application would check if the
|
|
|
|
|
shared memory block exists and if it does, it will connect to the QLocalServer
|
|
|
|
|
to notify the primary instance that a new instance had been started, after which
|
|
|
|
|
it would terminate with status code `0`. In the Primary Instance
|
|
|
|
|
`SingleApplication` would emit the `instanceStarted()` signal upon detecting
|
|
|
|
|
that a new instance had been started.
|
2015-02-27 03:15:26 +08:00
|
|
|
|
|
2015-11-05 00:30:30 +08:00
|
|
|
|
The library uses `stdlib` to terminate the program with the `exit()` function.
|
2015-02-27 03:15:26 +08:00
|
|
|
|
|
2016-08-16 06:02:40 +08:00
|
|
|
|
You can use the library as if you use any other `QCoreApplication` derived
|
|
|
|
|
class:
|
2016-03-05 02:15:13 +08:00
|
|
|
|
|
2016-05-10 00:05:58 +08:00
|
|
|
|
```cpp
|
|
|
|
|
#include <QApplication>
|
2016-08-10 09:42:46 +08:00
|
|
|
|
#include <SingleApplication.h>
|
2015-02-27 03:15:26 +08:00
|
|
|
|
|
2016-05-05 03:40:03 +08:00
|
|
|
|
int main( int argc, char* argv[] )
|
2015-02-27 03:15:26 +08:00
|
|
|
|
{
|
2016-05-05 03:40:03 +08:00
|
|
|
|
SingleApplication app( argc, argv );
|
2015-02-27 03:15:26 +08:00
|
|
|
|
|
|
|
|
|
return app.exec();
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2016-05-10 00:05:58 +08:00
|
|
|
|
To include the library files I would recommend that you add it as a git
|
|
|
|
|
submodule to your project and include it's contents with a `.pri` file. Here is
|
|
|
|
|
how:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
|
|
|
|
|
```
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
Then include the `singleapplication.pri` file in your `.pro` project file. Also
|
|
|
|
|
don't forget to specify which `QCoreApplication` class your app is using if it
|
|
|
|
|
is not `QCoreApplication`.
|
2016-05-10 00:05:58 +08:00
|
|
|
|
|
|
|
|
|
```qmake
|
2016-05-27 09:36:12 +08:00
|
|
|
|
include(singleapplication/singleapplication.pri)
|
2016-08-10 09:42:46 +08:00
|
|
|
|
DEFINES += QAPPLICATION_CLASS=QApplication
|
2016-05-10 00:05:58 +08:00
|
|
|
|
```
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
The `Instance Started` signal
|
2015-02-27 03:15:26 +08:00
|
|
|
|
------------------------
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
The SingleApplication class implements a `instanceStarted()` signal. You can
|
|
|
|
|
bind to that signal to raise your application's window when a new instance had
|
2016-08-10 10:24:46 +08:00
|
|
|
|
been started, for example.
|
2016-05-05 03:40:03 +08:00
|
|
|
|
|
2015-06-09 22:29:20 +08:00
|
|
|
|
```cpp
|
2016-05-05 03:40:03 +08:00
|
|
|
|
// window is a QWindow instance
|
2016-08-10 10:24:46 +08:00
|
|
|
|
QObject::connect(
|
|
|
|
|
&app,
|
|
|
|
|
&SingleApplication::instanceStarted,
|
|
|
|
|
&window,
|
|
|
|
|
&QWindow::raise
|
|
|
|
|
);
|
2016-05-05 03:40:03 +08:00
|
|
|
|
```
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
Using `SingleApplication::instance()` is a neat way to get the
|
2016-05-10 00:05:58 +08:00
|
|
|
|
`SingleApplication` instance for binding to it's signals anywhere in your
|
|
|
|
|
program.
|
2016-05-05 03:40:03 +08:00
|
|
|
|
|
|
|
|
|
Secondary Instances
|
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
|
|
If you want to be able to launch additional Secondary Instances (not related to
|
|
|
|
|
your Primary Instance) you have to enable that with the third parameter of the
|
2016-08-10 09:42:46 +08:00
|
|
|
|
`SingleApplication` constructor. The default is `false` meaning no Secondary
|
|
|
|
|
Instances. Here is an example of how you would start a Secondary Instance send
|
|
|
|
|
a message with the command line arguments to the primary instance and then shut
|
|
|
|
|
down.
|
2016-05-05 03:40:03 +08:00
|
|
|
|
|
|
|
|
|
```cpp
|
2016-08-10 09:42:46 +08:00
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
SingleApplication app( argc, argv, true );
|
|
|
|
|
|
|
|
|
|
if( app.isSecondary() ) {
|
|
|
|
|
app.sendMessage( app.arguments().join(' ')).toUtf8() );
|
|
|
|
|
app.exit( 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return app.exec();
|
|
|
|
|
}
|
2015-06-09 22:29:20 +08:00
|
|
|
|
```
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
___Note:__ A secondary instance won't cause the emission of the
|
2016-08-16 06:02:40 +08:00
|
|
|
|
`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
|
|
|
|
|
details.
|
2016-05-05 03:40:03 +08:00
|
|
|
|
|
2016-05-10 00:05:58 +08:00
|
|
|
|
You can check whether your instance is a primary or secondary with the following
|
|
|
|
|
methods:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
app.isPrimary();
|
|
|
|
|
// or
|
|
|
|
|
app.isSecondary();
|
|
|
|
|
```
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
__*Note:*__ If your Primary Instance is terminated a newly launched instance
|
|
|
|
|
will replace the Primary one even if the Secondary flag has been set.
|
2015-06-09 22:29:20 +08:00
|
|
|
|
|
2016-08-10 10:24:46 +08:00
|
|
|
|
API
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
### Members
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Depending on whether `allowSecondary` is set, this constructor may terminate
|
|
|
|
|
your app if there is already a primary instance running. Additional `Options`
|
|
|
|
|
can be specified to set whether the SingleApplication block should work
|
|
|
|
|
user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
|
|
|
|
|
used to notify the primary instance whenever a secondary instance had been
|
|
|
|
|
started (disabled by default). `timeout` specifies the maximum time in
|
|
|
|
|
milliseconds to wait for blocking operations.
|
|
|
|
|
|
|
|
|
|
*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
|
|
|
|
|
recognizes.*
|
|
|
|
|
|
|
|
|
|
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
|
|
|
|
|
and the secondary instance.*
|
|
|
|
|
|
|
|
|
|
*__Note:__ Operating system can restrict the shared memory blocks to the same
|
|
|
|
|
user, in which case the User/System modes will have no effect and the block will
|
|
|
|
|
be user wide.*
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
|
|
|
|
|
in milliseconds for blocking functions
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
bool SingleApplication::isPrimary()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Returns if the instance is the primary instance.
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
bool SingleApplication::isSecondary()
|
|
|
|
|
```
|
|
|
|
|
Returns if the instance is a secondary instance.
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
quint32 SingleApplication::instanceId()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Returns a unique identifier for the current instance
|
|
|
|
|
|
|
|
|
|
### Signals
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
void SingleApplication::instanceStarted()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Triggered whenever a new instance had been started, except for secondary
|
|
|
|
|
instances if the `Mode::SecondaryNotification` flag is not specified.
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message )
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Triggered whenever there is a message received from a secondary instance.
|
|
|
|
|
|
|
|
|
|
### Flags
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
enum SingleApplication::Mode
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
* `Mode::User` - The SingleApplication block should apply user wide. This adds
|
|
|
|
|
user specific data to the key used for the shared memory and server name.
|
|
|
|
|
This is the default functionality.
|
|
|
|
|
* `Mode::System` – The SingleApplication block applies system-wide.
|
|
|
|
|
* `SecondaryNotification` – Whether to trigger `instanceStarted()` even
|
|
|
|
|
whenever secondary instances are started.
|
|
|
|
|
|
|
|
|
|
*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
|
|
|
|
|
and the secondary instance.*
|
|
|
|
|
|
|
|
|
|
*__Note:__ Operating system can restrict the shared memory blocks to the same
|
|
|
|
|
user, in which case the User/System modes will have no effect and the block will
|
|
|
|
|
be user wide.*
|
|
|
|
|
|
2016-07-05 06:17:23 +08:00
|
|
|
|
Versioning
|
|
|
|
|
----------
|
|
|
|
|
|
2016-08-10 09:42:46 +08:00
|
|
|
|
The current library versions is `3.0a`.
|
|
|
|
|
|
2016-07-05 06:17:23 +08:00
|
|
|
|
Each major version introduces either very significant changes or is not
|
|
|
|
|
backwards compatible with the previous version. Minor versions only add
|
|
|
|
|
additional features, bug fixes or performance improvements and are backwards
|
2016-08-10 09:42:46 +08:00
|
|
|
|
compatible with the previous release. See `CHANGELOG.md` for more details.
|
2016-07-05 06:17:23 +08:00
|
|
|
|
|
2015-06-06 05:26:41 +08:00
|
|
|
|
Implementation
|
|
|
|
|
--------------
|
|
|
|
|
|
2016-05-05 03:40:03 +08:00
|
|
|
|
The library is implemented with a QSharedMemory block which is thread safe and
|
|
|
|
|
guarantees a race condition will not occur. It also uses a QLocalSocket to
|
|
|
|
|
notify the main process that a new instance had been spawned and thus invoke the
|
2016-08-10 09:42:46 +08:00
|
|
|
|
`instanceStarted()` signal.
|
2016-05-05 03:40:03 +08:00
|
|
|
|
|
|
|
|
|
To handle an issue on `*nix` systems, where the operating system owns the shared
|
|
|
|
|
memory block and if the program crashes the memory remains untouched, the
|
2016-05-12 01:53:27 +08:00
|
|
|
|
library binds to the following signals and closes the program with
|
|
|
|
|
`error code = 128 + signum` where signum is the number representation of the
|
|
|
|
|
signal listed below. Handling the signal is required in order to safely delete
|
|
|
|
|
the `QSharedMemory` block. Each of these signals are potentially lethal and will
|
2016-05-05 03:40:03 +08:00
|
|
|
|
results in process termination.
|
2016-05-04 21:36:51 +08:00
|
|
|
|
|
|
|
|
|
* `SIGHUP` - `1`, Hangup.
|
|
|
|
|
* `SIGINT` - `2`, Terminal interrupt signal
|
|
|
|
|
* `SIGQUIT` - `3`, Terminal quit signal.
|
|
|
|
|
* `SIGILL` - `4`, Illegal instruction.
|
|
|
|
|
* `SIGABRT` - `6`, Process abort signal.
|
|
|
|
|
* `SIGBUS` - `7`, Access to an undefined portion of a memory object.
|
|
|
|
|
* `SIGFPE` - `8`, Erroneous arithmetic operation (such as division by zero).
|
|
|
|
|
* `SIGSEGV` - `11`, Invalid memory reference.
|
|
|
|
|
* `SIGSYS` - `12`, Bad system call.
|
|
|
|
|
* `SIGPIPE` - `13`, Write on a pipe with no one to read it.
|
|
|
|
|
* `SIGALRM` - `14`, Alarm clock.
|
|
|
|
|
* `SIGTERM` - `15`, Termination signal.
|
|
|
|
|
* `SIGXCPU` - `24`, CPU time limit exceeded.
|
|
|
|
|
* `SIGXFSZ` - `25`, File size limit exceeded.
|
2015-06-06 05:26:41 +08:00
|
|
|
|
|
2016-08-10 10:24:46 +08:00
|
|
|
|
Additionally the library can recover from being killed with uncatchable signals
|
|
|
|
|
and will reset the memory block given that there are no other instances running.
|
2015-05-07 23:26:06 +08:00
|
|
|
|
|
2015-02-27 03:15:26 +08:00
|
|
|
|
License
|
|
|
|
|
-------
|
2016-08-10 09:50:22 +08:00
|
|
|
|
This library and it's supporting documentation are released under
|
2016-08-10 10:24:46 +08:00
|
|
|
|
`The MIT License (MIT)` with the exception of some of the examples distributed
|
|
|
|
|
under the BSD license.
|