summaryrefslogtreecommitdiffstats
path: root/third_party/SingleApplication-3.1.3.1
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/SingleApplication-3.1.3.1')
-rw-r--r--third_party/SingleApplication-3.1.3.1/.gitignore16
-rw-r--r--third_party/SingleApplication-3.1.3.1/CHANGELOG.md271
-rw-r--r--third_party/SingleApplication-3.1.3.1/CMakeLists.txt34
-rw-r--r--third_party/SingleApplication-3.1.3.1/LICENSE24
-rw-r--r--third_party/SingleApplication-3.1.3.1/README.md295
-rw-r--r--third_party/SingleApplication-3.1.3.1/SingleApplication1
-rw-r--r--third_party/SingleApplication-3.1.3.1/Windows.md46
-rw-r--r--third_party/SingleApplication-3.1.3.1/singleapplication.cpp201
-rw-r--r--third_party/SingleApplication-3.1.3.1/singleapplication.h147
-rw-r--r--third_party/SingleApplication-3.1.3.1/singleapplication.pri20
-rw-r--r--third_party/SingleApplication-3.1.3.1/singleapplication_p.cpp433
-rw-r--r--third_party/SingleApplication-3.1.3.1/singleapplication_p.h100
12 files changed, 1588 insertions, 0 deletions
diff --git a/third_party/SingleApplication-3.1.3.1/.gitignore b/third_party/SingleApplication-3.1.3.1/.gitignore
new file mode 100644
index 00000000..35533fe8
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/.gitignore
@@ -0,0 +1,16 @@
+/examples/*/*.o
+/examples/*/Makefile
+/examples/*/moc_*.cpp
+/examples/*/moc_predefs.h
+/examples/*/*.qmake.stash
+/examples/basic/basic
+/examples/calculator/calculator
+/examples/sending_arguments/sending_arguments
+/**/CMakeLists.txt.user
+/**/CMakeCache.txt
+/**/CMakeCache/*
+/**/CMakeFiles/*
+/**/Makefile
+/**/cmake_install.cmake
+/**/*_autogen/
+libSingleApplication.a
diff --git a/third_party/SingleApplication-3.1.3.1/CHANGELOG.md b/third_party/SingleApplication-3.1.3.1/CHANGELOG.md
new file mode 100644
index 00000000..3662b0b2
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/CHANGELOG.md
@@ -0,0 +1,271 @@
+Changelog
+=========
+
+If by accident I have forgotten to credit someone in the CHANGELOG, email me and I will fix it.
+
+__3.1.3.1__
+---------
+* CMake build system improvements
+* Fixed Clang Tidy warnings
+
+ _Hennadii Chernyshchyk_
+
+__3.1.3__
+---------
+* Improved `CMakeLists.txt`
+
+ _Hennadii Chernyshchyk_
+
+__3.1.2__
+---------
+
+* Fix a crash when exiting an application on Android and iOS
+
+ _Emeric Grange_
+
+__3.1.1a__
+----------
+
+* Added currentUser() method that returns the user the current instance is running as.
+
+ _Leander Schulten_
+
+__3.1.0a__
+----------
+
+* Added primaryUser() method that returns the user the primary instance is running as.
+
+__3.0.19__
+----------
+
+* Fixed code warning for depricated functions in Qt 5.10 related to `QTime` and `qrand()`.
+
+ _Hennadii Chernyshchyk_
+ _Anton Filimonov_
+ _Jonas Kvinge_
+
+__3.0.18__
+----------
+
+* Fallback to standard QApplication class on iOS and Android systems where
+ the library is not supported.
+
+* Added Build CI tests to verify the library builds successfully on Linux, Windows and MacOS across multiple Qt versions.
+
+ _Anton Filimonov_
+
+__3.0.17__
+----------
+
+* Fixed compilation warning/error caused by `geteuid()` on unix based systems.
+
+ _Iakov Kirilenko_
+
+* Added CMake support
+
+ _Hennadii Chernyshchyk_
+
+__3.0.16__
+----------
+
+* Use geteuid and getpwuid to get username on Unix, fallback to environment variable.
+
+ _Jonas Kvinge_
+
+__3.0.15__
+----------
+
+* Bug Fix: sendMessage() might return false even though data was actually written.
+
+ _Jonas Kvinge_
+
+__3.0.14__
+----------
+
+* Fixed uninitialised variables in the `SingleApplicationPrivate` constructor.
+
+__3.0.13a__
+----------
+
+* Process socket events asynchronously
+* Fix undefined variable error on Windows
+
+ _Francis Giraldeau_
+
+__3.0.12a__
+----------
+
+* Removed signal handling.
+
+__3.0.11a__
+----------
+
+* Fixed bug where the message sent by the second process was not received
+ correctly when the message is sent immediately following a connection.
+
+ _Francis Giraldeau_
+
+* Refactored code and implemented shared memory block consistency checks
+ via `qChecksum()` (CRC-16).
+* Explicit `qWarning` and `qCritical` when the library is unable to initialise
+ correctly.
+
+__3.0.10__
+----------
+
+* Removed C style casts and eliminated all clang warnings. Fixed `instanceId`
+ reading from only one byte in the message deserialization. Cleaned up
+ serialization code using `QDataStream`. Changed connection type to use
+ `quint8 enum` rather than `char`.
+* Renamed `SingleAppConnectionType` to `ConnectionType`. Added initialization
+ values to all `ConnectionType` enum cases.
+
+ _Jedidiah Buck McCready_
+
+__3.0.9__
+---------
+
+* Added SingleApplicationPrivate::primaryPid() as a solution to allow
+ bringing the primary window of an application to the foreground on
+ Windows.
+
+ _Eelco van Dam from Peacs BV_
+
+__3.0.8__
+---------
+
+* Bug fix - changed QApplication::instance() to QCoreApplication::instance()
+
+ _Evgeniy Bazhenov_
+
+__3.0.7a__
+----------
+
+* Fixed compilation error with Mingw32 in MXE thanks to Vitaly Tonkacheyev.
+* Removed QMutex used for thread safe behaviour. The implementation now uses
+ QCoreApplication::instance() to get an instance to SingleApplication for
+ memory deallocation.
+
+__3.0.6a__
+----------
+
+* Reverted GetUserName API usage on Windows. Fixed bug with missing library.
+* Fixed bug in the Calculator example, preventing it's window to be raised
+ on Windows.
+
+ Special thanks to Charles Gunawan.
+
+__3.0.5a__
+----------
+
+* Fixed a memory leak in the SingleApplicationPrivate destructor.
+
+ _Sergei Moiseev_
+
+__3.0.4a__
+----------
+
+* Fixed shadow and uninitialised variable warnings.
+
+ _Paul Walmsley_
+
+__3.0.3a__
+----------
+
+* Removed Microsoft Windows specific code for getting username due to
+ multiple problems and compiler differences on Windows platforms. On
+ Windows the shared memory block in User mode now includes the user's
+ home path (which contains the user's username).
+
+* Explicitly getting absolute path of the user's home directory as on Unix
+ a relative path (`~`) may be returned.
+
+__3.0.2a__
+----------
+
+* Fixed bug on Windows when username containing wide characters causes the
+ library to crash.
+
+ _Le Liu_
+
+__3.0.1a__
+----------
+
+* Allows the application path and version to be excluded from the server name
+ hash. The following flags were added for this purpose:
+ * `SingleApplication::Mode::ExcludeAppVersion`
+ * `SingleApplication::Mode::ExcludeAppPath`
+* Allow a non elevated process to connect to a local server created by an
+ elevated process run by the same user on Windows
+* Fixes a problem with upper case letters in paths on Windows
+
+ _Le Liu_
+
+__v3.0a__
+---------
+
+* Deprecated secondary instances count.
+* Added a sendMessage() method to send a message to the primary instance.
+* Added a receivedMessage() signal, emitted when a message is received from a
+ secondary instance.
+* The SingleApplication constructor's third parameter is now a bool
+ specifying if the current instance should be allowed to run as a secondary
+ instance if there is already a primary instance.
+* The SingleApplication constructor accept a fourth parameter specifying if
+ the SingleApplication block should be User-wide or System-wide.
+* SingleApplication no longer relies on `applicationName` and
+ `organizationName` to be set. It instead concatenates all of the following
+ data and computes a `SHA256` hash which is used as the key of the
+ `QSharedMemory` block and the `QLocalServer`. Since at least
+ `applicationFilePath` is always present there is no need to explicitly set
+ any of the following prior to initialising `SingleApplication`.
+ * `QCoreApplication::applicationName`
+ * `QCoreApplication::applicationVersion`
+ * `QCoreApplication::applicationFilePath`
+ * `QCoreApplication::organizationName`
+ * `QCoreApplication::organizationDomain`
+ * User name or home directory path if in User mode
+* The primary instance is no longer notified when a secondary instance had
+ been started by default. A `Mode` flag for this feature exists.
+* Added `instanceNumber()` which represents a unique identifier for each
+ secondary instance started. When called from the primary instance will
+ return `0`.
+
+__v2.4__
+--------
+
+* Stability improvements
+* Support for secondary instances.
+* The library now recovers safely after the primary process has crashed
+and the shared memory had not been deleted.
+
+__v2.3__
+--------
+
+* Improved pimpl design and inheritance safety.
+
+ _Vladislav Pyatnichenko_
+
+__v2.2__
+--------
+
+* The `QAPPLICATION_CLASS` macro can now be defined in the file including the
+Single Application header or with a `DEFINES+=` statement in the project file.
+
+__v2.1__
+--------
+
+* A race condition can no longer occur when starting two processes nearly
+ simultaneously.
+
+ Fix issue [#3](https://github.com/itay-grudev/SingleApplication/issues/3)
+
+__v2.0__
+--------
+
+* SingleApplication is now being passed a reference to `argc` instead of a
+ copy.
+
+ Fix issue [#1](https://github.com/itay-grudev/SingleApplication/issues/1)
+
+* Improved documentation.
diff --git a/third_party/SingleApplication-3.1.3.1/CMakeLists.txt b/third_party/SingleApplication-3.1.3.1/CMakeLists.txt
new file mode 100644
index 00000000..85dba84c
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/CMakeLists.txt
@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.7.0)
+
+project(SingleApplication LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+add_library(${PROJECT_NAME} STATIC
+ singleapplication.cpp
+ singleapplication_p.cpp
+)
+add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
+
+# Find dependencies
+find_package(Qt5 COMPONENTS Network REQUIRED)
+target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network)
+
+if(QAPPLICATION_CLASS STREQUAL QApplication)
+ find_package(Qt5 COMPONENTS Widgets REQUIRED)
+ target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets)
+elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication)
+ find_package(Qt5 COMPONENTS Gui REQUIRED)
+ target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Gui)
+else()
+ set(QAPPLICATION_CLASS QCoreApplication)
+ find_package(Qt5 COMPONENTS Core REQUIRED)
+ target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core)
+endif()
+
+if(WIN32)
+ target_link_libraries(${PROJECT_NAME} PRIVATE advapi32)
+endif()
+
+target_compile_definitions(${PROJECT_NAME} PUBLIC QAPPLICATION_CLASS=${QAPPLICATION_CLASS})
+target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/third_party/SingleApplication-3.1.3.1/LICENSE b/third_party/SingleApplication-3.1.3.1/LICENSE
new file mode 100644
index 00000000..a82e5a68
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+
+Copyright (c) Itay Grudev 2015 - 2020
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+Note: Some of the examples include code not distributed under the terms of the
+MIT License.
diff --git a/third_party/SingleApplication-3.1.3.1/README.md b/third_party/SingleApplication-3.1.3.1/README.md
new file mode 100644
index 00000000..3c36b557
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/README.md
@@ -0,0 +1,295 @@
+SingleApplication
+=================
+[![CI](https://github.com/itay-grudev/SingleApplication/workflows/CI:%20Build%20Test/badge.svg)](https://github.com/itay-grudev/SingleApplication/actions)
+
+This is a replacement of the QtSingleApplication for `Qt5`.
+
+Keeps the Primary Instance of your Application and kills each subsequent
+instances. It can (if enabled) spawn secondary (non-related to the primary)
+instances and can send data to the primary instance from secondary instances.
+
+Usage
+-----
+
+The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
+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.
+
+You can use the library as if you use any other `QCoreApplication` derived
+class:
+
+```cpp
+#include <QApplication>
+#include <SingleApplication.h>
+
+int main( int argc, char* argv[] )
+{
+ SingleApplication app( argc, argv );
+
+ return app.exec();
+}
+```
+
+To include the library files I would recommend that you add it as a git
+submodule to your project. Here is how:
+
+```bash
+git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication
+```
+
+**Qmake:**
+
+Then include the `singleapplication.pri` file in your `.pro` project file.
+
+```qmake
+include(singleapplication/singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QApplication
+```
+
+**CMake:**
+
+Then include the subdirectory in your `CMakeLists.txt` project file.
+
+```cmake
+set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
+add_subdirectory(src/third-party/singleapplication)
+target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
+```
+
+
+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
+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.
+
+The library uses `stdlib` to terminate the program with the `exit()` function.
+
+Also don't forget to specify which `QCoreApplication` class your app is using if it
+is not `QCoreApplication` as in examples above.
+
+The `Instance Started` signal
+-----------------------------
+
+The SingleApplication class implements a `instanceStarted()` signal. You can
+bind to that signal to raise your application's window when a new instance had
+been started, for example.
+
+```cpp
+// window is a QWindow instance
+QObject::connect(
+ &app,
+ &SingleApplication::instanceStarted,
+ &window,
+ &QWindow::raise
+);
+```
+
+Using `SingleApplication::instance()` is a neat way to get the
+`SingleApplication` instance for binding to it's signals anywhere in your
+program.
+
+__Note:__ On Windows the ability to bring the application windows to the
+foreground is restricted. See [Windows specific implementations](Windows.md)
+for a workaround and an example implementation.
+
+
+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
+`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.
+
+```cpp
+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();
+}
+```
+
+*__Note:__ A secondary instance won't cause the emission of the
+`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
+details.*
+
+You can check whether your instance is a primary or secondary with the following
+methods:
+
+```cpp
+app.isPrimary();
+// or
+app.isSecondary();
+```
+
+*__Note:__ If your Primary Instance is terminated a newly launched instance
+will replace the Primary one even if the Secondary flag has been set.*
+
+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.
+
+---
+
+```cpp
+qint64 SingleApplication::primaryPid()
+```
+
+Returns the process ID (PID) of the primary instance.
+
+---
+
+```cpp
+QString SingleApplication::primaryUser()
+```
+
+Returns the username the primary instance is running as.
+
+---
+
+```cpp
+QString SingleApplication::currentUser()
+```
+
+Returns the username the current instance is running as.
+
+### 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.
+* `Mode::SecondaryNotification` – Whether to trigger `instanceStarted()` even
+ whenever secondary instances are started.
+* `Mode::ExcludeAppPath` – Excludes the application path from the server name
+ (and memory block) hash.
+* `Mode::ExcludeAppVersion` – Excludes the application version from the server
+ name (and memory block) hash.
+
+*__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.*
+
+---
+
+Versioning
+----------
+
+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
+compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for
+more details.
+
+Implementation
+--------------
+
+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
+`instanceStarted()` signal and for messaging the primary instance.
+
+Additionally the library can recover from being forcefully killed on *nix
+systems and will reset the memory block given that there are no other
+instances running.
+
+License
+-------
+This library and it's supporting documentation are released under
+`The MIT License (MIT)` with the exception of the Qt calculator examples which
+is distributed under the BSD license.
diff --git a/third_party/SingleApplication-3.1.3.1/SingleApplication b/third_party/SingleApplication-3.1.3.1/SingleApplication
new file mode 100644
index 00000000..8ead1a42
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/SingleApplication
@@ -0,0 +1 @@
+#include "singleapplication.h"
diff --git a/third_party/SingleApplication-3.1.3.1/Windows.md b/third_party/SingleApplication-3.1.3.1/Windows.md
new file mode 100644
index 00000000..13c52da0
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/Windows.md
@@ -0,0 +1,46 @@
+Windows Specific Implementations
+================================
+
+Setting the foreground window
+-----------------------------
+
+In the `instanceStarted()` example in the `README` we demonstrated how an
+application can bring it's primary instance window whenever a second copy
+of the application is started.
+
+On Windows the ability to bring the application windows to the foreground is
+restricted, see [`AllowSetForegroundWindow()`][AllowSetForegroundWindow] for more
+details.
+
+The background process (the primary instance) can bring its windows to the
+foreground if it is allowed by the current foreground process (the secondary
+instance). To bypass this `SingleApplication` must be initialized with the
+`allowSecondary` parameter set to `true` and the `options` parameter must
+include `Mode::SecondaryNotification`, See `SingleApplication::Mode` for more
+details.
+
+Here is an example:
+
+```cpp
+if( app.isSecondary() ) {
+ // This API requires LIBS += User32.lib to be added to the project
+ AllowSetForegroundWindow( DWORD( app.primaryPid() ) );
+}
+
+if( app.isPrimary() ) {
+ QObject::connect(
+ &app,
+ &SingleApplication::instanceStarted,
+ this,
+ &App::instanceStarted
+ );
+}
+```
+
+```cpp
+void App::instanceStarted() {
+ QApplication::setActiveWindow( [window/widget to set to the foreground] );
+}
+```
+
+[AllowSetForegroundWindow]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632668.aspx
diff --git a/third_party/SingleApplication-3.1.3.1/singleapplication.cpp b/third_party/SingleApplication-3.1.3.1/singleapplication.cpp
new file mode 100644
index 00000000..9af38804
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/singleapplication.cpp
@@ -0,0 +1,201 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2020
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QThread>
+#include <QtCore/QByteArray>
+#include <QtCore/QSharedMemory>
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+#include <QtCore/QRandomGenerator>
+#else
+#include <QtCore/QDateTime>
+#endif
+
+#include "singleapplication.h"
+#include "singleapplication_p.h"
+
+/**
+ * @brief Constructor. Checks and fires up LocalServer or closes the program
+ * if another instance already exists
+ * @param argc
+ * @param argv
+ * @param {bool} allowSecondaryInstances
+ */
+SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout )
+ : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
+{
+ Q_D(SingleApplication);
+
+#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
+ // On Android and iOS since the library is not supported fallback to
+ // standard QApplication behaviour by simply returning at this point.
+ qWarning() << "SingleApplication is not supported on Android and iOS systems.";
+ return;
+#endif
+
+ // Store the current mode of the program
+ d->options = options;
+
+ // Generating an application ID used for identifying the shared memory
+ // block and QLocalServer
+ d->genBlockServerName();
+
+#ifdef Q_OS_UNIX
+ // By explicitly attaching it and then deleting it we make sure that the
+ // memory is deleted even after the process has crashed on Unix.
+ d->memory = new QSharedMemory( d->blockServerName );
+ d->memory->attach();
+ delete d->memory;
+#endif
+ // Guarantee thread safe behaviour with a shared memory block.
+ d->memory = new QSharedMemory( d->blockServerName );
+
+ // Create a shared memory block
+ if( d->memory->create( sizeof( InstancesInfo ) ) ) {
+ // Initialize the shared memory block
+ d->memory->lock();
+ d->initializeMemoryBlock();
+ d->memory->unlock();
+ } else {
+ // Attempt to attach to the memory segment
+ if( ! d->memory->attach() ) {
+ qCritical() << "SingleApplication: Unable to attach to shared memory block.";
+ qCritical() << d->memory->errorString();
+ delete d;
+ ::exit( EXIT_FAILURE );
+ }
+ }
+
+ auto *inst = static_cast<InstancesInfo*>( d->memory->data() );
+ QElapsedTimer time;
+ time.start();
+
+ // Make sure the shared memory block is initialised and in consistent state
+ while( true ) {
+ d->memory->lock();
+
+ if( d->blockChecksum() == inst->checksum ) break;
+
+ if( time.elapsed() > 5000 ) {
+ qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
+ d->initializeMemoryBlock();
+ }
+
+ d->memory->unlock();
+
+ // Random sleep here limits the probability of a collision between two racing apps
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+ QThread::sleep( QRandomGenerator::global()->bounded( 8u, 18u ) );
+#else
+ qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
+ QThread::sleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ) );
+#endif
+ }
+
+ if( inst->primary == false) {
+ d->startPrimary();
+ d->memory->unlock();
+ return;
+ }
+
+ // Check if another instance can be started
+ if( allowSecondary ) {
+ inst->secondary += 1;
+ inst->checksum = d->blockChecksum();
+ d->instanceNumber = inst->secondary;
+ d->startSecondary();
+ if( d->options & Mode::SecondaryNotification ) {
+ d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
+ }
+ d->memory->unlock();
+ return;
+ }
+
+ d->memory->unlock();
+
+ d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
+
+ delete d;
+
+ ::exit( EXIT_SUCCESS );
+}
+
+/**
+ * @brief Destructor
+ */
+SingleApplication::~SingleApplication()
+{
+ Q_D(SingleApplication);
+ delete d;
+}
+
+bool SingleApplication::isPrimary()
+{
+ Q_D(SingleApplication);
+ return d->server != nullptr;
+}
+
+bool SingleApplication::isSecondary()
+{
+ Q_D(SingleApplication);
+ return d->server == nullptr;
+}
+
+quint32 SingleApplication::instanceId()
+{
+ Q_D(SingleApplication);
+ return d->instanceNumber;
+}
+
+qint64 SingleApplication::primaryPid()
+{
+ Q_D(SingleApplication);
+ return d->primaryPid();
+}
+
+QString SingleApplication::primaryUser()
+{
+ Q_D(SingleApplication);
+ return d->primaryUser();
+}
+
+QString SingleApplication::currentUser()
+{
+ Q_D(SingleApplication);
+ return d->getUsername();
+}
+
+bool SingleApplication::sendMessage( const QByteArray &message, int timeout )
+{
+ Q_D(SingleApplication);
+
+ // Nobody to connect to
+ if( isPrimary() ) return false;
+
+ // Make sure the socket is connected
+ d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect );
+
+ d->socket->write( message );
+ bool dataWritten = d->socket->waitForBytesWritten( timeout );
+ d->socket->flush();
+ return dataWritten;
+}
diff --git a/third_party/SingleApplication-3.1.3.1/singleapplication.h b/third_party/SingleApplication-3.1.3.1/singleapplication.h
new file mode 100644
index 00000000..fd806a3d
--- /dev/null
+++ b/third_party/SingleApplication-3.1.3.1/singleapplication.h
@@ -0,0 +1,147 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 20