Added switch delay and double-tap options to win32 and added a

tray icon to the client and server that gives status feedback to
the user and allows the user to kill the app.
This commit is contained in:
crs
2003-03-12 22:34:07 +00:00
parent f411df65fb
commit 1d17f865ea
82 changed files with 4420 additions and 396 deletions

View File

@@ -0,0 +1,183 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#include "CConfig.h"
#include "ProtocolTypes.h"
#include "CStringUtil.h"
#include "CArch.h"
#include "CAdvancedOptions.h"
#include "LaunchUtil.h"
#include "resource.h"
//
// CAdvancedOptions
//
CAdvancedOptions* CAdvancedOptions::s_singleton = NULL;
CAdvancedOptions::CAdvancedOptions(HWND parent, CConfig* config) :
m_parent(parent),
m_config(config),
m_isClient(false),
m_screenName(ARCH->getHostName()),
m_port(kDefaultPort)
{
assert(s_singleton == NULL);
s_singleton = this;
}
CAdvancedOptions::~CAdvancedOptions()
{
s_singleton = NULL;
}
void
CAdvancedOptions::doModal(bool isClient)
{
// save state
m_isClient = isClient;
// do dialog
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADVANCED_OPTIONS),
m_parent, dlgProc, (LPARAM)this);
}
CString
CAdvancedOptions::getScreenName() const
{
return m_screenName;
}
int
CAdvancedOptions::getPort() const
{
return m_port;
}
CString
CAdvancedOptions::getCommandLine(bool isClient, const CString& serverName) const
{
CString cmdLine;
// screen name
if (!m_screenName.empty()) {
cmdLine += " --name ";
cmdLine += m_screenName;
}
// port
char portString[20];
sprintf(portString, "%d", m_port);
if (isClient) {
cmdLine += " ";
cmdLine += serverName;
cmdLine += ":";
cmdLine += portString;
}
else {
cmdLine += " --address :";
cmdLine += portString;
}
return cmdLine;
}
void
CAdvancedOptions::init(HWND hwnd)
{
HWND child;
char buffer[20];
sprintf(buffer, "%d", m_port);
child = getItem(hwnd, IDC_ADVANCED_PORT_EDIT);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
child = getItem(hwnd, IDC_ADVANCED_NAME_EDIT);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)m_screenName.c_str());
}
bool
CAdvancedOptions::save(HWND hwnd)
{
HWND child = getItem(hwnd, IDC_ADVANCED_NAME_EDIT);
CString name = getWindowText(child);
if (!m_config->isValidScreenName(name)) {
showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SCREEN_NAME).c_str(),
name.c_str()));
SetFocus(child);
return false;
}
if (!m_isClient && !m_config->isScreen(name)) {
showError(hwnd, CStringUtil::format(
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
name.c_str()));
SetFocus(child);
return false;
}
// get and verify port
child = getItem(hwnd, IDC_ADVANCED_PORT_EDIT);
CString portString = getWindowText(child);
int port = atoi(portString.c_str());
if (port < 1 || port > 65535) {
CString defaultPortString = CStringUtil::print("%d", kDefaultPort);
showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_PORT).c_str(),
portString.c_str(),
defaultPortString.c_str()));
SetFocus(child);
return false;
}
// save state
m_screenName = name;
m_port = port;
return true;
}
BOOL
CAdvancedOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
{
switch (message) {
case WM_INITDIALOG:
init(hwnd);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (save(hwnd)) {
EndDialog(hwnd, 0);
}
return TRUE;
case IDCANCEL:
EndDialog(hwnd, 0);
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
BOOL CALLBACK
CAdvancedOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
}

View File

@@ -0,0 +1,74 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CADVANCEDOPTIONS_H
#define CADVANCEDOPTIONS_H
#include "CString.h"
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
class CConfig;
//! Advanced options dialog for Microsoft Windows launcher
class CAdvancedOptions {
public:
CAdvancedOptions(HWND parent, CConfig*);
~CAdvancedOptions();
//! @name manipulators
//@{
//! Run dialog
/*!
Display and handle the dialog until closed by the user.
*/
void doModal(bool isClient);
//@}
//! @name accessors
//@{
//! Get the screen name
CString getScreenName() const;
//! Get the port
int getPort() const;
//! Convert options to command line string
CString getCommandLine(bool isClient,
const CString& serverName) const;
//@}
private:
void init(HWND hwnd);
bool save(HWND hwnd);
// message handling
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
private:
static CAdvancedOptions* s_singleton;
HWND m_parent;
CConfig* m_config;
bool m_isClient;
CString m_screenName;
int m_port;
};
#endif

View File

@@ -0,0 +1,211 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*/
#include "CConfig.h"
#include "ProtocolTypes.h"
#include "CStringUtil.h"
#include "CArch.h"
#include "CGlobalOptions.h"
#include "LaunchUtil.h"
#include "resource.h"
static const int s_defaultDelay = 250;
//
// CGlobalOptions
//
CGlobalOptions* CGlobalOptions::s_singleton = NULL;
CGlobalOptions::CGlobalOptions(HWND parent, CConfig* config) :
m_parent(parent),
m_config(config),
m_delayTime(s_defaultDelay),
m_twoTapTime(s_defaultDelay)
{
assert(s_singleton == NULL);
s_singleton = this;
}
CGlobalOptions::~CGlobalOptions()
{
s_singleton = NULL;
}
void
CGlobalOptions::doModal()
{
// do dialog
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_GLOBAL_OPTIONS),
m_parent, dlgProc, (LPARAM)this);
}
void
CGlobalOptions::init(HWND hwnd)
{
HWND child;
char buffer[30];
// reset options
sprintf(buffer, "%d", m_delayTime);
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
setItemChecked(child, false);
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
setWindowText(child, buffer);
sprintf(buffer, "%d", m_twoTapTime);
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
setItemChecked(child, false);
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
setWindowText(child, buffer);
// get the global options
const CConfig::CScreenOptions* options = m_config->getOptions("");
if (options != NULL) {
for (CConfig::CScreenOptions::const_iterator index = options->begin();
index != options->end(); ++index) {
const OptionID id = index->first;
const OptionValue value = index->second;
if (id == kOptionScreenSwitchDelay) {
if (value > 0) {
sprintf(buffer, "%d", value);
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
setItemChecked(child, true);
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
setWindowText(child, buffer);
}
}
else if (id == kOptionScreenSwitchTwoTap) {
if (value > 0) {
sprintf(buffer, "%d", value);
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
setItemChecked(child, true);
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
setWindowText(child, buffer);
}
}
}
}
}
bool
CGlobalOptions::save(HWND hwnd)
{
HWND child;
int newDelayTime = 0;
int newTwoTapTime = 0;
// get requested options
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
if (isItemChecked(child)) {
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
newDelayTime = getTime(hwnd, child, true);
if (newDelayTime == 0) {
return false;
}
}
else {
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
newDelayTime = getTime(hwnd, child, false);
if (newDelayTime == 0) {
newDelayTime = s_defaultDelay;
}
}
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
if (isItemChecked(child)) {
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
newTwoTapTime = getTime(hwnd, child, true);
if (newTwoTapTime == 0) {
return false;
}
}
else {
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
newTwoTapTime = getTime(hwnd, child, false);
if (newTwoTapTime == 0) {
newTwoTapTime = s_defaultDelay;
}
}
// remove existing config options
m_config->removeOption("", kOptionScreenSwitchDelay);
m_config->removeOption("", kOptionScreenSwitchTwoTap);
// add requested options
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
if (isItemChecked(child)) {
m_config->addOption("", kOptionScreenSwitchDelay, newDelayTime);
}
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
if (isItemChecked(child)) {
m_config->addOption("", kOptionScreenSwitchTwoTap, newTwoTapTime);
}
// save last values
m_delayTime = newDelayTime;
m_twoTapTime = newTwoTapTime;
return true;
}
int
CGlobalOptions::getTime(HWND hwnd, HWND child, bool reportError)
{
CString valueString = getWindowText(child);
int value = atoi(valueString.c_str());
if (value < 1) {
if (reportError) {
showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_TIME).c_str(),
valueString.c_str()));
SetFocus(child);
}
return 0;
}
return value;
}
BOOL
CGlobalOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
{
switch (message) {
case WM_INITDIALOG:
init(hwnd);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (save(hwnd)) {
EndDialog(hwnd, 0);
}
return TRUE;
case IDCANCEL:
EndDialog(hwnd, 0);
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
BOOL CALLBACK
CGlobalOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
}

View File

@@ -0,0 +1,66 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CGLOBALOPTIONS_H
#define CGLOBALOPTIONS_H
#include "CString.h"
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
class CConfig;
//! Global options dialog for Microsoft Windows launcher
class CGlobalOptions {
public:
CGlobalOptions(HWND parent, CConfig*);
~CGlobalOptions();
//! @name manipulators
//@{
//! Run dialog
/*!
Display and handle the dialog until closed by the user.
*/
void doModal();
//@}
//! @name accessors
//@{
//@}
private:
void init(HWND hwnd);
bool save(HWND hwnd);
int getTime(HWND hwnd, HWND child, bool reportError);
// message handling
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
private:
static CGlobalOptions* s_singleton;
HWND m_parent;
CConfig* m_config;
int m_delayTime;
int m_twoTapTime;
};
#endif

View File

@@ -103,6 +103,18 @@ enableItem(HWND hwnd, int id, bool enabled)
EnableWindow(GetDlgItem(hwnd, id), enabled);
}
void
setItemChecked(HWND hwnd, bool checked)
{
SendMessage(hwnd, BM_SETCHECK, checked ? BST_CHECKED : BST_UNCHECKED, 0);
}
bool
isItemChecked(HWND hwnd)
{
return (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
}
CString
getAppPath(const CString& appName)
{

View File

@@ -42,6 +42,9 @@ CString getWindowText(HWND hwnd);
HWND getItem(HWND hwnd, int id);
void enableItem(HWND hwnd, int id, bool enabled);
void setItemChecked(HWND, bool);
bool isItemChecked(HWND);
CString getAppPath(const CString& appName);
bool loadConfig(CConfig& config);

View File

@@ -16,8 +16,12 @@ DEPTH = ../..
VDEPTH = ./$(VPATH)/$(DEPTH)
EXTRA_DIST = \
CAdvancedOptions.cpp \
CAdvancedOptions.h \
CAutoStart.cpp \
CAutoStart.h \
CGlobalOptions.cpp \
CGlobalOptions.h \
LaunchUtil.cpp \
LaunchUtil.h \
launcher.cpp \

View File

@@ -13,6 +13,8 @@
*/
#include "CConfig.h"
#include "KeyTypes.h"
#include "OptionTypes.h"
#include "ProtocolTypes.h"
#include "CLog.h"
#include "CStringUtil.h"
@@ -24,6 +26,8 @@
// these must come after the above because it includes windows.h
#include "LaunchUtil.h"
#include "CAutoStart.h"
#include "CGlobalOptions.h"
#include "CAdvancedOptions.h"
#define CONFIG_NAME "synergy.sgc"
#define CLIENT_APP "synergyc.exe"
@@ -47,10 +51,28 @@ public:
HANDLE m_stop;
};
HINSTANCE s_instance = NULL;
struct CModifierInfo {
public:
int m_ctrlID;
const char* m_name;
KeyModifierID m_modifierID;
OptionID m_optionID;
};
static const TCHAR* s_mainClass = TEXT("GoSynergy");
static const TCHAR* s_layoutClass = TEXT("SynergyLayout");
static const CModifierInfo s_modifiers[] = {
{ IDC_ADD_MOD_SHIFT, "Shift",
kKeyModifierIDShift, kOptionModifierMapForShift },
{ IDC_ADD_MOD_CTRL, "Ctrl",
kKeyModifierIDControl, kOptionModifierMapForControl },
{ IDC_ADD_MOD_ALT, "Alt",
kKeyModifierIDAlt, kOptionModifierMapForAlt },
{ IDC_ADD_MOD_META, "Meta",
kKeyModifierIDMeta, kOptionModifierMapForMeta },
{ IDC_ADD_MOD_SUPER, "Super",
kKeyModifierIDSuper, kOptionModifierMapForSuper }
};
static const KeyModifierID baseModifier = kKeyModifierIDShift;
static const char* s_debugName[][2] = {
{ TEXT("Error"), "ERROR" },
@@ -63,6 +85,14 @@ static const char* s_debugName[][2] = {
};
static const int s_defaultDebug = 3; // INFO
HINSTANCE s_instance = NULL;
static CGlobalOptions* s_globalOptions = NULL;
static CAdvancedOptions* s_advancedOptions = NULL;
static const TCHAR* s_mainClass = TEXT("GoSynergy");
static const TCHAR* s_layoutClass = TEXT("SynergyLayout");
//
// program arguments
//
@@ -127,7 +157,7 @@ bool
isClientChecked(HWND hwnd)
{
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
return (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED);
return isItemChecked(child);
}
static
@@ -476,58 +506,20 @@ static
CString
getCommandLine(HWND hwnd, bool testing)
{
// decide if client or server
const bool isClient = isClientChecked(hwnd);
// get and verify screen name
HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
CString name = getWindowText(child);
if (!ARG->m_config.isValidScreenName(name)) {
showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SCREEN_NAME).c_str(),
name.c_str()));
SetFocus(child);
return CString();
}
if (!isClient && !ARG->m_config.isScreen(name)) {
showError(hwnd, CStringUtil::format(
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
name.c_str()));
SetFocus(child);
return CString();
}
// get and verify port
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
CString portString = getWindowText(child);
UInt32 port = (UInt32)atoi(portString.c_str());
if (port < 1 || port > 65535) {
CString defaultPortString = CStringUtil::print("%d", kDefaultPort);
showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_PORT).c_str(),
portString.c_str(),
defaultPortString.c_str()));
SetFocus(child);
return CString();
}
// prepare command line
CString cmdLine;
if (testing) {
// constant testing args
cmdLine += " -z --no-restart --no-daemon";
// debug level testing arg
child = getItem(hwnd, IDC_MAIN_DEBUG);
cmdLine += " --debug ";
cmdLine += s_debugName[SendMessage(child, CB_GETCURSEL, 0, 0)][1];
// add constant testing args
if (testing) {
cmdLine += " -z --no-restart --no-daemon";
}
cmdLine += " --name ";
cmdLine += name;
// get the server name
CString server;
bool isClient = isClientChecked(hwnd);
if (isClient) {
// check server name
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
CString server = getWindowText(child);
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
server = getWindowText(child);
if (!ARG->m_config.isValidScreenName(server)) {
showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SERVER_NAME).c_str(),
@@ -551,16 +543,19 @@ getCommandLine(HWND hwnd, bool testing)
if (testing) {
cmdLine += " --no-camp";
}
cmdLine += " ";
cmdLine += server;
cmdLine += ":";
cmdLine += portString;
}
else {
cmdLine += " --address :";
cmdLine += portString;
// debug level
if (testing) {
HWND child = getItem(hwnd, IDC_MAIN_DEBUG);
DWORD debug = SendMessage(child, CB_GETCURSEL, 0, 0);
cmdLine += " --debug ";
cmdLine += s_debugName[debug][1];
}
// add advanced options
cmdLine += s_advancedOptions->getCommandLine(isClient, server);
return cmdLine;
}
@@ -711,11 +706,9 @@ initMainWindow(HWND hwnd)
// choose client/server radio buttons
HWND child;
child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
SendMessage(child, BM_SETCHECK, !configLoaded ?
BST_CHECKED : BST_UNCHECKED, 0);
setItemChecked(child, !configLoaded);
child = getItem(hwnd, IDC_MAIN_SERVER_RADIO);
SendMessage(child, BM_SETCHECK, configLoaded ?
BST_CHECKED : BST_UNCHECKED, 0);
setItemChecked(child, configLoaded);
// if config is loaded then initialize server controls
if (configLoaded) {
@@ -729,16 +722,7 @@ initMainWindow(HWND hwnd)
}
}
// initialize other controls
char buffer[256];
sprintf(buffer, "%d", kDefaultPort);
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
CString hostname = ARCH->getHostName();
child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)hostname.c_str());
// debug level
child = getItem(hwnd, IDC_MAIN_DEBUG);
for (unsigned int i = 0; i < sizeof(s_debugName) /
sizeof(s_debugName[0]); ++i) {
@@ -794,19 +778,32 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
CConfig::CScreenOptions::const_iterator index;
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
index = info->m_options.find(kOptionHalfDuplexCapsLock);
if (index != info->m_options.end() && index->second != 0) {
SendMessage(child, BM_SETCHECK, BST_CHECKED, 0);
}
else {
SendMessage(child, BM_SETCHECK, BST_UNCHECKED, 0);
}
setItemChecked(child, (index != info->m_options.end() &&
index->second != 0));
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
index = info->m_options.find(kOptionHalfDuplexNumLock);
if (index != info->m_options.end() && index->second != 0) {
SendMessage(child, BM_SETCHECK, BST_CHECKED, 0);
}
else {
SendMessage(child, BM_SETCHECK, BST_UNCHECKED, 0);
setItemChecked(child, (index != info->m_options.end() &&
index->second != 0));
// modifier options
for (UInt32 i = 0; i < sizeof(s_modifiers) /
sizeof(s_modifiers[0]); ++i) {
child = getItem(hwnd, s_modifiers[i].m_ctrlID);
// fill in options
for (UInt32 j = 0; j < sizeof(s_modifiers) /
sizeof(s_modifiers[0]); ++j) {
SendMessage(child, CB_ADDSTRING, 0,
(LPARAM)s_modifiers[j].m_name);
}
// choose current value
index = info->m_options.find(s_modifiers[i].m_optionID);
KeyModifierID id = s_modifiers[i].m_modifierID;
if (index != info->m_options.end()) {
id = index->second;
}
SendMessage(child, CB_SETCURSEL, id - baseModifier, 0);
}
return TRUE;
@@ -883,20 +880,36 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
// save options
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
if (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED) {
if (isItemChecked(child)) {
info->m_options[kOptionHalfDuplexCapsLock] = 1;
}
else {
info->m_options.erase(kOptionHalfDuplexCapsLock);
}
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
if (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED) {
if (isItemChecked(child)) {
info->m_options[kOptionHalfDuplexNumLock] = 1;
}
else {
info->m_options.erase(kOptionHalfDuplexNumLock);
}
// save modifier options
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
for (UInt32 i = 0; i < sizeof(s_modifiers) /
sizeof(s_modifiers[0]); ++i) {
child = getItem(hwnd, s_modifiers[i].m_ctrlID);
KeyModifierID id = static_cast<KeyModifierID>(
SendMessage(child, CB_GETCURSEL, 0, 0) +
baseModifier);
if (id != s_modifiers[i].m_modifierID) {
info->m_options[s_modifiers[i].m_optionID] = id;
}
else {
info->m_options.erase(s_modifiers[i].m_optionID);
}
}
// success
EndDialog(hwnd, 1);
info = NULL;
@@ -1065,6 +1078,16 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
return 0;
}
break;
case IDC_MAIN_OPTIONS:
s_globalOptions->doModal();
enableSaveControls(hwnd);
break;
case IDC_MAIN_ADVANCED:
s_advancedOptions->doModal(isClientChecked(hwnd));
enableSaveControls(hwnd);
break;
}
default:
@@ -1076,7 +1099,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
{
CArch arch;
CArch arch(instance);
CLOG;
CArgs args;
@@ -1108,8 +1131,10 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
HWND m_mainWindow = CreateDialog(s_instance,
MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
// prep window
// prep windows
initMainWindow(m_mainWindow);
s_globalOptions = new CGlobalOptions(m_mainWindow, &ARG->m_config);
s_advancedOptions = new CAdvancedOptions(m_mainWindow, &ARG->m_config);
// show window
ShowWindow(m_mainWindow, nCmdShow);

View File

@@ -95,10 +95,18 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CAdvancedOptions.cpp
# End Source File
# Begin Source File
SOURCE=.\CAutoStart.cpp
# End Source File
# Begin Source File
SOURCE=.\CGlobalOptions.cpp
# End Source File
# Begin Source File
SOURCE=.\launcher.cpp
# End Source File
# Begin Source File
@@ -115,10 +123,18 @@ SOURCE=.\LaunchUtil.cpp
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CAdvancedOptions.h
# End Source File
# Begin Source File
SOURCE=.\CAutoStart.h
# End Source File
# Begin Source File
SOURCE=.\CGlobalOptions.h
# End Source File
# Begin Source File
SOURCE=.\LaunchUtil.h
# End Source File
# Begin Source File

View File

@@ -40,11 +40,14 @@
#define IDS_SERVER_IS_CLIENT 36
#define IDS_ADD_SCREEN 37
#define IDS_EDIT_SCREEN 38
#define IDS_INVALID_TIME 39
#define IDD_MAIN 101
#define IDD_ADD 102
#define IDD_WAIT 103
#define IDI_SYNERGY 104
#define IDD_AUTOSTART 105
#define IDD_ADVANCED_OPTIONS 106
#define IDD_GLOBAL_OPTIONS 107
#define IDC_MAIN_CLIENT_RADIO 1000
#define IDC_MAIN_SERVER_RADIO 1001
#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1002
@@ -76,18 +79,31 @@
#define IDC_AUTOSTART_INSTALL_USER 1033
#define IDC_AUTOSTART_INSTALL_SYSTEM 1034
#define IDC_MAIN_AUTOSTART 1035
#define IDC_MAIN_DEBUG 1036
#define IDC_MAIN_OPTIONS 1036
#define IDC_ADD_HD_CAPS_CHECK 1037
#define IDC_MAIN_ADVANCED 1037
#define IDC_ADD_HD_NUM_CHECK 1038
#define IDC_ADVANCED_NAME_EDIT 1038
#define IDC_ADVANCED_PORT_EDIT 1039
#define IDC_MAIN_DEBUG 1040
#define IDC_GLOBAL_DELAY_CHECK 1041
#define IDC_GLOBAL_DELAY_TIME 1042
#define IDC_GLOBAL_TWO_TAP_CHECK 1043
#define IDC_ADD_MOD_SHIFT 1043
#define IDC_GLOBAL_TWO_TAP_TIME 1044
#define IDC_ADD_MOD_CTRL 1044
#define IDC_ADD_MOD_ALT 1045
#define IDC_ADD_MOD_META 1046
#define IDC_ADD_MOD_SUPER 1047
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 106
#define _APS_NEXT_RESOURCE_VALUE 108
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1038
#define _APS_NEXT_CONTROL_VALUE 1044
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,163 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CClientTaskBarReceiver.h"
#include "CClient.h"
#include "CLock.h"
#include "TMethodJob.h"
#include "CArch.h"
//
// CClientTaskBarReceiver
//
CClientTaskBarReceiver::CClientTaskBarReceiver() :
m_quit(NULL),
m_state(kNotRunning),
m_client(NULL)
{
// create a job for getting notification when the client's
// status changes.
m_job = new TMethodJob<CClientTaskBarReceiver>(this,
&CClientTaskBarReceiver::statusChanged, NULL);
}
CClientTaskBarReceiver::~CClientTaskBarReceiver()
{
if (m_client != NULL) {
m_client->removeStatusJob(m_job);
}
delete m_job;
delete m_quit;
}
void
CClientTaskBarReceiver::setClient(CClient* client)
{
{
CLock lock(&m_mutex);
if (m_client != client) {
if (m_client != NULL) {
m_client->removeStatusJob(m_job);
}
m_client = client;
if (m_client != NULL) {
m_client->addStatusJob(m_job);
}
}
}
ARCH->updateReceiver(this);
}
void
CClientTaskBarReceiver::setState(EState state)
{
{
CLock lock(&m_mutex);
m_state = state;
}
ARCH->updateReceiver(this);
}
void
CClientTaskBarReceiver::setQuitJob(IJob* job)
{
CLock lock(&m_mutex);
delete m_quit;
m_quit = job;
}
CClientTaskBarReceiver::EState
CClientTaskBarReceiver::getState() const
{
return m_state;
}
CClient*
CClientTaskBarReceiver::getClient() const
{
return m_client;
}
void
CClientTaskBarReceiver::lock() const
{
m_mutex.lock();
}
void
CClientTaskBarReceiver::unlock() const
{
m_mutex.unlock();
}
std::string
CClientTaskBarReceiver::getToolTip() const
{
switch (m_state) {
case kNotRunning:
return "Synergy: Not running";
case kNotWorking:
return CString("Synergy: ") + m_errorMessage;
case kNotConnected:
return "Synergy: Waiting for clients";
case kConnected:
return "Synergy: Connected";
default:
return "";
}
}
void
CClientTaskBarReceiver::quit()
{
if (m_quit != NULL) {
m_quit->run();
}
}
void
CClientTaskBarReceiver::onStatusChanged()
{
// do nothing
}
void
CClientTaskBarReceiver::statusChanged(void*)
{
// update our status
switch (m_client->getStatus(&m_errorMessage)) {
case CClient::kNotRunning:
setState(kNotRunning);
break;
case CClient::kRunning:
setState(kConnected);
break;
case CClient::kError:
setState(kNotWorking);
break;
default:
break;
}
// let subclasses have a go
onStatusChanged();
}

View File

@@ -0,0 +1,110 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CCLIENTTASKBARRECEIVER_H
#define CCLIENTTASKBARRECEIVER_H
#include "CMutex.h"
#include "CString.h"
#include "IArchTaskBarReceiver.h"
class CClient;
class IJob;
//! Implementation of IArchTaskBarReceiver for the synergy server
class CClientTaskBarReceiver : public IArchTaskBarReceiver {
public:
enum EState {
kNotRunning,
kNotWorking,
kNotConnected,
kConnected,
kMaxState
};
CClientTaskBarReceiver();
virtual ~CClientTaskBarReceiver();
//! @name manipulators
//@{
//! Set server
/*!
Sets the server. The receiver will query state from this server.
*/
void setClient(CClient*);
//! Set state
/*!
Sets the current server state.
*/
void setState(EState);
//! Set the quit job that causes the server to quit
/*!
Set the job that causes the server to quit.
*/
void setQuitJob(IJob* adopted);
//@}
//! @name accessors
//@{
//! Get state
/*!
Returns the current server state. The receiver is not locked
by this call; the caller must do the locking.
*/
EState getState() const;
//! Get server
/*!
Returns the server set by \c setClient().
*/
CClient* getClient() const;
//@}
// IArchTaskBarReceiver overrides
virtual void showStatus() = 0;
virtual void runMenu(int x, int y) = 0;
virtual void primaryAction() = 0;
virtual void lock() const;
virtual void unlock() const;
virtual const Icon getIcon() const = 0;
virtual std::string getToolTip() const;
protected:
void quit();
//! Status change notification
/*!
Called when status changes. The default implementation does
nothing.
*/
virtual void onStatusChanged();
private:
void statusChanged(void*);
private:
CMutex m_mutex;
IJob* m_quit;
EState m_state;
CClient* m_client;
IJob* m_job;
CString m_errorMessage;
};
#endif

View File

@@ -0,0 +1,280 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CMSWindowsClientTaskBarReceiver.h"
#include "CClient.h"
#include "BasicTypes.h"
#include "CArch.h"
#include "CArchTaskBarWindows.h"
#include "resource.h"
static const UINT g_stateToIconID[CMSWindowsClientTaskBarReceiver::kMaxState] =
{
IDI_TASKBAR_NOT_RUNNING,
IDI_TASKBAR_NOT_WORKING,
IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_CONNECTED
};
//
// CMSWindowsClientTaskBarReceiver
//
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
HINSTANCE appInstance) :
CClientTaskBarReceiver(),
m_appInstance(appInstance),
m_window(NULL)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(g_stateToIconID[i]);
}
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
// don't create the window yet. we'll create it on demand. this
// has the side benefit of being created in the thread used for
// the task bar. that's good because it means the existence of
// the window won't prevent changing the main thread's desktop.
// add ourself to the task bar
ARCH->addReceiver(this);
}
CMSWindowsClientTaskBarReceiver::~CMSWindowsClientTaskBarReceiver()
{
ARCH->removeReceiver(this);
for (UInt32 i = 0; i < kMaxState; ++i) {
deleteIcon(m_icon[i]);
}
DestroyMenu(m_menu);
destroyWindow();
}
void
CMSWindowsClientTaskBarReceiver::showStatus()
{
// create the window
createWindow();
// lock self while getting status
lock();
// get the current status
std::string status = getToolTip();
// done getting status
unlock();
// update dialog
HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
if (!IsWindowVisible(m_window)) {
// position it by the mouse
POINT cursorPos;
GetCursorPos(&cursorPos);
RECT windowRect;
GetWindowRect(m_window, &windowRect);
int x = cursorPos.x;
int y = cursorPos.y;
int fw = GetSystemMetrics(SM_CXDLGFRAME);
int fh = GetSystemMetrics(SM_CYDLGFRAME);
int ww = windowRect.right - windowRect.left;
int wh = windowRect.bottom - windowRect.top;
int sw = GetSystemMetrics(SM_CXFULLSCREEN);
int sh = GetSystemMetrics(SM_CYFULLSCREEN);
if (fw < 1) {
fw = 1;
}
if (fh < 1) {
fh = 1;
}
if (x + ww - fw > sw) {
x -= ww - fw;
}
else {
x -= fw;
}
if (x < 0) {
x = 0;
}
if (y + wh - fh > sh) {
y -= wh - fh;
}
else {
y -= fh;
}
if (y < 0) {
y = 0;
}
SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
SWP_SHOWWINDOW);
}
}
void
CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
{
// do popup menu. we need a window to pass to TrackPopupMenu().
// the SetForegroundWindow() and SendMessage() calls around
// TrackPopupMenu() are to get the menu to be dismissed when
// another window gets activated and are just one of those
// win32 weirdnesses.
createWindow();
SetForegroundWindow(m_window);
HMENU menu = GetSubMenu(m_menu, 0);
SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
int n = TrackPopupMenu(menu,
TPM_NONOTIFY |
TPM_RETURNCMD |
TPM_LEFTBUTTON |
TPM_RIGHTBUTTON,
x, y, 0, m_window, NULL);
SendMessage(m_window, WM_NULL, 0, 0);
// perform the requested operation
switch (n) {
case IDC_TASKBAR_STATUS:
showStatus();
break;
case IDC_TASKBAR_QUIT:
quit();
break;
}
}
void
CMSWindowsClientTaskBarReceiver::primaryAction()
{
showStatus();
}
const IArchTaskBarReceiver::Icon
CMSWindowsClientTaskBarReceiver::getIcon() const
{
return reinterpret_cast<Icon>(m_icon[getState()]);
}
void
CMSWindowsClientTaskBarReceiver::onStatusChanged()
{
if (IsWindowVisible(m_window)) {
showStatus();
}
}
HICON
CMSWindowsClientTaskBarReceiver::loadIcon(UINT id)
{
HANDLE icon = LoadImage(m_appInstance,
MAKEINTRESOURCE(id),
IMAGE_ICON,
0, 0,
LR_DEFAULTCOLOR);
return reinterpret_cast<HICON>(icon);
}
void
CMSWindowsClientTaskBarReceiver::deleteIcon(HICON icon)
{
if (icon != NULL) {
DestroyIcon(icon);
}
}
void
CMSWindowsClientTaskBarReceiver::createWindow()
{
// ignore if already created
if (m_window != NULL) {
return;
}
// get the status dialog
m_window = CreateDialogParam(m_appInstance,
MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
NULL,
&CMSWindowsClientTaskBarReceiver::staticDlgProc,
reinterpret_cast<LPARAM>(
reinterpret_cast<void*>(this)));
// window should appear on top of everything, including (especially)
// the task bar.
DWORD style = GetWindowLong(m_window, GWL_EXSTYLE);
style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
SetWindowLong(m_window, GWL_EXSTYLE, style);
// tell the task bar about this dialog
CArchTaskBarWindows::addDialog(m_window);
}
void
CMSWindowsClientTaskBarReceiver::destroyWindow()
{
if (m_window != NULL) {
CArchTaskBarWindows::removeDialog(m_window);
DestroyWindow(m_window);
m_window = NULL;
}
}
BOOL
CMSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM)
{
switch (msg) {
case WM_INITDIALOG:
// use default focus
return TRUE;
case WM_ACTIVATE:
// hide when another window is activated
if (LOWORD(wParam) == WA_INACTIVE) {
ShowWindow(hwnd, SW_HIDE);
}
break;
}
return FALSE;
}
BOOL CALLBACK
CMSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam)
{
// if msg is WM_INITDIALOG, extract the CMSWindowsClientTaskBarReceiver*
// and put it in the extra window data then forward the call.
CMSWindowsClientTaskBarReceiver* self = NULL;
if (msg == WM_INITDIALOG) {
self = reinterpret_cast<CMSWindowsClientTaskBarReceiver*>(
reinterpret_cast<void*>(lParam));
SetWindowLong(hwnd, GWL_USERDATA, lParam);
}
else {
// get the extra window data and forward the call
LONG data = GetWindowLong(hwnd, GWL_USERDATA);
if (data != 0) {
self = reinterpret_cast<CMSWindowsClientTaskBarReceiver*>(
reinterpret_cast<void*>(data));
}
}
// forward the message
if (self != NULL) {
return self->dlgProc(hwnd, msg, wParam, lParam);
}
else {
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
}
}

