diff --git a/CMakeLists.txt b/CMakeLists.txt index 91a4111b..9a6a284b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -422,7 +422,7 @@ endif() # single instance functionality set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication") -add_subdirectory(third_party/SingleApplication-3.0.19/) +add_subdirectory(third_party/SingleApplication-3.1.3.1/) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/third_party/SingleApplication-3.0.19/.gitignore b/third_party/SingleApplication-3.1.3.1/.gitignore similarity index 58% rename from third_party/SingleApplication-3.0.19/.gitignore rename to third_party/SingleApplication-3.1.3.1/.gitignore index ad390758..35533fe8 100644 --- a/third_party/SingleApplication-3.0.19/.gitignore +++ b/third_party/SingleApplication-3.1.3.1/.gitignore @@ -6,4 +6,11 @@ /examples/basic/basic /examples/calculator/calculator /examples/sending_arguments/sending_arguments -CMakeLists.txt.user +/**/CMakeLists.txt.user +/**/CMakeCache.txt +/**/CMakeCache/* +/**/CMakeFiles/* +/**/Makefile +/**/cmake_install.cmake +/**/*_autogen/ +libSingleApplication.a diff --git a/third_party/SingleApplication-3.0.19/CHANGELOG.md b/third_party/SingleApplication-3.1.3.1/CHANGELOG.md similarity index 91% rename from third_party/SingleApplication-3.0.19/CHANGELOG.md rename to third_party/SingleApplication-3.1.3.1/CHANGELOG.md index 36f1e261..3662b0b2 100644 --- a/third_party/SingleApplication-3.0.19/CHANGELOG.md +++ b/third_party/SingleApplication-3.1.3.1/CHANGELOG.md @@ -1,6 +1,40 @@ 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__ ---------- diff --git a/third_party/SingleApplication-3.0.19/CMakeLists.txt b/third_party/SingleApplication-3.1.3.1/CMakeLists.txt similarity index 52% rename from third_party/SingleApplication-3.0.19/CMakeLists.txt rename to third_party/SingleApplication-3.1.3.1/CMakeLists.txt index 076d514d..85dba84c 100644 --- a/third_party/SingleApplication-3.0.19/CMakeLists.txt +++ b/third_party/SingleApplication-3.1.3.1/CMakeLists.txt @@ -1,45 +1,34 @@ -cmake_minimum_required(VERSION 3.1.0) +cmake_minimum_required(VERSION 3.7.0) -project(SingleApplication) +project(SingleApplication LANGUAGES CXX) -set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) -# SingleApplication base class -set(QAPPLICATION_CLASS QCoreApplication CACHE STRING "Inheritance class for SingleApplication") -set_property(CACHE QAPPLICATION_CLASS PROPERTY STRINGS QApplication QGuiApplication QCoreApplication) - -# Libary target add_library(${PROJECT_NAME} STATIC singleapplication.cpp singleapplication_p.cpp - ) +) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) # Find dependencies -find_package(Qt5Network) +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) -endif() -target_compile_definitions(${PROJECT_NAME} PUBLIC QAPPLICATION_CLASS=${QAPPLICATION_CLASS}) - -# Link dependencies -target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Network) -if(QAPPLICATION_CLASS STREQUAL QApplication) - target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets) -elseif(QAPPLICATION_CLASS STREQUAL QGuiApplication) - target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Gui) -else() - target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core) + 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}) - -add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) diff --git a/third_party/SingleApplication-3.0.19/LICENSE b/third_party/SingleApplication-3.1.3.1/LICENSE similarity index 96% rename from third_party/SingleApplication-3.0.19/LICENSE rename to third_party/SingleApplication-3.1.3.1/LICENSE index 85b2a149..a82e5a68 100644 --- a/third_party/SingleApplication-3.0.19/LICENSE +++ b/third_party/SingleApplication-3.1.3.1/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) Itay Grudev 2015 - 2016 +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 diff --git a/third_party/SingleApplication-3.0.19/README.md b/third_party/SingleApplication-3.1.3.1/README.md similarity index 93% rename from third_party/SingleApplication-3.0.19/README.md rename to third_party/SingleApplication-3.1.3.1/README.md index 5d609865..3c36b557 100644 --- a/third_party/SingleApplication-3.0.19/README.md +++ b/third_party/SingleApplication-3.1.3.1/README.md @@ -1,5 +1,6 @@ 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`. @@ -15,18 +16,6 @@ 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. -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. - You can use the library as if you use any other `QCoreApplication` derived class: @@ -43,8 +32,7 @@ int main( int argc, char* argv[] ) ``` 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: +submodule to your project. Here is how: ```bash git submodule add git@github.com:itay-grudev/SingleApplication.git singleapplication @@ -66,13 +54,27 @@ 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 @@ -204,6 +206,22 @@ 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 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.0.19/Windows.md b/third_party/SingleApplication-3.1.3.1/Windows.md similarity index 100% rename from third_party/SingleApplication-3.0.19/Windows.md rename to third_party/SingleApplication-3.1.3.1/Windows.md diff --git a/third_party/SingleApplication-3.0.19/singleapplication.cpp b/third_party/SingleApplication-3.1.3.1/singleapplication.cpp similarity index 93% rename from third_party/SingleApplication-3.0.19/singleapplication.cpp rename to third_party/SingleApplication-3.1.3.1/singleapplication.cpp index 8ff8747a..9af38804 100644 --- a/third_party/SingleApplication-3.0.19/singleapplication.cpp +++ b/third_party/SingleApplication-3.1.3.1/singleapplication.cpp @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) Itay Grudev 2015 - 2018 +// 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 @@ -85,7 +85,7 @@ SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSeconda } } - InstancesInfo* inst = static_cast( d->memory->data() ); + auto *inst = static_cast( d->memory->data() ); QElapsedTimer time; time.start(); @@ -172,7 +172,19 @@ qint64 SingleApplication::primaryPid() return d->primaryPid(); } -bool SingleApplication::sendMessage( QByteArray message, int timeout ) +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); diff --git a/third_party/SingleApplication-3.0.19/singleapplication.h b/third_party/SingleApplication-3.1.3.1/singleapplication.h similarity index 91% rename from third_party/SingleApplication-3.0.19/singleapplication.h rename to third_party/SingleApplication-3.1.3.1/singleapplication.h index cb505971..fd806a3d 100644 --- a/third_party/SingleApplication-3.0.19/singleapplication.h +++ b/third_party/SingleApplication-3.1.3.1/singleapplication.h @@ -43,7 +43,7 @@ class SingleApplication : public QAPPLICATION_CLASS { Q_OBJECT - typedef QAPPLICATION_CLASS app_t; + using app_t = QAPPLICATION_CLASS; public: /** @@ -86,7 +86,7 @@ public: * @see See the corresponding QAPPLICATION_CLASS constructor for reference */ explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000 ); - ~SingleApplication(); + ~SingleApplication() override; /** * @brief Returns if the instance is the primary instance @@ -112,6 +112,18 @@ public: */ qint64 primaryPid(); + /** + * @brief Returns the username of the user running the primary instance + * @returns {QString} + */ + QString primaryUser(); + + /** + * @brief Returns the username of the current user + * @returns {QString} + */ + QString currentUser(); + /** * @brief Sends a message to the primary instance. Returns true on success. * @param {int} timeout - Timeout for connecting @@ -119,7 +131,7 @@ public: * @note sendMessage() will return false if invoked from the primary * instance. */ - bool sendMessage( QByteArray message, int timeout = 100 ); + bool sendMessage( const QByteArray &message, int timeout = 100 ); Q_SIGNALS: void instanceStarted(); diff --git a/third_party/SingleApplication-3.1.3.1/singleapplication.pri b/third_party/SingleApplication-3.1.3.1/singleapplication.pri new file mode 100644 index 00000000..ae81f599 --- /dev/null +++ b/third_party/SingleApplication-3.1.3.1/singleapplication.pri @@ -0,0 +1,20 @@ +QT += core network +CONFIG += c++11 + +HEADERS += $$PWD/SingleApplication \ + $$PWD/singleapplication.h \ + $$PWD/singleapplication_p.h +SOURCES += $$PWD/singleapplication.cpp \ + $$PWD/singleapplication_p.cpp + +INCLUDEPATH += $$PWD + +win32 { + msvc:LIBS += Advapi32.lib + gcc:LIBS += -ladvapi32 +} + +DISTFILES += \ + $$PWD/README.md \ + $$PWD/CHANGELOG.md \ + $$PWD/Windows.md diff --git a/third_party/SingleApplication-3.0.19/singleapplication_p.cpp b/third_party/SingleApplication-3.1.3.1/singleapplication_p.cpp similarity index 85% rename from third_party/SingleApplication-3.0.19/singleapplication_p.cpp rename to third_party/SingleApplication-3.1.3.1/singleapplication_p.cpp index 884fe631..705609f2 100644 --- a/third_party/SingleApplication-3.0.19/singleapplication_p.cpp +++ b/third_party/SingleApplication-3.1.3.1/singleapplication_p.cpp @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) Itay Grudev 2015 - 2018 +// 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 @@ -69,18 +69,52 @@ SingleApplicationPrivate::~SingleApplicationPrivate() delete socket; } - memory->lock(); - InstancesInfo* inst = static_cast(memory->data()); - if( server != nullptr ) { - server->close(); - delete server; - inst->primary = false; - inst->primaryPid = -1; - inst->checksum = blockChecksum(); - } - memory->unlock(); + if( memory != nullptr ) { + memory->lock(); + auto *inst = static_cast(memory->data()); + if( server != nullptr ) { + server->close(); + delete server; + inst->primary = false; + inst->primaryPid = -1; + inst->primaryUser[0] = '\0'; + inst->checksum = blockChecksum(); + } + memory->unlock(); - delete memory; + delete memory; + } +} + +QString SingleApplicationPrivate::getUsername() +{ +#ifdef Q_OS_WIN + wchar_t username[UNLEN + 1]; + // Specifies size of the buffer on input + DWORD usernameLength = UNLEN + 1; + if( GetUserNameW( username, &usernameLength ) ) + return QString::fromWCharArray( username ); +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) + return QString::fromLocal8Bit( qgetenv( "USERNAME" ) ); +#else + return qEnvironmentVariable( "USERNAME" ); +#endif +#endif +#ifdef Q_OS_UNIX + QString username; + uid_t uid = geteuid(); + struct passwd *pw = getpwuid( uid ); + if( pw ) + username = QString::fromLocal8Bit( pw->pw_name ); + if ( username.isEmpty() ) { +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) + username = QString::fromLocal8Bit( qgetenv( "USER" ) ); +#else + username = qEnvironmentVariable( "USER" ); +#endif + } + return username; +#endif } void SingleApplicationPrivate::genBlockServerName() @@ -105,28 +139,7 @@ void SingleApplicationPrivate::genBlockServerName() // User level block requires a user specific data in the hash if( options & SingleApplication::Mode::User ) { -#ifdef Q_OS_WIN - wchar_t username [ UNLEN + 1 ]; - // Specifies size of the buffer on input - DWORD usernameLength = UNLEN + 1; - if( GetUserNameW( username, &usernameLength ) ) { - appData.addData( QString::fromWCharArray(username).toUtf8() ); - } else { - appData.addData( qgetenv("USERNAME") ); - } -#endif -#ifdef Q_OS_UNIX - QByteArray username; - uid_t uid = geteuid(); - struct passwd *pw = getpwuid(uid); - if( pw ) { - username = pw->pw_name; - } - if( username.isEmpty() ) { - username = qgetenv("USER"); - } - appData.addData(username); -#endif + appData.addData( getUsername().toUtf8() ); } // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with @@ -136,10 +149,11 @@ void SingleApplicationPrivate::genBlockServerName() void SingleApplicationPrivate::initializeMemoryBlock() { - InstancesInfo* inst = static_cast( memory->data() ); + auto *inst = static_cast( memory->data() ); inst->primary = false; inst->secondary = 0; inst->primaryPid = -1; + inst->primaryUser[0] = '\0'; inst->checksum = blockChecksum(); } @@ -169,10 +183,12 @@ void SingleApplicationPrivate::startPrimary() ); // Reset the number of connections - InstancesInfo* inst = static_cast ( memory->data() ); + auto *inst = static_cast ( memory->data() ); inst->primary = true; inst->primaryPid = q->applicationPid(); + strncpy( inst->primaryUser, getUsername().toUtf8().data(), 127 ); + inst->primaryUser[127] = '\0'; inst->checksum = blockChecksum(); instanceNumber = 0; @@ -250,13 +266,25 @@ qint64 SingleApplicationPrivate::primaryPid() qint64 pid; memory->lock(); - InstancesInfo* inst = static_cast( memory->data() ); + auto *inst = static_cast( memory->data() ); pid = inst->primaryPid; memory->unlock(); return pid; } +QString SingleApplicationPrivate::primaryUser() +{ + QByteArray username; + + memory->lock(); + auto *inst = static_cast( memory->data() ); + username = inst->primaryUser; + memory->unlock(); + + return QString::fromUtf8( username ); +} + /** * @brief Executed when a connection has been made to the LocalServer */ diff --git a/third_party/SingleApplication-3.0.19/singleapplication_p.h b/third_party/SingleApplication-3.1.3.1/singleapplication_p.h similarity index 92% rename from third_party/SingleApplication-3.0.19/singleapplication_p.h rename to third_party/SingleApplication-3.1.3.1/singleapplication_p.h index e2c361fb..29ba346b 100644 --- a/third_party/SingleApplication-3.0.19/singleapplication_p.h +++ b/third_party/SingleApplication-3.1.3.1/singleapplication_p.h @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) Itay Grudev 2015 - 2016 +// 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 @@ -42,14 +42,13 @@ struct InstancesInfo { quint32 secondary; qint64 primaryPid; quint16 checksum; + char primaryUser[128]; }; struct ConnectionInfo { - explicit ConnectionInfo() : - msgLen(0), instanceId(0), stage(0) {} - qint64 msgLen; - quint32 instanceId; - quint8 stage; + qint64 msgLen = 0; + quint32 instanceId = 0; + quint8 stage = 0; }; class SingleApplicationPrivate : public QObject { @@ -69,8 +68,9 @@ public: Q_DECLARE_PUBLIC(SingleApplication) SingleApplicationPrivate( SingleApplication *q_ptr ); - ~SingleApplicationPrivate(); + ~SingleApplicationPrivate() override; + QString getUsername(); void genBlockServerName(); void initializeMemoryBlock(); void startPrimary(); @@ -78,6 +78,7 @@ public: void connectToPrimary(int msecs, ConnectionType connectionType ); quint16 blockChecksum(); qint64 primaryPid(); + QString primaryUser(); void readInitMessageHeader(QLocalSocket *socket); void readInitMessageBody(QLocalSocket *socket);