From: tobtoht Date: Tue, 1 Oct 2024 02:21:42 +0000 (+0200) Subject: remove SingleApplication X-Git-Url: https://git.nutra.tk/v2?a=commitdiff_plain;h=4b197dd49cb2e7178ad056f7d515711166d33a04;p=gamesguru%2Ffeather.git remove SingleApplication --- diff --git a/.gitmodules b/.gitmodules index 6187c662..a8c3a3d3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "monero"] path = monero url = https://github.com/feather-wallet/monero.git -[submodule "src/third-party/singleapplication"] - path = src/third-party/singleapplication - url = https://github.com/itay-grudev/SingleApplication.git [submodule "src/third-party/polyseed"] path = src/third-party/polyseed url = https://github.com/tevador/polyseed.git diff --git a/src/Application.cpp b/src/Application.cpp new file mode 100644 index 00000000..5758662a --- /dev/null +++ b/src/Application.cpp @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-FileCopyrightText: 2020-2024 The Monero Project + +#include "Application.h" + +#include "config.h" + +#include +#include +#include + +namespace +{ + constexpr int WaitTimeoutMSec = 150; + const char BlockSizeProperty[] = "blockSize"; +} // namespace + +Application::Application(int& argc, char** argv) + : QApplication(argc, argv) + , m_alreadyRunning(false) + , m_lockFile(nullptr) +{ + QString userName = qgetenv("USER"); + if (userName.isEmpty()) { + userName = qgetenv("USERNAME"); + } + QString identifier = "feather"; + if (!userName.isEmpty()) { + identifier += "-" + userName; + } + + QString lockName = identifier + ".lock"; + m_socketName = identifier + ".socket"; + + // According to documentation we should use RuntimeLocation on *nixes, but even Qt doesn't respect + // this and creates sockets in TempLocation, so let's be consistent. + m_lockFile = new QLockFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + lockName); + m_lockFile->setStaleLockTime(0); + m_lockFile->tryLock(); + + m_lockServer.setSocketOptions(QLocalServer::UserAccessOption); + connect(&m_lockServer, SIGNAL(newConnection()), this, SIGNAL(anotherInstanceStarted())); + connect(&m_lockServer, &QLocalServer::newConnection, this, &Application::processIncomingConnection); + + switch (m_lockFile->error()) { + case QLockFile::NoError: + // No existing lock was found, start listener + m_lockServer.listen(m_socketName); + break; + case QLockFile::LockFailedError: { + // Attempt to connect to the existing instance + QLocalSocket client; + for (int i = 0; i < 3; ++i) { + client.connectToServer(m_socketName); + if (client.waitForConnected(WaitTimeoutMSec)) { + // Connection succeeded, this will raise the existing window if minimized + client.abort(); + m_alreadyRunning = true; + break; + } + } + + if (!m_alreadyRunning) { + // If we get here then the original instance is likely dead + qWarning() << "Existing single-instance lock file is invalid. Launching new instance."; + + // forceably reset the lock file + m_lockFile->removeStaleLockFile(); + m_lockFile->tryLock(); + // start the listen server + m_lockServer.listen(m_socketName); + } + break; + } + default: + qWarning() << "The lock file could not be created. Single-instance mode disabled."; + } +} + +Application::~Application() +{ + if (m_lockFile) { + m_lockFile->unlock(); + delete m_lockFile; + } +} + +bool Application::isAlreadyRunning() const +{ + return m_alreadyRunning; +} + +void Application::processIncomingConnection() +{ + qDebug() << "We got an incoming connection"; + if (m_lockServer.hasPendingConnections()) { + QLocalSocket* socket = m_lockServer.nextPendingConnection(); + socket->setProperty(BlockSizeProperty, 0); + } +} diff --git a/src/Application.h b/src/Application.h new file mode 100644 index 00000000..3600334c --- /dev/null +++ b/src/Application.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-FileCopyrightText: 2020-2024 The Monero Project + +#ifndef FEATHER_APPLICATION_H +#define FEATHER_APPLICATION_H + +#include +#include + +class QLockFile; +class QSocketNotifier; + +class Application : public QApplication { + Q_OBJECT + +public: + Application(int& argc, char** argv); + ~Application() override; + + bool isAlreadyRunning() const; + +signals: + void anotherInstanceStarted(); + +private slots: + void processIncomingConnection(); + +private: + bool m_alreadyRunning; + QLockFile* m_lockFile; + QLocalServer m_lockServer; + QString m_socketName; +}; + + +#endif //FEATHER_APPLICATION_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 42253b30..9100de99 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,11 +20,6 @@ endif() find_package(Qt6 REQUIRED COMPONENTS ${QT_COMPONENTS}) -if (NOT APPLE) - set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication") - add_subdirectory(third-party/singleapplication) -endif() - if (CHECK_UPDATES) add_subdirectory(openpgp) endif() @@ -280,10 +275,6 @@ target_link_libraries(feather PRIVATE ${BCUR_LIBRARY} ) -if(NOT APPLE) - target_link_libraries(feather PRIVATE SingleApplication::SingleApplication) -endif() - if(CHECK_UPDATES) target_link_libraries(feather PRIVATE openpgp) endif() diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index 6a37a62c..2dd53701 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -3,12 +3,12 @@ #include "WindowManager.h" -#include #include #include #include #include +#include "Application.h" #include "constants.h" #include "dialog/PasswordDialog.h" #include "dialog/SplashDialog.h" @@ -33,6 +33,7 @@ WindowManager::WindowManager(QObject *parent) connect(m_walletManager, &WalletManager::deviceError, this, &WindowManager::onDeviceError); connect(m_walletManager, &WalletManager::walletPassphraseNeeded, this, &WindowManager::onWalletPassphraseNeeded); + connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(raise())); connect(qApp, &QGuiApplication::lastWindowClosed, this, &WindowManager::quitAfterLastWindow); m_tray = new QSystemTrayIcon(icons()->icon("appicons/64x64.png")); @@ -66,6 +67,7 @@ WindowManager::~WindowManager() { qDebug() << "~WindowManager"; m_cleanupThread->quit(); m_cleanupThread->wait(); + qDebug() << "Cleanup thread done"; } // ######################## APPLICATION LIFECYCLE ######################## @@ -100,6 +102,7 @@ void WindowManager::close() { torManager()->stop(); + qDebug() << "Calling QApplication::quit()"; QApplication::quit(); } diff --git a/src/WindowManager.h b/src/WindowManager.h index 92c9225d..beccd5ed 100644 --- a/src/WindowManager.h +++ b/src/WindowManager.h @@ -30,7 +30,6 @@ public: void closeWindow(MainWindow *window); void showWizard(WalletWizard::Page startPage); void restartApplication(const QString &binaryFilename); - void raise(); void showSettings(Nodes *nodes, QWidget *parent, bool showProxyTab = false); @@ -59,6 +58,7 @@ public slots: void tryOpenWallet(const QString &path, const QString &password); private slots: + void raise(); void onWalletOpened(Wallet *wallet); void onWalletCreated(Wallet *wallet); void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); diff --git a/src/main.cpp b/src/main.cpp index e1512a00..1627805b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,9 @@ // SPDX-License-Identifier: BSD-3-Clause // SPDX-FileCopyrightText: 2020-2024 The Monero Project -#include -#include -#include -#include -#if !defined(Q_OS_MAC) -#include -#endif - +#include "Application.h" #include "config-feather.h" #include "constants.h" -#include "MainWindow.h" #include "utils/EventFilter.h" #include "utils/os/Prestium.h" #include "WindowManager.h" @@ -24,8 +16,6 @@ #include #endif -#include - #if defined(Q_OS_WIN) #include #include @@ -89,12 +79,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round); #endif -#if defined(Q_OS_MAC) - // https://github.com/itay-grudev/SingleApplication/issues/136#issuecomment-1925441403 - QApplication app(argc, argv); -#else - SingleApplication app(argc, argv); -#endif + Application app(argc, argv); QApplication::setApplicationName("Feather"); QApplication::setApplicationVersion(FEATHER_VERSION); @@ -122,6 +107,11 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { return EXIT_SUCCESS; } + if (app.isAlreadyRunning()) { + qWarning() << "Another instance of Feather is already running"; + return EXIT_SUCCESS; + } + bool stagenet = parser.isSet(stagenetOption); bool testnet = parser.isSet(testnetOption); bool quiet = parser.isSet(quietModeOption); @@ -193,8 +183,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { conf()->set(Config::restartRequired, false); - parser.process(app); // Parse again for --help and --version - if (!quiet) { QMap info; info["Qt"] = QT_VERSION_STR; @@ -238,13 +226,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { auto wm = windowManager(); wm->setEventFilter(&filter); -#if !defined(Q_OS_MAC) - QObject::connect(&app, &SingleApplication::instanceStarted, [&wm]() { - wm->raise(); - }); -#endif - - int exitCode = QApplication::exec(); - qDebug() << "QApplication::exec() returned"; + int exitCode = Application::exec(); + qDebug() << "Application::exec() returned"; return exitCode; } diff --git a/src/third-party/singleapplication b/src/third-party/singleapplication deleted file mode 160000 index 3e8e85d1..00000000 --- a/src/third-party/singleapplication +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3e8e85d1a487e433751711a8a090659684d42e3b