").arg(kAppName);
- if (isServer) {
+ if (Settings::value(Settings::Core::CoreMode).value() == Settings::Server) {
message.append(
QObject::tr(
"
Try moving your mouse to your other computer. Once there, go ahead "
@@ -159,7 +158,10 @@ void showFirstConnectedMessage(QWidget *parent, bool closeToTray, bool enableSer
message.append(QObject::tr("
Try controlling this computer remotely.
"));
}
- if (!closeToTray && !enableService) {
+ using ProcessMode = Settings::ProcessMode;
+
+ if (Settings::value(Settings::Core::ProcessMode).value() == ProcessMode::Desktop &&
+ !Settings::value(Settings::Gui::CloseToTray).toBool()) {
message.append(
QObject::tr(
"
As you do not have the setting enabled to keep %1 running in "
diff --git a/src/lib/gui/Messages.h b/src/lib/gui/Messages.h
index 5e36aec34dbf..d2bb88c8711c 100644
--- a/src/lib/gui/Messages.h
+++ b/src/lib/gui/Messages.h
@@ -21,7 +21,7 @@ void raiseCriticalDialog();
void showFirstServerStartMessage(QWidget *parent);
-void showFirstConnectedMessage(QWidget *parent, bool closeToTray, bool enableService, bool isServer);
+void showFirstConnectedMessage(QWidget *parent);
void showCloseReminder(QWidget *parent);
From d8e9ac27f5e5f53308c9ee58344c246b2b7a2170 Mon Sep 17 00:00:00 2001
From: sithlord48
Date: Sat, 4 Apr 2026 14:29:49 -0400
Subject: [PATCH 04/24] refactor: Messages::showNewClientPrompt check if server
auth is needed when the message is shown not in the signal
---
src/lib/gui/MainWindow.cpp | 4 ++--
src/lib/gui/MainWindow.h | 2 +-
src/lib/gui/Messages.cpp | 5 +++--
src/lib/gui/Messages.h | 2 +-
src/lib/gui/core/ServerConnection.cpp | 4 +---
src/lib/gui/core/ServerConnection.h | 2 +-
6 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/src/lib/gui/MainWindow.cpp b/src/lib/gui/MainWindow.cpp
index b13e58b176c2..4903d33c74c1 100644
--- a/src/lib/gui/MainWindow.cpp
+++ b/src/lib/gui/MainWindow.cpp
@@ -1187,10 +1187,10 @@ void MainWindow::showClientError(deskflow::client::ErrorType error, const QStrin
m_clientErrorVisible = false;
}
-void MainWindow::handleNewClientPromptRequest(const QString &clientName, bool usePeerAuth)
+void MainWindow::handleNewClientPromptRequest(const QString &clientName)
{
showAndActivate();
- bool result = deskflow::gui::messages::showNewClientPrompt(this, clientName, usePeerAuth);
+ bool result = deskflow::gui::messages::showNewClientPrompt(this, clientName);
m_serverConnection.handleNewClientResult(clientName, result);
}
diff --git a/src/lib/gui/MainWindow.h b/src/lib/gui/MainWindow.h
index 82bf075c3193..21c688f70b0d 100644
--- a/src/lib/gui/MainWindow.h
+++ b/src/lib/gui/MainWindow.h
@@ -140,7 +140,7 @@ class MainWindow : public QMainWindow
void daemonIpcClientConnectionFailed();
void toggleCanRunCore(bool enableButtons);
void remoteHostChanged(const QString &newRemoteHost);
- void handleNewClientPromptRequest(const QString &clientName, bool usePeerAuth);
+ void handleNewClientPromptRequest(const QString &clientName);
void updateIpLabel(const QStringList &addresses);
void updateTimeoutDelay(int newDelay);
diff --git a/src/lib/gui/Messages.cpp b/src/lib/gui/Messages.cpp
index 7a81df80aa12..e9ca50cde9e7 100644
--- a/src/lib/gui/Messages.cpp
+++ b/src/lib/gui/Messages.cpp
@@ -184,9 +184,10 @@ void showFirstConnectedMessage(QWidget *parent)
QMessageBox::information(parent, title, message);
}
-bool showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth)
+bool showNewClientPrompt(QWidget *parent, const QString &clientName)
{
- if (serverRequiresPeerAuth) {
+ if (Settings::value(Settings::Security::TlsEnabled).toBool() &&
+ Settings::value(Settings::Security::CheckPeers).toBool()) {
// When peer auth is enabled you will be prompted to allow the connection before seeing this dialog.
// This is why we do not show a dialog with an option to ignore the new client
QMessageBox::information(
diff --git a/src/lib/gui/Messages.h b/src/lib/gui/Messages.h
index d2bb88c8711c..858887e0e016 100644
--- a/src/lib/gui/Messages.h
+++ b/src/lib/gui/Messages.h
@@ -25,7 +25,7 @@ void showFirstConnectedMessage(QWidget *parent);
void showCloseReminder(QWidget *parent);
-bool showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth = false);
+bool showNewClientPrompt(QWidget *parent, const QString &clientName);
bool showClearSettings(QWidget *parent);
diff --git a/src/lib/gui/core/ServerConnection.cpp b/src/lib/gui/core/ServerConnection.cpp
index 94baa2ef17e8..f1ba9357d1c4 100644
--- a/src/lib/gui/core/ServerConnection.cpp
+++ b/src/lib/gui/core/ServerConnection.cpp
@@ -82,9 +82,7 @@ void ServerConnection::handleNewClient(const QString &clientName)
}
m_messageShowing = true;
- const bool tlsEnabled = Settings::value(Settings::Security::TlsEnabled).toBool();
- const bool requireCerts = Settings::value(Settings::Security::CheckPeers).toBool();
- Q_EMIT requestNewClientPrompt(clientName, tlsEnabled && requireCerts);
+ Q_EMIT requestNewClientPrompt(clientName);
}
void ServerConnection::handleNewClientResult(const QString &clientName, bool acceptClient)
diff --git a/src/lib/gui/core/ServerConnection.h b/src/lib/gui/core/ServerConnection.h
index 8fa698649e25..fa656479f051 100644
--- a/src/lib/gui/core/ServerConnection.h
+++ b/src/lib/gui/core/ServerConnection.h
@@ -31,7 +31,7 @@ class ServerConnection : public QObject
void handleNewClientResult(const QString &clientName, bool acceptClient);
Q_SIGNALS:
- void requestNewClientPrompt(const QString &clientName, bool peerAuthRequired);
+ void requestNewClientPrompt(const QString &clientName);
void configureClient(const QString &clientName);
void clientsChanged(const QStringList &clients);
From 8a77e5f1301a298dac3c8261b07008e8fd0526ab Mon Sep 17 00:00:00 2001
From: Nick Bolton
Date: Fri, 5 Dec 2025 18:09:25 +0000
Subject: [PATCH 05/24] refactor(core): Convert app to Qt app
---
src/apps/deskflow-core/deskflow-core.cpp | 35 +++++++---
src/lib/deskflow/App.cpp | 89 +++++++++++++++---------
src/lib/deskflow/App.h | 9 ++-
3 files changed, 87 insertions(+), 46 deletions(-)
diff --git a/src/apps/deskflow-core/deskflow-core.cpp b/src/apps/deskflow-core/deskflow-core.cpp
index 052b380e8a84..e4d1b37ea028 100644
--- a/src/apps/deskflow-core/deskflow-core.cpp
+++ b/src/apps/deskflow-core/deskflow-core.cpp
@@ -1,7 +1,7 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello
- * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
+ * SPDX-FileCopyrightText: (C) 2012 - 2016, 2025 - 2026 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@@ -21,15 +21,27 @@
#include
#endif
+#include
#include
#include
#include
+#include
void showHelp(const CoreArgParser &parser)
{
QTextStream(stdout) << parser.helpText();
}
+App *createApp(const CoreArgParser &parser, EventQueue &events, const QString &processName)
+{
+ if (parser.serverMode()) {
+ return new ServerApp(&events, processName);
+ } else if (parser.clientMode()) {
+ return new ClientApp(&events, processName);
+ }
+ return nullptr;
+}
+
int main(int argc, char **argv)
{
#if defined(Q_OS_WIN)
@@ -86,13 +98,18 @@ int main(int argc, char **argv)
EventQueue events;
const auto processName = QFileInfo(argv[0]).fileName();
- if (parser.serverMode()) {
- ServerApp app(&events, processName);
- return app.run();
- } else if (parser.clientMode()) {
- ClientApp app(&events, processName);
- return app.run();
- }
+ App *coreApp = createApp(parser, events, processName);
+
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationName(QStringLiteral("%1 Core").arg(kAppName));
+
+ QThread coreThread;
+ QObject::connect(&coreThread, &QThread::finished, &app, &QCoreApplication::quit);
+ coreApp->run(coreThread);
+
+ const auto exitCode = QCoreApplication::exec();
+ coreThread.wait();
- return s_exitSuccess;
+ LOG_DEBUG("core exited, code: %d", exitCode);
+ return exitCode;
}
diff --git a/src/lib/deskflow/App.cpp b/src/lib/deskflow/App.cpp
index 4548960672cd..f6e23b60aab2 100644
--- a/src/lib/deskflow/App.cpp
+++ b/src/lib/deskflow/App.cpp
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
+ * SPDX-FileCopyrightText: (C) 2012 - 2026 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@@ -57,48 +57,69 @@ App::~App()
s_instance = nullptr;
}
-int App::run()
+void App::run(QThread &coreThread)
{
+ LOG_NOTE("starting core");
+
+ // Important: Move the daemon app to the daemon thread before creating any more Qt objects
+ // owned by the daemon app, as they will be created on the daemon thread.
+ moveToThread(&coreThread);
+
+ connect(&coreThread, &QThread::started, this, [this, &coreThread]() {
+ LOG_DEBUG("core thread started");
+
#if MAC_OS_X_VERSION_10_7
- // dock hide only supported on lion :(
- ProcessSerialNumber psn = {0, kCurrentProcess};
+ // dock hide only supported on lion :(
+ ProcessSerialNumber psn = {0, kCurrentProcess};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- GetCurrentProcess(&psn);
+ GetCurrentProcess(&psn);
#pragma GCC diagnostic pop
- TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
+ TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
#endif
- // install application in to arch
- appUtil().adoptApp(this);
-
- // HACK: fail by default (saves us setting result in each catch)
- int result = s_exitFailed;
-
- try {
- result = appUtil().run();
- } catch (ExitAppException &e) {
- // instead of showing a nasty error, just exit with the error code.
- // not sure if i like this behaviour, but it's probably better than
- // using the exit(int) function!
- result = e.getCode();
- } catch (DisplayInvalidException &die) {
- LOG_CRIT("a display invalid exception error occurred: %s\n", die.what());
- // display invalid exceptions can occur when going to sleep. When this
- // process exits, the UI will restart us instantly. We don't really want
- // that behevior, so we quies for a bit
- Arch::sleep(10);
- } catch (std::runtime_error &re) {
- LOG_CRIT("a runtime error occurred: %s\n", re.what());
- } catch (std::exception &e) {
- LOG_CRIT("an error occurred: %s\n", e.what());
- } catch (...) {
- LOG_CRIT("an unknown error occurred\n");
- }
-
- return result;
+ // install application in to arch
+ appUtil().adoptApp(this);
+
+ // HACK: fail by default (saves us setting result in each catch)
+ int result = s_exitFailed;
+
+ try {
+ result = appUtil().run();
+ } catch (ExitAppException &e) {
+ // instead of showing a nasty error, just exit with the error code.
+ // not sure if i like this behaviour, but it's probably better than
+ // using the exit(int) function!
+ result = e.getCode();
+ } catch (DisplayInvalidException &die) {
+ LOG_CRIT("a display invalid exception error occurred: %s\n", die.what());
+ // display invalid exceptions can occur when going to sleep. When this
+ // process exits, the UI will restart us instantly. We don't really want
+ // that behevior, so we quies for a bit
+ Arch::sleep(10);
+ } catch (std::runtime_error &re) {
+ LOG_CRIT("a runtime error occurred: %s\n", re.what());
+ } catch (std::exception &e) {
+ LOG_CRIT("an error occurred: %s\n", e.what());
+ } catch (...) {
+ LOG_CRIT("an unknown error occurred\n");
+ }
+
+ if (result == s_exitSuccess) {
+ LOG_INFO("core stopped successfully");
+ } else {
+ // TODO: surface error code to main thread somehow
+ LOG_ERR("core stopped with error code: %d", result);
+ }
+
+ coreThread.quit();
+ LOG_DEBUG("core thread finished");
+ });
+
+ LOG_DEBUG("starting core thread");
+ coreThread.start();
}
void App::setupFileLogging()
diff --git a/src/lib/deskflow/App.h b/src/lib/deskflow/App.h
index 52baded3f304..c3846d8fe0dc 100644
--- a/src/lib/deskflow/App.h
+++ b/src/lib/deskflow/App.h
@@ -1,7 +1,7 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
- * SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
+ * SPDX-FileCopyrightText: (C) 2012 - 2026 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@@ -19,6 +19,9 @@
#include "deskflow/unix/AppUtilUnix.h"
#endif
+#include
+#include
+
#include
#include
@@ -30,7 +33,7 @@ class FileLogOutputter;
class IEventQueue;
class SocketMultiplexer;
-class App : public IApp
+class App : public QObject, private IApp
{
public:
class XNoEiSupport : public std::runtime_error
@@ -72,7 +75,7 @@ class App : public IApp
return m_appUtil;
}
- int run();
+ void run(QThread &coreThread);
void setupFileLogging();
void loggingFilterWarning() const;
void initApp() override;
From 29352d97b3ebf709258332c4d2cf69eac933f73f Mon Sep 17 00:00:00 2001
From: Nick Bolton
Date: Thu, 26 Mar 2026 15:00:26 +0000
Subject: [PATCH 06/24] fix(core): Destroy temporary QCoreApplication before
creating the real one
---
src/apps/deskflow-core/deskflow-core.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/apps/deskflow-core/deskflow-core.cpp b/src/apps/deskflow-core/deskflow-core.cpp
index e4d1b37ea028..3da8edd3d8b7 100644
--- a/src/apps/deskflow-core/deskflow-core.cpp
+++ b/src/apps/deskflow-core/deskflow-core.cpp
@@ -45,9 +45,10 @@ App *createApp(const CoreArgParser &parser, EventQueue &events, const QString &p
int main(int argc, char **argv)
{
#if defined(Q_OS_WIN)
- // HACK to make sure settings gets the correct qApp path
- QCoreApplication m(argc, argv);
- m.deleteLater();
+ {
+ // HACK to make sure settings gets the correct qApp path
+ QCoreApplication m(argc, argv);
+ }
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
#endif
From aaef600ffa538f775a9dfff74d61516a6d8a8013 Mon Sep 17 00:00:00 2001
From: Nick Bolton
Date: Mon, 30 Mar 2026 19:08:08 +0100
Subject: [PATCH 07/24] fix(mac): Remove Cocoa app loop and fix macOS event tap
for Qt threading
---
src/lib/deskflow/App.cpp | 4 ----
src/lib/deskflow/ClientApp.cpp | 13 -------------
src/lib/deskflow/ServerApp.cpp | 14 --------------
src/lib/platform/OSXEventQueueBuffer.cpp | 15 +++++----------
src/lib/platform/OSXEventQueueBuffer.h | 1 -
src/lib/platform/OSXScreen.h | 3 +++
src/lib/platform/OSXScreen.mm | 24 ++++++++++++++++++++++--
7 files changed, 30 insertions(+), 44 deletions(-)
diff --git a/src/lib/deskflow/App.cpp b/src/lib/deskflow/App.cpp
index f6e23b60aab2..36a00b6f74d8 100644
--- a/src/lib/deskflow/App.cpp
+++ b/src/lib/deskflow/App.cpp
@@ -23,7 +23,6 @@
#include
#if defined(Q_OS_MAC)
-#include "platform/OSXCocoaApp.h"
#include
#endif
@@ -172,7 +171,4 @@ void App::handleScreenError() const
void App::runEventsLoop(const void *)
{
m_events->loop();
-#if defined(Q_OS_MAC)
- stopCocoaLoop();
-#endif
}
diff --git a/src/lib/deskflow/ClientApp.cpp b/src/lib/deskflow/ClientApp.cpp
index 7dcbf131b68c..08cce6d1bc93 100644
--- a/src/lib/deskflow/ClientApp.cpp
+++ b/src/lib/deskflow/ClientApp.cpp
@@ -37,9 +37,6 @@
#endif
#if defined(Q_OS_MAC)
-#include "base/TMethodJob.h"
-#include "mt/Thread.h"
-#include "platform/OSXCocoaApp.h"
#include "platform/OSXScreen.h"
#endif
@@ -330,17 +327,7 @@ int ClientApp::mainLoop()
// later. the timer installed by startClient() will take care of
// that.
-#if defined(Q_OS_MAC)
- Thread thread(new TMethodJob(this, &ClientApp::runEventsLoop, nullptr));
-
- // wait until carbon loop is ready
- OSXScreen *screen = dynamic_cast(m_clientScreen->getPlatformScreen());
- screen->waitForCarbonLoop();
-
- runCocoaApp();
-#else
getEvents()->loop();
-#endif
// close down
LOG_DEBUG("stopping client");
diff --git a/src/lib/deskflow/ServerApp.cpp b/src/lib/deskflow/ServerApp.cpp
index 15c27a480019..3b5c2e58bc24 100644
--- a/src/lib/deskflow/ServerApp.cpp
+++ b/src/lib/deskflow/ServerApp.cpp
@@ -43,9 +43,6 @@
#endif
#if defined(Q_OS_MAC)
-#include "base/TMethodJob.h"
-#include "mt/Thread.h"
-#include "platform/OSXCocoaApp.h"
#include "platform/OSXScreen.h"
#endif
@@ -541,18 +538,7 @@ int ServerApp::mainLoop()
// later. the timer installed by startServer() will take care of
// that.
-#if defined(Q_OS_MAC)
-
- Thread thread(new TMethodJob(this, &ServerApp::runEventsLoop, nullptr));
-
- // wait until carbon loop is ready
- OSXScreen *screen = dynamic_cast(m_serverScreen->getPlatformScreen());
- screen->waitForCarbonLoop();
-
- runCocoaApp();
-#else
getEvents()->loop();
-#endif
// close down
LOG_DEBUG("stopping server");
diff --git a/src/lib/platform/OSXEventQueueBuffer.cpp b/src/lib/platform/OSXEventQueueBuffer.cpp
index 9389e4ef9e62..ada237c92ae4 100644
--- a/src/lib/platform/OSXEventQueueBuffer.cpp
+++ b/src/lib/platform/OSXEventQueueBuffer.cpp
@@ -58,16 +58,11 @@ IEventQueueBuffer::Type OSXEventQueueBuffer::getEvent(Event &event, uint32_t &da
bool OSXEventQueueBuffer::addEvent(uint32_t dataID)
{
- // Use GCD to dispatch event addition on the main queue
- dispatch_async(dispatch_get_main_queue(), ^{
- std::scoped_lock lock{this->m_mutex};
- LOG_DEBUG2("adding user event with dataID: %u", dataID);
- this->m_dataQueue.push(dataID);
- this->m_cond.notify_one();
- LOG_DEBUG2("user event added to queue, dataID=%u", dataID);
- });
-
- // Always return true since dispatch_async does not fail under normal conditions
+ std::scoped_lock lock{m_mutex};
+ LOG_DEBUG2("adding user event with dataID: %u", dataID);
+ m_dataQueue.push(dataID);
+ m_cond.notify_one();
+ LOG_DEBUG2("user event added to queue, dataID=%u", dataID);
return true;
}
diff --git a/src/lib/platform/OSXEventQueueBuffer.h b/src/lib/platform/OSXEventQueueBuffer.h
index 0057aa2ebe27..02efcfed69e8 100644
--- a/src/lib/platform/OSXEventQueueBuffer.h
+++ b/src/lib/platform/OSXEventQueueBuffer.h
@@ -12,7 +12,6 @@
#include "base/IEventQueueBuffer.h"
#include
-#include
#include
#include
diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h
index 87b5f4f5b170..37c48da29a4d 100644
--- a/src/lib/platform/OSXScreen.h
+++ b/src/lib/platform/OSXScreen.h
@@ -21,6 +21,7 @@
#include
#include
Keyboard layout support requires matching layouts on all computers. "
+ "The following layouts from the other computer are not installed on this computer:
"
+ "
%1
"
+ "
Please install them to enable support for these layouts.
")
+ .arg(layouts));
+
+ auto *checkBox = new QCheckBox(tr("Don't show this again"), &msgBox);
+ msgBox.setCheckBox(checkBox);
+ msgBox.exec();
+
+ if (checkBox->isChecked()) {
+ Settings::setValue(Settings::Gui::IgnoreMissingKeyboardLayouts, true);
+ }
+}
+
void MainWindow::handlePeerFingerprint(const QString &fingerprint)
{
const auto sha256Text = QString(fingerprint).remove(':');
diff --git a/src/lib/gui/MainWindow.h b/src/lib/gui/MainWindow.h
index fbac2fcc8782..1ec5d97f6767 100644
--- a/src/lib/gui/MainWindow.h
+++ b/src/lib/gui/MainWindow.h
@@ -119,6 +119,7 @@ class MainWindow : public QMainWindow
void handleUnrecognisedClient(const QString &clientName);
void handleConnectionRefused(deskflow::core::ConnectionRefusal reason);
void handlePeerFingerprint(const QString &fingerprint);
+ void handleMissingKeyboardLayouts(const QString &layouts);
void closeEvent(QCloseEvent *event) override;
void secureSocket(bool secureSocket);
void connectSlots();
diff --git a/src/lib/gui/core/CoreProcess.cpp b/src/lib/gui/core/CoreProcess.cpp
index 935f36081c00..ef634dfef331 100644
--- a/src/lib/gui/core/CoreProcess.cpp
+++ b/src/lib/gui/core/CoreProcess.cpp
@@ -564,6 +564,8 @@ void CoreProcess::onCoreIpcMessageReceived(const QString &command, const QString
Q_EMIT retryIn(args.toInt());
} else if (command == "peerFingerprint") {
Q_EMIT peerFingerprint(args);
+ } else if (command == "missingKeyboardLayouts") {
+ Q_EMIT missingKeyboardLayouts(args);
}
}
diff --git a/src/lib/gui/core/CoreProcess.h b/src/lib/gui/core/CoreProcess.h
index 45cfa34bea8e..71cebca01360 100644
--- a/src/lib/gui/core/CoreProcess.h
+++ b/src/lib/gui/core/CoreProcess.h
@@ -93,6 +93,7 @@ class CoreProcess : public QObject
void connectionRefused(deskflow::core::ConnectionRefusal reason);
void retryIn(int seconds);
void peerFingerprint(const QString &fingerprint);
+ void missingKeyboardLayouts(const QString &layouts);
private Q_SLOTS:
void onProcessFinished(int exitCode, QProcess::ExitStatus);
diff --git a/translations/deskflow_es.ts b/translations/deskflow_es.ts
index 05dc0f82fbc7..f4d9e94c4594 100644
--- a/translations/deskflow_es.ts
+++ b/translations/deskflow_es.ts
@@ -559,6 +559,18 @@ Additionally, check you are able to %1 the server config file: %2
Además, verifique que puede %1 el archivo de configuración del servidor: %2
+
+ Don't show this again
+
+
+
+ Missing Keyboard Layouts
+
+
+
+ <p>Keyboard layout support requires matching layouts on all computers. The following layouts from the other computer are not installed on this computer:</p><p><b>%1</b></p><p>Please install them to enable support for these layouts.</p>
+
+ NewScreenWidget
diff --git a/translations/deskflow_it.ts b/translations/deskflow_it.ts
index f58928c6ce27..7620a385603a 100644
--- a/translations/deskflow_it.ts
+++ b/translations/deskflow_it.ts
@@ -559,6 +559,18 @@ Additionally, check you are able to %1 the server config file: %2
Inoltre, verifica di poter %1 il file di configurazione del server: %2
+
+ Don't show this again
+
+
+
+ Missing Keyboard Layouts
+
+
+
+ <p>Keyboard layout support requires matching layouts on all computers. The following layouts from the other computer are not installed on this computer:</p><p><b>%1</b></p><p>Please install them to enable support for these layouts.</p>
+
+ NewScreenWidget
diff --git a/translations/deskflow_ja.ts b/translations/deskflow_ja.ts
index 1484e003d83b..decc3c314f8e 100644
--- a/translations/deskflow_ja.ts
+++ b/translations/deskflow_ja.ts
@@ -559,6 +559,18 @@ Additionally, check you are able to %1 the server config file: %2
また、サーバー設定ファイルを%1できることを確認してください: %2
+
+ Don't show this again
+
+
+
+ Missing Keyboard Layouts
+
+
+
+ <p>Keyboard layout support requires matching layouts on all computers. The following layouts from the other computer are not installed on this computer:</p><p><b>%1</b></p><p>Please install them to enable support for these layouts.</p>
+
+ NewScreenWidget
diff --git a/translations/deskflow_ko.ts b/translations/deskflow_ko.ts
index e96f0cdbb3a2..b1e1bdecf48f 100644
--- a/translations/deskflow_ko.ts
+++ b/translations/deskflow_ko.ts
@@ -559,6 +559,18 @@ Additionally, check you are able to %1 the server config file: %2
또한 서버 구성 파일을 %1할 수 있는지 확인하세요: %2
+
+ Don't show this again
+
+
+
+ Missing Keyboard Layouts
+
+
+
+ <p>Keyboard layout support requires matching layouts on all computers. The following layouts from the other computer are not installed on this computer:</p><p><b>%1</b></p><p>Please install them to enable support for these layouts.</p>
+
+ NewScreenWidget
diff --git a/translations/deskflow_ru.ts b/translations/deskflow_ru.ts
index 0f6f316aaf0a..de4223837eb0 100644
--- a/translations/deskflow_ru.ts
+++ b/translations/deskflow_ru.ts
@@ -559,6 +559,18 @@ Additionally, check you are able to %1 the server config file: %2
Также убедитесь, что вы можете %1 файл конфигурации сервера: %2
+
+ Don't show this again
+
+
+
+ Missing Keyboard Layouts
+
+
+
+ <p>Keyboard layout support requires matching layouts on all computers. The following layouts from the other computer are not installed on this computer:</p><p><b>%1</b></p><p>Please install them to enable support for these layouts.</p>
+
+ NewScreenWidget
diff --git a/translations/deskflow_zh_CN.ts b/translations/deskflow_zh_CN.ts
index cd9fdf2c0f57..30a3384a84e8 100644
--- a/translations/deskflow_zh_CN.ts
+++ b/translations/deskflow_zh_CN.ts
@@ -559,6 +559,18 @@ Additionally, check you are able to %1 the server config file: %2
另外,请检查您是否能够%1服务器配置文件:%2
+
+ Don't show this again
+
+
+
+ Missing Keyboard Layouts
+
+
+
+ <p>Keyboard layout support requires matching layouts on all computers. The following layouts from the other computer are not installed on this computer:</p><p><b>%1</b></p><p>Please install them to enable support for these layouts.</p>
+
+ NewScreenWidget
From 25f3eb3f229e9c934e319c3d68623ba81201eda6 Mon Sep 17 00:00:00 2001
From: Nick Bolton
Date: Tue, 31 Mar 2026 10:06:00 +0100
Subject: [PATCH 17/24] feat(ipc): Differentiate between Daemon and Core IPC
logs
---
src/lib/deskflow/ipc/CoreIpcServer.cpp | 2 +-
src/lib/deskflow/ipc/DaemonIpcServer.cpp | 2 +-
src/lib/deskflow/ipc/IpcServer.cpp | 55 +++++++++++++-----------
src/lib/deskflow/ipc/IpcServer.h | 3 +-
src/lib/gui/ipc/CoreIpcClient.cpp | 2 +-
src/lib/gui/ipc/DaemonIpcClient.cpp | 2 +-
src/lib/gui/ipc/IpcClient.cpp | 46 +++++++++++---------
src/lib/gui/ipc/IpcClient.h | 3 +-
8 files changed, 65 insertions(+), 50 deletions(-)
diff --git a/src/lib/deskflow/ipc/CoreIpcServer.cpp b/src/lib/deskflow/ipc/CoreIpcServer.cpp
index 4ead60f9f8d9..f73f726316c6 100644
--- a/src/lib/deskflow/ipc/CoreIpcServer.cpp
+++ b/src/lib/deskflow/ipc/CoreIpcServer.cpp
@@ -15,7 +15,7 @@ namespace deskflow::core::ipc {
static CoreIpcServer *s_instance = nullptr;
-CoreIpcServer::CoreIpcServer(QObject *parent) : IpcServer(parent, kCoreIpcName)
+CoreIpcServer::CoreIpcServer(QObject *parent) : IpcServer(parent, kCoreIpcName, "core")
{
assert(s_instance == nullptr);
s_instance = this;
diff --git a/src/lib/deskflow/ipc/DaemonIpcServer.cpp b/src/lib/deskflow/ipc/DaemonIpcServer.cpp
index 366151a4129e..9d34eabca966 100644
--- a/src/lib/deskflow/ipc/DaemonIpcServer.cpp
+++ b/src/lib/deskflow/ipc/DaemonIpcServer.cpp
@@ -17,7 +17,7 @@ const auto kAckMessage = "ok";
const auto kErrorMessage = "error";
DaemonIpcServer::DaemonIpcServer(QObject *parent, const QString &logFilename)
- : IpcServer(parent, kDaemonIpcName),
+ : IpcServer(parent, kDaemonIpcName, "daemon"),
m_logFilename(logFilename)
{
// do nothing
diff --git a/src/lib/deskflow/ipc/IpcServer.cpp b/src/lib/deskflow/ipc/IpcServer.cpp
index 39eff2971a94..39c622add335 100644
--- a/src/lib/deskflow/ipc/IpcServer.cpp
+++ b/src/lib/deskflow/ipc/IpcServer.cpp
@@ -14,10 +14,11 @@
namespace deskflow::core::ipc {
-IpcServer::IpcServer(QObject *parent, const QString &serverName)
+IpcServer::IpcServer(QObject *parent, const QString &serverName, const QString &typeName)
: QObject(parent),
m_server{new QLocalServer(this)}, // NOSONAR - Qt memory
- m_serverName(serverName)
+ m_serverName(serverName),
+ m_typeName(typeName.toUtf8())
{
// do nothing
}
@@ -35,9 +36,9 @@ void IpcServer::listen()
connect(m_server, &QLocalServer::newConnection, this, &IpcServer::handleNewConnection);
QLocalServer::removeServer(m_serverName);
if (m_server->listen(m_serverName)) {
- LOG_DEBUG("ipc server listening on: %s", m_serverName.toUtf8().constData());
+ LOG_DEBUG("%s ipc server listening on: %s", m_typeName.constData(), m_serverName.toUtf8().constData());
} else {
- LOG_ERR("ipc server failed to listen on: %s", m_serverName.toUtf8().constData());
+ LOG_ERR("%s ipc server failed to listen on: %s", m_typeName.constData(), m_serverName.toUtf8().constData());
}
}
@@ -45,11 +46,11 @@ void IpcServer::handleNewConnection()
{
QLocalSocket *clientSocket = m_server->nextPendingConnection();
if (!clientSocket) {
- LOG_ERR("ipc server failed to get new connection");
+ LOG_ERR("%s ipc server failed to get new connection", m_typeName.constData());
return;
}
- LOG_DEBUG("ipc server got new connection");
+ LOG_DEBUG("%s ipc server got new connection", m_typeName.constData());
m_clients.insert(clientSocket);
connect(clientSocket, &QLocalSocket::readyRead, this, &IpcServer::handleReadyRead);
@@ -60,17 +61,17 @@ void IpcServer::handleNewConnection()
void IpcServer::handleReadyRead()
{
const auto clientSocket = qobject_cast(sender());
- LOG_DEBUG1("ipc server ready to read data");
+ LOG_DEBUG1("%s ipc server ready to read data", m_typeName.constData());
QByteArray data = clientSocket->readAll();
if (data.isEmpty()) {
- LOG_WARN("ipc server got empty message");
+ LOG_WARN("%s ipc server got empty message", m_typeName.constData());
return;
}
// we don't handle incomplete messages yet; each socket read must have delimiters.
if (!data.contains('\n')) {
- LOG_WARN("ipc server got incomplete message: %s", data.constData());
+ LOG_WARN("%s ipc server got incomplete message: %s", m_typeName.constData(), data.constData());
return;
}
@@ -87,7 +88,7 @@ void IpcServer::handleReadyRead()
void IpcServer::handleDisconnected()
{
const auto clientSocket = qobject_cast(sender());
- LOG_DEBUG("ipc server client disconnected");
+ LOG_DEBUG("%s ipc server client disconnected", m_typeName.constData());
m_clients.remove(clientSocket);
clientSocket->deleteLater();
}
@@ -95,17 +96,17 @@ void IpcServer::handleDisconnected()
void IpcServer::handleErrorOccurred()
{
const auto clientSocket = qobject_cast(sender());
- LOG_ERR("ipc server client error: %s", clientSocket->errorString().toUtf8().constData());
+ LOG_ERR("%s ipc server client error: %s", m_typeName.constData(), clientSocket->errorString().toUtf8().constData());
m_clients.remove(clientSocket);
clientSocket->deleteLater();
}
void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &message)
{
- LOG_DEBUG1("ipc server got message: %s", message.toUtf8().constData());
+ LOG_DEBUG1("%s ipc server got message: %s", m_typeName.constData(), message.toUtf8().constData());
const auto parts = message.split('=');
if (parts.isEmpty()) {
- LOG_ERR("ipc server got invalid message: %s", message.toUtf8().constData());
+ LOG_ERR("%s ipc server got invalid message: %s", m_typeName.constData(), message.toUtf8().constData());
writeToClientSocket(clientSocket, "error");
return;
}
@@ -113,29 +114,28 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
if (const auto &command = parts.at(0); command == "hello") {
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
const auto clientVersion = parts.size() >= 2 ? parts.at(1) : QString();
+ LOG_DEBUG("%s ipc server got hello message (version: %s)", m_typeName.constData(), versionId.toUtf8().constData());
+
if (clientVersion != versionId) {
- LOG_ERR(
- "ipc client version mismatch (client: %s, server: %s)",
- clientVersion.isEmpty() ? "unknown" : clientVersion.toUtf8().constData(), versionId.toUtf8().constData()
- );
+ LOG_ERR("%s ipc client version mismatch (server: %s)", m_typeName.constData(), versionId.toUtf8().constData());
writeToClientSocket(clientSocket, "error");
clientSocket->flush();
clientSocket->disconnectFromServer();
return;
}
- LOG_DEBUG("ipc server got hello message, sending hello back");
+ LOG_DEBUG("%s ipc server sending hello back", m_typeName.constData());
writeToClientSocket(clientSocket, QString("hello=%1").arg(versionId));
// Replay messages that were queued before any clients connected.
LOG_DEBUG1("ipc server replaying %d pending messages", m_pendingMessages.size());
for (const auto &pending : std::as_const(m_pendingMessages)) {
- LOG_DEBUG1("ipc server replaying: %s", pending.toUtf8().constData());
+ LOG_DEBUG1("%s ipc server replaying: %s", m_typeName.constData(), pending.toUtf8().constData());
writeToClientSocket(clientSocket, pending);
}
m_pendingMessages.clear();
} else if (command == "noop") {
- LOG_DEBUG("ipc server got noop message");
+ LOG_DEBUG("%s ipc server got noop message", m_typeName.constData());
writeToClientSocket(clientSocket, "ok");
} else {
processCommand(clientSocket, command, parts);
@@ -149,12 +149,17 @@ void IpcServer::broadcastCommand(const QString &command, const QString &args)
const auto message = args.isEmpty() ? command : command + "=" + args;
if (m_clients.isEmpty()) {
- LOG_DEBUG1("ipc server has no clients, message queued: %s", message.toUtf8().constData());
+ LOG_DEBUG1(
+ "%s ipc server has no clients, message queued: %s", m_typeName.constData(), message.toUtf8().constData()
+ );
m_pendingMessages.append(message);
return;
}
- LOG_DEBUG1("ipc server broadcasting message to %d clients: %s", m_clients.size(), message.toUtf8().constData());
+ LOG_DEBUG1(
+ "%s ipc server broadcasting message to %d clients: %s", m_typeName.constData(), m_clients.size(),
+ message.toUtf8().constData()
+ );
for (auto *client : std::as_const(m_clients)) {
writeToClientSocket(client, message);
client->flush();
@@ -166,9 +171,11 @@ void IpcServer::writeToClientSocket(QLocalSocket *&clientSocket, const QString &
QByteArray messageData = message.toUtf8() + '\n';
qint64 bytesWritten = clientSocket->write(messageData);
if (bytesWritten != messageData.size()) {
- LOG_ERR("ipc server failed to write full message to client socket");
+ LOG_ERR("%s ipc server failed to write full message to client socket", m_typeName.constData());
} else {
- LOG_DEBUG1("ipc server wrote message to client socket: %s", message.toUtf8().constData());
+ LOG_DEBUG1(
+ "%s ipc server wrote message to client socket: %s", m_typeName.constData(), message.toUtf8().constData()
+ );
}
}
diff --git a/src/lib/deskflow/ipc/IpcServer.h b/src/lib/deskflow/ipc/IpcServer.h
index 3e2a874b9ef0..e26000a699fe 100644
--- a/src/lib/deskflow/ipc/IpcServer.h
+++ b/src/lib/deskflow/ipc/IpcServer.h
@@ -19,7 +19,7 @@ class IpcServer : public QObject
Q_OBJECT
public:
- explicit IpcServer(QObject *parent, const QString &serverName);
+ explicit IpcServer(QObject *parent, const QString &serverName, const QString &typeName);
~IpcServer() override;
void listen();
@@ -54,6 +54,7 @@ class IpcServer : public QObject
QSet m_clients;
QString m_serverName;
QStringList m_pendingMessages;
+ QByteArray m_typeName;
};
} // namespace deskflow::core::ipc
diff --git a/src/lib/gui/ipc/CoreIpcClient.cpp b/src/lib/gui/ipc/CoreIpcClient.cpp
index 047761efdd08..ccfa2ed5ecd6 100644
--- a/src/lib/gui/ipc/CoreIpcClient.cpp
+++ b/src/lib/gui/ipc/CoreIpcClient.cpp
@@ -15,7 +15,7 @@
namespace deskflow::gui::ipc {
-CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName)
+CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName, "core")
{
// do nothing
}
diff --git a/src/lib/gui/ipc/DaemonIpcClient.cpp b/src/lib/gui/ipc/DaemonIpcClient.cpp
index 124967eac37d..454d8f354fd2 100644
--- a/src/lib/gui/ipc/DaemonIpcClient.cpp
+++ b/src/lib/gui/ipc/DaemonIpcClient.cpp
@@ -12,7 +12,7 @@
namespace deskflow::gui::ipc {
-DaemonIpcClient::DaemonIpcClient(QObject *parent) : IpcClient(parent, kDaemonIpcName)
+DaemonIpcClient::DaemonIpcClient(QObject *parent) : IpcClient(parent, kDaemonIpcName, "daemon")
{
}
diff --git a/src/lib/gui/ipc/IpcClient.cpp b/src/lib/gui/ipc/IpcClient.cpp
index 644d9470588c..19af227bc8e0 100644
--- a/src/lib/gui/ipc/IpcClient.cpp
+++ b/src/lib/gui/ipc/IpcClient.cpp
@@ -14,10 +14,11 @@
namespace deskflow::gui::ipc {
-IpcClient::IpcClient(QObject *parent, const QString &socketName)
+IpcClient::IpcClient(QObject *parent, const QString &socketName, const QString &typeName)
: QObject(parent),
m_socket{new QLocalSocket(this)},
- m_socketName(socketName) // NOSONAR - Qt memory
+ m_socketName(socketName), // NOSONAR - Qt memory
+ m_typeName(typeName)
{
connect(m_socket, &QLocalSocket::disconnected, this, &IpcClient::handleDisconnected);
connect(m_socket, &QLocalSocket::errorOccurred, this, &IpcClient::handleErrorOccurred);
@@ -27,17 +28,18 @@ IpcClient::IpcClient(QObject *parent, const QString &socketName)
void IpcClient::connectToServer()
{
if (m_state == State::Connecting) {
- qWarning() << "ipc client already connecting to server";
+ qWarning().noquote() << QStringLiteral("%1 ipc client already connecting to server").arg(m_typeName);
return;
}
if (m_state != State::Unconnected) {
- qDebug() << "ipc client not in unconnected state, disconnecting";
+ qDebug().noquote() << QStringLiteral("%1 ipc client not in unconnected state, disconnecting").arg(m_typeName);
disconnectFromServer();
}
if (m_socket->state() != QLocalSocket::UnconnectedState) {
- qWarning() << "ipc client socket not in unconnected state, disconnecting";
+ qWarning().noquote(
+ ) << QStringLiteral("%1 ipc client socket not in unconnected state, disconnecting").arg(m_typeName);
disconnectFromServer();
}
@@ -50,16 +52,18 @@ void IpcClient::attemptConnection()
const auto kRetryLimit = 3;
if (m_retryCount >= kRetryLimit) {
- qWarning() << "ipc client failed to connect after" << kRetryLimit << "attempts";
+ qWarning().noquote() << QStringLiteral("%1 ipc client failed to connect after %2 attempts")
+ .arg(m_typeName, QString::number(kRetryLimit));
m_state = State::Unconnected;
Q_EMIT connectionFailed();
return;
}
if (m_retryCount == 0) {
- qDebug() << "ipc client connecting to server:" << m_socketName;
+ qDebug().noquote() << QStringLiteral("%1 ipc client connecting to server: %2").arg(m_typeName, m_socketName);
} else {
- qDebug() << "ipc client retrying connection, attempt:" << m_retryCount + 1;
+ qDebug().noquote() << QStringLiteral("%1 ipc client retrying connection, attempt: %2")
+ .arg(m_typeName, QString::number(m_retryCount + 1));
}
m_state = State::Connecting;
@@ -69,8 +73,8 @@ void IpcClient::attemptConnection()
m_socket, &QLocalSocket::connected, this,
[this] {
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
- m_socket->write(QString("hello=%1\n").arg(versionId).toUtf8());
- qDebug() << "ipc client sent hello with version:" << versionId;
+ m_socket->write(QStringLiteral("hello=%1\n").arg(versionId).toUtf8());
+ qDebug().noquote() << QStringLiteral("%1 ipc client sent hello with version: %2").arg(m_typeName, versionId);
},
Qt::SingleShotConnection
);
@@ -78,7 +82,8 @@ void IpcClient::attemptConnection()
connect(
m_socket, &QLocalSocket::errorOccurred, this,
[this] {
- qWarning() << "ipc client failed to connect:" << m_socket->errorString();
+ qWarning().noquote(
+ ) << QStringLiteral("%1 ipc client failed to connect: %2").arg(m_typeName, m_socket->errorString());
m_socket->disconnectFromServer();
m_state = State::Unconnected;
QTimer::singleShot(0, this, &IpcClient::attemptConnection);
@@ -92,7 +97,7 @@ void IpcClient::attemptConnection()
void IpcClient::disconnectFromServer()
{
m_state = State::Disconnecting;
- qDebug() << "ipc client disconnecting from server";
+ qDebug().noquote() << QStringLiteral("%1 ipc client disconnecting from server").arg(m_typeName);
m_socket->disconnectFromServer();
m_state = State::Unconnected;
}
@@ -103,7 +108,7 @@ void IpcClient::handleDisconnected()
return;
}
- qDebug() << "ipc client disconnected from server";
+ qDebug().noquote() << QStringLiteral("%1 ipc client disconnected from server").arg(m_typeName);
const auto wasConnected = m_state == State::Connected;
m_state = State::Unconnected;
@@ -118,7 +123,7 @@ void IpcClient::handleErrorOccurred()
return;
}
- qWarning() << "ipc client error:" << m_socket->errorString();
+ qWarning().noquote() << QStringLiteral("%1 ipc client error: %2").arg(m_typeName, m_socket->errorString());
if (m_state == State::Connected) {
disconnectFromServer();
@@ -136,10 +141,10 @@ void IpcClient::handleReadyRead()
const auto message = QString::fromUtf8(data.left(index));
data.remove(0, index + 1);
- qDebug("ipc client message: %s", message.toUtf8().constData());
+ qDebug().noquote() << QStringLiteral("%1 ipc client message: %2").arg(m_typeName, message);
const auto parts = message.split('=');
if (parts.isEmpty()) {
- qWarning("ipc client got invalid message: %s", message.toUtf8().constData());
+ qWarning().noquote() << QStringLiteral("%1 ipc client got invalid message: %2").arg(m_typeName, message);
continue;
}
@@ -165,26 +170,27 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
const auto serverVersion = parts.size() >= 2 ? parts.at(1) : QString();
if (serverVersion != versionId) {
- qCritical() << "ipc version mismatch (client:" << versionId << "server:" << serverVersion << ")";
+ qCritical().noquote(
+ ) << QStringLiteral("%1 ipc version mismatch (client: %2 , server: %3)").arg(m_typeName, versionId, serverVersion);
disconnectFromServer();
Q_EMIT connectionFailed();
return;
}
m_state = State::Connected;
- qDebug() << "ipc client connected";
+ qDebug().noquote() << QStringLiteral("%1 ipc client connected").arg(m_typeName);
Q_EMIT connected();
}
void IpcClient::sendMessage(const QString &message)
{
if (m_state != State::Connected) {
- qWarning() << "cannot send command, ipc client not connected";
+ qWarning().noquote() << QStringLiteral("%1 cannot send command, ipc client not connected").arg(m_typeName);
return;
}
m_socket->write(message.toUtf8() + "\n");
- qDebug() << "ipc client sent message:" << message;
+ qDebug().noquote() << QStringLiteral("%1 ipc client sent message: %2").arg(m_typeName, message);
}
} // namespace deskflow::gui::ipc
diff --git a/src/lib/gui/ipc/IpcClient.h b/src/lib/gui/ipc/IpcClient.h
index 1f2b296d6db1..231b1600f064 100644
--- a/src/lib/gui/ipc/IpcClient.h
+++ b/src/lib/gui/ipc/IpcClient.h
@@ -26,7 +26,7 @@ class IpcClient : public QObject
};
public:
- explicit IpcClient(QObject *parent, const QString &socketName);
+ explicit IpcClient(QObject *parent, const QString &socketName, const QString &typeName);
void connectToServer();
void disconnectFromServer();
@@ -62,6 +62,7 @@ private Q_SLOTS:
QString m_socketName;
QByteArray m_readBuffer;
int m_retryCount{0};
+ QString m_typeName;
};
} // namespace deskflow::gui::ipc
From 77bee2ddf3af50be240d4fd09414062220dcf6be Mon Sep 17 00:00:00 2001
From: Nick Bolton
Date: Tue, 31 Mar 2026 10:24:59 +0100
Subject: [PATCH 18/24] feat(ipc): Log more detail on IPC error handling
---
src/lib/deskflow/ipc/IpcServer.cpp | 2 +-
src/lib/gui/ipc/IpcClient.cpp | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/lib/deskflow/ipc/IpcServer.cpp b/src/lib/deskflow/ipc/IpcServer.cpp
index 39c622add335..71607bcc6e64 100644
--- a/src/lib/deskflow/ipc/IpcServer.cpp
+++ b/src/lib/deskflow/ipc/IpcServer.cpp
@@ -118,7 +118,7 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
if (clientVersion != versionId) {
LOG_ERR("%s ipc client version mismatch (server: %s)", m_typeName.constData(), versionId.toUtf8().constData());
- writeToClientSocket(clientSocket, "error");
+ writeToClientSocket(clientSocket, QStringLiteral("error=version mismatch, expected: %1").arg(versionId));
clientSocket->flush();
clientSocket->disconnectFromServer();
return;
diff --git a/src/lib/gui/ipc/IpcClient.cpp b/src/lib/gui/ipc/IpcClient.cpp
index 19af227bc8e0..700e216b1600 100644
--- a/src/lib/gui/ipc/IpcClient.cpp
+++ b/src/lib/gui/ipc/IpcClient.cpp
@@ -163,6 +163,14 @@ void IpcClient::handleReadyRead()
void IpcClient::handleHandshakeMessage(const QStringList &parts)
{
+ if (parts.at(0) == "error") {
+ const auto detail = parts.size() >= 2 ? parts.at(1) : QString("unknown");
+ qCritical().noquote() << m_typeName << "ipc server rejected connection:" << detail;
+ disconnectFromServer();
+ Q_EMIT connectionFailed();
+ return;
+ }
+
if (parts.at(0) != "hello") {
return;
}
From 7c30add2a1966d2f47bf0e9c608aa916b45f2eab Mon Sep 17 00:00:00 2001
From: Nick Bolton
Date: Tue, 7 Apr 2026 12:30:33 +0100
Subject: [PATCH 19/24] feat(ipc): Error handling for missing version in IPC
handshake
---
src/lib/deskflow/ipc/IpcServer.cpp | 15 +++++++++++++--
src/lib/gui/ipc/IpcClient.cpp | 9 ++++++++-
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/lib/deskflow/ipc/IpcServer.cpp b/src/lib/deskflow/ipc/IpcServer.cpp
index 71607bcc6e64..50ebe04f54e1 100644
--- a/src/lib/deskflow/ipc/IpcServer.cpp
+++ b/src/lib/deskflow/ipc/IpcServer.cpp
@@ -112,12 +112,23 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
}
if (const auto &command = parts.at(0); command == "hello") {
+ if (parts.size() < 2) {
+ LOG_ERR("%s ipc client hello missing version", m_typeName.constData());
+ writeToClientSocket(clientSocket, "error=missing version");
+ clientSocket->flush();
+ clientSocket->disconnectFromServer();
+ return;
+ }
+
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
- const auto clientVersion = parts.size() >= 2 ? parts.at(1) : QString();
+ const auto clientVersion = parts.at(1);
LOG_DEBUG("%s ipc server got hello message (version: %s)", m_typeName.constData(), versionId.toUtf8().constData());
if (clientVersion != versionId) {
- LOG_ERR("%s ipc client version mismatch (server: %s)", m_typeName.constData(), versionId.toUtf8().constData());
+ LOG_ERR(
+ "%s ipc client version mismatch (client: %s, server: %s)", m_typeName.constData(),
+ clientVersion.toUtf8().constData(), versionId.toUtf8().constData()
+ );
writeToClientSocket(clientSocket, QStringLiteral("error=version mismatch, expected: %1").arg(versionId));
clientSocket->flush();
clientSocket->disconnectFromServer();
diff --git a/src/lib/gui/ipc/IpcClient.cpp b/src/lib/gui/ipc/IpcClient.cpp
index 700e216b1600..7418340b43d9 100644
--- a/src/lib/gui/ipc/IpcClient.cpp
+++ b/src/lib/gui/ipc/IpcClient.cpp
@@ -175,8 +175,15 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
return;
}
+ if (parts.size() < 2) {
+ qCritical().noquote() << QStringLiteral("%1 ipc server hello missing version").arg(m_typeName);
+ disconnectFromServer();
+ Q_EMIT connectionFailed();
+ return;
+ }
+
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
- const auto serverVersion = parts.size() >= 2 ? parts.at(1) : QString();
+ const auto serverVersion = parts.at(1);
if (serverVersion != versionId) {
qCritical().noquote(
) << QStringLiteral("%1 ipc version mismatch (client: %2 , server: %3)").arg(m_typeName, versionId, serverVersion);
From 7f2953d422169d9669e844c91f83d8215df40a39 Mon Sep 17 00:00:00 2001
From: sithlord48
Date: Mon, 6 Apr 2026 07:30:23 -0400
Subject: [PATCH 20/24] ci: Remove stale action
---
.github/workflows/issue-check-stale.yml | 23 -----------------------
1 file changed, 23 deletions(-)
delete mode 100644 .github/workflows/issue-check-stale.yml
diff --git a/.github/workflows/issue-check-stale.yml b/.github/workflows/issue-check-stale.yml
deleted file mode 100644
index 9393987bbc04..000000000000
--- a/.github/workflows/issue-check-stale.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: Close stale issues and PRs
-on:
- schedule:
- - cron: "0 5 * * *"
-
-jobs:
- stale-issues:
- runs-on: ubuntu-slim
- timeout-minutes: 10
-
- steps:
- - uses: actions/stale@v6
- with:
- stale-issue-message: "This issue is stale because it has been open 1 year with no activity. Remove the stale label or add a comment, otherwise this will be closed in 30 days."
- stale-pr-message: "This PR is stale because it has been open 1 year with no activity. Remove the stale label or add a comment, otherwise this will be closed in 30 days."
- close-issue-message: "This issue was closed because it has been stale for 1 year with no activity."
- close-pr-message: "This PR was closed because it has been stale for 1 year with no activity."
- days-before-issue-stale: 365
- days-before-pr-stale: 365
- days-before-issue-close: 30
- days-before-pr-close: 30
- stale-issue-label: ":bread: stale"
- stale-pr-label: ":bread: stale"
From bdb73097781464fab61c34628892d07b17579278 Mon Sep 17 00:00:00 2001
From: sithlord48
Date: Tue, 7 Apr 2026 12:16:13 -0400
Subject: [PATCH 21/24] refactor(ipcClient): declare values in if statement
where possible
---
src/lib/gui/ipc/IpcClient.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/lib/gui/ipc/IpcClient.cpp b/src/lib/gui/ipc/IpcClient.cpp
index 7418340b43d9..37a7ee85665f 100644
--- a/src/lib/gui/ipc/IpcClient.cpp
+++ b/src/lib/gui/ipc/IpcClient.cpp
@@ -49,11 +49,9 @@ void IpcClient::connectToServer()
void IpcClient::attemptConnection()
{
- const auto kRetryLimit = 3;
-
- if (m_retryCount >= kRetryLimit) {
+ if (const int retryLimit = 3; m_retryCount >= retryLimit) {
qWarning().noquote() << QStringLiteral("%1 ipc client failed to connect after %2 attempts")
- .arg(m_typeName, QString::number(kRetryLimit));
+ .arg(m_typeName, QString::number(retryLimit));
m_state = State::Unconnected;
Q_EMIT connectionFailed();
return;
@@ -183,8 +181,7 @@ void IpcClient::handleHandshakeMessage(const QStringList &parts)
}
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
- const auto serverVersion = parts.at(1);
- if (serverVersion != versionId) {
+ if (const auto serverVersion = parts.at(1); serverVersion != versionId) {
qCritical().noquote(
) << QStringLiteral("%1 ipc version mismatch (client: %2 , server: %3)").arg(m_typeName, versionId, serverVersion);
disconnectFromServer();
From d1074f64ae66113a1e0f31875fda4bc5840d65dd Mon Sep 17 00:00:00 2001
From: sithlord48
Date: Wed, 8 Apr 2026 01:02:16 -0400
Subject: [PATCH 22/24] refactor(ipc): use more QStringLiterals
---
src/lib/deskflow/ipc/CoreIpc.cpp | 2 +-
src/lib/deskflow/ipc/CoreIpcServer.cpp | 2 +-
src/lib/deskflow/ipc/DaemonIpcServer.cpp | 22 +++++++++++-----------
src/lib/deskflow/ipc/IpcServer.cpp | 12 ++++++------
src/lib/gui/ipc/CoreIpcClient.cpp | 2 +-
src/lib/gui/ipc/DaemonIpcClient.cpp | 18 +++++++++---------
src/lib/gui/ipc/IpcClient.cpp | 8 ++++----
7 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/src/lib/deskflow/ipc/CoreIpc.cpp b/src/lib/deskflow/ipc/CoreIpc.cpp
index 7dad7ca71775..b48f1554da94 100644
--- a/src/lib/deskflow/ipc/CoreIpc.cpp
+++ b/src/lib/deskflow/ipc/CoreIpc.cpp
@@ -24,5 +24,5 @@ void ipcSendToClient(const QString &command, const QString &args)
void ipcSendConnectionState(deskflow::core::ConnectionState state)
{
const auto metaEnum = QMetaEnum::fromType();
- ipcSendToClient("connectionState", metaEnum.valueToKey(static_cast(state)));
+ ipcSendToClient(QStringLiteral("connectionState"), metaEnum.valueToKey(static_cast(state)));
}
diff --git a/src/lib/deskflow/ipc/CoreIpcServer.cpp b/src/lib/deskflow/ipc/CoreIpcServer.cpp
index f73f726316c6..f0ad0a39ddd5 100644
--- a/src/lib/deskflow/ipc/CoreIpcServer.cpp
+++ b/src/lib/deskflow/ipc/CoreIpcServer.cpp
@@ -15,7 +15,7 @@ namespace deskflow::core::ipc {
static CoreIpcServer *s_instance = nullptr;
-CoreIpcServer::CoreIpcServer(QObject *parent) : IpcServer(parent, kCoreIpcName, "core")
+CoreIpcServer::CoreIpcServer(QObject *parent) : IpcServer(parent, kCoreIpcName, QStringLiteral("core"))
{
assert(s_instance == nullptr);
s_instance = this;
diff --git a/src/lib/deskflow/ipc/DaemonIpcServer.cpp b/src/lib/deskflow/ipc/DaemonIpcServer.cpp
index 9d34eabca966..374a9217bf17 100644
--- a/src/lib/deskflow/ipc/DaemonIpcServer.cpp
+++ b/src/lib/deskflow/ipc/DaemonIpcServer.cpp
@@ -17,7 +17,7 @@ const auto kAckMessage = "ok";
const auto kErrorMessage = "error";
DaemonIpcServer::DaemonIpcServer(QObject *parent, const QString &logFilename)
- : IpcServer(parent, kDaemonIpcName, "daemon"),
+ : IpcServer(parent, kDaemonIpcName, QStringLiteral("daemon")),
m_logFilename(logFilename)
{
// do nothing
@@ -25,24 +25,24 @@ DaemonIpcServer::DaemonIpcServer(QObject *parent, const QString &logFilename)
void DaemonIpcServer::processCommand(QLocalSocket *clientSocket, const QString &command, const QStringList &parts)
{
- if (command == "logLevel") {
+ if (command == QStringLiteral("logLevel")) {
processLogLevel(clientSocket, parts);
- } else if (command == "elevate") {
+ } else if (command == QStringLiteral("elevate")) {
processElevate(clientSocket, parts);
- } else if (command == "command") {
+ } else if (command == QStringLiteral("command")) {
processCommandMessage(clientSocket, parts);
- } else if (command == "start") {
+ } else if (command == QStringLiteral("start")) {
LOG_DEBUG("daemon ipc server got start message");
Q_EMIT startProcessRequested();
writeToClientSocket(clientSocket, kAckMessage);
- } else if (command == "stop") {
+ } else if (command == QStringLiteral("stop")) {
LOG_DEBUG("daemon ipc server got stop message");
Q_EMIT stopProcessRequested();
writeToClientSocket(clientSocket, kAckMessage);
- } else if (command == "logPath") {
+ } else if (command == QStringLiteral("logPath")) {
LOG_DEBUG("daemon ipc server got log path request");
- writeToClientSocket(clientSocket, "logPath=" + m_logFilename.toUtf8());
- } else if (command == "clearSettings") {
+ writeToClientSocket(clientSocket, QStringLiteral("logPath=%1").arg(m_logFilename.toUtf8()));
+ } else if (command == QStringLiteral("clearSettings")) {
LOG_DEBUG("daemon ipc server got clear settings message");
Q_EMIT clearSettingsRequested();
writeToClientSocket(clientSocket, kAckMessage);
@@ -80,14 +80,14 @@ void DaemonIpcServer::processElevate(QLocalSocket *&clientSocket, const QStringL
}
const auto &elevate = messageParts[1];
- if (elevate != "yes" && elevate != "no") {
+ if (elevate != QStringLiteral("yes") && elevate != QStringLiteral("no")) {
LOG_ERR("daemon ipc server got invalid elevate value: %s", elevate.toUtf8().constData());
writeToClientSocket(clientSocket, kErrorMessage);
return;
}
LOG_DEBUG("daemon ipc server got new elevate value: %s", elevate.toUtf8().constData());
- Q_EMIT elevateModeChanged(elevate == "yes");
+ Q_EMIT elevateModeChanged(elevate == QStringLiteral("yes"));
writeToClientSocket(clientSocket, kAckMessage);
}
diff --git a/src/lib/deskflow/ipc/IpcServer.cpp b/src/lib/deskflow/ipc/IpcServer.cpp
index 50ebe04f54e1..616a3f3884b0 100644
--- a/src/lib/deskflow/ipc/IpcServer.cpp
+++ b/src/lib/deskflow/ipc/IpcServer.cpp
@@ -107,11 +107,11 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
const auto parts = message.split('=');
if (parts.isEmpty()) {
LOG_ERR("%s ipc server got invalid message: %s", m_typeName.constData(), message.toUtf8().constData());
- writeToClientSocket(clientSocket, "error");
+ writeToClientSocket(clientSocket, QStringLiteral("error"));
return;
}
- if (const auto &command = parts.at(0); command == "hello") {
+ if (const auto &command = parts.at(0); command == QStringLiteral("hello")) {
if (parts.size() < 2) {
LOG_ERR("%s ipc client hello missing version", m_typeName.constData());
writeToClientSocket(clientSocket, "error=missing version");
@@ -136,7 +136,7 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
}
LOG_DEBUG("%s ipc server sending hello back", m_typeName.constData());
- writeToClientSocket(clientSocket, QString("hello=%1").arg(versionId));
+ writeToClientSocket(clientSocket, QStringLiteral("hello=%1").arg(versionId));
// Replay messages that were queued before any clients connected.
LOG_DEBUG1("ipc server replaying %d pending messages", m_pendingMessages.size());
@@ -145,9 +145,9 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
writeToClientSocket(clientSocket, pending);
}
m_pendingMessages.clear();
- } else if (command == "noop") {
+ } else if (command == QStringLiteral("noop")) {
LOG_DEBUG("%s ipc server got noop message", m_typeName.constData());
- writeToClientSocket(clientSocket, "ok");
+ writeToClientSocket(clientSocket, QStringLiteral("ok"));
} else {
processCommand(clientSocket, command, parts);
}
@@ -157,7 +157,7 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
void IpcServer::broadcastCommand(const QString &command, const QString &args)
{
- const auto message = args.isEmpty() ? command : command + "=" + args;
+ const auto message = args.isEmpty() ? command : QStringLiteral("%1=%2").arg(command, args);
if (m_clients.isEmpty()) {
LOG_DEBUG1(
diff --git a/src/lib/gui/ipc/CoreIpcClient.cpp b/src/lib/gui/ipc/CoreIpcClient.cpp
index ccfa2ed5ecd6..c4633b2abb8c 100644
--- a/src/lib/gui/ipc/CoreIpcClient.cpp
+++ b/src/lib/gui/ipc/CoreIpcClient.cpp
@@ -15,7 +15,7 @@
namespace deskflow::gui::ipc {
-CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName, "core")
+CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName, QStringLiteral("core"))
{
// do nothing
}
diff --git a/src/lib/gui/ipc/DaemonIpcClient.cpp b/src/lib/gui/ipc/DaemonIpcClient.cpp
index 454d8f354fd2..41a4bba66c33 100644
--- a/src/lib/gui/ipc/DaemonIpcClient.cpp
+++ b/src/lib/gui/ipc/DaemonIpcClient.cpp
@@ -12,41 +12,41 @@
namespace deskflow::gui::ipc {
-DaemonIpcClient::DaemonIpcClient(QObject *parent) : IpcClient(parent, kDaemonIpcName, "daemon")
+DaemonIpcClient::DaemonIpcClient(QObject *parent) : IpcClient(parent, kDaemonIpcName, QStringLiteral("daemon"))
{
}
void DaemonIpcClient::sendLogLevel(const QString &logLevel)
{
- sendMessage("logLevel=" + logLevel);
+ sendMessage(QStringLiteral("logLevel=%1").arg(logLevel));
}
void DaemonIpcClient::sendStartProcess(const QString &command, bool elevate)
{
const auto elevateStr = elevate ? QStringLiteral("yes") : QStringLiteral("no");
- sendMessage("elevate=" + elevateStr);
- sendMessage("command=" + command);
- sendMessage("start");
+ sendMessage(QStringLiteral("elevate=%1").arg(elevateStr));
+ sendMessage(QStringLiteral("command=%1").arg(command));
+ sendMessage(QStringLiteral("start"));
}
void DaemonIpcClient::sendStopProcess()
{
- sendMessage("stop");
+ sendMessage(QStringLiteral("stop"));
}
void DaemonIpcClient::sendClearSettings()
{
- sendMessage("clearSettings");
+ sendMessage(QStringLiteral("clearSettings"));
}
void DaemonIpcClient::requestLogPath()
{
- sendMessage("logPath");
+ sendMessage(QStringLiteral("logPath"));
}
void DaemonIpcClient::processCommand(const QString &command, const QStringList &parts)
{
- if (command == "logPath" && parts.size() == 2) {
+ if (command == QStringLiteral("logPath") && parts.size() == 2) {
Q_EMIT logPathReceived(parts[1]);
}
}
diff --git a/src/lib/gui/ipc/IpcClient.cpp b/src/lib/gui/ipc/IpcClient.cpp
index 37a7ee85665f..79a5d118759f 100644
--- a/src/lib/gui/ipc/IpcClient.cpp
+++ b/src/lib/gui/ipc/IpcClient.cpp
@@ -161,15 +161,15 @@ void IpcClient::handleReadyRead()
void IpcClient::handleHandshakeMessage(const QStringList &parts)
{
- if (parts.at(0) == "error") {
- const auto detail = parts.size() >= 2 ? parts.at(1) : QString("unknown");
- qCritical().noquote() << m_typeName << "ipc server rejected connection:" << detail;
+ if (parts.at(0) == QStringLiteral("error")) {
+ const auto detail = parts.size() >= 2 ? parts.at(1) : QStringLiteral("unknown");
+ qCritical().noquote() << QStringLiteral("%1 ipc server rejected connection: %2").arg(m_typeName, detail);
disconnectFromServer();
Q_EMIT connectionFailed();
return;
}
- if (parts.at(0) != "hello") {
+ if (parts.at(0) != QStringLiteral("hello")) {
return;
}
From e293d4eb8c9a11869510651689d244130bacc1a1 Mon Sep 17 00:00:00 2001
From: sithlord48
Date: Wed, 8 Apr 2026 01:20:02 -0400
Subject: [PATCH 23/24] refactor(ipc): add missing use of at for lists
---
src/lib/deskflow/ipc/DaemonIpcServer.cpp | 6 +++---
src/lib/gui/ipc/CoreIpcClient.cpp | 2 +-
src/lib/gui/ipc/DaemonIpcClient.cpp | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/lib/deskflow/ipc/DaemonIpcServer.cpp b/src/lib/deskflow/ipc/DaemonIpcServer.cpp
index 374a9217bf17..cd15de9afbb8 100644
--- a/src/lib/deskflow/ipc/DaemonIpcServer.cpp
+++ b/src/lib/deskflow/ipc/DaemonIpcServer.cpp
@@ -59,7 +59,7 @@ void DaemonIpcServer::processLogLevel(QLocalSocket *&clientSocket, const QString
return;
}
- const auto &logLevel = messageParts[1];
+ const auto &logLevel = messageParts.at(1);
if (logLevel.isEmpty()) {
LOG_ERR("daemon ipc server got empty log level");
writeToClientSocket(clientSocket, kErrorMessage);
@@ -79,7 +79,7 @@ void DaemonIpcServer::processElevate(QLocalSocket *&clientSocket, const QStringL
return;
}
- const auto &elevate = messageParts[1];
+ const auto &elevate = messageParts.at(1);
if (elevate != QStringLiteral("yes") && elevate != QStringLiteral("no")) {
LOG_ERR("daemon ipc server got invalid elevate value: %s", elevate.toUtf8().constData());
writeToClientSocket(clientSocket, kErrorMessage);
@@ -99,7 +99,7 @@ void DaemonIpcServer::processCommandMessage(QLocalSocket *&clientSocket, const Q
return;
}
- const auto &command = messageParts[1];
+ const auto &command = messageParts.at(1);
if (command.isEmpty()) {
LOG_ERR("daemon ipc server got empty command");
writeToClientSocket(clientSocket, kErrorMessage);
diff --git a/src/lib/gui/ipc/CoreIpcClient.cpp b/src/lib/gui/ipc/CoreIpcClient.cpp
index c4633b2abb8c..5315a6854f35 100644
--- a/src/lib/gui/ipc/CoreIpcClient.cpp
+++ b/src/lib/gui/ipc/CoreIpcClient.cpp
@@ -22,7 +22,7 @@ CoreIpcClient::CoreIpcClient(QObject *parent) : IpcClient(parent, kCoreIpcName,
void CoreIpcClient::processCommand(const QString &command, const QStringList &parts)
{
- const auto args = parts.size() >= 2 ? parts[1] : QString();
+ const auto args = parts.size() >= 2 ? parts.at(1) : QString();
Q_EMIT commandReceived(command, args);
}
diff --git a/src/lib/gui/ipc/DaemonIpcClient.cpp b/src/lib/gui/ipc/DaemonIpcClient.cpp
index 41a4bba66c33..82b3459934f4 100644
--- a/src/lib/gui/ipc/DaemonIpcClient.cpp
+++ b/src/lib/gui/ipc/DaemonIpcClient.cpp
@@ -47,7 +47,7 @@ void DaemonIpcClient::requestLogPath()
void DaemonIpcClient::processCommand(const QString &command, const QStringList &parts)
{
if (command == QStringLiteral("logPath") && parts.size() == 2) {
- Q_EMIT logPathReceived(parts[1]);
+ Q_EMIT logPathReceived(parts.at(1));
}
}
From 1922f916af0243ec5b2d528072da59338f52dc87 Mon Sep 17 00:00:00 2001
From: sithlord48
Date: Wed, 8 Apr 2026 01:42:19 -0400
Subject: [PATCH 24/24] refactor: Move -> deskflow/languages/LanguageManager ->
deskflow/KeyboardLayoutManager rename methods to relfect its use for keyboard
layouts not languages
---
src/lib/client/ServerProxy.cpp | 30 +++----
src/lib/client/ServerProxy.h | 8 +-
src/lib/deskflow/CMakeLists.txt | 4 +-
src/lib/deskflow/KeyboardLayoutManager.cpp | 90 +++++++++++++++++++
src/lib/deskflow/KeyboardLayoutManager.h | 63 +++++++++++++
.../deskflow/languages/LanguageManager.cpp | 89 ------------------
src/lib/deskflow/languages/LanguageManager.h | 65 --------------
src/lib/server/ClientProxy1_8.cpp | 16 ++--
src/unittests/deskflow/CMakeLists.txt | 4 +-
.../deskflow/KeyboardLayoutManagerTests.cpp | 63 +++++++++++++
...erTests.h => KeyboardLayoutManagerTests.h} | 12 +--
.../deskflow/LanguageManagerTests.cpp | 63 -------------
12 files changed, 253 insertions(+), 254 deletions(-)
create mode 100644 src/lib/deskflow/KeyboardLayoutManager.cpp
create mode 100644 src/lib/deskflow/KeyboardLayoutManager.h
delete mode 100644 src/lib/deskflow/languages/LanguageManager.cpp
delete mode 100644 src/lib/deskflow/languages/LanguageManager.h
create mode 100644 src/unittests/deskflow/KeyboardLayoutManagerTests.cpp
rename src/unittests/deskflow/{LanguageManagerTests.h => KeyboardLayoutManagerTests.h} (67%)
delete mode 100644 src/unittests/deskflow/LanguageManagerTests.cpp
diff --git a/src/lib/client/ServerProxy.cpp b/src/lib/client/ServerProxy.cpp
index c23cd6a0d425..a04aa35e293b 100644
--- a/src/lib/client/ServerProxy.cpp
+++ b/src/lib/client/ServerProxy.cpp
@@ -141,7 +141,7 @@ ServerProxy::ConnectionResult ServerProxy::parseHandshakeMessage(const uint8_t *
// handshake is complete
m_parser = &ServerProxy::parseMessage;
- if (const auto missedKeyboardLayouts = m_languageManager.getMissedLanguages(); !missedKeyboardLayouts.empty()) {
+ if (const auto missedKeyboardLayouts = m_layoutManager.getMissedLayouts(); !missedKeyboardLayouts.empty()) {
LOG_WARN("server layouts missing on this computer: %s", missedKeyboardLayouts.c_str());
ipcSendToClient("missingKeyboardLayouts", QString::fromStdString(missedKeyboardLayouts));
}
@@ -505,8 +505,8 @@ void ServerProxy::enter()
m_dxMouse = 0;
m_dyMouse = 0;
m_seqNum = seqNum;
- m_serverLanguage = "";
- m_isUserNotifiedAboutLanguageSyncError = false;
+ m_serverLayout = "";
+ m_isUserNotifiedAboutLayoutSyncError = false;
// forward
m_client->enter(x, y, seqNum, static_cast(mask), false);
@@ -825,28 +825,28 @@ void ServerProxy::secureInputNotification()
void ServerProxy::setServerLanguages()
{
- std::string serverLanguages;
- ProtocolUtil::readf(m_stream, kMsgDLanguageSynchronisation + 4, &serverLanguages);
- m_languageManager.setRemoteLanguages(serverLanguages);
+ std::string serverLayout;
+ ProtocolUtil::readf(m_stream, kMsgDLanguageSynchronisation + 4, &serverLayout);
+ m_layoutManager.setRemoteLayouts(serverLayout);
}
void ServerProxy::setActiveServerLanguage(const std::string_view &language)
{
if (!language.empty() && (language.size() > 0)) {
- if (m_serverLanguage != language) {
- m_isUserNotifiedAboutLanguageSyncError = false;
- m_serverLanguage = language;
+ if (m_serverLayout != language) {
+ m_isUserNotifiedAboutLayoutSyncError = false;
+ m_serverLayout = language;
}
- if (!m_languageManager.isLanguageInstalled(m_serverLanguage)) {
- if (!m_isUserNotifiedAboutLanguageSyncError) {
- LOG_WARN("current server language is not installed on client");
- m_isUserNotifiedAboutLanguageSyncError = true;
+ if (!m_layoutManager.isLayoutInstalled(m_serverLayout)) {
+ if (!m_isUserNotifiedAboutLayoutSyncError) {
+ LOG_WARN("current server layout is not installed on client");
+ m_isUserNotifiedAboutLayoutSyncError = true;
}
} else {
- m_isUserNotifiedAboutLanguageSyncError = false;
+ m_isUserNotifiedAboutLayoutSyncError = false;
}
} else {
- LOG_DEBUG1("active server language is empty");
+ LOG_DEBUG1("active server layout is empty");
}
}
diff --git a/src/lib/client/ServerProxy.h b/src/lib/client/ServerProxy.h
index 59535664018f..149d7b972ea4 100644
--- a/src/lib/client/ServerProxy.h
+++ b/src/lib/client/ServerProxy.h
@@ -10,7 +10,7 @@
#include "deskflow/ClipboardTypes.h"
#include "deskflow/KeyTypes.h"
-#include "deskflow/languages/LanguageManager.h"
+#include "deskflow/KeyboardLayoutManager.h"
class Client;
class ClientInfo;
@@ -123,7 +123,7 @@ class ServerProxy
MessageParser m_parser = &ServerProxy::parseHandshakeMessage;
IEventQueue *m_events = nullptr;
- std::string m_serverLanguage = "";
- bool m_isUserNotifiedAboutLanguageSyncError = false;
- deskflow::languages::LanguageManager m_languageManager;
+ std::string m_serverLayout = "";
+ bool m_isUserNotifiedAboutLayoutSyncError = false;
+ deskflow::KeyboardLayoutManager m_layoutManager;
};
diff --git a/src/lib/deskflow/CMakeLists.txt b/src/lib/deskflow/CMakeLists.txt
index 2d8ab2a0b6de..a0bc4c2367a1 100644
--- a/src/lib/deskflow/CMakeLists.txt
+++ b/src/lib/deskflow/CMakeLists.txt
@@ -77,8 +77,8 @@ add_library(${lib_name} STATIC ${PLATFORM_CODE}
ServerApp.h
StreamChunker.cpp
StreamChunker.h
- languages/LanguageManager.cpp
- languages/LanguageManager.h
+ KeyboardLayoutManager.cpp
+ KeyboardLayoutManager.h
ipc/IpcServer.cpp
ipc/IpcServer.h
ipc/DaemonIpcServer.cpp
diff --git a/src/lib/deskflow/KeyboardLayoutManager.cpp b/src/lib/deskflow/KeyboardLayoutManager.cpp
new file mode 100644
index 000000000000..b571b8fe39f8
--- /dev/null
+++ b/src/lib/deskflow/KeyboardLayoutManager.cpp
@@ -0,0 +1,90 @@
+/*
+ * Deskflow -- mouse and keyboard sharing utility
+ * SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
+ * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
+ */
+
+#include "KeyboardLayoutManager.h"
+#include "base/Log.h"
+
+#include
+
+namespace {
+
+std::string vectorToString(const std::vector &vector, const std::string_view &delimiter = "")
+{
+ std::string string;
+ for (const auto &item : vector) {
+ if (&item != &vector[0]) {
+ string += delimiter;
+ }
+ string += item;
+ }
+ return string;
+}
+
+} // anonymous namespace
+
+namespace deskflow {
+
+KeyboardLayoutManager::KeyboardLayoutManager(const std::vector &localLayouts)
+ : m_localLayouts(localLayouts)
+{
+ LOG_INFO("local layouts: %s", vectorToString(m_localLayouts, ", ").c_str());
+}
+
+void KeyboardLayoutManager::setRemoteLayouts(const std::string_view &remoteLayouts)
+{
+ m_remoteLayouts.clear();
+ if (!remoteLayouts.empty()) {
+ for (size_t i = 0; i <= remoteLayouts.size() - 2; i += 2) {
+ auto rLangs = remoteLayouts.substr(i, 2);
+ m_remoteLayouts.emplace_back(rLangs);
+ }
+ }
+ LOG_INFO("remote layouts: %s", vectorToString(m_remoteLayouts, ", ").c_str());
+}
+
+const std::vector &KeyboardLayoutManager::getRemoteLayouts() const
+{
+ return m_remoteLayouts;
+}
+
+const std::vector &KeyboardLayoutManager::getLocalLayouts() const
+{
+ return m_localLayouts;
+}
+
+std::string KeyboardLayoutManager::getMissedLayouts() const
+{
+ std::string missedLayouts;
+
+ for (const auto &layout : m_remoteLayouts) {
+ if (!isLayoutInstalled(layout)) {
+ if (!missedLayouts.empty()) {
+ missedLayouts += ", ";
+ }
+ missedLayouts += layout;
+ }
+ }
+
+ return missedLayouts;
+}
+
+std::string KeyboardLayoutManager::getSerializedLocalLayouts() const
+{
+ return vectorToString(m_localLayouts);
+}
+
+bool KeyboardLayoutManager::isLayoutInstalled(const std::string &layout) const
+{
+ bool isInstalled = true;
+
+ if (!m_localLayouts.empty()) {
+ isInstalled = (std::find(m_localLayouts.begin(), m_localLayouts.end(), layout) != m_localLayouts.end());
+ }
+
+ return isInstalled;
+}
+
+} // namespace deskflow
diff --git a/src/lib/deskflow/KeyboardLayoutManager.h b/src/lib/deskflow/KeyboardLayoutManager.h
new file mode 100644
index 000000000000..2e4094e6089e
--- /dev/null
+++ b/src/lib/deskflow/KeyboardLayoutManager.h
@@ -0,0 +1,63 @@
+/*
+ * Deskflow -- mouse and keyboard sharing utility
+ * SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
+ * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
+ */
+
+#pragma once
+
+#include "deskflow/AppUtil.h"
+#include
+
+namespace deskflow {
+
+class KeyboardLayoutManager
+{
+ std::vector m_remoteLayouts;
+ std::vector m_localLayouts;
+
+public:
+ explicit KeyboardLayoutManager(
+ const std::vector &localLayouts = AppUtil::instance().getKeyboardLayoutList()
+ );
+
+ /**
+ * @brief setRemoteLayouts sets remote layouts
+ * @param remoteLayouts is a string with sericalized layouts
+ */
+ void setRemoteLayouts(const std::string_view &remoteLayouts);
+
+ /**
+ * @brief getRemoteLayouts getter for remote layouts
+ * @return vector of remote layouts
+ */
+ const std::vector &getRemoteLayouts() const;
+
+ /**
+ * @brief getLocalLayouts getter for local layouts
+ * @return vector of local layouts
+ */
+ const std::vector &getLocalLayouts() const;
+
+ /**
+ * @brief getMissedLayouts getter for missed layouts on local machine
+ * @return difference between remote and local layouts as a coma separated
+ * string
+ */
+ std::string getMissedLayouts() const;
+
+ /**
+ * @brief getSerializedLocalLayouts getter for local serialized layouts
+ * @return serialized local layouts as a string
+ */
+ std::string getSerializedLocalLayouts() const;
+
+ /**
+ * @brief isLayoutInstalled checks if layout is installed
+ * @param layout which should be checked
+ * @return true if the specified layout is installed
+ */
+ bool isLayoutInstalled(const std::string &layout) const;
+};
+
+} // namespace deskflow
diff --git a/src/lib/deskflow/languages/LanguageManager.cpp b/src/lib/deskflow/languages/LanguageManager.cpp
deleted file mode 100644
index 6df5339f7c67..000000000000
--- a/src/lib/deskflow/languages/LanguageManager.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
- * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
- */
-
-#include "LanguageManager.h"
-#include "base/Log.h"
-
-#include
-
-namespace {
-
-std::string vectorToString(const std::vector &vector, const std::string_view &delimiter = "")
-{
- std::string string;
- for (const auto &item : vector) {
- if (&item != &vector[0]) {
- string += delimiter;
- }
- string += item;
- }
- return string;
-}
-
-} // anonymous namespace
-
-namespace deskflow::languages {
-
-LanguageManager::LanguageManager(const std::vector &localLanguages) : m_localLanguages(localLanguages)
-{
- LOG_INFO("local languages: %s", vectorToString(m_localLanguages, ", ").c_str());
-}
-
-void LanguageManager::setRemoteLanguages(const std::string_view &remoteLanguages)
-{
- m_remoteLanguages.clear();
- if (!remoteLanguages.empty()) {
- for (size_t i = 0; i <= remoteLanguages.size() - 2; i += 2) {
- auto rLangs = remoteLanguages.substr(i, 2);
- m_remoteLanguages.emplace_back(rLangs);
- }
- }
- LOG_INFO("remote languages: %s", vectorToString(m_remoteLanguages, ", ").c_str());
-}
-
-const std::vector &LanguageManager::getRemoteLanguages() const
-{
- return m_remoteLanguages;
-}
-
-const std::vector &LanguageManager::getLocalLanguages() const
-{
- return m_localLanguages;
-}
-
-std::string LanguageManager::getMissedLanguages() const
-{
- std::string missedLanguages;
-
- for (const auto &language : m_remoteLanguages) {
- if (!isLanguageInstalled(language)) {
- if (!missedLanguages.empty()) {
- missedLanguages += ", ";
- }
- missedLanguages += language;
- }
- }
-
- return missedLanguages;
-}
-
-std::string LanguageManager::getSerializedLocalLanguages() const
-{
- return vectorToString(m_localLanguages);
-}
-
-bool LanguageManager::isLanguageInstalled(const std::string &language) const
-{
- bool isInstalled = true;
-
- if (!m_localLanguages.empty()) {
- isInstalled = (std::find(m_localLanguages.begin(), m_localLanguages.end(), language) != m_localLanguages.end());
- }
-
- return isInstalled;
-}
-
-} // namespace deskflow::languages
diff --git a/src/lib/deskflow/languages/LanguageManager.h b/src/lib/deskflow/languages/LanguageManager.h
deleted file mode 100644
index 4aef2db60157..000000000000
--- a/src/lib/deskflow/languages/LanguageManager.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2014 - 2021 Symless Ltd.
- * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
- */
-
-#pragma once
-
-#include "deskflow/AppUtil.h"
-#include
-
-namespace deskflow::languages {
-
-// TODO: rename class and namespace; "languages" is a misnomer. These are keyboard
-// _layouts_ (Windows/X11) or input sources (macOS), not spoken "languages".
-class LanguageManager
-{
- std::vector m_remoteLanguages;
- std::vector m_localLanguages;
-
-public:
- explicit LanguageManager(
- const std::vector &localLanguages = AppUtil::instance().getKeyboardLayoutList()
- );
-
- /**
- * @brief setRemoteLanguages sets remote languages
- * @param remoteLanguages is a string with sericalized languages
- */
- void setRemoteLanguages(const std::string_view &remoteLanguages);
-
- /**
- * @brief getRemoteLanguages getter for remote languages
- * @return vector of remote languages
- */
- const std::vector &getRemoteLanguages() const;
-
- /**
- * @brief getLocalLanguages getter for local languages
- * @return vector of local languages
- */
- const std::vector &getLocalLanguages() const;
-
- /**
- * @brief getMissedLanguages getter for missed languages on local machine
- * @return difference between remote and local languages as a coma separated
- * string
- */
- std::string getMissedLanguages() const;
-
- /**
- * @brief getSerializedLocalLanguages getter for local serialized languages
- * @return serialized local languages as a string
- */
- std::string getSerializedLocalLanguages() const;
-
- /**
- * @brief isLanguageInstalled checks if language is installed
- * @param language which should be checked
- * @return true if the specified language is installed
- */
- bool isLanguageInstalled(const std::string &language) const;
-};
-
-} // namespace deskflow::languages
diff --git a/src/lib/server/ClientProxy1_8.cpp b/src/lib/server/ClientProxy1_8.cpp
index 7a86073c2c2d..fcdb633520c4 100644
--- a/src/lib/server/ClientProxy1_8.cpp
+++ b/src/lib/server/ClientProxy1_8.cpp
@@ -5,8 +5,8 @@
*/
#include "base/Log.h"
+#include "deskflow/KeyboardLayoutManager.h"
#include "deskflow/ProtocolUtil.h"
-#include "deskflow/languages/LanguageManager.h"
#include "ClientProxy1_8.h"
@@ -20,11 +20,11 @@ ClientProxy1_8::ClientProxy1_8(
void ClientProxy1_8::synchronizeLanguages() const
{
- deskflow::languages::LanguageManager languageManager;
- auto localLanguages = languageManager.getSerializedLocalLanguages();
- if (!localLanguages.empty()) {
- LOG_DEBUG1("send server languages to the client: %s", localLanguages.c_str());
- ProtocolUtil::writef(getStream(), kMsgDLanguageSynchronisation, &localLanguages);
+ deskflow::KeyboardLayoutManager layoutManager;
+ auto localLayouts = layoutManager.getSerializedLocalLayouts();
+ if (!localLayouts.empty()) {
+ LOG_DEBUG1("send server languages to the client: %s", localLayouts.c_str());
+ ProtocolUtil::writef(getStream(), kMsgDLanguageSynchronisation, &localLayouts);
} else {
LOG_ERR("failed to read server languages");
}
@@ -33,8 +33,8 @@ void ClientProxy1_8::synchronizeLanguages() const
void ClientProxy1_8::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const std::string &language)
{
LOG(
- (CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x, language=%s", getName().c_str(), key,
- mask, button, language.c_str())
+ (CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x, layout=%s", getName().c_str(), key, mask,
+ button, language.c_str())
);
ProtocolUtil::writef(getStream(), kMsgDKeyDownLang, key, mask, button, &language);
}
diff --git a/src/unittests/deskflow/CMakeLists.txt b/src/unittests/deskflow/CMakeLists.txt
index f4beb8abe3d6..937a3573f24f 100644
--- a/src/unittests/deskflow/CMakeLists.txt
+++ b/src/unittests/deskflow/CMakeLists.txt
@@ -46,10 +46,10 @@ create_test(
)
create_test(
- NAME LanguageManagerTests
+ NAME KeyboardLayoutManagerTests
DEPENDS app
LIBS arch base ${extra_libs}
- SOURCE LanguageManagerTests.cpp
+ SOURCE KeyboardLayoutManagerTests.cpp
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/deskflow"
)
diff --git a/src/unittests/deskflow/KeyboardLayoutManagerTests.cpp b/src/unittests/deskflow/KeyboardLayoutManagerTests.cpp
new file mode 100644
index 000000000000..0d602a8d0e42
--- /dev/null
+++ b/src/unittests/deskflow/KeyboardLayoutManagerTests.cpp
@@ -0,0 +1,63 @@
+/*
+ * Deskflow -- mouse and keyboard sharing utility
+ * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello
+ * SPDX-FileCopyrightText: (C) 2014 - 2024 Symless Ltd.
+ * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
+ */
+
+#include "KeyboardLayoutManagerTests.h"
+
+#include "deskflow/KeyboardLayoutManager.h"
+
+void KeyboardLayoutManagerTests::initTestCase()
+{
+ m_log.setFilter(LogLevel::Debug2);
+}
+
+void KeyboardLayoutManagerTests::remoteLayouts()
+{
+ std::string remoteLayouts = "ruenuk";
+ deskflow::KeyboardLayoutManager manager({"ru", "en", "uk"});
+
+ manager.setRemoteLayouts(remoteLayouts);
+ QCOMPARE(manager.getRemoteLayouts(), (std::vector{"ru", "en", "uk"}));
+
+ manager.setRemoteLayouts(std::string());
+ QVERIFY(manager.getRemoteLayouts().empty());
+}
+
+void KeyboardLayoutManagerTests::localLayout()
+{
+ std::vector localLayouts = {"ru", "en", "uk"};
+ deskflow::KeyboardLayoutManager manager(localLayouts);
+ QCOMPARE(manager.getLocalLayouts(), (std::vector{"ru", "en", "uk"}));
+}
+
+void KeyboardLayoutManagerTests::missedLayout()
+{
+ std::string remoteLayouts = "ruenuk";
+ std::vector localLayouts = {"en"};
+ deskflow::KeyboardLayoutManager manager(localLayouts);
+
+ manager.setRemoteLayouts(remoteLayouts);
+ QCOMPARE(manager.getMissedLayouts(), "ru, uk");
+}
+
+void KeyboardLayoutManagerTests::layoutInstall()
+{
+ std::vector localLayouts = {"ru", "en", "uk"};
+ deskflow::KeyboardLayoutManager manager(localLayouts);
+
+ QVERIFY(!manager.isLayoutInstalled("us"));
+ QVERIFY(manager.isLayoutInstalled("en"));
+}
+
+void KeyboardLayoutManagerTests::serializeLocalLayouts()
+{
+ std::vector localLayouts = {"ru", "en", "uk"};
+ deskflow::KeyboardLayoutManager manager(localLayouts);
+
+ QCOMPARE(manager.getSerializedLocalLayouts(), "ruenuk");
+}
+
+QTEST_MAIN(KeyboardLayoutManagerTests)
diff --git a/src/unittests/deskflow/LanguageManagerTests.h b/src/unittests/deskflow/KeyboardLayoutManagerTests.h
similarity index 67%
rename from src/unittests/deskflow/LanguageManagerTests.h
rename to src/unittests/deskflow/KeyboardLayoutManagerTests.h
index 9816c8b6a3dd..14ba6ffd7055 100644
--- a/src/unittests/deskflow/LanguageManagerTests.h
+++ b/src/unittests/deskflow/KeyboardLayoutManagerTests.h
@@ -8,17 +8,17 @@
#include
-class LanguageManagerTests : public QObject
+class KeyboardLayoutManagerTests : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
// Test are run in order top to bottom
- void remoteLanguages();
- void localLanguage();
- void missedLanguage();
- void serializeLocalLanguages();
- void languageInstall();
+ void remoteLayouts();
+ void localLayout();
+ void missedLayout();
+ void serializeLocalLayouts();
+ void layoutInstall();
private:
Log m_log;
diff --git a/src/unittests/deskflow/LanguageManagerTests.cpp b/src/unittests/deskflow/LanguageManagerTests.cpp
deleted file mode 100644
index 4f1464f1ede0..000000000000
--- a/src/unittests/deskflow/LanguageManagerTests.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Deskflow -- mouse and keyboard sharing utility
- * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello
- * SPDX-FileCopyrightText: (C) 2014 - 2024 Symless Ltd.
- * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
- */
-
-#include "LanguageManagerTests.h"
-
-#include "deskflow/languages/LanguageManager.h"
-
-void LanguageManagerTests::initTestCase()
-{
- m_log.setFilter(LogLevel::Debug2);
-}
-
-void LanguageManagerTests::remoteLanguages()
-{
- std::string remoteLanguages = "ruenuk";
- deskflow::languages::LanguageManager manager({"ru", "en", "uk"});
-
- manager.setRemoteLanguages(remoteLanguages);
- QCOMPARE(manager.getRemoteLanguages(), (std::vector{"ru", "en", "uk"}));
-
- manager.setRemoteLanguages(std::string());
- QVERIFY(manager.getRemoteLanguages().empty());
-}
-
-void LanguageManagerTests::localLanguage()
-{
- std::vector localLanguages = {"ru", "en", "uk"};
- deskflow::languages::LanguageManager manager(localLanguages);
- QCOMPARE(manager.getLocalLanguages(), (std::vector{"ru", "en", "uk"}));
-}
-
-void LanguageManagerTests::missedLanguage()
-{
- std::string remoteLanguages = "ruenuk";
- std::vector localLanguages = {"en"};
- deskflow::languages::LanguageManager manager(localLanguages);
-
- manager.setRemoteLanguages(remoteLanguages);
- QCOMPARE(manager.getMissedLanguages(), "ru, uk");
-}
-
-void LanguageManagerTests::languageInstall()
-{
- std::vector localLanguages = {"ru", "en", "uk"};
- deskflow::languages::LanguageManager manager(localLanguages);
-
- QVERIFY(!manager.isLanguageInstalled("us"));
- QVERIFY(manager.isLanguageInstalled("en"));
-}
-
-void LanguageManagerTests::serializeLocalLanguages()
-{
- std::vector localLanguages = {"ru", "en", "uk"};
- deskflow::languages::LanguageManager manager(localLanguages);
-
- QCOMPARE(manager.getSerializedLocalLanguages(), "ruenuk");
-}
-
-QTEST_MAIN(LanguageManagerTests)