- made windows gui service only (removed desktop mode).

- changed watchdog to only launch if it has a command.
This commit is contained in:
Nick Bolton 2013-10-15 15:46:02 +00:00
parent 8040f1c5a3
commit 658a3e3e8f
11 changed files with 92 additions and 245 deletions

View File

@ -364,6 +364,9 @@
</item>
<item>
<widget class="QPushButton" name="m_pButtonApply">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Apply</string>
</property>

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>368</width>
<height>485</height>
<height>354</height>
</rect>
</property>
<property name="windowTitle">
@ -89,30 +89,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="m_pLabel_22">
<property name="text">
<string>&amp;Process mode:</string>
</property>
<property name="buddy">
<cstring>m_pComboProcessMode</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="m_pComboProcessMode">
<item>
<property name="text">
<string>Service</string>
</property>
</item>
<item>
<property name="text">
<string>Desktop (legacy)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="m_pLabel_27">
<property name="sizePolicy">
@ -141,36 +117,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_pGroupUserInterface">
<property name="title">
<string>&amp;Startup</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoStart">
<property name="text">
<string>&amp;Start Synergy after logging in</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoConnect">
<property name="text">
<string>&amp;Automatically start server/client</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoHide">
<property name="text">
<string>&amp;Hide when server/client starts</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_pGroupCrypto">
<property name="enabled">
@ -355,10 +301,6 @@
<tabstop>m_pLineEditScreenName</tabstop>
<tabstop>m_pSpinBoxPort</tabstop>
<tabstop>m_pLineEditInterface</tabstop>
<tabstop>m_pComboProcessMode</tabstop>
<tabstop>m_pCheckBoxAutoStart</tabstop>
<tabstop>m_pCheckBoxAutoConnect</tabstop>
<tabstop>m_pCheckBoxAutoHide</tabstop>
<tabstop>m_pLineEditCryptoPass</tabstop>
<tabstop>m_pComboLogLevel</tabstop>
<tabstop>m_pCheckBoxLogToFile</tabstop>

View File