View File

@@ -0,0 +1,58 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CMSWINDOWSCLIENTTASKBARRECEIVER_H
#define CMSWINDOWSCLIENTTASKBARRECEIVER_H
#define WIN32_LEAN_AND_MEAN
#include "CClientTaskBarReceiver.h"
#include <windows.h>
//! Implementation of CClientTaskBarReceiver for Microsoft Windows
class CMSWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
public:
CMSWindowsClientTaskBarReceiver(HINSTANCE);
virtual ~CMSWindowsClientTaskBarReceiver();
// IArchTaskBarReceiver overrides
virtual void showStatus();
virtual void runMenu(int x, int y);
virtual void primaryAction();
virtual const Icon getIcon() const;
protected:
// CClientTaskBarReceiver overrides
virtual void onStatusChanged();
private:
HICON loadIcon(UINT);
void deleteIcon(HICON);
void createWindow();
void destroyWindow();
BOOL dlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK
staticDlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam);
private:
HINSTANCE m_appInstance;
HWND m_window;
HMENU m_menu;
HICON m_icon[kMaxState];
};
#endif

View File

@@ -0,0 +1,61 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CXWindowsClientTaskBarReceiver.h"
#include "CArch.h"
//
// CXWindowsClientTaskBarReceiver
//
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver()
{
// add ourself to the task bar
ARCH->addReceiver(this);
}
CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver()
{
ARCH->removeReceiver(this);
}
void
CXWindowsClientTaskBarReceiver::showStatus()
{
// do nothing
}
void
CXWindowsClientTaskBarReceiver::runMenu(int, int)
{
// do nothing
}
void
CXWindowsClientTaskBarReceiver::primaryAction()
{
// do nothing
}
const IArchTaskBarReceiver::Icon
CXWindowsClientTaskBarReceiver::getIcon() const
{
return NULL;
}
void
CXWindowsClientTaskBarReceiver::onStatusChanged()
{
// do nothing
}

