From dcdd5996223a4e1043cd4e492f976fd432de0691 Mon Sep 17 00:00:00 2001 From: "Michael Ziminsky (Z)" Date: Sat, 7 Jun 2025 17:26:49 -0700 Subject: [PATCH] Factor out common socket messaging code to simplify adding new single instance commands --- src/gui/Application.cpp | 71 ++++++++++++++++------------------------- src/gui/Application.h | 5 +++ 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index 01553ad91..402b50c3d 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -47,6 +47,12 @@ namespace int g_OriginalFontSize = 0; } // namespace +enum Application::SocketCmd : quint32 +{ + OpenFiles = 1, + LockAll, +}; + Application::Application(int& argc, char** argv) : QApplication(argc, argv) #ifdef Q_OS_UNIX @@ -54,11 +60,7 @@ Application::Application(int& argc, char** argv) #endif , m_alreadyRunning(false) , m_lockFile(nullptr) -#if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) { -#else -{ -#endif #if defined(Q_OS_UNIX) registerUnixSignals(); #endif @@ -324,13 +326,13 @@ void Application::socketReadyRead() return; } - QStringList fileNames; - quint32 id; - in >> id; + SocketCmd id; + // manual reinterpret_cast not needed for Qt 5.14+ + in >> reinterpret_cast::type&>(id); - // TODO: move constants to enum switch (id) { - case 1: + case SocketCmd::OpenFiles: { + QStringList fileNames; in >> fileNames; for (const QString& fileName : asConst(fileNames)) { const QFileInfo fInfo(fileName); @@ -338,9 +340,9 @@ void Application::socketReadyRead() emit openFile(fileName); } } - break; - case 2: + } + case SocketCmd::LockAll: getMainWindow()->lockAllDatabases(); break; } @@ -357,13 +359,7 @@ bool Application::isAlreadyRunning() const return config()->get(Config::SingleInstance).toBool() && m_alreadyRunning; } -/** - * Send to-open file names to the running UI instance - * - * @param fileNames - list of file names to open - * @return true if all operations succeeded (connection made, data sent, connection closed) - */ -bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames) +bool Application::sendSocketCommand(SocketCmd id, const std::function& caller) { QLocalSocket client; client.connectToServer(m_socketName); @@ -376,8 +372,8 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames) QDataStream out(&data, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_5_0); out << quint32(0); // reserve space for block size - out << quint32(1); // ID for file name send. TODO: move to enum - out << fileNames; // send file names to be opened + out << id; // ID of command being sent. + caller(out); // Pass to caller to add any additional data out.device()->seek(0); out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size @@ -388,6 +384,17 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames) return writeOk && disconnected; } +/** + * Send to-open file names to the running UI instance + * + * @param fileNames - list of file names to open + * @return true if all operations succeeded (connection made, data sent, connection closed) + */ +bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames) +{ + return this->sendSocketCommand(SocketCmd::OpenFiles, [fileNames](QDataStream& out) { out << fileNames; }); +} + /** * Locks all open databases in the running instance * @@ -395,29 +402,7 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames) */ bool Application::sendLockToInstance() { - // Make a connection to avoid SIGSEGV - QLocalSocket client; - client.connectToServer(m_socketName); - const bool connected = client.waitForConnected(WaitTimeoutMSec); - if (!connected) { - return false; - } - - // Send lock signal - QByteArray data; - QDataStream out(&data, QIODevice::WriteOnly); - out.setVersion(QDataStream::Qt_5_0); - out << quint32(0); // reserve space for block size - out << quint32(2); // ID for database lock. TODO: move to enum - out.device()->seek(0); - out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size - - // Finish gracefully - const bool writeOk = client.write(data) != -1 && client.waitForBytesWritten(WaitTimeoutMSec); - client.disconnectFromServer(); - const bool disconnected = - client.state() == QLocalSocket::UnconnectedState || client.waitForConnected(WaitTimeoutMSec); - return writeOk && disconnected; + return this->sendSocketCommand(SocketCmd::LockAll, [](QDataStream&) { /* No Data */ }); } bool Application::isDarkTheme() const diff --git a/src/gui/Application.h b/src/gui/Application.h index 349c93923..4d7a87fca 100644 --- a/src/gui/Application.h +++ b/src/gui/Application.h @@ -23,6 +23,7 @@ #include #include #include +#include #if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)) @@ -78,6 +79,10 @@ private: static void handleUnixSignal(int sig); static int unixSignalSocket[2]; #endif + + enum SocketCmd : quint32; + bool sendSocketCommand(SocketCmd id, const std::function&); + bool m_alreadyRunning; bool m_darkTheme = false; QLockFile* m_lockFile;