feat: Option to change server protocol in GUI

This commit is contained in:
Nick Bolton 2024-10-18 16:13:13 +01:00
parent 512faeea28
commit a5cd0fab9e
14 changed files with 623 additions and 448 deletions

View file

@ -72,15 +72,26 @@ bool ServerConfig::save(const QString &fileName) const
bool ServerConfig::operator==(const ServerConfig &sc) const bool ServerConfig::operator==(const ServerConfig &sc) const
{ {
return m_Screens == sc.m_Screens && m_Columns == sc.m_Columns && m_Rows == sc.m_Rows && return m_Screens == sc.m_Screens && //
m_HasHeartbeat == sc.m_HasHeartbeat && m_Heartbeat == sc.m_Heartbeat && m_Columns == sc.m_Columns && //
m_RelativeMouseMoves == sc.m_RelativeMouseMoves && m_Win32KeepForeground == sc.m_Win32KeepForeground && m_Rows == sc.m_Rows && //
m_HasSwitchDelay == sc.m_HasSwitchDelay && m_SwitchDelay == sc.m_SwitchDelay && m_HasHeartbeat == sc.m_HasHeartbeat && //
m_HasSwitchDoubleTap == sc.m_HasSwitchDoubleTap && m_SwitchDoubleTap == sc.m_SwitchDoubleTap && m_Heartbeat == sc.m_Heartbeat && //
m_SwitchCornerSize == sc.m_SwitchCornerSize && m_SwitchCorners == sc.m_SwitchCorners && m_Protocol == sc.m_Protocol && //
m_Hotkeys == sc.m_Hotkeys && m_pAppConfig == sc.m_pAppConfig && m_RelativeMouseMoves == sc.m_RelativeMouseMoves && //
m_EnableDragAndDrop == sc.m_EnableDragAndDrop && m_DisableLockToScreen == sc.m_DisableLockToScreen && m_Win32KeepForeground == sc.m_Win32KeepForeground && //
m_ClipboardSharing == sc.m_ClipboardSharing && m_ClipboardSharingSize == sc.m_ClipboardSharingSize && m_HasSwitchDelay == sc.m_HasSwitchDelay && //
m_SwitchDelay == sc.m_SwitchDelay && //
m_HasSwitchDoubleTap == sc.m_HasSwitchDoubleTap && //
m_SwitchDoubleTap == sc.m_SwitchDoubleTap && //
m_SwitchCornerSize == sc.m_SwitchCornerSize && //
m_SwitchCorners == sc.m_SwitchCorners && //
m_Hotkeys == sc.m_Hotkeys && //
m_pAppConfig == sc.m_pAppConfig && //
m_EnableDragAndDrop == sc.m_EnableDragAndDrop && //
m_DisableLockToScreen == sc.m_DisableLockToScreen && //
m_ClipboardSharing == sc.m_ClipboardSharing && //
m_ClipboardSharingSize == sc.m_ClipboardSharingSize && //
m_pMainWindow == sc.m_pMainWindow; m_pMainWindow == sc.m_pMainWindow;
} }
@ -118,6 +129,7 @@ void ServerConfig::commit()
settings().setValue("hasHeartbeat", hasHeartbeat()); settings().setValue("hasHeartbeat", hasHeartbeat());
settings().setValue("heartbeat", heartbeat()); settings().setValue("heartbeat", heartbeat());
settings().setValue("protocol", static_cast<int>(protocol()));
settings().setValue("relativeMouseMoves", relativeMouseMoves()); settings().setValue("relativeMouseMoves", relativeMouseMoves());
settings().setValue("win32KeepForeground", win32KeepForeground()); settings().setValue("win32KeepForeground", win32KeepForeground());
settings().setValue("hasSwitchDelay", hasSwitchDelay()); settings().setValue("hasSwitchDelay", hasSwitchDelay());
@ -172,6 +184,7 @@ void ServerConfig::recall()
haveHeartbeat(settings().value("hasHeartbeat", false).toBool()); haveHeartbeat(settings().value("hasHeartbeat", false).toBool());
setHeartbeat(settings().value("heartbeat", 5000).toInt()); setHeartbeat(settings().value("heartbeat", 5000).toInt());
setProtocol(static_cast<ServerProtocol>(settings().value("protocol", static_cast<int>(protocol())).toInt()));
setRelativeMouseMoves(settings().value("relativeMouseMoves", false).toBool()); setRelativeMouseMoves(settings().value("relativeMouseMoves", false).toBool());
setWin32KeepForeground(settings().value("win32KeepForeground", false).toBool()); setWin32KeepForeground(settings().value("win32KeepForeground", false).toBool());
haveSwitchDelay(settings().value("hasSwitchDelay", false).toBool()); haveSwitchDelay(settings().value("hasSwitchDelay", false).toBool());
@ -232,6 +245,8 @@ int ServerConfig::adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) co
QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config) QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config)
{ {
using enum synergy::gui::ServerProtocol;
outStream << "section: screens" << Qt::endl; outStream << "section: screens" << Qt::endl;
foreach (const Screen &s, config.screens()) foreach (const Screen &s, config.screens())
@ -266,8 +281,15 @@ QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config)
outStream << "section: options" << Qt::endl; outStream << "section: options" << Qt::endl;
if (config.hasHeartbeat()) if (config.hasHeartbeat())
outStream << "\t" outStream << "\t" << "heartbeat = " << config.heartbeat() << Qt::endl;
<< "heartbeat = " << config.heartbeat() << Qt::endl;
if (config.protocol() == kSynergy) {
outStream << "\t" << "protocol = synergy" << Qt::endl;
} else if (config.protocol() == kBarrier) {
outStream << "\t" << "protocol = barrier" << Qt::endl;
} else {
qFatal("unrecognized protocol when writing config");
}
outStream << "\t" outStream << "\t"
<< "relativeMouseMoves = " << (config.relativeMouseMoves() ? "true" : "false") << Qt::endl; << "relativeMouseMoves = " << (config.relativeMouseMoves() ? "true" : "false") << Qt::endl;

View file

@ -36,9 +36,25 @@ class ServerConfigDialog;
class MainWindow; class MainWindow;
class AppConfig; class AppConfig;
namespace synergy::gui {
enum class ServerProtocol
{
kSynergy,
kBarrier
};
// The default protocol was decided by a community vote.
// TODO: Remove this link when the vote concludes:
// https://github.com/deskflow/deskflow/discussions/7742
const auto kDefaultProtocol = ServerProtocol::kSynergy;
} // namespace synergy::gui
class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig
{ {
using QSettingsProxy = deskflow::gui::proxy::QSettingsProxy; using QSettingsProxy = deskflow::gui::proxy::QSettingsProxy;
using ServerProtocol = synergy::gui::ServerProtocol;
friend class ServerConfigDialog; friend class ServerConfigDialog;
friend QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config); friend QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config);
@ -80,6 +96,10 @@ public:
{ {
return m_Heartbeat; return m_Heartbeat;
} }
ServerProtocol protocol() const
{
return m_Protocol;
}
bool relativeMouseMoves() const bool relativeMouseMoves() const
{ {
return m_RelativeMouseMoves; return m_RelativeMouseMoves;
@ -188,6 +208,10 @@ private:
{ {
m_Heartbeat = val; m_Heartbeat = val;
} }
void setProtocol(ServerProtocol val)
{
m_Protocol = val;
}
void setRelativeMouseMoves(bool on) void setRelativeMouseMoves(bool on)
{ {
m_RelativeMouseMoves = on; m_RelativeMouseMoves = on;
@ -252,6 +276,7 @@ private:
private: private:
bool m_HasHeartbeat = false; bool m_HasHeartbeat = false;
int m_Heartbeat = 0; int m_Heartbeat = 0;
ServerProtocol m_Protocol = synergy::gui::kDefaultProtocol;
bool m_RelativeMouseMoves = false; bool m_RelativeMouseMoves = false;
bool m_Win32KeepForeground = false; bool m_Win32KeepForeground = false;
bool m_HasSwitchDelay = false; bool m_HasSwitchDelay = false;

View file

@ -30,6 +30,7 @@
#include <QtGui> #include <QtGui>
using enum ScreenConfig::SwitchCorner; using enum ScreenConfig::SwitchCorner;
using ServerProtocol = synergy::gui::ServerProtocol;
ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, AppConfig &appConfig) ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, AppConfig &appConfig)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
@ -51,6 +52,8 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
ui->m_pEditConfigFile->setText(serverConfig().configFile()); ui->m_pEditConfigFile->setText(serverConfig().configFile());
ui->m_pCheckBoxUseExternalConfig->setChecked(serverConfig().useExternalConfig()); ui->m_pCheckBoxUseExternalConfig->setChecked(serverConfig().useExternalConfig());
ui->m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat()); ui->m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat());
ui->m_pRadioProtocolSynergy->setChecked(serverConfig().protocol() == ServerProtocol::kSynergy);
ui->m_pRadioProtocolBarrier->setChecked(serverConfig().protocol() == ServerProtocol::kBarrier);
ui->m_pSpinBoxHeartbeat->setValue(serverConfig().heartbeat()); ui->m_pSpinBoxHeartbeat->setValue(serverConfig().heartbeat());
ui->m_pCheckBoxRelativeMouseMoves->setChecked(serverConfig().relativeMouseMoves()); ui->m_pCheckBoxRelativeMouseMoves->setChecked(serverConfig().relativeMouseMoves());
@ -99,6 +102,8 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
// computers // computers
connect(&m_ScreenSetupModel, &ScreenSetupModel::screensChanged, this, &ServerConfigDialog::onChange); connect(&m_ScreenSetupModel, &ScreenSetupModel::screensChanged, this, &ServerConfigDialog::onChange);
// Above Qt 6.7 the checkbox signal signature has changed from int to Qt::CheckState
#if QT_VERSION <= QT_VERSION_CHECK(6, 7, 0) #if QT_VERSION <= QT_VERSION_CHECK(6, 7, 0)
// advanced // advanced
connect(ui->m_pCheckBoxSwitchDelay, &QCheckBox::stateChanged, this, [this](const int &v) { connect(ui->m_pCheckBoxSwitchDelay, &QCheckBox::stateChanged, this, [this](const int &v) {
@ -237,6 +242,18 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
onChange(); onChange();
} }
); );
connect(ui->m_pRadioProtocolSynergy, &QRadioButton::toggled, this, [this](const bool &v) {
if (v) {
serverConfig().setProtocol(ServerProtocol::kSynergy);
onChange();
}
});
connect(ui->m_pRadioProtocolBarrier, &QRadioButton::toggled, this, [this](const bool &v) {
if (v) {
serverConfig().setProtocol(ServerProtocol::kBarrier);
onChange();
}
});
connect(ui->m_pEditConfigFile, &QLineEdit::textChanged, this, [this]() { connect(ui->m_pEditConfigFile, &QLineEdit::textChanged, this, [this]() {
serverConfig().setConfigFile(ui->m_pEditConfigFile->text()); serverConfig().setConfigFile(ui->m_pEditConfigFile->text());

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,7 @@ void HelloBack::handleHello(deskflow::IStream *stream, const std::string &client
} }
// check versions // check versions
LOG_DEBUG("got hello version %s, %d.%d", protocolName.c_str(), serverMajor, serverMinor); LOG_DEBUG("got hello from %s, protocol v%d.%d", protocolName.c_str(), serverMajor, serverMinor);
const auto helloBackMajor = m_majorVersion; const auto helloBackMajor = m_majorVersion;
auto helloBackMinor = m_minorVersion; auto helloBackMinor = m_minorVersion;

View file

@ -28,6 +28,15 @@ String XBadClient::getWhat() const throw()
return "XBadClient"; return "XBadClient";
} }
//
// XInvalidProtocol
//
String XInvalidProtocol::getWhat() const throw()
{
return "XInvalidProtocol";
}
// //
// XIncompatibleClient // XIncompatibleClient
// //

View file

@ -35,6 +35,12 @@ Thrown when the client fails to follow the protocol.
*/ */
XBASE_SUBCLASS_WHAT(XBadClient, XDeskflow); XBASE_SUBCLASS_WHAT(XBadClient, XDeskflow);
//! Server protocol error
/*!
Thrown when the server protocol is unrecognized.
*/
XBASE_SUBCLASS_WHAT(XInvalidProtocol, XDeskflow);
//! Incompatible client exception //! Incompatible client exception
/*! /*!
Thrown when a client attempting to connect has an incompatible version. Thrown when a client attempting to connect has an incompatible version.

View file

@ -55,6 +55,7 @@ static const OptionID kOptionModifierMapForAltGr = OPTION_CODE("MMFG");
static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM"); static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM");
static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR"); static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR");
static const OptionID kOptionHeartbeat = OPTION_CODE("HART"); static const OptionID kOptionHeartbeat = OPTION_CODE("HART");
static const OptionID kOptionProtocol = OPTION_CODE("PROT");
static const OptionID kOptionScreenSwitchCorners = OPTION_CODE("SSCM"); static const OptionID kOptionScreenSwitchCorners = OPTION_CODE("SSCM");
static const OptionID kOptionScreenSwitchCornerSize = OPTION_CODE("SSCS"); static const OptionID kOptionScreenSwitchCornerSize = OPTION_CODE("SSCS");
static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT");
@ -98,4 +99,13 @@ enum EScreenSwitchCornerMasks
}; };
//@} //@}
//! @name Network protocol
//@{
enum class ENetworkProtocol
{
kSynergy,
kBarrier
};
//@}
#undef OPTION_CODE #undef OPTION_CODE

View file

@ -60,9 +60,10 @@ ClientProxyUnknown::ClientProxyUnknown(deskflow::IStream *stream, double timeout
m_timer = m_events->newOneShotTimer(timeout, this); m_timer = m_events->newOneShotTimer(timeout, this);
addStreamHandlers(); addStreamHandlers();
std::string helloMessage = std::string(kSynergyProtocolName).append(kMsgHelloArgs); const auto protocol = m_server->protocolString();
const auto helloMessage = protocol + kMsgHelloArgs;
LOG((CLOG_DEBUG1 "saying hello")); LOG_DEBUG("saying hello as %s, protocol v%d.%d", protocol.c_str(), kProtocolMajorVersion, kProtocolMinorVersion);
ProtocolUtil::writef(m_stream, helloMessage.c_str(), kProtocolMajorVersion, kProtocolMinorVersion); ProtocolUtil::writef(m_stream, helloMessage.c_str(), kProtocolMajorVersion, kProtocolMinorVersion);
} }

View file

@ -21,6 +21,7 @@
#include "base/Event.h" #include "base/Event.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
#include "base/String.h" #include "base/String.h"
#include "deskflow/option_types.h"
class ClientProxy; class ClientProxy;
class EventQueueTimer; class EventQueueTimer;

View file

@ -22,7 +22,9 @@
#include "common/stdistream.h" #include "common/stdistream.h"
#include "common/stdostream.h" #include "common/stdostream.h"
#include "deskflow/KeyMap.h" #include "deskflow/KeyMap.h"
#include "deskflow/XDeskflow.h"
#include "deskflow/key_types.h" #include "deskflow/key_types.h"
#include "deskflow/option_types.h"
#include "net/XSocket.h" #include "net/XSocket.h"
#include "server/Server.h" #include "server/Server.h"
@ -32,6 +34,9 @@ using namespace deskflow::string;
namespace deskflow::server { namespace deskflow::server {
const auto kSynergyProtocolOption = "synergy";
const auto kBarrierProtocolOption = "barrier";
// //
// Config // Config
// //
@ -675,6 +680,8 @@ void Config::readSectionOptions(ConfigReadContext &s)
} }
} else if (name == "heartbeat") { } else if (name == "heartbeat") {
addOption("", kOptionHeartbeat, s.parseInt(value)); addOption("", kOptionHeartbeat, s.parseInt(value));
} else if (name == "protocol") {
addOption("", kOptionProtocol, s.parseProtocol(value));
} else if (name == "switchCorners") { } else if (name == "switchCorners") {
addOption("", kOptionScreenSwitchCorners, s.parseCorners(value)); addOption("", kOptionScreenSwitchCorners, s.parseCorners(value));
} else if (name == "switchCornerSize") { } else if (name == "switchCornerSize") {
@ -1325,6 +1332,17 @@ String Config::getOptionValue(OptionID id, OptionValue value)
} }
return result; return result;
} }
if (id == kOptionProtocol) {
using enum ENetworkProtocol;
const auto enumValue = static_cast<ENetworkProtocol>(value);
if (enumValue == kSynergy) {
return kSynergyProtocolOption;
} else if (enumValue == kBarrier) {
return kBarrierProtocolOption;
} else {
throw XInvalidProtocol();
}
}
return ""; return "";
} }
@ -1822,6 +1840,16 @@ OptionValue ConfigReadContext::parseCorner(const String &arg) const
throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); throw XConfigRead(*this, "invalid argument \"%{1}\"", arg);
} }
OptionValue ConfigReadContext::parseProtocol(const String &args) const
{
if (CaselessCmp::equal(args, kSynergyProtocolOption)) {
return static_cast<OptionValue>(ENetworkProtocol::kSynergy);
} else if (CaselessCmp::equal(args, kBarrierProtocolOption)) {
return static_cast<OptionValue>(ENetworkProtocol::kBarrier);
}
throw XConfigRead(*this, "invalid protocol argument \"%{1}\"", args);
}
OptionValue ConfigReadContext::parseCorners(const String &args) const OptionValue ConfigReadContext::parseCorners(const String &args) const
{ {
// find first token // find first token

View file

@ -537,6 +537,7 @@ public:
OptionValue parseModifierKey(const String &) const; OptionValue parseModifierKey(const String &) const;
OptionValue parseCorner(const String &) const; OptionValue parseCorner(const String &) const;
OptionValue parseCorners(const String &) const; OptionValue parseCorners(const String &) const;
OptionValue parseProtocol(const String &) const;
Config::Interval parseInterval(const ArgList &args) const; Config::Interval parseInterval(const ArgList &args) const;
void parseNameWithArgs( void parseNameWithArgs(
const String &type, const String &line, const String &delim, String::size_type &index, String &name, ArgList &args const String &type, const String &line, const String &delim, String::size_type &index, String &name, ArgList &args

View file

@ -31,6 +31,7 @@
#include "deskflow/PacketStreamFilter.h" #include "deskflow/PacketStreamFilter.h"
#include "deskflow/Screen.h" #include "deskflow/Screen.h"
#include "deskflow/StreamChunker.h" #include "deskflow/StreamChunker.h"
#include "deskflow/XDeskflow.h"
#include "deskflow/option_types.h" #include "deskflow/option_types.h"
#include "deskflow/protocol_types.h" #include "deskflow/protocol_types.h"
#include "mt/Thread.h" #include "mt/Thread.h"
@ -341,6 +342,17 @@ void Server::disconnect()
} }
} }
std::string Server::protocolString() const
{
using enum ENetworkProtocol;
if (m_protocol == kSynergy) {
return kSynergyProtocolName;
} else if (m_protocol == kBarrier) {
return kBarrierProtocolName;
}
throw XInvalidProtocol();
}
UInt32 Server::getNumClients() const UInt32 Server::getNumClients() const
{ {
return (SInt32)m_clients.size(); return (SInt32)m_clients.size();
@ -1100,7 +1112,17 @@ void Server::processOptions()
for (Config::ScreenOptions::const_iterator index = options->begin(); index != options->end(); ++index) { for (Config::ScreenOptions::const_iterator index = options->begin(); index != options->end(); ++index) {
const OptionID id = index->first; const OptionID id = index->first;
const OptionValue value = index->second; const OptionValue value = index->second;
if (id == kOptionScreenSwitchDelay) { if (id == kOptionProtocol) {
using enum ENetworkProtocol;
const auto enumValue = static_cast<ENetworkProtocol>(value);
if (enumValue == kSynergy) {
m_protocol = kSynergy;
} else if (enumValue == kBarrier) {
m_protocol = kBarrier;
} else {
throw XInvalidProtocol();
}
} else if (id == kOptionScreenSwitchDelay) {
m_switchWaitDelay = 1.0e-3 * static_cast<double>(value); m_switchWaitDelay = 1.0e-3 * static_cast<double>(value);
if (m_switchWaitDelay < 0.0) { if (m_switchWaitDelay < 0.0) {
m_switchWaitDelay = 0.0; m_switchWaitDelay = 0.0;

View file

@ -31,6 +31,7 @@
#include "deskflow/clipboard_types.h" #include "deskflow/clipboard_types.h"
#include "deskflow/key_types.h" #include "deskflow/key_types.h"
#include "deskflow/mouse_types.h" #include "deskflow/mouse_types.h"
#include "deskflow/option_types.h"
#include "server/Config.h" #include "server/Config.h"
#include <memory> #include <memory>
@ -192,6 +193,12 @@ public:
//! @name accessors //! @name accessors
//@{ //@{
//! Get the network protocol
/*!
Returns the network protocol used by the server.
*/
std::string protocolString() const;
//! Get number of connected clients //! Get number of connected clients
/*! /*!
Returns the number of connected clients, including the server itself. Returns the number of connected clients, including the server itself.
@ -422,6 +429,9 @@ private:
UInt32 m_clipboardSeqNum; UInt32 m_clipboardSeqNum;
}; };
// used in hello message sent to the client
ENetworkProtocol m_protocol;
// the primary screen client // the primary screen client
PrimaryClient *m_primaryClient; PrimaryClient *m_primaryClient;