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
|
$2
|
||||||
fi
|
fi
|
||||||
])dnl ACX_PTHREAD
|
])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 "CConfig.h"
|
||||||
#include "LaunchUtil.h"
|
#include "LaunchUtil.h"
|
||||||
|
#include "CMSWindowsUtil.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "stdfstream.h"
|
#include "stdfstream.h"
|
||||||
|
@ -23,32 +24,13 @@
|
||||||
CString
|
CString
|
||||||
getString(DWORD id)
|
getString(DWORD id)
|
||||||
{
|
{
|
||||||
char buffer[1024];
|
return CMSWindowsUtil::getString(s_instance, id);
|
||||||
buffer[0] = '\0';
|
|
||||||
LoadString(s_instance, id, buffer, sizeof(buffer) / sizeof(buffer[0]));
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CString
|
CString
|
||||||
getErrorString(DWORD error)
|
getErrorString(DWORD error)
|
||||||
{
|
{
|
||||||
char* buffer;
|
return CMSWindowsUtil::getErrorString(s_instance, error, IDS_ERROR);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -332,8 +332,8 @@ BEGIN
|
||||||
"Synergy is not configured to start automatically."
|
"Synergy is not configured to start automatically."
|
||||||
IDS_INSTALL_LABEL "Install"
|
IDS_INSTALL_LABEL "Install"
|
||||||
IDS_UNINSTALL_LABEL "Uninstall"
|
IDS_UNINSTALL_LABEL "Uninstall"
|
||||||
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}."
|
IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}"
|
||||||
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}."
|
IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}"
|
||||||
IDS_INSTALL_TITLE "Installed Auto-Start"
|
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_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."
|
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_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_ADD_SCREEN "Add Screen"
|
||||||
IDS_EDIT_SCREEN "Edit Screen %{1}"
|
IDS_EDIT_SCREEN "Edit Screen %{1}"
|
||||||
|
IDS_ERROR_CODE "Error code: %{1}"
|
||||||
END
|
END
|
||||||
|
|
||||||
#endif // English (U.S.) resources
|
#endif // English (U.S.) resources
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#define IDS_ADD_SCREEN 37
|
#define IDS_ADD_SCREEN 37
|
||||||
#define IDS_EDIT_SCREEN 38
|
#define IDS_EDIT_SCREEN 38
|
||||||
#define IDS_INVALID_TIME 39
|
#define IDS_INVALID_TIME 39
|
||||||
|
#define IDS_ERROR_CODE 39
|
||||||
#define IDD_MAIN 101
|
#define IDD_MAIN 101
|
||||||
#define IDD_ADD 102
|
#define IDD_ADD 102
|
||||||
#define IDD_WAIT 103
|
#define IDD_WAIT 103
|
||||||
|
|
|
@ -21,18 +21,19 @@
|
||||||
#include "CArchTaskBarWindows.h"
|
#include "CArchTaskBarWindows.h"
|
||||||
#include "resource.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_RUNNING,
|
||||||
IDI_TASKBAR_NOT_WORKING,
|
IDI_TASKBAR_NOT_WORKING,
|
||||||
IDI_TASKBAR_NOT_CONNECTED,
|
IDI_TASKBAR_NOT_CONNECTED,
|
||||||
|
IDI_TASKBAR_NOT_CONNECTED,
|
||||||
IDI_TASKBAR_CONNECTED
|
IDI_TASKBAR_CONNECTED
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// CMSWindowsClientTaskBarReceiver
|
|
||||||
//
|
|
||||||
|
|
||||||
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
|
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
|
||||||
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
|
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
|
||||||
CClientTaskBarReceiver(),
|
CClientTaskBarReceiver(),
|
||||||
|
@ -41,7 +42,7 @@ CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
|
||||||
m_logBuffer(logBuffer)
|
m_logBuffer(logBuffer)
|
||||||
{
|
{
|
||||||
for (UInt32 i = 0; i < kMaxState; ++i) {
|
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));
|
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
|
||||||
|
|
||||||
|
@ -171,7 +172,7 @@ CMSWindowsClientTaskBarReceiver::primaryAction()
|
||||||
const IArchTaskBarReceiver::Icon
|
const IArchTaskBarReceiver::Icon
|
||||||
CMSWindowsClientTaskBarReceiver::getIcon() const
|
CMSWindowsClientTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<Icon>(m_icon[getState()]);
|
return reinterpret_cast<Icon>(m_icon[getStatus()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -58,6 +58,7 @@ private:
|
||||||
HMENU m_menu;
|
HMENU m_menu;
|
||||||
HICON m_icon[kMaxState];
|
HICON m_icon[kMaxState];
|
||||||
const CBufferedLogOutputter* m_logBuffer;
|
const CBufferedLogOutputter* m_logBuffer;
|
||||||
|
static const UINT s_stateToIconID[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
// CXWindowsClientTaskBarReceiver
|
// CXWindowsClientTaskBarReceiver
|
||||||
//
|
//
|
||||||
|
|
||||||
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver()
|
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(
|
||||||
|
const CBufferedLogOutputter*)
|
||||||
{
|
{
|
||||||
// add ourself to the task bar
|
// add ourself to the task bar
|
||||||
ARCH->addReceiver(this);
|
ARCH->addReceiver(this);
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
|
|
||||||
#include "CClientTaskBarReceiver.h"
|
#include "CClientTaskBarReceiver.h"
|
||||||
|
|
||||||
|
class CBufferedLogOutputter;
|
||||||
|
|
||||||
//! Implementation of CClientTaskBarReceiver for X Windows
|
//! Implementation of CClientTaskBarReceiver for X Windows
|
||||||
class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
|
class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
|
||||||
public:
|
public:
|
||||||
CXWindowsClientTaskBarReceiver();
|
CXWindowsClientTaskBarReceiver(const CBufferedLogOutputter*);
|
||||||
virtual ~CXWindowsClientTaskBarReceiver();
|
virtual ~CXWindowsClientTaskBarReceiver();
|
||||||
|
|
||||||
// IArchTaskBarReceiver overrides
|
// IArchTaskBarReceiver overrides
|
||||||
|
|
|
@ -48,6 +48,7 @@ synergyc_LDADD = \
|
||||||
$(DEPTH)/lib/io/libio.a \
|
$(DEPTH)/lib/io/libio.a \
|
||||||
$(DEPTH)/lib/mt/libmt.a \
|
$(DEPTH)/lib/mt/libmt.a \
|
||||||
$(DEPTH)/lib/base/libbase.a \
|
$(DEPTH)/lib/base/libbase.a \
|
||||||
|
$(DEPTH)/lib/common/libcommon.a \
|
||||||
$(DEPTH)/lib/arch/libarch.a \
|
$(DEPTH)/lib/arch/libarch.a \
|
||||||
$(X_LIBS) \
|
$(X_LIBS) \
|
||||||
$(X_PRE_LIBS) \
|
$(X_PRE_LIBS) \
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
// Used by synergyc.rc
|
// Used by synergyc.rc
|
||||||
//
|
//
|
||||||
#define IDS_FAILED 1
|
#define IDS_FAILED 1
|
||||||
|
#define IDS_INIT_FAILED 2
|
||||||
|
#define IDS_UNCAUGHT_EXCEPTION 3
|
||||||
#define IDI_SYNERGY 101
|
#define IDI_SYNERGY 101
|
||||||
#define IDI_TASKBAR_NOT_RUNNING 102
|
#define IDI_TASKBAR_NOT_RUNNING 102
|
||||||
#define IDI_TASKBAR_NOT_WORKING 103
|
#define IDI_TASKBAR_NOT_WORKING 103
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "CFunctionEventJob.h"
|
#include "CFunctionEventJob.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
#include "LogOutputters.h"
|
#include "LogOutputters.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
|
@ -33,8 +34,9 @@
|
||||||
|
|
||||||
#define DAEMON_RUNNING(running_)
|
#define DAEMON_RUNNING(running_)
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
#include "CMSWindowsScreen.h"
|
|
||||||
#include "CArchMiscWindows.h"
|
#include "CArchMiscWindows.h"
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
|
#include "CMSWindowsUtil.h"
|
||||||
#include "CMSWindowsClientTaskBarReceiver.h"
|
#include "CMSWindowsClientTaskBarReceiver.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#undef DAEMON_RUNNING
|
#undef DAEMON_RUNNING
|
||||||
|
@ -51,6 +53,9 @@
|
||||||
#define DAEMON_NAME "synergyc"
|
#define DAEMON_NAME "synergyc"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef int (*StartupFunc)(int, char**);
|
||||||
|
static void parse(int argc, const char* const* argv);
|
||||||
|
|
||||||
//
|
//
|
||||||
// program arguments
|
// program arguments
|
||||||
//
|
//
|
||||||
|
@ -64,7 +69,8 @@ public:
|
||||||
m_backend(false),
|
m_backend(false),
|
||||||
m_restartable(true),
|
m_restartable(true),
|
||||||
m_daemon(true),
|
m_daemon(true),
|
||||||
m_logFilter(NULL)
|
m_logFilter(NULL),
|
||||||
|
m_serverAddress(NULL)
|
||||||
{ s_instance = this; }
|
{ s_instance = this; }
|
||||||
~CArgs() { s_instance = NULL; }
|
~CArgs() { s_instance = NULL; }
|
||||||
|
|
||||||
|
@ -76,7 +82,7 @@ public:
|
||||||
bool m_daemon;
|
bool m_daemon;
|
||||||
const char* m_logFilter;
|
const char* m_logFilter;
|
||||||
CString m_name;
|
CString m_name;
|
||||||
CNetworkAddress m_serverAddress;
|
CNetworkAddress* m_serverAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
CArgs* CArgs::s_instance = NULL;
|
CArgs* CArgs::s_instance = NULL;
|
||||||
|
@ -97,6 +103,18 @@ createScreen()
|
||||||
#endif
|
#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
|
// platform independent main
|
||||||
|
@ -292,7 +310,7 @@ startClient()
|
||||||
try {
|
try {
|
||||||
clientScreen = openClientScreen();
|
clientScreen = openClientScreen();
|
||||||
s_client = openClient(ARG->m_name,
|
s_client = openClient(ARG->m_name,
|
||||||
ARG->m_serverAddress, clientScreen);
|
*ARG->m_serverAddress, clientScreen);
|
||||||
s_clientScreen = clientScreen;
|
s_clientScreen = clientScreen;
|
||||||
LOG((CLOG_NOTE "started client"));
|
LOG((CLOG_NOTE "started client"));
|
||||||
s_client->connect();
|
s_client->connect();
|
||||||
|
@ -338,7 +356,7 @@ stopClient()
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
realMain()
|
mainLoop()
|
||||||
{
|
{
|
||||||
// start the client. if this return false then we've failed and
|
// start the client. if this return false then we've failed and
|
||||||
// we shouldn't retry.
|
// we shouldn't retry.
|
||||||
|
@ -350,8 +368,8 @@ realMain()
|
||||||
// run event loop. if startClient() failed we're supposed to retry
|
// run event loop. if startClient() failed we're supposed to retry
|
||||||
// later. the timer installed by startClient() will take care of
|
// later. the timer installed by startClient() will take care of
|
||||||
// that.
|
// that.
|
||||||
DAEMON_RUNNING(true);
|
|
||||||
CEvent event;
|
CEvent event;
|
||||||
|
DAEMON_RUNNING(true);
|
||||||
EVENTQUEUE->getEvent(event);
|
EVENTQUEUE->getEvent(event);
|
||||||
while (event.getType() != CEvent::kQuit) {
|
while (event.getType() != CEvent::kQuit) {
|
||||||
EVENTQUEUE->dispatchEvent(event);
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
@ -369,45 +387,65 @@ realMain()
|
||||||
return kExitSuccess;
|
return kExitSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
static
|
static
|
||||||
void
|
int
|
||||||
realMainEntry(void* vresult)
|
daemonMainLoop(int, const char**)
|
||||||
{
|
{
|
||||||
*reinterpret_cast<int*>(vresult) = realMain();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
return mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
runMainInThread(void)
|
standardStartup(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int result = 0;
|
// parse command line
|
||||||
CThread appThread(new CFunctionJob(&realMainEntry, &result));
|
parse(argc, argv);
|
||||||
try {
|
|
||||||
#if WINDOWS_LIKE
|
// daemonize if requested
|
||||||
MSG msg;
|
if (ARG->m_daemon) {
|
||||||
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
|
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
|
||||||
// check for a quit event
|
|
||||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
||||||
if (msg.message == WM_QUIT) {
|
|
||||||
CThread::getCurrentThread().cancel();
|
|
||||||
}
|
}
|
||||||
TranslateMessage(&msg);
|
else {
|
||||||
DispatchMessage(&msg);
|
return mainLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
appThread.wait(-1.0);
|
static
|
||||||
#endif
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
|
||||||
appThread.cancel();
|
|
||||||
appThread.wait(-1.0);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -588,7 +626,7 @@ parse(int argc, const char* const* argv)
|
||||||
|
|
||||||
// save server address
|
// save server address
|
||||||
try {
|
try {
|
||||||
ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
*ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
||||||
}
|
}
|
||||||
catch (XSocketAddress& e) {
|
catch (XSocketAddress& e) {
|
||||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||||
|
@ -676,193 +714,107 @@ byeThrow(int x)
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
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);
|
parse(argc, argv);
|
||||||
|
|
||||||
// cannot run as backend if running as a service
|
|
||||||
ARG->m_backend = false;
|
ARG->m_backend = false;
|
||||||
|
return CArchMiscWindows::runDaemon(mainLoop);
|
||||||
// run as a service
|
|
||||||
return CArchMiscWindows::runDaemon(realMain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup95(int, const char**)
|
daemonNTStartup(int, char**)
|
||||||
{
|
{
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
return runMainInThread();
|
bye = &byeThrow;
|
||||||
|
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
void
|
||||||
run(int argc, char** argv)
|
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
|
||||||
{
|
{
|
||||||
|
CString fmt = CMSWindowsUtil::getString(instance, id);
|
||||||
|
CString msg = CStringUtil::format(fmt.c_str(), arg);
|
||||||
|
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI
|
||||||
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
CArch arch(instance);
|
||||||
|
CMSWindowsScreen::init(instance);
|
||||||
|
CLOG;
|
||||||
|
// FIXME
|
||||||
|
// CThread::getCurrentThread().setPriority(-14);
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
// windows NT family starts services using no command line options.
|
||||||
// since i'm not sure how to tell the difference between that and
|
// 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
|
// 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.
|
// 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
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
// of the service code path.
|
// of the service code path.
|
||||||
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
StartupFunc startup = &standardStartup;
|
||||||
try {
|
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
startup = &daemonNTStartup;
|
||||||
}
|
}
|
||||||
catch (XArchDaemon& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
|
||||||
}
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(argc, argv);
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
if (ARG->m_daemon) {
|
|
||||||
// start as a daemon
|
|
||||||
if (CArchMiscWindows::isWindows95Family()) {
|
|
||||||
try {
|
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
|
||||||
}
|
|
||||||
catch (XArchDaemon& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
|
||||||
}
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// cannot start a service from the command line so just
|
|
||||||
// run normally (except with log messages redirected).
|
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
|
||||||
return runMainInThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// run
|
|
||||||
return runMainInThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WINAPI
|
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|
||||||
{
|
|
||||||
CArch arch(instance);
|
|
||||||
CLOG;
|
|
||||||
CArgs args;
|
|
||||||
|
|
||||||
// save instance
|
|
||||||
CMSWindowsScreen::init(instance);
|
|
||||||
|
|
||||||
// get program name
|
|
||||||
ARG->m_pname = ARCH->getBasename(__argv[0]);
|
|
||||||
|
|
||||||
// send PRINT and FATAL output to a message box
|
// send PRINT and FATAL output to a message box
|
||||||
CLOG->insert(new CMessageBoxOutputter);
|
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
|
||||||
|
|
||||||
// save log messages
|
|
||||||
CBufferedLogOutputter logBuffer(1000);
|
|
||||||
CLOG->insert(&logBuffer, true);
|
|
||||||
|
|
||||||
// make the task bar receiver. the user can control this app
|
|
||||||
// through the task bar.
|
|
||||||
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance,
|
|
||||||
&logBuffer);
|
|
||||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
|
||||||
|
|
||||||
int result;
|
|
||||||
try {
|
|
||||||
// run in foreground or as a daemon
|
|
||||||
result = run(__argc, __argv);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// note that we don't rethrow thread cancellation. we'll
|
|
||||||
// be exiting soon so it doesn't matter. what we'd like
|
|
||||||
// is for everything after this try/catch to be in a
|
|
||||||
// finally block.
|
|
||||||
result = kExitFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// done with task bar receiver
|
|
||||||
delete s_taskBarReceiver;
|
|
||||||
|
|
||||||
// done with log buffer
|
|
||||||
CLOG->remove(&logBuffer);
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
// let user examine any messages if we're running as a backend
|
||||||
// by putting up a dialog box before exiting.
|
// by putting up a dialog box before exiting.
|
||||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
if (args.m_backend && s_hasImportantLogMessages) {
|
||||||
char msg[1024];
|
showError(instance, args.m_pname, IDS_FAILED, "");
|
||||||
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;
|
delete CLOG;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (XArch& e) {
|
||||||
|
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
daemonStartup(int, const char**)
|
|
||||||
{
|
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
|
||||||
return realMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char** argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
CArgs args;
|
||||||
|
try {
|
||||||
|
int result;
|
||||||
CArch arch;
|
CArch arch;
|
||||||
CLOG;
|
CLOG;
|
||||||
|
|
||||||
// go really fast
|
|
||||||
CThread::getCurrentThread().setPriority(-14);
|
|
||||||
|
|
||||||
CSocketMultiplexer multiplexer;
|
|
||||||
CEventQueue eventQueue;
|
|
||||||
|
|
||||||
// get program name
|
|
||||||
CArgs args;
|
CArgs args;
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
result = run(argc, argv, NULL, &standardStartup);
|
||||||
|
delete CLOG;
|
||||||
// make the task bar receiver. the user can control this app
|
|
||||||
// through the task bar.
|
|
||||||
s_taskBarReceiver = new CXWindowsClientTaskBarReceiver;
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(argc, argv);
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
int result;
|
|
||||||
if (ARG->m_daemon) {
|
|
||||||
try {
|
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
|
||||||
}
|
|
||||||
catch (XArchDaemon&) {
|
|
||||||
LOG((CLOG_CRIT "failed to daemonize"));
|
|
||||||
result = kExitFailed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = realMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
// done with task bar receiver
|
|
||||||
delete s_taskBarReceiver;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (XArch& e) {
|
||||||
|
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,8 @@ END
|
||||||
STRINGTABLE DISCARDABLE
|
STRINGTABLE DISCARDABLE
|
||||||
BEGIN
|
BEGIN
|
||||||
IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
|
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
|
END
|
||||||
|
|
||||||
#endif // English (U.S.) resources
|
#endif // English (U.S.) resources
|
||||||
|
|
|
@ -21,7 +21,11 @@
|
||||||
#include "CArchTaskBarWindows.h"
|
#include "CArchTaskBarWindows.h"
|
||||||
#include "resource.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_RUNNING,
|
||||||
IDI_TASKBAR_NOT_WORKING,
|
IDI_TASKBAR_NOT_WORKING,
|
||||||
|
@ -29,10 +33,6 @@ static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
|
||||||
IDI_TASKBAR_CONNECTED
|
IDI_TASKBAR_CONNECTED
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// CMSWindowsServerTaskBarReceiver
|
|
||||||
//
|
|
||||||
|
|
||||||
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
|
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
|
||||||
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
|
HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
|
||||||
CServerTaskBarReceiver(),
|
CServerTaskBarReceiver(),
|
||||||
|
@ -41,7 +41,7 @@ CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
|
||||||
m_logBuffer(logBuffer)
|
m_logBuffer(logBuffer)
|
||||||
{
|
{
|
||||||
for (UInt32 i = 0; i < kMaxState; ++i) {
|
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));
|
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
|
||||||
|
|
||||||
|
@ -77,12 +77,7 @@ CMSWindowsServerTaskBarReceiver::showStatus()
|
||||||
std::string status = getToolTip();
|
std::string status = getToolTip();
|
||||||
|
|
||||||
// get the connect clients, if any
|
// get the connect clients, if any
|
||||||
typedef std::vector<CString> CClientList;
|
const CClients& clients = getClients();
|
||||||
CClientList clients;
|
|
||||||
CServer* server = getServer();
|
|
||||||
if (server != NULL) {
|
|
||||||
server->getClients(clients);
|
|
||||||
}
|
|
||||||
|
|
||||||
// done getting status
|
// done getting status
|
||||||
unlock();
|
unlock();
|
||||||
|
@ -92,7 +87,7 @@ CMSWindowsServerTaskBarReceiver::showStatus()
|
||||||
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
|
||||||
child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS);
|
child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS);
|
||||||
SendMessage(child, LB_RESETCONTENT, 0, 0);
|
SendMessage(child, LB_RESETCONTENT, 0, 0);
|
||||||
for (CClientList::const_iterator index = clients.begin();
|
for (CClients::const_iterator index = clients.begin();
|
||||||
index != clients.end(); ) {
|
index != clients.end(); ) {
|
||||||
const char* client = index->c_str();
|
const char* client = index->c_str();
|
||||||
if (++index == clients.end()) {
|
if (++index == clients.end()) {
|
||||||
|
@ -191,7 +186,7 @@ CMSWindowsServerTaskBarReceiver::primaryAction()
|
||||||
const IArchTaskBarReceiver::Icon
|
const IArchTaskBarReceiver::Icon
|
||||||
CMSWindowsServerTaskBarReceiver::getIcon() const
|
CMSWindowsServerTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<Icon>(m_icon[getState()]);
|
return reinterpret_cast<Icon>(m_icon[getStatus()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -58,6 +58,7 @@ private:
|
||||||
HMENU m_menu;
|
HMENU m_menu;
|
||||||
HICON m_icon[kMaxState];
|
HICON m_icon[kMaxState];
|
||||||
const CBufferedLogOutputter* m_logBuffer;
|
const CBufferedLogOutputter* m_logBuffer;
|
||||||
|
static const UINT s_stateToIconID[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
// CXWindowsServerTaskBarReceiver
|
// CXWindowsServerTaskBarReceiver
|
||||||
//
|
//
|
||||||
|
|
||||||
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver()
|
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver(
|
||||||
|
const CBufferedLogOutputter*)
|
||||||
{
|
{
|
||||||
// add ourself to the task bar
|
// add ourself to the task bar
|
||||||
ARCH->addReceiver(this);
|
ARCH->addReceiver(this);
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
|
|
||||||
#include "CServerTaskBarReceiver.h"
|
#include "CServerTaskBarReceiver.h"
|
||||||
|
|
||||||
|
class CBufferedLogOutputter;
|
||||||
|
|
||||||
//! Implementation of CServerTaskBarReceiver for X Windows
|
//! Implementation of CServerTaskBarReceiver for X Windows
|
||||||
class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
|
class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
|
||||||
public:
|
public:
|
||||||
CXWindowsServerTaskBarReceiver();
|
CXWindowsServerTaskBarReceiver(const CBufferedLogOutputter*);
|
||||||
virtual ~CXWindowsServerTaskBarReceiver();
|
virtual ~CXWindowsServerTaskBarReceiver();
|
||||||
|
|
||||||
// IArchTaskBarReceiver overrides
|
// IArchTaskBarReceiver overrides
|
||||||
|
|
|
@ -48,6 +48,7 @@ synergys_LDADD = \
|
||||||
$(DEPTH)/lib/io/libio.a \
|
$(DEPTH)/lib/io/libio.a \
|
||||||
$(DEPTH)/lib/mt/libmt.a \
|
$(DEPTH)/lib/mt/libmt.a \
|
||||||
$(DEPTH)/lib/base/libbase.a \
|
$(DEPTH)/lib/base/libbase.a \
|
||||||
|
$(DEPTH)/lib/common/libcommon.a \
|
||||||
$(DEPTH)/lib/arch/libarch.a \
|
$(DEPTH)/lib/arch/libarch.a \
|
||||||
$(X_LIBS) \
|
$(X_LIBS) \
|
||||||
$(X_PRE_LIBS) \
|
$(X_PRE_LIBS) \
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
// Used by synergys.rc
|
// Used by synergys.rc
|
||||||
//
|
//
|
||||||
#define IDS_FAILED 1
|
#define IDS_FAILED 1
|
||||||
|
#define IDS_INIT_FAILED 2
|
||||||
|
#define IDS_UNCAUGHT_EXCEPTION 3
|
||||||
#define IDI_SYNERGY 101
|
#define IDI_SYNERGY 101
|
||||||
#define IDI_TASKBAR_NOT_RUNNING 102
|
#define IDI_TASKBAR_NOT_RUNNING 102
|
||||||
#define IDI_TASKBAR_NOT_WORKING 103
|
#define IDI_TASKBAR_NOT_WORKING 103
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include "CEventQueue.h"
|
#include "CEventQueue.h"
|
||||||
#include "CFunctionEventJob.h"
|
#include "CFunctionEventJob.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
#include "LogOutputters.h"
|
#include "LogOutputters.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
|
@ -36,8 +38,9 @@
|
||||||
|
|
||||||
#define DAEMON_RUNNING(running_)
|
#define DAEMON_RUNNING(running_)
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
#include "CMSWindowsScreen.h"
|
|
||||||
#include "CArchMiscWindows.h"
|
#include "CArchMiscWindows.h"
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
|
#include "CMSWindowsUtil.h"
|
||||||
#include "CMSWindowsServerTaskBarReceiver.h"
|
#include "CMSWindowsServerTaskBarReceiver.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#undef DAEMON_RUNNING
|
#undef DAEMON_RUNNING
|
||||||
|
@ -63,6 +66,10 @@
|
||||||
#define SYS_CONFIG_NAME "synergy.conf"
|
#define SYS_CONFIG_NAME "synergy.conf"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef int (*StartupFunc)(int, char**);
|
||||||
|
static void parse(int argc, const char* const* argv);
|
||||||
|
static void loadConfig();
|
||||||
|
|
||||||
//
|
//
|
||||||
// program arguments
|
// program arguments
|
||||||
//
|
//
|
||||||
|
@ -90,8 +97,8 @@ public:
|
||||||
const char* m_configFile;
|
const char* m_configFile;
|
||||||
const char* m_logFilter;
|
const char* m_logFilter;
|
||||||
CString m_name;
|
CString m_name;
|
||||||
CNetworkAddress m_synergyAddress;
|
CNetworkAddress* m_synergyAddress;
|
||||||
CConfig m_config;
|
CConfig* m_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
CArgs* CArgs::s_instance = NULL;
|
CArgs* CArgs::s_instance = NULL;
|
||||||
|
@ -112,6 +119,18 @@ createScreen()
|
||||||
#endif
|
#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
|
// platform independent main
|
||||||
|
@ -299,11 +318,11 @@ startServer()
|
||||||
CPrimaryClient* primaryClient = NULL;
|
CPrimaryClient* primaryClient = NULL;
|
||||||
CClientListener* listener = NULL;
|
CClientListener* listener = NULL;
|
||||||
try {
|
try {
|
||||||
CString name = ARG->m_config.getCanonicalName(ARG->m_name);
|
CString name = ARG->m_config->getCanonicalName(ARG->m_name);
|
||||||
serverScreen = openServerScreen();
|
serverScreen = openServerScreen();
|
||||||
primaryClient = openPrimaryClient(name, serverScreen);
|
primaryClient = openPrimaryClient(name, serverScreen);
|
||||||
listener = openClientListener(ARG->m_config.getSynergyAddress());
|
listener = openClientListener(ARG->m_config->getSynergyAddress());
|
||||||
s_server = openServer(ARG->m_config, primaryClient);
|
s_server = openServer(*ARG->m_config, primaryClient);
|
||||||
s_serverScreen = serverScreen;
|
s_serverScreen = serverScreen;
|
||||||
s_primaryClient = primaryClient;
|
s_primaryClient = primaryClient;
|
||||||
s_listener = listener;
|
s_listener = listener;
|
||||||
|
@ -372,26 +391,26 @@ stopServer()
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
realMain()
|
mainLoop()
|
||||||
{
|
{
|
||||||
// if configuration has no screens then add this system
|
// if configuration has no screens then add this system
|
||||||
// as the default
|
// as the default
|
||||||
if (ARG->m_config.begin() == ARG->m_config.end()) {
|
if (ARG->m_config->begin() == ARG->m_config->end()) {
|
||||||
ARG->m_config.addScreen(ARG->m_name);
|
ARG->m_config->addScreen(ARG->m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the contact address, if provided, in the config.
|
// set the contact address, if provided, in the config.
|
||||||
// otherwise, if the config doesn't have an address, use
|
// otherwise, if the config doesn't have an address, use
|
||||||
// the default.
|
// the default.
|
||||||
if (ARG->m_synergyAddress.isValid()) {
|
if (ARG->m_synergyAddress->isValid()) {
|
||||||
ARG->m_config.setSynergyAddress(ARG->m_synergyAddress);
|
ARG->m_config->setSynergyAddress(*ARG->m_synergyAddress);
|
||||||
}
|
}
|
||||||
else if (!ARG->m_config.getSynergyAddress().isValid()) {
|
else if (!ARG->m_config->getSynergyAddress().isValid()) {
|
||||||
ARG->m_config.setSynergyAddress(CNetworkAddress(kDefaultPort));
|
ARG->m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
// canonicalize the primary screen name
|
// 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()) {
|
if (primaryName.empty()) {
|
||||||
LOG((CLOG_CRIT "unknown screen name `%s'", ARG->m_name.c_str()));
|
LOG((CLOG_CRIT "unknown screen name `%s'", ARG->m_name.c_str()));
|
||||||
return kExitFailed;
|
return kExitFailed;
|
||||||
|
@ -407,8 +426,8 @@ realMain()
|
||||||
// run event loop. if startServer() failed we're supposed to retry
|
// run event loop. if startServer() failed we're supposed to retry
|
||||||
// later. the timer installed by startServer() will take care of
|
// later. the timer installed by startServer() will take care of
|
||||||
// that.
|
// that.
|
||||||
DAEMON_RUNNING(true);
|
|
||||||
CEvent event;
|
CEvent event;
|
||||||
|
DAEMON_RUNNING(true);
|
||||||
EVENTQUEUE->getEvent(event);
|
EVENTQUEUE->getEvent(event);
|
||||||
while (event.getType() != CEvent::kQuit) {
|
while (event.getType() != CEvent::kQuit) {
|
||||||
EVENTQUEUE->dispatchEvent(event);
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
@ -426,43 +445,71 @@ realMain()
|
||||||
return kExitSuccess;
|
return kExitSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX
|
|
||||||
static
|
static
|
||||||
void
|
int
|
||||||
realMainEntry(void* vresult)
|
daemonMainLoop(int, const char**)
|
||||||
{
|
{
|
||||||
*reinterpret_cast<int*>(vresult) = realMain();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
return mainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
runMainInThread(void)
|
standardStartup(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int result = 0;
|
// parse command line
|
||||||
CThread appThread(new CFunctionJob(&realMainEntry, &result));
|
parse(argc, argv);
|
||||||
try {
|
|
||||||
#if WINDOWS_LIKE
|
// load configuration
|
||||||
MSG msg;
|
loadConfig();
|
||||||
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
|
|
||||||
// check for a quit event
|
// daemonize if requested
|
||||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
if (ARG->m_daemon) {
|
||||||
if (msg.message == WM_QUIT) {
|
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
|
||||||
CThread::getCurrentThread().cancel();
|
}
|
||||||
|
else {
|
||||||
|
return mainLoop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||||
|
{
|
||||||
|
// general initialization
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
ARG->m_synergyAddress = new CNetworkAddress;
|
||||||
|
ARG->m_config = new CConfig;
|
||||||
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
|
// install caller's output filter
|
||||||
|
if (outputter != NULL) {
|
||||||
|
CLOG->insert(outputter);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
appThread.wait(-1.0);
|
// save log messages
|
||||||
#endif
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
|
||||||
appThread.cancel();
|
|
||||||
appThread.wait(-1.0);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// command line parsing
|
// command line parsing
|
||||||
|
@ -606,7 +653,7 @@ parse(int argc, const char* const* argv)
|
||||||
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
||||||
// save listen address
|
// save listen address
|
||||||
try {
|
try {
|
||||||
ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
|
*ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
|
||||||
kDefaultPort);
|
kDefaultPort);
|
||||||
}
|
}
|
||||||
catch (XSocketAddress& e) {
|
catch (XSocketAddress& e) {
|
||||||
|
@ -723,7 +770,7 @@ loadConfig(const char* pathname)
|
||||||
if (!configStream) {
|
if (!configStream) {
|
||||||
throw XConfigRead("cannot open file");
|
throw XConfigRead("cannot open file");
|
||||||
}
|
}
|
||||||
configStream >> ARG->m_config;
|
configStream >> *ARG->m_config;
|
||||||
LOG((CLOG_DEBUG "configuration read successfully"));
|
LOG((CLOG_DEBUG "configuration read successfully"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -828,198 +875,108 @@ byeThrow(int x)
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
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);
|
parse(argc, argv);
|
||||||
|
|
||||||
// cannot run as backend if running as a service
|
|
||||||
ARG->m_backend = false;
|
ARG->m_backend = false;
|
||||||
|
|
||||||
// load configuration
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
return CArchMiscWindows::runDaemon(mainLoop);
|
||||||
// run as a service
|
|
||||||
return CArchMiscWindows::runDaemon(realMain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
daemonStartup95(int, const char**)
|
daemonNTStartup(int, char**)
|
||||||
{
|
{
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
return runMainInThread();
|
bye = &byeThrow;
|
||||||
|
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
void
|
||||||
run(int argc, char** argv)
|
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
|
||||||
{
|
{
|
||||||
|
CString fmt = CMSWindowsUtil::getString(instance, id);
|
||||||
|
CString msg = CStringUtil::format(fmt.c_str(), arg);
|
||||||
|
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WINAPI
|
||||||
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
CArch arch(instance);
|
||||||
|
CMSWindowsScreen::init(instance);
|
||||||
|
CLOG;
|
||||||
|
// FIXME
|
||||||
|
// CThread::getCurrentThread().setPriority(-14);
|
||||||
|
CArgs args;
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
// windows NT family starts services using no command line options.
|
||||||
// since i'm not sure how to tell the difference between that and
|
// 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
|
// 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.
|
// 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
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
// of the service code path.
|
// of the service code path.
|
||||||
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
StartupFunc startup = &standardStartup;
|
||||||
try {
|
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
startup = &daemonNTStartup;
|
||||||
}
|
}
|
||||||
catch (XArchDaemon& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
|
||||||
}
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(argc, argv);
|
|
||||||
|
|
||||||
// load configuration
|
|
||||||
loadConfig();
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
if (ARG->m_daemon) {
|
|
||||||
// start as a daemon
|
|
||||||
if (CArchMiscWindows::isWindows95Family()) {
|
|
||||||
try {
|
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
|
||||||
}
|
|
||||||
catch (XArchDaemon& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
|
||||||
}
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// cannot start a service from the command line so just
|
|
||||||
// run normally (except with log messages redirected).
|
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
|
||||||
return runMainInThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// run
|
|
||||||
return runMainInThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WINAPI
|
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|
||||||
{
|
|
||||||
CArch arch(instance);
|
|
||||||
CLOG;
|
|
||||||
CArgs args;
|
|
||||||
|
|
||||||
// save instance
|
|
||||||
CMSWindowsScreen::init(instance);
|
|
||||||
|
|
||||||
// get program name
|
|
||||||
ARG->m_pname = ARCH->getBasename(__argv[0]);
|
|
||||||
|
|
||||||
// send PRINT and FATAL output to a message box
|
// send PRINT and FATAL output to a message box
|
||||||
CLOG->insert(new CMessageBoxOutputter);
|
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
|
||||||
|
|
||||||
// save log messages
|
|
||||||
CBufferedLogOutputter logBuffer(1000);
|
|
||||||
CLOG->insert(&logBuffer, true);
|
|
||||||
|
|
||||||
// make the task bar receiver. the user can control this app
|
|
||||||
// through the task bar.
|
|
||||||
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance,
|
|
||||||
&logBuffer);
|
|
||||||
|
|
||||||
int result;
|
|
||||||
try {
|
|
||||||
// run in foreground or as a daemon
|
|
||||||
result = run(__argc, __argv);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// note that we don't rethrow thread cancellation. we'll
|
|
||||||
// be exiting soon so it doesn't matter. what we'd like
|
|
||||||
// is for everything after this try/catch to be in a
|
|
||||||
// finally block.
|
|
||||||
result = kExitFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// done with task bar receiver
|
|
||||||
delete s_taskBarReceiver;
|
|
||||||
|
|
||||||
// done with log buffer
|
|
||||||
CLOG->remove(&logBuffer);
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
// let user examine any messages if we're running as a backend
|
||||||
// by putting up a dialog box before exiting.
|
// by putting up a dialog box before exiting.
|
||||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
if (args.m_backend && s_hasImportantLogMessages) {
|
||||||
char msg[1024];
|
showError(instance, args.m_pname, IDS_FAILED, "");
|
||||||
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;
|
delete CLOG;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (XArch& e) {
|
||||||
|
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
daemonStartup(int, const char**)
|
|
||||||
{
|
|
||||||
CSystemLogger sysLogger(DAEMON_NAME);
|
|
||||||
return realMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char** argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
CArgs args;
|
||||||
|
try {
|
||||||
|
int result;
|
||||||
CArch arch;
|
CArch arch;
|
||||||
CLOG;
|
CLOG;
|
||||||
|
|
||||||
// go really fast
|
|
||||||
CThread::getCurrentThread().setPriority(-14);
|
|
||||||
|
|
||||||
CSocketMultiplexer multiplexer;
|
|
||||||
CEventQueue eventQueue;
|
|
||||||
|
|
||||||
// get program name
|
|
||||||
CArgs args;
|
CArgs args;
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
result = run(argc, argv, NULL, &standardStartup);
|
||||||
|
delete CLOG;
|
||||||
// make the task bar receiver. the user can control this app
|
|
||||||
// through the task bar.
|
|
||||||
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(argc, argv);
|
|
||||||
|
|
||||||
// load configuration
|
|
||||||
loadConfig();
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
int result;
|
|
||||||
if (ARG->m_daemon) {
|
|
||||||
try {
|
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
|
||||||
}
|
|
||||||
catch (XArchDaemon&) {
|
|
||||||
LOG((CLOG_CRIT "failed to daemonize"));
|
|
||||||
result = kExitFailed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = realMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
// done with task bar receiver
|
|
||||||
delete s_taskBarReceiver;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (XArch& e) {
|
||||||
|
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,8 @@ END
|
||||||
STRINGTABLE DISCARDABLE
|
STRINGTABLE DISCARDABLE
|
||||||
BEGIN
|
BEGIN
|
||||||
IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
|
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
|
END
|
||||||
|
|
||||||
#endif // English (U.S.) resources
|
#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 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
|
dnl adjust variables for X11 and pthreads
|
||||||
CXXFLAGS="$CXXFLAGS $SYNERGY_CXXFLAGS $X_CFLAGS $PTHREAD_CFLAGS -D_BSD_SOURCE -D_XOPEN_SOURCE=500"
|
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);
|
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
|
bool
|
||||||
CArch::isSameThread(CArchThread thread1, CArchThread thread2)
|
CArch::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
{
|
{
|
||||||
|
@ -390,13 +378,13 @@ CArch::getIDOfThread(CArchThread thread)
|
||||||
void
|
void
|
||||||
CArch::setInterruptHandler(InterruptFunc func, void* userData)
|
CArch::setInterruptHandler(InterruptFunc func, void* userData)
|
||||||
{
|
{
|
||||||
return m_mt->setInterruptHandler(func, userData);
|
m_mt->setInterruptHandler(func, userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArch::interrupt()
|
CArch::interrupt()
|
||||||
{
|
{
|
||||||
return m_mt->interrupt();
|
m_mt->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
CArchSocket
|
CArchSocket
|
||||||
|
@ -459,6 +447,12 @@ CArch::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
return m_net->pollSocket(pe, num, timeout);
|
return m_net->pollSocket(pe, num, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::unblockPollSocket(CArchThread thread)
|
||||||
|
{
|
||||||
|
m_net->unblockPollSocket(thread);
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CArch::readSocket(CArchSocket s, void* buf, size_t len)
|
CArch::readSocket(CArchSocket s, void* buf, size_t len)
|
||||||
{
|
{
|
||||||
|
|
|
@ -116,8 +116,6 @@ public:
|
||||||
virtual void setPriorityOfThread(CArchThread, int n);
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
virtual void testCancelThread();
|
virtual void testCancelThread();
|
||||||
virtual bool wait(CArchThread, double timeout);
|
virtual bool wait(CArchThread, double timeout);
|
||||||
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
|
||||||
virtual void unblockThread(CArchThread thread);
|
|
||||||
virtual bool isSameThread(CArchThread, CArchThread);
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
@ -136,6 +134,7 @@ public:
|
||||||
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
||||||
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
||||||
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
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 readSocket(CArchSocket s, void* buf, size_t len);
|
||||||
virtual size_t writeSocket(CArchSocket s,
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
const void* buf, size_t len);
|
const void* buf, size_t len);
|
||||||
|
|
|
@ -110,7 +110,7 @@ CArchConsoleWindows::getNewlineForConsole()
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
CArchConsoleWindows::signalHandler(DWORD)
|
CArchConsoleWindows::signalHandler(DWORD)
|
||||||
{
|
{
|
||||||
// terminate thread and skip remaining handlers
|
// terminate app and skip remaining handlers
|
||||||
ARCH->cancelThread(s_thread);
|
ARCH->interrupt();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,9 @@
|
||||||
|
|
||||||
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
|
CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
|
||||||
|
|
||||||
CArchDaemonWindows::CArchDaemonWindows() :
|
CArchDaemonWindows::CArchDaemonWindows()
|
||||||
m_daemonThread(NULL)
|
|
||||||
{
|
{
|
||||||
// do nothing
|
m_quitMessage = RegisterWindowMessage("SynergyDaemonExit");
|
||||||
}
|
}
|
||||||
|
|
||||||
CArchDaemonWindows::~CArchDaemonWindows()
|
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
|
void
|
||||||
CArchDaemonWindows::daemonFailed(int result)
|
CArchDaemonWindows::daemonFailed(int result)
|
||||||
{
|
{
|
||||||
|
@ -437,6 +447,20 @@ CArchDaemonWindows::openUserStartupKey()
|
||||||
return CArchMiscWindows::openKey(HKEY_CURRENT_USER, s_keyNames);
|
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
|
int
|
||||||
CArchDaemonWindows::doRunDaemon(RunFunc run)
|
CArchDaemonWindows::doRunDaemon(RunFunc run)
|
||||||
{
|
{
|
||||||
|
@ -444,115 +468,68 @@ CArchDaemonWindows::doRunDaemon(RunFunc run)
|
||||||
assert(m_serviceMutex != NULL);
|
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);
|
ARCH->lockMutex(m_serviceMutex);
|
||||||
try {
|
m_daemonThreadID = GetCurrentThreadId();
|
||||||
int result;
|
while (m_serviceState != SERVICE_STOPPED) {
|
||||||
m_serviceHandlerWaiting = false;
|
// wait until we're told to start
|
||||||
m_serviceRunning = false;
|
while (!isRunState(m_serviceState) &&
|
||||||
for (;;) {
|
m_serviceState != SERVICE_STOP_PENDING) {
|
||||||
// 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);
|
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit loop if we've been told to stop
|
// run unless told to stop
|
||||||
if (m_serviceState == SERVICE_STOPPED) {
|
if (m_serviceState != SERVICE_STOP_PENDING) {
|
||||||
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);
|
ARCH->unlockMutex(m_serviceMutex);
|
||||||
|
try {
|
||||||
return result;
|
result = run();
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// FIXME -- report error
|
ARCH->lockMutex(m_serviceMutex);
|
||||||
|
|
||||||
// prevent serviceHandler from changing state
|
|
||||||
m_serviceState = SERVICE_STOPPED;
|
|
||||||
|
|
||||||
// set status
|
|
||||||
setStatusError(0);
|
setStatusError(0);
|
||||||
|
m_serviceState = SERVICE_STOPPED;
|
||||||
// wake up serviceHandler if it's waiting then wait for it
|
setStatus(m_serviceState);
|
||||||
if (m_serviceHandlerWaiting) {
|
|
||||||
m_serviceHandlerWaiting = false;
|
|
||||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
|
||||||
// serviceHandler has exited by now
|
|
||||||
}
|
|
||||||
|
|
||||||
ARCH->unlockMutex(m_serviceMutex);
|
ARCH->unlockMutex(m_serviceMutex);
|
||||||
throw;
|
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
|
void
|
||||||
CArchDaemonWindows::doDaemonRunning(bool running)
|
CArchDaemonWindows::doDaemonRunning(bool running)
|
||||||
{
|
{
|
||||||
|
ARCH->lockMutex(m_serviceMutex);
|
||||||
if (running) {
|
if (running) {
|
||||||
|
m_serviceState = SERVICE_RUNNING;
|
||||||
|
setStatus(m_serviceState);
|
||||||
|
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||||
|
}
|
||||||
ARCH->unlockMutex(m_serviceMutex);
|
ARCH->unlockMutex(m_serviceMutex);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ARCH->lockMutex(m_serviceMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
UINT
|
||||||
CArchDaemonWindows::runDaemonThread(RunFunc run)
|
CArchDaemonWindows::doGetDaemonQuitMessage()
|
||||||
{
|
{
|
||||||
return reinterpret_cast<void*>(run());
|
return m_quitMessage;
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
CArchDaemonWindows::runDaemonThreadEntry(void* vrun)
|
|
||||||
{
|
|
||||||
assert(s_daemon != NULL);
|
|
||||||
|
|
||||||
return s_daemon->runDaemonThread(reinterpret_cast<RunFunc>(vrun));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -583,6 +560,8 @@ CArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
|
||||||
void
|
void
|
||||||
CArchDaemonWindows::setStatusError(DWORD error)
|
CArchDaemonWindows::setStatusError(DWORD error)
|
||||||
{
|
{
|
||||||
|
assert(s_daemon != NULL);
|
||||||
|
|
||||||
SERVICE_STATUS status;
|
SERVICE_STATUS status;
|
||||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
|
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
|
||||||
SERVICE_INTERACTIVE_PROCESS;
|
SERVICE_INTERACTIVE_PROCESS;
|
||||||
|
@ -607,9 +586,8 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
|
||||||
// create synchronization objects
|
// create synchronization objects
|
||||||
m_serviceMutex = ARCH->newMutex();
|
m_serviceMutex = ARCH->newMutex();
|
||||||
m_serviceCondVar = ARCH->newCondVar();
|
m_serviceCondVar = ARCH->newCondVar();
|
||||||
m_serviceState = SERVICE_RUNNING;
|
|
||||||
|
|
||||||
// register our service handler functiom
|
// register our service handler function
|
||||||
m_statusHandle = RegisterServiceCtrlHandler(argv[0],
|
m_statusHandle = RegisterServiceCtrlHandler(argv[0],
|
||||||
&CArchDaemonWindows::serviceHandlerEntry);
|
&CArchDaemonWindows::serviceHandlerEntry);
|
||||||
if (m_statusHandle == NULL) {
|
if (m_statusHandle == NULL) {
|
||||||
|
@ -621,7 +599,8 @@ CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell service control manager that we're starting
|
// 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.
|
// if no arguments supplied then try getting them from the registry.
|
||||||
// the first argument doesn't count because it's the service name.
|
// the first argument doesn't count because it's the service name.
|
||||||
|
@ -726,58 +705,40 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
|
||||||
ARCH->lockMutex(m_serviceMutex);
|
ARCH->lockMutex(m_serviceMutex);
|
||||||
|
|
||||||
// ignore request if service is already stopped
|
// ignore request if service is already stopped
|
||||||
if (m_serviceState == SERVICE_STOPPED) {
|
if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) {
|
||||||
|
if (s_daemon != NULL) {
|
||||||
setStatus(m_serviceState);
|
setStatus(m_serviceState);
|
||||||
|
}
|
||||||
ARCH->unlockMutex(m_serviceMutex);
|
ARCH->unlockMutex(m_serviceMutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ctrl) {
|
switch (ctrl) {
|
||||||
case SERVICE_CONTROL_PAUSE:
|
case SERVICE_CONTROL_PAUSE:
|
||||||
// update state
|
|
||||||
m_serviceState = SERVICE_PAUSE_PENDING;
|
m_serviceState = SERVICE_PAUSE_PENDING;
|
||||||
setStatus(m_serviceState, 0, 5000);
|
setStatus(m_serviceState, 0, 5000);
|
||||||
|
PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
|
||||||
// stop run callback if running and wait for it to finish
|
while (isRunState(m_serviceState)) {
|
||||||
if (m_serviceRunning) {
|
|
||||||
m_serviceHandlerWaiting = true;
|
|
||||||
ARCH->cancelThread(m_daemonThread);
|
|
||||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
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;
|
break;
|
||||||
|
|
||||||
case SERVICE_CONTROL_CONTINUE:
|
case SERVICE_CONTROL_CONTINUE:
|
||||||
// required status update
|
// FIXME -- maybe should flush quit messages from queue
|
||||||
setStatus(m_serviceState);
|
m_serviceState = SERVICE_CONTINUE_PENDING;
|
||||||
|
setStatus(m_serviceState, 0, 5000);
|
||||||
// update state but let main loop send RUNNING notification
|
|
||||||
m_serviceState = SERVICE_RUNNING;
|
|
||||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||||
ARCH->unlockMutex(m_serviceMutex);
|
break;
|
||||||
return;
|
|
||||||
|
|
||||||
case SERVICE_CONTROL_STOP:
|
case SERVICE_CONTROL_STOP:
|
||||||
case SERVICE_CONTROL_SHUTDOWN:
|
case SERVICE_CONTROL_SHUTDOWN:
|
||||||
// update state
|
|
||||||
m_serviceState = SERVICE_STOP_PENDING;
|
m_serviceState = SERVICE_STOP_PENDING;
|
||||||
setStatus(m_serviceState, 0, 5000);
|
setStatus(m_serviceState, 0, 5000);
|
||||||
|
PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
|
||||||
// stop run callback if running and wait for it to finish
|
ARCH->broadcastCondVar(m_serviceCondVar);
|
||||||
if (m_serviceRunning) {
|
while (isRunState(m_serviceState)) {
|
||||||
m_serviceHandlerWaiting = true;
|
|
||||||
ARCH->cancelThread(m_daemonThread);
|
|
||||||
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update state
|
|
||||||
m_serviceState = SERVICE_STOPPED;
|
|
||||||
ARCH->broadcastCondVar(m_serviceCondVar);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -785,12 +746,10 @@ CArchDaemonWindows::serviceHandler(DWORD ctrl)
|
||||||
// fall through
|
// fall through
|
||||||
|
|
||||||
case SERVICE_CONTROL_INTERROGATE:
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
setStatus(m_serviceState);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send update
|
|
||||||
setStatus(m_serviceState);
|
|
||||||
|
|
||||||
ARCH->unlockMutex(m_serviceMutex);
|
ARCH->unlockMutex(m_serviceMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
(i.e. after initialization) and \c daemonRunning(false) when it leaves
|
(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
|
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
|
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
|
what \c runFunc returns. \c runFunc should call \c daemonFailed() if
|
||||||
the daemon fails.
|
the daemon fails.
|
||||||
*/
|
*/
|
||||||
|
@ -63,6 +63,14 @@ public:
|
||||||
*/
|
*/
|
||||||
static void daemonFailed(int result);
|
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
|
// IArchDaemon overrides
|
||||||
virtual void installDaemon(const char* name,
|
virtual void installDaemon(const char* name,
|
||||||
const char* description,
|
const char* description,
|
||||||
|
@ -81,13 +89,13 @@ private:
|
||||||
|
|
||||||
int doRunDaemon(RunFunc runFunc);
|
int doRunDaemon(RunFunc runFunc);
|
||||||
void doDaemonRunning(bool running);
|
void doDaemonRunning(bool running);
|
||||||
|
UINT doGetDaemonQuitMessage();
|
||||||
|
|
||||||
static void setStatus(DWORD state);
|
static void setStatus(DWORD state);
|
||||||
static void setStatus(DWORD state, DWORD step, DWORD waitHint);
|
static void setStatus(DWORD state, DWORD step, DWORD waitHint);
|
||||||
static void setStatusError(DWORD error);
|
static void setStatusError(DWORD error);
|
||||||
|
|
||||||
void* runDaemonThread(RunFunc);
|
static bool isRunState(DWORD state);
|
||||||
static void* runDaemonThreadEntry(void*);
|
|
||||||
|
|
||||||
void serviceMain(DWORD, LPTSTR*);
|
void serviceMain(DWORD, LPTSTR*);
|
||||||
static void WINAPI serviceMainEntry(DWORD, LPTSTR*);
|
static void WINAPI serviceMainEntry(DWORD, LPTSTR*);
|
||||||
|
@ -113,11 +121,13 @@ private:
|
||||||
bool m_serviceHandlerWaiting;
|
bool m_serviceHandlerWaiting;
|
||||||
bool m_serviceRunning;
|
bool m_serviceRunning;
|
||||||
|
|
||||||
CArchThread m_daemonThread;
|
DWORD m_daemonThreadID;
|
||||||
DaemonFunc m_daemonFunc;
|
DaemonFunc m_daemonFunc;
|
||||||
int m_daemonResult;
|
int m_daemonResult;
|
||||||
|
|
||||||
SERVICE_STATUS_HANDLE m_statusHandle;
|
SERVICE_STATUS_HANDLE m_statusHandle;
|
||||||
|
|
||||||
|
UINT m_quitMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,9 +19,12 @@
|
||||||
// CArchMiscWindows
|
// CArchMiscWindows
|
||||||
//
|
//
|
||||||
|
|
||||||
|
CArchMiscWindows::CDialogs* CArchMiscWindows::s_dialogs = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchMiscWindows::init()
|
CArchMiscWindows::init()
|
||||||
{
|
{
|
||||||
|
s_dialogs = new CDialogs;
|
||||||
isWindows95Family();
|
isWindows95Family();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +67,12 @@ CArchMiscWindows::daemonFailed(int result)
|
||||||
CArchDaemonWindows::daemonFailed(result);
|
CArchDaemonWindows::daemonFailed(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT
|
||||||
|
CArchMiscWindows::getDaemonQuitMessage()
|
||||||
|
{
|
||||||
|
return CArchDaemonWindows::getDaemonQuitMessage();
|
||||||
|
}
|
||||||
|
|
||||||
HKEY
|
HKEY
|
||||||
CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName)
|
CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName)
|
||||||
{
|
{
|
||||||
|
@ -196,3 +205,27 @@ CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name)
|
||||||
}
|
}
|
||||||
return value;
|
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 "common.h"
|
||||||
#include "stdstring.h"
|
#include "stdstring.h"
|
||||||
|
#include "stdset.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
//! Miscellaneous win32 functions.
|
//! Miscellaneous win32 functions.
|
||||||
|
@ -53,6 +54,12 @@ public:
|
||||||
*/
|
*/
|
||||||
static void daemonFailed(int result);
|
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
|
//! Open and return a registry key, closing the parent key
|
||||||
static HKEY openKey(HKEY parent, const TCHAR* child);
|
static HKEY openKey(HKEY parent, const TCHAR* child);
|
||||||
|
|
||||||
|
@ -83,6 +90,24 @@ public:
|
||||||
|
|
||||||
//! Read a DWORD value from the registry
|
//! Read a DWORD value from the registry
|
||||||
static DWORD readValueInt(HKEY, const TCHAR* name);
|
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
|
#endif
|
||||||
|
|
|
@ -134,6 +134,18 @@ CArchMultithreadPosix::~CArchMultithreadPosix()
|
||||||
s_instance = NULL;
|
s_instance = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMultithreadPosix::unblockThread(CArchThread thread)
|
||||||
|
{
|
||||||
|
pthread_kill(thread->m_thread, SIGWAKEUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchMultithreadPosix*
|
||||||
|
CArchMultithreadPosix::getInstance()
|
||||||
|
{
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
CArchCond
|
CArchCond
|
||||||
CArchMultithreadPosix::newCondVar()
|
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
|
bool
|
||||||
CArchMultithreadPosix::isSameThread(CArchThread thread1, CArchThread thread2)
|
CArchMultithreadPosix::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
{
|
{
|
||||||
|
@ -575,7 +574,7 @@ CArchMultithreadPosix::interrupt()
|
||||||
lockMutex(m_threadMutex);
|
lockMutex(m_threadMutex);
|
||||||
if (m_signalFunc != NULL) {
|
if (m_signalFunc != NULL) {
|
||||||
m_signalFunc(m_signalUserData);
|
m_signalFunc(m_signalUserData);
|
||||||
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
|
unblockThread(m_mainThread);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ARCH->cancelThread(m_mainThread);
|
ARCH->cancelThread(m_mainThread);
|
||||||
|
|
|
@ -37,6 +37,19 @@ public:
|
||||||
CArchMultithreadPosix();
|
CArchMultithreadPosix();
|
||||||
virtual ~CArchMultithreadPosix();
|
virtual ~CArchMultithreadPosix();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
void unblockThread(CArchThread thread);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
static CArchMultithreadPosix* getInstance();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
// IArchMultithread overrides
|
// IArchMultithread overrides
|
||||||
virtual CArchCond newCondVar();
|
virtual CArchCond newCondVar();
|
||||||
virtual void closeCondVar(CArchCond);
|
virtual void closeCondVar(CArchCond);
|
||||||
|
@ -55,8 +68,6 @@ public:
|
||||||
virtual void setPriorityOfThread(CArchThread, int n);
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
virtual void testCancelThread();
|
virtual void testCancelThread();
|
||||||
virtual bool wait(CArchThread, double timeout);
|
virtual bool wait(CArchThread, double timeout);
|
||||||
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
|
||||||
virtual void unblockThread(CArchThread thread);
|
|
||||||
virtual bool isSameThread(CArchThread, CArchThread);
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
bool m_cancelling;
|
bool m_cancelling;
|
||||||
HANDLE m_exit;
|
HANDLE m_exit;
|
||||||
void* m_result;
|
void* m_result;
|
||||||
|
void* m_networkData;
|
||||||
};
|
};
|
||||||
|
|
||||||
CArchThreadImpl::CArchThreadImpl() :
|
CArchThreadImpl::CArchThreadImpl() :
|
||||||
|
@ -59,7 +60,8 @@ CArchThreadImpl::CArchThreadImpl() :
|
||||||
m_func(NULL),
|
m_func(NULL),
|
||||||
m_userData(NULL),
|
m_userData(NULL),
|
||||||
m_cancelling(false),
|
m_cancelling(false),
|
||||||
m_result(NULL)
|
m_result(NULL),
|
||||||
|
m_networkData(NULL)
|
||||||
{
|
{
|
||||||
m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
|
m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
m_cancel = 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::s_instance = NULL;
|
||||||
|
|
||||||
CArchMultithreadWindows::CArchMultithreadWindows()
|
CArchMultithreadWindows::CArchMultithreadWindows() :
|
||||||
|
m_signalFunc(NULL),
|
||||||
|
m_signalUserData(NULL)
|
||||||
{
|
{
|
||||||
assert(s_instance == NULL);
|
assert(s_instance == NULL);
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
@ -88,10 +92,10 @@ CArchMultithreadWindows::CArchMultithreadWindows()
|
||||||
|
|
||||||
// create thread for calling (main) thread and add it to our
|
// create thread for calling (main) thread and add it to our
|
||||||
// list. no need to lock the mutex since we're the only thread.
|
// list. no need to lock the mutex since we're the only thread.
|
||||||
CArchThreadImpl* mainThread = new CArchThreadImpl;
|
m_mainThread = new CArchThreadImpl;
|
||||||
mainThread->m_thread = NULL;
|
m_mainThread->m_thread = NULL;
|
||||||
mainThread->m_id = GetCurrentThreadId();
|
m_mainThread->m_id = GetCurrentThreadId();
|
||||||
insert(mainThread);
|
insert(m_mainThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
CArchMultithreadWindows::~CArchMultithreadWindows()
|
CArchMultithreadWindows::~CArchMultithreadWindows()
|
||||||
|
@ -108,6 +112,24 @@ CArchMultithreadWindows::~CArchMultithreadWindows()
|
||||||
delete m_threadMutex;
|
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
|
HANDLE
|
||||||
CArchMultithreadWindows::getCancelEventForCurrentThread()
|
CArchMultithreadWindows::getCancelEventForCurrentThread()
|
||||||
{
|
{
|
||||||
|
@ -183,7 +205,7 @@ CArchMultithreadWindows::waitCondVar(CArchCond cond,
|
||||||
|
|
||||||
// make a list of the condition variable events and the cancel event
|
// make a list of the condition variable events and the cancel event
|
||||||
// for the current thread.
|
// for the current thread.
|
||||||
HANDLE handles[3];
|
HANDLE handles[4];
|
||||||
handles[0] = cond->m_events[CArchCondImpl::kSignal];
|
handles[0] = cond->m_events[CArchCondImpl::kSignal];
|
||||||
handles[1] = cond->m_events[CArchCondImpl::kBroadcast];
|
handles[1] = cond->m_events[CArchCondImpl::kBroadcast];
|
||||||
handles[2] = getCancelEventForCurrentThread();
|
handles[2] = getCancelEventForCurrentThread();
|
||||||
|
@ -446,8 +468,8 @@ CArchMultithreadWindows::wait(CArchThread target, double timeout)
|
||||||
t = (DWORD)(1000.0 * timeout);
|
t = (DWORD)(1000.0 * timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for this thread to be cancelled or for the target thread to
|
// wait for this thread to be cancelled or woken up or for the
|
||||||
// terminate.
|
// target thread to terminate.
|
||||||
HANDLE handles[2];
|
HANDLE handles[2];
|
||||||
handles[0] = target->m_exit;
|
handles[0] = target->m_exit;
|
||||||
handles[1] = self->m_cancel;
|
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
|
bool
|
||||||
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
|
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
{
|
{
|
||||||
|
@ -637,6 +528,29 @@ CArchMultithreadWindows::getIDOfThread(CArchThread thread)
|
||||||
return static_cast<ThreadID>(thread->m_id);
|
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*
|
CArchThreadImpl*
|
||||||
CArchMultithreadWindows::find(DWORD id)
|
CArchMultithreadWindows::find(DWORD id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,12 +43,20 @@ public:
|
||||||
CArchMultithreadWindows();
|
CArchMultithreadWindows();
|
||||||
virtual ~CArchMultithreadWindows();
|
virtual ~CArchMultithreadWindows();
|
||||||
|
|
||||||
|
//
|
||||||
|
// manipulators
|
||||||
|
//
|
||||||
|
|
||||||
|
void setNetworkDataForCurrentThread(void*);
|
||||||
|
|
||||||
//
|
//
|
||||||
// accessors
|
// accessors
|
||||||
//
|
//
|
||||||
|
|
||||||
HANDLE getCancelEventForCurrentThread();
|
HANDLE getCancelEventForCurrentThread();
|
||||||
|
|
||||||
|
void* getNetworkDataForThread(CArchThread);
|
||||||
|
|
||||||
static CArchMultithreadWindows* getInstance();
|
static CArchMultithreadWindows* getInstance();
|
||||||
|
|
||||||
// IArchMultithread overrides
|
// IArchMultithread overrides
|
||||||
|
@ -69,11 +77,12 @@ public:
|
||||||
virtual void setPriorityOfThread(CArchThread, int n);
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
virtual void testCancelThread();
|
virtual void testCancelThread();
|
||||||
virtual bool wait(CArchThread, double timeout);
|
virtual bool wait(CArchThread, double timeout);
|
||||||
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
|
||||||
virtual bool isSameThread(CArchThread, CArchThread);
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
virtual ThreadID getIDOfThread(CArchThread);
|
virtual ThreadID getIDOfThread(CArchThread);
|
||||||
|
virtual void setInterruptHandler(InterruptFunc, void*);
|
||||||
|
virtual void interrupt();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CArchThreadImpl* find(DWORD id);
|
CArchThreadImpl* find(DWORD id);
|
||||||
|
@ -96,6 +105,10 @@ private:
|
||||||
CArchMutex m_threadMutex;
|
CArchMutex m_threadMutex;
|
||||||
|
|
||||||
CThreadList m_threadList;
|
CThreadList m_threadList;
|
||||||
|
CArchThread m_mainThread;
|
||||||
|
|
||||||
|
InterruptFunc m_signalFunc;
|
||||||
|
void* m_signalUserData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -424,6 +424,12 @@ CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkBSD::unblockPollSocket(CArchThread thread)
|
||||||
|
{
|
||||||
|
CArchMultithreadPosix::getInstance()->unblockThread(thread);
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
|
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 (n == -1) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
n = 0;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
else if (errno == EAGAIN) {
|
else if (errno == EAGAIN) {
|
||||||
n = 0;
|
n = 0;
|
||||||
|
@ -460,8 +466,8 @@ CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
n = 0;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
else if (errno == EAGAIN) {
|
else if (errno == EAGAIN) {
|
||||||
// no buffer space
|
// no buffer space
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
||||||
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
||||||
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
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 readSocket(CArchSocket s, void* buf, size_t len);
|
||||||
virtual size_t writeSocket(CArchSocket s,
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
const void* buf, size_t len);
|
const void* buf, size_t len);
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
|
|
||||||
#include "CArchNetworkWinsock.h"
|
#include "CArchNetworkWinsock.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
#include "XArchWindows.h"
|
#include "XArchWindows.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
static const int s_family[] = {
|
static const int s_family[] = {
|
||||||
PF_UNSPEC,
|
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 struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name);
|
||||||
static int (PASCAL FAR *WSACleanup_winsock)(void);
|
static int (PASCAL FAR *WSACleanup_winsock)(void);
|
||||||
static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset);
|
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
|
#undef FD_ISSET
|
||||||
#define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
|
#define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
|
||||||
|
@ -68,13 +77,23 @@ netGetProcAddress(HMODULE module, LPCSTR name)
|
||||||
return func;
|
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::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(WSACleanup_winsock == NULL);
|
||||||
assert(s_networkModule == NULL);
|
assert(s_networkModule == NULL);
|
||||||
|
@ -110,14 +129,16 @@ CArchNetworkWinsock::~CArchNetworkWinsock()
|
||||||
void
|
void
|
||||||
CArchNetworkWinsock::init(HMODULE module)
|
CArchNetworkWinsock::init(HMODULE module)
|
||||||
{
|
{
|
||||||
assert(module != NULL);
|
if (module == NULL) {
|
||||||
|
throw XArchNetworkSupport("");
|
||||||
|
}
|
||||||
|
|
||||||
// get startup function address
|
// get startup function address
|
||||||
int (PASCAL FAR *startup)(WORD, LPWSADATA);
|
int (PASCAL FAR *startup)(WORD, LPWSADATA);
|
||||||
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
|
setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
|
||||||
|
|
||||||
// startup network library
|
// startup network library
|
||||||
WORD version = MAKEWORD(1 /*major*/, 1 /*minor*/);
|
WORD version = MAKEWORD(2 /*major*/, 0 /*minor*/);
|
||||||
WSADATA data;
|
WSADATA data;
|
||||||
int err = startup(version, &data);
|
int err = startup(version, &data);
|
||||||
if (data.wVersion != version) {
|
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(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
|
||||||
setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
|
setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
|
||||||
setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *));
|
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;
|
s_networkModule = module;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +199,8 @@ CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
|
||||||
socket->m_socket = fd;
|
socket->m_socket = fd;
|
||||||
socket->m_connected = false;
|
socket->m_connected = false;
|
||||||
socket->m_refCount = 1;
|
socket->m_refCount = 1;
|
||||||
|
socket->m_event = WSACreateEvent_winsock();
|
||||||
|
socket->m_pollWrite = false;
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +232,7 @@ CArchNetworkWinsock::closeSocket(CArchSocket s)
|
||||||
if (close_winsock(s->m_socket) == SOCKET_ERROR) {
|
if (close_winsock(s->m_socket) == SOCKET_ERROR) {
|
||||||
// close failed
|
// close failed
|
||||||
int err = getsockerror_winsock();
|
int err = getsockerror_winsock();
|
||||||
if (err == EINTR) {
|
if (err == WSAEINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
ARCH->testCancelThread();
|
||||||
continue;
|
continue;
|
||||||
|
@ -215,6 +245,7 @@ CArchNetworkWinsock::closeSocket(CArchSocket s)
|
||||||
throwError(err);
|
throwError(err);
|
||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
|
WSACloseEvent_winsock(s->m_event);
|
||||||
delete s;
|
delete s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,35 +301,24 @@ CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
|
||||||
{
|
{
|
||||||
assert(s != NULL);
|
assert(s != NULL);
|
||||||
|
|
||||||
// if user passed NULL in addr then use scratch space
|
// create new socket and temporary address
|
||||||
CArchNetAddress dummy;
|
|
||||||
if (addr == NULL) {
|
|
||||||
addr = &dummy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new socket and address
|
|
||||||
CArchSocketImpl* socket = new CArchSocketImpl;
|
CArchSocketImpl* socket = new CArchSocketImpl;
|
||||||
*addr = new CArchNetAddressImpl;
|
CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr));
|
||||||
|
|
||||||
// accept on socket
|
// accept on socket
|
||||||
SOCKET fd;
|
SOCKET fd;
|
||||||
do {
|
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) {
|
if (fd == INVALID_SOCKET) {
|
||||||
int err = getsockerror_winsock();
|
int err = getsockerror_winsock();
|
||||||
if (err == EINTR) {
|
delete socket;
|
||||||
|
free(tmp);
|
||||||
|
*addr = NULL;
|
||||||
|
if (err == WSAEINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
ARCH->testCancelThread();
|
||||||
continue;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (err == WSAECONNABORTED) {
|
|
||||||
// connection was aborted; try again
|
|
||||||
ARCH->testCancelThread();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
delete socket;
|
|
||||||
delete *addr;
|
|
||||||
*addr = NULL;
|
|
||||||
throwError(err);
|
throwError(err);
|
||||||
}
|
}
|
||||||
} while (false);
|
} while (false);
|
||||||
|
@ -307,12 +327,15 @@ CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
|
||||||
socket->m_socket = fd;
|
socket->m_socket = fd;
|
||||||
socket->m_connected = true;
|
socket->m_connected = true;
|
||||||
socket->m_refCount = 1;
|
socket->m_refCount = 1;
|
||||||
|
socket->m_event = WSACreateEvent_winsock();
|
||||||
|
socket->m_pollWrite = true;
|
||||||
|
|
||||||
// discard address if not requested
|
// copy address if requested
|
||||||
if (addr == &dummy) {
|
if (addr != NULL) {
|
||||||
ARCH->closeAddr(dummy);
|
*addr = ARCH->copyAddr(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +348,7 @@ CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
do {
|
do {
|
||||||
if (connect_winsock(s->m_socket, &addr->m_addr,
|
if (connect_winsock(s->m_socket, &addr->m_addr,
|
||||||
addr->m_len) == SOCKET_ERROR) {
|
addr->m_len) == SOCKET_ERROR) {
|
||||||
if (getsockerror_winsock() == EINTR) {
|
if (getsockerror_winsock() == WSAEINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
ARCH->testCancelThread();
|
||||||
continue;
|
continue;
|
||||||
|
@ -354,19 +377,13 @@ CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
|
||||||
int
|
int
|
||||||
CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
|
CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
{
|
{
|
||||||
int i, n;
|
int i;
|
||||||
|
DWORD n;
|
||||||
|
|
||||||
do {
|
// prepare sockets and wait list
|
||||||
// prepare sets for select
|
bool canWrite = false;
|
||||||
n = 0;
|
WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
|
||||||
fd_set readSet, writeSet, errSet;
|
for (i = 0, n = 0; i < num; ++i) {
|
||||||
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
|
// reset return flags
|
||||||
pe[i].m_revents = 0;
|
pe[i].m_revents = 0;
|
||||||
|
|
||||||
|
@ -376,73 +393,146 @@ CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe[i].m_events & kPOLLIN) {
|
// select desired events
|
||||||
FD_SET(pe[i].m_socket->m_socket, &readSet);
|
long socketEvents = 0;
|
||||||
readSetP = &readSet;
|
if ((pe[i].m_events & kPOLLIN) != 0) {
|
||||||
n = 1;
|
socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
|
||||||
}
|
}
|
||||||
if (pe[i].m_events & kPOLLOUT) {
|
if ((pe[i].m_events & kPOLLOUT) != 0) {
|
||||||
FD_SET(pe[i].m_socket->m_socket, &writeSet);
|
socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
|
||||||
writeSetP = &writeSet;
|
|
||||||
n = 1;
|
// if m_pollWrite is false then we assume the socket is
|
||||||
}
|
// writable. winsock doesn't signal writability except
|
||||||
if (true) {
|
// when the state changes from unwritable.
|
||||||
FD_SET(pe[i].m_socket->m_socket, &errSet);
|
if (!pe[i].m_socket->m_pollWrite) {
|
||||||
errSetP = &errSet;
|
canWrite = true;
|
||||||
n = 1;
|
pe[i].m_revents |= kPOLLOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are no sockets then don't block forever
|
// if no events then ignore socket
|
||||||
if (n == 0 && timeout < 0.0) {
|
if (socketEvents == 0) {
|
||||||
timeout = 0.0;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare timeout for select
|
// select socket for desired events
|
||||||
struct timeval timeout2;
|
WSAEventSelect_winsock(pe[i].m_socket->m_socket,
|
||||||
struct timeval* timeout2P;
|
pe[i].m_socket->m_event, socketEvents);
|
||||||
if (timeout < 0) {
|
|
||||||
timeout2P = NULL;
|
// add socket event to wait list
|
||||||
}
|
events[n++] = pe[i].m_socket->m_event;
|
||||||
else {
|
|
||||||
timeout2P = &timeout2;
|
|
||||||
timeout2.tv_sec = static_cast<int>(timeout);
|
|
||||||
timeout2.tv_usec = static_cast<int>(1.0e+6 *
|
|
||||||
(timeout - timeout2.tv_sec));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// do the select
|
// if no sockets then return immediately
|
||||||
n = select_winsock(0, readSetP, writeSetP, errSetP, timeout2P);
|
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
|
// handle results
|
||||||
if (n == SOCKET_ERROR) {
|
if (result == WSA_WAIT_FAILED) {
|
||||||
if (getsockerror_winsock() == EINTR) {
|
if (getsockerror_winsock() == WSAEINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
ARCH->testCancelThread();
|
||||||
continue;
|
return 0;
|
||||||
}
|
}
|
||||||
throwError(getsockerror_winsock());
|
throwError(getsockerror_winsock());
|
||||||
}
|
}
|
||||||
n = 0;
|
if (result == WSA_WAIT_TIMEOUT && !canWrite) {
|
||||||
for (i = 0; i < num; ++i) {
|
return 0;
|
||||||
if (pe[i].m_socket != NULL) {
|
}
|
||||||
if (FD_ISSET(pe[i].m_socket->m_socket, &readSet)) {
|
if (result == WSA_WAIT_EVENT_0 + n - 1) {
|
||||||
|
// the unblock event was signalled
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0, n = 0; i < num; ++i) {
|
||||||
|
// skip events we didn't check
|
||||||
|
if (pe[i].m_socket == NULL ||
|
||||||
|
(pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get events
|
||||||
|
WSANETWORKEVENTS info;
|
||||||
|
if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
|
||||||
|
pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((info.lNetworkEvents & FD_READ) != 0) {
|
||||||
pe[i].m_revents |= kPOLLIN;
|
pe[i].m_revents |= kPOLLIN;
|
||||||
}
|
}
|
||||||
if (FD_ISSET(pe[i].m_socket->m_socket, &writeSet)) {
|
if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLIN;
|
||||||
|
}
|
||||||
|
if ((info.lNetworkEvents & FD_WRITE) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLOUT;
|
||||||
|
|
||||||
|
// socket is now writable so don't bothing polling for
|
||||||
|
// writable until it becomes unwritable.
|
||||||
|
pe[i].m_socket->m_pollWrite = false;
|
||||||
|
}
|
||||||
|
if ((info.lNetworkEvents & FD_CONNECT) != 0) {
|
||||||
|
if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLERR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pe[i].m_revents |= kPOLLOUT;
|
||||||
|
pe[i].m_socket->m_pollWrite = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((info.lNetworkEvents & FD_CLOSE) != 0) {
|
||||||
|
if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLERR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((pe[i].m_events & kPOLLIN) != 0) {
|
||||||
|
pe[i].m_revents |= kPOLLIN;
|
||||||
|
}
|
||||||
|
if ((pe[i].m_events & kPOLLOUT) != 0) {
|
||||||
pe[i].m_revents |= kPOLLOUT;
|
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) {
|
if (pe[i].m_revents != 0) {
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (false);
|
|
||||||
|
|
||||||
return n;
|
return (int)n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchNetworkWinsock::unblockPollSocket(CArchThread thread)
|
||||||
|
{
|
||||||
|
// set the unblock event
|
||||||
|
CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
|
||||||
|
WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
|
||||||
|
if (unblockEvent != NULL) {
|
||||||
|
WSASetEvent_winsock(*unblockEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
@ -454,10 +544,14 @@ CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
|
||||||
do {
|
do {
|
||||||
n = recv_winsock(s->m_socket, buf, len, 0);
|
n = recv_winsock(s->m_socket, buf, len, 0);
|
||||||
if (n == SOCKET_ERROR) {
|
if (n == SOCKET_ERROR) {
|
||||||
if (getsockerror_winsock() == EINTR) {
|
if (getsockerror_winsock() == WSAEINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
n = 0;
|
||||||
continue;
|
break;
|
||||||
|
}
|
||||||
|
else if (getsockerror_winsock() == WSAEWOULDBLOCK) {
|
||||||
|
n = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
throwError(getsockerror_winsock());
|
throwError(getsockerror_winsock());
|
||||||
}
|
}
|
||||||
|
@ -475,10 +569,15 @@ CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
|
||||||
do {
|
do {
|
||||||
n = send_winsock(s->m_socket, buf, len, 0);
|
n = send_winsock(s->m_socket, buf, len, 0);
|
||||||
if (n == SOCKET_ERROR) {
|
if (n == SOCKET_ERROR) {
|
||||||
if (getsockerror_winsock() == EINTR) {
|
if (getsockerror_winsock() == WSAEINTR) {
|
||||||
// interrupted system call
|
// interrupted system call
|
||||||
ARCH->testCancelThread();
|
n = 0;
|
||||||
continue;
|
break;
|
||||||
|
}
|
||||||
|
else if (getsockerror_winsock() == WSAEWOULDBLOCK) {
|
||||||
|
s->m_pollWrite = true;
|
||||||
|
n = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
throwError(getsockerror_winsock());
|
throwError(getsockerror_winsock());
|
||||||
}
|
}
|
||||||
|
@ -559,26 +658,20 @@ CArchNetworkWinsock::getHostName()
|
||||||
CArchNetAddress
|
CArchNetAddress
|
||||||
CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
||||||
{
|
{
|
||||||
// allocate address
|
CArchNetAddressImpl* addr = NULL;
|
||||||
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
|
|
||||||
|
|
||||||
// fill it in
|
|
||||||
switch (family) {
|
switch (family) {
|
||||||
case kINET: {
|
case kINET: {
|
||||||
struct sockaddr_in* ipAddr =
|
addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||||
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||||
ipAddr->sin_family = AF_INET;
|
ipAddr->sin_family = AF_INET;
|
||||||
ipAddr->sin_port = 0;
|
ipAddr->sin_port = 0;
|
||||||
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
||||||
addr->m_len = sizeof(struct sockaddr_in);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
delete addr;
|
|
||||||
assert(0 && "invalid family");
|
assert(0 && "invalid family");
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,26 +680,27 @@ CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
|
||||||
{
|
{
|
||||||
assert(addr != NULL);
|
assert(addr != NULL);
|
||||||
|
|
||||||
// allocate and copy address
|
CArchNetAddressImpl* copy = CArchNetAddressImpl::alloc(addr->m_len);
|
||||||
return new CArchNetAddressImpl(*addr);
|
memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
CArchNetAddress
|
CArchNetAddress
|
||||||
CArchNetworkWinsock::nameToAddr(const std::string& name)
|
CArchNetworkWinsock::nameToAddr(const std::string& name)
|
||||||
{
|
{
|
||||||
// allocate address
|
// allocate address
|
||||||
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
|
CArchNetAddressImpl* addr = NULL;
|
||||||
|
|
||||||
// try to convert assuming an IPv4 dot notation address
|
// try to convert assuming an IPv4 dot notation address
|
||||||
struct sockaddr_in inaddr;
|
struct sockaddr_in inaddr;
|
||||||
memset(&inaddr, 0, sizeof(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());
|
inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str());
|
||||||
if (inaddr.sin_addr.s_addr != INADDR_NONE) {
|
if (inaddr.sin_addr.s_addr != INADDR_NONE) {
|
||||||
// it's a dot notation address
|
// it's a dot notation address
|
||||||
addr->m_len = sizeof(struct sockaddr_in);
|
addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||||
inaddr.sin_family = AF_INET;
|
memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
|
||||||
inaddr.sin_port = 0;
|
|
||||||
memcpy(&addr->m_addr, &inaddr, addr->m_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
@ -616,16 +710,8 @@ CArchNetworkWinsock::nameToAddr(const std::string& name)
|
||||||
delete addr;
|
delete addr;
|
||||||
throwNameError(getsockerror_winsock());
|
throwNameError(getsockerror_winsock());
|
||||||
}
|
}
|
||||||
|
addr = CArchNetAddressImpl::alloc(info->h_length);
|
||||||
// copy over address (only IPv4 currently supported)
|
memcpy(TYPED_ADDR(void, addr), info->h_addr_list[0], info->h_length);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
|
@ -636,7 +722,7 @@ CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
|
||||||
{
|
{
|
||||||
assert(addr != NULL);
|
assert(addr != NULL);
|
||||||
|
|
||||||
delete addr;
|
free(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
@ -734,8 +820,8 @@ CArchNetworkWinsock::isAnyAddr(CArchNetAddress addr)
|
||||||
case kINET: {
|
case kINET: {
|
||||||
struct sockaddr_in* ipAddr =
|
struct sockaddr_in* ipAddr =
|
||||||
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
|
||||||
return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
|
return (addr->m_len == sizeof(struct sockaddr_in) &&
|
||||||
addr->m_len == sizeof(struct sockaddr_in));
|
ipAddr->sin_addr.s_addr == INADDR_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
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
|
void
|
||||||
CArchNetworkWinsock::throwError(int err)
|
CArchNetworkWinsock::throwError(int err)
|
||||||
{
|
{
|
||||||
|
@ -786,8 +879,10 @@ CArchNetworkWinsock::throwError(int err)
|
||||||
case WSAENOTCONN:
|
case WSAENOTCONN:
|
||||||
throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
|
throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
case WSAENETRESET:
|
|
||||||
case WSAEDISCON:
|
case WSAEDISCON:
|
||||||
|
throw XArchNetworkShutdown(new XArchEvalWinsock(err));
|
||||||
|
|
||||||
|
case WSAENETRESET:
|
||||||
case WSAECONNABORTED:
|
case WSAECONNABORTED:
|
||||||
case WSAECONNRESET:
|
case WSAECONNRESET:
|
||||||
throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
|
throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
|
||||||
|
|
|
@ -33,16 +33,20 @@ public:
|
||||||
SOCKET m_socket;
|
SOCKET m_socket;
|
||||||
bool m_connected;
|
bool m_connected;
|
||||||
int m_refCount;
|
int m_refCount;
|
||||||
|
WSAEVENT m_event;
|
||||||
|
bool m_pollWrite;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CArchNetAddressImpl {
|
class CArchNetAddressImpl {
|
||||||
public:
|
public:
|
||||||
CArchNetAddressImpl() : m_len(sizeof(m_addr)) { }
|
static CArchNetAddressImpl* alloc(size_t);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct sockaddr m_addr;
|
|
||||||
int m_len;
|
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
|
//! Win32 implementation of IArchNetwork
|
||||||
class CArchNetworkWinsock : public IArchNetwork {
|
class CArchNetworkWinsock : public IArchNetwork {
|
||||||
|
@ -61,6 +65,7 @@ public:
|
||||||
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
|
||||||
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
virtual void connectSocket(CArchSocket s, CArchNetAddress name);
|
||||||
virtual int pollSocket(CPollEntry[], int num, double timeout);
|
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 readSocket(CArchSocket s, void* buf, size_t len);
|
||||||
virtual size_t writeSocket(CArchSocket s,
|
virtual size_t writeSocket(CArchSocket s,
|
||||||
const void* buf, size_t len);
|
const void* buf, size_t len);
|
||||||
|
@ -78,6 +83,7 @@ public:
|
||||||
virtual void setAddrPort(CArchNetAddress, int port);
|
virtual void setAddrPort(CArchNetAddress, int port);
|
||||||
virtual int getAddrPort(CArchNetAddress);
|
virtual int getAddrPort(CArchNetAddress);
|
||||||
virtual bool isAnyAddr(CArchNetAddress);
|
virtual bool isAnyAddr(CArchNetAddress);
|
||||||
|
virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init(HMODULE);
|
void init(HMODULE);
|
||||||
|
|
|
@ -41,71 +41,67 @@ CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) :
|
||||||
// save app instance
|
// save app instance
|
||||||
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
|
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
|
||||||
|
|
||||||
// we need a mutex
|
// register the task bar restart message
|
||||||
m_mutex = ARCH->newMutex();
|
m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||||||
|
|
||||||
// and a condition variable which uses the above mutex
|
// register a window class
|
||||||
m_ready = false;
|
WNDCLASSEX classInfo;
|
||||||
m_condVar = ARCH->newCondVar();
|
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
|
// create window
|
||||||
// about to create to know if it initialized successfully.
|
m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
|
||||||
// so we lock the condition variable.
|
reinterpret_cast<LPCTSTR>(m_windowClass),
|
||||||
ARCH->lockMutex(m_mutex);
|
TEXT("Synergy Task Bar"),
|
||||||
|
WS_POPUP,
|
||||||
// open a window and run an event loop in a separate thread.
|
0, 0, 1, 1,
|
||||||
// this has to happen in a separate thread because if we
|
NULL,
|
||||||
// create a window on the current desktop with the current
|
NULL,
|
||||||
// thread then the current thread won't be able to switch
|
s_appInstance,
|
||||||
// desktops if it needs to.
|
reinterpret_cast<void*>(this));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CArchTaskBarWindows::~CArchTaskBarWindows()
|
CArchTaskBarWindows::~CArchTaskBarWindows()
|
||||||
{
|
{
|
||||||
if (m_thread != NULL) {
|
if (m_hwnd != NULL) {
|
||||||
ARCH->cancelThread(m_thread);
|
removeAllIcons();
|
||||||
ARCH->wait(m_thread, -1.0);
|
DestroyWindow(m_hwnd);
|
||||||
ARCH->closeThread(m_thread);
|
|
||||||
}
|
}
|
||||||
ARCH->closeCondVar(m_condVar);
|
UnregisterClass((LPCTSTR)m_windowClass, s_appInstance);
|
||||||
ARCH->closeMutex(m_mutex);
|
|
||||||
s_instance = NULL;
|
s_instance = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::addDialog(HWND hwnd)
|
CArchTaskBarWindows::addDialog(HWND hwnd)
|
||||||
{
|
{
|
||||||
// add dialog to added dialogs list
|
CArchMiscWindows::addDialog(hwnd);
|
||||||
ARCH->lockMutex(s_instance->m_mutex);
|
|
||||||
s_instance->m_addedDialogs.insert(std::make_pair(hwnd, true));
|
|
||||||
ARCH->unlockMutex(s_instance->m_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::removeDialog(HWND hwnd)
|
CArchTaskBarWindows::removeDialog(HWND hwnd)
|
||||||
{
|
{
|
||||||
// mark dialog as removed
|
CArchMiscWindows::removeDialog(hwnd);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
|
CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
|
||||||
{
|
{
|
||||||
|
if (m_hwnd == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore bogus receiver
|
// ignore bogus receiver
|
||||||
if (receiver == NULL) {
|
if (receiver == NULL) {
|
||||||
return;
|
return;
|
||||||
|
@ -180,53 +176,43 @@ CArchTaskBarWindows::recycleID(UINT id)
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::addIcon(UINT id)
|
CArchTaskBarWindows::addIcon(UINT id)
|
||||||
{
|
{
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
||||||
if (index != m_idTable.end()) {
|
if (index != m_idTable.end()) {
|
||||||
modifyIconNoLock(index->second, NIM_ADD);
|
modifyIconNoLock(index->second, NIM_ADD);
|
||||||
}
|
}
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::removeIcon(UINT id)
|
CArchTaskBarWindows::removeIcon(UINT id)
|
||||||
{
|
{
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
removeIconNoLock(id);
|
removeIconNoLock(id);
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::updateIcon(UINT id)
|
CArchTaskBarWindows::updateIcon(UINT id)
|
||||||
{
|
{
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
||||||
if (index != m_idTable.end()) {
|
if (index != m_idTable.end()) {
|
||||||
modifyIconNoLock(index->second, NIM_MODIFY);
|
modifyIconNoLock(index->second, NIM_MODIFY);
|
||||||
}
|
}
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::addAllIcons()
|
CArchTaskBarWindows::addAllIcons()
|
||||||
{
|
{
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
||||||
index != m_receivers.end(); ++index) {
|
index != m_receivers.end(); ++index) {
|
||||||
modifyIconNoLock(index, NIM_ADD);
|
modifyIconNoLock(index, NIM_ADD);
|
||||||
}
|
}
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchTaskBarWindows::removeAllIcons()
|
CArchTaskBarWindows::removeAllIcons()
|
||||||
{
|
{
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
||||||
index != m_receivers.end(); ++index) {
|
index != m_receivers.end(); ++index) {
|
||||||
removeIconNoLock(index->second.m_id);
|
removeIconNoLock(index->second.m_id);
|
||||||
}
|
}
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
LRESULT
|
||||||
CArchTaskBarWindows::wndProc(HWND hwnd,
|
CArchTaskBarWindows::wndProc(HWND hwnd,
|
||||||
UINT msg, WPARAM wParam, LPARAM lParam)
|
UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
@ -432,87 +375,3 @@ CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
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
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include "IArchTaskBar.h"
|
#include "IArchTaskBar.h"
|
||||||
#include "IArchMultithread.h"
|
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -78,21 +77,13 @@ private:
|
||||||
LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
|
LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
static LRESULT CALLBACK
|
static LRESULT CALLBACK
|
||||||
staticWndProc(HWND, UINT, WPARAM, LPARAM);
|
staticWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
void threadMainLoop();
|
|
||||||
static void* threadEntry(void*);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static CArchTaskBarWindows* s_instance;
|
static CArchTaskBarWindows* s_instance;
|
||||||
static HINSTANCE s_appInstance;
|
static HINSTANCE s_appInstance;
|
||||||
|
|
||||||
// multithread data
|
|
||||||
CArchMutex m_mutex;
|
|
||||||
CArchCond m_condVar;
|
|
||||||
bool m_ready;
|
|
||||||
int m_result;
|
|
||||||
CArchThread m_thread;
|
|
||||||
|
|
||||||
// child thread data
|
// child thread data
|
||||||
|
ATOM m_windowClass;
|
||||||
HWND m_hwnd;
|
HWND m_hwnd;
|
||||||
UINT m_taskBarRestart;
|
UINT m_taskBarRestart;
|
||||||
|
|
||||||
|
|
|
@ -67,13 +67,6 @@ synergy. Each architecture must implement this interface.
|
||||||
*/
|
*/
|
||||||
class IArchMultithread : public IInterface {
|
class IArchMultithread : public IInterface {
|
||||||
public:
|
public:
|
||||||
//! Result of waitForEvent()
|
|
||||||
enum EWaitResult {
|
|
||||||
kEvent, //!< An event is pending
|
|
||||||
kExit, //!< Thread exited
|
|
||||||
kTimeout //!< Wait timed out
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Type of thread entry point
|
//! Type of thread entry point
|
||||||
typedef void* (*ThreadFunc)(void*);
|
typedef void* (*ThreadFunc)(void*);
|
||||||
//! Type of thread identifier
|
//! Type of thread identifier
|
||||||
|
@ -213,30 +206,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool wait(CArchThread thread, double timeout) = 0;
|
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
|
//! Compare threads
|
||||||
/*!
|
/*!
|
||||||
Returns true iff two thread objects refer to the same thread.
|
Returns true iff two thread objects refer to the same thread.
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "IInterface.h"
|
#include "IInterface.h"
|
||||||
#include "stdstring.h"
|
#include "stdstring.h"
|
||||||
|
|
||||||
|
class CArchThreadImpl;
|
||||||
|
typedef CArchThreadImpl* CArchThread;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class CArchSocketImpl
|
\class CArchSocketImpl
|
||||||
\brief Internal socket data.
|
\brief Internal socket data.
|
||||||
|
@ -179,12 +182,21 @@ public:
|
||||||
the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL
|
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
|
are set in \c m_revents as appropriate. If a socket indicates
|
||||||
\c kPOLLERR then \c throwErrorOnSocket() can be used to determine
|
\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)
|
(Cancellation point)
|
||||||
*/
|
*/
|
||||||
virtual int pollSocket(CPollEntry[], int num, double timeout) = 0;
|
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 data from socket
|
||||||
/*!
|
/*!
|
||||||
Read up to \c len bytes from socket \c s in \c buf and return the
|
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
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CArchImpl.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\CArchLogWindows.h
|
SOURCE=.\CArchLogWindows.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
|
@ -169,6 +169,10 @@ retry:
|
||||||
event = removeEvent(dataID);
|
event = removeEvent(dataID);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "invalid event type");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,7 +502,7 @@ CEventQueue::CTimer::reset()
|
||||||
m_time = m_timeout;
|
m_time = m_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
CEventQueue::CTimer::CTimer&
|
CEventQueue::CTimer&
|
||||||
CEventQueue::CTimer::operator-=(double dt)
|
CEventQueue::CTimer::operator-=(double dt)
|
||||||
{
|
{
|
||||||
m_time -= 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.
|
(which can appear in any order), and its contents can be swapped.
|
||||||
*/
|
*/
|
||||||
template <class T, class Container = std::vector<T>,
|
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> >
|
class Compare = std::greater<typename Container::value_type> >
|
||||||
|
#endif
|
||||||
class CPriorityQueue {
|
class CPriorityQueue {
|
||||||
public:
|
public:
|
||||||
typedef typename Container::value_type value_type;
|
typedef typename Container::value_type value_type;
|
||||||
|
|
|
@ -53,7 +53,7 @@ CSimpleEventQueueBuffer::waitForEvent(double timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
IEventQueueBuffer::Type
|
IEventQueueBuffer::Type
|
||||||
CSimpleEventQueueBuffer::getEvent(CEvent& event, UInt32& dataID)
|
CSimpleEventQueueBuffer::getEvent(CEvent&, UInt32& dataID)
|
||||||
{
|
{
|
||||||
CArchMutexLock lock(m_queueMutex);
|
CArchMutexLock lock(m_queueMutex);
|
||||||
if (!m_queueReady) {
|
if (!m_queueReady) {
|
||||||
|
|
|
@ -39,7 +39,8 @@ CServerProxy::CServerProxy(CClient* client, IStream* stream) :
|
||||||
m_seqNum(0),
|
m_seqNum(0),
|
||||||
m_compressMouse(false),
|
m_compressMouse(false),
|
||||||
m_ignoreMouse(false),
|
m_ignoreMouse(false),
|
||||||
m_heartRate(0.0)
|
m_heartRate(0.0),
|
||||||
|
m_parser(&CServerProxy::parseHandshakeMessage)
|
||||||
{
|
{
|
||||||
assert(m_client != NULL);
|
assert(m_client != NULL);
|
||||||
assert(m_stream != NULL);
|
assert(m_stream != NULL);
|
||||||
|
@ -52,7 +53,7 @@ CServerProxy::CServerProxy(CClient* client, IStream* stream) :
|
||||||
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
EVENTQUEUE->adoptHandler(IStream::getInputReadyEvent(),
|
||||||
m_stream->getEventTarget(),
|
m_stream->getEventTarget(),
|
||||||
new TMethodEventJob<CServerProxy>(this,
|
new TMethodEventJob<CServerProxy>(this,
|
||||||
&CServerProxy::handleMessage));
|
&CServerProxy::handleData));
|
||||||
|
|
||||||
// send heartbeat
|
// send heartbeat
|
||||||
installHeartBeat(kHeartRate);
|
installHeartBeat(kHeartRate);
|
||||||
|
@ -61,6 +62,8 @@ CServerProxy::CServerProxy(CClient* client, IStream* stream) :
|
||||||
CServerProxy::~CServerProxy()
|
CServerProxy::~CServerProxy()
|
||||||
{
|
{
|
||||||
installHeartBeat(-1.0);
|
installHeartBeat(-1.0);
|
||||||
|
EVENTQUEUE->removeHandler(IStream::getInputReadyEvent(),
|
||||||
|
m_stream->getEventTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
CEvent::Type
|
CEvent::Type
|
||||||
|
@ -87,24 +90,107 @@ CServerProxy::installHeartBeat(double heartRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServerProxy::handleMessage(const CEvent&, void*)
|
CServerProxy::handleData(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
while (m_stream->isReady()) {
|
// handle messages until there are no more. first read message code.
|
||||||
// read next code
|
|
||||||
UInt8 code[4];
|
UInt8 code[4];
|
||||||
UInt32 n = m_stream->read(code, sizeof(code));
|
UInt32 n = m_stream->read(code, 4);
|
||||||
if (n == 0) {
|
while (n != 0) {
|
||||||
break;
|
// verify we got an entire code
|
||||||
}
|
|
||||||
if (n != 4) {
|
if (n != 4) {
|
||||||
// client sent an incomplete message
|
LOG((CLOG_ERR "incomplete message from server: %d bytes", n));
|
||||||
LOG((CLOG_ERR "incomplete message from server"));
|
|
||||||
m_client->disconnect("incomplete message from server");
|
m_client->disconnect("incomplete message from server");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse message
|
// parse message
|
||||||
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
|
LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3]));
|
||||||
|
switch ((this->*m_parser)(code)) {
|
||||||
|
case kOkay:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kUnknown:
|
||||||
|
LOG((CLOG_ERR "invalid message from server"));
|
||||||
|
m_client->disconnect("invalid message from server");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case kDisconnect:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// next message
|
||||||
|
n = m_stream->read(code, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
flushCompressedMouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerProxy::EResult
|
||||||
|
CServerProxy::parseHandshakeMessage(const UInt8* code)
|
||||||
|
{
|
||||||
|
if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||||
|
queryInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgCInfoAck, 4) == 0) {
|
||||||
|
infoAcknowledgment();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgCResetOptions, 4) == 0) {
|
||||||
|
resetOptions();
|
||||||
|
|
||||||
|
// handshake is complete
|
||||||
|
m_parser = &CServerProxy::parseMessage;
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getHandshakeCompleteEvent(), this));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgCNoop, 4) == 0) {
|
||||||
|
// accept and discard no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgCClose, 4) == 0) {
|
||||||
|
// server wants us to hangup
|
||||||
|
LOG((CLOG_DEBUG1 "recv close"));
|
||||||
|
m_client->disconnect(NULL);
|
||||||
|
return kDisconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
|
||||||
|
SInt32 major, minor;
|
||||||
|
CProtocolUtil::readf(m_stream,
|
||||||
|
kMsgEIncompatible + 4, &major, &minor);
|
||||||
|
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
|
||||||
|
m_client->disconnect("server has incompatible version");
|
||||||
|
return kDisconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
||||||
|
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
|
||||||
|
m_client->disconnect("server already has a connected client with our name");
|
||||||
|
return kDisconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
||||||
|
LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
|
||||||
|
m_client->disconnect("server refused client with our name");
|
||||||
|
return kDisconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
||||||
|
LOG((CLOG_ERR "server disconnected due to a protocol error"));
|
||||||
|
m_client->disconnect("server reported a protocol error");
|
||||||
|
return kDisconnect;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return kUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kOkay;
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerProxy::EResult
|
||||||
|
CServerProxy::parseMessage(const UInt8* code)
|
||||||
|
{
|
||||||
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
if (memcmp(code, kMsgDMouseMove, 4) == 0) {
|
||||||
mouseMove();
|
mouseMove();
|
||||||
}
|
}
|
||||||
|
@ -177,44 +263,18 @@ CServerProxy::handleMessage(const CEvent&, void*)
|
||||||
// server wants us to hangup
|
// server wants us to hangup
|
||||||
LOG((CLOG_DEBUG1 "recv close"));
|
LOG((CLOG_DEBUG1 "recv close"));
|
||||||
m_client->disconnect(NULL);
|
m_client->disconnect(NULL);
|
||||||
break;
|
return kDisconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEIncompatible, 4) == 0) {
|
|
||||||
SInt32 major, minor;
|
|
||||||
CProtocolUtil::readf(m_stream,
|
|
||||||
kMsgEIncompatible + 4, &major, &minor);
|
|
||||||
LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor));
|
|
||||||
m_client->disconnect("server has incompatible version");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
|
||||||
LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str()));
|
|
||||||
m_client->disconnect("server already has a connected client with our name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
|
||||||
LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str()));
|
|
||||||
m_client->disconnect("server refused client with our name");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
||||||
LOG((CLOG_ERR "server disconnected due to a protocol error"));
|
LOG((CLOG_ERR "server disconnected due to a protocol error"));
|
||||||
m_client->disconnect("server reported a protocol error");
|
m_client->disconnect("server reported a protocol error");
|
||||||
return;
|
return kDisconnect;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return kUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
return kOkay;
|
||||||
// unknown message
|
|
||||||
LOG((CLOG_ERR "unknown message: %d %d %d %d [%c%c%c%c]", code[0], code[1], code[2], code[3], code[0], code[1], code[2], code[3]));
|
|
||||||
m_client->disconnect("unknown message from server");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flushCompressedMouse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -42,9 +42,9 @@ public:
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
virtual void onInfoChanged();
|
void onInfoChanged();
|
||||||
virtual bool onGrabClipboard(ClipboardID);
|
bool onGrabClipboard(ClipboardID);
|
||||||
virtual void onClipboardChanged(ClipboardID, const IClipboard*);
|
void onClipboardChanged(ClipboardID, const IClipboard*);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
|
@ -59,6 +59,11 @@ public:
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum EResult { kOkay, kUnknown, kDisconnect };
|
||||||
|
EResult parseHandshakeMessage(const UInt8* code);
|
||||||
|
EResult parseMessage(const UInt8* code);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// if compressing mouse motion then send the last motion now
|
// if compressing mouse motion then send the last motion now
|
||||||
void flushCompressedMouse();
|
void flushCompressedMouse();
|
||||||
|
@ -72,7 +77,7 @@ private:
|
||||||
KeyModifierMask translateModifierMask(KeyModifierMask) const;
|
KeyModifierMask translateModifierMask(KeyModifierMask) const;
|
||||||
|
|
||||||
// event handlers
|
// event handlers
|
||||||
void handleMessage(const CEvent&, void*);
|
void handleData(const CEvent&, void*);
|
||||||
void handleHeartBeat(const CEvent&, void*);
|
void handleHeartBeat(const CEvent&, void*);
|
||||||
|
|
||||||
// message handlers
|
// message handlers
|
||||||
|
@ -94,6 +99,8 @@ private:
|
||||||
void infoAcknowledgment();
|
void infoAcknowledgment();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef EResult (CServerProxy::*MessageParser)(const UInt8*);
|
||||||
|
|
||||||
CClient* m_client;
|
CClient* m_client;
|
||||||
IStream* m_stream;
|
IStream* m_stream;
|
||||||
CEventQueueTimer* m_timer;
|
CEventQueueTimer* m_timer;
|
||||||
|
@ -108,6 +115,8 @@ private:
|
||||||
KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast];
|
KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast];
|
||||||
double m_heartRate;
|
double m_heartRate;
|
||||||
|
|
||||||
|
MessageParser m_parser;
|
||||||
|
|
||||||
static CEvent::Type s_handshakeCompleteEvent;
|
static CEvent::Type s_handshakeCompleteEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ EXTRA_DIST = \
|
||||||
common.dsp \
|
common.dsp \
|
||||||
BasicTypes.h \
|
BasicTypes.h \
|
||||||
IInterface.h \
|
IInterface.h \
|
||||||
Version.h \
|
|
||||||
common.h \
|
common.h \
|
||||||
stdbitset.h \
|
stdbitset.h \
|
||||||
stddeque.h \
|
stddeque.h \
|
||||||
|
@ -40,5 +39,11 @@ MAINTAINERCLEANFILES = \
|
||||||
Makefile.in \
|
Makefile.in \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
noinst_LIBRARIES = libcommon.a
|
||||||
|
libcommon_a_SOURCES = \
|
||||||
|
Version.cpp \
|
||||||
|
Version.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -23,17 +23,17 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// important strings
|
// important strings
|
||||||
static const char* kApplication = "synergy";
|
extern const char* kApplication;
|
||||||
static const char* kCopyright = "Copyright (C) 2002 Chris Schoeneman";
|
extern const char* kCopyright;
|
||||||
static const char* kContact = "Chris Schoeneman, crs23@bigfoot.com";
|
extern const char* kContact;
|
||||||
static const char* kWebsite = "http://synergy2.sourceforge.net/";
|
extern const char* kWebsite;
|
||||||
|
|
||||||
// build version. follows linux kernel style: an even minor number implies
|
// build version. follows linux kernel style: an even minor number implies
|
||||||
// a release version, odd implies development version.
|
// a release version, odd implies development version.
|
||||||
static const char* kVersion = VERSION;
|
extern const char* kVersion;
|
||||||
|
|
||||||
// application version
|
// application version
|
||||||
static const char* kAppVersion = "synergy " VERSION;
|
extern const char* kAppVersion;
|
||||||
|
|
||||||
// exit codes
|
// exit codes
|
||||||
static const int kExitSuccess = 0; // successful completion
|
static const int kExitSuccess = 0; // successful completion
|
||||||
|
|
|
@ -85,6 +85,10 @@ LIB32=link.exe -lib
|
||||||
# Begin Group "Source Files"
|
# Begin Group "Source Files"
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\Version.cpp
|
||||||
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
# Begin Group "Header Files"
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,12 @@ CThread::setPriority(int n)
|
||||||
ARCH->setPriorityOfThread(m_thread, n);
|
ARCH->setPriorityOfThread(m_thread, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CThread::unblockPollSocket()
|
||||||
|
{
|
||||||
|
ARCH->unblockPollSocket(m_thread);
|
||||||
|
}
|
||||||
|
|
||||||
CThread
|
CThread
|
||||||
CThread::getCurrentThread()
|
CThread::getCurrentThread()
|
||||||
{
|
{
|
||||||
|
@ -97,24 +103,6 @@ CThread::wait(double timeout) const
|
||||||
return ARCH->wait(m_thread, timeout);
|
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*
|
void*
|
||||||
CThread::getResult() const
|
CThread::getResult() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,13 +39,6 @@ documentation.
|
||||||
// note -- do not derive from this class
|
// note -- do not derive from this class
|
||||||
class CThread {
|
class CThread {
|
||||||
public:
|
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
|
//! Run \c adoptedJob in a new thread
|
||||||
/*!
|
/*!
|
||||||
Create and start a new thread executing the \c adoptedJob. The
|
Create and start a new thread executing the \c adoptedJob. The
|
||||||
|
@ -130,6 +123,13 @@ public:
|
||||||
*/
|
*/
|
||||||
void setPriority(int n);
|
void setPriority(int n);
|
||||||
|
|
||||||
|
//! Force pollSocket() to return
|
||||||
|
/*!
|
||||||
|
Forces a currently blocked pollSocket() in the thread to return
|
||||||
|
immediately.
|
||||||
|
*/
|
||||||
|
void unblockPollSocket();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -164,31 +164,6 @@ public:
|
||||||
*/
|
*/
|
||||||
bool wait(double timeout = -1.0) const;
|
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
|
//! Get the exit result
|
||||||
/*!
|
/*!
|
||||||
Returns the exit result. This does an implicit wait(). It returns
|
Returns the exit result. This does an implicit wait(). It returns
|
||||||
|
|
|
@ -54,6 +54,7 @@ CSocketMultiplexer::CSocketMultiplexer() :
|
||||||
CSocketMultiplexer::~CSocketMultiplexer()
|
CSocketMultiplexer::~CSocketMultiplexer()
|
||||||
{
|
{
|
||||||
m_thread->cancel();
|
m_thread->cancel();
|
||||||
|
m_thread->unblockPollSocket();
|
||||||
m_thread->wait();
|
m_thread->wait();
|
||||||
delete m_thread;
|
delete m_thread;
|
||||||
delete m_polling;
|
delete m_polling;
|
||||||
|
@ -87,7 +88,7 @@ CSocketMultiplexer::addSocket(ISocket* socket, ISocketMultiplexerJob* job)
|
||||||
*m_pollable = false;
|
*m_pollable = false;
|
||||||
|
|
||||||
// break thread out of poll
|
// break thread out of poll
|
||||||
m_thread->unblock();
|
m_thread->unblockPollSocket();
|
||||||
|
|
||||||
// wait for poll to finish
|
// wait for poll to finish
|
||||||
while (*m_polling) {
|
while (*m_polling) {
|
||||||
|
@ -129,7 +130,7 @@ CSocketMultiplexer::removeSocket(ISocket* socket)
|
||||||
*m_pollable = false;
|
*m_pollable = false;
|
||||||
|
|
||||||
// break thread out of poll
|
// break thread out of poll
|
||||||
m_thread->unblock();
|
m_thread->unblockPollSocket();
|
||||||
|
|
||||||
// wait until thread finishes poll
|
// wait until thread finishes poll
|
||||||
while (*m_polling) {
|
while (*m_polling) {
|
||||||
|
@ -160,11 +161,12 @@ CSocketMultiplexer::serviceThread(void*)
|
||||||
|
|
||||||
// service the connections
|
// service the connections
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
CThread::testCancel();
|
||||||
{
|
{
|
||||||
CLock lock(m_mutex);
|
CLock lock(m_mutex);
|
||||||
|
|
||||||
// wait until pollable
|
// wait until pollable
|
||||||
while (!*m_pollable) {
|
while (!(bool)*m_pollable) {
|
||||||
m_pollable->wait();
|
m_pollable->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +283,6 @@ CSocketMultiplexer::CJobCursor
|
||||||
CSocketMultiplexer::nextCursor(CJobCursor cursor)
|
CSocketMultiplexer::nextCursor(CJobCursor cursor)
|
||||||
{
|
{
|
||||||
CLock lock(m_mutex);
|
CLock lock(m_mutex);
|
||||||
ISocketMultiplexerJob* job = NULL;
|
|
||||||
CJobCursor j = m_socketJobs.end();
|
CJobCursor j = m_socketJobs.end();
|
||||||
CJobCursor i = cursor;
|
CJobCursor i = cursor;
|
||||||
while (++i != m_socketJobs.end()) {
|
while (++i != m_socketJobs.end()) {
|
||||||
|
|
|
@ -34,3 +34,18 @@ IDataSocket::getConnectionFailedEvent()
|
||||||
return CEvent::registerTypeOnce(s_failedEvent,
|
return CEvent::registerTypeOnce(s_failedEvent,
|
||||||
"IDataSocket::failed");
|
"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
|
// 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 bind(const CNetworkAddress&) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close();
|
||||||
virtual void* getEventTarget() const = 0;
|
virtual void* getEventTarget() const;
|
||||||
|
|
||||||
// IStream overrides
|
// IStream overrides
|
||||||
virtual UInt32 read(void* buffer, UInt32 n) = 0;
|
virtual UInt32 read(void* buffer, UInt32 n) = 0;
|
||||||
|
|
|
@ -21,6 +21,12 @@
|
||||||
//! Encapsulate Microsoft Windows desktop
|
//! Encapsulate Microsoft Windows desktop
|
||||||
class CMSWindowsDesktop {
|
class CMSWindowsDesktop {
|
||||||
public:
|
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
|
//! Open the input desktop
|
||||||
/*!
|
/*!
|
||||||
Opens the input desktop. The caller must close the 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) {
|
for (size_t j = 0; j < CModifierKeys::s_maxKeys; ++j) {
|
||||||
if (s_modifiers[i].m_keys[j] != 0) {
|
if (s_modifiers[i].m_keys[j] != 0) {
|
||||||
SHORT s = GetKeyState(s_modifiers[i].m_keys[j]);
|
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 (keyState != NULL) {
|
||||||
if ((s & 0x01) != 0) {
|
if ((s & 0x01) != 0) {
|
||||||
keyState->setToggled(s_modifiers[i].m_mask);
|
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 "IPlatformScreen.h"
|
||||||
#include "CMSWindowsKeyMapper.h"
|
#include "CMSWindowsKeyMapper.h"
|
||||||
#include "CSynergyHook.h"
|
#include "CSynergyHook.h"
|
||||||
|
#include "CCondVar.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
class CEventQueueTimer;
|
||||||
class CMSWindowsScreenSaver;
|
class CMSWindowsScreenSaver;
|
||||||
class IScreenReceiver;
|
class CThread;
|
||||||
class IPrimaryScreenReceiver;
|
|
||||||
|
|
||||||
//! Implementation of IPlatformScreen for Microsoft Windows
|
//! Implementation of IPlatformScreen for Microsoft Windows
|
||||||
class CMSWindowsScreen : public IPlatformScreen {
|
class CMSWindowsScreen : public IPlatformScreen {
|
||||||
public:
|
public:
|
||||||
CMSWindowsScreen(IScreenReceiver*, IPrimaryScreenReceiver*);
|
CMSWindowsScreen(bool isPrimary);
|
||||||
virtual ~CMSWindowsScreen();
|
virtual ~CMSWindowsScreen();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
|
@ -56,12 +57,9 @@ public:
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IPlatformScreen overrides
|
// IPlatformScreen overrides
|
||||||
virtual void open(IKeyState*);
|
virtual void setKeyState(IKeyState*);
|
||||||
virtual void close();
|
|
||||||
virtual void enable();
|
virtual void enable();
|
||||||
virtual void disable();
|
virtual void disable();
|
||||||
virtual void mainLoop();
|
|
||||||
virtual void exitMainLoop();
|
|
||||||
virtual void enter();
|
virtual void enter();
|
||||||
virtual bool leave();
|
virtual bool leave();
|
||||||
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
virtual bool setClipboard(ClipboardID, const IClipboard*);
|
||||||
|
@ -72,17 +70,22 @@ public:
|
||||||
virtual void resetOptions();
|
virtual void resetOptions();
|
||||||
virtual void setOptions(const COptionsList& options);
|
virtual void setOptions(const COptionsList& options);
|
||||||
virtual void updateKeys();
|
virtual void updateKeys();
|
||||||
|
virtual void setSequenceNumber(UInt32);
|
||||||
virtual bool isPrimary() const;
|
virtual bool isPrimary() const;
|
||||||
virtual bool getClipboard(ClipboardID, IClipboard*) const;
|
|
||||||
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
|
// IScreen overrides
|
||||||
virtual void getCursorPos(SInt32&, SInt32&) const;
|
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
|
// IPrimaryScreen overrides
|
||||||
virtual void reconfigure(UInt32 activeSides);
|
virtual void reconfigure(UInt32 activeSides);
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual UInt32 addOneShotTimer(double timeout);
|
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual bool isAnyMouseButtonDown() const;
|
virtual bool isAnyMouseButtonDown() const;
|
||||||
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
virtual const char* getKeyName(KeyButton) const;
|
virtual const char* getKeyName(KeyButton) const;
|
||||||
|
|
||||||
// ISecondaryScreen overrides
|
// ISecondaryScreen overrides
|
||||||
|
@ -97,17 +100,31 @@ public:
|
||||||
bool isAutoRepeat) const;
|
bool isAutoRepeat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// update screen size cache
|
class CDesk {
|
||||||
void updateScreenShape();
|
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
|
// FIXME -- comment
|
||||||
// all hooks, switches the desktop, then creates the window and rehooks
|
HINSTANCE openHookLibrary(const char* name);
|
||||||
// all hooks (because you can't switch the thread's desktop if it has
|
void closeHookLibrary(HINSTANCE hookLibrary) const;
|
||||||
// any windows or hooks).
|
HCURSOR createBlankCursor() const;
|
||||||
bool switchDesktop(HDESK desk);
|
void destroyCursor(HCURSOR cursor) const;
|
||||||
|
ATOM createWindowClass() const;
|
||||||
// make sure we're on the expected desktop
|
ATOM createDeskWindowClass(bool isPrimary) const;
|
||||||
void syncDesktop() 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
|
// handle message before it gets dispatched. returns true iff
|
||||||
// the message should not be dispatched.
|
// the message should not be dispatched.
|
||||||
|
@ -128,10 +145,8 @@ private:
|
||||||
bool onMouseMove(SInt32 x, SInt32 y);
|
bool onMouseMove(SInt32 x, SInt32 y);
|
||||||
bool onMouseWheel(SInt32 delta);
|
bool onMouseWheel(SInt32 delta);
|
||||||
bool onScreensaver(bool activated);
|
bool onScreensaver(bool activated);
|
||||||
bool onTimer(UINT timerID);
|
|
||||||
bool onDisplayChange();
|
bool onDisplayChange();
|
||||||
bool onClipboardChange();
|
bool onClipboardChange();
|
||||||
bool onActivate(bool activated);
|
|
||||||
|
|
||||||
// XXX
|
// XXX
|
||||||
// warp cursor without discarding queued events
|
// warp cursor without discarding queued events
|
||||||
|
@ -144,11 +159,8 @@ private:
|
||||||
bool ignore() const;
|
bool ignore() const;
|
||||||
// XXX
|
// XXX
|
||||||
|
|
||||||
// create the transparent cursor
|
// update screen size cache
|
||||||
HCURSOR createBlankCursor() const;
|
void updateScreenShape();
|
||||||
|
|
||||||
// show/hide the cursor
|
|
||||||
void showCursor(bool) const;
|
|
||||||
|
|
||||||
// enable/disable special key combinations so we can catch/pass them
|
// enable/disable special key combinations so we can catch/pass them
|
||||||
void enableSpecialKeys(bool) const;
|
void enableSpecialKeys(bool) const;
|
||||||
|
@ -169,6 +181,22 @@ private:
|
||||||
// our window proc
|
// our window proc
|
||||||
static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
|
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:
|
private:
|
||||||
static HINSTANCE s_instance;
|
static HINSTANCE s_instance;
|
||||||
|
|
||||||
|
@ -178,17 +206,13 @@ private:
|
||||||
// true if windows 95/98/me
|
// true if windows 95/98/me
|
||||||
bool m_is95Family;
|
bool m_is95Family;
|
||||||
|
|
||||||
// receivers
|
|
||||||
IScreenReceiver* m_receiver;
|
|
||||||
IPrimaryScreenReceiver* m_primaryReceiver;
|
|
||||||
|
|
||||||
// true if mouse has entered the screen
|
// true if mouse has entered the screen
|
||||||
bool m_isOnScreen;
|
bool m_isOnScreen;
|
||||||
|
|
||||||
// our resources
|
// our resources
|
||||||
ATOM m_class;
|
ATOM m_class;
|
||||||
|
ATOM m_deskClass;
|
||||||
HCURSOR m_cursor;
|
HCURSOR m_cursor;
|
||||||
HWND m_window;
|
|
||||||
|
|
||||||
// screen shape stuff
|
// screen shape stuff
|
||||||
SInt32 m_x, m_y;
|
SInt32 m_x, m_y;
|
||||||
|
@ -201,6 +225,8 @@ private:
|
||||||
// last mouse position
|
// last mouse position
|
||||||
SInt32 m_xCursor, m_yCursor;
|
SInt32 m_xCursor, m_yCursor;
|
||||||
|
|
||||||
|
UInt32 m_sequenceNumber;
|
||||||
|
|
||||||
// used to discard queued messages that are no longer needed
|
// used to discard queued messages that are no longer needed
|
||||||
UInt32 m_mark;
|
UInt32 m_mark;
|
||||||
UInt32 m_markReceived;
|
UInt32 m_markReceived;
|
||||||
|
@ -208,33 +234,27 @@ private:
|
||||||
// the main loop's thread id
|
// the main loop's thread id
|
||||||
DWORD m_threadID;
|
DWORD m_threadID;
|
||||||
|
|
||||||
// the thread id of the last attached thread
|
|
||||||
DWORD m_lastThreadID;
|
|
||||||
|
|
||||||
// the timer used to check for desktop switching
|
// the timer used to check for desktop switching
|
||||||
UINT m_timer;
|
CEventQueueTimer* m_timer;
|
||||||
|
|
||||||
// the one shot timer
|
|
||||||
UINT m_oneShotTimer;
|
|
||||||
|
|
||||||
// screen saver stuff
|
// screen saver stuff
|
||||||
CMSWindowsScreenSaver* m_screensaver;
|
CMSWindowsScreenSaver* m_screensaver;
|
||||||
bool m_screensaverNotify;
|
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;
|
HWND m_nextClipboardWindow;
|
||||||
bool m_ownClipboard;
|
bool m_ownClipboard;
|
||||||
|
|
||||||
// the current desk and it's name
|
// the current desk and it's name
|
||||||
HDESK m_desk;
|
CDesk* m_activeDesk;
|
||||||
CString m_deskName;
|
CString m_activeDeskName;
|
||||||
|
|
||||||
// true when the current desktop is inaccessible. while
|
// one desk per desktop and a cond var to communicate with it
|
||||||
// the desktop is inaccessible we won't receive user input
|
CMutex m_mutex;
|
||||||
// and we'll lose track of the keyboard state. when the
|
CCondVar<bool> m_deskReady;
|
||||||
// desktop becomes accessible again we'll notify the event
|
CDesks m_desks;
|
||||||
// handler of that.
|
|
||||||
bool m_inaccessibleDesktop;
|
|
||||||
|
|
||||||
// hook library stuff
|
// hook library stuff
|
||||||
HINSTANCE m_hookLibrary;
|
HINSTANCE m_hookLibrary;
|
||||||
|
@ -247,7 +267,6 @@ private:
|
||||||
SetModeFunc m_setMode;
|
SetModeFunc m_setMode;
|
||||||
InstallScreenSaverFunc m_installScreensaver;
|
InstallScreenSaverFunc m_installScreensaver;
|
||||||
UninstallScreenSaverFunc m_uninstallScreensaver;
|
UninstallScreenSaverFunc m_uninstallScreensaver;
|
||||||
bool m_lowLevel;
|
|
||||||
|
|
||||||
// keyboard stuff
|
// keyboard stuff
|
||||||
IKeyState* m_keyState;
|
IKeyState* m_keyState;
|
||||||
|
@ -256,9 +275,6 @@ private:
|
||||||
// map of button state
|
// map of button state
|
||||||
BYTE m_buttons[1 + kButtonExtra0 + 1];
|
BYTE m_buttons[1 + kButtonExtra0 + 1];
|
||||||
|
|
||||||
// stuff for hiding the cursor
|
|
||||||
DWORD m_cursorThread;
|
|
||||||
|
|
||||||
static CMSWindowsScreen* s_screen;
|
static CMSWindowsScreen* s_screen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -76,13 +76,10 @@ static DWORD g_threadID = 0;
|
||||||
static HHOOK g_keyboard = NULL;
|
static HHOOK g_keyboard = NULL;
|
||||||
static HHOOK g_mouse = NULL;
|
static HHOOK g_mouse = NULL;
|
||||||
static HHOOK g_getMessage = 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_keyboardLL = NULL;
|
||||||
static HHOOK g_mouseLL = NULL;
|
static HHOOK g_mouseLL = NULL;
|
||||||
static bool g_screenSaver = false;
|
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 UInt32 g_zoneSides = 0;
|
||||||
static SInt32 g_zoneSize = 0;
|
static SInt32 g_zoneSize = 0;
|
||||||
static SInt32 g_xScreen = 0;
|
static SInt32 g_xScreen = 0;
|
||||||
|
@ -141,6 +138,7 @@ restoreCursor()
|
||||||
g_cursorThread = 0;
|
g_cursorThread = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
|
@ -170,6 +168,7 @@ keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
|
@ -231,7 +230,7 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
|
||||||
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
|
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else if (g_mode == kHOOK_WATCH_JUMP_ZONE) {
|
||||||
// check for mouse inside jump zone
|
// check for mouse inside jump zone
|
||||||
bool inside = false;
|
bool inside = false;
|
||||||
if (!inside && (g_zoneSides & kLeftMask) != 0) {
|
if (!inside && (g_zoneSides & kLeftMask) != 0) {
|
||||||
|
@ -259,6 +258,7 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
static
|
static
|
||||||
LRESULT CALLBACK
|
LRESULT CALLBACK
|
||||||
keyboardHook(int code, WPARAM wParam, LPARAM lParam)
|
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);
|
return CallNextHookEx(g_keyboard, code, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
LRESULT CALLBACK
|
LRESULT CALLBACK
|
||||||
|
@ -354,6 +355,7 @@ getMessageHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
// side, key repeats are not reported to us.
|
// side, key repeats are not reported to us.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
static
|
static
|
||||||
LRESULT CALLBACK
|
LRESULT CALLBACK
|
||||||
keyboardLLHook(int code, WPARAM wParam, LPARAM lParam)
|
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);
|
return CallNextHookEx(g_keyboardLL, code, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// low-level mouse hook -- this allows us to capture and handle mouse
|
// 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);
|
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
|
#endif
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -559,12 +476,8 @@ DllMain(HINSTANCE instance, DWORD reason, LPVOID)
|
||||||
}
|
}
|
||||||
else if (reason == DLL_PROCESS_DETACH) {
|
else if (reason == DLL_PROCESS_DETACH) {
|
||||||
if (g_processID == GetCurrentProcessId()) {
|
if (g_processID == GetCurrentProcessId()) {
|
||||||
if (g_keyboard != NULL ||
|
|
||||||
g_mouse != NULL ||
|
|
||||||
g_getMessage != NULL) {
|
|
||||||
uninstall();
|
uninstall();
|
||||||
uninstallScreenSaver();
|
uninstallScreenSaver();
|
||||||
}
|
|
||||||
g_processID = 0;
|
g_processID = 0;
|
||||||
g_hinstance = NULL;
|
g_hinstance = NULL;
|
||||||
}
|
}
|
||||||
|
@ -601,9 +514,6 @@ init(DWORD threadID)
|
||||||
g_keyboard = NULL;
|
g_keyboard = NULL;
|
||||||
g_mouse = NULL;
|
g_mouse = NULL;
|
||||||
g_getMessage = NULL;
|
g_getMessage = NULL;
|
||||||
g_hookThreadLL = NULL;
|
|
||||||
g_hookThreadIDLL = 0;
|
|
||||||
g_hookEventLL = NULL;
|
|
||||||
g_keyboardLL = NULL;
|
g_keyboardLL = NULL;
|
||||||
g_mouseLL = NULL;
|
g_mouseLL = NULL;
|
||||||
g_screenSaver = false;
|
g_screenSaver = false;
|
||||||
|
@ -614,7 +524,7 @@ init(DWORD threadID)
|
||||||
g_threadID = threadID;
|
g_threadID = threadID;
|
||||||
|
|
||||||
// set defaults
|
// set defaults
|
||||||
g_mode = kHOOK_WATCH_JUMP_ZONE;
|
g_mode = kHOOK_DISABLE;
|
||||||
g_zoneSides = 0;
|
g_zoneSides = 0;
|
||||||
g_zoneSize = 0;
|
g_zoneSize = 0;
|
||||||
g_xScreen = 0;
|
g_xScreen = 0;
|
||||||
|
@ -663,75 +573,51 @@ install()
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// install low-level keyboard/mouse hooks, if possible. since these
|
// install keyboard hook
|
||||||
// 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) {
|
|
||||||
#if !NO_GRAB_KEYBOARD
|
#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,
|
g_keyboard = SetWindowsHookEx(WH_KEYBOARD,
|
||||||
&keyboardHook,
|
&keyboardHook,
|
||||||
g_hinstance,
|
g_hinstance,
|
||||||
0);
|
0);
|
||||||
#else
|
}
|
||||||
// keep compiler quiet
|
|
||||||
&keyboardHook;
|
|
||||||
#endif
|
#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,
|
g_mouse = SetWindowsHookEx(WH_MOUSE,
|
||||||
&mouseHook,
|
&mouseHook,
|
||||||
g_hinstance,
|
g_hinstance,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for any failures. uninstall all hooks on failure.
|
// check that we got all the hooks we wanted
|
||||||
if (g_hookThreadLL == NULL &&
|
if ((g_getMessage == NULL && g_wheelSupport == kWheelOld) ||
|
||||||
#if !NO_GRAB_KEYBOARD
|
#if !NO_GRAB_KEYBOARD
|
||||||
(g_keyboard == NULL || g_mouse == NULL)) {
|
(g_keyboardLL == NULL && g_keyboard == NULL) ||
|
||||||
#else
|
|
||||||
(g_mouse == NULL)) {
|
|
||||||
#endif
|
#endif
|
||||||
if (g_keyboard != NULL) {
|
(g_mouseLL == NULL && g_mouse == NULL)) {
|
||||||
UnhookWindowsHookEx(g_keyboard);
|
uninstall();
|
||||||
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;
|
|
||||||
return kHOOK_FAILED;
|
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
|
int
|
||||||
|
@ -740,14 +626,13 @@ uninstall(void)
|
||||||
assert(g_hinstance != NULL);
|
assert(g_hinstance != NULL);
|
||||||
|
|
||||||
// uninstall hooks
|
// uninstall hooks
|
||||||
if (g_hookThreadLL != NULL) {
|
if (g_keyboardLL != NULL) {
|
||||||
PostThreadMessage(g_hookThreadIDLL, WM_QUIT, 0, 0);
|
UnhookWindowsHookEx(g_keyboardLL);
|
||||||
WaitForSingleObject(g_hookThreadLL, INFINITE);
|
g_keyboardLL = NULL;
|
||||||
CloseHandle(g_hookEventLL);
|
}
|
||||||
CloseHandle(g_hookThreadLL);
|
if (g_mouseLL != NULL) {
|
||||||
g_hookEventLL = NULL;
|
UnhookWindowsHookEx(g_mouseLL);
|
||||||
g_hookThreadLL = NULL;
|
g_mouseLL = NULL;
|
||||||
g_hookThreadIDLL = 0;
|
|
||||||
}
|
}
|
||||||
if (g_keyboard != NULL) {
|
if (g_keyboard != NULL) {
|
||||||
UnhookWindowsHookEx(g_keyboard);
|
UnhookWindowsHookEx(g_keyboard);
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; <unused>
|
#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; <unused>
|
||||||
#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY
|
#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY
|
||||||
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
|
#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP
|
||||||
|
#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_SCREEN_SAVER
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ enum EHookResult {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EHookMode {
|
enum EHookMode {
|
||||||
|
kHOOK_DISABLE,
|
||||||
kHOOK_WATCH_JUMP_ZONE,
|
kHOOK_WATCH_JUMP_ZONE,
|
||||||
kHOOK_RELAY_EVENTS
|
kHOOK_RELAY_EVENTS
|
||||||
};
|
};
|
||||||
|
|
|
@ -740,7 +740,7 @@ CXWindowsClipboard::motifFillCache()
|
||||||
// save it
|
// save it
|
||||||
motifFormats.insert(std::make_pair(motifFormat->m_type, data));
|
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
|
// try each converter in order (because they're in order of
|
||||||
// preference).
|
// preference).
|
||||||
|
|
|
@ -143,6 +143,7 @@ CXWindowsEventQueueBuffer::addEvent(UInt32 dataID)
|
||||||
|
|
||||||
// force waitForEvent() to return
|
// force waitForEvent() to return
|
||||||
XFlush(m_display);
|
XFlush(m_display);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -154,7 +155,7 @@ CXWindowsEventQueueBuffer::isEmpty() const
|
||||||
CEventQueueTimer*
|
CEventQueueTimer*
|
||||||
CXWindowsEventQueueBuffer::newTimer(double, bool) const
|
CXWindowsEventQueueBuffer::newTimer(double, bool) const
|
||||||
{
|
{
|
||||||
return new CEventQueueTimer();
|
return new CEventQueueTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -309,7 +309,7 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||||
|
|
||||||
// get modifier map from server
|
// get modifier map from server
|
||||||
XModifierKeymap* modifiers = XGetModifierMapping(display);
|
XModifierKeymap* modifiers = XGetModifierMapping(display);
|
||||||
int keysPerModifier = modifiers->max_keypermod;
|
unsigned int keysPerModifier = modifiers->max_keypermod;
|
||||||
|
|
||||||
// clear state
|
// clear state
|
||||||
m_keysymMap.clear();
|
m_keysymMap.clear();
|
||||||
|
@ -330,7 +330,6 @@ CXWindowsKeyMapper::updateKeysymMap(Display* display, IKeyState* keyState)
|
||||||
// the keysym map. also collect all keycodes for each modifier.
|
// the keysym map. also collect all keycodes for each modifier.
|
||||||
for (unsigned int i = 0; i < 8; ++i) {
|
for (unsigned int i = 0; i < 8; ++i) {
|
||||||
// no keycodes for this modifier yet
|
// no keycodes for this modifier yet
|
||||||
bool hasKeycode = false;
|
|
||||||
KeyModifierMask mask = 0;
|
KeyModifierMask mask = 0;
|
||||||
IKeyState::KeyButtons modifierKeys;
|
IKeyState::KeyButtons modifierKeys;
|
||||||
|
|
||||||
|
|
|
@ -128,8 +128,8 @@ CXWindowsScreen::CXWindowsScreen(bool isPrimary) :
|
||||||
m_isOnScreen(m_isPrimary),
|
m_isOnScreen(m_isPrimary),
|
||||||
m_x(0), m_y(0),
|
m_x(0), m_y(0),
|
||||||
m_w(0), m_h(0),
|
m_w(0), m_h(0),
|
||||||
m_xCursor(0), m_yCursor(0),
|
|
||||||
m_xCenter(0), m_yCenter(0),
|
m_xCenter(0), m_yCenter(0),
|
||||||
|
m_xCursor(0), m_yCursor(0),
|
||||||
m_keyState(NULL),
|
m_keyState(NULL),
|
||||||
m_keyMapper(),
|
m_keyMapper(),
|
||||||
m_im(NULL),
|
m_im(NULL),
|
||||||
|
|
|
@ -28,6 +28,7 @@ EXTRA_DIST = \
|
||||||
CMSWindowsKeyMapper.cpp \
|
CMSWindowsKeyMapper.cpp \
|
||||||
CMSWindowsScreen.cpp \
|
CMSWindowsScreen.cpp \
|
||||||
CMSWindowsScreenSaver.cpp \
|
CMSWindowsScreenSaver.cpp \
|
||||||
|
CMSWindowsUtil.cpp \
|
||||||
CSynergyHook.cpp \
|
CSynergyHook.cpp \
|
||||||
CMSWindowsClipboard.h \
|
CMSWindowsClipboard.h \
|
||||||
CMSWindowsClipboardAnyTextConverter.h \
|
CMSWindowsClipboardAnyTextConverter.h \
|
||||||
|
@ -38,6 +39,7 @@ EXTRA_DIST = \
|
||||||
CMSWindowsKeyMapper.h \
|
CMSWindowsKeyMapper.h \
|
||||||
CMSWindowsScreen.h \
|
CMSWindowsScreen.h \
|
||||||
CMSWindowsScreenSaver.h \
|
CMSWindowsScreenSaver.h \
|
||||||
|
CMSWindowsUtil.h \
|
||||||
CSynergyHook.h \
|
CSynergyHook.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,10 @@ SOURCE=.\CMSWindowsScreen.cpp
|
||||||
|
|
||||||
SOURCE=.\CMSWindowsScreenSaver.cpp
|
SOURCE=.\CMSWindowsScreenSaver.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsUtil.cpp
|
||||||
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
# Begin Group "Header Files"
|
# Begin Group "Header Files"
|
||||||
|
|
||||||
|
@ -161,6 +165,10 @@ SOURCE=.\CMSWindowsScreen.h
|
||||||
|
|
||||||
SOURCE=.\CMSWindowsScreenSaver.h
|
SOURCE=.\CMSWindowsScreenSaver.h
|
||||||
# End Source File
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsUtil.h
|
||||||
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
# End Target
|
# End Target
|
||||||
# End Project
|
# End Project
|
||||||
|
|
|
@ -47,13 +47,13 @@ CClientListener::CClientListener(const CNetworkAddress& address,
|
||||||
LOG((CLOG_DEBUG1 "binding listen socket"));
|
LOG((CLOG_DEBUG1 "binding listen socket"));
|
||||||
m_listen->bind(address);
|
m_listen->bind(address);
|
||||||
}
|
}
|
||||||
catch (XSocketAddressInUse& e) {
|
catch (XSocketAddressInUse&) {
|
||||||
delete m_listen;
|
delete m_listen;
|
||||||
delete m_socketFactory;
|
delete m_socketFactory;
|
||||||
delete m_streamFilterFactory;
|
delete m_streamFilterFactory;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase&) {
|
||||||
delete m_listen;
|
delete m_listen;
|
||||||
delete m_socketFactory;
|
delete m_socketFactory;
|
||||||
delete m_streamFilterFactory;
|
delete m_streamFilterFactory;
|
||||||
|
|
|
@ -37,8 +37,8 @@ CEvent::Type CServer::s_errorEvent = CEvent::kUnknown;
|
||||||
CEvent::Type CServer::s_disconnectedEvent = CEvent::kUnknown;
|
CEvent::Type CServer::s_disconnectedEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
|
CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
|
||||||
m_active(primaryClient),
|
|
||||||
m_primaryClient(primaryClient),
|
m_primaryClient(primaryClient),
|
||||||
|
m_active(primaryClient),
|
||||||
m_seqNum(0),
|
m_seqNum(0),
|
||||||
m_config(config),
|
m_config(config),
|
||||||
m_activeSaver(NULL),
|
m_activeSaver(NULL),
|
||||||
|
@ -117,9 +117,6 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient) :
|
||||||
// add connection
|
// add connection
|
||||||
addClient(m_primaryClient);
|
addClient(m_primaryClient);
|
||||||
|
|
||||||
// tell it about the active sides
|
|
||||||
m_primaryClient->reconfigure(getActivePrimarySides());
|
|
||||||
|
|
||||||
// tell primary client about its options
|
// tell primary client about its options
|
||||||
sendOptions(m_primaryClient);
|
sendOptions(m_primaryClient);
|
||||||
|
|
||||||
|
@ -171,8 +168,7 @@ bool
|
||||||
CServer::setConfig(const CConfig& config)
|
CServer::setConfig(const CConfig& config)
|
||||||
{
|
{
|
||||||
// refuse configuration if it doesn't include the primary screen
|
// refuse configuration if it doesn't include the primary screen
|
||||||
if (m_primaryClient != NULL &&
|
if (!config.isScreen(m_primaryClient->getName())) {
|
||||||
!config.isScreen(m_primaryClient->getName())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,9 +181,7 @@ CServer::setConfig(const CConfig& config)
|
||||||
processOptions();
|
processOptions();
|
||||||
|
|
||||||
// tell primary screen about reconfiguration
|
// tell primary screen about reconfiguration
|
||||||
if (m_primaryClient != NULL) {
|
|
||||||
m_primaryClient->reconfigure(getActivePrimarySides());
|
m_primaryClient->reconfigure(getActivePrimarySides());
|
||||||
}
|
|
||||||
|
|
||||||
// tell all (connected) clients about current options
|
// tell all (connected) clients about current options
|
||||||
for (CClientList::const_iterator index = m_clients.begin();
|
for (CClientList::const_iterator index = m_clients.begin();
|
||||||
|
@ -296,18 +290,17 @@ CServer::getName(const IClient* client) const
|
||||||
UInt32
|
UInt32
|
||||||
CServer::getActivePrimarySides() const
|
CServer::getActivePrimarySides() const
|
||||||
{
|
{
|
||||||
CString primaryName = getName(m_primaryClient);
|
|
||||||
UInt32 sides = 0;
|
UInt32 sides = 0;
|
||||||
if (!m_config.getNeighbor(primaryName, kLeft).empty()) {
|
if (getNeighbor(m_primaryClient, kLeft) != NULL) {
|
||||||
sides |= kLeftMask;
|
sides |= kLeftMask;
|
||||||
}
|
}
|
||||||
if (!m_config.getNeighbor(primaryName, kRight).empty()) {
|
if (getNeighbor(m_primaryClient, kRight) != NULL) {
|
||||||
sides |= kRightMask;
|
sides |= kRightMask;
|
||||||
}
|
}
|
||||||
if (!m_config.getNeighbor(primaryName, kTop).empty()) {
|
if (getNeighbor(m_primaryClient, kTop) != NULL) {
|
||||||
sides |= kTopMask;
|
sides |= kTopMask;
|
||||||
}
|
}
|
||||||
if (!m_config.getNeighbor(primaryName, kBottom).empty()) {
|
if (getNeighbor(m_primaryClient, kBottom) != NULL) {
|
||||||
sides |= kBottomMask;
|
sides |= kBottomMask;
|
||||||
}
|
}
|
||||||
return sides;
|
return sides;
|
||||||
|
@ -546,6 +539,10 @@ CServer::getNeighbor(IClient* src,
|
||||||
assert(lastGoodScreen != NULL);
|
assert(lastGoodScreen != NULL);
|
||||||
y += dy;
|
y += dy;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kNoDirection:
|
||||||
|
assert(0 && "bad direction");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save destination screen
|
// save destination screen
|
||||||
|
@ -582,6 +579,10 @@ CServer::getNeighbor(IClient* src,
|
||||||
y < dy + getJumpZoneSize(dst))
|
y < dy + getJumpZoneSize(dst))
|
||||||
y = dy + getJumpZoneSize(dst);
|
y = dy + getJumpZoneSize(dst);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kNoDirection:
|
||||||
|
assert(0 && "bad direction");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,6 +624,10 @@ CServer::getNeighbor(IClient* src,
|
||||||
}
|
}
|
||||||
x += dx;
|
x += dx;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kNoDirection:
|
||||||
|
assert(0 && "bad direction");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
|
@ -999,13 +1004,13 @@ CServer::handleWheelEvent(const CEvent& event, void*)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServer::handleScreensaverActivatedEvent(const CEvent& event, void*)
|
CServer::handleScreensaverActivatedEvent(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
onScreensaver(true);
|
onScreensaver(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServer::handleScreensaverDeactivatedEvent(const CEvent& event, void*)
|
CServer::handleScreensaverDeactivatedEvent(const CEvent&, void*)
|
||||||
{
|
{
|
||||||
onScreensaver(false);
|
onScreensaver(false);
|
||||||
}
|
}
|
||||||
|
@ -1212,7 +1217,6 @@ CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
|
||||||
LOG((CLOG_DEBUG2 "onMouseMovePrimary %d,%d", x, y));
|
LOG((CLOG_DEBUG2 "onMouseMovePrimary %d,%d", x, y));
|
||||||
|
|
||||||
// mouse move on primary (server's) screen
|
// mouse move on primary (server's) screen
|
||||||
assert(m_primaryClient != NULL);
|
|
||||||
assert(m_active == m_primaryClient);
|
assert(m_active == m_primaryClient);
|
||||||
|
|
||||||
// save position
|
// save position
|
||||||
|
@ -1429,6 +1433,10 @@ CServer::addClient(IClient* client)
|
||||||
// add to list
|
// add to list
|
||||||
m_clientSet.insert(client);
|
m_clientSet.insert(client);
|
||||||
m_clients.insert(std::make_pair(name, client));
|
m_clients.insert(std::make_pair(name, client));
|
||||||
|
|
||||||
|
// tell primary client about the active sides
|
||||||
|
m_primaryClient->reconfigure(getActivePrimarySides());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1452,6 +1460,7 @@ CServer::removeClient(IClient* client)
|
||||||
// remove from list
|
// remove from list
|
||||||
m_clients.erase(i);
|
m_clients.erase(i);
|
||||||
m_clientSet.erase(client);
|
m_clientSet.erase(client);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1477,7 +1486,7 @@ CServer::closeClient(IClient* client, const char* msg)
|
||||||
|
|
||||||
// install timer. wait timeout seconds for client to close.
|
// install timer. wait timeout seconds for client to close.
|
||||||
double timeout = 5.0;
|
double timeout = 5.0;
|
||||||
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(5.0, NULL);
|
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
|
||||||
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
||||||
new TMethodEventJob<CServer>(this,
|
new TMethodEventJob<CServer>(this,
|
||||||
&CServer::handleClientCloseTimeout, client));
|
&CServer::handleClientCloseTimeout, client));
|
||||||
|
@ -1577,6 +1586,9 @@ CServer::forceLeaveClient(IClient* client)
|
||||||
if (m_activeSaver == client) {
|
if (m_activeSaver == client) {
|
||||||
m_activeSaver = NULL;
|
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)
|
CProtocolUtil::vreadf(IStream* stream, const char* fmt, va_list args)
|
||||||
{
|
{
|
||||||
assert(stream != NULL);
|
assert(stream != NULL);
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static void vwritef(IStream*,
|
static void vwritef(IStream*,
|
||||||
const char* fmt, UInt32 size, va_list);
|
const char* fmt, UInt32 size, va_list);
|
||||||
static bool vreadf(IStream*,
|
static void vreadf(IStream*,
|
||||||
const char* fmt, va_list);
|
const char* fmt, va_list);
|
||||||
|
|
||||||
static UInt32 getLength(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_isPrimary(platformScreen->isPrimary()),
|
||||||
m_enabled(false),
|
m_enabled(false),
|
||||||
m_entered(m_isPrimary),
|
m_entered(m_isPrimary),
|
||||||
m_toggleKeys(0),
|
m_screenSaverSync(true),
|
||||||
m_screenSaverSync(true)
|
m_toggleKeys(0)
|
||||||
{
|
{
|
||||||
assert(m_screen != NULL);
|
assert(m_screen != NULL);
|
||||||
|
|
||||||
|
@ -376,7 +376,7 @@ CScreen::setOptions(const COptionsList& options)
|
||||||
void
|
void
|
||||||
CScreen::setSequenceNumber(UInt32 seqNum)
|
CScreen::setSequenceNumber(UInt32 seqNum)
|
||||||
{
|
{
|
||||||
return m_screen->setSequenceNumber(seqNum);
|
m_screen->setSequenceNumber(seqNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -73,8 +73,7 @@ public:
|
||||||
//! Get shape changed event type
|
//! Get shape changed event type
|
||||||
/*!
|
/*!
|
||||||
Returns the shape changed event type. This is sent whenever the
|
Returns the shape changed event type. This is sent whenever the
|
||||||
screen's shape changes, the cursor center moves, or the jump zone
|
screen's shape changes.
|
||||||
size changes.
|
|
||||||
*/
|
*/
|
||||||
static CEvent::Type getShapeChangedEvent();
|
static CEvent::Type getShapeChangedEvent();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue