QtAppInstanceManager is a tool to control how many instances of your Qt5 application are running at the same time, and to send messages between instances. It uses a local socket under the hood. You may then build upon this foundation any messaging system or protocol, such as JSON-RPC for instance (NB: not provided because out of the scope of this library).
It is intended to be a replacement for QtSingleApplication
, the deprecated Qt4 official project.
Also, it differs from itay-grudev's SingleApplication because you don't need to inherit a child class of QCoreApplication
to use QtAppInstanceManager
, therefore it doesn't need configure-time flags and macros.
- Platform: Windows, MacOS, Linux.
- CMake 3.21+
- Qt 5.15+
-
Add the library as a dependency with CMake FetchContent.
include(FetchContent) FetchContent_Declare(QtAppInstanceManager GIT_REPOSITORY "https://github.com/oclero/qtappinstancemanager.git" ) FetchContent_MakeAvailable(QtAppInstanceManager)
-
Link with the library in CMake.
target_link_libraries(your_project oclero::QtAppInstanceManager)
-
Include the only necessary header in your C++ file.
#include <oclero/QtAppInstanceManager.hpp>
Just create an oclero::QtAppInstanceManager
and configure it to allow only one instance running at the same time with setForceSingleInstance(true)
.
Complete example can be found in the /examples
directory, including CMake and C++ file.
// Initialize instance manager to force only one instance running.
oclero::QtAppInstanceManager instanceManager;
instanceManager.setMode(QtAppInstanceManager::Mode::SingleInstance);
// When another instance will start, it will immediately quit the app and send its
// arguments to the primary instance.
QObject::connect(&instanceManager,
&oclero::QtAppInstanceManager::secondaryInstanceMessageReceived,
&instanceManager,
[](const unsigned int id, QByteArray const& data) {
// Do what you want:
// - Raise the main window.
// - Open a file in an another tab of your main window.
// - ...
qDebug() << "Secondary instance message received: " << data;
});
// If you don't want for the app to quit, you can set the manual mode and handle this step by yourself.
instanceManager.setAppExitMode(QtAppInstanceManager::AppExitMode::Manual);
QObject::connect(&instanceManager,
&QtAppInstanceManager::appExitRequested,
&singleInstance,
[]() {
// Do what you want.
// Usually you should quit the app.
qDebug() << "This app should exit";
QCoreApplication::quit();
std::exit(EXIT_SUCCESS);
});
oclero::QtAppInstanceManager instanceManager;
// If we are the FIRST instance to launch,
// we'll receive messages from other instances that will launch after us.
QObject::connect(&instanceManager,
&oclero::QtAppInstanceManager::secondaryInstanceMessageReceived,
&instanceManager,
[](const unsigned int id, QByteArray const& data) {
qDebug() << "Message received from secondary instance: " << data;
});
// If we are another instance, we are able to receive messages from the primary one.
QObject::connect(&instanceManager,
&oclero::QtAppInstanceManager::primaryInstanceMessageReceived,
&instanceManager,
[](QByteArray const& data) {
qDebug() << "Message received from primary instance: " << data;
});
// If ever the first instance to launch unexpectly shuts down,
// one of the secondary instances will immediately take of the role of the primary one.
QObject::connect(&instanceManager,
&oclero::QtAppInstanceManager::instanceRoleChanged,
&instanceManager,
[&instanceManager]() {
// There is a short period of time before roles are assigned again.
if (!instanceManager.isPrimaryInstance() && !instanceManager.isSecondaryInstance()) {
qDebug() << "Waiting for new role...";
} else {
qDebug() << "New role: " << (instanceManager.isPrimaryInstance() ? "Primary" : "Secondary");
}
});
Olivier Cléro | email | website | github
Thanks to Emilien Vallot for his help and advices.
QtAppInstanceManager is available under the MIT license. See the LICENSE file for more info.