Merged Win32 updates. Added full warnings on g++. Fixed bug in

client when handling server rejection.
This commit is contained in:
crs 2004-02-28 12:19:49 +00:00
parent 612a2054e6
commit 54acf38d82
74 changed files with 2333 additions and 2185 deletions

View File

@ -513,3 +513,33 @@ else
$2
fi
])dnl ACX_PTHREAD
dnl enable maximum compiler warnings
dnl we only know how to do this for g++
AC_DEFUN([ACX_CXX_WARNINGS], [
AC_MSG_CHECKING([for C++ compiler warning flags])
if test "$GXX" = "yes"; then
acx_cxx_warnings="-Wall"
fi
if test -n "$acx_cxx_warnings"; then
CXXFLAGS="$CXXFLAGS $acx_cxx_warnings"
else
acx_cxx_warnings="unknown"
fi
AC_MSG_RESULT($acx_cxx_warnings)
])dnl ACX_CXX_WARNINGS
dnl enable compiler warnings are errors
dnl we only know how to do this for g++
AC_DEFUN([ACX_CXX_WARNINGS_ARE_ERRORS], [
AC_MSG_CHECKING([for C++ compiler warning are errors flags])
if test "$GXX" = "yes"; then
acx_cxx_warnings_are_errors="-Werror"
fi
if test -n "$acx_cxx_warnings_are_errors"; then
CXXFLAGS="$CXXFLAGS $acx_cxx_warnings_are_errors"
else
acx_cxx_warnings_are_errors="unknown"
fi
AC_MSG_RESULT($acx_cxx_warnings_are_errors)
])dnl ACX_CXX_WARNINGS_ARE_ERRORS

View File

@ -14,6 +14,7 @@
#include "CConfig.h"
#include "LaunchUtil.h"
#include "CMSWindowsUtil.h"
#include "CArch.h"
#include "resource.h"
#include "stdfstream.h"
@ -23,32 +24,13 @@
CString
getString(DWORD id)
{
char buffer[1024];
buffer[0] = '\0';
LoadString(s_instance, id, buffer, sizeof(buffer) / sizeof(buffer[0]));
return buffer;
return CMSWindowsUtil::getString(s_instance, id);
}
CString
getErrorString(DWORD error)
{
char* buffer;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
0,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&buffer,
0,
NULL) == 0) {
return getString(IDS_ERROR);
}
else {
CString result(buffer);
LocalFree(buffer);
return result;
}
return CMSWindowsUtil::getErrorString(s_instance, error, IDS_ERROR);
}
void

View File

@ -332,8 +332,8 @@ BEGIN
"Synergy is not configured to start automatically."
IDS_INSTALL_LABEL "Install"
IDS_UNINSTALL_LABEL "Uninstall"
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}."
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}."
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}"
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}"
IDS_INSTALL_TITLE "Installed Auto-Start"
IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer."
IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in."
@ -348,6 +348,7 @@ BEGIN
IDS_SERVER_IS_CLIENT "Please enter the computer name of the synergy server, not\nthe name of this computer, in the Server Host Name field."
IDS_ADD_SCREEN "Add Screen"
IDS_EDIT_SCREEN "Edit Screen %{1}"
IDS_ERROR_CODE "Error code: %{1}"
END
#endif // English (U.S.) resources

View File

@ -41,6 +41,7 @@
#define IDS_ADD_SCREEN 37
#define IDS_EDIT_SCREEN 38
#define IDS_INVALID_TIME 39
#define IDS_ERROR_CODE 39
#define IDD_MAIN 101
#define IDD_ADD 102
#define IDD_WAIT 103

View File

@ -21,18 +21,19 @@
#include "CArchTaskBarWindows.h"
#include "resource.h"
static const UINT g_stateToIconID[CMSWindowsClientTaskBarReceiver::kMaxState] =
//
// CMSWindowsClientTaskBarReceiver
//
const UINT CMSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] =
{
IDI_TASKBAR_NOT_RUNNING,
IDI_TASKBAR_NOT_WORKING,
IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_CONNECTED
};
//
// CMSWindowsClientTaskBarReceiver
//
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
CClientTaskBarReceiver(),
@ -41,7 +42,7 @@ CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
m_logBuffer(logBuffer)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(g_stateToIconID[i]);
m_icon[i] = loadIcon(s_stateToIconID[i]);
}
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
@ -171,7 +172,7 @@ CMSWindowsClientTaskBarReceiver::primaryAction()
const IArchTaskBarReceiver::Icon
CMSWindowsClientTaskBarReceiver::getIcon() const
{
return reinterpret_cast<Icon>(m_icon[getState()]);
return reinterpret_cast<Icon>(m_icon[getStatus()]);
}
void

View File

@ -58,6 +58,7 @@ private:
HMENU m_menu;
HICON m_icon[kMaxState];
const CBufferedLogOutputter* m_logBuffer;
static const UINT s_stateToIconID[];
};
#endif

View File

@ -19,7 +19,8 @@
// CXWindowsClientTaskBarReceiver
//
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver()
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(
const CBufferedLogOutputter*)
{
// add ourself to the task bar
ARCH->addReceiver(this);

View File

@ -17,10 +17,12 @@
#include "CClientTaskBarReceiver.h"
class CBufferedLogOutputter;
//! Implementation of CClientTaskBarReceiver for X Windows
class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
public:
CXWindowsClientTaskBarReceiver();
CXWindowsClientTaskBarReceiver(const CBufferedLogOutputter*);
virtual ~CXWindowsClientTaskBarReceiver();
// IArchTaskBarReceiver overrides

View File

@ -48,6 +48,7 @@ synergyc_LDADD = \
$(DEPTH)/lib/io/libio.a \
$(DEPTH)/lib/mt/libmt.a \
$(DEPTH)/lib/base/libbase.a \
$(DEPTH)/lib/common/libcommon.a \
$(DEPTH)/lib/arch/libarch.a \
$(X_LIBS) \
$(X_PRE_LIBS) \

View File

@ -3,6 +3,8 @@
// Used by synergyc.rc
//
#define IDS_FAILED 1
#define IDS_INIT_FAILED 2
#define IDS_UNCAUGHT_EXCEPTION 3
#define IDI_SYNERGY 101
#define IDI_TASKBAR_NOT_RUNNING 102
#define IDI_TASKBAR_NOT_WORKING 103

View File

@ -26,6 +26,7 @@
#include "CFunctionEventJob.h"
#include "CLog.h"
#include "CString.h"
#include "CStringUtil.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "XArch.h"
@ -33,8 +34,9 @@
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
#include "CArchMiscWindows.h"
#include "CMSWindowsScreen.h"
#include "CMSWindowsUtil.h"
#include "CMSWindowsClientTaskBarReceiver.h"
#include "resource.h"
#undef DAEMON_RUNNING
@ -51,6 +53,9 @@
#define DAEMON_NAME "synergyc"
#endif
typedef int (*StartupFunc)(int, char**);
static void parse(int argc, const char* const* argv);
//
// program arguments
//
@ -64,7 +69,8 @@ public:
m_backend(false),
m_restartable(true),
m_daemon(true),
m_logFilter(NULL)
m_logFilter(NULL),
m_serverAddress(NULL)
{ s_instance = this; }
~CArgs() { s_instance = NULL; }
@ -76,7 +82,7 @@ public:
bool m_daemon;
const char* m_logFilter;
CString m_name;
CNetworkAddress m_serverAddress;
CNetworkAddress* m_serverAddress;
};
CArgs* CArgs::s_instance = NULL;
@ -97,6 +103,18 @@ createScreen()
#endif
}
static
CClientTaskBarReceiver*
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
{
#if WINDOWS_LIKE
return new CMSWindowsClientTaskBarReceiver(
CMSWindowsScreen::getInstance(), logBuffer);
#elif UNIX_LIKE
return new CXWindowsClientTaskBarReceiver(logBuffer);
#endif
}
//
// platform independent main
@ -292,7 +310,7 @@ startClient()
try {
clientScreen = openClientScreen();
s_client = openClient(ARG->m_name,
ARG->m_serverAddress, clientScreen);
*ARG->m_serverAddress, clientScreen);
s_clientScreen = clientScreen;
LOG((CLOG_NOTE "started client"));
s_client->connect();
@ -338,7 +356,7 @@ stopClient()
static
int
realMain()
mainLoop()
{
// start the client. if this return false then we've failed and
// we shouldn't retry.
@ -350,8 +368,8 @@ realMain()
// run event loop. if startClient() failed we're supposed to retry
// later. the timer installed by startClient() will take care of
// that.
DAEMON_RUNNING(true);
CEvent event;
DAEMON_RUNNING(true);
EVENTQUEUE->getEvent(event);
while (event.getType() != CEvent::kQuit) {
EVENTQUEUE->dispatchEvent(event);
@ -369,45 +387,65 @@ realMain()
return kExitSuccess;
}
/*
static
void
realMainEntry(void* vresult)
int
daemonMainLoop(int, const char**)
{
*reinterpret_cast<int*>(vresult) = realMain();
CSystemLogger sysLogger(DAEMON_NAME);
return mainLoop();
}
static
int
runMainInThread(void)
standardStartup(int argc, char** argv)
{
int result = 0;
CThread appThread(new CFunctionJob(&realMainEntry, &result));
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();
// parse command line
parse(argc, argv);
// daemonize if requested
if (ARG->m_daemon) {
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
else {
return mainLoop();
}
}
#else
appThread.wait(-1.0);
#endif
static
int
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
{
// general initialization
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
ARG->m_serverAddress = new CNetworkAddress;
ARG->m_pname = ARCH->getBasename(argv[0]);
// install caller's output filter
if (outputter != NULL) {
CLOG->insert(outputter);
}
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = createTaskBarReceiver(&logBuffer);
// run
int result = startup(argc, argv);
// done with task bar receiver
delete s_taskBarReceiver;
// done with log buffer
CLOG->remove(&logBuffer);
delete ARG->m_serverAddress;
return result;
}
catch (XThread&) {
appThread.cancel();
appThread.wait(-1.0);
throw;
}
}
*/
//
@ -588,7 +626,7 @@ parse(int argc, const char* const* argv)
// save server address
try {
ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
*ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
}
catch (XSocketAddress& e) {
LOG((CLOG_PRINT "%s: %s" BYE,
@ -676,193 +714,107 @@ byeThrow(int x)
static
int
daemonStartup(int argc, const char** argv)
daemonNTMainLoop(int argc, const char** argv)
{
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;
// parse command line
parse(argc, argv);
// cannot run as backend if running as a service
ARG->m_backend = false;
// run as a service
return CArchMiscWindows::runDaemon(realMain);
return CArchMiscWindows::runDaemon(mainLoop);
}
static
int
daemonStartup95(int, const char**)
daemonNTStartup(int, char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
bye = &byeThrow;
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
}
static
int
run(int argc, char** argv)
void
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
{
CString fmt = CMSWindowsUtil::getString(instance, id);
CString msg = CStringUtil::format(fmt.c_str(), arg);
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
}
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
try {
CArch arch(instance);
CMSWindowsScreen::init(instance);
CLOG;
// FIXME
// CThread::getCurrentThread().setPriority(-14);
CArgs args;
// 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);
StartupFunc startup = &standardStartup;
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
startup = &daemonNTStartup;
}
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(instance);
CLOG;
CArgs args;
// save instance
CMSWindowsScreen::init(instance);
// get program name
ARG->m_pname = ARCH->getBasename(__argv[0]);
// send PRINT and FATAL output to a message box
CLOG->insert(new CMessageBoxOutputter);
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance,
&logBuffer);
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
int result;
try {
// run in foreground or as a daemon
result = run(__argc, __argv);
}
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;
// done with log buffer
CLOG->remove(&logBuffer);
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
// 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) {
char msg[1024];
msg[0] = '\0';
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
if (args.m_backend && s_hasImportantLogMessages) {
showError(instance, args.m_pname, IDS_FAILED, "");
}
delete CLOG;
return result;
}
catch (XBase& e) {
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
throw;
}
catch (XArch& e) {
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
return kExitFailed;
}
catch (...) {
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
throw;
}
}
#elif UNIX_LIKE
static
int
daemonStartup(int, const char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return realMain();
}
int
main(int argc, char** argv)
{
CArgs args;
try {
int result;
CArch arch;
CLOG;
// go really fast
CThread::getCurrentThread().setPriority(-14);
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
// get program name
CArgs args;
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;
// parse command line
parse(argc, argv);
// daemonize if requested
int result;
if (ARG->m_daemon) {
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to daemonize"));
result = kExitFailed;
}
}
else {
result = realMain();
}
// done with task bar receiver
delete s_taskBarReceiver;
result = run(argc, argv, NULL, &standardStartup);
delete CLOG;
return result;
}
catch (XBase& e) {
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
throw;
}
catch (XArch& e) {
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
return kExitFailed;
}
catch (...) {
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
throw;
}
}
#else

View File

@ -99,6 +99,8 @@ END
STRINGTABLE DISCARDABLE
BEGIN
IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
IDS_INIT_FAILED "Synergy failed to initialize: %{1}"
IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}"
END
#endif // English (U.S.) resources

View File