View File

@@ -0,0 +1,37 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CXWINDOWSCLIENTTASKBARRECEIVER_H
#define CXWINDOWSCLIENTTASKBARRECEIVER_H
#include "CClientTaskBarReceiver.h"
//! Implementation of CClientTaskBarReceiver for X Windows
class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
public:
CXWindowsClientTaskBarReceiver();
virtual ~CXWindowsClientTaskBarReceiver();
// IArchTaskBarReceiver overrides
virtual void showStatus();
virtual void runMenu(int x, int y);
virtual void primaryAction();
virtual const Icon getIcon() const;
protected:
// CClientTaskBarReceiver overrides
virtual void onStatusChanged();
};
#endif

View File

@@ -15,19 +15,29 @@ NULL =
DEPTH = ../..
VDEPTH = ./$(VPATH)/$(DEPTH)
EXTRA_DIST = \
resource.h \
synergyc.dsp \
synergyc.ico \
synergyc.rc \
EXTRA_DIST = \
CMSWindowsClientTaskBarReceiver.cpp \
CMSWindowsClientTaskBarReceiver.h \
resource.h \
synergyc.dsp \
synergyc.ico \
synergyc.rc \
tb_error.ico \
tb_idle.ico \
tb_run.ico \
tb_wait.ico \
$(NULL)
MAINTAINERCLEANFILES = \
Makefile.in \
MAINTAINERCLEANFILES = \
Makefile.in \
$(NULL)
bin_PROGRAMS = synergyc
synergyc_SOURCES = \
CClientTaskBarReceiver.cpp \
CClientTaskBarReceiver.h \
CXWindowsClientTaskBarReceiver.cpp \
CXWindowsClientTaskBarReceiver.h \
synergyc.cpp \
$(NULL)
synergyc_LDADD = \

