mirror of
https://github.com/debauchee/barrier.git
synced 2024-11-23 20:12:39 +03:00
Merged Win32 updates. Added full warnings on g++. Fixed bug in
client when handling server rejection.
This commit is contained in:
parent
612a2054e6
commit
54acf38d82
30
acinclude.m4
30
acinclude.m4
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -58,6 +58,7 @@ private:
|
||||
HMENU m_menu;
|
||||
HICON m_icon[kMaxState];
|
||||
const CBufferedLogOutputter* m_logBuffer;
|
||||
static const UINT s_stateToIconID[];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -19,7 +19,8 @@
|
||||
// CXWindowsClientTaskBarReceiver
|
||||
//
|
||||
|
||||
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver()
|
||||
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(
|
||||
const CBufferedLogOutputter*)
|
||||
{
|
||||
// add ourself to the task bar
|
||||
ARCH->addReceiver(this);
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
appThread.wait(-1.0);
|
||||
#endif
|
||||
return result;
|
||||
// parse command line
|
||||
parse(argc, argv);
|
||||
|
||||
// daemonize if requested
|
||||
if (ARG->m_daemon) {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
|
||||
}
|
||||
catch (XThread&) {
|
||||
appThread.cancel();
|
||||
appThread.wait(-1.0);
|
||||
throw;
|
||||
else {
|
||||
return mainLoop();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
@ -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,192 +714,106 @@ 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)
|
||||
{
|
||||
// windows NT family starts services using no command line options.
|
||||
// since i'm not sure how to tell the difference between that and
|
||||
// a user providing no options we'll assume that if there are no
|
||||
// arguments and we're on NT then we're being invoked as a service.
|
||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||
// of the service code path.
|
||||
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||
}
|
||||
catch (XArchDaemon& e) {
|
||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||
}
|
||||
return kExitFailed;
|
||||
}
|
||||
|
||||
// parse command line
|
||||
parse(argc, argv);
|
||||
|
||||
// daemonize if requested
|
||||
if (ARG->m_daemon) {
|
||||
// start as a daemon
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||
}
|
||||
catch (XArchDaemon& e) {
|
||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||
}
|
||||
return kExitFailed;
|
||||
}
|
||||
else {
|
||||
// cannot start a service from the command line so just
|
||||
// run normally (except with log messages redirected).
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
return runMainInThread();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// run
|
||||
return runMainInThread();
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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.
|
||||
StartupFunc startup = &standardStartup;
|
||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||
startup = &daemonNTStartup;
|
||||
}
|
||||
|
||||
// send PRINT and FATAL output to a message box
|
||||
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 (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 (...) {
|
||||
// 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;
|
||||
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
|
||||
throw;
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
// done with log buffer
|
||||
CLOG->remove(&logBuffer);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
delete CLOG;
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif UNIX_LIKE
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup(int, const char**)
|
||||
{
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
return realMain();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
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;
|
||||
}
|
||||
try {
|
||||
int result;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
result = run(argc, argv, NULL, &standardStartup);
|
||||
delete CLOG;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
result = realMain();
|
||||
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;
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -58,6 +58,7 @@ private:
|
||||
HMENU m_menu;
|
||||
HICON m_icon[kMaxState];
|
||||
const CBufferedLogOutputter* m_logBuffer;
|
||||
static const UINT s_stateToIconID[];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -19,7 +19,8 @@
|
||||
// CXWindowsServerTaskBarReceiver
|
||||
//
|
||||
|
||||
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver()
|
||||
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver(
|
||||
const CBufferedLogOutputter*)
|
||||
{
|
||||
// add ourself to the task bar
|
||||
ARCH->addReceiver(this);
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
appThread.wait(-1.0);
|
||||
#endif
|
||||
return result;
|
||||
// parse command line
|
||||
parse(argc, argv);
|
||||
|
||||
// load configuration
|
||||
loadConfig();
|
||||
|
||||
// daemonize if requested
|
||||
if (ARG->m_daemon) {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
|
||||
}
|
||||
catch (XThread&) {
|
||||
appThread.cancel();
|
||||
appThread.wait(-1.0);
|
||||
throw;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 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,197 +875,107 @@ 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)
|
||||
{
|
||||
// windows NT family starts services using no command line options.
|
||||
// since i'm not sure how to tell the difference between that and
|
||||
// a user providing no options we'll assume that if there are no
|
||||
// arguments and we're on NT then we're being invoked as a service.
|
||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||
// of the service code path.
|
||||
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||
}
|
||||
catch (XArchDaemon& e) {
|
||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||
}
|
||||
return kExitFailed;
|
||||
}
|
||||
|
||||
// parse command line
|
||||
parse(argc, argv);
|
||||
|
||||
// load configuration
|
||||
loadConfig();
|
||||
|
||||
// daemonize if requested
|
||||
if (ARG->m_daemon) {
|
||||
// start as a daemon
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||
}
|
||||
catch (XArchDaemon& e) {
|
||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||
}
|
||||
return kExitFailed;
|
||||
}
|
||||
else {
|
||||
// cannot start a service from the command line so just
|
||||
// run normally (except with log messages redirected).
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
return runMainInThread();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// run
|
||||
return runMainInThread();
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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.
|
||||
StartupFunc startup = &standardStartup;
|
||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||
startup = &daemonNTStartup;
|
||||
}
|
||||
|
||||
// send PRINT and FATAL output to a message box
|
||||
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 (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 (...) {
|
||||
// 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;
|
||||
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
|
||||
throw;
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
// done with log buffer
|
||||
CLOG->remove(&logBuffer);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
delete CLOG;
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif UNIX_LIKE
|
||||
|
||||
static
|
||||
int
|
||||
daemonStartup(int, const char**)
|
||||
{
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
return realMain();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
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;
|
||||
}
|
||||
try {
|
||||
int result;
|
||||
CArch arch;
|
||||
CLOG;
|
||||
CArgs args;
|
||||
result = run(argc, argv, NULL, &standardStartup);
|
||||
delete CLOG;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
result = realMain();
|
||||
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;
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,122 +447,89 @@ 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)
|
||||
{
|
||||
// should only be called from DaemonFunc
|
||||
assert(m_serviceMutex != NULL);
|
||||
assert(run != 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) {
|
||||
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;
|
||||
}
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (...) {
|
||||
// FIXME -- report error
|
||||
|
||||
// prevent serviceHandler from changing state
|
||||
m_serviceState = SERVICE_STOPPED;
|
||||
|
||||
// set status
|
||||
setStatusError(0);
|
||||
|
||||
// wake up serviceHandler if it's waiting then wait for it
|
||||
if (m_serviceHandlerWaiting) {
|
||||
m_serviceHandlerWaiting = false;
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
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);
|
||||
// serviceHandler has exited by now
|
||||
}
|
||||
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
throw;
|
||||
// run unless told to stop
|
||||
if (m_serviceState != SERVICE_STOP_PENDING) {
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
try {
|
||||
result = run();
|
||||
}
|
||||
catch (...) {
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
setStatusError(0);
|
||||
m_serviceState = SERVICE_STOPPED;
|
||||
setStatus(m_serviceState);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
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) {
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
}
|
||||
else {
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
m_serviceState = SERVICE_RUNNING;
|
||||
setStatus(m_serviceState);
|
||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||
}
|
||||
ARCH->unlockMutex(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;
|
||||
@ -605,11 +584,10 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
|
||||
const char** argv = const_cast<const char**>(argvIn);
|
||||
|
||||
// create synchronization objects
|
||||
m_serviceMutex = ARCH->newMutex();
|
||||
m_serviceCondVar = ARCH->newCondVar();
|
||||
m_serviceState = SERVICE_RUNNING;
|
||||
|
||||
// register our service handler functiom
|
||||
m_serviceMutex = ARCH->newMutex();
|
||||
m_serviceCondVar = ARCH->newCondVar();
|
||||
|
||||
// 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) {
|
||||
setStatus(m_serviceState);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,95 +377,162 @@ 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) {
|
||||
// reset return flags
|
||||
pe[i].m_revents = 0;
|
||||
// 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;
|
||||
|
||||
// set invalid flag if socket is bogus then go to next socket
|
||||
if (pe[i].m_socket == NULL) {
|
||||
pe[i].m_revents |= kPOLLNVAL;
|
||||
continue;
|
||||
}
|
||||
// set invalid flag if socket is bogus then go to next socket
|
||||
if (pe[i].m_socket == NULL) {
|
||||
pe[i].m_revents |= kPOLLNVAL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pe[i].m_events & kPOLLIN) {
|
||||
FD_SET(pe[i].m_socket->m_socket, &readSet);
|
||||
readSetP = &readSet;
|
||||
n = 1;
|
||||
}
|
||||
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;
|
||||
// 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) != 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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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 (result == WSA_WAIT_FAILED) {
|
||||
if (getsockerror_winsock() == WSAEINTR) {
|
||||
// interrupted system call
|
||||
ARCH->testCancelThread();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
timeout2P = &timeout2;
|
||||
timeout2.tv_sec = static_cast<int>(timeout);
|
||||
timeout2.tv_usec = static_cast<int>(1.0e+6 *
|
||||
(timeout - timeout2.tv_sec));
|
||||
throwError(getsockerror_winsock());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// do the select
|
||||
n = select_winsock(0, readSetP, writeSetP, errSetP, timeout2P);
|
||||
// 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 ((info.lNetworkEvents & FD_ACCEPT) != 0) {
|
||||
pe[i].m_revents |= kPOLLIN;
|
||||
}
|
||||
if ((info.lNetworkEvents & FD_WRITE) != 0) {
|
||||
pe[i].m_revents |= kPOLLOUT;
|
||||
|
||||
// handle results
|
||||
if (n == SOCKET_ERROR) {
|
||||
if (getsockerror_winsock() == EINTR) {
|
||||
// interrupted system call
|
||||
ARCH->testCancelThread();
|
||||
continue;
|
||||
// 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;
|
||||
}
|
||||
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 ((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 (FD_ISSET(pe[i].m_socket->m_socket, &writeSet)) {
|
||||
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);
|
||||
if (pe[i].m_revents != 0) {
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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,136 +90,193 @@ CServerProxy::installHeartBeat(double heartRate)
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::handleMessage(const CEvent&, void*)
|
||||
CServerProxy::handleData(const CEvent&, void*)
|
||||
{
|
||||
while (m_stream->isReady()) {
|
||||
// read next code
|
||||
UInt8 code[4];
|
||||
UInt32 n = m_stream->read(code, sizeof(code));
|
||||
if (n == 0) {
|
||||
break;
|
||||
}
|
||||
// handle messages until there are no more. first read message code.
|
||||
UInt8 code[4];
|
||||
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]));
|
||||
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
||||
mouseMove();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
|
||||
mouseWheel();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
|
||||
keyDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
|
||||
keyUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
|
||||
mouseDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
|
||||
mouseUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
||||
keyRepeat();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||
// accept and discard no-op
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
||||
enter();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCLeave, 4) == 0) {
|
||||
leave();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||
grabClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
||||
screensaver();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
queryInfo();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
||||
infoAcknowledgment();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||
setClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
|
||||
resetOptions();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
|
||||
setOptions();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
||||
// server wants us to hangup
|
||||
LOG((CLOG_DEBUG1 "recv close"));
|
||||
m_client->disconnect(NULL);
|
||||
switch ((this->*m_parser)(code)) {
|
||||
case kOkay:
|
||||
break;
|
||||
}
|
||||
|
||||
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");
|
||||
case kUnknown:
|
||||
LOG((CLOG_ERR "invalid message from server"));
|
||||
m_client->disconnect("invalid message from server");
|
||||
return;
|
||||
|
||||
case kDisconnect:
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseWheel, 4) == 0) {
|
||||
mouseWheel();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyDown, 4) == 0) {
|
||||
keyDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyUp, 4) == 0) {
|
||||
keyUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseDown, 4) == 0) {
|
||||
mouseDown();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDMouseUp, 4) == 0) {
|
||||
mouseUp();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) {
|
||||
keyRepeat();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||
// accept and discard no-op
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCEnter, 4) == 0) {
|
||||
enter();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCLeave, 4) == 0) {
|
||||
leave();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
|
||||
grabClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCScreenSaver, 4) == 0) {
|
||||
screensaver();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
queryInfo();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
||||
infoAcknowledgment();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||
setClipboard();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
|
||||
resetOptions();
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgDSetOptions, 4) == 0) {
|
||||
setOptions();
|
||||
}
|
||||
|
||||
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, 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;
|
||||
}
|
||||
|
||||
void
|
||||
CServerProxy::handleHeartBeat(const CEvent&, void*)
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
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);
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
@ -308,8 +308,8 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||
}
|
||||
|
||||
// get modifier map from server
|
||||
XModifierKeymap* modifiers = XGetModifierMapping(display);
|
||||
int keysPerModifier = modifiers->max_keypermod;
|
||||
XModifierKeymap* modifiers = XGetModifierMapping(display);
|
||||
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;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,7 +89,7 @@ CProtocolUtil::vwritef(IStream* stream,
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
CProtocolUtil::vreadf(IStream* stream, const char* fmt, va_list args)
|
||||
{
|
||||
assert(stream != NULL);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user