@ -21,7 +21,11 @@
#include "CArchTaskBarWindows.h"
#include "resource.h"
static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
//
// CMSWindowsServerTaskBarReceiver
//
const UINT CMSWindowsServerTaskBarReceiver::s_stateToIconID[kMaxState] =
{
IDI_TASKBAR_NOT_RUNNING,
IDI_TASKBAR_NOT_WORKING,
@ -29,10 +33,6 @@ static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
IDI_TASKBAR_CONNECTED
};
//
// CMSWindowsServerTaskBarReceiver
//
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
CServerTaskBarReceiver(),
@ -41,7 +41,7 @@ CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
m_logBuffer(logBuffer)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(g_stateToIconID[i]);
m_icon[i] = loadIcon(s_stateToIconID[i]);
}
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
@ -77,12 +77,7 @@ CMSWindowsServerTaskBarReceiver::showStatus()
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);
}
const CClients& clients = getClients();
// done getting status
unlock();
@ -92,7 +87,7 @@ CMSWindowsServerTaskBarReceiver::showStatus()
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();
for (CClients::const_iterator index = clients.begin();
index != clients.end(); ) {
const char* client = index->c_str();
if (++index == clients.end()) {
@ -191,7 +186,7 @@ CMSWindowsServerTaskBarReceiver::primaryAction()
const IArchTaskBarReceiver::Icon
CMSWindowsServerTaskBarReceiver::getIcon() const
{
return reinterpret_cast<Icon>(m_icon[getState()]);
return reinterpret_cast<Icon>(m_icon[getStatus()]);
}
void

View File

@ -58,6 +58,7 @@ private:
HMENU m_menu;
HICON m_icon[kMaxState];
const CBufferedLogOutputter* m_logBuffer;
static const UINT s_stateToIconID[];
};
#endif

View File

@ -19,7 +19,8 @@
// CXWindowsServerTaskBarReceiver
//
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver()
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver(
const CBufferedLogOutputter*)
{
// add ourself to the task bar
ARCH->addReceiver(this);

View File

@ -17,10 +17,12 @@
#include "CServerTaskBarReceiver.h"
class CBufferedLogOutputter;
//! Implementation of CServerTaskBarReceiver for X Windows
class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
public:
CXWindowsServerTaskBarReceiver();
CXWindowsServerTaskBarReceiver(const CBufferedLogOutputter*);
virtual ~CXWindowsServerTaskBarReceiver();
// IArchTaskBarReceiver overrides

View File

@ -48,6 +48,7 @@ synergys_LDADD = \
$(DEPTH)/lib/io/libio.a \
$(DEPTH)/lib/mt/libmt.a \
$(DEPTH)/lib/base/libbase.a \
$(DEPTH)/lib/common/libcommon.a \
$(DEPTH)/lib/arch/libarch.a \
$(X_LIBS) \
$(X_PRE_LIBS) \

View File

@ -3,6 +3,8 @@
// Used by synergys.rc
//
#define IDS_FAILED 1
#define IDS_INIT_FAILED 2
#define IDS_UNCAUGHT_EXCEPTION 3
#define IDI_SYNERGY 101
#define IDI_TASKBAR_NOT_RUNNING 102
#define IDI_TASKBAR_NOT_WORKING 103

View File

@ -28,6 +28,8 @@
#include "CEventQueue.h"
#include "CFunctionEventJob.h"
#include "CLog.h"
#include "CString.h"
#include "CStringUtil.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "XArch.h"
@ -36,8 +38,9 @@
#define DAEMON_RUNNING(running_)
#if WINDOWS_LIKE
#include "CMSWindowsScreen.h"
#include "CArchMiscWindows.h"
#include "CMSWindowsScreen.h"
#include "CMSWindowsUtil.h"
#include "CMSWindowsServerTaskBarReceiver.h"
#include "resource.h"
#undef DAEMON_RUNNING
@ -63,6 +66,10 @@
#define SYS_CONFIG_NAME "synergy.conf"
#endif
typedef int (*StartupFunc)(int, char**);
static void parse(int argc, const char* const* argv);
static void loadConfig();
//
// program arguments
//
@ -90,8 +97,8 @@ public:
const char* m_configFile;
const char* m_logFilter;
CString m_name;
CNetworkAddress m_synergyAddress;
CConfig m_config;
CNetworkAddress* m_synergyAddress;
CConfig* m_config;
};
CArgs* CArgs::s_instance = NULL;
@ -112,6 +119,18 @@ createScreen()
#endif
}
static
CServerTaskBarReceiver*
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
{
#if WINDOWS_LIKE
return new CMSWindowsServerTaskBarReceiver(
CMSWindowsScreen::getInstance(), logBuffer);
#elif UNIX_LIKE
return new CXWindowsServerTaskBarReceiver(logBuffer);
#endif
}
//
// platform independent main
@ -299,11 +318,11 @@ startServer()
CPrimaryClient* primaryClient = NULL;
CClientListener* listener = NULL;
try {
CString name = ARG->m_config.getCanonicalName(ARG->m_name);
CString name = ARG->m_config->getCanonicalName(ARG->m_name);
serverScreen = openServerScreen();
primaryClient = openPrimaryClient(name, serverScreen);
listener = openClientListener(ARG->m_config.getSynergyAddress());
s_server = openServer(ARG->m_config, primaryClient);
listener = openClientListener(ARG->m_config->getSynergyAddress());
s_server = openServer(*ARG->m_config, primaryClient);
s_serverScreen = serverScreen;
s_primaryClient = primaryClient;
s_listener = listener;
@ -372,26 +391,26 @@ stopServer()
static
int
realMain()
mainLoop()
{
// if configuration has no screens then add this system
// as the default
if (ARG->m_config.begin() == ARG->m_config.end()) {
ARG->m_config.addScreen(ARG->m_name);
if (ARG->m_config->begin() == ARG->m_config->end()) {
ARG->m_config->addScreen(ARG->m_name);
}
// set the contact address, if provided, in the config.
// otherwise, if the config doesn't have an address, use
// the default.
if (ARG->m_synergyAddress.isValid()) {
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
if (ARG->m_synergyAddress->isValid()) {
ARG->m_config->setSynergyAddress(*ARG->m_synergyAddress);
}
else if (!ARG->m_config.getSynergyAddress().isValid()) {
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
else if (!ARG->m_config->getSynergyAddress().isValid()) {
ARG->m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
}
// canonicalize the primary screen name
CString primaryName = ARG->m_config.getCanonicalName(ARG->m_name);
CString primaryName = ARG->m_config->getCanonicalName(ARG->m_name);
if (primaryName.empty()) {
LOG((CLOG_CRIT "unknown screen name `%s'", ARG->m_name.c_str()));
return kExitFailed;
@ -407,8 +426,8 @@ realMain()
// run event loop. if startServer() failed we're supposed to retry
// later. the timer installed by startServer() will take care of
// that.
DAEMON_RUNNING(true);
CEvent event;
DAEMON_RUNNING(true);
EVENTQUEUE->getEvent(event);
while (event.getType() != CEvent::kQuit) {
EVENTQUEUE->dispatchEvent(event);
@ -426,43 +445,71 @@ realMain()
return kExitSuccess;
}
/* XXX
static
void
realMainEntry(void* vresult)
int
daemonMainLoop(int, const char**)
{
*reinterpret_cast<int*>(vresult) = realMain();
CSystemLogger sysLogger(DAEMON_NAME);
return mainLoop();
}
static
int
runMainInThread(void)
standardStartup(int argc, char** argv)
{
int result = 0;
CThread appThread(new CFunctionJob(&realMainEntry, &result));
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();
// parse command line
parse(argc, argv);
// load configuration
loadConfig();
// daemonize if requested
if (ARG->m_daemon) {
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
}
else {
return mainLoop();
}
}
static
int
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
{
// general initialization
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
ARG->m_synergyAddress = new CNetworkAddress;
ARG->m_config = new CConfig;
ARG->m_pname = ARCH->getBasename(argv[0]);
// install caller's output filter
if (outputter != NULL) {
CLOG->insert(outputter);
}
#else
appThread.wait(-1.0);
#endif
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = createTaskBarReceiver(&logBuffer);
// run
int result = startup(argc, argv);
// done with task bar receiver
delete s_taskBarReceiver;
// done with log buffer
CLOG->remove(&logBuffer);
delete ARG->m_config;
delete ARG->m_synergyAddress;
return result;
}
catch (XThread&) {
appThread.cancel();
appThread.wait(-1.0);
throw;
}
}
*/
//
// command line parsing
@ -606,7 +653,7 @@ parse(int argc, const char* const* argv)
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
// save listen address
try {
ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
*ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
kDefaultPort);
}
catch (XSocketAddress& e) {
@ -723,7 +770,7 @@ loadConfig(const char* pathname)
if (!configStream) {
throw XConfigRead("cannot open file");
}
configStream >> ARG->m_config;
configStream >> *ARG->m_config;
LOG((CLOG_DEBUG "configuration read successfully"));
return true;
}
@ -828,198 +875,108 @@ byeThrow(int x)
static
int
daemonStartup(int argc, const char** argv)
daemonNTMainLoop(int argc, const char** argv)
{
CSystemLogger sysLogger(DAEMON_NAME);
// catch errors that would normally exit
bye = &byeThrow;
// parse command line
parse(argc, argv);
// cannot run as backend if running as a service
ARG->m_backend = false;
// load configuration
loadConfig();
// run as a service
return CArchMiscWindows::runDaemon(realMain);
return CArchMiscWindows::runDaemon(mainLoop);
}
static
int
daemonStartup95(int, const char**)
daemonNTStartup(int, char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return runMainInThread();
bye = &byeThrow;
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
}
static
int
run(int argc, char** argv)
void
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
{
CString fmt = CMSWindowsUtil::getString(instance, id);
CString msg = CStringUtil::format(fmt.c_str(), arg);
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
}
int WINAPI
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
{
try {
CArch arch(instance);
CMSWindowsScreen::init(instance);
CLOG;
// FIXME
// CThread::getCurrentThread().setPriority(-14);
CArgs args;
// 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);
StartupFunc startup = &standardStartup;
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
startup = &daemonNTStartup;
}
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(instance);
CLOG;
CArgs args;
// save instance
CMSWindowsScreen::init(instance);
// get program name
ARG->m_pname = ARCH->getBasename(__argv[0]);
// send PRINT and FATAL output to a message box
CLOG->insert(new CMessageBoxOutputter);
// save log messages
CBufferedLogOutputter logBuffer(1000);
CLOG->insert(&logBuffer, true);
// make the task bar receiver. the user can control this app
// through the task bar.
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
&logBuffer);
int result;
try {
// run in foreground or as a daemon
result = run(__argc, __argv);
}
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;
// done with log buffer
CLOG->remove(&logBuffer);
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
// 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) {
char msg[1024];
msg[0] = '\0';
LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0]));
MessageBox(NULL, msg, ARG->m_pname, MB_OK | MB_ICONWARNING);
if (args.m_backend && s_hasImportantLogMessages) {
showError(instance, args.m_pname, IDS_FAILED, "");
}
delete CLOG;
return result;
}
catch (XBase& e) {
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
throw;
}
catch (XArch& e) {
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
return kExitFailed;
}
catch (...) {
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
throw;
}
}
#elif UNIX_LIKE
static
int
daemonStartup(int, const char**)
{
CSystemLogger sysLogger(DAEMON_NAME);
return realMain();
}
int
main(int argc, char** argv)
{
CArgs args;
try {
int result;
CArch arch;
CLOG;
// go really fast
CThread::getCurrentThread().setPriority(-14);
CSocketMultiplexer multiplexer;
CEventQueue eventQueue;
// get program name
CArgs args;
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;
// parse command line
parse(argc, argv);
// load configuration
loadConfig();
// daemonize if requested
int result;
if (ARG->m_daemon) {
try {
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
}
catch (XArchDaemon&) {
LOG((CLOG_CRIT "failed to daemonize"));
result = kExitFailed;
}
}
else {
result = realMain();
}
// done with task bar receiver
delete s_taskBarReceiver;
result = run(argc, argv, NULL, &standardStartup);
delete CLOG;
return result;
}
catch (XBase& e) {
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
throw;
}
catch (XArch& e) {
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
return kExitFailed;
}
catch (...) {
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
throw;
}
}
#else

View File

@ -102,6 +102,8 @@ END
STRINGTABLE DISCARDABLE
BEGIN
IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
IDS_INIT_FAILED "Synergy failed to initialize: %{1}"
IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}"
END
#endif // English (U.S.) resources

View File

@ -94,6 +94,9 @@ dnl use AC_REPLACE_FUNCS() for stuff in string.h
dnl checks for system services
dnl enable maximum compiler warnings and warnings are errors.
ACX_CXX_WARNINGS
ACX_CXX_WARNINGS_ARE_ERRORS
dnl adjust variables for X11 and pthreads
CXXFLAGS="$CXXFLAGS $SYNERGY_CXXFLAGS $X_CFLAGS $PTHREAD_CFLAGS -D_BSD_SOURCE -D_XOPEN_SOURCE=500"

View File