View File

@@ -4,6 +4,15 @@
//
#define IDS_FAILED 1
#define IDI_SYNERGY 101
#define IDI_TASKBAR_NOT_RUNNING 102
#define IDI_TASKBAR_NOT_WORKING 103
#define IDI_TASKBAR_NOT_CONNECTED 104
#define IDI_TASKBAR_CONNECTED 105
#define IDR_TASKBAR 107
#define IDD_TASKBAR_STATUS 108
#define IDC_TASKBAR_STATUS_STATUS 1000
#define IDC_TASKBAR_QUIT 40003
#define IDC_TASKBAR_STATUS 40004
// Next default values for new objects
//

View File

@@ -25,6 +25,7 @@
#include "CMutex.h"
#include "CThread.h"
#include "XThread.h"
#include "CFunctionJob.h"
#include "CLog.h"
#include "LogOutputters.h"
#include "CString.h"
@@ -34,12 +35,15 @@
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
#include "CMSWindowsSecondaryScreen.h"
#include "CMSWindowsClientTaskBarReceiver.h"
#include "resource.h"
#undef DAEMON_RUNNING
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
#elif UNIX_LIKE
#include "CXWindowsSecondaryScreen.h"
#include "CXWindowsClientTaskBarReceiver.h"
#endif
// platform dependent name of a daemon
@@ -112,11 +116,46 @@ CSecondaryScreenFactory::create(IScreenReceiver* receiver)
}
//! CQuitJob
/*!
A job that cancels a given thread.
*/
class CQuitJob : public IJob {
public:
CQuitJob(const CThread& thread);
~CQuitJob();
// IJob overrides
virtual void run();
private:
CThread m_thread;
};
CQuitJob::CQuitJob(const CThread& thread) :
m_thread(thread)
{
// do nothing
}
CQuitJob::~CQuitJob()
{
// do nothing
}
void
CQuitJob::run()
{
m_thread.cancel();
}
//
// platform independent main
//
static CClient* s_client = NULL;
static CClient* s_client = NULL;
static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
static
int
@@ -137,6 +176,7 @@ realMain(void)
// open client
try {
s_taskBarReceiver->setClient(s_client);
s_client->open();
opened = true;
@@ -160,11 +200,10 @@ realMain(void)
DAEMON_RUNNING(false); \
locked = true; \
} \
if (s_client != NULL) { \
if (opened) { \
s_client->close(); \
} \
if (opened) { \
s_client->close(); \
} \
s_taskBarReceiver->setClient(NULL); \
delete s_client; \
s_client = NULL; \
} while (false)
@@ -205,6 +244,43 @@ realMain(void)
return result;
}
static
void
realMainEntry(void*)
{
CThread::exit(reinterpret_cast<void*>(realMain()));
}
static
int
runMainInThread(void)
{
CThread appThread(new CFunctionJob(&realMainEntry));
try {
#if WINDOWS_LIKE
MSG msg;
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
// check for a quit event
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
CThread::getCurrentThread().cancel();
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#else
appThread.wait(-1.0);
#endif
return reinterpret_cast<int>(appThread.getResult());
}
catch (XThread&) {
appThread.cancel();
appThread.wait(-1.0);
throw;
}
}
//
// command line parsing
@@ -273,7 +349,7 @@ help()
static
bool
isArg(int argi, int argc, const char** argv,
isArg(int argi, int argc, const char* const* argv,
const char* name1, const char* name2,
int minRequiredParameters = 0)
{
@@ -294,7 +370,7 @@ isArg(int argi, int argc, const char** argv,
static
void
parse(int argc, const char** argv)
parse(int argc, const char* const* argv)
{
assert(ARG->m_pname != NULL);
assert(argv != NULL);
@@ -424,16 +500,6 @@ parse(int argc, const char** argv)
}
}
static
void
useSystemLog()
{
// redirect log messages
ILogOutputter* logger = new CSystemLogOutputter;
logger->open(DAEMON_NAME);
CLOG->insert(new CStopLogOutputter);
CLOG->insert(logger);
}
//
// platform dependent entry points
@@ -441,8 +507,6 @@ useSystemLog()
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
static bool s_hasImportantLogMessages = false;
//
@@ -494,7 +558,10 @@ static
int
daemonStartup(int argc, const char** argv)
{
useSystemLog();
CSystemLogger sysLogger(DAEMON_NAME);
// have to cancel this thread to quit
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// catch errors that would normally exit
bye = &byeThrow;
@@ -513,14 +580,62 @@ static
int
daemonStartup95(int, const char**)
{
useSystemLog();
return realMain();
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
}
static
int
run(int argc, char** argv)
{
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
// parse command line
parse(argc, argv);
// daemonize if requested
if (ARG->m_daemon) {
// start as a daemon
if (CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
else {
// cannot start a service from the command line so just
// run normally (except with log messages redirected).
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
}
}
else {
// run
return runMainInThread();
}
}
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
CArch arch;
CArch arch(instance);
CLOG;
CArgs args;
@@ -533,52 +648,27 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// send PRINT and FATAL output to a message box
CLOG->insert(new CMessageBoxOutputter);
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
int result = kExitFailed;
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
delete CLOG;
return result;
}
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance);
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// parse command line
parse(__argc, const_cast<const char**>(__argv));
// daemonize if requested
int result;
if (ARG->m_daemon) {
// start as a daemon
if (CArchMiscWindows::isWindows95Family()) {
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
result = kExitFailed;
}
}
else {
// cannot start a service from the command line so just
// run normally (except with log messages redirected).
useSystemLog();
result = realMain();
}
try {
// run in foreground or as a daemon
result = run(__argc, __argv);
}
else {
// run
result = realMain();
catch (...) {
// note that we don't rethrow thread cancellation. we'll
// be exiting soon so it doesn't matter. what we'd like
// is for everything after this try/catch to be in a
// finally block.
result = kExitFailed;
}
// done with task bar receiver
delete s_taskBarReceiver;
// let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting.
if (ARG->m_backend && s_hasImportantLogMessages) {
@@ -598,7 +688,7 @@ static
int
daemonStartup(int, const char**)
{
useSystemLog();
CSystemLogger sysLogger(DAEMON_NAME);
return realMain();
}
@@ -612,8 +702,13 @@ main(int argc, char** argv)
// get program name
ARG->m_pname = ARCH->getBasename(argv[0]);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CXWindowsClientTaskBarReceiver;
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// parse command line
parse(argc, const_cast<const char**>(argv));
parse(argc, argv);
// daemonize if requested
int result;
@@ -630,6 +725,9 @@ main(int argc, char** argv)
result = realMain();
}
// done with task bar receiver
delete s_taskBarReceiver;
return result;
}

View File

@@ -94,6 +94,14 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CClientTaskBarReceiver.cpp
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsClientTaskBarReceiver.cpp
# End Source File
# Begin Source File
SOURCE=.\synergyc.cpp
# End Source File
# Begin Source File
@@ -106,6 +114,14 @@ SOURCE=.\synergyc.rc
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CClientTaskBarReceiver.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsClientTaskBarReceiver.h
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# End Group
@@ -116,6 +132,22 @@ SOURCE=.\resource.h
SOURCE=.\synergyc.ico
# End Source File
# Begin Source File
SOURCE=.\tb_error.ico
# End Source File
# Begin Source File
SOURCE=.\tb_idle.ico
# End Source File
# Begin Source File
SOURCE=.\tb_run.ico
# End Source File
# Begin Source File
SOURCE=.\tb_wait.ico
# End Source File
# End Group
# End Target
# End Project

BIN
cmd/synergyc/tb_error.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
cmd/synergyc/tb_idle.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
cmd/synergyc/tb_run.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
cmd/synergyc/tb_wait.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View File

@@ -0,0 +1,300 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CMSWindowsServerTaskBarReceiver.h"
#include "CServer.h"
#include "BasicTypes.h"
#include "CArch.h"
#include "CArchTaskBarWindows.h"
#include "resource.h"
static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
{
IDI_TASKBAR_NOT_RUNNING,
IDI_TASKBAR_NOT_WORKING,
IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_CONNECTED
};
//
// CMSWindowsServerTaskBarReceiver
//
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
HINSTANCE appInstance) :
CServerTaskBarReceiver(),
m_appInstance(appInstance),
m_window(NULL)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(g_stateToIconID[i]);
}
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
// don't create the window yet. we'll create it on demand. this
// has the side benefit of being created in the thread used for
// the task bar. that's good because it means the existence of
// the window won't prevent changing the main thread's desktop.
// add ourself to the task bar
ARCH->addReceiver(this);
}
CMSWindowsServerTaskBarReceiver::~CMSWindowsServerTaskBarReceiver()
{
ARCH->removeReceiver(this);
for (UInt32 i = 0; i < kMaxState; ++i) {
deleteIcon(m_icon[i]);
}
DestroyMenu(m_menu);
destroyWindow();
}
void
CMSWindowsServerTaskBarReceiver::showStatus()
{
// create the window
createWindow();
// lock self while getting status
lock();
// get the current status
std::string status = getToolTip();
// get the connect clients, if any
typedef std::vector<CString> CClientList;
CClientList clients;
CServer* server = getServer();
if (server != NULL) {
server->getClients(clients);
}
// done getting status
unlock();
// update dialog
HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS);
SendMessage(child, LB_RESETCONTENT, 0, 0);
for (CClientList::const_iterator index = clients.begin();
index != clients.end(); ) {
const char* client = index->c_str();
if (++index == clients.end()) {
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)client);
}
else {
SendMessage(child, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)client);
}
}
if (!IsWindowVisible(m_window)) {
// position it by the mouse
POINT cursorPos;
GetCursorPos(&cursorPos);
RECT windowRect;
GetWindowRect(m_window, &windowRect);
int x = cursorPos.x;
int y = cursorPos.y;
int fw = GetSystemMetrics(SM_CXDLGFRAME);
int fh = GetSystemMetrics(SM_CYDLGFRAME);
int ww = windowRect.right - windowRect.left;
int wh = windowRect.bottom - windowRect.top;
int sw = GetSystemMetrics(SM_CXFULLSCREEN);
int sh = GetSystemMetrics(SM_CYFULLSCREEN);
if (fw < 1) {
fw = 1;
}
if (fh < 1) {
fh = 1;
}
if (x + ww - fw > sw) {
x -= ww - fw;
}
else {
x -= fw;
}
if (x < 0) {
x = 0;
}
if (y + wh - fh > sh) {
y -= wh - fh;
}
else {
y -= fh;
}
if (y < 0) {
y = 0;
}
SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
SWP_SHOWWINDOW);
}
}
void
CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
{
// do popup menu. we need a window to pass to TrackPopupMenu().
// the SetForegroundWindow() and SendMessage() calls around
// TrackPopupMenu() are to get the menu to be dismissed when
// another window gets activated and are just one of those
// win32 weirdnesses.
createWindow();
SetForegroundWindow(m_window);
HMENU menu = GetSubMenu(m_menu, 0);
SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
int n = TrackPopupMenu(menu,
TPM_NONOTIFY |
TPM_RETURNCMD |
TPM_LEFTBUTTON |
TPM_RIGHTBUTTON,
x, y, 0, m_window, NULL);
SendMessage(m_window, WM_NULL, 0, 0);
// perform the requested operation
switch (n) {
case IDC_TASKBAR_STATUS:
showStatus();
break;
case IDC_TASKBAR_QUIT:
quit();
break;
}
}
void
CMSWindowsServerTaskBarReceiver::primaryAction()
{
showStatus();
}
const IArchTaskBarReceiver::Icon
CMSWindowsServerTaskBarReceiver::getIcon() const
{
return reinterpret_cast<Icon>(m_icon[getState()]);
}
void
CMSWindowsServerTaskBarReceiver::onStatusChanged()
{
if (IsWindowVisible(m_window)) {
showStatus();
}
}
HICON
CMSWindowsServerTaskBarReceiver::loadIcon(UINT id)
{
HANDLE icon = LoadImage(m_appInstance,
MAKEINTRESOURCE(id),
IMAGE_ICON,
0, 0,
LR_DEFAULTCOLOR);
return reinterpret_cast<HICON>(icon);
}
void
CMSWindowsServerTaskBarReceiver::deleteIcon(HICON icon)
{
if (icon != NULL) {
DestroyIcon(icon);
}
}
void
CMSWindowsServerTaskBarReceiver::createWindow()
{
// ignore if already created
if (m_window != NULL) {
return;
}
// get the status dialog
m_window = CreateDialogParam(m_appInstance,
MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
NULL,
&CMSWindowsServerTaskBarReceiver::staticDlgProc,
reinterpret_cast<LPARAM>(
reinterpret_cast<void*>(this)));
// window should appear on top of everything, including (especially)
// the task bar.
DWORD style = GetWindowLong(m_window, GWL_EXSTYLE);
style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
SetWindowLong(m_window, GWL_EXSTYLE, style);
// tell the task bar about this dialog
CArchTaskBarWindows::addDialog(m_window);
}
void
CMSWindowsServerTaskBarReceiver::destroyWindow()
{
if (m_window != NULL) {
CArchTaskBarWindows::removeDialog(m_window);
DestroyWindow(m_window);
m_window = NULL;
}
}
BOOL
CMSWindowsServerTaskBarReceiver::dlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM)
{
switch (msg) {
case WM_INITDIALOG:
// use default focus
return TRUE;
case WM_ACTIVATE:
// hide when another window is activated
if (LOWORD(wParam) == WA_INACTIVE) {
ShowWindow(hwnd, SW_HIDE);
}
break;
}
return FALSE;
}
BOOL CALLBACK
CMSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam)
{
// if msg is WM_INITDIALOG, extract the CMSWindowsServerTaskBarReceiver*
// and put it in the extra window data then forward the call.
CMSWindowsServerTaskBarReceiver* self = NULL;
if (msg == WM_INITDIALOG) {
self = reinterpret_cast<CMSWindowsServerTaskBarReceiver*>(
reinterpret_cast<void*>(lParam));
SetWindowLong(hwnd, GWL_USERDATA, lParam);
}
else {
// get the extra window data and forward the call
LONG data = GetWindowLong(hwnd, GWL_USERDATA);
if (data != 0) {
self = reinterpret_cast<CMSWindowsServerTaskBarReceiver*>(
reinterpret_cast<void*>(data));
}
}
// forward the message
if (self != NULL) {
return self->dlgProc(hwnd, msg, wParam, lParam);
}
else {
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
}
}

