diff --git a/vendor/DOtherSide/lib/CMakeLists.txt b/vendor/DOtherSide/lib/CMakeLists.txt index e69cabefd6..91dcf5265b 100644 --- a/vendor/DOtherSide/lib/CMakeLists.txt +++ b/vendor/DOtherSide/lib/CMakeLists.txt @@ -22,6 +22,7 @@ macro(add_target name type) include/DOtherSide/Utils.h include/DOtherSide/DosDockClicker.h include/DOtherSide/DOtherSideStatusWindow.h + include/DOtherSide/DOtherSideSingleInstance.h src/DOtherSide.cpp src/DosQMetaObject.cpp src/DosQDeclarative.cpp @@ -32,6 +33,7 @@ macro(add_target name type) src/DosQQuickImageProvider.cpp src/DosDockClicker.cpp src/DOtherSideStatusWindow.cpp + src/DOtherSideSingleInstance.cpp ) if (APPLE) diff --git a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h index 8f0daee39b..4b75d38400 100644 --- a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h +++ b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h @@ -973,6 +973,26 @@ DOS_API int DOS_CALL dos_qdeclarative_qmlregistersingletontype(const QmlRegister /// @} +/// \defgroup SingleInstance SingleInstance +/// \brief Functions related to the SingleInstance cclass +/// @{ + +/// \brief Create a new SingleInstance class +/// \param uniqueName The UTF-8 string for QLocalServer name +/// \note The returned SingleInstance should be freed using the dos_singleinstance_delete() function +DOS_API DosSingleInstance *DOS_CALL dos_singleinstance_create(const char *uniqueName); + +/// \brief Returns bool indicating whether this is the first instance or not +/// \returns true if this is the first instance +/// \param vptr The SingleInstance +DOS_API bool DOS_CALL dos_singleinstance_isfirst(DosSingleInstance *vptr); + +/// \brief Free the memory allocated for the SingleInstance +/// \param vptr The SingleInstance to be freed +DOS_API void DOS_CALL dos_singleinstance_delete(DosSingleInstance *vptr); + +/// @} + #ifdef __cplusplus } #endif diff --git a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h new file mode 100644 index 0000000000..8051720093 --- /dev/null +++ b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h @@ -0,0 +1,26 @@ +#ifndef SINGLEINSTANCE_H +#define SINGLEINSTANCE_H + +#include + +class QLocalServer; + +class SingleInstance : public QObject +{ + Q_OBJECT + +public: + explicit SingleInstance(const QString &uniqueName, QObject *parent = nullptr); + ~SingleInstance() override; + + bool isFirstInstance() const; + +signals: + void secondInstanceDetected(); + +private: + QLocalServer *m_localServer; +}; + + +#endif // SINGLEINSTANCE_H diff --git a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideStatusWindow.h b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideStatusWindow.h index 6a559125b4..2776ab487c 100644 --- a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideStatusWindow.h +++ b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideStatusWindow.h @@ -4,8 +4,6 @@ #include #include -class QLocalServer; - class StatusWindow: public QQuickWindow { Q_OBJECT @@ -15,7 +13,6 @@ class StatusWindow: public QQuickWindow public: explicit StatusWindow(QWindow *parent = nullptr); - ~StatusWindow(); Q_INVOKABLE void toggleFullScreen(); @@ -33,14 +30,12 @@ signals: void secondInstanceDetected(); private: - void checkSingleInstance(); void removeTitleBar(); void showTitleBar(); void initCallbacks(); private: bool m_isFullScreen; - QLocalServer *m_localServer; }; #endif // STATUSWINDOW_H diff --git a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideTypes.h b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideTypes.h index fb48bd1342..b0c9e86d17 100644 --- a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideTypes.h +++ b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideTypes.h @@ -95,6 +95,9 @@ typedef void DosQQuickImageProvider; /// A pointer to a QPixmap typedef void DosPixmap; +/// A pointer to SingleInstance +typedef void DosSingleInstance; + /// A pixmap callback to be supplied to an image provider /// \param id Image source id /// \param width pointer to the width of the image diff --git a/vendor/DOtherSide/lib/src/DOtherSide.cpp b/vendor/DOtherSide/lib/src/DOtherSide.cpp index da4df54aa2..1cb89e3fbf 100644 --- a/vendor/DOtherSide/lib/src/DOtherSide.cpp +++ b/vendor/DOtherSide/lib/src/DOtherSide.cpp @@ -59,6 +59,7 @@ #include "DOtherSide/DosQQuickImageProvider.h" #include "DOtherSide/DosDockClicker.h" #include "DOtherSide/DOtherSideStatusWindow.h" +#include "DOtherSide/DOtherSideSingleInstance.h" namespace { @@ -1292,3 +1293,23 @@ char *dos_qurl_replaceHostAndAddPath(char* url, char* newScheme, char* newHost, return convert_to_cstring(newQurl.toString()); } + +DosSingleInstance *dos_singleinstance_create(const char *uniqueName) +{ + return new SingleInstance(QString::fromUtf8(uniqueName)); +} + +void dos_singleinstance_delete(DosSingleInstance *vptr) +{ + auto dsi = static_cast(vptr); + delete dsi; +} + +bool dos_singleinstance_isfirst(DosSingleInstance *vptr) +{ + auto dsi = static_cast(vptr); + if (dsi) { + return dsi->isFirstInstance(); + } + return false; +} diff --git a/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp b/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp new file mode 100644 index 0000000000..c74cde964f --- /dev/null +++ b/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp @@ -0,0 +1,39 @@ +#include "DOtherSide/DOtherSideSingleInstance.h" + +#include +#include + +SingleInstance::SingleInstance(const QString &uniqueName, QObject *parent) + : QObject(parent) + , m_localServer(new QLocalServer(this)) +{ + QString socketName = uniqueName; + +#ifndef Q_OS_WIN + socketName = QString("/tmp/%1").arg(socketName); +#endif + + QLocalSocket localSocket; + localSocket.connectToServer(socketName); + + // the first instance start will be delayed by this timeout (ms) to ensure there are no other instances. + // note: this is an ad-hoc timeout value selected based on prior experience. + if (!localSocket.waitForConnected(100)) { + connect(m_localServer, &QLocalServer::newConnection, this, &SingleInstance::secondInstanceDetected); + if (!m_localServer->listen(socketName)) { + qWarning() << "QLocalServer::listen(" << socketName << ") failed"; + } + } +} + +SingleInstance::~SingleInstance() +{ + if (m_localServer->isListening()) { + m_localServer->close(); + } +} + +bool SingleInstance::isFirstInstance() const +{ + return m_localServer->isListening(); +} diff --git a/vendor/DOtherSide/lib/src/DOtherSideStatusWindow.cpp b/vendor/DOtherSide/lib/src/DOtherSideStatusWindow.cpp index 966fa95ec8..1864d963be 100644 --- a/vendor/DOtherSide/lib/src/DOtherSideStatusWindow.cpp +++ b/vendor/DOtherSide/lib/src/DOtherSideStatusWindow.cpp @@ -1,16 +1,9 @@ #include "DOtherSide/DOtherSideStatusWindow.h" -#include -#include -#include -#include - StatusWindow::StatusWindow(QWindow *parent) : QQuickWindow(parent), - m_isFullScreen(false), - m_localServer(new QLocalServer(this)) + m_isFullScreen(false) { - checkSingleInstance(); removeTitleBar(); connect(this, &QQuickWindow::windowStateChanged, [&](Qt::WindowState windowState) { @@ -26,13 +19,6 @@ StatusWindow::StatusWindow(QWindow *parent) }); } -StatusWindow::~StatusWindow() -{ - if (m_localServer->isListening()) { - m_localServer->close(); - } -} - void StatusWindow::toggleFullScreen() { if (m_isFullScreen) { @@ -46,28 +32,3 @@ bool StatusWindow::isFullScreen() const { return m_isFullScreen; } - -void StatusWindow::checkSingleInstance() -{ - const auto currentDir = QDir::currentPath(); - auto socketName = QString(QCryptographicHash::hash(currentDir.toUtf8(), QCryptographicHash::Md5).toHex()); - -#ifndef Q_OS_WIN - socketName = QString("/tmp/%1").arg(socketName); -#endif - - QLocalSocket localSocket; - localSocket.connectToServer(socketName); - - // the first instance start will be delayed by this timeout (ms) to ensure there are no other instances. - // note: this is an ad-hoc timeout value selected based on prior experience. - const bool connected = localSocket.waitForConnected(100); - if (!connected) { - connect(m_localServer, &QLocalServer::newConnection, this, &StatusWindow::secondInstanceDetected); - if (!m_localServer->listen(socketName)) { - qWarning() << "QLocalServer::listen(" << socketName << ") failed"; - } - } else { - qFatal("Terminating app as the second running instance..."); - } -}