@ -351,18 +351,6 @@ CArch::wait(CArchThread thread, double timeout)
return m_mt->wait(thread, timeout);
}
IArchMultithread::EWaitResult
CArch::waitForEvent(CArchThread thread, double timeout)
{
return m_mt->waitForEvent(thread, timeout);
}
void
CArch::unblockThread(CArchThread thread)
{
m_mt->unblockThread(thread);
}
bool
CArch::isSameThread(CArchThread thread1, CArchThread thread2)
{
@ -390,13 +378,13 @@ CArch::getIDOfThread(CArchThread thread)
void
CArch::setInterruptHandler(InterruptFunc func, void* userData)
{
return m_mt->setInterruptHandler(func, userData);
m_mt->setInterruptHandler(func, userData);
}
void
CArch::interrupt()
{
return m_mt->interrupt();
m_mt->interrupt();
}
CArchSocket
@ -459,6 +447,12 @@ CArch::pollSocket(CPollEntry pe[], int num, double timeout)
return m_net->pollSocket(pe, num, timeout);
}
void
CArch::unblockPollSocket(CArchThread thread)
{
m_net->unblockPollSocket(thread);
}
size_t
CArch::readSocket(CArchSocket s, void* buf, size_t len)
{

View File

@ -116,8 +116,6 @@ public:
virtual void setPriorityOfThread(CArchThread, int n);
virtual void testCancelThread();
virtual bool wait(CArchThread, double timeout);
virtual EWaitResult waitForEvent(CArchThread, double timeout);
virtual void unblockThread(CArchThread thread);
virtual bool isSameThread(CArchThread, CArchThread);
virtual bool isExitedThread(CArchThread);
virtual void* getResultOfThread(CArchThread);
@ -136,6 +134,7 @@ public:
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
virtual int pollSocket(CPollEntry[], int num, double timeout);
virtual void unblockPollSocket(CArchThread thread);
virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
virtual size_t writeSocket(CArchSocket s,
const void* buf, size_t len);

View File

@ -110,7 +110,7 @@ CArchConsoleWindows::getNewlineForConsole()
BOOL WINAPI
CArchConsoleWindows::signalHandler(DWORD)
{
// terminate thread and skip remaining handlers
ARCH->cancelThread(s_thread);
// terminate app and skip remaining handlers
ARCH->interrupt();
return TRUE;
}

View File

@ -24,10 +24,9 @@
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
CArchDaemonWindows::CArchDaemonWindows() :
m_daemonThread(NULL)
CArchDaemonWindows::CArchDaemonWindows()
{
// do nothing
m_quitMessage = RegisterWindowMessage("SynergyDaemonExit");
}
CArchDaemonWindows::~CArchDaemonWindows()
@ -55,6 +54,17 @@ CArchDaemonWindows::daemonRunning(bool running)
}
}
UINT
CArchDaemonWindows::getDaemonQuitMessage()
{
if (s_daemon != NULL) {
return s_daemon->doGetDaemonQuitMessage();
}
else {
return 0;
}
}
void
CArchDaemonWindows::daemonFailed(int result)
{
@ -437,6 +447,20 @@ CArchDaemonWindows::openUserStartupKey()
return CArchMiscWindows::openKey(HKEY_CURRENT_USER, s_keyNames);
}
bool
CArchDaemonWindows::isRunState(DWORD state)
{
switch (state) {
case SERVICE_START_PENDING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_RUNNING:
return true;
default:
return false;
}
}
int
CArchDaemonWindows::doRunDaemon(RunFunc run)
{
@ -444,115 +468,68 @@ CArchDaemonWindows::doRunDaemon(RunFunc run)
assert(m_serviceMutex != NULL);
assert(run != NULL);
// create message queue for this thread
MSG dummy;
PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE);
int result = 0;
ARCH->lockMutex(m_serviceMutex);
try {
int result;
m_serviceHandlerWaiting = false;
m_serviceRunning = false;
for (;;) {
// mark server as running
setStatus(SERVICE_RUNNING);
// run callback in another thread
m_serviceRunning = true;
m_daemonThread = ARCH->newThread(
&CArchDaemonWindows::runDaemonThreadEntry, run);
ARCH->wait(m_daemonThread, -1.0);
result = reinterpret_cast<int>(
ARCH->getResultOfThread(m_daemonThread));
m_serviceRunning = false;
// notify handler that the server stopped. if handler
// isn't waiting then we stopped unexpectedly and we
// quit.
if (m_serviceHandlerWaiting) {
m_serviceHandlerWaiting = false;
ARCH->broadcastCondVar(m_serviceCondVar);
}
else {
break;
}
// wait until we're told what to do next
while (m_serviceState != SERVICE_RUNNING &&
m_serviceState != SERVICE_STOPPED) {
m_daemonThreadID = GetCurrentThreadId();
while (m_serviceState != SERVICE_STOPPED) {
// wait until we're told to start
while (!isRunState(m_serviceState) &&
m_serviceState != SERVICE_STOP_PENDING) {
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
}
// exit loop if we've been told to stop
if (m_serviceState == SERVICE_STOPPED) {
break;
}
// done with callback thread
ARCH->closeThread(m_daemonThread);
m_daemonThread = NULL;
}
// prevent daemonHandler from changing state
m_serviceState = SERVICE_STOPPED;
// tell service control that the service is stopped.
// FIXME -- hopefully this will ensure that our handler won't
// be called again but i can't find documentation that
// verifies that. if it does it'll crash on the mutex that
// we're about to destroy.
setStatus(m_serviceState);
// clean up
if (m_daemonThread != NULL) {
ARCH->closeThread(m_daemonThread);
m_daemonThread = NULL;
}
// run unless told to stop
if (m_serviceState != SERVICE_STOP_PENDING) {
ARCH->unlockMutex(m_serviceMutex);
return result;
try {
result = run();
}
catch (...) {
// FIXME -- report error
// prevent serviceHandler from changing state
m_serviceState = SERVICE_STOPPED;
// set status
ARCH->lockMutex(m_serviceMutex);
setStatusError(0);
// wake up serviceHandler if it's waiting then wait for it
if (m_serviceHandlerWaiting) {
m_serviceHandlerWaiting = false;
m_serviceState = SERVICE_STOPPED;
setStatus(m_serviceState);
ARCH->broadcastCondVar(m_serviceCondVar);
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
// serviceHandler has exited by now
}
ARCH->unlockMutex(m_serviceMutex);
throw;
}
ARCH->lockMutex(m_serviceMutex);
}
// notify of new state
if (m_serviceState == SERVICE_PAUSE_PENDING) {
m_serviceState = SERVICE_PAUSED;
}
else {
m_serviceState = SERVICE_STOPPED;
}
setStatus(m_serviceState);
ARCH->broadcastCondVar(m_serviceCondVar);
}
ARCH->unlockMutex(m_serviceMutex);
return result;
}
void
CArchDaemonWindows::doDaemonRunning(bool running)
{
ARCH->lockMutex(m_serviceMutex);
if (running) {
m_serviceState = SERVICE_RUNNING;
setStatus(m_serviceState);
ARCH->broadcastCondVar(m_serviceCondVar);
}
ARCH->unlockMutex(m_serviceMutex);
}
else {
ARCH->lockMutex(m_serviceMutex);
}
}
void*
CArchDaemonWindows::runDaemonThread(RunFunc run)
UINT
CArchDaemonWindows::doGetDaemonQuitMessage()
{
return reinterpret_cast<void*>(run());
}
void*
CArchDaemonWindows::runDaemonThreadEntry(void* vrun)
{
assert(s_daemon != NULL);
return s_daemon->runDaemonThread(reinterpret_cast<RunFunc>(vrun));
return m_quitMessage;
}
void
@ -583,6 +560,8 @@ CArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
void
CArchDaemonWindows::setStatusError(DWORD error)
{
assert(s_daemon != NULL);
SERVICE_STATUS status;
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
SERVICE_INTERACTIVE_PROCESS;
@ -607,9 +586,8 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
// create synchronization objects
m_serviceMutex = ARCH->newMutex();
m_serviceCondVar = ARCH->newCondVar();
m_serviceState = SERVICE_RUNNING;
// register our service handler functiom
// register our service handler function
m_statusHandle = RegisterServiceCtrlHandler(argv[0],
&CArchDaemonWindows::serviceHandlerEntry);
if (m_statusHandle == NULL) {
@ -621,7 +599,8 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
}
// tell service control manager that we're starting
setStatus(SERVICE_START_PENDING, 0, 10000);
m_serviceState = SERVICE_START_PENDING;
setStatus(m_serviceState, 0, 10000);
// if no arguments supplied then try getting them from the registry.
// the first argument doesn't count because it's the service name.
@ -726,58 +705,40 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
ARCH->lockMutex(m_serviceMutex);
// ignore request if service is already stopped
if (m_serviceState == SERVICE_STOPPED) {
if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) {
if (s_daemon != NULL) {
setStatus(m_serviceState);
}
ARCH->unlockMutex(m_serviceMutex);
return;
}
switch (ctrl) {
case SERVICE_CONTROL_PAUSE:
// update state
m_serviceState = SERVICE_PAUSE_PENDING;
setStatus(m_serviceState, 0, 5000);
// stop run callback if running and wait for it to finish
if (m_serviceRunning) {
m_serviceHandlerWaiting = true;
ARCH->cancelThread(m_daemonThread);
PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
while (isRunState(m_serviceState)) {
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
}
// update state if service hasn't stopped while we were waiting
if (m_serviceState != SERVICE_STOPPED) {
m_serviceState = SERVICE_PAUSED;
}
ARCH->broadcastCondVar(m_serviceCondVar);
break;
case SERVICE_CONTROL_CONTINUE:
// required status update
setStatus(m_serviceState);
// update state but let main loop send RUNNING notification
m_serviceState = SERVICE_RUNNING;
// FIXME -- maybe should flush quit messages from queue
m_serviceState = SERVICE_CONTINUE_PENDING;
setStatus(m_serviceState, 0, 5000);
ARCH->broadcastCondVar(m_serviceCondVar);
ARCH->unlockMutex(m_serviceMutex);
return;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
// update state
m_serviceState = SERVICE_STOP_PENDING;
setStatus(m_serviceState, 0, 5000);
// stop run callback if running and wait for it to finish
if (m_serviceRunning) {
m_serviceHandlerWaiting = true;
ARCH->cancelThread(m_daemonThread);
PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
ARCH->broadcastCondVar(m_serviceCondVar);
while (isRunState(m_serviceState)) {
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
}
// update state
m_serviceState = SERVICE_STOPPED;
ARCH->broadcastCondVar(m_serviceCondVar);
break;
default:
@ -785,12 +746,10 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
// fall through
case SERVICE_CONTROL_INTERROGATE:
setStatus(m_serviceState);
break;
}
// send update
setStatus(m_serviceState);
ARCH->unlockMutex(m_serviceMutex);
}

View File

@ -42,7 +42,7 @@ public:
(i.e. after initialization) and \c daemonRunning(false) when it leaves
the main loop. The \c runFunc is called in a new thread and when the
daemon must exit the main loop due to some external control the
thread is cancelled on behalf of the client. This function returns
getDaemonQuitMessage() is posted to the thread. This function returns
what \c runFunc returns. \c runFunc should call \c daemonFailed() if
the daemon fails.
*/
@ -63,6 +63,14 @@ public:
*/
static void daemonFailed(int result);
//! Get daemon quit message
/*!
The windows NT daemon tells daemon thread to exit by posting this
message to it. The thread must, of course, have a message queue
for this to work.
*/
static UINT getDaemonQuitMessage();
// IArchDaemon overrides
virtual void installDaemon(const char* name,
const char* description,
@ -81,13 +89,13 @@ private:
int doRunDaemon(RunFunc runFunc);
void doDaemonRunning(bool running);
UINT doGetDaemonQuitMessage();
static void setStatus(DWORD state);
static void setStatus(DWORD state, DWORD step, DWORD waitHint);
static void setStatusError(DWORD error);
void* runDaemonThread(RunFunc);
static void* runDaemonThreadEntry(void*);
static bool isRunState(DWORD state);
void serviceMain(DWORD, LPTSTR*);
static void WINAPI serviceMainEntry(DWORD, LPTSTR*);
@ -113,11 +121,13 @@ private:
bool m_serviceHandlerWaiting;
bool m_serviceRunning;
CArchThread m_daemonThread;
DWORD m_daemonThreadID;
DaemonFunc m_daemonFunc;
int m_daemonResult;
SERVICE_STATUS_HANDLE m_statusHandle;
UINT m_quitMessage;
};
#endif

View File

@ -19,9 +19,12 @@
// CArchMiscWindows
//
CArchMiscWindows::CDialogs* CArchMiscWindows::s_dialogs = NULL;
void
CArchMiscWindows::init()
{
s_dialogs = new CDialogs;
isWindows95Family();
}
@ -64,6 +67,12 @@ CArchMiscWindows::daemonFailed(int result)
CArchDaemonWindows::daemonFailed(result);
}
UINT
CArchMiscWindows::getDaemonQuitMessage()
{
return CArchDaemonWindows::getDaemonQuitMessage();
}
HKEY
CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName)
{
@ -196,3 +205,27 @@ CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name)
}
return value;
}
void
CArchMiscWindows::addDialog(HWND hwnd)
{
s_dialogs->insert(hwnd);
}
void
CArchMiscWindows::removeDialog(HWND hwnd)
{
s_dialogs->erase(hwnd);
}
bool
CArchMiscWindows::processDialog(MSG* msg)
{
for (CDialogs::const_iterator index = s_dialogs->begin();
index != s_dialogs->end(); ++index) {
if (IsDialogMessage(*index, msg)) {
return true;
}
}
return false;
}

View File

@ -19,6 +19,7 @@
#include "common.h"
#include "stdstring.h"
#include "stdset.h"
#include <windows.h>
//! Miscellaneous win32 functions.
@ -53,6 +54,12 @@ public:
*/
static void daemonFailed(int result);
//! Get daemon quit message
/*!
Delegates to CArchDaemonWindows.
*/
static UINT getDaemonQuitMessage();
//! Open and return a registry key, closing the parent key
static HKEY openKey(HKEY parent, const TCHAR* child);
@ -83,6 +90,24 @@ public:
//! Read a DWORD value from the registry
static DWORD readValueInt(HKEY, const TCHAR* name);
//! Add a dialog
static void addDialog(HWND);
//! Remove a dialog
static void removeDialog(HWND);
//! Process dialog message
/*!
Checks if the message is destined for a dialog. If so the message
is passed to the dialog and returns true, otherwise returns false.
*/
static bool processDialog(MSG*);
private:
typedef std::set<HWND> CDialogs;
static CDialogs* s_dialogs;
};
#endif

View File

@ -134,6 +134,18 @@ CArchMultithreadPosix::~CArchMultithreadPosix()
s_instance = NULL;
}
void
CArchMultithreadPosix::unblockThread(CArchThread thread)
{
pthread_kill(thread->m_thread, SIGWAKEUP);
}
CArchMultithreadPosix*
CArchMultithreadPosix::getInstance()
{
return s_instance;
}
CArchCond
CArchMultithreadPosix::newCondVar()
{
@ -517,19 +529,6 @@ CArchMultithreadPosix::wait(CArchThread target, double timeout)
}
}
IArchMultithread::EWaitResult
CArchMultithreadPosix::waitForEvent(CArchThread, double /*timeout*/)
{
// not implemented
return kTimeout;
}
void
CArchMultithreadPosix::unblockThread(CArchThread thread)
{
pthread_kill(thread->m_thread, SIGWAKEUP);
}
bool
CArchMultithreadPosix::isSameThread(CArchThread thread1, CArchThread thread2)
{
@ -575,7 +574,7 @@ CArchMultithreadPosix::interrupt()
lockMutex(m_threadMutex);
if (m_signalFunc != NULL) {
m_signalFunc(m_signalUserData);
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
unblockThread(m_mainThread);
}
else {
ARCH->cancelThread(m_mainThread);

View File

@ -37,6 +37,19 @@ public:
CArchMultithreadPosix();
virtual ~CArchMultithreadPosix();
//! @name manipulators
//@{
void unblockThread(CArchThread thread);
//@}
//! @name accessors
//@{
static CArchMultithreadPosix* getInstance();
//@}
// IArchMultithread overrides
virtual CArchCond newCondVar();
virtual void closeCondVar(CArchCond);
@ -55,8 +68,6 @@ public:
virtual void setPriorityOfThread(CArchThread, int n);
virtual void testCancelThread();
virtual bool wait(CArchThread, double timeout);
virtual EWaitResult waitForEvent(CArchThread, double timeout);
virtual void unblockThread(CArchThread thread);
virtual bool isSameThread(CArchThread, CArchThread);
virtual bool isExitedThread(CArchThread);
virtual void* getResultOfThread(CArchThread);

View File

@ -50,6 +50,7 @@ public:
bool m_cancelling;
HANDLE m_exit;
void* m_result;
void* m_networkData;
};
CArchThreadImpl::CArchThreadImpl() :
@ -59,7 +60,8 @@ CArchThreadImpl::CArchThreadImpl() :
m_func(NULL),
m_userData(NULL),
m_cancelling(false),
m_result(NULL)
m_result(NULL),
m_networkData(NULL)
{
m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
@ -78,7 +80,9 @@ CArchThreadImpl::~CArchThreadImpl()
CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
CArchMultithreadWindows::CArchMultithreadWindows()
CArchMultithreadWindows::CArchMultithreadWindows() :
m_signalFunc(NULL),
m_signalUserData(NULL)
{
assert(s_instance == NULL);
s_instance = this;
@ -88,10 +92,10 @@ CArchMultithreadWindows::CArchMultithreadWindows()
// create thread for calling (main) thread and add it to our
// list. no need to lock the mutex since we're the only thread.
CArchThreadImpl* mainThread = new CArchThreadImpl;
mainThread->m_thread = NULL;
mainThread->m_id = GetCurrentThreadId();
insert(mainThread);
m_mainThread = new CArchThreadImpl;
m_mainThread->m_thread = NULL;
m_mainThread->m_id = GetCurrentThreadId();
insert(m_mainThread);
}
CArchMultithreadWindows::~CArchMultithreadWindows()
@ -108,6 +112,24 @@ CArchMultithreadWindows::~CArchMultithreadWindows()
delete m_threadMutex;
}
void
CArchMultithreadWindows::setNetworkDataForCurrentThread(void* data)
{
lockMutex(m_threadMutex);
CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
thread->m_networkData = data;
unlockMutex(m_threadMutex);
}
void*
CArchMultithreadWindows::getNetworkDataForThread(CArchThread thread)
{
lockMutex(m_threadMutex);
void* data = thread->m_networkData;
unlockMutex(m_threadMutex);
return data;
}
HANDLE
CArchMultithreadWindows::getCancelEventForCurrentThread()
{
@ -183,7 +205,7 @@ CArchMultithreadWindows::waitCondVar(CArchCond cond,
// make a list of the condition variable events and the cancel event
// for the current thread.
HANDLE handles[3];
HANDLE handles[4];
handles[0] = cond->m_events[CArchCondImpl::kSignal];
handles[1] = cond->m_events[CArchCondImpl::kBroadcast];
handles[2] = getCancelEventForCurrentThread();
@ -446,8 +468,8 @@ CArchMultithreadWindows::wait(CArchThread target, double timeout)
t = (DWORD)(1000.0 * timeout);
}
// wait for this thread to be cancelled or for the target thread to
// terminate.
// wait for this thread to be cancelled or woken up or for the
// target thread to terminate.
HANDLE handles[2];
handles[0] = target->m_exit;
handles[1] = self->m_cancel;
@ -478,137 +500,6 @@ CArchMultithreadWindows::wait(CArchThread target, double timeout)
}
}
IArchMultithread::EWaitResult
CArchMultithreadWindows::waitForEvent(CArchThread target, double timeout)
{
// find current thread. ref the target so it can't go away while
// we're watching it.
lockMutex(m_threadMutex);
CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
assert(self != NULL);
if (target != NULL) {
refThread(target);
}
unlockMutex(m_threadMutex);
// see if we've been cancelled before checking if any events
// are pending.
DWORD result = WaitForSingleObject(self->m_cancel, 0);
if (result == WAIT_OBJECT_0) {
if (target != NULL) {
closeThread(target);
}
testCancelThreadImpl(self);
}
// check if messages are available first. if we don't do this then
// MsgWaitForMultipleObjects() will block even if the queue isn't
// empty if the messages in the queue were there before the last
// call to GetMessage()/PeekMessage().
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
return kEvent;
}
// convert timeout
DWORD t;
if (timeout < 0.0) {
t = INFINITE;
}
else {
t = (DWORD)(1000.0 * timeout);
}
// wait for this thread to be cancelled or for the target thread to
// terminate.
DWORD n = (target == NULL || target == self) ? 1 : 2;
HANDLE handles[2];
handles[0] = self->m_cancel;
handles[1] = (n == 2) ? target->m_exit : NULL;
result = MsgWaitForMultipleObjects(n, handles, FALSE, t, QS_ALLINPUT);
// cancel takes priority
if (result != WAIT_OBJECT_0 + 0 &&
WaitForSingleObject(handles[0], 0) == WAIT_OBJECT_0) {
result = WAIT_OBJECT_0 + 0;
}
// release target
if (target != NULL) {
closeThread(target);
}
// handle result
switch (result) {
case WAIT_OBJECT_0 + 0:
// this thread was cancelled. does not return.
testCancelThreadImpl(self);
case WAIT_OBJECT_0 + 1:
// target thread terminated
if (n == 2) {
return kExit;
}
// fall through
case WAIT_OBJECT_0 + 2:
// message is available
return kEvent;
default:
// timeout or error
return kTimeout;
}
}
/*
bool
CArchMultithreadWindows::waitForEvent(double timeout)
{
// check if messages are available first. if we don't do this then
// MsgWaitForMultipleObjects() will block even if the queue isn't
// empty if the messages in the queue were there before the last
// call to GetMessage()/PeekMessage().
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
return true;
}
// find current thread
lockMutex(m_threadMutex);
CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
unlockMutex(m_threadMutex);
assert(self != NULL);
// convert timeout
DWORD t;
if (timeout < 0.0) {
t = INFINITE;
}
else {
t = (DWORD)(1000.0 * timeout);
}
// wait for this thread to be cancelled or for a message
HANDLE handles[1];
handles[0] = self->m_cancel;
DWORD result = MsgWaitForMultipleObjects(1, handles, FALSE, t, QS_ALLINPUT);
// handle result
switch (result) {
case WAIT_OBJECT_0 + 1:
// message is available
return true;
case WAIT_OBJECT_0 + 0:
// this thread was cancelled. does not return.
testCancelThreadImpl(self);
default:
// timeout or error
return false;
}
}
*/
bool
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
{
@ -637,6 +528,29 @@ CArchMultithreadWindows::getIDOfThread(CArchThread thread)
return static_cast<ThreadID>(thread->m_id);
}
void
CArchMultithreadWindows::setInterruptHandler(InterruptFunc func, void* userData)
{
lockMutex(m_threadMutex);
m_signalFunc = func;
m_signalUserData = userData;
unlockMutex(m_threadMutex);
}
void
CArchMultithreadWindows::interrupt()
{
lockMutex(m_threadMutex);
if (m_signalFunc != NULL) {
m_signalFunc(m_signalUserData);
ARCH->unblockPollSocket(m_mainThread);
}
else {
ARCH->cancelThread(m_mainThread);
}
unlockMutex(m_threadMutex);
}
CArchThreadImpl*
CArchMultithreadWindows::find(DWORD id)
{

View File

@ -43,12 +43,20 @@ public:
CArchMultithreadWindows();
virtual ~CArchMultithreadWindows();
//
// manipulators
//
void setNetworkDataForCurrentThread(void*);
//
// accessors
//
HANDLE getCancelEventForCurrentThread();
void* getNetworkDataForThread(CArchThread);
static CArchMultithreadWindows* getInstance();
// IArchMultithread overrides
@ -69,11 +77,12 @@ public:
virtual void setPriorityOfThread(CArchThread, int n);
virtual void testCancelThread();
virtual bool wait(CArchThread, double timeout);
virtual EWaitResult waitForEvent(CArchThread, double timeout);
virtual bool isSameThread(CArchThread, CArchThread);
virtual bool isExitedThread(CArchThread);
virtual void* getResultOfThread(CArchThread);
virtual ThreadID getIDOfThread(CArchThread);
virtual void setInterruptHandler(InterruptFunc, void*);
virtual void interrupt();
private:
CArchThreadImpl* find(DWORD id);
@ -96,6 +105,10 @@ private:
CArchMutex m_threadMutex;
CThreadList m_threadList;
CArchThread m_mainThread;
InterruptFunc m_signalFunc;
void* m_signalUserData;
};
#endif

