Factor out common socket messaging code to simplify adding new single instance commands

This commit is contained in:
Michael Ziminsky (Z) 2025-06-07 17:26:49 -07:00
parent db0f091536
commit dcdd599622
No known key found for this signature in database
2 changed files with 33 additions and 43 deletions

View file

@ -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<typename std::underlying_type<SocketCmd>::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<void(QDataStream&)>& 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

View file

@ -23,6 +23,7 @@
#include <QApplication>
#include <QString>
#include <QtNetwork/qlocalserver.h>
#include <functional>
#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<void(QDataStream&)>&);
bool m_alreadyRunning;
bool m_darkTheme = false;
QLockFile* m_lockFile;