@ -47,14 +47,10 @@ static const char* logLevelNames[] =
AppConfig::AppConfig(QSettings* settings) :
m_pSettings(settings),
m_AutoConnect(false),
m_ScreenName(),
m_Port(24800),
m_Interface(),
m_LogLevel(0),
m_AutoStart(false),
m_AutoHide(false),
m_AutoStartPrompt(false),
m_WizardLastRun(0),
m_CryptoPass(),
m_ProcessMode(DEFAULT_PROCESS_MODE)
@ -102,62 +98,15 @@ QString AppConfig::logLevelText() const
return logLevelNames[logLevel()];
}
void AppConfig::setAutoStart(bool b)
{
m_AutoStart = b;
// always create or delete the links/files/entries even if they exist already,
// in case it was broken.
#if defined(Q_OS_LINUX)
QString desktopFileName("synergy.desktop");
QString desktopFilePath("/usr/share/applications/" + desktopFileName);
QString autoStartPath(QDir::homePath() + "/.config/autostart/" + desktopFileName);
if (b)
{
QFile::link(desktopFilePath, autoStartPath);
}
else
{
QFile::remove(autoStartPath);
}
#elif defined(Q_OS_WIN)
QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
QString path("Synergy");
if (b)
{
settings.setValue(path, QCoreApplication::applicationFilePath());
}
else
{
settings.remove(path);
}
settings.sync();
#endif
// TODO: mac os x auto start
}
void AppConfig::loadSettings()
{
m_AutoConnect = settings().value("autoConnect", false).toBool();
m_ScreenName = settings().value("screenName", QHostInfo::localHostName()).toString();
m_Port = settings().value("port", 24800).toInt();
m_Interface = settings().value("interface").toString();
m_LogLevel = settings().value("logLevel", 3).toInt(); // level 3: INFO
m_LogToFile = settings().value("logToFile", false).toBool();
m_LogFilename = settings().value("logFilename", synergyLogDir() + "synergy.log").toString();
m_AutoStart = settings().value("autoStart", false).toBool();
m_AutoHide = settings().value("autoHide", true).toBool();
m_AutoStartPrompt = settings().value("autoStartPrompt", true).toBool();
m_WizardLastRun = settings().value("wizardLastRun", 0).toInt();
m_ProcessMode = (ProcessMode)settings().value("processMode2", DEFAULT_PROCESS_MODE).toInt();
m_CryptoPass = settings().value("cryptoPass", "").toString();
m_CryptoEnabled = settings().value("cryptoEnabled", false).toBool();
m_Language = settings().value("language", QLocale::system().name()).toString();
@ -167,18 +116,13 @@ void AppConfig::loadSettings()
void AppConfig::saveSettings()
{
settings().setValue("autoConnect", m_AutoConnect);
settings().setValue("screenName", m_ScreenName);
settings().setValue("port", m_Port);
settings().setValue("interface", m_Interface);
settings().setValue("logLevel", m_LogLevel);
settings().setValue("logToFile", m_LogToFile);
settings().setValue("logFilename", m_LogFilename);
settings().setValue("autoStart", m_AutoStart);
settings().setValue("autoHide", m_AutoHide);
settings().setValue("autoStartPrompt", m_AutoStartPrompt);
settings().setValue("wizardLastRun", kWizardVersion);
settings().setValue("processMode2", m_ProcessMode);
settings().setValue("cryptoPass", m_CryptoPass);
settings().setValue("cryptoEnabled", m_CryptoEnabled);
settings().setValue("language", m_Language);

View File

@ -53,7 +53,6 @@ class AppConfig
~AppConfig();
public:
bool autoConnect() const { return m_AutoConnect; }
const QString& screenName() const { return m_ScreenName; }
int port() const { return m_Port; }
const QString& interface() const { return m_Interface; }
@ -61,9 +60,6 @@ class AppConfig
bool logToFile() const { return m_LogToFile; }
const QString& logFilename() const { return m_LogFilename; }
QString logLevelText() const;
bool autoStart() const { return m_AutoStart; }
bool autoHide() const { return m_AutoHide; }
bool autoStartPrompt() const { return m_AutoStartPrompt; }
const QString& cryptoPass() const { return m_CryptoPass; }
bool cryptoEnabled() const { return m_CryptoEnabled; }
QString cryptoModeString() const;
@ -84,18 +80,13 @@ class AppConfig
protected:
QSettings& settings() { return *m_pSettings; }
void setAutoConnect(bool b) { m_AutoConnect = b; }
void setScreenName(const QString& s) { m_ScreenName = s; }
void setPort(int i) { m_Port = i; }
void setInterface(const QString& s) { m_Interface = s; }
void setLogLevel(int i) { m_LogLevel = i; }
void setLogToFile(bool b) { m_LogToFile = b; }
void setLogFilename(const QString& s) { m_LogFilename = s; }
void setAutoStart(bool b);
void setAutoHide(bool b) { m_AutoHide = b; }
void setAutoStartPrompt(bool b) { m_AutoStartPrompt = b; }
void setCryptoEnabled(bool b) { m_CryptoEnabled = b; }
void setProcessMode(ProcessMode p) { m_ProcessMode = p; }
void setWizardHasRun() { m_WizardLastRun = kWizardVersion; }
void setLanguage(const QString language) { m_Language = language; }
void setPremiumEmail(const QString premiumEmail) { m_PremiumEmail = premiumEmail; }
@ -108,16 +99,12 @@ class AppConfig
private:
QSettings* m_pSettings;
bool m_AutoConnect;
QString m_ScreenName;
int m_Port;
QString m_Interface;
int m_LogLevel;
bool m_LogToFile;
QString m_LogFilename;
bool m_AutoStart;
bool m_AutoHide;
bool m_AutoStartPrompt;
int m_WizardLastRun;
bool m_CryptoEnabled;
QString m_CryptoPass;

View File

@ -119,8 +119,6 @@ MainWindow::~MainWindow()
void MainWindow::start(bool firstRun)
{
onModeChanged(!firstRun && appConfig().autoConnect(), false);
createTrayIcon();
// always show. auto-hide only happens when we have a connection.
@ -131,8 +129,6 @@ void MainWindow::start(bool firstRun)
void MainWindow::onModeChanged(bool startDesktop, bool applyService)
{
refreshApplyButton();
if (appConfig().processMode() == Service)
{
// form is always enabled in service mode.
@ -158,11 +154,6 @@ void MainWindow::onModeChanged(bool startDesktop, bool applyService)
m_pElevateCheckBox->setEnabled(appConfig().processMode() == Service);
}
void MainWindow::refreshApplyButton()
{
m_pButtonApply->setEnabled(appConfig().processMode() == Service);
}
void MainWindow::setStatus(const QString &status)
{
m_pStatusLabel->setText(status);
@ -282,6 +273,7 @@ void MainWindow::setIcon(qSynergyState state)
void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
{
#ifndef Q_OS_WIN
if (reason == QSystemTrayIcon::DoubleClick)
{
if (isVisible())
@ -294,6 +286,7 @@ void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
activateWindow();
}
}
#endif
}
void MainWindow::logOutput()
@ -356,13 +349,6 @@ void MainWindow::updateStateFromLogLine(const QString &line)
line.contains("connected to server"))
{
setSynergyState(synergyConnected);
// only hide once after each new connection.
if (!m_AlreadyHidden && appConfig().autoHide())
{
hide();
m_AlreadyHidden = true;
}
}
}
@ -646,12 +632,14 @@ void MainWindow::setSynergyState(qSynergyState state)
disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger()));
connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger()));
m_pButtonToggleStart->setText(tr("&Stop"));
m_pButtonApply->setEnabled((appConfig().processMode() == Service));
}
else
{
disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger()));
connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger()));
m_pButtonToggleStart->setText(tr("&Start"));
m_pButtonApply->setEnabled(false);
}
bool connected = state == synergyConnected;
@ -693,9 +681,9 @@ void MainWindow::setFormEnabled(bool enabled)
void MainWindow::setVisible(bool visible)
{
QMainWindow::setVisible(visible);
m_pActionMinimize->setEnabled(visible);
m_pActionRestore->setEnabled(!visible);
QMainWindow::setVisible(visible);
#if MAC_OS_X_VERSION_10_7
// dock hide only supported on lion :(

View File

@ -114,7 +114,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void logOutput();
void logError();
void updateFound(const QString& version);
void refreshApplyButton();
protected:
QSettings& settings() { return m_Settings; }

View File

@ -34,16 +34,12 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
m_Locale.fillLanguageComboBox(m_pComboLanguage);
m_pCheckBoxAutoConnect->setChecked(appConfig().autoConnect());
m_pLineEditScreenName->setText(appConfig().screenName());
m_pSpinBoxPort->setValue(appConfig().port());
m_pLineEditInterface->setText(appConfig().interface());
m_pComboProcessMode->setCurrentIndex(appConfig().processMode());
m_pComboLogLevel->setCurrentIndex(appConfig().logLevel());
m_pCheckBoxLogToFile->setChecked(appConfig().logToFile());
m_pLineEditLogFilename->setText(appConfig().logFilename());
m_pCheckBoxAutoStart->setChecked(appConfig().autoStart());
m_pCheckBoxAutoHide->setChecked(appConfig().autoHide());
m_pCheckBoxEnableCrypto->setChecked(appConfig().cryptoEnabled());
setIndexFromItemData(m_pComboLanguage, appConfig().language());
if (appConfig().cryptoEnabled())
@ -66,16 +62,12 @@ void SettingsDialog::accept()
return;
}
appConfig().setAutoConnect(m_pCheckBoxAutoConnect->isChecked());
appConfig().setScreenName(m_pLineEditScreenName->text());
appConfig().setPort(m_pSpinBoxPort->value());
appConfig().setInterface(m_pLineEditInterface->text());
appConfig().setProcessMode((ProcessMode)m_pComboProcessMode->currentIndex());
appConfig().setLogLevel(m_pComboLogLevel->currentIndex());
appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked());
appConfig().setLogFilename(m_pLineEditLogFilename->text());
appConfig().setAutoStart(m_pCheckBoxAutoStart->isChecked());
appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked());
appConfig().setCryptoEnabled(cryptoEnabled);
appConfig().setCryptoPass(cryptoPass);
appConfig().setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
@ -98,14 +90,12 @@ void SettingsDialog::changeEvent(QEvent* event)
case QEvent::LanguageChange:
{
int logLevelIndex = m_pComboLogLevel->currentIndex();
int processModeIndex = m_pComboProcessMode->currentIndex();
m_pComboLanguage->blockSignals(true);
retranslateUi(this);
m_pComboLanguage->blockSignals(false);
m_pComboLogLevel->setCurrentIndex(logLevelIndex);
m_pComboProcessMode->setCurrentIndex(processModeIndex);
break;
}