View File

@@ -0,0 +1,58 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CMSWINDOWSSERVERTASKBARRECEIVER_H
#define CMSWINDOWSSERVERTASKBARRECEIVER_H
#define WIN32_LEAN_AND_MEAN
#include "CServerTaskBarReceiver.h"
#include <windows.h>
//! Implementation of CServerTaskBarReceiver for Microsoft Windows
class CMSWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
public:
CMSWindowsServerTaskBarReceiver(HINSTANCE);
virtual ~CMSWindowsServerTaskBarReceiver();
// IArchTaskBarReceiver overrides
virtual void showStatus();
virtual void runMenu(int x, int y);
virtual void primaryAction();
virtual const Icon getIcon() const;
protected:
// CServerTaskBarReceiver overrides
virtual void onStatusChanged();
private:
HICON loadIcon(UINT);
void deleteIcon(HICON);
void createWindow();
void destroyWindow();
BOOL dlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK
staticDlgProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam);
private:
HINSTANCE m_appInstance;
HWND m_window;
HMENU m_menu;
HICON m_icon[kMaxState];
};
#endif

View File

@@ -0,0 +1,171 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CServerTaskBarReceiver.h"
#include "CServer.h"
#include "CLock.h"
#include "TMethodJob.h"
#include "CArch.h"
//
// CServerTaskBarReceiver
//
CServerTaskBarReceiver::CServerTaskBarReceiver() :
m_quit(NULL),
m_state(kNotRunning),
m_server(NULL)
{
// create a job for getting notification when the server's
// status changes.
m_job = new TMethodJob<CServerTaskBarReceiver>(this,
&CServerTaskBarReceiver::statusChanged, NULL);
}
CServerTaskBarReceiver::~CServerTaskBarReceiver()
{
if (m_server != NULL) {
m_server->removeStatusJob(m_job);
}
delete m_job;
delete m_quit;
}
void
CServerTaskBarReceiver::setServer(CServer* server)
{
{
CLock lock(&m_mutex);
if (m_server != server) {
if (m_server != NULL) {
m_server->removeStatusJob(m_job);
}
m_server = server;
if (m_server != NULL) {
m_server->addStatusJob(m_job);
}
}
}
ARCH->updateReceiver(this);
}
void
CServerTaskBarReceiver::setState(EState state)
{
{
CLock lock(&m_mutex);
m_state = state;
}
ARCH->updateReceiver(this);
}
void
CServerTaskBarReceiver::setQuitJob(IJob* job)
{
CLock lock(&m_mutex);
delete m_quit;
m_quit = job;
}
CServerTaskBarReceiver::EState
CServerTaskBarReceiver::getState() const
{
return m_state;
}
CServer*
CServerTaskBarReceiver::getServer() const
{
return m_server;
}
void
CServerTaskBarReceiver::lock() const
{
m_mutex.lock();
}
void
CServerTaskBarReceiver::unlock() const
{
m_mutex.unlock();
}
std::string
CServerTaskBarReceiver::getToolTip() const
{
switch (m_state) {
case kNotRunning:
return "Synergy: Not running";
case kNotWorking:
return CString("Synergy: ") + m_errorMessage;
case kNotConnected:
return "Synergy: Waiting for clients";
case kConnected:
return "Synergy: Connected";
default:
return "";
}
}
void
CServerTaskBarReceiver::quit()
{
if (m_quit != NULL) {
m_quit->run();
}
}
void
CServerTaskBarReceiver::onStatusChanged()
{
// do nothing
}
void
CServerTaskBarReceiver::statusChanged(void*)
{
// update our status
switch (m_server->getStatus(&m_errorMessage)) {
case CServer::kNotRunning:
setState(kNotRunning);
break;
case CServer::kRunning:
if (m_server->getNumClients() > 1)
setState(kConnected);
else
setState(kNotConnected);
break;
case CServer::kServerNameUnknown:
m_errorMessage = "Server name is not in configuration";
setState(kNotWorking);
break;
case CServer::kError:
setState(kNotWorking);
break;
default:
break;
}
// let subclasses have a go
onStatusChanged();
}

