diff --git a/ChangeLog b/ChangeLog
index d29fd8b6..85ec662c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+1.6.0
+=====
+Feature #65 - Auto config feature using Zeroconf/Bonjour
+
1.5.1
=====
Bug #3307 - Configuration file paths containing spaces don't work
diff --git a/ext/bonjour/x64/libdnssd.a b/ext/bonjour/x64/libdnssd.a
new file mode 100644
index 00000000..0e31ab58
Binary files /dev/null and b/ext/bonjour/x64/libdnssd.a differ
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index 9b1c833b..a585a232 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -41,7 +41,12 @@ SOURCES += src/main.cpp \
src/Ipc.cpp \
src/SynergyLocale.cpp \
src/QUtility.cpp \
- src/PremiumAuth.cpp
+ src/PremiumAuth.cpp \
+ src/ZeroconfServer.cpp \
+ src/ZeroconfThread.cpp \
+ src/ZeroconfRegister.cpp \
+ src/ZeroconfBrowser.cpp \
+ src/ZeroconfService.cpp
HEADERS += src/MainWindow.h \
src/AboutDialog.h \
src/ServerConfig.h \
@@ -69,7 +74,13 @@ HEADERS += src/MainWindow.h \
src/Ipc.h \
src/SynergyLocale.h \
src/QUtility.h \
- src/PremiumAuth.h
+ src/PremiumAuth.h \
+ src/ZeroconfServer.h \
+ src/ZeroconfThread.h \
+ src/ZeroconfRegister.h \
+ src/ZeroconfRecord.h \
+ src/ZeroconfBrowser.h \
+ src/ZeroconfService.h
RESOURCES += res/Synergy.qrc
RC_FILE = res/win/Synergy.rc
macx {
@@ -82,6 +93,9 @@ macx {
QMAKE_BUNDLE_DATA += QSYNERGY_ICON
LIBS += $$MACX_LIBS
}
+unix:!macx {
+ LIBS += -ldns_sd
+}
debug {
OBJECTS_DIR = tmp/debug
MOC_DIR = tmp/debug
@@ -95,5 +109,7 @@ release {
win32 {
Debug:DESTDIR = ../../bin/Debug
Release:DESTDIR = ../../bin/Release
+ LIBS += -L"../../ext/bonjour/x64" -ldnssd
+ INCLUDEPATH += "$(BONJOUR_SDK_HOME)/Include"
}
else:DESTDIR = ../../bin
diff --git a/src/gui/res/MainWindowBase.ui b/src/gui/res/MainWindowBase.ui
index 42a0e484..faa87258 100644
--- a/src/gui/res/MainWindowBase.ui
+++ b/src/gui/res/MainWindowBase.ui
@@ -252,7 +252,7 @@
- &Client (use another computer's keyboard and mouse):
+ &Client (use another computer's mouse and keyboard):
true
diff --git a/src/gui/res/SetupWizardBase.ui b/src/gui/res/SetupWizardBase.ui
index 32407740..b6f25474 100644
--- a/src/gui/res/SetupWizardBase.ui
+++ b/src/gui/res/SetupWizardBase.ui
@@ -128,7 +128,7 @@
-
- Yes, I have Synergy Premium
+ I donated to Synergy and have a premium login...
@@ -289,33 +289,10 @@
- -
-
-
- Tell me more...
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 5
-
-
-
-
-
- Not interested
+ No, I have not donated to Synergy, skip this step
@@ -360,7 +337,7 @@
- &Server (new setup)
+ &Server (share this computer's mouse and keyboard)
@@ -373,7 +350,11 @@
- This is the first computer you are configuring. Your keyboard and mouse are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html>
true
@@ -405,7 +386,7 @@
- &Client (add to setup)
+ &Client (use another computer's mouse and keyboard)
@@ -418,7 +399,11 @@
- You have already set up a server. This is a computer you wish to control using the server's keyboard and mouse. There can be many clients in your setup.
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html>
true
@@ -443,225 +428,15 @@
-
-
-
- 0
- 0
-
-
-
- Encryption
-
-
- -
-
-
- Network traffic can be easily monitored on public networks (e.g. schools and corporate networks) or WiFi networks. Using encryption can reduce the risk that sensitive information (e.g. passwords) will be revealed to others.
-
-
- true
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 10
-
-
-
-
- -
-
-
-
- 75
- true
-
-
-
- Enable encryption
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Fixed
-
-
-
- 20
- 10
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- A longer password will provide stronger encryption. It is a good idea to use 20 characters or more.
-
-
- true
-
-
-
- -
-
-
-
-
-
-
- 100
- 0
-
-
-
-
- 75
- true
-
-
-
- &Password:
-
-
- 10
-
-
- m_pLineEditCryptoPassword1
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
- 200
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
- QLineEdit::Password
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 75
- true
-
-
-
- &Confirm:
-
-
- 10
-
-
- m_pLineEditCryptoPassword2
-
-
-
- -
-
-
- false
-
-
-
- 0
- 0
-
-
-
-
- 200
- 0
-
-
-
- QLineEdit::Password
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 100
-
-
-
-
-
-
m_pComboLanguage
m_pRadioButtonPremiumLogin
m_pLineEditPremiumEmail
m_pLineEditPremiumPassword
- m_pRadioButtonPremiumRegister
m_pRadioButtonPremiumLater
m_pServerRadioButton
m_pClientRadioButton
- m_pLineEditCryptoPassword1
- m_pLineEditCryptoPassword2
diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp
index 555d62f3..dbb70d8b 100644
--- a/src/gui/src/MainWindow.cpp
+++ b/src/gui/src/MainWindow.cpp
@@ -25,6 +25,7 @@
#include "ServerConfigDialog.h"
#include "SettingsDialog.h"
#include "SetupWizard.h"
+#include "ZeroconfService.h"
#include
#include
@@ -64,7 +65,7 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
m_AppConfig(appConfig),
m_pSynergy(NULL),
m_SynergyState(synergyDisconnected),
- m_ServerConfig(&m_Settings, 5, 3),
+ m_ServerConfig(&m_Settings, 5, 3, m_AppConfig.screenName()),
m_pTempConfigFile(NULL),
m_pTrayIcon(NULL),
m_pTrayIconMenu(NULL),
@@ -75,7 +76,8 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
m_pMenuFile(NULL),
m_pMenuEdit(NULL),
m_pMenuWindow(NULL),
- m_pMenuHelp(NULL)
+ m_pMenuHelp(NULL),
+ m_pZeroconfService(NULL)
{
setupUi(this);
@@ -107,16 +109,20 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
resize(700, 530);
setMinimumSize(size());
#endif
+
+ updateZeroconfService();
+
}
MainWindow::~MainWindow()
{
- if (appConfig().processMode() == Desktop)
- {
+ if (appConfig().processMode() == Desktop) {
stopDesktop();
}
saveSettings();
+
+ delete m_pZeroconfService;
}
void MainWindow::open()
@@ -382,13 +388,13 @@ void MainWindow::startSynergy()
args << "-f" << "--no-tray" << "--debug" << appConfig().logLevelText();
- if (!appConfig().screenName().isEmpty())
- args << "--name" << appConfig().screenName();
- if (appConfig().cryptoEnabled())
- {
- args << "--crypto-pass" << appConfig().cryptoPass();
- }
+ args << "--name" << getScreenName();
+
+ if (appConfig().cryptoEnabled())
+ {
+ args << "--crypto-pass" << appConfig().cryptoPass();
+ }
if (desktopMode)
{
@@ -553,7 +559,8 @@ QString MainWindow::configFilename()
QString MainWindow::address()
{
- return (!appConfig().interface().isEmpty() ? appConfig().interface() : "") + ":" + QString::number(appConfig().port());
+ QString i = appConfig().interface();
+ return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port());
}
QString MainWindow::appPath(const QString& name)
@@ -796,6 +803,29 @@ void MainWindow::updatePremiumInfo()
}
}
+void MainWindow::updateZeroconfService()
+{
+ if (!m_AppConfig.wizardShouldRun()) {
+ if (m_pZeroconfService) {
+ delete m_pZeroconfService;
+ }
+
+ m_pZeroconfService = new ZeroconfService(this);
+ }
+}
+
+void MainWindow::on_m_pGroupClient_toggled(bool on)
+{
+ m_pGroupServer->setChecked(!on);
+ updateZeroconfService();
+}
+
+void MainWindow::on_m_pGroupServer_toggled(bool on)
+{
+ m_pGroupClient->setChecked(!on);
+ updateZeroconfService();
+}
+
bool MainWindow::on_m_pButtonBrowseConfigFile_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Browse for a synergys config file"), QString(), synergyConfigFilter);
@@ -841,12 +871,37 @@ void MainWindow::on_m_pActionSettings_triggered()
}
}
-void MainWindow::on_m_pButtonConfigureServer_clicked()
+void MainWindow::autoAddScreen(const QString name)
+{
+ int r = m_ServerConfig.autoAddScreen(name);
+ if (r != kAutoAddScreenOk) {
+ switch (r) {
+ case kAutoAddScreenNoServer:
+ showConfigureServer(
+ tr("Please add the server (%1) to the grid.")
+ .arg(appConfig().screenName()));
+ break;
+
+ case kAutoAddScreenNoSpace:
+ showConfigureServer(
+ tr("Please add the client (%1) to the grid.").arg(name));
+ break;
+ }
+ }
+}
+
+void MainWindow::showConfigureServer(const QString& message)
{
ServerConfigDialog dlg(this, serverConfig(), appConfig().screenName());
+ dlg.message(message);
dlg.exec();
}
+void MainWindow::on_m_pButtonConfigureServer_clicked()
+{
+ showConfigureServer();
+}
+
void MainWindow::on_m_pActionWizard_triggered()
{
SetupWizard wizard(*this, false);
diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h
index 5ff697fe..0efea0ef 100644
--- a/src/gui/src/MainWindow.h
+++ b/src/gui/src/MainWindow.h
@@ -49,6 +49,7 @@ class QTemporaryFile;
class LogDialog;
class QSynergyApplication;
class SetupWizard;
+class ZeroconfService;
class MainWindow : public QMainWindow, public Ui::MainWindowBase
{
@@ -91,6 +92,13 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void open();
void clearLog();
VersionChecker& versionChecker() { return m_VersionChecker; }
+ QString getScreenName();
+ void startSynergy();
+ ServerConfig& serverConfig() { return m_ServerConfig; }
+ void showConfigureServer(const QString& message);
+ void showConfigureServer() { showConfigureServer(""); }
+ void autoAddScreen(const QString name);
+ void updateZeroconfService();
public slots:
void appendLogRaw(const QString& text);
@@ -98,8 +106,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void appendLogError(const QString& text);
protected slots:
- void on_m_pGroupClient_toggled(bool on) { m_pGroupServer->setChecked(!on); }
- void on_m_pGroupServer_toggled(bool on) { m_pGroupClient->setChecked(!on); }
+ void on_m_pGroupClient_toggled(bool on);
+ void on_m_pGroupServer_toggled(bool on);
bool on_m_pButtonBrowseConfigFile_clicked();
void on_m_pButtonConfigureServer_clicked();
bool on_m_pActionSave_triggered();
@@ -109,7 +117,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void on_m_pElevateCheckBox_toggled(bool checked);
void synergyFinished(int exitCode, QProcess::ExitStatus);
void trayActivated(QSystemTrayIcon::ActivationReason reason);
- void startSynergy();
void stopSynergy();
void logOutput();
void logError();
@@ -120,7 +127,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
AppConfig& appConfig() { return m_AppConfig; }
QProcess*& synergyProcess() { return m_pSynergy; }
void setSynergyProcess(QProcess* p) { m_pSynergy = p; }
- ServerConfig& serverConfig() { return m_ServerConfig; }
void initConnections();
void createMenuBar();
void createStatusBar();
@@ -137,7 +143,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void onModeChanged(bool startDesktop, bool applyService);
void updateStateFromLogLine(const QString& line);
QString getIPAddresses();
- QString getScreenName();
void stopService();
void stopDesktop();
void changeEvent(QEvent* event);
@@ -163,6 +168,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
QMenu* m_pMenuEdit;
QMenu* m_pMenuWindow;
QMenu* m_pMenuHelp;
+ ZeroconfService* m_pZeroconfService;
private slots:
void on_m_pButtonApply_clicked();
diff --git a/src/gui/src/Screen.h b/src/gui/src/Screen.h
index c8bf8cfc..855b265b 100644
--- a/src/gui/src/Screen.h
+++ b/src/gui/src/Screen.h
@@ -64,12 +64,12 @@ class Screen : public BaseConfig
QTextStream& writeAliasesSection(QTextStream& outStream) const;
bool swapped() const { return m_Swapped; }
+ QString& name() { return m_Name; }
+ void setName(const QString& name) { m_Name = name; }
protected:
void init();
- void setName(const QString& name) { m_Name = name; }
QPixmap* pixmap() { return &m_Pixmap; }
- QString& name() { return m_Name; }
void setPixmap(const QPixmap& pixmap) { m_Pixmap = pixmap; }
QStringList& aliases() { return m_Aliases; }
diff --git a/src/gui/src/ServerConfig.cpp b/src/gui/src/ServerConfig.cpp
index 7823e19f..12819c1a 100644
--- a/src/gui/src/ServerConfig.cpp
+++ b/src/gui/src/ServerConfig.cpp
@@ -28,18 +28,21 @@ static const struct
const char* name;
} neighbourDirs[] =
{
- { 0, -1, "up" },
{ 1, 0, "right" },
- { 0, 1, "down" },
{ -1, 0, "left" },
+ { 0, -1, "up" },
+ { 0, 1, "down" },
+
};
+const int serverDefaultIndex = 7;
-ServerConfig::ServerConfig(QSettings* settings, int numColumns, int numRows) :
+ServerConfig::ServerConfig(QSettings* settings, int numColumns, int numRows , QString serverName) :
m_pSettings(settings),
m_Screens(),
m_NumColumns(numColumns),
- m_NumRows(numRows)
+ m_NumRows(numRows),
+ m_ServerName(serverName)
{
Q_ASSERT(m_pSettings);
@@ -263,3 +266,62 @@ int ServerConfig::numScreens() const
return rval;
}
+
+int ServerConfig::autoAddScreen(const QString name)
+{
+ int serverIndex = -1;
+ int targetIndex = -1;
+ if (!findScreenName(m_ServerName, serverIndex)) {
+ if (!tryFixNoServer(m_ServerName, serverIndex)) {
+ return kAutoAddScreenNoServer;
+ }
+ }
+ if (findScreenName(name, targetIndex)) {
+ // already exists.
+ return kAutoAddScreenOk;
+ }
+
+ bool success = false;
+ for (unsigned int i = 0; i < sizeof(neighbourDirs) / sizeof(neighbourDirs[0]); i++) {
+ int idx = adjacentScreenIndex(serverIndex, neighbourDirs[i].x, neighbourDirs[i].y);
+ if (idx != -1 && screens()[idx].isNull()) {
+ m_Screens[idx].setName(name);
+ success = true;
+ break;
+ }
+ }
+
+ if (!success) {
+ return kAutoAddScreenNoSpace;
+ }
+
+ saveSettings();
+ return kAutoAddScreenOk;
+}
+
+bool ServerConfig::findScreenName(const QString& name, int& index)
+{
+ bool found = false;
+ for (int i = 0; i < screens().size(); i++) {
+ QString test = screens()[i].name();
+ if (!screens()[i].isNull() &&
+ screens()[i].name().compare(name) == 0) {
+ index = i;
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+bool ServerConfig::tryFixNoServer(const QString& name, int& index)
+{
+ bool fixed = false;
+ if (screens()[serverDefaultIndex].isNull()) {
+ m_Screens[serverDefaultIndex].setName(name);
+ index = serverDefaultIndex;
+ fixed = true;
+ }
+
+ return fixed;
+}
diff --git a/src/gui/src/ServerConfig.h b/src/gui/src/ServerConfig.h
index d1b5d75d..89a6d7cd 100644
--- a/src/gui/src/ServerConfig.h
+++ b/src/gui/src/ServerConfig.h
@@ -38,7 +38,7 @@ class ServerConfig : public BaseConfig
friend QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config);
public:
- ServerConfig(QSettings* settings, int numColumns, int numRows);
+ ServerConfig(QSettings* settings, int numColumns, int numRows, QString serverName);
~ServerConfig();
public:
@@ -64,6 +64,7 @@ class ServerConfig : public BaseConfig
bool save(const QString& fileName) const;
void save(QFile& file) const;
int numScreens() const;
+ int autoAddScreen(const QString name);
protected:
QSettings& settings() { return *m_pSettings; }
@@ -89,6 +90,10 @@ class ServerConfig : public BaseConfig
void init();
int adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const;
+ private:
+ bool findScreenName(const QString& name, int& index);
+ bool tryFixNoServer(const QString& name, int& index);
+
private:
QSettings* m_pSettings;
ScreenList m_Screens;
@@ -106,9 +111,16 @@ class ServerConfig : public BaseConfig
int m_SwitchCornerSize;
QList m_SwitchCorners;
HotkeyList m_Hotkeys;
+ QString m_ServerName;
};
QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config);
+enum {
+ kAutoAddScreenOk,
+ kAutoAddScreenNoServer,
+ kAutoAddScreenNoSpace
+};
+
#endif
diff --git a/src/gui/src/ServerConfigDialog.cpp b/src/gui/src/ServerConfigDialog.cpp
index d37d29a5..1ff11ec5 100644
--- a/src/gui/src/ServerConfigDialog.cpp
+++ b/src/gui/src/ServerConfigDialog.cpp
@@ -23,13 +23,15 @@
#include
#include
+#include
ServerConfigDialog::ServerConfigDialog(QWidget* parent, ServerConfig& config, const QString& defaultScreenName) :
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
Ui::ServerConfigDialogBase(),
m_OrigServerConfig(config),
m_ServerConfig(config),
- m_ScreenSetupModel(serverConfig().screens(), serverConfig().numColumns(), serverConfig().numRows())
+ m_ScreenSetupModel(serverConfig().screens(), serverConfig().numColumns(), serverConfig().numRows()),
+ m_Message("")
{
setupUi(this);
@@ -61,6 +63,17 @@ ServerConfigDialog::ServerConfigDialog(QWidget* parent, ServerConfig& config, co
model().screen(serverConfig().numColumns() / 2, serverConfig().numRows() / 2) = Screen(defaultScreenName);
}
+void ServerConfigDialog::showEvent(QShowEvent* event)
+{
+ QDialog::show();
+
+ if (!m_Message.isEmpty())
+ {
+ // TODO: ideally this massage box should pop up after the dialog is shown
+ QMessageBox::information(this, tr("Configure server"), m_Message);
+ }
+}
+
void ServerConfigDialog::accept()
{
serverConfig().haveHeartbeat(m_pCheckBoxHeartbeat->isChecked());
diff --git a/src/gui/src/ServerConfigDialog.h b/src/gui/src/ServerConfigDialog.h
index f27abe87..1752b82a 100644
--- a/src/gui/src/ServerConfigDialog.h
+++ b/src/gui/src/ServerConfigDialog.h
@@ -36,6 +36,8 @@ class ServerConfigDialog : public QDialog, public Ui::ServerConfigDialogBase
public slots:
void accept();
+ void showEvent(QShowEvent* event);
+ void message(const QString& message) { m_Message = message; }
protected slots:
void on_m_pButtonNewHotkey_clicked();
@@ -57,6 +59,7 @@ class ServerConfigDialog : public QDialog, public Ui::ServerConfigDialogBase
ServerConfig& m_OrigServerConfig;
ServerConfig m_ServerConfig;
ScreenSetupModel m_ScreenSetupModel;
+ QString m_Message;
};
#endif
diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp
index 3ad12098..924e677a 100644
--- a/src/gui/src/SetupWizard.cpp
+++ b/src/gui/src/SetupWizard.cpp
@@ -105,13 +105,6 @@ bool SetupWizard::validateCurrentPage()
return false;
}
}
- else if (m_pRadioButtonPremiumRegister->isChecked())
- {
- const QUrl url(QString(PREMIUM_REGISTER_URL));
- QDesktopServices::openUrl(url);
- m_pRadioButtonPremiumLogin->setChecked(true);
- return false;
- }
else if (m_pRadioButtonPremiumLater->isChecked())
{
return true;
@@ -122,25 +115,6 @@ bool SetupWizard::validateCurrentPage()
return false;
}
}
- else if (currentPage() == m_pCryptoPage)
- {
- if (m_pCheckBoxEnableCrypto->isChecked())
- {
- if (m_pLineEditCryptoPassword1->text().isEmpty())
- {
- message.setText(tr("Encryption password required."));
- message.exec();
- return false;
- }
-
- if (m_pLineEditCryptoPassword1->text() != m_pLineEditCryptoPassword2->text())
- {
- message.setText(tr("Encryption password and confirmation do not match."));
- message.exec();
- return false;
- }
- }
- }
return true;
}
@@ -169,8 +143,6 @@ void SetupWizard::accept()
{
AppConfig& appConfig = m_MainWindow.appConfig();
- appConfig.setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
- appConfig.setCryptoPass(m_pLineEditCryptoPassword1->text());
appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text());
@@ -205,6 +177,7 @@ void SetupWizard::accept()
if (m_StartMain)
{
+ m_MainWindow.updateZeroconfService();
m_MainWindow.open();
}
@@ -225,14 +198,6 @@ void SetupWizard::reject()
void SetupWizard::on_m_pCheckBoxEnableCrypto_stateChanged(int )
{
- bool enabled = m_pCheckBoxEnableCrypto->isChecked();
- m_pLineEditCryptoPassword1->setEnabled(enabled);
- m_pLineEditCryptoPassword2->setEnabled(enabled);
- if (!enabled)
- {
- m_pLineEditCryptoPassword1->clear();
- m_pLineEditCryptoPassword2->clear();
- }
}
void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index)
diff --git a/src/gui/src/ZeroconfBrowser.cpp b/src/gui/src/ZeroconfBrowser.cpp
new file mode 100644
index 00000000..690ec54c
--- /dev/null
+++ b/src/gui/src/ZeroconfBrowser.cpp
@@ -0,0 +1,88 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfBrowser.h"
+
+#include
+
+ZeroconfBrowser::ZeroconfBrowser(QObject* parent) :
+ QObject(parent),
+ m_DnsServiceRef(0),
+ m_pSocket(0)
+{
+}
+
+ZeroconfBrowser::~ZeroconfBrowser()
+{
+ if (m_DnsServiceRef) {
+ DNSServiceRefDeallocate(m_DnsServiceRef);
+ m_DnsServiceRef = 0;
+ }
+}
+
+void ZeroconfBrowser::browseForType(const QString& type)
+{
+ DNSServiceErrorType err = DNSServiceBrowse(&m_DnsServiceRef, 0, 0,
+ type.toUtf8().constData(), 0, browseReply, this);
+
+ if (err != kDNSServiceErr_NoError) {
+ emit error(err);
+ }
+ else {
+ int sockFD = DNSServiceRefSockFD(m_DnsServiceRef);
+ if (sockFD == -1) {
+ emit error(kDNSServiceErr_Invalid);
+ }
+ else {
+ m_pSocket = new QSocketNotifier(sockFD, QSocketNotifier::Read, this);
+ connect(m_pSocket, SIGNAL(activated(int)), this,
+ SLOT(socketReadyRead()));
+ }
+ }
+}
+
+void ZeroconfBrowser::socketReadyRead()
+{
+ DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef);
+ if (err != kDNSServiceErr_NoError) {
+ emit error(err);
+ }
+}
+
+void ZeroconfBrowser::browseReply(DNSServiceRef, DNSServiceFlags flags,
+ quint32, DNSServiceErrorType errorCode, const char* serviceName,
+ const char* regType, const char* replyDomain, void* context)
+{
+ ZeroconfBrowser* browser = static_cast(context);
+ if (errorCode != kDNSServiceErr_NoError) {
+ emit browser->error(errorCode);
+ }
+ else {
+ ZeroconfRecord record(serviceName, regType, replyDomain);
+ if (flags & kDNSServiceFlagsAdd) {
+ if (!browser->m_Records.contains(record)) {
+ browser->m_Records.append(record);
+ }
+ }
+ else {
+ browser->m_Records.removeAll(record);
+ }
+ if (!(flags & kDNSServiceFlagsMoreComing)) {
+ emit browser->currentRecordsChanged(browser->m_Records);
+ }
+ }
+}
diff --git a/src/gui/src/ZeroconfBrowser.h b/src/gui/src/ZeroconfBrowser.h
new file mode 100644
index 00000000..ce8218eb
--- /dev/null
+++ b/src/gui/src/ZeroconfBrowser.h
@@ -0,0 +1,57 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfRecord.h"
+
+#include
+#define _MSL_STDINT_H
+#include
+#include
+
+class QSocketNotifier;
+
+class ZeroconfBrowser : public QObject
+{
+ Q_OBJECT
+
+public:
+ ZeroconfBrowser(QObject* parent = 0);
+ ~ZeroconfBrowser();
+ void browseForType(const QString& type);
+ inline QList currentRecords() const { return m_Records; }
+ inline QString serviceType() const { return m_BrowsingType; }
+
+signals:
+ void currentRecordsChanged(const QList& list);
+ void error(DNSServiceErrorType err);
+
+private slots:
+ void socketReadyRead();
+
+private:
+ static void DNSSD_API browseReply(DNSServiceRef, DNSServiceFlags flags,
+ quint32, DNSServiceErrorType errorCode, const char* serviceName,
+ const char* regType, const char* replyDomain, void* context);
+
+private:
+ DNSServiceRef m_DnsServiceRef;
+ QSocketNotifier* m_pSocket;
+ QList m_Records;
+ QString m_BrowsingType;
+};
diff --git a/src/gui/src/ZeroconfRecord.h b/src/gui/src/ZeroconfRecord.h
new file mode 100644
index 00000000..2e1e739f
--- /dev/null
+++ b/src/gui/src/ZeroconfRecord.h
@@ -0,0 +1,50 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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
+
+class ZeroconfRecord
+{
+public:
+ ZeroconfRecord() {}
+ ZeroconfRecord(const QString& name, const QString& regType,
+ const QString& domain)
+ : serviceName(name), registeredType(regType), replyDomain(domain)
+ {}
+ ZeroconfRecord(const char* name, const char* regType, const char* domain)
+ {
+ serviceName = QString::fromUtf8(name);
+ registeredType = QString::fromUtf8(regType);
+ replyDomain = QString::fromUtf8(domain);
+ }
+
+ bool operator==(const ZeroconfRecord& other) const {
+ return serviceName == other.serviceName
+ && registeredType == other.registeredType
+ && replyDomain == other.replyDomain;
+ }
+
+public:
+ QString serviceName;
+ QString registeredType;
+ QString replyDomain;
+};
+
+Q_DECLARE_METATYPE(ZeroconfRecord)
diff --git a/src/gui/src/ZeroconfRegister.cpp b/src/gui/src/ZeroconfRegister.cpp
new file mode 100644
index 00000000..83408376
--- /dev/null
+++ b/src/gui/src/ZeroconfRegister.cpp
@@ -0,0 +1,89 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfRegister.h"
+
+#include
+
+ZeroconfRegister::ZeroconfRegister(QObject* parent) :
+ QObject(parent),
+ m_DnsServiceRef(0),
+ m_pSocket(0)
+{
+}
+
+ZeroconfRegister::~ZeroconfRegister()
+{
+ if (m_DnsServiceRef) {
+ DNSServiceRefDeallocate(m_DnsServiceRef);
+ m_DnsServiceRef = 0;
+ }
+}
+
+void ZeroconfRegister::registerService(const ZeroconfRecord& record,
+ quint16 servicePort)
+{
+ if (m_DnsServiceRef) {
+ qWarning("Warning: Already registered a service for this object");
+ return;
+ }
+
+ quint16 bigEndianPort = servicePort;
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ {
+ bigEndianPort = 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8);
+ }
+#endif
+
+ DNSServiceErrorType err = DNSServiceRegister(&m_DnsServiceRef, 0, 0,
+ record.serviceName.toUtf8().constData(),
+ record.registeredType.toUtf8().constData(),
+ record.replyDomain.isEmpty() ? 0 : record.replyDomain.toUtf8().constData(),
+ 0, bigEndianPort, 0, 0, registerService, this);
+
+ if (err != kDNSServiceErr_NoError) {
+ emit error(err);
+ }
+ else {
+ int sockfd = DNSServiceRefSockFD(m_DnsServiceRef);
+ if (sockfd == -1) {
+ emit error(kDNSServiceErr_Invalid);
+ }
+ else {
+ m_pSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
+ connect(m_pSocket, SIGNAL(activated(int)), this, SLOT(socketReadyRead()));
+ }
+ }
+}
+
+void ZeroconfRegister::socketReadyRead()
+{
+ DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef);
+ if (err != kDNSServiceErr_NoError) {
+ emit error(err);
+ }
+}
+
+void ZeroconfRegister::registerService(DNSServiceRef, DNSServiceFlags,
+ DNSServiceErrorType errorCode, const char* name, const char* regtype,
+ const char* domain, void* data)
+{
+ ZeroconfRegister* serviceRegister = static_cast(data);
+ if (errorCode != kDNSServiceErr_NoError) {
+ emit serviceRegister->error(errorCode);
+ }
+}
diff --git a/src/gui/src/ZeroconfRegister.h b/src/gui/src/ZeroconfRegister.h
new file mode 100644
index 00000000..726905ec
--- /dev/null
+++ b/src/gui/src/ZeroconfRegister.h
@@ -0,0 +1,61 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfRecord.h"
+
+class QSocketNotifier;
+
+// Bonjour flags
+#define _MSL_STDINT_H
+#include
+#if defined(Q_OS_WIN)
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include
+
+class ZeroconfRegister : public QObject
+{
+ Q_OBJECT
+
+public:
+ ZeroconfRegister(QObject* parent = 0);
+ ~ZeroconfRegister();
+
+ void registerService(const ZeroconfRecord& record, quint16 servicePort);
+ inline ZeroconfRecord registeredRecord() const { return finalRecord; }
+
+signals:
+ void error(DNSServiceErrorType error);
+ void serviceRegistered(const ZeroconfRecord& record);
+
+private slots:
+ void socketReadyRead();
+
+private:
+ static void DNSSD_API registerService(DNSServiceRef sdRef,
+ DNSServiceFlags, DNSServiceErrorType errorCode, const char* name,
+ const char* regtype, const char* domain, void* context);
+
+private:
+ DNSServiceRef m_DnsServiceRef;
+ QSocketNotifier* m_pSocket;
+ ZeroconfRecord finalRecord;
+};
diff --git a/src/gui/src/ZeroconfServer.cpp b/src/gui/src/ZeroconfServer.cpp
new file mode 100644
index 00000000..a7297659
--- /dev/null
+++ b/src/gui/src/ZeroconfServer.cpp
@@ -0,0 +1,33 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfServer.h"
+#include "ZeroconfThread.h"
+
+#include
+
+ZeroconfServer::ZeroconfServer(QObject* parent) :
+ QTcpServer(parent)
+{
+}
+
+void ZeroconfServer::incomingConnection(int socketDescriptor)
+{
+ ZeroconfThread* thread = new ZeroconfThread(socketDescriptor, this);
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+}
diff --git a/src/gui/src/ZeroconfServer.h b/src/gui/src/ZeroconfServer.h
new file mode 100644
index 00000000..2b658e48
--- /dev/null
+++ b/src/gui/src/ZeroconfServer.h
@@ -0,0 +1,37 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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
+
+class ZeroconfRegister;
+
+class ZeroconfServer : public QTcpServer
+{
+ Q_OBJECT
+
+public:
+ ZeroconfServer(QObject* parent = 0);
+
+protected:
+ void incomingConnection(int socketDescriptor);
+
+private:
+ QStringList fortunes;
+};
diff --git a/src/gui/src/ZeroconfService.cpp b/src/gui/src/ZeroconfService.cpp
new file mode 100644
index 00000000..3660a312
--- /dev/null
+++ b/src/gui/src/ZeroconfService.cpp
@@ -0,0 +1,145 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfService.h"
+
+#include "MainWindow.h"
+#include "ZeroconfRegister.h"
+#include "ZeroconfBrowser.h"
+
+#include
+#include
+#define _MSL_STDINT_H
+#include
+#include
+
+const char* ZeroconfService:: m_ServerServiceName = "_synergyServerZeroconf._tcp";
+const char* ZeroconfService:: m_ClientServiceName = "_synergyClientZeroconf._tcp";
+
+ZeroconfService::ZeroconfService(MainWindow* mainWindow) :
+ m_pMainWindow(mainWindow),
+ m_pZeroconfBrowser(0),
+ m_pZeroconfRegister(0),
+ m_ServiceRegistered(false)
+{
+ if (m_pMainWindow->synergyType() == MainWindow::synergyServer) {
+ if (registerService(true)) {
+ m_pZeroconfBrowser = new ZeroconfBrowser(this);
+ connect(m_pZeroconfBrowser, SIGNAL(
+ currentRecordsChanged(const QList&)),
+ this, SLOT(clientDetected(const QList&)));
+ m_pZeroconfBrowser->browseForType(
+ QLatin1String(m_ClientServiceName));
+ }
+ }
+ else {
+ m_pZeroconfBrowser = new ZeroconfBrowser(this);
+ connect(m_pZeroconfBrowser, SIGNAL(
+ currentRecordsChanged(const QList&)),
+ this, SLOT(serverDetected(const QList&)));
+ m_pZeroconfBrowser->browseForType(
+ QLatin1String(m_ServerServiceName));
+ }
+
+ connect(m_pZeroconfBrowser, SIGNAL(error(DNSServiceErrorType)),
+ this, SLOT(errorHandle(int32_t)));
+}
+
+ZeroconfService::~ZeroconfService()
+{
+ if (m_pZeroconfBrowser) {
+ delete m_pZeroconfBrowser;
+ }
+ if (m_pZeroconfRegister) {
+ delete m_pZeroconfRegister;
+ }
+}
+
+void ZeroconfService::serverDetected(const QList& list)
+{
+ foreach (ZeroconfRecord record, list) {
+ registerService(false);
+ m_pMainWindow->m_pLineEditHostname->setText(record.serviceName);
+ m_pMainWindow->appendLogNote(tr("zeroconf server detected: %1").arg(
+ record.serviceName));
+ }
+
+ if (!list.isEmpty()) {
+ m_pMainWindow->startSynergy();
+ }
+}
+
+void ZeroconfService::clientDetected(const QList& list)
+{
+ foreach (ZeroconfRecord record, list) {
+ m_pMainWindow->appendLogNote(tr("zeroconf client detected: %1").arg(
+ record.serviceName));
+ m_pMainWindow->autoAddScreen(record.serviceName);
+ }
+
+ if (!list.isEmpty()) {
+ m_pMainWindow->startSynergy();
+ }
+}
+
+void ZeroconfService::errorHandle(int32_t errorCode)
+{
+ QMessageBox::critical(0, tr("Zero configuration service"),
+ tr("Error code: %1.").arg(errorCode));
+}
+
+QString ZeroconfService::getLocalIPAddresses()
+{
+ foreach (const QHostAddress& address, QNetworkInterface::allAddresses()) {
+ if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))
+ return address.toString();
+ }
+ return "";
+}
+
+bool ZeroconfService::registerService(bool server)
+{
+ bool result = true;
+
+ if (!m_ServiceRegistered) {
+ if (!m_zeroconfServer.listen()) {
+ QMessageBox::critical(0, tr("Zero configuration service"),
+ tr("Unable to start the zeroconf: %1.")
+ .arg(m_zeroconfServer.errorString()));
+ result = false;
+ }
+ else {
+ m_pZeroconfRegister = new ZeroconfRegister(this);
+ if (server) {
+ m_pZeroconfRegister->registerService(
+ ZeroconfRecord(tr("%1").arg(getLocalIPAddresses()),
+ QLatin1String(m_ServerServiceName), QString()),
+ m_zeroconfServer.serverPort());
+ }
+ else {
+ m_pZeroconfRegister->registerService(
+ ZeroconfRecord(tr("%1").arg(m_pMainWindow->getScreenName()),
+ QLatin1String(m_ClientServiceName), QString()),
+ m_zeroconfServer.serverPort());
+ }
+
+ m_ServiceRegistered = true;
+ }
+ }
+
+ return result;
+}
diff --git a/src/gui/src/ZeroconfService.h b/src/gui/src/ZeroconfService.h
new file mode 100644
index 00000000..44782a5d
--- /dev/null
+++ b/src/gui/src/ZeroconfService.h
@@ -0,0 +1,55 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfServer.h"
+#include "ZeroconfRecord.h"
+
+#include
+
+class ZeroconfRegister;
+class ZeroconfBrowser;
+class MainWindow;
+
+class ZeroconfService : public QObject
+{
+ Q_OBJECT
+
+public:
+ ZeroconfService(MainWindow* mainWindow);
+ ~ZeroconfService();
+
+private slots:
+ void serverDetected(const QList& list);
+ void clientDetected(const QList& list);
+ void errorHandle(int32_t errorCode);
+
+private:
+ QString getLocalIPAddresses();
+ bool registerService(bool server);
+
+private:
+ MainWindow* m_pMainWindow;
+ ZeroconfServer m_zeroconfServer;
+ ZeroconfBrowser* m_pZeroconfBrowser;
+ ZeroconfRegister* m_pZeroconfRegister;
+ bool m_ServiceRegistered;
+
+ static const char* m_ServerServiceName;
+ static const char* m_ClientServiceName;
+};
diff --git a/src/gui/src/ZeroconfThread.cpp b/src/gui/src/ZeroconfThread.cpp
new file mode 100644
index 00000000..41f37adf
--- /dev/null
+++ b/src/gui/src/ZeroconfThread.cpp
@@ -0,0 +1,38 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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 "ZeroconfThread.h"
+
+#include
+
+ZeroconfThread::ZeroconfThread(int socketDescriptor, QObject* parent) :
+ QThread(parent),
+ m_SocketDescriptor(socketDescriptor)
+{
+}
+
+void ZeroconfThread::run()
+{
+ QTcpSocket tcpSocket;
+ if (!tcpSocket.setSocketDescriptor(m_SocketDescriptor)) {
+ emit error(tcpSocket.error());
+ return;
+ }
+
+ tcpSocket.disconnectFromHost();
+ tcpSocket.waitForDisconnected();
+}
diff --git a/src/gui/src/ZeroconfThread.h b/src/gui/src/ZeroconfThread.h
new file mode 100644
index 00000000..42347ff3
--- /dev/null
+++ b/src/gui/src/ZeroconfThread.h
@@ -0,0 +1,38 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2014 Bolton Software 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 COPYING 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
+
+class ZeroconfThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ ZeroconfThread(int socketDescriptor, QObject* parent);
+
+ void run();
+
+signals:
+ void error(QTcpSocket::SocketError socketError);
+
+private:
+ int m_SocketDescriptor;
+ QString m_Text;
+};