View File

@ -424,6 +424,12 @@ CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
#endif
void
CArchNetworkBSD::unblockPollSocket(CArchThread thread)
{
CArchMultithreadPosix::getInstance()->unblockThread(thread);
}
size_t
CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
{
@ -435,8 +441,8 @@ CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
if (n == -1) {
if (errno == EINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
n = 0;
break;
}
else if (errno == EAGAIN) {
n = 0;
@ -460,8 +466,8 @@ CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
if (n == -1) {
if (errno == EINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
n = 0;
break;
}
else if (errno == EAGAIN) {
// no buffer space

View File

@ -60,6 +60,7 @@ public:
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
virtual int pollSocket(CPollEntry[], int num, double timeout);
virtual void unblockPollSocket(CArchThread thread);
virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
virtual size_t writeSocket(CArchSocket s,
const void* buf, size_t len);

View File

@ -15,7 +15,9 @@
#include "CArchNetworkWinsock.h"
#include "CArch.h"
#include "IArchMultithread.h"
#include "XArchWindows.h"
#include <malloc.h>
static const int s_family[] = {
PF_UNSPEC,
@ -49,6 +51,13 @@ static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR *
static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name);
static int (PASCAL FAR *WSACleanup_winsock)(void);
static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset);
static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void);
static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT);
static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT);
static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT);
static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long);
static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL);
static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS);
#undef FD_ISSET
#define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
@ -68,13 +77,23 @@ netGetProcAddress(HMODULE module, LPCSTR name)
return func;
}
CArchNetAddressImpl*
CArchNetAddressImpl::alloc(size_t size)
{
size_t totalSize = size + ADDR_HDR_SIZE;
CArchNetAddressImpl* addr = (CArchNetAddressImpl*)malloc(totalSize);
addr->m_len = size;
return addr;
}
//
// CArchNetworkWinsock
//
CArchNetworkWinsock::CArchNetworkWinsock()
{
static const char* s_library[] = { "ws2_32.dll", "wsock32.dll" };
static const char* s_library[] = { "ws2_32.dll" };
assert(WSACleanup_winsock == NULL);
assert(s_networkModule == NULL);
@ -110,14 +129,16 @@ CArchNetworkWinsock::~CArchNetworkWinsock()
void
CArchNetworkWinsock::init(HMODULE module)
{
assert(module != NULL);
if (module == NULL) {
throw XArchNetworkSupport("");
}
// get startup function address
int (PASCAL FAR *startup)(WORD, LPWSADATA);
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
// startup network library
WORD version = MAKEWORD(1 /*major*/, 1 /*minor*/);
WORD version = MAKEWORD(2 /*major*/, 0 /*minor*/);
WSADATA data;
int err = startup(version, &data);
if (data.wVersion != version) {
@ -152,6 +173,13 @@ CArchNetworkWinsock::init(HMODULE module)
setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *));
setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void));
setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT));
setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long));
setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL));
setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
s_networkModule = module;
}
@ -171,6 +199,8 @@ CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
socket->m_socket = fd;
socket->m_connected = false;
socket->m_refCount = 1;
socket->m_event = WSACreateEvent_winsock();
socket->m_pollWrite = false;
return socket;
}
@ -202,7 +232,7 @@ CArchNetworkWinsock::closeSocket(CArchSocket s)
if (close_winsock(s->m_socket) == SOCKET_ERROR) {
// close failed
int err = getsockerror_winsock();
if (err == EINTR) {
if (err == WSAEINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
@ -215,6 +245,7 @@ CArchNetworkWinsock::closeSocket(CArchSocket s)
throwError(err);
}
} while (false);
WSACloseEvent_winsock(s->m_event);
delete s;
}
}
@ -270,35 +301,24 @@ CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
{
assert(s != NULL);
// if user passed NULL in addr then use scratch space
CArchNetAddress dummy;
if (addr == NULL) {
addr = &dummy;
}
// create new socket and address
// create new socket and temporary address
CArchSocketImpl* socket = new CArchSocketImpl;
*addr = new CArchNetAddressImpl;
CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr));
// accept on socket
SOCKET fd;
do {
fd = accept_winsock(s->m_socket, &(*addr)->m_addr, &(*addr)->m_len);
fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len);
if (fd == INVALID_SOCKET) {
int err = getsockerror_winsock();
if (err == EINTR) {
delete socket;
free(tmp);
*addr = NULL;
if (err == WSAEINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
return NULL;
}
if (err == WSAECONNABORTED) {
// connection was aborted; try again
ARCH->testCancelThread();
continue;
}
delete socket;
delete *addr;
*addr = NULL;
throwError(err);
}
} while (false);
@ -307,12 +327,15 @@ CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
socket->m_socket = fd;
socket->m_connected = true;
socket->m_refCount = 1;
socket->m_event = WSACreateEvent_winsock();
socket->m_pollWrite = true;
// discard address if not requested
if (addr == &dummy) {
ARCH->closeAddr(dummy);
// copy address if requested
if (addr != NULL) {
*addr = ARCH->copyAddr(tmp);
}
free(tmp);
return socket;
}
@ -325,7 +348,7 @@ CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
do {
if (connect_winsock(s->m_socket, &addr->m_addr,
addr->m_len) == SOCKET_ERROR) {
if (getsockerror_winsock() == EINTR) {
if (getsockerror_winsock() == WSAEINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
@ -354,19 +377,13 @@ CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
int
CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
{
int i, n;
int i;
DWORD n;
do {
// prepare sets for select
n = 0;
fd_set readSet, writeSet, errSet;
fd_set* readSetP = NULL;
fd_set* writeSetP = NULL;
fd_set* errSetP = NULL;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_ZERO(&errSet);
for (i = 0; i < num; ++i) {
// prepare sockets and wait list
bool canWrite = false;
WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
for (i = 0, n = 0; i < num; ++i) {
// reset return flags
pe[i].m_revents = 0;
@ -376,73 +393,146 @@ CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
continue;
}
if (pe[i].m_events & kPOLLIN) {
FD_SET(pe[i].m_socket->m_socket, &readSet);
readSetP = &readSet;
n = 1;
// select desired events
long socketEvents = 0;
if ((pe[i].m_events & kPOLLIN) != 0) {
socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
}
if (pe[i].m_events & kPOLLOUT) {
FD_SET(pe[i].m_socket->m_socket, &writeSet);
writeSetP = &writeSet;
n = 1;
}
if (true) {
FD_SET(pe[i].m_socket->m_socket, &errSet);
errSetP = &errSet;
n = 1;
if ((pe[i].m_events & kPOLLOUT) != 0) {
socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
// if m_pollWrite is false then we assume the socket is
// writable. winsock doesn't signal writability except
// when the state changes from unwritable.
if (!pe[i].m_socket->m_pollWrite) {
canWrite = true;
pe[i].m_revents |= kPOLLOUT;
}
}
// if there are no sockets then don't block forever
if (n == 0 && timeout < 0.0) {
timeout = 0.0;
// if no events then ignore socket
if (socketEvents == 0) {
continue;
}
// prepare timeout for select
struct timeval timeout2;
struct timeval* timeout2P;
if (timeout < 0) {
timeout2P = NULL;
}
else {
timeout2P = &timeout2;
timeout2.tv_sec = static_cast<int>(timeout);
timeout2.tv_usec = static_cast<int>(1.0e+6 *
(timeout - timeout2.tv_sec));
// select socket for desired events
WSAEventSelect_winsock(pe[i].m_socket->m_socket,
pe[i].m_socket->m_event, socketEvents);
// add socket event to wait list
events[n++] = pe[i].m_socket->m_event;
}
// do the select
n = select_winsock(0, readSetP, writeSetP, errSetP, timeout2P);
// if no sockets then return immediately
if (n == 0) {
return 0;
}
// add the unblock event
CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
CArchThread thread = mt->newCurrentThread();
WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
if (unblockEvent == NULL) {
unblockEvent = new WSAEVENT;
*unblockEvent = WSACreateEvent_winsock();
mt->setNetworkDataForCurrentThread(unblockEvent);
}
events[n++] = *unblockEvent;
// prepare timeout
DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout);
if (canWrite) {
// if we know we can write then don't block
t = 0;
}
// wait
DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE);
// reset the unblock event
WSAResetEvent_winsock(*unblockEvent);
// handle results
if (n == SOCKET_ERROR) {
if (getsockerror_winsock() == EINTR) {
if (result == WSA_WAIT_FAILED) {
if (getsockerror_winsock() == WSAEINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
return 0;
}
throwError(getsockerror_winsock());
}
n = 0;
for (i = 0; i < num; ++i) {
if (pe[i].m_socket != NULL) {
if (FD_ISSET(pe[i].m_socket->m_socket, &readSet)) {
if (result == WSA_WAIT_TIMEOUT && !canWrite) {
return 0;
}
if (result == WSA_WAIT_EVENT_0 + n - 1) {
// the unblock event was signalled
return 0;
}
for (i = 0, n = 0; i < num; ++i) {
// skip events we didn't check
if (pe[i].m_socket == NULL ||
(pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
continue;
}
// get events
WSANETWORKEVENTS info;
if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
continue;
}
if ((info.lNetworkEvents & FD_READ) != 0) {
pe[i].m_revents |= kPOLLIN;
}
if (FD_ISSET(pe[i].m_socket->m_socket, &writeSet)) {
if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
pe[i].m_revents |= kPOLLIN;
}
if ((info.lNetworkEvents & FD_WRITE) != 0) {
pe[i].m_revents |= kPOLLOUT;
// socket is now writable so don't bothing polling for
// writable until it becomes unwritable.
pe[i].m_socket->m_pollWrite = false;
}
if ((info.lNetworkEvents & FD_CONNECT) != 0) {
if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
pe[i].m_revents |= kPOLLERR;
}
else {
pe[i].m_revents |= kPOLLOUT;
pe[i].m_socket->m_pollWrite = false;
}
}
if ((info.lNetworkEvents & FD_CLOSE) != 0) {
if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
pe[i].m_revents |= kPOLLERR;
}
else {
if ((pe[i].m_events & kPOLLIN) != 0) {
pe[i].m_revents |= kPOLLIN;
}
if ((pe[i].m_events & kPOLLOUT) != 0) {
pe[i].m_revents |= kPOLLOUT;
}
if (FD_ISSET(pe[i].m_socket->m_socket, &errSet)) {
pe[i].m_revents |= kPOLLERR;
}
}
if (pe[i].m_revents != 0) {
++n;
}
}
} while (false);
return n;
return (int)n;
}
void
CArchNetworkWinsock::unblockPollSocket(CArchThread thread)
{
// set the unblock event
CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
if (unblockEvent != NULL) {
WSASetEvent_winsock(*unblockEvent);
}
}
size_t
@ -454,10 +544,14 @@ CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
do {
n = recv_winsock(s->m_socket, buf, len, 0);
if (n == SOCKET_ERROR) {
if (getsockerror_winsock() == EINTR) {
if (getsockerror_winsock() == WSAEINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
n = 0;
break;
}
else if (getsockerror_winsock() == WSAEWOULDBLOCK) {
n = 0;
break;
}
throwError(getsockerror_winsock());
}
@ -475,10 +569,15 @@ CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
do {
n = send_winsock(s->m_socket, buf, len, 0);
if (n == SOCKET_ERROR) {
if (getsockerror_winsock() == EINTR) {
if (getsockerror_winsock() == WSAEINTR) {
// interrupted system call
ARCH->testCancelThread();
continue;
n = 0;
break;
}
else if (getsockerror_winsock() == WSAEWOULDBLOCK) {
s->m_pollWrite = true;
n = 0;
break;
}
throwError(getsockerror_winsock());
}
@ -559,26 +658,20 @@ CArchNetworkWinsock::getHostName()
CArchNetAddress
CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
{
// allocate address
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
// fill it in
CArchNetAddressImpl* addr = NULL;
switch (family) {
case kINET: {
struct sockaddr_in* ipAddr =
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
ipAddr->sin_family = AF_INET;
ipAddr->sin_port = 0;
ipAddr->sin_addr.s_addr = INADDR_ANY;
addr->m_len = sizeof(struct sockaddr_in);
break;
}
default:
delete addr;
assert(0 && "invalid family");
}
return addr;
}
@ -587,26 +680,27 @@ CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
{
assert(addr != NULL);
// allocate and copy address
return new CArchNetAddressImpl(*addr);
CArchNetAddressImpl* copy = CArchNetAddressImpl::alloc(addr->m_len);
memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
return copy;
}
CArchNetAddress
CArchNetworkWinsock::nameToAddr(const std::string& name)
{
// allocate address
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
CArchNetAddressImpl* addr = NULL;
// try to convert assuming an IPv4 dot notation address
struct sockaddr_in inaddr;
memset(&inaddr, 0, sizeof(inaddr));
inaddr.sin_family = AF_INET;
inaddr.sin_port = 0;
inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str());
if (inaddr.sin_addr.s_addr != INADDR_NONE) {
// it's a dot notation address
addr->m_len = sizeof(struct sockaddr_in);
inaddr.sin_family = AF_INET;
inaddr.sin_port = 0;
memcpy(&addr->m_addr, &inaddr, addr->m_len);
addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
}
else {
@ -616,16 +710,8 @@ CArchNetworkWinsock::nameToAddr(const std::string& name)
delete addr;
throwNameError(getsockerror_winsock());
}
// copy over address (only IPv4 currently supported)
if (info->h_addrtype == AF_INET) {
addr->m_len = sizeof(struct sockaddr_in);
inaddr.sin_family = info->h_addrtype;
inaddr.sin_port = 0;
memcpy(&inaddr.sin_addr, info->h_addr_list[0],
sizeof(inaddr.sin_addr));
memcpy(&addr->m_addr, &inaddr, addr->m_len);
}
addr = CArchNetAddressImpl::alloc(info->h_length);
memcpy(TYPED_ADDR(void, addr), info->h_addr_list[0], info->h_length);
}
return addr;
@ -636,7 +722,7 @@ CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
{
assert(addr != NULL);
delete addr;
free(addr);
}
std::string
@ -734,8 +820,8 @@ CArchNetworkWinsock::isAnyAddr(CArchNetAddress addr)
case kINET: {
struct sockaddr_in* ipAddr =
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
addr->m_len == sizeof(struct sockaddr_in));
return (addr->m_len == sizeof(struct sockaddr_in) &&
ipAddr->sin_addr.s_addr == INADDR_ANY);
}
default:
@ -744,6 +830,13 @@ CArchNetworkWinsock::isAnyAddr(CArchNetAddress addr)
}
}
bool
CArchNetworkWinsock::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
{
return (a == b || (a->m_len == b->m_len &&
memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0));
}
void
CArchNetworkWinsock::throwError(int err)
{
@ -786,8 +879,10 @@ CArchNetworkWinsock::throwError(int err)
case WSAENOTCONN:
throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
case WSAENETRESET:
case WSAEDISCON:
throw XArchNetworkShutdown(new XArchEvalWinsock(err));
case WSAENETRESET:
case WSAECONNABORTED:
case WSAECONNRESET:
throw XArchNetworkDisconnected(new XArchEvalWinsock(err));

View File

@ -33,16 +33,20 @@ public:
SOCKET m_socket;
bool m_connected;
int m_refCount;
WSAEVENT m_event;
bool m_pollWrite;
};
class CArchNetAddressImpl {
public:
CArchNetAddressImpl() : m_len(sizeof(m_addr)) { }
static CArchNetAddressImpl* alloc(size_t);
public:
struct sockaddr m_addr;
int m_len;
struct sockaddr m_addr;
};
#define ADDR_HDR_SIZE offsetof(CArchNetAddressImpl, m_addr)
#define TYPED_ADDR(type_, addr_) (reinterpret_cast<type_*>(&addr_->m_addr))
//! Win32 implementation of IArchNetwork
class CArchNetworkWinsock : public IArchNetwork {
@ -61,6 +65,7 @@ public:
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
virtual int pollSocket(CPollEntry[], int num, double timeout);
virtual void unblockPollSocket(CArchThread thread);
virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
virtual size_t writeSocket(CArchSocket s,
const void* buf, size_t len);
@ -78,6 +83,7 @@ public:
virtual void setAddrPort(CArchNetAddress, int port);
virtual int getAddrPort(CArchNetAddress);
virtual bool isAnyAddr(CArchNetAddress);
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
private:
void init(HMODULE);

View File

@ -41,71 +41,67 @@ CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) :
// save app instance
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
// we need a mutex
m_mutex = ARCH->newMutex();
// register the task bar restart message
m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
// and a condition variable which uses the above mutex
m_ready = false;
m_condVar = ARCH->newCondVar();
// register a window class
WNDCLASSEX classInfo;
classInfo.cbSize = sizeof(classInfo);
classInfo.style = CS_NOCLOSE;
classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
classInfo.cbClsExtra = 0;
classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
classInfo.hInstance = s_appInstance;
classInfo.hIcon = NULL;
classInfo.hCursor = NULL;
classInfo.hbrBackground = NULL;
classInfo.lpszMenuName = NULL;
classInfo.lpszClassName = TEXT("SynergyTaskBar");
classInfo.hIconSm = NULL;
m_windowClass = RegisterClassEx(&classInfo);
// we're going to want to get a result from the thread we're
// about to create to know if it initialized successfully.
// so we lock the condition variable.
ARCH->lockMutex(m_mutex);
// open a window and run an event loop in a separate thread.
// this has to happen in a separate thread because if we
// create a window on the current desktop with the current
// thread then the current thread won't be able to switch
// desktops if it needs to.
m_thread = ARCH->newThread(&CArchTaskBarWindows::threadEntry, this);
// wait for child thread
while (!m_ready) {
ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
}
// ready
ARCH->unlockMutex(m_mutex);
// create window
m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
reinterpret_cast<LPCTSTR>(m_windowClass),
TEXT("Synergy Task Bar"),
WS_POPUP,
0, 0, 1, 1,
NULL,
NULL,
s_appInstance,
reinterpret_cast<void*>(this));
}
CArchTaskBarWindows::~CArchTaskBarWindows()
{
if (m_thread != NULL) {
ARCH->cancelThread(m_thread);
ARCH->wait(m_thread, -1.0);
ARCH->closeThread(m_thread);
if (m_hwnd != NULL) {
removeAllIcons();
DestroyWindow(m_hwnd);
}
ARCH->closeCondVar(m_condVar);
ARCH->closeMutex(m_mutex);
UnregisterClass((LPCTSTR)m_windowClass, s_appInstance);
s_instance = NULL;
}
void
CArchTaskBarWindows::addDialog(HWND hwnd)
{
// add dialog to added dialogs list
ARCH->lockMutex(s_instance->m_mutex);
s_instance->m_addedDialogs.insert(std::make_pair(hwnd, true));
ARCH->unlockMutex(s_instance->m_mutex);
CArchMiscWindows::addDialog(hwnd);
}
void
CArchTaskBarWindows::removeDialog(HWND hwnd)
{
// mark dialog as removed
ARCH->lockMutex(s_instance->m_mutex);
CDialogs::iterator index = s_instance->m_dialogs.find(hwnd);
if (index != s_instance->m_dialogs.end()) {
index->second = false;
}
s_instance->m_addedDialogs.erase(hwnd);
ARCH->unlockMutex(s_instance->m_mutex);
CArchMiscWindows::removeDialog(hwnd);
}
void
CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
{
if (m_hwnd == NULL) {
return;
}
// ignore bogus receiver
if (receiver == NULL) {
return;
@ -180,53 +176,43 @@ CArchTaskBarWindows::recycleID(UINT id)
void
CArchTaskBarWindows::addIcon(UINT id)
{
ARCH->lockMutex(m_mutex);
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
if (index != m_idTable.end()) {
modifyIconNoLock(index->second, NIM_ADD);
}
ARCH->unlockMutex(m_mutex);
}
void
CArchTaskBarWindows::removeIcon(UINT id)
{
ARCH->lockMutex(m_mutex);
removeIconNoLock(id);
ARCH->unlockMutex(m_mutex);
}
void
CArchTaskBarWindows::updateIcon(UINT id)
{
ARCH->lockMutex(m_mutex);
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
if (index != m_idTable.end()) {
modifyIconNoLock(index->second, NIM_MODIFY);
}
ARCH->unlockMutex(m_mutex);
}
void
CArchTaskBarWindows::addAllIcons()
{
ARCH->lockMutex(m_mutex);
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
index != m_receivers.end(); ++index) {
modifyIconNoLock(index, NIM_ADD);
}
ARCH->unlockMutex(m_mutex);
}
void
CArchTaskBarWindows::removeAllIcons()
{
ARCH->lockMutex(m_mutex);
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
index != m_receivers.end(); ++index) {
removeIconNoLock(index->second.m_id);
}
ARCH->unlockMutex(m_mutex);
}
void
@ -319,49 +305,6 @@ CArchTaskBarWindows::handleIconMessage(
}
}
bool
CArchTaskBarWindows::processDialogs(MSG* msg)
{
// only one thread can be in this method on any particular object
// at any given time. that's not a problem since only our event
// loop calls this method and there's just one of those.
ARCH->lockMutex(m_mutex);
// remove removed dialogs
m_dialogs.erase(false);
// merge added dialogs into the dialog list
for (CDialogs::const_iterator index = m_addedDialogs.begin();
index != m_addedDialogs.end(); ++index) {
m_dialogs.insert(std::make_pair(index->first, index->second));
}
m_addedDialogs.clear();
ARCH->unlockMutex(m_mutex);
// check message against all dialogs until one handles it.
// note that we don't hold a lock while checking because
// the message is processed and may make calls to this
// object. that's okay because addDialog() and
// removeDialog() don't change the map itself (just the
// values of some elements).
ARCH->lockMutex(m_mutex);
for (CDialogs::const_iterator index = m_dialogs.begin();
index != m_dialogs.end(); ++index) {
if (index->second) {
ARCH->unlockMutex(m_mutex);
if (IsDialogMessage(index->first, msg)) {
return true;
}
ARCH->lockMutex(m_mutex);
}
}
ARCH->unlockMutex(m_mutex);
return false;
}
LRESULT
CArchTaskBarWindows::wndProc(HWND hwnd,
UINT msg, WPARAM wParam, LPARAM lParam)
@ -432,87 +375,3 @@ CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
void
CArchTaskBarWindows::threadMainLoop()
{
// register the task bar restart message
m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
// register a window class
WNDCLASSEX classInfo;
classInfo.cbSize = sizeof(classInfo);
classInfo.style = CS_NOCLOSE;
classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
classInfo.cbClsExtra = 0;
classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
classInfo.hInstance = s_appInstance;
classInfo.hIcon = NULL;
classInfo.hCursor = NULL;
classInfo.hbrBackground = NULL;
classInfo.lpszMenuName = NULL;
classInfo.lpszClassName = TEXT("SynergyTaskBar");
classInfo.hIconSm = NULL;
ATOM windowClass = RegisterClassEx(&classInfo);
// create window
m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
reinterpret_cast<LPCTSTR>(windowClass),
TEXT("Synergy Task Bar"),
WS_POPUP,
0, 0, 1, 1,
NULL,
NULL,
s_appInstance,
reinterpret_cast<void*>(this));
// signal ready
ARCH->lockMutex(m_mutex);
m_ready = true;
ARCH->broadcastCondVar(m_condVar);
ARCH->unlockMutex(m_mutex);
// handle failure
if (m_hwnd == NULL) {
UnregisterClass((LPCTSTR)windowClass, s_appInstance);
return;
}
try {
// main loop
MSG msg;
for (;;) {
// wait for message
if (ARCH->waitForEvent(NULL, -1.0) != IArchMultithread::kEvent) {
continue;
}
// peek for message and remove it. we don't GetMessage()
// because we should never block here, only in waitForEvent().
if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
continue;
}
// check message against dialogs
if (!processDialogs(&msg)) {
// process message
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
catch (XThread&) {
// clean up
removeAllIcons();
DestroyWindow(m_hwnd);
UnregisterClass((LPCTSTR)windowClass, s_appInstance);
throw;
}
}
void*
CArchTaskBarWindows::threadEntry(void* self)
{
reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
return NULL;
}

View File

@ -18,7 +18,6 @@
#define WIN32_LEAN_AND_MEAN
#include "IArchTaskBar.h"
#include "IArchMultithread.h"
#include "stdmap.h"
#include "stdvector.h"
#include <windows.h>
@ -78,21 +77,13 @@ private:
LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK
staticWndProc(HWND, UINT, WPARAM, LPARAM);
void threadMainLoop();
static void* threadEntry(void*);
private:
static CArchTaskBarWindows* s_instance;
static HINSTANCE s_appInstance;
// multithread data
CArchMutex m_mutex;
CArchCond m_condVar;
bool m_ready;
int m_result;
CArchThread m_thread;
// child thread data
ATOM m_windowClass;
HWND m_hwnd;
UINT m_taskBarRestart;

View File

@ -67,13 +67,6 @@ synergy. Each architecture must implement this interface.
*/
class IArchMultithread : public IInterface {
public:
//! Result of waitForEvent()
enum EWaitResult {
kEvent, //!< An event is pending
kExit, //!< Thread exited
kTimeout //!< Wait timed out
};
//! Type of thread entry point
typedef void* (*ThreadFunc)(void*);
//! Type of thread identifier
@ -213,30 +206,6 @@ public:
*/
virtual bool wait(CArchThread thread, double timeout) = 0;
//! Wait for a user event
/*!
Waits for up to \c timeout seconds for a pending user event or
\c thread to exit (normally or by cancellation). Waits forever
if \c timeout < 0. Returns kEvent if an event occurred, kExit
if \c thread exited, or kTimeout if the timeout expired. If
\c thread is NULL then it doesn't wait for any thread to exit
and it will not return kExit.
This method is not required by all platforms.
(Cancellation point)
*/
virtual EWaitResult waitForEvent(CArchThread thread, double timeout) = 0;
//! Unblock thread in system call
/*!
Cause a thread that's in a blocking system call to return. This
call may return before the thread is unblocked. If the thread is
not in a blocking system call, this call has no effect. This does
not cause a lockMutex() or waitCondVar() to return prematurely.
*/
virtual void unblockThread(CArchThread thread) = 0;
//! Compare threads
/*!
Returns true iff two thread objects refer to the same thread.

View File

@ -18,6 +18,9 @@
#include "IInterface.h"
#include "stdstring.h"
class CArchThreadImpl;
typedef CArchThreadImpl* CArchThread;
/*!
\class CArchSocketImpl
\brief Internal socket data.
@ -179,12 +182,21 @@ public:
the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL
are set in \c m_revents as appropriate. If a socket indicates
\c kPOLLERR then \c throwErrorOnSocket() can be used to determine
the type of error.
the type of error. Returns 0 immediately regardless of the \c timeout
if no valid sockets are selected for testing.
(Cancellation point)
*/
virtual int pollSocket(CPollEntry[], int num, double timeout) = 0;
//! Unblock thread in pollSocket()
/*!
Cause a thread that's in a pollSocket() call to return. This
call may return before the thread is unblocked. If the thread is
not in a pollSocket() call this call has no effect.
*/
virtual void unblockPollSocket(CArchThread thread) = 0;
//! Read data from socket
/*!
Read up to \c len bytes from socket \c s in \c buf and return the

View File

@ -119,10 +119,6 @@ SOURCE=.\CArchFileWindows.h
# End Source File
# Begin Source File
SOURCE=.\CArchImpl.h
# End Source File
# Begin Source File
SOURCE=.\CArchLogWindows.h
# End Source File
# Begin Source File

View File

@ -169,6 +169,10 @@ retry:
event = removeEvent(dataID);
return true;
}
default:
assert(0 && "invalid event type");
return false;
}
}
@ -498,7 +502,7 @@ CEventQueue::CTimer::reset()
m_time = m_timeout;
}
CEventQueue::CTimer::CTimer&
CEventQueue::CTimer&
CEventQueue::CTimer::operator-=(double dt)
{
m_time -= dt;

View File

@ -26,7 +26,11 @@ it sorts by std::greater, it has a forward iterator through the elements
(which can appear in any order), and its contents can be swapped.
*/
template <class T, class Container = std::vector<T>,
#if WINDOWS_LIKE
class Compare = std::greater<Container::value_type> >
#else
class Compare = std::greater<typename Container::value_type> >
#endif
class CPriorityQueue {
public:
typedef typename Container::value_type value_type;

View File

@ -53,7 +53,7 @@ CSimpleEventQueueBuffer::waitForEvent(double timeout)
}
IEventQueueBuffer::Type
CSimpleEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
CSimpleEventQueueBuffer::getEvent(CEvent&, UInt32& dataID)
{
CArchMutexLock lock(m_queueMutex);
if (!m_queueReady) {

View File

@ -39,7 +39,8 @@ CServerProxy::CServerProxy(CClient* client, IStream* stream) :
m_seqNum(0),
m_compressMouse(false),
m_ignoreMouse(false),
m_heartRate(0.0)
m_heartRate(0.0),
m_parser(&CServerProxy::parseHandshakeMessage)
{
assert(m_client != NULL);
assert(m_stream != NULL);
@ -52,7 +53,7 @@ CServerProxy::CServerProxy(CClient* client, IStream* stream) :
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget(),
new TMethodEventJob<CServerProxy>(this,
&CServerProxy::handleMessage));
&CServerProxy::handleData));
// send heartbeat
installHeartBeat(kHeartRate);
@ -61,6 +62,8 @@ CServerProxy::CServerProxy(CClient* client, IStream* stream) :
CServerProxy::~CServerProxy()
{
installHeartBeat(-1.0);
EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
m_stream->getEventTarget());
}
CEvent::Type
@ -87,24 +90,107 @@ CServerProxy::installHeartBeat(double heartRate)
}
void
CServerProxy::handleMessage(const CEvent&, void*)
CServerProxy::handleData(const CEvent&, void*)
{
while (m_stream->isReady()) {
// read next code
// handle messages until there are no more. first read message code.
UInt8 code[4];
UInt32 n = m_stream->read(code, sizeof(code));
if (n == 0) {
break;
}
UInt32 n = m_stream->read(code, 4);
while (n != 0) {
// verify we got an entire code
if (n != 4) {
// client sent an incomplete message
LOG((CLOG_ERR "incomplete message from server"));
LOG((CLOG_ERR "incomplete message from server: %d bytes", n));
m_client->disconnect("incomplete message from server");
return;
}
// parse message
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
switch ((this->*m_parser)(code)) {
case kOkay:
break;
case kUnknown:
LOG((CLOG_ERR "invalid message from server"));
m_client->disconnect("invalid message from server");
return;
case kDisconnect:
return;
}
// next message
n = m_stream->read(code, 4);
}
flushCompressedMouse();
}
CServerProxy::EResult
CServerProxy::parseHandshakeMessage(const UInt8* code)
{
if (memcmp(code, kMsgQInfo, 4) == 0) {
queryInfo();
}
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
infoAcknowledgment();
}
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
resetOptions();
// handshake is complete
m_parser = &CServerProxy::parseMessage;
EVENTQUEUE->addEvent(CEvent(getHandshakeCompleteEvent(), this));
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// accept and discard no-op
}
else if (memcmp(code, kMsgCClose, 4) == 0) {
// server wants us to hangup
LOG((CLOG_DEBUG1 "recv close"));
m_client->disconnect(NULL);
return kDisconnect;
}
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
SInt32 major, minor;
CProtocolUtil::readf(m_stream,
kMsgEIncompatible + 4, &major, &minor);
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
m_client->disconnect("server has incompatible version");
return kDisconnect;
}
else if (memcmp(code, kMsgEBusy, 4) == 0) {
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
m_client->disconnect("server already has a connected client with our name");
return kDisconnect;
}
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
m_client->disconnect("server refused client with our name");
return kDisconnect;
}
else if (memcmp(code, kMsgEBad, 4) == 0) {
LOG((CLOG_ERR "server disconnected due to a protocol error"));
m_client->disconnect("server reported a protocol error");
return kDisconnect;
}
else {
return kUnknown;
}
return kOkay;
}
CServerProxy::EResult
CServerProxy::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
mouseMove();
}
@ -177,44 +263,18 @@ CServerProxy::handleMessage(const CEvent&, void*)
// server wants us to hangup
LOG((CLOG_DEBUG1 "recv close"));
m_client->disconnect(NULL);
break;
return kDisconnect;
}
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
SInt32 major, minor;
CProtocolUtil::readf(m_stream,
kMsgEIncompatible + 4, &major, &minor);
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
m_client->disconnect("server has incompatible version");
return;
}
else if (memcmp(code, kMsgEBusy, 4) == 0) {
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
m_client->disconnect("server already has a connected client with our name");
return;
}
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
m_client->disconnect("server refused client with our name");
return;
}
else if (memcmp(code, kMsgEBad, 4) == 0) {
LOG((CLOG_ERR "server disconnected due to a protocol error"));
m_client->disconnect("server reported a protocol error");
return;
return kDisconnect;
}
else {
return kUnknown;
}
else {
// unknown message
LOG((CLOG_ERR "unknown message: %d %d %d %d [%c%c%c%c]", code[0], code[1], code[2], code[3], code[0], code[1], code[2], code[3]));
m_client->disconnect("unknown message from server");
return;
}
}
flushCompressedMouse();
return kOkay;
}
void