View File

@ -50,7 +50,9 @@ int main(int argc, char* argv[])
if (!waitForTray())
return -1;
#ifndef Q_OS_WIN
QApplication::setQuitOnLastWindowClosed(false);
#endif
QSettings settings;
AppConfig appConfig(&settings);

View File

@ -54,8 +54,8 @@ CMSWindowsWatchdog::CMSWindowsWatchdog(
m_ipcServer(ipcServer),
m_ipcLogOutputter(ipcLogOutputter),
m_elevateProcess(false),
m_launched(false),
m_failures(0)
m_processFailures(0),
m_processRunning(false)
{
}
@ -165,56 +165,70 @@ CMSWindowsWatchdog::mainLoop(void*)
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
while (m_monitoring) {
// relaunch if the process was running but has stopped unexpectedly.
if ((m_launched && !isProcessRunning()) || m_session.hasChanged() || m_commandChanged) {
std::string command = getCommand();
if (command.empty()) {
// this appears on first launch when the user hasn't configured
// anything yet, so don't show it as a warning, only show it as
// debug to devs to let them know why nothing happened.
LOG((CLOG_DEBUG "nothing to launch, no command specified."));
try {
if (m_processRunning && getCommand().empty()) {
LOG((CLOG_INFO "process started but command is empty, shutting down"));
shutdownExistingProcesses();
m_processRunning = false;
continue;
}
try {
startProcess(command);
if (m_processFailures != 0) {
// increasing backoff period, maximum of 10 seconds.
int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10;
LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures));
ARCH->sleep(timeout);
}
catch (XArch& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what().c_str()));
m_launched = false;
continue;
if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) {
startProcess();
}
catch (XSynergy& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what()));
m_launched = false;
continue;
if (m_processRunning && !isProcessActive()) {
m_processFailures++;
m_processRunning = false;
LOG((CLOG_WARN "detected application not running, pid=%d",
m_processInfo.dwProcessId));
}
}
if (sendSasFunc != NULL) {
if (sendSasFunc != NULL) {
HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
if (sendSasEvent != NULL) {
HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS");
if (sendSasEvent != NULL) {
// use SendSAS event to wait for next session (timeout 1 second).
if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) {
LOG((CLOG_DEBUG "calling SendSAS"));
sendSasFunc(FALSE);
// use SendSAS event to wait for next session (timeout 1 second).
if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) {
LOG((CLOG_DEBUG "calling SendSAS"));
sendSasFunc(FALSE);
}
CloseHandle(sendSasEvent);
continue;
}
CloseHandle(sendSasEvent);
continue;
}
}
// if the sas event failed, wait by sleeping.
ARCH->sleep(1);
// if the sas event failed, wait by sleeping.
ARCH->sleep(1);
}
catch (XArch& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what().c_str()));
m_processFailures++;
m_processRunning = false;
continue;
}
catch (XSynergy& e) {
LOG((CLOG_ERR "failed to launch, error: %s", e.what()));
m_processFailures++;
m_processRunning = false;
continue;
}
}
if (m_launched) {
if (m_processRunning) {
LOG((CLOG_DEBUG "terminated running process on exit"));
shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
}
@ -223,47 +237,26 @@ CMSWindowsWatchdog::mainLoop(void*)
}
bool
CMSWindowsWatchdog::isProcessRunning()
CMSWindowsWatchdog::isProcessActive()
{
bool running;
if (m_launched) {
DWORD exitCode;
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
if (!running && !m_command.empty()) {
m_failures++;
LOG((CLOG_INFO
"detected application not running, pid=%d, failures=%d",
m_processInfo.dwProcessId, m_failures));
// increasing backoff period, maximum of 10 seconds.
int timeout = (m_failures * 2) < 10 ? (m_failures * 2) : 10;
LOG((CLOG_DEBUG "waiting, backoff period is %d seconds", timeout));
ARCH->sleep(timeout);
// double check, in case process started after we waited.
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
running = (exitCode == STILL_ACTIVE);
}
else {
// reset failures when running.
m_failures = 0;
}
}
return running;
DWORD exitCode;
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
return exitCode == STILL_ACTIVE;
}
void
CMSWindowsWatchdog::startProcess(std::string& command)
CMSWindowsWatchdog::startProcess()
{
if (m_command.empty()) {
throw XMSWindowsWatchdogError("cannot start process, command is empty");
}
m_commandChanged = false;
if (m_launched) {
if (m_processRunning) {
LOG((CLOG_DEBUG "closing existing process to make way for new one"));
shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20);
m_launched = false;
m_processRunning = false;
}
m_session.updateActiveSession();
@ -299,7 +292,7 @@ CMSWindowsWatchdog::startProcess(std::string& command)
// re-launch in current active user session
LOG((CLOG_INFO "starting new process"));
BOOL createRet = CreateProcessAsUser(
userToken, NULL, LPSTR(command.c_str()),
userToken, NULL, LPSTR(m_command.c_str()),
&sa, NULL, TRUE, creationFlags,
environment, NULL, &si, &m_processInfo);
@ -311,9 +304,11 @@ CMSWindowsWatchdog::startProcess(std::string& command)
throw XArch(new XArchEvalWindows);
}
else {
m_processRunning = true;
m_processFailures = 0;
LOG((CLOG_DEBUG "started process, session=%i, command=%s",
m_session.getActiveSessionId(), command.c_str()));
m_launched = true;
m_session.getActiveSessionId(), m_command.c_str()));
}
}
@ -470,4 +465,5 @@ CMSWindowsWatchdog::shutdownExistingProcesses()
}
CloseHandle(snapshot);
m_processRunning = false;
}

