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