View File

@ -42,9 +42,9 @@ public:
//! @name manipulators
//@{
virtual void onInfoChanged();
virtual bool onGrabClipboard(ClipboardID);
virtual void onClipboardChanged(ClipboardID, const IClipboard*);
void onInfoChanged();
bool onGrabClipboard(ClipboardID);
void onClipboardChanged(ClipboardID, const IClipboard*);
//@}
//! @name accessors
@ -59,6 +59,11 @@ public:
//@}
protected:
enum EResult { kOkay, kUnknown, kDisconnect };
EResult parseHandshakeMessage(const UInt8* code);
EResult parseMessage(const UInt8* code);
private:
// if compressing mouse motion then send the last motion now
void flushCompressedMouse();
@ -72,7 +77,7 @@ private:
KeyModifierMask translateModifierMask(KeyModifierMask) const;
// event handlers
void handleMessage(const CEvent&, void*);
void handleData(const CEvent&, void*);
void handleHeartBeat(const CEvent&, void*);
// message handlers
@ -94,6 +99,8 @@ private:
void infoAcknowledgment();
private:
typedef EResult (CServerProxy::*MessageParser)(const UInt8*);
CClient* m_client;
IStream* m_stream;
CEventQueueTimer* m_timer;
@ -108,6 +115,8 @@ private:
KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast];
double m_heartRate;
MessageParser m_parser;
static CEvent::Type s_handshakeCompleteEvent;
};