View File

@@ -0,0 +1,110 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CSERVERTASKBARRECEIVER_H
#define CSERVERTASKBARRECEIVER_H
#include "CMutex.h"
#include "CString.h"
#include "IArchTaskBarReceiver.h"
class CServer;
class IJob;
//! Implementation of IArchTaskBarReceiver for the synergy server
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
public:
enum EState {
kNotRunning,
kNotWorking,
kNotConnected,
kConnected,
kMaxState
};
CServerTaskBarReceiver();
virtual ~CServerTaskBarReceiver();
//! @name manipulators
//@{
//! Set server
/*!
Sets the server. The receiver will query state from this server.
*/
void setServer(CServer*);
//! Set state
/*!
Sets the current server state.
*/
void setState(EState);
//! Set the quit job that causes the server to quit
/*!
Set the job that causes the server to quit.
*/
void setQuitJob(IJob* adopted);
//@}
//! @name accessors
//@{
//! Get state
/*!
Returns the current server state. The receiver is not locked
by this call; the caller must do the locking.
*/
EState getState() const;
//! Get server
/*!
Returns the server set by \c setServer().
*/
CServer* getServer() const;
//@}
// IArchTaskBarReceiver overrides
virtual void showStatus() = 0;
virtual void runMenu(int x, int y) = 0;
virtual void primaryAction() = 0;
virtual void lock() const;
virtual void unlock() const;
virtual const Icon getIcon() const = 0;
virtual std::string getToolTip() const;
protected:
void quit();
//! Status change notification
/*!
Called when status changes. The default implementation does
nothing.
*/
virtual void onStatusChanged();
private:
void statusChanged(void*);
private:
CMutex m_mutex;
IJob* m_quit;
EState m_state;
CServer* m_server;
IJob* m_job;
CString m_errorMessage;
};
#endif