View File

@ -49,8 +49,8 @@ private:
void shutdownExistingProcesses();
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
void startProcess(std::string& command);
bool isProcessRunning();
void startProcess();
bool isProcessActive();
void sendSas();
private:
@ -66,9 +66,9 @@ private:
CIpcLogOutputter& m_ipcLogOutputter;
bool m_elevateProcess;
CMSWindowsSession m_session;
bool m_launched;
PROCESS_INFORMATION m_processInfo;
int m_failures;
int m_processFailures;
bool m_processRunning;
};
//! Relauncher error

View File

@ -45,6 +45,7 @@
#include "CMSWindowsScreen.h"
#include "CMSWindowsDebugOutputter.h"
#include "CMSWindowsWatchdog.h"
#include "CMSWindowsEventQueueBuffer.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@ -191,10 +192,7 @@ CDaemonApp::mainLoop(bool logToFile)
try
{
DAEMON_RUNNING(true);
/*while (true)
{
}*/
if (logToFile)
CLOG->insert(new CFileLogOutputter(logPath().c_str()));
@ -208,22 +206,21 @@ CDaemonApp::mainLoop(bool logToFile)
// send logging to gui via ipc, log system adopts outputter.
m_ipcLogOutputter = new CIpcLogOutputter(*m_ipcServer);
CLOG->insert(m_ipcLogOutputter);
#if SYSAPI_WIN32
m_watchdog = new CMSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter);
#endif
m_events->adoptHandler(
m_events->forCIpcServer().messageReceived(), m_ipcServer,
new TMethodEventJob<CDaemonApp>(this, &CDaemonApp::handleIpcMessage));
m_ipcServer->listen();
#if SYSAPI_WIN32
// HACK: create a dummy screen, which can handle system events
// (such as a stop request from the service controller).
CMSWindowsScreen::init(CArchMiscWindows::instanceWin32());
CScreen dummyScreen(new CMSWindowsScreen(false, true, false, m_events), m_events);
// install the platform event queue to handle service stop events.
m_events->adoptBuffer(new CMSWindowsEventQueueBuffer(m_events));
CString command = ARCH->setting("Command");
bool elevate = ARCH->setting("Elevate") == "1";
@ -234,7 +231,6 @@ CDaemonApp::mainLoop(bool logToFile)
m_watchdog->startAsync();
#endif
m_events->loop();
#if SYSAPI_WIN32
@ -248,7 +244,7 @@ CDaemonApp::mainLoop(bool logToFile)
CLOG->remove(m_ipcLogOutputter);
delete m_ipcLogOutputter;
delete m_ipcServer;
DAEMON_RUNNING(false);
}
catch (XArch& e) {