View File

@ -19,7 +19,6 @@ EXTRA_DIST = \
common.dsp \
BasicTypes.h \
IInterface.h \
Version.h \
common.h \
stdbitset.h \
stddeque.h \
@ -40,5 +39,11 @@ MAINTAINERCLEANFILES = \
Makefile.in \
$(NULL)
noinst_LIBRARIES = libcommon.a
libcommon_a_SOURCES = \
Version.cpp \
Version.h \
$(NULL)
INCLUDES = \
$(NULL)

View File

@ -23,17 +23,17 @@
#endif
// important strings
static const char* kApplication = "synergy";
static const char* kCopyright = "Copyright (C) 2002 Chris Schoeneman";
static const char* kContact = "Chris Schoeneman, crs23@bigfoot.com";
static const char* kWebsite = "http://synergy2.sourceforge.net/";
extern const char* kApplication;
extern const char* kCopyright;
extern const char* kContact;
extern const char* kWebsite;
// build version. follows linux kernel style: an even minor number implies
// a release version, odd implies development version.
static const char* kVersion = VERSION;
extern const char* kVersion;
// application version
static const char* kAppVersion = "synergy " VERSION;
extern const char* kAppVersion;
// exit codes
static const int kExitSuccess = 0; // successful completion

View File

@ -85,6 +85,10 @@ LIB32=link.exe -lib
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\Version.cpp
# End Source File
# End Group
# Begin Group "Header Files"

View File

