diff --git a/.env.example b/.env.example
index ef5b56cbb..ffce9a2df 100644
--- a/.env.example
+++ b/.env.example
@@ -7,28 +7,28 @@
#
# Serial key value to pre-fill the activation dialog
-# SYNERGY_TEST_SERIAL_KEY="DEADBEEF"
+# DESKFLOW_TEST_SERIAL_KEY="DEADBEEF"
# Shows the test menu in the GUI (on by default in debug mode)
-# SYNERGY_TEST_MENU=true
+# DESKFLOW_TEST_MENU=true
# Version checker URL to use (useful for testing)
-# SYNERGY_VERSION_URL="http://localhost:8787?version=v1"
+# DESKFLOW_VERSION_URL="https://api.deskflow.org/version?fake=1.100.0"
# Enable debug logging in the GUI (on by default in debug mode)
-# SYNERGY_GUI_DEBUG=true
+# DESKFLOW_GUI_DEBUG=true
# Enable verbose logging in the GUI (always off by default)
-# SYNERGY_GUI_VERBOSE=true
+# DESKFLOW_GUI_VERBOSE=true
# Reset all settings and delete all data on startup
-# SYNERGY_RESET_ALL=true
+# DESKFLOW_RESET_ALL=true
# Enable the activation dialog (used for testing)
-# SYNERGY_ENABLE_ACTIVATION=true
+# DESKFLOW_ENABLE_ACTIVATION=true
# Show licensed product menu items, etc (used for testing)
-# SYNERGY_LICENSED_PRODUCT=true
+# DESKFLOW_LICENSED_PRODUCT=true
#
# Build
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 495ee0cb6..0ebcf63bd 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -67,9 +67,9 @@
{
"label": "kill",
"type": "shell",
- "command": "killall synergy; killall synergyc; killall synergys || true",
+ "command": "killall deskflow; killall deskflowc; killall deskflows || true",
"windows": {
- "command": "taskkill /F /IM synergy.exe /IM synergyc.exe /IM synergys.exe; $true"
+ "command": "taskkill /F /IM deskflow.exe /IM deskflowc.exe /IM deskflows.exe; $true"
},
"presentation": {
"reveal": "silent"
@@ -83,11 +83,11 @@
{
"label": "gui",
"type": "process",
- "command": "${workspaceFolder}/build/bin/synergy",
+ "command": "${workspaceFolder}/build/bin/deskflow",
"dependsOn": ["build", "kill"],
"problemMatcher": [],
"windows": {
- "command": "${workspaceFolder}/build/bin/synergy.exe"
+ "command": "${workspaceFolder}/build/bin/deskflow.exe"
}
},
{
diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp
index 61dad7234..18f863e50 100644
--- a/src/gui/src/MainWindow.cpp
+++ b/src/gui/src/MainWindow.cpp
@@ -570,7 +570,15 @@ void MainWindow::open() {
showAndActivate();
}
- m_VersionChecker.checkLatest();
+ if (!m_AppConfig.enableUpdateCheck().has_value()) {
+ m_AppConfig.setEnableUpdateCheck(messages::showUpdateCheckOption(this));
+ }
+
+ if (m_AppConfig.enableUpdateCheck().value()) {
+ m_VersionChecker.checkLatest();
+ } else {
+ qDebug("update check disabled");
+ }
if (m_AppConfig.startedBefore()) {
m_CoreProcess.start();
diff --git a/src/lib/gui/VersionChecker.cpp b/src/lib/gui/VersionChecker.cpp
index e2cf52ee8..189ca3aea 100644
--- a/src/lib/gui/VersionChecker.cpp
+++ b/src/lib/gui/VersionChecker.cpp
@@ -17,6 +17,8 @@
#include "VersionChecker.h"
+#include "env_vars.h"
+
#include
#include
#include
@@ -27,17 +29,21 @@
const char *const kVersion = DESKFLOW_VERSION;
-VersionChecker::VersionChecker(std::shared_ptr network)
+using namespace deskflow::gui;
+
+VersionChecker::VersionChecker(
+ std::shared_ptr network)
: m_network(
- network ? network : std::make_shared(this)) {
+ network ? network : std::make_shared()) {
+ m_network->init();
connect(
- m_network.get(), SIGNAL(finished(QNetworkReply *)), this,
- SLOT(replyFinished(QNetworkReply *)));
+ m_network.get(), &QNetworkAccessManagerProxy::finished, this,
+ &VersionChecker::replyFinished);
}
void VersionChecker::checkLatest() const {
- const QString url =
- qEnvironmentVariable("DESKFLOW_VERSION_URL", DESKFLOW_VERSION_URL);
+ const QString url = env_vars::versionUrl();
+ qDebug("checking for updates at: %s", qPrintable(url));
auto request = QNetworkRequest(url);
auto userAgent = QString("Deskflow %1 on %2")
.arg(kVersion)
@@ -53,7 +59,10 @@ void VersionChecker::replyFinished(QNetworkReply *reply) {
auto newestVersion = QString(reply->readAll());
if (!newestVersion.isEmpty() &&
compareVersions(DESKFLOW_VERSION, newestVersion) > 0) {
+ qDebug("update found: %s", qPrintable(newestVersion));
emit updateFound(newestVersion);
+ } else {
+ qDebug("no updates found");
}
}
diff --git a/src/lib/gui/VersionChecker.h b/src/lib/gui/VersionChecker.h
index 8199d7039..f99e32dc5 100644
--- a/src/lib/gui/VersionChecker.h
+++ b/src/lib/gui/VersionChecker.h
@@ -17,6 +17,8 @@
#pragma once
+#include "proxy/QNetworkAccessManagerProxy.h"
+
#include
#include
#include
@@ -26,13 +28,16 @@ class QNetworkReply;
class VersionCheckerTests;
class VersionChecker : public QObject {
+ using QNetworkAccessManagerProxy =
+ deskflow::gui::proxy::QNetworkAccessManagerProxy;
+
Q_OBJECT
friend class VersionCheckerTests;
public:
explicit VersionChecker(
- std::shared_ptr network = nullptr);
+ std::shared_ptr network = nullptr);
void checkLatest() const;
public slots:
void replyFinished(QNetworkReply *reply);
@@ -50,5 +55,5 @@ private:
*/
static int getStageVersion(QString stage);
- std::shared_ptr m_network;
+ std::shared_ptr m_network;
};
diff --git a/src/lib/gui/config/AppConfig.cpp b/src/lib/gui/config/AppConfig.cpp
index 67fc99572..e22ef1718 100644
--- a/src/lib/gui/config/AppConfig.cpp
+++ b/src/lib/gui/config/AppConfig.cpp
@@ -94,6 +94,7 @@ const char *const AppConfig::m_SettingsName[] = {
"mainWindowPosition",
"showDevThanks",
"showCloseReminder",
+ "enableUpdateCheck",
};
AppConfig::AppConfig(
@@ -175,6 +176,8 @@ void AppConfig::recallFromCurrentScope() {
getFromCurrentScope(kShowDevThanks, m_ShowDevThanks).toBool();
m_ShowCloseReminder =
getFromCurrentScope(kShowCloseReminder, m_ShowCloseReminder).toBool();
+ m_EnableUpdateCheck = getFromCurrentScope(
+ kEnableUpdateCheck, [](const QVariant &v) { return v.toBool(); });
}
void AppConfig::recallScreenName() {
@@ -231,11 +234,11 @@ void AppConfig::commit() {
setInCurrentScope(kInvertConnection, m_InvertConnection);
setInCurrentScope(kEnableService, m_EnableService);
setInCurrentScope(kCloseToTray, m_CloseToTray);
- setInCurrentScope(kShowDevThanks, m_ShowDevThanks);
- setInCurrentScope(kShowCloseReminder, m_ShowCloseReminder);
-
setInCurrentScope(kMainWindowSize, m_MainWindowSize);
setInCurrentScope(kMainWindowPosition, m_MainWindowPosition);
+ setInCurrentScope(kShowDevThanks, m_ShowDevThanks);
+ setInCurrentScope(kShowCloseReminder, m_ShowCloseReminder);
+ setInCurrentScope(kEnableUpdateCheck, m_EnableUpdateCheck);
}
if (m_TlsChanged) {
@@ -535,6 +538,10 @@ bool AppConfig::showDevThanks() const { return m_ShowDevThanks; }
bool AppConfig::showCloseReminder() const { return m_ShowCloseReminder; }
+std::optional AppConfig::enableUpdateCheck() const {
+ return m_EnableUpdateCheck;
+}
+
///////////////////////////////////////////////////////////////////////////////
// End getters
///////////////////////////////////////////////////////////////////////////////
@@ -661,6 +668,10 @@ void AppConfig::setShowCloseReminder(bool value) {
m_ShowCloseReminder = value;
}
+void AppConfig::setEnableUpdateCheck(bool value) {
+ m_EnableUpdateCheck = value;
+}
+
///////////////////////////////////////////////////////////////////////////////
// End setters
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/lib/gui/config/AppConfig.h b/src/lib/gui/config/AppConfig.h
index f693be5ff..b99f38bb6 100644
--- a/src/lib/gui/config/AppConfig.h
+++ b/src/lib/gui/config/AppConfig.h
@@ -106,6 +106,7 @@ private:
kMainWindowPosition = 40,
kShowDevThanks = 41,
kShowCloseReminder = 42,
+ kEnableUpdateCheck = 43,
};
public:
@@ -180,6 +181,7 @@ public:
std::optional mainWindowPosition() const;
bool showDevThanks() const;
bool showCloseReminder() const;
+ std::optional enableUpdateCheck() const;
//
// Setters (overrides)
@@ -224,6 +226,7 @@ public:
void setMainWindowPosition(const QPoint &position);
void setShowDevThanks(bool show);
void setShowCloseReminder(bool show);
+ void setEnableUpdateCheck(bool value);
/// @brief Sets the user preference to load from SystemScope.
/// @param [in] value
@@ -332,6 +335,7 @@ private:
bool m_ShowDevThanks = !deskflow::gui::license::isLicensedProduct();
bool m_LoadFromSystemScope = false;
bool m_ShowCloseReminder = true;
+ std::optional m_EnableUpdateCheck;
/**
* @brief Flag is set when any TLS is setting is changed, and is reset
diff --git a/src/lib/gui/env_vars.h b/src/lib/gui/env_vars.h
new file mode 100644
index 000000000..f91f03d8e
--- /dev/null
+++ b/src/lib/gui/env_vars.h
@@ -0,0 +1,29 @@
+/*
+ * Deskflow -- mouse and keyboard sharing utility
+ * Copyright (C) 2024 Symless Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+namespace deskflow::gui::env_vars {
+
+inline QString versionUrl() {
+ return qEnvironmentVariable("DESKFLOW_VERSION_URL", DESKFLOW_VERSION_URL);
+}
+
+} // namespace deskflow::gui::env_vars
diff --git a/src/lib/gui/messages.cpp b/src/lib/gui/messages.cpp
index 97f05790b..2070ecb36 100644
--- a/src/lib/gui/messages.cpp
+++ b/src/lib/gui/messages.cpp
@@ -18,8 +18,10 @@
#include "messages.h"
#include "Logger.h"
+#include "common/constants.h"
#include "common/version.h"
#include "constants.h"
+#include "env_vars.h"
#include "gui/license/license_utils.h"
#include "styles.h"
@@ -314,4 +316,19 @@ void showWaylandLibraryError(QWidget *parent) {
.arg(kUrlBugReport, kColorSecondary));
}
+bool showUpdateCheckOption(QWidget *parent) {
+ QMessageBox message(parent);
+ message.addButton(QObject::tr("Close"), QMessageBox::RejectRole);
+ const auto checkButton = message.addButton(
+ QObject::tr("Check for updates"), QMessageBox::AcceptRole);
+ message.setText(
+ QString("Would you like to check for updates when %1 starts?
"
+ "Checking for updates requires an Internet connection.
"
+ "URL:
%2
")
+ .arg(kAppName, env_vars::versionUrl()));
+
+ message.exec();
+ return message.clickedButton() == checkButton;
+}
+
} // namespace deskflow::gui::messages
diff --git a/src/lib/gui/messages.h b/src/lib/gui/messages.h
index 4fa8d0ae1..ee42c9108 100644
--- a/src/lib/gui/messages.h
+++ b/src/lib/gui/messages.h
@@ -56,4 +56,6 @@ void showWaylandExperimental(QWidget *parent);
void showWaylandLibraryError(QWidget *parent);
+bool showUpdateCheckOption(QWidget *parent);
+
} // namespace deskflow::gui::messages
diff --git a/src/lib/gui/proxy/QNetworkAccessManagerProxy.cpp b/src/lib/gui/proxy/QNetworkAccessManagerProxy.cpp
new file mode 100644
index 000000000..d49086ac3
--- /dev/null
+++ b/src/lib/gui/proxy/QNetworkAccessManagerProxy.cpp
@@ -0,0 +1,37 @@
+/*
+ * Deskflow -- mouse and keyboard sharing utility
+ * Copyright (C) 2024 Symless Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "QNetworkAccessManagerProxy.h"
+
+#include
+#include
+
+namespace deskflow::gui::proxy {
+
+void QNetworkAccessManagerProxy::init() {
+ m_network = std::make_shared();
+
+ connect(
+ m_network.get(), &QNetworkAccessManager::finished, this,
+ [this](QNetworkReply *reply) { emit finished(reply); });
+}
+
+void QNetworkAccessManagerProxy::get(const QNetworkRequest &request) const {
+ m_network->get(request);
+}
+
+} // namespace deskflow::gui::proxy
diff --git a/src/lib/gui/proxy/QNetworkAccessManagerProxy.h b/src/lib/gui/proxy/QNetworkAccessManagerProxy.h
new file mode 100644
index 000000000..78df4c938
--- /dev/null
+++ b/src/lib/gui/proxy/QNetworkAccessManagerProxy.h
@@ -0,0 +1,39 @@
+/*
+ * Deskflow -- mouse and keyboard sharing utility
+ * Copyright (C) 2024 Symless Ltd.
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file LICENSE that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+namespace deskflow::gui::proxy {
+
+class QNetworkAccessManagerProxy : public QObject {
+ Q_OBJECT
+
+public:
+ virtual void init();
+ virtual void get(const QNetworkRequest &request) const;
+
+signals:
+ void finished(QNetworkReply *reply);
+
+private:
+ std::shared_ptr m_network;
+};
+
+} // namespace deskflow::gui::proxy
diff --git a/src/test/unittests/gui/VersionCheckerTests.cpp b/src/test/unittests/gui/VersionCheckerTests.cpp
index bd850a5ba..e3505e12f 100644
--- a/src/test/unittests/gui/VersionCheckerTests.cpp
+++ b/src/test/unittests/gui/VersionCheckerTests.cpp
@@ -16,9 +16,14 @@
*/
#include "gui/VersionChecker.h"
+#include "shared/gui/TestQtCoreApp.h"
+#include
#include
+using namespace deskflow::gui::proxy;
+using namespace testing;
+
class VersionCheckerTests : public ::testing::Test {
protected:
int compareVersions(const QString &left, const QString &right) {
@@ -26,6 +31,22 @@ protected:
}
};
+class MockNetworkAccessManager : public QNetworkAccessManagerProxy {
+public:
+ MOCK_METHOD(void, init, (), (override));
+ MOCK_METHOD(void, get, (const QNetworkRequest &request), (const, override));
+};
+
+TEST_F(VersionCheckerTests, checkLatest_callsNetworkGet) {
+ TestQtCoreApp app;
+ const auto network = std::make_shared>();
+ const VersionChecker checker(network);
+
+ EXPECT_CALL(*network, get(testing::_)).Times(1);
+
+ checker.checkLatest();
+}
+
TEST_F(VersionCheckerTests, compareVersions_major_isValid) {
EXPECT_EQ(compareVersions("1.0.0", "2.0.0"), 1);
EXPECT_EQ(compareVersions("2.0.0", "1.0.0"), -1);