View File

@@ -0,0 +1,61 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#include "CXWindowsServerTaskBarReceiver.h"
#include "CArch.h"
//
// CXWindowsServerTaskBarReceiver
//
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver()
{
// add ourself to the task bar
ARCH->addReceiver(this);
}
CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver()
{
ARCH->removeReceiver(this);
}
void
CXWindowsServerTaskBarReceiver::showStatus()
{
// do nothing
}
void
CXWindowsServerTaskBarReceiver::runMenu(int, int)
{
// do nothing
}
void
CXWindowsServerTaskBarReceiver::primaryAction()
{
// do nothing
}
const IArchTaskBarReceiver::Icon
CXWindowsServerTaskBarReceiver::getIcon() const
{
return NULL;
}
void
CXWindowsServerTaskBarReceiver::onStatusChanged()
{
// do nothing
}

View File

@@ -0,0 +1,37 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* 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.
*/
#ifndef CXWINDOWSSERVERTASKBARRECEIVER_H
#define CXWINDOWSSERVERTASKBARRECEIVER_H
#include "CServerTaskBarReceiver.h"
//! Implementation of CServerTaskBarReceiver for X Windows
class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
public:
CXWindowsServerTaskBarReceiver();
virtual ~CXWindowsServerTaskBarReceiver();
// IArchTaskBarReceiver overrides
virtual void showStatus();
virtual void runMenu(int x, int y);
virtual void primaryAction();
virtual const Icon getIcon() const;
protected:
// CServerTaskBarReceiver overrides
virtual void onStatusChanged();
};
#endif

View File

@@ -15,19 +15,29 @@ NULL =
DEPTH = ../..
VDEPTH = ./$(VPATH)/$(DEPTH)
EXTRA_DIST = \
resource.h \
synergys.ico \
synergys.dsp \
synergys.rc \
EXTRA_DIST = \
CMSWindowsServerTaskBarReceiver.cpp \
CMSWindowsServerTaskBarReceiver.h \
resource.h \
synergys.ico \
synergys.dsp \
synergys.rc \
tb_error.ico \
tb_idle.ico \
tb_run.ico \
tb_wait.ico \
$(NULL)
MAINTAINERCLEANFILES = \
Makefile.in \
MAINTAINERCLEANFILES = \
Makefile.in \
$(NULL)
bin_PROGRAMS = synergys
synergys_SOURCES = \
CServerTaskBarReceiver.cpp \
CServerTaskBarReceiver.h \
CXWindowsServerTaskBarReceiver.cpp \
CXWindowsServerTaskBarReceiver.h \
synergys.cpp \
$(NULL)
synergys_LDADD = \

View File

@@ -4,14 +4,24 @@
//
#define IDS_FAILED 1
#define IDI_SYNERGY 101
#define IDI_TASKBAR_NOT_RUNNING 102
#define IDI_TASKBAR_NOT_WORKING 103
#define IDI_TASKBAR_NOT_CONNECTED 104
#define IDI_TASKBAR_CONNECTED 105
#define IDR_TASKBAR 107
#define IDD_TASKBAR_STATUS 108
#define IDC_TASKBAR_STATUS_STATUS 1000
#define IDC_TASKBAR_STATUS_CLIENTS 1001
#define IDC_TASKBAR_QUIT 40003
#define IDC_TASKBAR_STATUS 40004
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_RESOURCE_VALUE 109
#define _APS_NEXT_COMMAND_VALUE 40005
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -24,6 +24,7 @@
#include "CMutex.h"
#include "CThread.h"
#include "XThread.h"
#include "CFunctionJob.h"
#include "CLog.h"
#include "LogOutputters.h"
#include "CArch.h"
@@ -33,12 +34,15 @@
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
#include "CMSWindowsPrimaryScreen.h"
#include "CMSWindowsServerTaskBarReceiver.h"
#include "resource.h"
#undef DAEMON_RUNNING
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
#elif UNIX_LIKE
#include "CXWindowsPrimaryScreen.h"
#include "CXWindowsServerTaskBarReceiver.h"
#endif
// platform dependent name of a daemon
@@ -123,11 +127,46 @@ CPrimaryScreenFactory::create(IScreenReceiver* receiver,
}
//! CQuitJob
/*!
A job that cancels a given thread.
*/
class CQuitJob : public IJob {
public:
CQuitJob(const CThread& thread);
~CQuitJob();
// IJob overrides
virtual void run();
private:
CThread m_thread;
};
CQuitJob::CQuitJob(const CThread& thread) :
m_thread(thread)
{
// do nothing
}
CQuitJob::~CQuitJob()
{
// do nothing
}
void
CQuitJob::run()
{
m_thread.cancel();
}
//
// platform independent main
//
static CServer* s_server = NULL;
static CServer* s_server = NULL;
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
static
int
@@ -168,6 +207,7 @@ realMain(void)
// open server
try {
s_taskBarReceiver->setServer(s_server);
s_server->open();
opened = true;
@@ -177,18 +217,17 @@ realMain(void)
s_server->mainLoop();
// clean up
#define FINALLY do { \
if (!locked) { \
DAEMON_RUNNING(false); \
locked = true; \
} \
if (s_server != NULL) { \
if (opened) { \
s_server->close(); \
} \
} \
delete s_server; \
s_server = NULL; \
#define FINALLY do { \
if (!locked) { \
DAEMON_RUNNING(false); \
locked = true; \
} \
if (opened) { \
s_server->close(); \
} \
s_taskBarReceiver->setServer(NULL); \
delete s_server; \
s_server = NULL; \
} while (false)
FINALLY;
}
@@ -227,6 +266,41 @@ realMain(void)
return result;
}
static
void
realMainEntry(void*)
{
CThread::exit(reinterpret_cast<void*>(realMain()));
}
static
int
runMainInThread(void)
{
CThread appThread(new CFunctionJob(&realMainEntry));
try {
#if WINDOWS_LIKE
MSG msg;
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
// check for a quit event
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
CThread::getCurrentThread().cancel();
}
}
}
#else
appThread.wait(-1.0);
#endif
return reinterpret_cast<int>(appThread.getResult());
}
catch (XThread&) {
appThread.cancel();
appThread.wait(-1.0);
throw;
}
}
//
// command line parsing
@@ -329,7 +403,7 @@ PLATFORM_EXTRA
static
bool
isArg(int argi, int argc, const char** argv,
isArg(int argi, int argc, const char* const* argv,
const char* name1, const char* name2,
int minRequiredParameters = 0)
{
@@ -350,7 +424,7 @@ isArg(int argi, int argc, const char** argv,
static
void
parse(int argc, const char** argv)
parse(int argc, const char* const* argv)
{
assert(ARG->m_pname != NULL);
assert(argv != NULL);
@@ -553,16 +627,6 @@ loadConfig()
}
}
static
void
useSystemLog()
{
// redirect log messages
ILogOutputter* logger = new CSystemLogOutputter;
logger->open(DAEMON_NAME);
CLOG->insert(new CStopLogOutputter);
CLOG->insert(logger);
}
//
// platform dependent entry points
@@ -570,8 +634,6 @@ useSystemLog()
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
static bool s_hasImportantLogMessages = false;
//
@@ -623,7 +685,10 @@ static
int
daemonStartup(int argc, const char** argv)
{
useSystemLog();
CSystemLogger sysLogger(DAEMON_NAME);
// have to cancel this thread to quit
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// catch errors that would normally exit
bye = &byeThrow;
@@ -645,14 +710,65 @@ static
int
daemonStartup95(int, const char**)
{
useSystemLog();
return realMain();
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
}
static
int
run(int argc, char** argv)
{
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
// parse command line
parse(argc, argv);
// load configuration
loadConfig();
// daemonize if requested
if (ARG->m_daemon) {
// start as a daemon
if (CArchMiscWindows::isWindows95Family()) {
try {
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
return kExitFailed;
}
else {
// cannot start a service from the command line so just
// run normally (except with log messages redirected).
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
}
}
else {
// run
return runMainInThread();
}
}
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
CArch arch;
CArch arch(instance);
CLOG;
CArgs args;
@@ -665,55 +781,27 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// send PRINT and FATAL output to a message box
CLOG->insert(new CMessageBoxOutputter);
// windows NT family starts services using no command line options.
// since i'm not sure how to tell the difference between that and
// a user providing no options we'll assume that if there are no
// arguments and we're on NT then we're being invoked as a service.
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
int result = kExitFailed;
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
}
delete CLOG;
return result;
}
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance);
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// parse command line
parse(__argc, const_cast<const char**>(__argv));
// load configuration
loadConfig();
// daemonize if requested
int result;
if (ARG->m_daemon) {
// start as a daemon
if (CArchMiscWindows::isWindows95Family()) {
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
}
catch (XArchDaemon& e) {
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
result = kExitFailed;
}
}
else {
// cannot start a service from the command line so just
// run normally (except with log messages redirected).
useSystemLog();
result = realMain();
}
try {
// run in foreground or as a daemon
result = run(__argc, __argv);
}
else {
// run
result = realMain();
catch (...) {
// note that we don't rethrow thread cancellation. we'll
// be exiting soon so it doesn't matter. what we'd like
// is for everything after this try/catch to be in a
// finally block.
result = kExitFailed;
}
// done with task bar receiver
delete s_taskBarReceiver;
// let user examine any messages if we're running as a backend
// by putting up a dialog box before exiting.
if (ARG->m_backend && s_hasImportantLogMessages) {
@@ -733,7 +821,7 @@ static
int
daemonStartup(int, const char**)
{
useSystemLog();
CSystemLogger sysLogger(DAEMON_NAME);
return realMain();
}
@@ -747,8 +835,13 @@ main(int argc, char** argv)
// get program name
ARG->m_pname = ARCH->getBasename(argv[0]);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
// parse command line
parse(argc, const_cast<const char**>(argv));
parse(argc, argv);
// load configuration
loadConfig();
@@ -768,6 +861,9 @@ main(int argc, char** argv)
result = realMain();
}
// done with task bar receiver
delete s_taskBarReceiver;
return result;
}

View File

@@ -94,6 +94,14 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CMSWindowsServerTaskBarReceiver.cpp
# End Source File
# Begin Source File
SOURCE=.\CServerTaskBarReceiver.cpp
# End Source File
# Begin Source File
SOURCE=.\synergys.cpp
# End Source File
# Begin Source File
@@ -106,6 +114,14 @@ SOURCE=.\synergys.rc
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CMSWindowsServerTaskBarReceiver.h
# End Source File
# Begin Source File
SOURCE=.\CServerTaskBarReceiver.h
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# End Group
@@ -116,6 +132,22 @@ SOURCE=.\resource.h
SOURCE=.\synergys.ico
# End Source File
# Begin Source File
SOURCE=.\tb_error.ico
# End Source File
# Begin Source File
SOURCE=.\tb_idle.ico
# End Source File
# Begin Source File
SOURCE=.\tb_run.ico
# End Source File
# Begin Source File
SOURCE=.\tb_wait.ico
# End Source File
# End Group
# End Target
# End Project

BIN
cmd/synergys/tb_error.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
cmd/synergys/tb_idle.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
cmd/synergys/tb_run.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
cmd/synergys/tb_wait.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B