@ -79,6 +79,12 @@ CThread::setPriority(int n)
ARCH->setPriorityOfThread(m_thread, n);
}
void
CThread::unblockPollSocket()
{
ARCH->unblockPollSocket(m_thread);
}
CThread
CThread::getCurrentThread()
{
@ -97,24 +103,6 @@ CThread::wait(double timeout) const
return ARCH->wait(m_thread, timeout);
}
CThread::EWaitResult
CThread::waitForEvent(double timeout) const
{
// IArchMultithread EWaitResults map directly to our EWaitResults
static const EWaitResult s_map[] = {
kEvent,
kExit,
kTimeout
};
return s_map[ARCH->waitForEvent(m_thread, timeout)];
}
void
CThread::unblock() const
{
ARCH->unblockThread(m_thread);
}
void*
CThread::getResult() const
{

View File

@ -39,13 +39,6 @@ documentation.
// note -- do not derive from this class
class CThread {
public:
//! Result of waitForEvent()
enum EWaitResult {
kEvent, //!< An event is pending
kExit, //!< Thread exited
kTimeout //!< Wait timed out
};
//! Run \c adoptedJob in a new thread
/*!
Create and start a new thread executing the \c adoptedJob. The
@ -130,6 +123,13 @@ public:
*/
void setPriority(int n);
//! Force pollSocket() to return
/*!
Forces a currently blocked pollSocket() in the thread to return
immediately.
*/
void unblockPollSocket();
//@}
//! @name accessors
//@{
@ -164,31 +164,6 @@ public:
*/
bool wait(double timeout = -1.0) const;
//! Wait for an event (win32)
/*!
Wait for the message queue to contain a message or for the thread
to exit for up to \c timeout seconds. This returns immediately if
any message is available (including messages that were already in
the queue during the last call to \c GetMessage() or
\c PeekMessage() or waitForEvent(). Returns kEvent if a message
is available, kExit if the thread exited, and kTimeout otherwise.
This will wait forever if \c timeout < 0.0.
This method is available under win32 only.
(cancellation point)
*/
EWaitResult waitForEvent(double timeout = -1.0) const;
//! Unblock thread in system call
/*!
Cause a thread that's in a blocking system call to return. This
call may return before the thread is unblocked. If the thread is
not in a blocking system call, this call has no effect. This does
not cause CMutex::lock() or CCondVar::wait() to return prematurely.
*/
void unblock() const;
//! Get the exit result
/*!
Returns the exit result. This does an implicit wait(). It returns

View File

@ -54,6 +54,7 @@ CSocketMultiplexer::CSocketMultiplexer() :
CSocketMultiplexer::~CSocketMultiplexer()
{
m_thread->cancel();
m_thread->unblockPollSocket();
m_thread->wait();
delete m_thread;
delete m_polling;
@ -87,7 +88,7 @@ CSocketMultiplexer::addSocket(ISocket* socket, ISocketMultiplexerJob* job)
*m_pollable = false;
// break thread out of poll
m_thread->unblock();
m_thread->unblockPollSocket();
// wait for poll to finish
while (*m_polling) {
@ -129,7 +130,7 @@ CSocketMultiplexer::removeSocket(ISocket* socket)
*m_pollable = false;
// break thread out of poll
m_thread->unblock();
m_thread->unblockPollSocket();
// wait until thread finishes poll
while (*m_polling) {
@ -160,11 +161,12 @@ CSocketMultiplexer::serviceThread(void*)
// service the connections
for (;;) {
CThread::testCancel();
{
CLock lock(m_mutex);
// wait until pollable
while (!*m_pollable) {
while (!(bool)*m_pollable) {
m_pollable->wait();
}
@ -281,7 +283,6 @@ CSocketMultiplexer::CJobCursor
CSocketMultiplexer::nextCursor(CJobCursor cursor)
{
CLock lock(m_mutex);
ISocketMultiplexerJob* job = NULL;
CJobCursor j = m_socketJobs.end();
CJobCursor i = cursor;
while (++i != m_socketJobs.end()) {

View File

@ -34,3 +34,18 @@ IDataSocket::getConnectionFailedEvent()
return CEvent::registerTypeOnce(s_failedEvent,
"IDataSocket::failed");
}
void
IDataSocket::close()
{
// this is here to work around a VC++6 bug. see the header file.
assert(0 && "bad call");
}
void*
IDataSocket::getEventTarget() const
{
// this is here to work around a VC++6 bug. see the header file.
assert(0 && "bad call");
return NULL;
}

View File

@ -65,9 +65,13 @@ public:
//@}
// ISocket overrides
// close() and getEventTarget() aren't pure to work around a bug
// in VC++6. it claims the methods are unused locals and warns
// that it's removing them. it's presumably tickled by inheriting
// methods with identical signatures from both superclasses.
virtual void bind(const CNetworkAddress&) = 0;
virtual void close() = 0;
virtual void* getEventTarget() const = 0;
virtual void close();
virtual void* getEventTarget() const;
// IStream overrides
virtual UInt32 read(void* buffer, UInt32 n) = 0;

View File

@ -21,6 +21,12 @@
//! Encapsulate Microsoft Windows desktop
class CMSWindowsDesktop {
public:
//! Open the desktop
/*!
Opens the desktop named \p name. The caller must close the desktop.
*/
static HDESK openDesktop(const CString& name);
//! Open the input desktop
/*!
Opens the input desktop. The caller must close the desktop.

View File

@ -0,0 +1,129 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 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 "CMSWindowsEventQueueBuffer.h"
#include "CThread.h"
#include "IEventQueue.h"
#include "CArchMiscWindows.h"
//
// CEventQueueTimer
//
class CEventQueueTimer { };
//
// CMSWindowsEventQueueBuffer
//
CMSWindowsEventQueueBuffer::CMSWindowsEventQueueBuffer()
{
// remember thread. we'll be posting messages to it.
m_thread = GetCurrentThreadId();
// create a message type for custom events
m_userEvent = RegisterWindowMessage("SYNERGY_USER_EVENT");
// get message type for daemon quit
m_daemonQuit = CArchMiscWindows::getDaemonQuitMessage();
// make sure this thread has a message queue
MSG dummy;
PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE);
}
CMSWindowsEventQueueBuffer::~CMSWindowsEventQueueBuffer()
{
// do nothing
}
void
CMSWindowsEventQueueBuffer::waitForEvent(double timeout)
{
// check if messages are available first. if we don't do this then
// MsgWaitForMultipleObjects() will block even if the queue isn't
// empty if the messages in the queue were there before the last
// call to GetMessage()/PeekMessage().
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
return;
}
// convert timeout
DWORD t;
if (timeout < 0.0) {
t = INFINITE;
}
else {
t = (DWORD)(1000.0 * timeout);
}
// wait for a message. we cannot be interrupted by thread
// cancellation but that's okay because we're run in the main
// thread and we never cancel that thread.
HANDLE dummy[1];
MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLINPUT);
}
IEventQueueBuffer::Type
CMSWindowsEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
{
// BOOL. yeah, right.
BOOL result = GetMessage(&m_event, NULL, 0, 0);
if (result == -1) {
return kNone;
}
else if (result == 0) {
event = CEvent(CEvent::kQuit);
return kSystem;
}
else if (m_event.message == m_daemonQuit) {
event = CEvent(CEvent::kQuit);
return kSystem;
}
else if (m_event.message == m_userEvent) {
dataID = static_cast<UInt32>(m_event.wParam);
return kUser;
}
else {
event = CEvent(CEvent::kSystem,
IEventQueue::getSystemTarget(), &m_event);
return kSystem;
}
}
bool
CMSWindowsEventQueueBuffer::addEvent(UInt32 dataID)
{
return (PostThreadMessage(m_thread, m_userEvent,
static_cast<WPARAM>(dataID), 0) != 0);
}
bool
CMSWindowsEventQueueBuffer::isEmpty() const
{
return (HIWORD(GetQueueStatus(QS_ALLINPUT)) == 0);
}
CEventQueueTimer*
CMSWindowsEventQueueBuffer::newTimer(double, bool) const
{
return new CEventQueueTimer;
}
void
CMSWindowsEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
{
delete timer;
}

View File

@ -0,0 +1,44 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 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 CMSWINDOWSEVENTQUEUEBUFFER_H
#define CMSWINDOWSEVENTQUEUEBUFFER_H
#include "IEventQueueBuffer.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//! Event queue buffer for Win32
class CMSWindowsEventQueueBuffer : public IEventQueueBuffer {
public:
CMSWindowsEventQueueBuffer();
virtual ~CMSWindowsEventQueueBuffer();
// IEventQueueBuffer overrides
virtual void waitForEvent(double timeout);
virtual Type getEvent(CEvent& event, UInt32& dataID);
virtual bool addEvent(UInt32 dataID);
virtual bool isEmpty() const;
virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const;
private:
DWORD m_thread;
UINT m_userEvent;
MSG m_event;
UINT m_daemonQuit;
};
#endif

View File

@ -741,7 +741,7 @@ CMSWindowsKeyMapper::update(IKeyState* keyState)
for (size_t j = 0; j < CModifierKeys::s_maxKeys; ++j) {
if (s_modifiers[i].m_keys[j] != 0) {
SHORT s = GetKeyState(s_modifiers[i].m_keys[j]);
m_keys[s_modifiers[i].m_keys[j]] = static_cast<BYTE>(s);
m_keys[s_modifiers[i].m_keys[j] & 0xffu] = static_cast<BYTE>(s);
if (keyState != NULL) {
if ((s & 0x01) != 0) {
keyState->setToggled(s_modifiers[i].m_mask);

File diff suppressed because it is too large Load Diff

View File

@ -18,19 +18,20 @@
#include "IPlatformScreen.h"
#include "CMSWindowsKeyMapper.h"
#include "CSynergyHook.h"
#include "CCondVar.h"
#include "CMutex.h"
#include "CString.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class CEventQueueTimer;
class CMSWindowsScreenSaver;
class IScreenReceiver;
class IPrimaryScreenReceiver;
class CThread;
//! Implementation of IPlatformScreen for Microsoft Windows
class CMSWindowsScreen : public IPlatformScreen {
public:
CMSWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
CMSWindowsScreen(bool isPrimary);
virtual ~CMSWindowsScreen();
//! @name manipulators
@ -56,12 +57,9 @@ public:
//@}
// IPlatformScreen overrides
virtual void open(IKeyState*);
virtual void close();
virtual void setKeyState(IKeyState*);
virtual void enable();
virtual void disable();
virtual void mainLoop();
virtual void exitMainLoop();
virtual void enter();
virtual bool leave();
virtual bool setClipboard(ClipboardID, const IClipboard*);
@ -72,17 +70,22 @@ public:
virtual void resetOptions();
virtual void setOptions(const COptionsList& options);
virtual void updateKeys();
virtual void setSequenceNumber(UInt32);
virtual bool isPrimary() const;
virtual bool getClipboard(ClipboardID, IClipboard*) const;
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
virtual void getCursorPos(SInt32&, SInt32&) const;
// IScreen overrides
virtual void* getEventTarget() const;
virtual bool getClipboard(ClipboardID id, IClipboard*) const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCursorPos(SInt32& x, SInt32& y) const;
// IPrimaryScreen overrides
virtual void reconfigure(UInt32 activeSides);
virtual void warpCursor(SInt32 x, SInt32 y);
virtual UInt32 addOneShotTimer(double timeout);
virtual SInt32 getJumpZoneSize() const;
virtual bool isAnyMouseButtonDown() const;
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
virtual const char* getKeyName(KeyButton) const;
// ISecondaryScreen overrides
@ -97,17 +100,31 @@ public:
bool isAutoRepeat) const;
private:
// update screen size cache
void updateScreenShape();
class CDesk {
public:
CString m_name;
CThread* m_thread;
DWORD m_threadID;
DWORD m_targetID;
HDESK m_desk;
HWND m_window;
bool m_lowLevel;
};
typedef std::map<CString, CDesk*> CDesks;
// switch to the given desktop. this destroys the window and unhooks
// all hooks, switches the desktop, then creates the window and rehooks
// all hooks (because you can't switch the thread's desktop if it has
// any windows or hooks).
bool switchDesktop(HDESK desk);
// make sure we're on the expected desktop
void syncDesktop() const;
// FIXME -- comment
HINSTANCE openHookLibrary(const char* name);
void closeHookLibrary(HINSTANCE hookLibrary) const;
HCURSOR createBlankCursor() const;
void destroyCursor(HCURSOR cursor) const;
ATOM createWindowClass() const;
ATOM createDeskWindowClass(bool isPrimary) const;
void destroyClass(ATOM windowClass) const;
HWND createWindow(ATOM windowClass, const char* name) const;
void destroyWindow(HWND) const;
void sendEvent(CEvent::Type type, void* = NULL);
void sendClipboardEvent(CEvent::Type type, ClipboardID id);
void handleSystemEvent(const CEvent& event, void*);
// handle message before it gets dispatched. returns true iff
// the message should not be dispatched.
@ -128,10 +145,8 @@ private:
bool onMouseMove(SInt32 x, SInt32 y);
bool onMouseWheel(SInt32 delta);
bool onScreensaver(bool activated);
bool onTimer(UINT timerID);
bool onDisplayChange();
bool onClipboardChange();
bool onActivate(bool activated);
// XXX
// warp cursor without discarding queued events
@ -144,11 +159,8 @@ private:
bool ignore() const;
// XXX
// create the transparent cursor
HCURSOR createBlankCursor() const;
// show/hide the cursor
void showCursor(bool) const;
// update screen size cache
void updateScreenShape();
// enable/disable special key combinations so we can catch/pass them
void enableSpecialKeys(bool) const;
@ -169,6 +181,22 @@ private:
// our window proc
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
// our desk window procs
static LRESULT CALLBACK primaryDeskProc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK secondaryDeskProc(HWND, UINT, WPARAM, LPARAM);
void deskMouseMove(SInt32 x, SInt32 y) const;
void deskEnter(CDesk* desk, DWORD& cursorThreadID);
void deskLeave(CDesk* desk, DWORD& cursorThreadID);
void deskThread(void* vdesk);
CDesk* addDesk(const CString& name, HDESK hdesk);
void removeDesks();
void checkDesk();
bool isDeskAccessible(const CDesk* desk) const;
void sendDeskMessage(UINT, WPARAM, LPARAM) const;
void waitForDesk() const;
void handleCheckDesk(const CEvent& event, void*);
private:
static HINSTANCE s_instance;
@ -178,17 +206,13 @@ private:
// true if windows 95/98/me
bool m_is95Family;
// receivers
IScreenReceiver* m_receiver;
IPrimaryScreenReceiver* m_primaryReceiver;
// true if mouse has entered the screen
bool m_isOnScreen;
// our resources
ATOM m_class;
ATOM m_deskClass;
HCURSOR m_cursor;
HWND m_window;
// screen shape stuff
SInt32 m_x, m_y;
@ -201,6 +225,8 @@ private:
// last mouse position
SInt32 m_xCursor, m_yCursor;
UInt32 m_sequenceNumber;
// used to discard queued messages that are no longer needed
UInt32 m_mark;
UInt32 m_markReceived;
@ -208,33 +234,27 @@ private:
// the main loop's thread id
DWORD m_threadID;
// the thread id of the last attached thread
DWORD m_lastThreadID;
// the timer used to check for desktop switching
UINT m_timer;
// the one shot timer
UINT m_oneShotTimer;
CEventQueueTimer* m_timer;
// screen saver stuff
CMSWindowsScreenSaver* m_screensaver;
bool m_screensaverNotify;
// clipboard stuff
// clipboard stuff. our window is used mainly as a clipboard
// owner and as a link in the clipboard viewer chain.
HWND m_window;
HWND m_nextClipboardWindow;
bool m_ownClipboard;
// the current desk and it's name
HDESK m_desk;
CString m_deskName;
CDesk* m_activeDesk;
CString m_activeDeskName;
// true when the current desktop is inaccessible. while
// the desktop is inaccessible we won't receive user input
// and we'll lose track of the keyboard state. when the
// desktop becomes accessible again we'll notify the event
// handler of that.
bool m_inaccessibleDesktop;
// one desk per desktop and a cond var to communicate with it
CMutex m_mutex;
CCondVar<bool> m_deskReady;
CDesks m_desks;
// hook library stuff
HINSTANCE m_hookLibrary;
@ -247,7 +267,6 @@ private:
SetModeFunc m_setMode;
InstallScreenSaverFunc m_installScreensaver;
UninstallScreenSaverFunc m_uninstallScreensaver;
bool m_lowLevel;
// keyboard stuff
IKeyState* m_keyState;
@ -256,9 +275,6 @@ private:
// map of button state
BYTE m_buttons[1 + kButtonExtra0 + 1];
// stuff for hiding the cursor
DWORD m_cursorThread;
static CMSWindowsScreen* s_screen;
};

View File

@ -76,13 +76,10 @@ static DWORD g_threadID = 0;
static HHOOK g_keyboard = NULL;
static HHOOK g_mouse = NULL;
static HHOOK g_getMessage = NULL;
static HANDLE g_hookThreadLL = NULL;
static DWORD g_hookThreadIDLL = 0;
static HANDLE g_hookEventLL = NULL;
static HHOOK g_keyboardLL = NULL;
static HHOOK g_mouseLL = NULL;
static bool g_screenSaver = false;
static EHookMode g_mode = kHOOK_WATCH_JUMP_ZONE;
static EHookMode g_mode = kHOOK_DISABLE;
static UInt32 g_zoneSides = 0;
static SInt32 g_zoneSize = 0;
static SInt32 g_xScreen = 0;
@ -141,6 +138,7 @@ restoreCursor()
g_cursorThread = 0;
}
#if !NO_GRAB_KEYBOARD
static
bool
keyboardHookHandler(WPARAM wParam, LPARAM lParam)
@ -170,6 +168,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
return false;
}
#endif
static
bool
@ -231,7 +230,7 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
return true;
}
else {
else if (g_mode == kHOOK_WATCH_JUMP_ZONE) {
// check for mouse inside jump zone
bool inside = false;
if (!inside && (g_zoneSides & kLeftMask) != 0) {
@ -259,6 +258,7 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
return false;
}
#if !NO_GRAB_KEYBOARD
static
LRESULT CALLBACK
keyboardHook(int code, WPARAM wParam, LPARAM lParam)
@ -272,6 +272,7 @@ keyboardHook(int code, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(g_keyboard, code, wParam, lParam);
}
#endif
static
LRESULT CALLBACK
@ -354,6 +355,7 @@ getMessageHook(int code, WPARAM wParam, LPARAM lParam)
// side, key repeats are not reported to us.
//
#if !NO_GRAB_KEYBOARD
static
LRESULT CALLBACK
keyboardLLHook(int code, WPARAM wParam, LPARAM lParam)
@ -385,6 +387,7 @@ keyboardLLHook(int code, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(g_keyboardLL, code, wParam, lParam);
}
#endif
//
// low-level mouse hook -- this allows us to capture and handle mouse
@ -411,92 +414,6 @@ mouseLLHook(int code, WPARAM wParam, LPARAM lParam)
return CallNextHookEx(g_mouseLL, code, wParam, lParam);
}
static
DWORD WINAPI
getLowLevelProc(void*)
{
// thread proc for low-level keyboard/mouse hooks. this does
// nothing but install the hook, process events, and uninstall
// the hook.
// force this thread to have a message queue
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
#if !NO_GRAB_KEYBOARD
// install low-level keyboard hook
g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL,
&keyboardLLHook,
g_hinstance,
0);
if (g_keyboardLL == NULL) {
// indicate failure and exit
g_hookThreadIDLL = 0;
SetEvent(g_hookEventLL);
return 1;
}
#else
// keep compiler quiet
&keyboardLLHook;
#endif
// install low-level mouse hook
g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL,
&mouseLLHook,
g_hinstance,
0);
if (g_mouseLL == NULL) {
// indicate failure and exit
if (g_keyboardLL != NULL) {
UnhookWindowsHookEx(g_keyboardLL);
g_keyboardLL = NULL;
}
g_hookThreadIDLL = 0;
SetEvent(g_hookEventLL);
return 1;
}
// ready
SetEvent(g_hookEventLL);
// message loop
bool done = false;
while (!done) {
switch (GetMessage(&msg, NULL, 0, 0)) {
case -1:
break;
case 0:
done = true;
break;
default:
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}
// uninstall hook
UnhookWindowsHookEx(g_mouseLL);
UnhookWindowsHookEx(g_keyboardLL);
g_mouseLL = NULL;
g_keyboardLL = NULL;
return 0;
}
#else // (_WIN32_WINNT < 0x0400)
static
DWORD WINAPI
getLowLevelProc(void*)
{
g_hookThreadIDLL = 0;
SetEvent(g_hookEventLL);
return 1;
}
#endif
static
@ -559,12 +476,8 @@ DllMain(HINSTANCE instance, DWORD reason, LPVOID)
}
else if (reason == DLL_PROCESS_DETACH) {
if (g_processID == GetCurrentProcessId()) {
if (g_keyboard != NULL ||
g_mouse != NULL ||
g_getMessage != NULL) {
uninstall();
uninstallScreenSaver();
}
g_processID = 0;
g_hinstance = NULL;
}
@ -601,9 +514,6 @@ init(DWORD threadID)
g_keyboard = NULL;
g_mouse = NULL;
g_getMessage = NULL;
g_hookThreadLL = NULL;
g_hookThreadIDLL = 0;
g_hookEventLL = NULL;
g_keyboardLL = NULL;
g_mouseLL = NULL;
g_screenSaver = false;
@ -614,7 +524,7 @@ init(DWORD threadID)
g_threadID = threadID;
// set defaults
g_mode = kHOOK_WATCH_JUMP_ZONE;
g_mode = kHOOK_DISABLE;
g_zoneSides = 0;
g_zoneSize = 0;
g_xScreen = 0;
@ -663,75 +573,51 @@ install()
0);
}
// install low-level keyboard/mouse hooks, if possible. since these
// hooks are called in the context of the installing thread and that
// thread must have a message loop but we don't want the caller's
// message loop to do the work, we'll fire up a separate thread
// just for the hooks. note that low-level hooks are only available
// on windows NT SP3 and above.
g_hookEventLL = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_hookEventLL != NULL) {
g_hookThreadLL = CreateThread(NULL, 0, &getLowLevelProc, 0,
CREATE_SUSPENDED, &g_hookThreadIDLL);
if (g_hookThreadLL != NULL) {
// start the thread and wait for it to initialize
ResumeThread(g_hookThreadLL);
WaitForSingleObject(g_hookEventLL, INFINITE);
ResetEvent(g_hookEventLL);
// the thread clears g_hookThreadIDLL if it failed
if (g_hookThreadIDLL == 0) {
CloseHandle(g_hookThreadLL);
g_hookThreadLL = NULL;
}
}
if (g_hookThreadLL == NULL) {
CloseHandle(g_hookEventLL);
g_hookEventLL = NULL;
}
}
// install non-low-level hooks if the low-level hooks are not installed
if (g_hookThreadLL == NULL) {
// install keyboard hook
#if !NO_GRAB_KEYBOARD
#if (_WIN32_WINNT >= 0x0400)
g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL,
&keyboardLLHook,
g_hinstance,
0);
#endif
if (g_keyboardLL == NULL) {
g_keyboard = SetWindowsHookEx(WH_KEYBOARD,
&keyboardHook,
g_hinstance,
0);
#else
// keep compiler quiet
&keyboardHook;
}
#endif
// install mouse hook
#if (_WIN32_WINNT >= 0x0400)
g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL,
&mouseLLHook,
g_hinstance,
0);
#endif
if (g_mouseLL == NULL) {
g_mouse = SetWindowsHookEx(WH_MOUSE,
&mouseHook,
g_hinstance,
0);
}
// check for any failures. uninstall all hooks on failure.
if (g_hookThreadLL == NULL &&
// check that we got all the hooks we wanted
if ((g_getMessage == NULL && g_wheelSupport == kWheelOld) ||
#if !NO_GRAB_KEYBOARD
(g_keyboard == NULL || g_mouse == NULL)) {
#else
(g_mouse == NULL)) {
(g_keyboardLL == NULL && g_keyboard == NULL) ||
#endif
if (g_keyboard != NULL) {
UnhookWindowsHookEx(g_keyboard);
g_keyboard = NULL;
}
if (g_mouse != NULL) {
UnhookWindowsHookEx(g_mouse);
g_mouse = NULL;
}
if (g_getMessage != NULL && !g_screenSaver) {
UnhookWindowsHookEx(g_getMessage);
g_getMessage = NULL;
}
g_threadID = NULL;
(g_mouseLL == NULL && g_mouse == NULL)) {
uninstall();
return kHOOK_FAILED;
}
return (g_hookThreadLL == NULL) ? kHOOK_OKAY : kHOOK_OKAY_LL;
if (g_keyboardLL != NULL || g_mouseLL != NULL) {
return kHOOK_OKAY_LL;
}
return kHOOK_OKAY;
}
int
@ -740,14 +626,13 @@ uninstall(void)
assert(g_hinstance != NULL);
// uninstall hooks
if (g_hookThreadLL != NULL) {
PostThreadMessage(g_hookThreadIDLL, WM_QUIT, 0, 0);
WaitForSingleObject(g_hookThreadLL, INFINITE);
CloseHandle(g_hookEventLL);
CloseHandle(g_hookThreadLL);
g_hookEventLL = NULL;
g_hookThreadLL = NULL;
g_hookThreadIDLL = 0;
if (g_keyboardLL != NULL) {
UnhookWindowsHookEx(g_keyboardLL);
g_keyboardLL = NULL;
}
if (g_mouseLL != NULL) {
UnhookWindowsHookEx(g_mouseLL);
g_mouseLL = NULL;
}
if (g_keyboard != NULL) {
UnhookWindowsHookEx(g_keyboard);

View File

@ -40,6 +40,7 @@
#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; <unused>
#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_SCREEN_SAVER
extern "C" {
@ -50,6 +51,7 @@ enum EHookResult {
};
enum EHookMode {
kHOOK_DISABLE,
kHOOK_WATCH_JUMP_ZONE,
kHOOK_RELAY_EVENTS
};

View File

@ -740,7 +740,7 @@ CXWindowsClipboard::motifFillCache()
// save it
motifFormats.insert(std::make_pair(motifFormat->m_type, data));
}
const UInt32 numMotifFormats = motifFormats.size();
//const UInt32 numMotifFormats = motifFormats.size();
// try each converter in order (because they're in order of
// preference).

View File

@ -143,6 +143,7 @@ CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
// force waitForEvent() to return
XFlush(m_display);
return true;
}
bool
@ -154,7 +155,7 @@ CXWindowsEventQueueBuffer::isEmpty() const
CEventQueueTimer*
CXWindowsEventQueueBuffer::newTimer(double, bool) const
{
return new CEventQueueTimer();
return new CEventQueueTimer;
}
void

View File

@ -309,7 +309,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
// get modifier map from server
XModifierKeymap* modifiers = XGetModifierMapping(display);
int keysPerModifier = modifiers->max_keypermod;
unsigned int keysPerModifier = modifiers->max_keypermod;
// clear state
m_keysymMap.clear();
@ -330,7 +330,6 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
// the keysym map. also collect all keycodes for each modifier.
for (unsigned int i = 0; i < 8; ++i) {
// no keycodes for this modifier yet
bool hasKeycode = false;
KeyModifierMask mask = 0;
IKeyState::KeyButtons modifierKeys;

View File

@ -128,8 +128,8 @@ CXWindowsScreen::CXWindowsScreen(bool isPrimary) :
m_isOnScreen(m_isPrimary),
m_x(0), m_y(0),
m_w(0), m_h(0),
m_xCursor(0), m_yCursor(0),
m_xCenter(0), m_yCenter(0),
m_xCursor(0), m_yCursor(0),
m_keyState(NULL),
m_keyMapper(),
m_im(NULL),

View File

@ -28,6 +28,7 @@ EXTRA_DIST = \
CMSWindowsKeyMapper.cpp \
CMSWindowsScreen.cpp \
CMSWindowsScreenSaver.cpp \
CMSWindowsUtil.cpp \
CSynergyHook.cpp \
CMSWindowsClipboard.h \
CMSWindowsClipboardAnyTextConverter.h \
@ -38,6 +39,7 @@ EXTRA_DIST = \
CMSWindowsKeyMapper.h \
CMSWindowsScreen.h \
CMSWindowsScreenSaver.h \
CMSWindowsUtil.h \
CSynergyHook.h \
$(NULL)

View File

@ -121,6 +121,10 @@ SOURCE=.\CMSWindowsScreen.cpp
SOURCE=.\CMSWindowsScreenSaver.cpp
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsUtil.cpp
# End Source File
# End Group
# Begin Group "Header Files"
@ -161,6 +165,10 @@ SOURCE=.\CMSWindowsScreen.h
SOURCE=.\CMSWindowsScreenSaver.h
# End Source File
# Begin Source File
SOURCE=.\CMSWindowsUtil.h
# End Source File
# End Group
# End Target
# End Project

View File

@ -47,13 +47,13 @@ CClientListener::CClientListener(const CNetworkAddress& address,
LOG((CLOG_DEBUG1 "binding listen socket"));
m_listen->bind(address);
}
catch (XSocketAddressInUse& e) {
catch (XSocketAddressInUse&) {
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;
throw;
}
catch (XBase& e) {
catch (XBase&) {
delete m_listen;
delete m_socketFactory;
delete m_streamFilterFactory;

View File

@ -37,8 +37,8 @@ CEvent::Type CServer::s_errorEvent = CEvent::kUnknown;
CEvent::Type CServer::s_disconnectedEvent = CEvent::kUnknown;
CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
m_active(primaryClient),
m_primaryClient(primaryClient),
m_active(primaryClient),
m_seqNum(0),
m_config(config),
m_activeSaver(NULL),
@ -117,9 +117,6 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
// add connection
addClient(m_primaryClient);
// tell it about the active sides
m_primaryClient->reconfigure(getActivePrimarySides());
// tell primary client about its options
sendOptions(m_primaryClient);
@ -171,8 +168,7 @@ bool
CServer::setConfig(const CConfig& config)
{
// refuse configuration if it doesn't include the primary screen
if (m_primaryClient != NULL &&
!config.isScreen(m_primaryClient->getName())) {
if (!config.isScreen(m_primaryClient->getName())) {
return false;
}
@ -185,9 +181,7 @@ CServer::setConfig(const CConfig& config)
processOptions();
// tell primary screen about reconfiguration
if (m_primaryClient != NULL) {
m_primaryClient->reconfigure(getActivePrimarySides());
}
// tell all (connected) clients about current options
for (CClientList::const_iterator index = m_clients.begin();
@ -296,18 +290,17 @@ CServer::getName(const IClient* client) const
UInt32
CServer::getActivePrimarySides() const
{
CString primaryName = getName(m_primaryClient);
UInt32 sides = 0;
if (!m_config.getNeighbor(primaryName, kLeft).empty()) {
if (getNeighbor(m_primaryClient, kLeft) != NULL) {
sides |= kLeftMask;
}
if (!m_config.getNeighbor(primaryName, kRight).empty()) {
if (getNeighbor(m_primaryClient, kRight) != NULL) {
sides |= kRightMask;
}
if (!m_config.getNeighbor(primaryName, kTop).empty()) {
if (getNeighbor(m_primaryClient, kTop) != NULL) {
sides |= kTopMask;
}
if (!m_config.getNeighbor(primaryName, kBottom).empty()) {
if (getNeighbor(m_primaryClient, kBottom) != NULL) {
sides |= kBottomMask;
}
return sides;
@ -546,6 +539,10 @@ CServer::getNeighbor(IClient* src,
assert(lastGoodScreen != NULL);
y += dy;
break;
case kNoDirection:
assert(0 && "bad direction");
return NULL;
}
// save destination screen
@ -582,6 +579,10 @@ CServer::getNeighbor(IClient* src,
y < dy + getJumpZoneSize(dst))
y = dy + getJumpZoneSize(dst);
break;
case kNoDirection:
assert(0 && "bad direction");
return NULL;
}
}
@ -623,6 +624,10 @@ CServer::getNeighbor(IClient* src,
}
x += dx;
break;
case kNoDirection:
assert(0 && "bad direction");
return NULL;
}
return dst;
@ -999,13 +1004,13 @@ CServer::handleWheelEvent(const CEvent& event, void*)
}
void
CServer::handleScreensaverActivatedEvent(const CEvent& event, void*)
CServer::handleScreensaverActivatedEvent(const CEvent&, void*)
{
onScreensaver(true);
}
void
CServer::handleScreensaverDeactivatedEvent(const CEvent& event, void*)
CServer::handleScreensaverDeactivatedEvent(const CEvent&, void*)
{
onScreensaver(false);
}
@ -1212,7 +1217,6 @@ CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
LOG((CLOG_DEBUG2 "onMouseMovePrimary %d,%d", x, y));
// mouse move on primary (server's) screen
assert(m_primaryClient != NULL);
assert(m_active == m_primaryClient);
// save position
@ -1429,6 +1433,10 @@ CServer::addClient(IClient* client)
// add to list
m_clientSet.insert(client);
m_clients.insert(std::make_pair(name, client));
// tell primary client about the active sides
m_primaryClient->reconfigure(getActivePrimarySides());
return true;
}
@ -1452,6 +1460,7 @@ CServer::removeClient(IClient* client)
// remove from list
m_clients.erase(i);
m_clientSet.erase(client);
return true;
}
@ -1477,7 +1486,7 @@ CServer::closeClient(IClient* client, const char* msg)
// install timer. wait timeout seconds for client to close.
double timeout = 5.0;
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(5.0, NULL);
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
new TMethodEventJob<CServer>(this,
&CServer::handleClientCloseTimeout, client));
@ -1577,6 +1586,9 @@ CServer::forceLeaveClient(IClient* client)
if (m_activeSaver == client) {
m_activeSaver = NULL;
}
// tell primary client about the active sides
m_primaryClient->reconfigure(getActivePrimarySides());
}

View File

@ -89,7 +89,7 @@ CProtocolUtil::vwritef(IStream* stream,
}
}
bool
void
CProtocolUtil::vreadf(IStream* stream, const char* fmt, va_list args)
{
assert(stream != NULL);

View File

@ -71,7 +71,7 @@ public:
private:
static void vwritef(IStream*,
const char* fmt, UInt32 size, va_list);
static bool vreadf(IStream*,
static void vreadf(IStream*,
const char* fmt, va_list);
static UInt32 getLength(const char* fmt, va_list);

View File

@ -27,8 +27,8 @@ CScreen::CScreen(IPlatformScreen* platformScreen) :
m_isPrimary(platformScreen->isPrimary()),
m_enabled(false),
m_entered(m_isPrimary),
m_toggleKeys(0),
m_screenSaverSync(true)
m_screenSaverSync(true),
m_toggleKeys(0)
{
assert(m_screen != NULL);
@ -376,7 +376,7 @@ CScreen::setOptions(const COptionsList& options)
void
CScreen::setSequenceNumber(UInt32 seqNum)
{
return m_screen->setSequenceNumber(seqNum);
m_screen->setSequenceNumber(seqNum);
}
bool

View File

@ -73,8 +73,7 @@ public:
//! Get shape changed event type
/*!
Returns the shape changed event type. This is sent whenever the
screen's shape changes, the cursor center moves, or the jump zone
size changes.
screen's shape changes.
*/
static CEvent::Type getShapeChangedEvent();