Some work toward Issue 27 and Issue 319
This commit is contained in:
parent
fea12827d4
commit
f974d8d680
|
@ -1,7 +1,7 @@
|
||||||
# Version number for Synergy+
|
# Version number for Synergy+
|
||||||
SET(VERSION_MAJOR 1)
|
SET(VERSION_MAJOR 1)
|
||||||
SET(VERSION_MINOR 3)
|
SET(VERSION_MINOR 4)
|
||||||
SET(VERSION_REV 5)
|
SET(VERSION_REV 0)
|
||||||
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}")
|
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}")
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,11 +44,28 @@ INCLUDE(${cmake_dir}/CMakeLists_cpack.txt)
|
||||||
IF(WIN32)
|
IF(WIN32)
|
||||||
# add /analyze in order to unconver potential bugs in the source code
|
# add /analyze in order to unconver potential bugs in the source code
|
||||||
# Details: http://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx
|
# Details: http://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx
|
||||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /analyze")
|
# add /FR to generate browse information (ncb files) usefull for using IDE
|
||||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /analyze")
|
|
||||||
|
#define _BIND_TO_CURRENT_CRT_VERSION 1
|
||||||
|
#define _BIND_TO_CURRENT_ATL_VERSION 1
|
||||||
|
#define _BIND_TO_CURRENT_MFC_VERSION 1
|
||||||
|
#define _BIND_TO_CURRENT_OPENMP_VERSION 1
|
||||||
|
# next line replaced the previous 4 ones:
|
||||||
|
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1;
|
||||||
|
|
||||||
|
# compiler: /MP - use multi cores to compile
|
||||||
|
# added _SECURE_SCL=1 for finding bugs with iterators - http://msdn.microsoft.com/en-us/library/aa985965.aspx
|
||||||
|
|
||||||
|
# common args between all vs builds
|
||||||
|
SET(VS_ARGS "/FR /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1 /D _SECURE_SCL=1 ${VS_ARGS_EXTRA}")
|
||||||
|
|
||||||
|
# we may use `cmake -D VS_ARGS_EXTRA="/analyze"` for example to specify
|
||||||
|
# analyze mode (since we don't always want to use it; e.g. on non-team
|
||||||
|
# or non-x86 compiler editions where there's no support)
|
||||||
|
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${VS_ARGS}")
|
||||||
|
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${VS_ARGS}")
|
||||||
|
|
||||||
# this line removes "/D NDEBUG" from release, we want them in order to find bugs even on release builds.
|
|
||||||
SET(CMAKE_CXX_FLAGS_RELEASE "/MD /O2 /Ob2")
|
|
||||||
ENDIF(WIN32)
|
ENDIF(WIN32)
|
||||||
|
|
||||||
|
# this line removes "/D NDEBUG" from release, we want them in order to find bugs even on release builds.
|
||||||
|
SET(CMAKE_CXX_FLAGS_RELEASE "/MD /O2 /Ob2")
|
||||||
|
|
|
@ -17,6 +17,18 @@ INSTALL(
|
||||||
TARGETS ${cpack_targets}
|
TARGETS ${cpack_targets}
|
||||||
RUNTIME DESTINATION bin)
|
RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
IF(WIN32)
|
||||||
|
INSTALL(
|
||||||
|
FILES
|
||||||
|
bin/Release/QtNetwork4.dll
|
||||||
|
bin/Release/QtGui4.dll
|
||||||
|
bin/Release/QtCore4.dll
|
||||||
|
bin/Release/qsynergy.exe
|
||||||
|
bin/Release/mingwm10.dll
|
||||||
|
bin/Release/libgcc_s_dw2-1.dll
|
||||||
|
DESTINATION bin)
|
||||||
|
ENDIF(WIN32)
|
||||||
|
|
||||||
# The default CPack behaviour is not to append the system processor
|
# The default CPack behaviour is not to append the system processor
|
||||||
# type, which is undesirable in our case, since we want to support
|
# type, which is undesirable in our case, since we want to support
|
||||||
# both 32-bit and 64-bit processors.
|
# both 32-bit and 64-bit processors.
|
||||||
|
@ -62,7 +74,7 @@ IF(WIN32)
|
||||||
SET(CPACK_NSIS_MUI_UNIICON ${WIN32_ICON})
|
SET(CPACK_NSIS_MUI_UNIICON ${WIN32_ICON})
|
||||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME launcher)
|
SET(CPACK_NSIS_INSTALLED_ICON_NAME launcher)
|
||||||
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "Synergy+")
|
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "Synergy+")
|
||||||
SET(CPACK_PACKAGE_EXECUTABLES launcher;Synergy+)
|
SET(CPACK_PACKAGE_EXECUTABLES qsynergy;Synergy+)
|
||||||
ENDIF(WIN32)
|
ENDIF(WIN32)
|
||||||
|
|
||||||
# For source package, leave out temp and Mercurial stuff.
|
# For source package, leave out temp and Mercurial stuff.
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
SET(root_lib ${root_dir}/lib)
|
SET(root_lib ${root_dir}/lib)
|
||||||
|
|
||||||
SET(src_lib_arch
|
SET(src_lib_arch
|
||||||
|
${root_lib}/arch/CArchAppUtil.cpp
|
||||||
${root_lib}/arch/CArch.cpp
|
${root_lib}/arch/CArch.cpp
|
||||||
${root_lib}/arch/CArchDaemonNone.cpp
|
${root_lib}/arch/CArchDaemonNone.cpp
|
||||||
${root_lib}/arch/XArch.cpp
|
${root_lib}/arch/XArch.cpp
|
||||||
|
${root_lib}/arch/CArchConsoleStd.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(src_lib_arch_unix
|
SET(src_lib_arch_unix
|
||||||
|
${root_lib}/arch/CArchAppUtilUnix.cpp
|
||||||
${root_lib}/arch/CArchConsoleUnix.cpp
|
${root_lib}/arch/CArchConsoleUnix.cpp
|
||||||
${root_lib}/arch/CArchDaemonUnix.cpp
|
${root_lib}/arch/CArchDaemonUnix.cpp
|
||||||
${root_lib}/arch/CArchFileUnix.cpp
|
${root_lib}/arch/CArchFileUnix.cpp
|
||||||
|
@ -22,6 +25,7 @@ SET(src_lib_arch_unix
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(src_lib_arch_windows
|
SET(src_lib_arch_windows
|
||||||
|
${root_lib}/arch/CArchAppUtilWindows.cpp
|
||||||
${root_lib}/arch/CArchConsoleWindows.cpp
|
${root_lib}/arch/CArchConsoleWindows.cpp
|
||||||
${root_lib}/arch/CArchDaemonWindows.cpp
|
${root_lib}/arch/CArchDaemonWindows.cpp
|
||||||
${root_lib}/arch/CArchFileWindows.cpp
|
${root_lib}/arch/CArchFileWindows.cpp
|
||||||
|
@ -38,6 +42,8 @@ SET(src_lib_arch_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(inc_lib_arch_windows
|
SET(inc_lib_arch_windows
|
||||||
|
${root_lib}/arch/CArchAppUtil.h
|
||||||
|
${root_lib}/arch/CArchAppUtilWindows.h
|
||||||
${root_lib}/arch/CArchConsoleWindows.h
|
${root_lib}/arch/CArchConsoleWindows.h
|
||||||
${root_lib}/arch/CArchDaemonWindows.h
|
${root_lib}/arch/CArchDaemonWindows.h
|
||||||
${root_lib}/arch/CArchFileWindows.h
|
${root_lib}/arch/CArchFileWindows.h
|
||||||
|
@ -50,6 +56,8 @@ SET(inc_lib_arch_windows
|
||||||
${root_lib}/arch/CArchSystemWindows.h
|
${root_lib}/arch/CArchSystemWindows.h
|
||||||
${root_lib}/arch/CArchTaskBarWindows.h
|
${root_lib}/arch/CArchTaskBarWindows.h
|
||||||
${root_lib}/arch/CArchTimeWindows.h
|
${root_lib}/arch/CArchTimeWindows.h
|
||||||
|
${root_lib}/arch/CArchConsoleStd.h
|
||||||
|
${root_lib}/arch/IArchAppUtil.h
|
||||||
${root_lib}/arch/XArchWindows.h
|
${root_lib}/arch/XArchWindows.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -264,6 +272,11 @@ SET(inc_lib_server
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(src_lib_synergy
|
SET(src_lib_synergy
|
||||||
|
${root_lib}/synergy/CClientTaskBarReceiver.cpp
|
||||||
|
${root_lib}/synergy/CServerTaskBarReceiver.cpp
|
||||||
|
${root_lib}/synergy/CApp.cpp
|
||||||
|
${root_lib}/synergy/CClientApp.cpp
|
||||||
|
${root_lib}/synergy/CServerApp.cpp
|
||||||
${root_lib}/synergy/CClipboard.cpp
|
${root_lib}/synergy/CClipboard.cpp
|
||||||
${root_lib}/synergy/CKeyMap.cpp
|
${root_lib}/synergy/CKeyMap.cpp
|
||||||
${root_lib}/synergy/CKeyState.cpp
|
${root_lib}/synergy/CKeyState.cpp
|
||||||
|
@ -282,6 +295,11 @@ SET(src_lib_synergy
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(inc_lib_synergy
|
SET(inc_lib_synergy
|
||||||
|
${root_lib}/synergy/CClientTaskBarReceiver.h
|
||||||
|
${root_lib}/synergy/CServerTaskBarReceiver.h
|
||||||
|
${root_lib}/synergy/CApp.h
|
||||||
|
${root_lib}/synergy/CClientApp.h
|
||||||
|
${root_lib}/synergy/CServerApp.h
|
||||||
${root_lib}/synergy/CClipboard.h
|
${root_lib}/synergy/CClipboard.h
|
||||||
${root_lib}/synergy/CKeyMap.h
|
${root_lib}/synergy/CKeyMap.h
|
||||||
${root_lib}/synergy/CKeyState.h
|
${root_lib}/synergy/CKeyState.h
|
||||||
|
@ -324,9 +342,17 @@ IF(UNIX)
|
||||||
LIST(APPEND src_lib ${src_lib_arch_unix})
|
LIST(APPEND src_lib ${src_lib_arch_unix})
|
||||||
|
|
||||||
IF(APPLE)
|
IF(APPLE)
|
||||||
LIST(APPEND src_lib ${src_lib_platform_carbon})
|
LIST(APPEND src_lib
|
||||||
|
${src_lib_platform_carbon}
|
||||||
|
${inc_lib_synergy_carbon}
|
||||||
|
${src_lib_synergy_carbon}
|
||||||
|
)
|
||||||
ELSE(APPLE)
|
ELSE(APPLE)
|
||||||
LIST(APPEND src_lib ${src_lib_platform_xwindows})
|
LIST(APPEND src_lib
|
||||||
|
${src_lib_platform_xwindows}
|
||||||
|
${inc_lib_synergy_xwindows}
|
||||||
|
${src_lib_synergy_xwindows}
|
||||||
|
)
|
||||||
ENDIF(APPLE)
|
ENDIF(APPLE)
|
||||||
|
|
||||||
ENDIF(UNIX)
|
ENDIF(UNIX)
|
||||||
|
@ -345,6 +371,8 @@ IF(WIN32)
|
||||||
${src_lib_arch_windows}
|
${src_lib_arch_windows}
|
||||||
${inc_lib_platform_mswindows}
|
${inc_lib_platform_mswindows}
|
||||||
${src_lib_platform_mswindows}
|
${src_lib_platform_mswindows}
|
||||||
|
${inc_lib_synergy_mswindows}
|
||||||
|
${src_lib_synergy_mswindows}
|
||||||
)
|
)
|
||||||
ENDIF(WIN32)
|
ENDIF(WIN32)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
SET(root_cmd_synergyc ${root_dir}/cmd/synergyc)
|
SET(root_cmd_synergyc ${root_dir}/cmd/synergyc)
|
||||||
|
|
||||||
SET(src_cmd_synergyc_common
|
SET(src_cmd_synergyc_common
|
||||||
${root_cmd_synergyc}/CClientTaskBarReceiver.cpp
|
|
||||||
${root_cmd_synergyc}/synergyc.cpp
|
${root_cmd_synergyc}/synergyc.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -66,5 +65,5 @@ SET(inc_dirs_cmd_synergyc
|
||||||
)
|
)
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES(${inc_dirs_cmd_synergyc})
|
INCLUDE_DIRECTORIES(${inc_dirs_cmd_synergyc})
|
||||||
ADD_EXECUTABLE(synergyc WIN32 ${src_cmd_synergyc})
|
ADD_EXECUTABLE(synergyc ${src_cmd_synergyc})
|
||||||
TARGET_LINK_LIBRARIES(synergyc synergy ${libs})
|
TARGET_LINK_LIBRARIES(synergyc synergy ${libs})
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
SET(root_cmd_synergys ${root_dir}/cmd/synergys)
|
SET(root_cmd_synergys ${root_dir}/cmd/synergys)
|
||||||
|
|
||||||
SET(src_cmd_synergys_common
|
SET(src_cmd_synergys_common
|
||||||
${root_cmd_synergys}/CServerTaskBarReceiver.cpp
|
|
||||||
${root_cmd_synergys}/synergys.cpp
|
${root_cmd_synergys}/synergys.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,7 +13,6 @@ SET(src_cmd_synergys_mswindows
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(inc_cmd_synergys_mswindows
|
SET(inc_cmd_synergys_mswindows
|
||||||
${root_cmd_synergys}/CServerTaskBarReceiver.h
|
|
||||||
${root_cmd_synergys}/CXWindowsServerTaskBarReceiver.h
|
${root_cmd_synergys}/CXWindowsServerTaskBarReceiver.h
|
||||||
${root_cmd_synergys}/resource.h
|
${root_cmd_synergys}/resource.h
|
||||||
${root_cmd_synergys}/COSXServerTaskBarReceiver.h
|
${root_cmd_synergys}/COSXServerTaskBarReceiver.h
|
||||||
|
@ -69,5 +67,5 @@ SET(inc_dirs_cmd_synergys
|
||||||
)
|
)
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES(${inc_dirs_cmd_synergys})
|
INCLUDE_DIRECTORIES(${inc_dirs_cmd_synergys})
|
||||||
ADD_EXECUTABLE(synergys WIN32 ${src_cmd_synergys})
|
ADD_EXECUTABLE(synergys ${src_cmd_synergys})
|
||||||
TARGET_LINK_LIBRARIES(synergys synergy ${libs})
|
TARGET_LINK_LIBRARIES(synergys synergy ${libs})
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
#include "LaunchUtil.h"
|
#include "LaunchUtil.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
|
||||||
static const char* CLIENT_DAEMON_NAME = "Synergy Client";
|
static const char* CLIENT_DAEMON_NAME = "Synergy+ Client";
|
||||||
static const char* SERVER_DAEMON_NAME = "Synergy Server";
|
static const char* SERVER_DAEMON_NAME = "Synergy+ Server";
|
||||||
static const char* CLIENT_DAEMON_INFO = "Uses a shared mouse and keyboard.";
|
static const char* CLIENT_DAEMON_INFO = "Uses a shared mouse and keyboard.";
|
||||||
static const char* SERVER_DAEMON_INFO = "Shares this system's mouse and keyboard with others.";
|
static const char* SERVER_DAEMON_INFO = "Shares this system's mouse and keyboard with others.";
|
||||||
|
|
||||||
|
|
|
@ -675,7 +675,9 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmdLine, int nCmdShow)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
CArch arch(instance);
|
CArchMiscWindows::setInstanceWin32(instance);
|
||||||
|
|
||||||
|
CArch arch;
|
||||||
CLOG;
|
CLOG;
|
||||||
CArgs args;
|
CArgs args;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
#include "BasicTypes.h"
|
#include "BasicTypes.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "CArchTaskBarWindows.h"
|
#include "CArchTaskBarWindows.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CMSWindowsClientTaskBarReceiver
|
// CMSWindowsClientTaskBarReceiver
|
||||||
|
@ -343,3 +345,20 @@ CMSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd,
|
||||||
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
|
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IArchTaskBarReceiver*
|
||||||
|
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
|
{
|
||||||
|
CArchMiscWindows::setIcons(
|
||||||
|
(HICON)LoadImage(CArchMiscWindows::instanceWin32(),
|
||||||
|
MAKEINTRESOURCE(IDI_SYNERGY),
|
||||||
|
IMAGE_ICON,
|
||||||
|
32, 32, LR_SHARED),
|
||||||
|
(HICON)LoadImage(CArchMiscWindows::instanceWin32(),
|
||||||
|
MAKEINTRESOURCE(IDI_SYNERGY),
|
||||||
|
IMAGE_ICON,
|
||||||
|
16, 16, LR_SHARED));
|
||||||
|
|
||||||
|
return new CMSWindowsClientTaskBarReceiver(
|
||||||
|
CMSWindowsScreen::getInstance(), logBuffer);
|
||||||
|
}
|
||||||
|
|
|
@ -54,3 +54,10 @@ COSXClientTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IArchTaskBarReceiver*
|
||||||
|
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
|
{
|
||||||
|
return new COSXClientTaskBarReceiver(logBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,3 +54,9 @@ CXWindowsClientTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IArchTaskBarReceiver*
|
||||||
|
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
|
{
|
||||||
|
return new CXWindowsClientTaskBarReceiver(logBuffer);
|
||||||
|
}
|
||||||
|
|
|
@ -12,943 +12,21 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CClient.h"
|
#include "CClientApp.h"
|
||||||
#include "CScreen.h"
|
|
||||||
#include "ProtocolTypes.h"
|
|
||||||
#include "Version.h"
|
|
||||||
#include "XScreen.h"
|
|
||||||
#include "CNetworkAddress.h"
|
|
||||||
#include "CSocketMultiplexer.h"
|
|
||||||
#include "CTCPSocketFactory.h"
|
|
||||||
#include "XSocket.h"
|
|
||||||
#include "CThread.h"
|
|
||||||
#include "CEventQueue.h"
|
|
||||||
#include "CFunctionEventJob.h"
|
|
||||||
#include "CFunctionJob.h"
|
|
||||||
#include "CLog.h"
|
|
||||||
#include "CString.h"
|
|
||||||
#include "CStringUtil.h"
|
|
||||||
#include "LogOutputters.h"
|
|
||||||
#include "CArch.h"
|
|
||||||
#include "XArch.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#define DAEMON_RUNNING(running_)
|
|
||||||
#if WINAPI_MSWINDOWS
|
#if WINAPI_MSWINDOWS
|
||||||
#include "CArchMiscWindows.h"
|
|
||||||
#include "CMSWindowsScreen.h"
|
|
||||||
#include "CMSWindowsUtil.h"
|
|
||||||
#include "CMSWindowsClientTaskBarReceiver.h"
|
#include "CMSWindowsClientTaskBarReceiver.h"
|
||||||
#include "resource.h"
|
|
||||||
#undef DAEMON_RUNNING
|
|
||||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
|
||||||
#elif WINAPI_XWINDOWS
|
#elif WINAPI_XWINDOWS
|
||||||
#include "CXWindowsScreen.h"
|
|
||||||
#include "CXWindowsClientTaskBarReceiver.h"
|
#include "CXWindowsClientTaskBarReceiver.h"
|
||||||
#elif WINAPI_CARBON
|
#elif WINAPI_CARBON
|
||||||
#include "COSXScreen.h"
|
|
||||||
#include "COSXClientTaskBarReceiver.h"
|
#include "COSXClientTaskBarReceiver.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
// platform dependent name of a daemon
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
#define DAEMON_NAME "Synergy+ Client"
|
|
||||||
#elif SYSAPI_UNIX
|
|
||||||
#define DAEMON_NAME "synergyc"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef int (*StartupFunc)(int, char**);
|
|
||||||
static bool startClient();
|
|
||||||
static void parse(int argc, const char* const* argv);
|
|
||||||
|
|
||||||
//
|
|
||||||
// program arguments
|
|
||||||
//
|
|
||||||
|
|
||||||
#define ARG CArgs::s_instance
|
|
||||||
|
|
||||||
class CArgs {
|
|
||||||
public:
|
|
||||||
CArgs() :
|
|
||||||
m_pname(NULL),
|
|
||||||
m_backend(false),
|
|
||||||
m_restartable(true),
|
|
||||||
m_daemon(true),
|
|
||||||
m_yscroll(0),
|
|
||||||
m_logFilter(NULL),
|
|
||||||
m_display(NULL),
|
|
||||||
m_serverAddress(NULL),
|
|
||||||
m_logFile(NULL)
|
|
||||||
{ s_instance = this; }
|
|
||||||
~CArgs() { s_instance = NULL; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
static CArgs* s_instance;
|
|
||||||
const char* m_pname;
|
|
||||||
bool m_backend;
|
|
||||||
bool m_restartable;
|
|
||||||
bool m_daemon;
|
|
||||||
int m_yscroll;
|
|
||||||
const char* m_logFilter;
|
|
||||||
const char* m_display;
|
|
||||||
CString m_name;
|
|
||||||
CNetworkAddress* m_serverAddress;
|
|
||||||
const char* m_logFile;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
CArgs* CArgs::s_instance = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// platform dependent factories
|
|
||||||
//
|
|
||||||
|
|
||||||
static
|
|
||||||
CScreen*
|
|
||||||
createScreen()
|
|
||||||
{
|
|
||||||
#if WINAPI_MSWINDOWS
|
|
||||||
return new CScreen(new CMSWindowsScreen(false));
|
|
||||||
#elif WINAPI_XWINDOWS
|
|
||||||
return new CScreen(new CXWindowsScreen(ARG->m_display, false, ARG->m_yscroll));
|
|
||||||
#elif WINAPI_CARBON
|
|
||||||
return new CScreen(new COSXScreen(false));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
CClientTaskBarReceiver*
|
|
||||||
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
|
||||||
{
|
|
||||||
#if WINAPI_MSWINDOWS
|
|
||||||
return new CMSWindowsClientTaskBarReceiver(
|
|
||||||
CMSWindowsScreen::getInstance(), logBuffer);
|
|
||||||
#elif WINAPI_XWINDOWS
|
|
||||||
return new CXWindowsClientTaskBarReceiver(logBuffer);
|
|
||||||
#elif WINAPI_CARBON
|
|
||||||
return new COSXClientTaskBarReceiver(logBuffer);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// platform independent main
|
|
||||||
//
|
|
||||||
|
|
||||||
static CClient* s_client = NULL;
|
|
||||||
static CScreen* s_clientScreen = NULL;
|
|
||||||
static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
|
|
||||||
//static double s_retryTime = 0.0;
|
|
||||||
static bool s_suspened = false;
|
|
||||||
|
|
||||||
#define RETRY_TIME 1.0
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
updateStatus()
|
|
||||||
{
|
|
||||||
s_taskBarReceiver->updateStatus(s_client, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
updateStatus(const CString& msg)
|
|
||||||
{
|
|
||||||
s_taskBarReceiver->updateStatus(s_client, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
resetRestartTimeout()
|
|
||||||
{
|
|
||||||
// retry time can nolonger be changed
|
|
||||||
//s_retryTime = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
double
|
|
||||||
nextRestartTimeout()
|
|
||||||
{
|
|
||||||
// retry at a constant rate (Issue 52)
|
|
||||||
return RETRY_TIME;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// choose next restart timeout. we start with rapid retries
|
|
||||||
// then slow down.
|
|
||||||
if (s_retryTime < 1.0) {
|
|
||||||
s_retryTime = 1.0;
|
|
||||||
}
|
|
||||||
else if (s_retryTime < 3.0) {
|
|
||||||
s_retryTime = 3.0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_retryTime = 5.0;
|
|
||||||
}
|
|
||||||
return s_retryTime;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
handleScreenError(const CEvent&, void*)
|
|
||||||
{
|
|
||||||
LOG((CLOG_CRIT "error on screen"));
|
|
||||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
CScreen*
|
|
||||||
openClientScreen()
|
|
||||||
{
|
|
||||||
CScreen* screen = createScreen();
|
|
||||||
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
|
||||||
screen->getEventTarget(),
|
|
||||||
new CFunctionEventJob(
|
|
||||||
&handleScreenError));
|
|
||||||
return screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
closeClientScreen(CScreen* screen)
|
|
||||||
{
|
|
||||||
if (screen != NULL) {
|
|
||||||
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
|
||||||
screen->getEventTarget());
|
|
||||||
delete screen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
handleClientRestart(const CEvent&, void* vtimer)
|
|
||||||
{
|
|
||||||
// discard old timer
|
|
||||||
CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer);
|
|
||||||
EVENTQUEUE->deleteTimer(timer);
|
|
||||||
EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
|
|
||||||
|
|
||||||
// reconnect
|
|
||||||
startClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
scheduleClientRestart(double retryTime)
|
|
||||||
{
|
|
||||||
// install a timer and handler to retry later
|
|
||||||
LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
|
|
||||||
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
|
|
||||||
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
|
||||||
new CFunctionEventJob(&handleClientRestart, timer));
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
handleClientConnected(const CEvent&, void*)
|
|
||||||
{
|
|
||||||
LOG((CLOG_NOTE "connected to server"));
|
|
||||||
resetRestartTimeout();
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
handleClientFailed(const CEvent& e, void*)
|
|
||||||
{
|
|
||||||
CClient::CFailInfo* info =
|
|
||||||
reinterpret_cast<CClient::CFailInfo*>(e.getData());
|
|
||||||
|
|
||||||
updateStatus(CString("Failed to connect to server: ") + info->m_what);
|
|
||||||
if (!ARG->m_restartable || !info->m_retry) {
|
|
||||||
LOG((CLOG_ERR "failed to connect to server: %s", info->m_what));
|
|
||||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG((CLOG_WARN "failed to connect to server: %s", info->m_what));
|
|
||||||
if (!s_suspened) {
|
|
||||||
scheduleClientRestart(nextRestartTimeout());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
handleClientDisconnected(const CEvent&, void*)
|
|
||||||
{
|
|
||||||
LOG((CLOG_NOTE "disconnected from server"));
|
|
||||||
if (!ARG->m_restartable) {
|
|
||||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
|
||||||
}
|
|
||||||
else if (!s_suspened) {
|
|
||||||
s_client->connect();
|
|
||||||
}
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
CClient*
|
|
||||||
openClient(const CString& name, const CNetworkAddress& address, CScreen* screen)
|
|
||||||
{
|
|
||||||
CClient* client = new CClient(name, address,
|
|
||||||
new CTCPSocketFactory, NULL, screen);
|
|
||||||
EVENTQUEUE->adoptHandler(CClient::getConnectedEvent(),
|
|
||||||
client->getEventTarget(),
|
|
||||||
new CFunctionEventJob(handleClientConnected));
|
|
||||||
EVENTQUEUE->adoptHandler(CClient::getConnectionFailedEvent(),
|
|
||||||
client->getEventTarget(),
|
|
||||||
new CFunctionEventJob(handleClientFailed));
|
|
||||||
EVENTQUEUE->adoptHandler(CClient::getDisconnectedEvent(),
|
|
||||||
client->getEventTarget(),
|
|
||||||
new CFunctionEventJob(handleClientDisconnected));
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
closeClient(CClient* client)
|
|
||||||
{
|
|
||||||
if (client == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVENTQUEUE->removeHandler(CClient::getConnectedEvent(), client);
|
|
||||||
EVENTQUEUE->removeHandler(CClient::getConnectionFailedEvent(), client);
|
|
||||||
EVENTQUEUE->removeHandler(CClient::getDisconnectedEvent(), client);
|
|
||||||
delete client;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
bool
|
|
||||||
startClient()
|
|
||||||
{
|
|
||||||
double retryTime;
|
|
||||||
CScreen* clientScreen = NULL;
|
|
||||||
try {
|
|
||||||
if (s_clientScreen == NULL) {
|
|
||||||
clientScreen = openClientScreen();
|
|
||||||
s_client = openClient(ARG->m_name,
|
|
||||||
*ARG->m_serverAddress, clientScreen);
|
|
||||||
s_clientScreen = clientScreen;
|
|
||||||
LOG((CLOG_NOTE "started client"));
|
|
||||||
}
|
|
||||||
s_client->connect();
|
|
||||||
updateStatus();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (XScreenUnavailable& e) {
|
|
||||||
LOG((CLOG_WARN "cannot open secondary screen: %s", e.what()));
|
|
||||||
closeClientScreen(clientScreen);
|
|
||||||
updateStatus(CString("Cannot open secondary screen: ") + e.what());
|
|
||||||
retryTime = e.getRetryTime();
|
|
||||||
}
|
|
||||||
catch (XScreenOpenFailure& e) {
|
|
||||||
LOG((CLOG_CRIT "cannot open secondary screen: %s", e.what()));
|
|
||||||
closeClientScreen(clientScreen);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (XBase& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start client: %s", e.what()));
|
|
||||||
closeClientScreen(clientScreen);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ARG->m_restartable) {
|
|
||||||
scheduleClientRestart(retryTime);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// don't try again
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
stopClient()
|
|
||||||
{
|
|
||||||
closeClient(s_client);
|
|
||||||
closeClientScreen(s_clientScreen);
|
|
||||||
s_client = NULL;
|
|
||||||
s_clientScreen = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
mainLoop()
|
|
||||||
{
|
|
||||||
// logging to files
|
|
||||||
CFileLogOutputter* fileLog = NULL;
|
|
||||||
|
|
||||||
if (ARG->m_logFile != NULL) {
|
|
||||||
fileLog = new CFileLogOutputter(ARG->m_logFile);
|
|
||||||
|
|
||||||
CLOG->insert(fileLog);
|
|
||||||
|
|
||||||
LOG((CLOG_DEBUG1 "Logging to file (%s) enabled", ARG->m_logFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create socket multiplexer. this must happen after daemonization
|
|
||||||
// on unix because threads evaporate across a fork().
|
|
||||||
CSocketMultiplexer multiplexer;
|
|
||||||
|
|
||||||
// create the event queue
|
|
||||||
CEventQueue eventQueue;
|
|
||||||
|
|
||||||
// start the client. if this return false then we've failed and
|
|
||||||
// we shouldn't retry.
|
|
||||||
LOG((CLOG_DEBUG1 "starting client"));
|
|
||||||
if (!startClient()) {
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// run event loop. if startClient() failed we're supposed to retry
|
|
||||||
// later. the timer installed by startClient() will take care of
|
|
||||||
// that.
|
|
||||||
CEvent event;
|
|
||||||
DAEMON_RUNNING(true);
|
|
||||||
EVENTQUEUE->getEvent(event);
|
|
||||||
while (event.getType() != CEvent::kQuit) {
|
|
||||||
EVENTQUEUE->dispatchEvent(event);
|
|
||||||
CEvent::deleteData(event);
|
|
||||||
EVENTQUEUE->getEvent(event);
|
|
||||||
}
|
|
||||||
DAEMON_RUNNING(false);
|
|
||||||
|
|
||||||
// close down
|
|
||||||
LOG((CLOG_DEBUG1 "stopping client"));
|
|
||||||
stopClient();
|
|
||||||
updateStatus();
|
|
||||||
LOG((CLOG_NOTE "stopped client"));
|
|
||||||
|
|
||||||
if (fileLog) {
|
|
||||||
CLOG->remove(fileLog);
|
|
||||||
delete fileLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kExitSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
daemonMainLoop(int, const char**)
|
|
||||||
{
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
CSystemLogger sysLogger(DAEMON_NAME, false);
|
|
||||||
#else
|
#else
|
||||||
CSystemLogger sysLogger(DAEMON_NAME, true);
|
#error Platform not supported.
|
||||||
#endif
|
#endif
|
||||||
return mainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
standardStartup(int argc, char** argv)
|
|
||||||
{
|
|
||||||
if (!ARG->m_daemon) {
|
|
||||||
ARCH->showConsole(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(argc, argv);
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
if (ARG->m_daemon) {
|
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return mainLoop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
|
||||||
{
|
|
||||||
// general initialization
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// command line parsing
|
|
||||||
//
|
|
||||||
|
|
||||||
#define BYE "\nTry `%s --help' for more information."
|
|
||||||
|
|
||||||
static void (*bye)(int) = &exit;
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
version()
|
|
||||||
{
|
|
||||||
LOG((CLOG_PRINT "%s %s, protocol version %d.%d\n%s",
|
|
||||||
ARG->m_pname,
|
|
||||||
kVersion,
|
|
||||||
kProtocolMajorVersion,
|
|
||||||
kProtocolMinorVersion,
|
|
||||||
kCopyright));
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
help()
|
|
||||||
{
|
|
||||||
#if WINAPI_XWINDOWS
|
|
||||||
# define USAGE_DISPLAY_ARG \
|
|
||||||
" [--display <display>]"
|
|
||||||
# define USAGE_DISPLAY_INFO \
|
|
||||||
" --display <display> connect to the X server at <display>\n"
|
|
||||||
#else
|
|
||||||
# define USAGE_DISPLAY_ARG
|
|
||||||
# define USAGE_DISPLAY_INFO
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LOG((CLOG_PRINT
|
|
||||||
"Usage: %s"
|
|
||||||
" [--daemon|--no-daemon]"
|
|
||||||
" [--debug <level>]"
|
|
||||||
USAGE_DISPLAY_ARG
|
|
||||||
" [--name <screen-name>]"
|
|
||||||
" [--yscroll <delta>]"
|
|
||||||
" [--restart|--no-restart]"
|
|
||||||
" <server-address>"
|
|
||||||
"\n\n"
|
|
||||||
"Start the synergy mouse/keyboard sharing server.\n"
|
|
||||||
"\n"
|
|
||||||
" -d, --debug <level> filter out log messages with priorty below level.\n"
|
|
||||||
" level may be: FATAL, ERROR, WARNING, NOTE, INFO,\n"
|
|
||||||
" DEBUG, DEBUG1, DEBUG2.\n"
|
|
||||||
USAGE_DISPLAY_INFO
|
|
||||||
" -f, --no-daemon run the client in the foreground.\n"
|
|
||||||
"* --daemon run the client as a daemon.\n"
|
|
||||||
" -n, --name <screen-name> use screen-name instead the hostname to identify\n"
|
|
||||||
" ourself to the server.\n"
|
|
||||||
" --yscroll <delta> defines the vertical scrolling delta, which is\n"
|
|
||||||
" 120 by default.\n"
|
|
||||||
" -1, --no-restart do not try to restart the client if it fails for\n"
|
|
||||||
" some reason.\n"
|
|
||||||
"* --restart restart the client automatically if it fails.\n"
|
|
||||||
" -l --log <file> write log messages to file.\n"
|
|
||||||
" -h, --help display this help and exit.\n"
|
|
||||||
" --version display version information and exit.\n"
|
|
||||||
"\n"
|
|
||||||
"* marks defaults.\n"
|
|
||||||
"\n"
|
|
||||||
"The server address is of the form: [<hostname>][:<port>]. The hostname\n"
|
|
||||||
"must be the address or hostname of the server. The port overrides the\n"
|
|
||||||
"default port, %d.\n"
|
|
||||||
"\n"
|
|
||||||
"Where log messages go depends on the platform and whether or not the\n"
|
|
||||||
"client is running as a daemon.",
|
|
||||||
ARG->m_pname, kDefaultPort));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
bool
|
|
||||||
isArg(int argi, int argc, const char* const* argv,
|
|
||||||
const char* name1, const char* name2,
|
|
||||||
int minRequiredParameters = 0)
|
|
||||||
{
|
|
||||||
if ((name1 != NULL && strcmp(argv[argi], name1) == 0) ||
|
|
||||||
(name2 != NULL && strcmp(argv[argi], name2) == 0)) {
|
|
||||||
// match. check args left.
|
|
||||||
if (argi + minRequiredParameters >= argc) {
|
|
||||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
|
||||||
ARG->m_pname, argv[argi], ARG->m_pname));
|
|
||||||
bye(kExitArgs);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no match
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
parse(int argc, const char* const* argv)
|
|
||||||
{
|
|
||||||
assert(ARG->m_pname != NULL);
|
|
||||||
assert(argv != NULL);
|
|
||||||
assert(argc >= 1);
|
|
||||||
|
|
||||||
if(ARG->m_pname == NULL
|
|
||||||
|| argv == NULL
|
|
||||||
|| argc < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set defaults
|
|
||||||
ARG->m_name = ARCH->getHostName();
|
|
||||||
|
|
||||||
// parse options
|
|
||||||
int i;
|
|
||||||
for (i = 1; i < argc; ++i) {
|
|
||||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
|
||||||
// change logging level
|
|
||||||
ARG->m_logFilter = argv[++i];
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
|
||||||
// save screen name
|
|
||||||
ARG->m_name = argv[++i];
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
|
||||||
// ignore -- included for backwards compatibility
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
|
||||||
// ignore -- included for backwards compatibility
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
|
||||||
// not a daemon
|
|
||||||
ARG->m_daemon = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
|
||||||
// daemonize
|
|
||||||
ARG->m_daemon = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if WINAPI_XWINDOWS
|
|
||||||
else if (isArg(i, argc, argv, "-display", "--display", 1)) {
|
|
||||||
// use alternative display
|
|
||||||
ARG->m_display = argv[++i];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) {
|
|
||||||
// define scroll
|
|
||||||
ARG->m_yscroll = atoi(argv[++i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-l", "--log", 1)) {
|
|
||||||
ARG->m_logFile = argv[++i];
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
|
||||||
// don't try to restart
|
|
||||||
ARG->m_restartable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
|
||||||
// try to restart
|
|
||||||
ARG->m_restartable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
|
||||||
ARG->m_backend = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
|
||||||
help();
|
|
||||||
bye(kExitSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, NULL, "--version")) {
|
|
||||||
version();
|
|
||||||
bye(kExitSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (isArg(i, argc, argv, "--", NULL)) {
|
|
||||||
// remaining arguments are not options
|
|
||||||
++i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (argv[i][0] == '-') {
|
|
||||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
|
||||||
ARG->m_pname, argv[i], ARG->m_pname));
|
|
||||||
bye(kExitArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
// this and remaining arguments are not options
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// exactly one non-option argument (server-address)
|
|
||||||
if (i == argc) {
|
|
||||||
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
|
||||||
ARG->m_pname, ARG->m_pname));
|
|
||||||
bye(kExitArgs);
|
|
||||||
}
|
|
||||||
if (i + 1 != argc) {
|
|
||||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
|
||||||
ARG->m_pname, argv[i], ARG->m_pname));
|
|
||||||
bye(kExitArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save server address
|
|
||||||
try {
|
|
||||||
*ARG->m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
|
||||||
ARG->m_serverAddress->resolve();
|
|
||||||
}
|
|
||||||
catch (XSocketAddress& e) {
|
|
||||||
// allow an address that we can't look up if we're restartable.
|
|
||||||
// we'll try to resolve the address each time we connect to the
|
|
||||||
// server. a bad port will never get better. patch by Brent
|
|
||||||
// Priddy.
|
|
||||||
if (!ARG->m_restartable || e.getError() == XSocketAddress::kBadPort) {
|
|
||||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
|
||||||
ARG->m_pname, e.what(), ARG->m_pname));
|
|
||||||
bye(kExitFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// increase default filter level for daemon. the user must
|
|
||||||
// explicitly request another level for a daemon.
|
|
||||||
if (ARG->m_daemon && ARG->m_logFilter == NULL) {
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
if (CArchMiscWindows::isWindows95Family()) {
|
|
||||||
// windows 95 has no place for logging so avoid showing
|
|
||||||
// the log console window.
|
|
||||||
ARG->m_logFilter = "FATAL";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
ARG->m_logFilter = "NOTE";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set log filter
|
|
||||||
if (!CLOG->setFilter(ARG->m_logFilter)) {
|
|
||||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
|
||||||
ARG->m_pname, ARG->m_logFilter, ARG->m_pname));
|
|
||||||
bye(kExitArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// identify system
|
|
||||||
LOG((CLOG_INFO "%s Client on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str()));
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#ifdef _AMD64_
|
|
||||||
LOG((CLOG_WARN "This is an experimental x64 build of %s. Use it at your own risk.", kApplication));
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// platform dependent entry points
|
|
||||||
//
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
static bool s_hasImportantLogMessages = false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// CMessageBoxOutputter
|
|
||||||
//
|
|
||||||
// This class writes severe log messages to a message box
|
|
||||||
//
|
|
||||||
|
|
||||||
class CMessageBoxOutputter : public ILogOutputter {
|
|
||||||
public:
|
|
||||||
CMessageBoxOutputter() { }
|
|
||||||
virtual ~CMessageBoxOutputter() { }
|
|
||||||
|
|
||||||
// ILogOutputter overrides
|
|
||||||
virtual void open(const char*) { }
|
|
||||||
virtual void close() { }
|
|
||||||
virtual void show(bool) { }
|
|
||||||
virtual bool write(ELevel level, const char* message);
|
|
||||||
virtual const char* getNewline() const { return ""; }
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
|
||||||
CMessageBoxOutputter::write(ELevel level, const char* message)
|
|
||||||
{
|
|
||||||
// note any important messages the user may need to know about
|
|
||||||
if (level <= CLog::kWARNING) {
|
|
||||||
s_hasImportantLogMessages = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FATAL and PRINT messages get a dialog box if not running as
|
|
||||||
// backend. if we're running as a backend the user will have
|
|
||||||
// a chance to see the messages when we exit.
|
|
||||||
if (!ARG->m_backend && level <= CLog::kFATAL) {
|
|
||||||
MessageBox(NULL, message, ARG->m_pname, MB_OK | MB_ICONWARNING);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
byeThrow(int x)
|
|
||||||
{
|
|
||||||
CArchMiscWindows::daemonFailed(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
daemonNTMainLoop(int argc, const char** argv)
|
|
||||||
{
|
|
||||||
parse(argc, argv);
|
|
||||||
ARG->m_backend = false;
|
|
||||||
return CArchMiscWindows::runDaemon(mainLoop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
daemonNTStartup(int, char**)
|
|
||||||
{
|
|
||||||
CSystemLogger sysLogger(DAEMON_NAME, false);
|
|
||||||
bye = &byeThrow;
|
|
||||||
return ARCH->daemonize(DAEMON_NAME, &daemonNTMainLoop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
int
|
|
||||||
foregroundStartup(int argc, char** argv)
|
|
||||||
{
|
|
||||||
ARCH->showConsole(false);
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(argc, argv);
|
|
||||||
|
|
||||||
// never daemonize
|
|
||||||
return mainLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
showError(HINSTANCE instance, const char* title, UINT id, const char* arg)
|
|
||||||
{
|
|
||||||
CString fmt = CMSWindowsUtil::getString(instance, id);
|
|
||||||
CString msg = CStringUtil::format(fmt.c_str(), arg);
|
|
||||||
MessageBox(NULL, msg.c_str(), title, MB_OK | MB_ICONWARNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
int WINAPI
|
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
CArchMiscWindows::setIcons((HICON)LoadImage(instance,
|
|
||||||
MAKEINTRESOURCE(IDI_SYNERGY),
|
|
||||||
IMAGE_ICON,
|
|
||||||
32, 32, LR_SHARED),
|
|
||||||
(HICON)LoadImage(instance,
|
|
||||||
MAKEINTRESOURCE(IDI_SYNERGY),
|
|
||||||
IMAGE_ICON,
|
|
||||||
16, 16, LR_SHARED));
|
|
||||||
CArch arch(instance);
|
|
||||||
CMSWindowsScreen::init(instance);
|
|
||||||
CLOG;
|
|
||||||
CThread::getCurrentThread().setPriority(-14);
|
|
||||||
CArgs args;
|
|
||||||
|
|
||||||
// set title on log window
|
|
||||||
ARCH->openConsole((CString(kAppVersion) + " " + "Client").c_str());
|
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
|
||||||
// since i'm not sure how to tell the difference between that and
|
|
||||||
// a user providing no options we'll assume that if there are no
|
|
||||||
// arguments and we're on NT then we're being invoked as a service.
|
|
||||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
|
||||||
// of the service code path.
|
|
||||||
StartupFunc startup = &standardStartup;
|
|
||||||
if (!CArchMiscWindows::isWindows95Family()) {
|
|
||||||
if (__argc <= 1) {
|
|
||||||
startup = &daemonNTStartup;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
startup = &foregroundStartup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// send PRINT and FATAL output to a message box
|
|
||||||
int result = run(__argc, __argv, new CMessageBoxOutputter, startup);
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
|
||||||
// by putting up a dialog box before exiting.
|
|
||||||
if (args.m_backend && s_hasImportantLogMessages) {
|
|
||||||
showError(instance, args.m_pname, IDS_FAILED, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
delete CLOG;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (XBase& e) {
|
|
||||||
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, e.what());
|
|
||||||
//throw;
|
|
||||||
}
|
|
||||||
catch (XArch& e) {
|
|
||||||
showError(instance, __argv[0], IDS_INIT_FAILED, e.what().c_str());
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
showError(instance, __argv[0], IDS_UNCAUGHT_EXCEPTION, "<unknown>");
|
|
||||||
//throw;
|
|
||||||
}
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif SYSAPI_UNIX
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char** argv)
|
main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CArgs args;
|
CClientApp app;
|
||||||
try {
|
return app.run(argc, argv, createTaskBarReceiver);
|
||||||
int result;
|
|
||||||
CArch arch;
|
|
||||||
CLOG;
|
|
||||||
CArgs args;
|
|
||||||
result = run(argc, argv, NULL, &standardStartup);
|
|
||||||
delete CLOG;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (XBase& e) {
|
|
||||||
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (XArch& e) {
|
|
||||||
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str()));
|
|
||||||
return kExitFailed;
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#error no main() for platform
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -21,10 +21,8 @@
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include "CArchTaskBarWindows.h"
|
#include "CArchTaskBarWindows.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
extern CEvent::Type getReloadConfigEvent();
|
#include "CMSWindowsScreen.h"
|
||||||
extern CEvent::Type getForceReconnectEvent();
|
|
||||||
extern CEvent::Type getResetServerEvent();
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CMSWindowsServerTaskBarReceiver
|
// CMSWindowsServerTaskBarReceiver
|
||||||
|
@ -378,3 +376,20 @@ CMSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd,
|
||||||
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
|
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IArchTaskBarReceiver*
|
||||||
|
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
|
{
|
||||||
|
CArchMiscWindows::setIcons(
|
||||||
|
(HICON)LoadImage(CArchMiscWindows::instanceWin32(),
|
||||||
|
MAKEINTRESOURCE(IDI_SYNERGY),
|
||||||
|
IMAGE_ICON,
|
||||||
|
32, 32, LR_SHARED),
|
||||||
|
(HICON)LoadImage(CArchMiscWindows::instanceWin32(),
|
||||||
|
MAKEINTRESOURCE(IDI_SYNERGY),
|
||||||
|
IMAGE_ICON,
|
||||||
|
16, 16, LR_SHARED));
|
||||||
|
|
||||||
|
return new CMSWindowsServerTaskBarReceiver(
|
||||||
|
CMSWindowsScreen::getInstance(), logBuffer);
|
||||||
|
}
|
||||||
|
|
|
@ -54,3 +54,9 @@ COSXServerTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IArchTaskBarReceiver*
|
||||||
|
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
|
{
|
||||||
|
return new COSXServerTaskBarReceiver(logBuffer);
|
||||||
|
}
|
||||||
|
|
|
@ -54,3 +54,9 @@ CXWindowsServerTaskBarReceiver::getIcon() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IArchTaskBarReceiver*
|
||||||
|
createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
|
||||||
|
{
|
||||||
|
return new CXWindowsServerTaskBarReceiver(logBuffer);
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -83,3 +83,5 @@ release {
|
||||||
RCC_DIR = tmp/release
|
RCC_DIR = tmp/release
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug:DESTDIR = ../bin/Debug
|
||||||
|
Release:DESTDIR = ../bin/Release
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 281 KiB |
|
@ -1 +1 @@
|
||||||
IDI_ICON1 ICON DISCARDABLE "res\win\QSynergy.ico"
|
IDI_ICON1 ICON DISCARDABLE "res\\win\\QSynergy.ico"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
const char AppConfig::m_SynergysName[] = "synergys.exe";
|
const char AppConfig::m_SynergysName[] = "synergys.exe";
|
||||||
const char AppConfig::m_SynergycName[] = "synergyc.exe";
|
const char AppConfig::m_SynergycName[] = "synergyc.exe";
|
||||||
const char AppConfig::m_SynergyProgramDir[] = "c:/program files/synergy/";
|
const char AppConfig::m_SynergyProgramDir[] = "./";
|
||||||
#else
|
#else
|
||||||
const char AppConfig::m_SynergysName[] = "synergys";
|
const char AppConfig::m_SynergysName[] = "synergys";
|
||||||
const char AppConfig::m_SynergycName[] = "synergyc";
|
const char AppConfig::m_SynergycName[] = "synergyc";
|
||||||
|
|
|
@ -224,7 +224,7 @@ void MainWindow::startSynergy()
|
||||||
setSynergyProcess(new QProcess(this));
|
setSynergyProcess(new QProcess(this));
|
||||||
|
|
||||||
if ((synergyType() == synergyClient && !clientArgs(args, app))
|
if ((synergyType() == synergyClient && !clientArgs(args, app))
|
||||||
|| synergyType() == synergyServer && !serverArgs(args, app))
|
|| (synergyType() == synergyServer && !serverArgs(args, app)))
|
||||||
{
|
{
|
||||||
stopSynergy();
|
stopSynergy();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication::setOrganizationName("Fidra");
|
QCoreApplication::setOrganizationName("The Synergy+ Project");
|
||||||
QCoreApplication::setOrganizationDomain("www.fidra.de");
|
QCoreApplication::setOrganizationDomain("http://code.google.com/p/synergy-plus/");
|
||||||
QCoreApplication::setApplicationName("QSynergy");
|
QCoreApplication::setApplicationName("Synergy+");
|
||||||
|
|
||||||
QSynergyApplication app(argc, argv);
|
QSynergyApplication app(argc, argv);
|
||||||
|
|
||||||
#if !defined(Q_OS_MAC)
|
#if !defined(Q_OS_MAC)
|
||||||
if (!QSystemTrayIcon::isSystemTrayAvailable())
|
if (!QSystemTrayIcon::isSystemTrayAvailable())
|
||||||
{
|
{
|
||||||
QMessageBox::critical(NULL, "QSynergy", QObject::tr("There doesn't seem to be a system tray available. Quitting."));
|
QMessageBox::critical(NULL, "Synergy+", QObject::tr("There doesn't seem to be a system tray available. Quitting."));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
|
||||||
#undef ARCH_CONSOLE
|
#undef ARCH_CONSOLE
|
||||||
#undef ARCH_DAEMON
|
#undef ARCH_DAEMON
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
# include "CArchSystemWindows.h"
|
# include "CArchSystemWindows.h"
|
||||||
# include "CArchTaskBarWindows.h"
|
# include "CArchTaskBarWindows.h"
|
||||||
# include "CArchTimeWindows.h"
|
# include "CArchTimeWindows.h"
|
||||||
|
# include "CArchAppUtilWindows.h"
|
||||||
#elif SYSAPI_UNIX
|
#elif SYSAPI_UNIX
|
||||||
# include "CArchConsoleUnix.h"
|
# include "CArchConsoleUnix.h"
|
||||||
# include "CArchDaemonUnix.h"
|
# include "CArchDaemonUnix.h"
|
||||||
|
@ -55,6 +57,7 @@
|
||||||
# include "CArchSystemUnix.h"
|
# include "CArchSystemUnix.h"
|
||||||
# include "CArchTaskBarXWindows.h"
|
# include "CArchTaskBarXWindows.h"
|
||||||
# include "CArchTimeUnix.h"
|
# include "CArchTimeUnix.h"
|
||||||
|
# include "CArchAppUtilUnix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(ARCH_CONSOLE)
|
#if !defined(ARCH_CONSOLE)
|
||||||
|
@ -101,13 +104,17 @@
|
||||||
# error unsupported platform for time
|
# error unsupported platform for time
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_APPUTIL)
|
||||||
|
# error unsupported platform for app util
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// CArch
|
// CArch
|
||||||
//
|
//
|
||||||
|
|
||||||
CArch* CArch::s_instance = NULL;
|
CArch* CArch::s_instance = NULL;
|
||||||
|
|
||||||
CArch::CArch(ARCH_ARGS* args)
|
CArch::CArch()
|
||||||
{
|
{
|
||||||
// only once instance of CArch
|
// only once instance of CArch
|
||||||
assert(s_instance == NULL);
|
assert(s_instance == NULL);
|
||||||
|
@ -122,9 +129,10 @@ CArch::CArch(ARCH_ARGS* args)
|
||||||
m_sleep = new ARCH_SLEEP;
|
m_sleep = new ARCH_SLEEP;
|
||||||
m_string = new ARCH_STRING;
|
m_string = new ARCH_STRING;
|
||||||
m_time = new ARCH_TIME;
|
m_time = new ARCH_TIME;
|
||||||
m_console = new ARCH_CONSOLE(args);
|
m_console = new ARCH_CONSOLE;
|
||||||
m_daemon = new ARCH_DAEMON;
|
m_daemon = new ARCH_DAEMON;
|
||||||
m_taskbar = new ARCH_TASKBAR(args);
|
m_taskbar = new ARCH_TASKBAR;
|
||||||
|
m_appUtil = new ARCH_APPUTIL;
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
CArchMiscWindows::init();
|
CArchMiscWindows::init();
|
||||||
|
@ -145,6 +153,7 @@ CArch::~CArch()
|
||||||
delete m_file;
|
delete m_file;
|
||||||
delete m_system;
|
delete m_system;
|
||||||
delete m_mt;
|
delete m_mt;
|
||||||
|
delete m_appUtil;
|
||||||
|
|
||||||
// no instance
|
// no instance
|
||||||
s_instance = NULL;
|
s_instance = NULL;
|
||||||
|
@ -182,12 +191,6 @@ CArch::writeConsole(const char* str)
|
||||||
m_console->writeConsole(str);
|
m_console->writeConsole(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
|
||||||
CArch::getNewlineForConsole()
|
|
||||||
{
|
|
||||||
return m_console->getNewlineForConsole();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CArch::installDaemon(const char* name,
|
CArch::installDaemon(const char* name,
|
||||||
const char* description,
|
const char* description,
|
||||||
|
@ -643,3 +646,27 @@ CArch::time()
|
||||||
{
|
{
|
||||||
return m_time->time();
|
return m_time->time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArch::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
return m_appUtil->parseArg(argc, argv, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArch::adoptApp(CApp* app)
|
||||||
|
{
|
||||||
|
m_appUtil->adoptApp(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
CApp&
|
||||||
|
CArch::app() const
|
||||||
|
{
|
||||||
|
return m_appUtil->app();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArch::run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver)
|
||||||
|
{
|
||||||
|
return m_appUtil->run(argc, argv, createTaskBarReceiver);
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "IArchSystem.h"
|
#include "IArchSystem.h"
|
||||||
#include "IArchTaskBar.h"
|
#include "IArchTaskBar.h"
|
||||||
#include "IArchTime.h"
|
#include "IArchTime.h"
|
||||||
|
#include "IArchAppUtil.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\def ARCH
|
\def ARCH
|
||||||
|
@ -33,9 +34,7 @@ This macro evaluates to the singleton CArch object.
|
||||||
*/
|
*/
|
||||||
#define ARCH (CArch::getInstance())
|
#define ARCH (CArch::getInstance())
|
||||||
|
|
||||||
#define ARCH_ARGS void
|
//! Delegating implementation of architecture dependent interfaces
|
||||||
|
|
||||||
//! Delegating mplementation of architecture dependent interfaces
|
|
||||||
/*!
|
/*!
|
||||||
This class is a centralized interface to all architecture dependent
|
This class is a centralized interface to all architecture dependent
|
||||||
interface implementations (except miscellaneous functions). It
|
interface implementations (except miscellaneous functions). It
|
||||||
|
@ -55,9 +54,10 @@ class CArch : public IArchConsole,
|
||||||
public IArchString,
|
public IArchString,
|
||||||
public IArchSystem,
|
public IArchSystem,
|
||||||
public IArchTaskBar,
|
public IArchTaskBar,
|
||||||
public IArchTime {
|
public IArchTime,
|
||||||
|
public IArchAppUtil {
|
||||||
public:
|
public:
|
||||||
CArch(ARCH_ARGS* args = NULL);
|
CArch();
|
||||||
~CArch();
|
~CArch();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -76,7 +76,6 @@ public:
|
||||||
virtual void closeConsole();
|
virtual void closeConsole();
|
||||||
virtual void showConsole(bool showIfEmpty);
|
virtual void showConsole(bool showIfEmpty);
|
||||||
virtual void writeConsole(const char*);
|
virtual void writeConsole(const char*);
|
||||||
virtual const char* getNewlineForConsole();
|
|
||||||
|
|
||||||
// IArchDaemon overrides
|
// IArchDaemon overrides
|
||||||
virtual void installDaemon(const char* name,
|
virtual void installDaemon(const char* name,
|
||||||
|
@ -184,6 +183,12 @@ public:
|
||||||
// IArchTime overrides
|
// IArchTime overrides
|
||||||
virtual double time();
|
virtual double time();
|
||||||
|
|
||||||
|
// IArchAppUtil overrides
|
||||||
|
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
virtual void adoptApp(CApp* app);
|
||||||
|
virtual CApp& app() const;
|
||||||
|
virtual int run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static CArch* s_instance;
|
static CArch* s_instance;
|
||||||
|
|
||||||
|
@ -198,6 +203,7 @@ private:
|
||||||
IArchSystem* m_system;
|
IArchSystem* m_system;
|
||||||
IArchTaskBar* m_taskbar;
|
IArchTaskBar* m_taskbar;
|
||||||
IArchTime* m_time;
|
IArchTime* m_time;
|
||||||
|
IArchAppUtil* m_appUtil;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Convenience object to lock/unlock an arch mutex
|
//! Convenience object to lock/unlock an arch mutex
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchAppUtil.h"
|
||||||
|
#include "CApp.h"
|
||||||
|
|
||||||
|
CArchAppUtil* CArchAppUtil::s_instance = nullptr;
|
||||||
|
|
||||||
|
CArchAppUtil::CArchAppUtil() :
|
||||||
|
m_app(nullptr)
|
||||||
|
{
|
||||||
|
s_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchAppUtil::~CArchAppUtil()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchAppUtil::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
// no common platform args (yet)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtil::adoptApp(CApp* app)
|
||||||
|
{
|
||||||
|
m_app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
CApp&
|
||||||
|
CArchAppUtil::app() const
|
||||||
|
{
|
||||||
|
assert(m_app != nullptr);
|
||||||
|
return *m_app;
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchAppUtil&
|
||||||
|
CArchAppUtil::instance()
|
||||||
|
{
|
||||||
|
assert(s_instance != nullptr);
|
||||||
|
return *s_instance;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IArchAppUtil.h"
|
||||||
|
|
||||||
|
class CArchAppUtil : public IArchAppUtil {
|
||||||
|
public:
|
||||||
|
CArchAppUtil();
|
||||||
|
virtual ~CArchAppUtil();
|
||||||
|
|
||||||
|
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
virtual void adoptApp(CApp* app);
|
||||||
|
CApp& app() const;
|
||||||
|
|
||||||
|
static CArchAppUtil& instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CApp* m_app;
|
||||||
|
static CArchAppUtil* s_instance;
|
||||||
|
};
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchAppUtilUnix.h"
|
||||||
|
|
||||||
|
CArchAppUtilUnix::CArchAppUtilUnix()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchAppUtilUnix::~CArchAppUtilUnix()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchAppUtilUnix::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
#if WINAPI_XWINDOWS
|
||||||
|
if (app().isArg(i, argc, argv, "-display", "--display", 1)) {
|
||||||
|
// use alternative display
|
||||||
|
app().argsBase().m_display = argv[++i];
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// option not supported here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
// no options for carbon
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
standardStartupStatic(int argc, char** argv)
|
||||||
|
{
|
||||||
|
return CArchAppUtil::instance().app().standardStartup(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchAppUtilUnix::run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver)
|
||||||
|
{
|
||||||
|
return app().runInner(argc, argv, NULL, &standardStartupStatic, createTaskBarReceiver);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CArchAppUtil.h"
|
||||||
|
|
||||||
|
#define ARCH_APPUTIL CArchAppUtilUnix
|
||||||
|
|
||||||
|
class CArchAppUtilUnix : public CArchAppUtil {
|
||||||
|
public:
|
||||||
|
CArchAppUtilUnix();
|
||||||
|
virtual ~CArchAppUtilUnix();
|
||||||
|
|
||||||
|
bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
int run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||||
|
};
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchAppUtilWindows.h"
|
||||||
|
#include "Version.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
#include "XArchWindows.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
|
#include "CApp.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <conio.h>
|
||||||
|
|
||||||
|
CArchAppUtilWindows::CArchAppUtilWindows()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchAppUtilWindows::~CArchAppUtilWindows()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchAppUtilWindows::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
if (app().isArg(i, argc, argv, NULL, "--service")) {
|
||||||
|
|
||||||
|
const char* action = argv[++i];
|
||||||
|
|
||||||
|
if (_stricmp(action, "install") == 0) {
|
||||||
|
installService();
|
||||||
|
}
|
||||||
|
else if (_stricmp(action, "uninstall") == 0) {
|
||||||
|
uninstallService();
|
||||||
|
}
|
||||||
|
else if (_stricmp(action, "start") == 0) {
|
||||||
|
startService();
|
||||||
|
}
|
||||||
|
else if (_stricmp(action, "stop") == 0) {
|
||||||
|
stopService();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((CLOG_ERR "unknown service action: %s", action));
|
||||||
|
app().m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
app().m_bye(kExitSuccess);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// option not supported here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtilWindows::adoptApp(CApp* app)
|
||||||
|
{
|
||||||
|
app->m_bye = &exitPause;
|
||||||
|
CArchAppUtil::adoptApp(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CArchAppUtilWindows::getServiceArgs() const
|
||||||
|
{
|
||||||
|
std::stringstream argBuf;
|
||||||
|
for (int i = 1; i < __argc; i++) {
|
||||||
|
const char* arg = __argv[i];
|
||||||
|
|
||||||
|
// ignore service setup args
|
||||||
|
if (_stricmp(arg, "--service") == 0) {
|
||||||
|
// ignore and skip the next arg also (service action)
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
argBuf << " " << __argv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return argBuf.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtilWindows::installService()
|
||||||
|
{
|
||||||
|
CString args = getServiceArgs();
|
||||||
|
|
||||||
|
// get the path of this program
|
||||||
|
char thisPath[MAX_PATH];
|
||||||
|
GetModuleFileName(CArchMiscWindows::instanceWin32(), thisPath, MAX_PATH);
|
||||||
|
|
||||||
|
ARCH->installDaemon(
|
||||||
|
app().daemonName(), app().daemonInfo(),
|
||||||
|
thisPath, args.c_str(), NULL, true);
|
||||||
|
|
||||||
|
LOG((CLOG_INFO "service '%s' installed with args: %s",
|
||||||
|
app().daemonName(), args != "" ? args.c_str() : "none" ));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtilWindows::uninstallService()
|
||||||
|
{
|
||||||
|
ARCH->uninstallDaemon(app().daemonName(), true);
|
||||||
|
LOG((CLOG_INFO "service '%s' uninstalled", app().daemonName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtilWindows::startService()
|
||||||
|
{
|
||||||
|
// open service manager
|
||||||
|
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||||
|
if (mgr == NULL) {
|
||||||
|
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the service
|
||||||
|
SC_HANDLE service = OpenService(
|
||||||
|
mgr, app().daemonName(), SERVICE_START);
|
||||||
|
|
||||||
|
if (service == NULL) {
|
||||||
|
CloseServiceHandle(mgr);
|
||||||
|
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the service
|
||||||
|
if (StartService(service, 0, NULL)) {
|
||||||
|
LOG((CLOG_INFO "service '%s' started", app().daemonName()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtilWindows::stopService()
|
||||||
|
{
|
||||||
|
// open service manager
|
||||||
|
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||||
|
if (mgr == NULL) {
|
||||||
|
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the service
|
||||||
|
SC_HANDLE service = OpenService(
|
||||||
|
mgr, app().daemonName(),
|
||||||
|
SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||||
|
|
||||||
|
if (service == NULL) {
|
||||||
|
CloseServiceHandle(mgr);
|
||||||
|
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ask the service to stop, asynchronously
|
||||||
|
SERVICE_STATUS ss;
|
||||||
|
if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) {
|
||||||
|
DWORD dwErrCode = GetLastError();
|
||||||
|
if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) {
|
||||||
|
LOG((CLOG_ERR "cannot stop service '%s'", app().daemonName()));
|
||||||
|
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG((CLOG_INFO "service '%s' stopping asyncronously", app().daemonName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exitPause(int code)
|
||||||
|
{
|
||||||
|
CString name;
|
||||||
|
CArchMiscWindows::getParentProcessName(name);
|
||||||
|
|
||||||
|
// if the user did not launch from the command prompt (i.e. it was launched
|
||||||
|
// by double clicking, or through a debugger), allow user to read any error
|
||||||
|
// messages (instead of the window closing automatically).
|
||||||
|
if (name != "cmd.exe") {
|
||||||
|
std::cout << std::endl << "Press any key to exit..." << std::endl;
|
||||||
|
int c = _getch();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
mainLoopStatic()
|
||||||
|
{
|
||||||
|
return CArchAppUtil::instance().app().mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchAppUtilWindows::daemonNTMainLoop(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
app().parseArgs(argc, argv);
|
||||||
|
app().argsBase().m_backend = false;
|
||||||
|
app().loadConfig();
|
||||||
|
return CArchMiscWindows::runDaemon(mainLoopStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchAppUtilWindows::byeThrow(int x)
|
||||||
|
{
|
||||||
|
CArchMiscWindows::daemonFailed(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int daemonNTMainLoopStatic(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
return CArchAppUtil::instance().app().daemonMainLoop(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchAppUtilWindows::daemonNTStartup(int, char**)
|
||||||
|
{
|
||||||
|
CSystemLogger sysLogger(app().daemonName(), false);
|
||||||
|
app().m_bye = &byeThrow;
|
||||||
|
return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
daemonNTStartupStatic(int argc, char** argv)
|
||||||
|
{
|
||||||
|
return CArchAppUtilWindows::instance().daemonNTStartup(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
foregroundStartupStatic(int argc, char** argv)
|
||||||
|
{
|
||||||
|
return CArchAppUtil::instance().app().foregroundStartup(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CArchAppUtilWindows::run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver)
|
||||||
|
{
|
||||||
|
// record window instance for tray icon, etc
|
||||||
|
CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||||
|
|
||||||
|
CMSWindowsScreen::init(CArchMiscWindows::instanceWin32());
|
||||||
|
CThread::getCurrentThread().setPriority(-14);
|
||||||
|
|
||||||
|
StartupFunc startup;
|
||||||
|
if (CArchMiscWindows::wasLaunchedAsService()) {
|
||||||
|
startup = &daemonNTStartupStatic;
|
||||||
|
} else {
|
||||||
|
startup = &foregroundStartupStatic;
|
||||||
|
app().argsBase().m_daemon = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return app().runInner(argc, argv, NULL, startup, createTaskBarReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
CArchAppUtilWindows&
|
||||||
|
CArchAppUtilWindows::instance()
|
||||||
|
{
|
||||||
|
return (CArchAppUtilWindows&)CArchAppUtil::instance();
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CArchAppUtil.h"
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
|
#include "Windows.h"
|
||||||
|
|
||||||
|
#define ARCH_APPUTIL CArchAppUtilWindows
|
||||||
|
|
||||||
|
class CArchAppUtilWindows : public CArchAppUtil {
|
||||||
|
public:
|
||||||
|
CArchAppUtilWindows();
|
||||||
|
virtual ~CArchAppUtilWindows();
|
||||||
|
|
||||||
|
// Gets the arguments to be used with a service.
|
||||||
|
CString getServiceArgs() const;
|
||||||
|
|
||||||
|
// Install application as Windows service.
|
||||||
|
void installService();
|
||||||
|
|
||||||
|
// Uninstall a Windows service with matching daemon name.
|
||||||
|
void uninstallService();
|
||||||
|
|
||||||
|
// Start a Windows service with matching daemon name.
|
||||||
|
void startService();
|
||||||
|
|
||||||
|
// Stop a Windows service with matching daemon name.
|
||||||
|
void stopService();
|
||||||
|
|
||||||
|
// Will install, uninstall, start, or stop the service depending on arg.
|
||||||
|
void handleServiceArg(const char* serviceAction);
|
||||||
|
|
||||||
|
bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
|
||||||
|
void adoptApp(CApp* app);
|
||||||
|
|
||||||
|
int daemonNTStartup(int, char**);
|
||||||
|
|
||||||
|
int daemonNTMainLoop(int argc, const char** argv);
|
||||||
|
|
||||||
|
int run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||||
|
|
||||||
|
static void byeThrow(int x);
|
||||||
|
|
||||||
|
static CArchAppUtilWindows& instance();
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: move to class
|
||||||
|
void exitPause(int code);
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CArchConsoleStd.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchConsoleStd::writeConsole(const char* str)
|
||||||
|
{
|
||||||
|
// TODO: we need to use cerr also somehow
|
||||||
|
std::cout << str << std::endl;
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IArchConsole.h"
|
||||||
|
|
||||||
|
//! Cross platform implementation of IArchConsole
|
||||||
|
class CArchConsoleStd : public IArchConsole {
|
||||||
|
public:
|
||||||
|
CArchConsoleStd() { }
|
||||||
|
virtual ~CArchConsoleStd() { }
|
||||||
|
|
||||||
|
// IArchConsole overrides
|
||||||
|
virtual void openConsole(const char* title) { }
|
||||||
|
virtual void closeConsole() { }
|
||||||
|
virtual void showConsole(bool) { }
|
||||||
|
virtual void writeConsole(const char*);
|
||||||
|
};
|
|
@ -13,49 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CArchConsoleUnix.h"
|
#include "CArchConsoleUnix.h"
|
||||||
#include <cstdio>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
//
|
CArchConsoleUnix::CArchConsoleUnix() { }
|
||||||
// CArchConsoleUnix
|
|
||||||
//
|
|
||||||
|
|
||||||
CArchConsoleUnix::CArchConsoleUnix(void*)
|
CArchConsoleUnix::~CArchConsoleUnix() { }
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
CArchConsoleUnix::~CArchConsoleUnix()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleUnix::openConsole(const char*)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleUnix::closeConsole()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleUnix::showConsole(bool)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleUnix::writeConsole(const char* str)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
CArchConsoleUnix::getNewlineForConsole()
|
|
||||||
{
|
|
||||||
return "\n";
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,25 +12,14 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CARCHCONSOLEUNIX_H
|
#pragma once
|
||||||
#define CARCHCONSOLEUNIX_H
|
|
||||||
|
|
||||||
#include "IArchConsole.h"
|
#include "CArchConsoleStd.h"
|
||||||
|
|
||||||
#define ARCH_CONSOLE CArchConsoleUnix
|
#define ARCH_CONSOLE CArchConsoleUnix
|
||||||
|
|
||||||
//! Unix implementation of IArchConsole
|
class CArchConsoleUnix : public CArchConsoleStd {
|
||||||
class CArchConsoleUnix : public IArchConsole {
|
|
||||||
public:
|
public:
|
||||||
CArchConsoleUnix(void*);
|
CArchConsoleUnix();
|
||||||
virtual ~CArchConsoleUnix();
|
virtual ~CArchConsoleUnix();
|
||||||
|
|
||||||
// IArchConsole overrides
|
|
||||||
virtual void openConsole(const char* title);
|
|
||||||
virtual void closeConsole();
|
|
||||||
virtual void showConsole(bool);
|
|
||||||
virtual void writeConsole(const char*);
|
|
||||||
virtual const char* getNewlineForConsole();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -13,427 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CArchConsoleWindows.h"
|
#include "CArchConsoleWindows.h"
|
||||||
#include "IArchMultithread.h"
|
|
||||||
#include "CArch.h"
|
|
||||||
#include "CArchMiscWindows.h"
|
|
||||||
#include <richedit.h>
|
|
||||||
|
|
||||||
#define SYNERGY_MSG_CONSOLE_OPEN WM_APP + 0x0021
|
CArchConsoleWindows::CArchConsoleWindows() { }
|
||||||
#define SYNERGY_MSG_CONSOLE_CLOSE WM_APP + 0x0022
|
|
||||||
#define SYNERGY_MSG_CONSOLE_SHOW WM_APP + 0x0023
|
|
||||||
#define SYNERGY_MSG_CONSOLE_WRITE WM_APP + 0x0024
|
|
||||||
#define SYNERGY_MSG_CONSOLE_CLEAR WM_APP + 0x0025
|
|
||||||
#define TWIPS_PER_POINT 20
|
|
||||||
|
|
||||||
//
|
CArchConsoleWindows::~CArchConsoleWindows() { }
|
||||||
// CArchConsoleWindows
|
|
||||||
//
|
|
||||||
|
|
||||||
CArchConsoleWindows* CArchConsoleWindows::s_instance = NULL;
|
|
||||||
HINSTANCE CArchConsoleWindows::s_appInstance = NULL;
|
|
||||||
|
|
||||||
CArchConsoleWindows::CArchConsoleWindows(void* appInstance) :
|
|
||||||
m_show(false),
|
|
||||||
m_maxLines(1000),
|
|
||||||
m_numCharacters(0),
|
|
||||||
m_maxCharacters(65536)
|
|
||||||
{
|
|
||||||
// save the singleton instance
|
|
||||||
s_instance = this;
|
|
||||||
|
|
||||||
// save app instance
|
|
||||||
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
|
|
||||||
|
|
||||||
// we need a mutex
|
|
||||||
m_mutex = ARCH->newMutex();
|
|
||||||
|
|
||||||
// and a condition variable which uses the above mutex
|
|
||||||
m_ready = false;
|
|
||||||
m_condVar = ARCH->newCondVar();
|
|
||||||
|
|
||||||
// we're going to want to get a result from the thread we're
|
|
||||||
// about to create to know if it initialized successfully.
|
|
||||||
// so we lock the condition variable.
|
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
|
|
||||||
// open a window and run an event loop in a separate thread.
|
|
||||||
// this has to happen in a separate thread because if we
|
|
||||||
// create a window on the current desktop with the current
|
|
||||||
// thread then the current thread won't be able to switch
|
|
||||||
// desktops if it needs to.
|
|
||||||
m_thread = ARCH->newThread(&CArchConsoleWindows::threadEntry, this);
|
|
||||||
|
|
||||||
// wait for child thread
|
|
||||||
while (!m_ready) {
|
|
||||||
ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ready
|
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CArchConsoleWindows::~CArchConsoleWindows()
|
|
||||||
{
|
|
||||||
if (m_thread != NULL) {
|
|
||||||
PostMessage(m_hwnd, WM_QUIT, 0, 0);
|
|
||||||
ARCH->wait(m_thread, -1.0);
|
|
||||||
ARCH->closeThread(m_thread);
|
|
||||||
}
|
|
||||||
ARCH->closeCondVar(m_condVar);
|
|
||||||
ARCH->closeMutex(m_mutex);
|
|
||||||
s_instance = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::openConsole(const char* title)
|
|
||||||
{
|
|
||||||
SetWindowText(m_frame, title);
|
|
||||||
SendMessage(m_frame, SYNERGY_MSG_CONSOLE_OPEN, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::closeConsole()
|
|
||||||
{
|
|
||||||
SendMessage(m_frame, SYNERGY_MSG_CONSOLE_CLOSE, 0, 0);
|
|
||||||
SendMessage(m_frame, SYNERGY_MSG_CONSOLE_CLEAR, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::showConsole(bool showIfEmpty)
|
|
||||||
{
|
|
||||||
SendMessage(m_frame, SYNERGY_MSG_CONSOLE_SHOW, showIfEmpty ? 1 : 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::writeConsole(const char* str)
|
|
||||||
{
|
|
||||||
SendMessage(m_frame, SYNERGY_MSG_CONSOLE_WRITE,
|
|
||||||
reinterpret_cast<WPARAM>(str), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
CArchConsoleWindows::getNewlineForConsole()
|
|
||||||
{
|
|
||||||
return "\r\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::clearBuffer()
|
|
||||||
{
|
|
||||||
m_buffer.clear();
|
|
||||||
m_numCharacters = 0;
|
|
||||||
SetWindowText(m_hwnd, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::appendBuffer(const char* msg)
|
|
||||||
{
|
|
||||||
bool wasEmpty = m_buffer.empty();
|
|
||||||
|
|
||||||
// get current selection
|
|
||||||
CHARRANGE selection;
|
|
||||||
SendMessage(m_hwnd, EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&selection));
|
|
||||||
|
|
||||||
// remove tail of buffer
|
|
||||||
size_t removedCharacters = 0;
|
|
||||||
while (m_buffer.size() >= m_maxLines) {
|
|
||||||
removedCharacters += m_buffer.front().size();
|
|
||||||
m_buffer.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove lines from top of control
|
|
||||||
if (removedCharacters > 0) {
|
|
||||||
CHARRANGE range;
|
|
||||||
range.cpMin = 0;
|
|
||||||
range.cpMax = static_cast<LONG>(removedCharacters);
|
|
||||||
SendMessage(m_hwnd, EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&range));
|
|
||||||
SendMessage(m_hwnd, EM_REPLACESEL, FALSE, reinterpret_cast<LPARAM>(""));
|
|
||||||
|
|
||||||
// adjust selection
|
|
||||||
if (selection.cpMin < static_cast<LONG>(removedCharacters) ||
|
|
||||||
selection.cpMax < static_cast<LONG>(removedCharacters)) {
|
|
||||||
selection.cpMin = 0;
|
|
||||||
selection.cpMax = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
selection.cpMin -= static_cast<LONG>(removedCharacters);
|
|
||||||
selection.cpMax -= static_cast<LONG>(removedCharacters);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_numCharacters -= removedCharacters;
|
|
||||||
}
|
|
||||||
|
|
||||||
// append message
|
|
||||||
m_buffer.push_back(msg);
|
|
||||||
size_t newNumCharacters = m_numCharacters + m_buffer.back().size();
|
|
||||||
|
|
||||||
// add line to bottom of control
|
|
||||||
if (newNumCharacters > m_maxCharacters) {
|
|
||||||
m_maxCharacters = newNumCharacters;
|
|
||||||
SendMessage(m_hwnd, EM_EXLIMITTEXT, 0, m_maxCharacters);
|
|
||||||
}
|
|
||||||
CHARRANGE range;
|
|
||||||
range.cpMin = (LONG)m_numCharacters;
|
|
||||||
range.cpMax = (LONG)m_numCharacters;
|
|
||||||
SendMessage(m_hwnd, EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&range));
|
|
||||||
SendMessage(m_hwnd, EM_REPLACESEL, FALSE,
|
|
||||||
reinterpret_cast<LPARAM>(m_buffer.back().c_str()));
|
|
||||||
|
|
||||||
// adjust selection
|
|
||||||
bool atEnd = false;
|
|
||||||
if (selection.cpMax == static_cast<LONG>(m_numCharacters)) {
|
|
||||||
selection.cpMin = static_cast<LONG>(newNumCharacters);
|
|
||||||
selection.cpMax = static_cast<LONG>(newNumCharacters);
|
|
||||||
atEnd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore the selection
|
|
||||||
SendMessage(m_hwnd, EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&selection));
|
|
||||||
if (atEnd) {
|
|
||||||
SendMessage(m_hwnd, EM_SCROLLCARET, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasEmpty && m_show) {
|
|
||||||
ShowWindow(m_frame, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_numCharacters = newNumCharacters;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::setSize(int width, int height)
|
|
||||||
{
|
|
||||||
DWORD style = GetWindowLong(m_frame, GWL_STYLE);
|
|
||||||
DWORD exStyle = GetWindowLong(m_frame, GWL_EXSTYLE);
|
|
||||||
RECT rect;
|
|
||||||
rect.left = 100;
|
|
||||||
rect.top = 100;
|
|
||||||
rect.right = rect.left + width * m_wChar;
|
|
||||||
rect.bottom = rect.top + height * m_hChar;
|
|
||||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
|
||||||
SetWindowPos(m_frame, NULL, 0, 0, rect.right - rect.left,
|
|
||||||
rect.bottom - rect.top,
|
|
||||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT
|
|
||||||
CArchConsoleWindows::wndProc(HWND hwnd,
|
|
||||||
UINT msg, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
switch (msg) {
|
|
||||||
case WM_CLOSE:
|
|
||||||
ShowWindow(m_frame, FALSE);
|
|
||||||
m_show = false;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case SYNERGY_MSG_CONSOLE_OPEN:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case SYNERGY_MSG_CONSOLE_CLOSE:
|
|
||||||
SendMessage(m_frame, WM_CLOSE, 0, 0);
|
|
||||||
m_show = false;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case SYNERGY_MSG_CONSOLE_SHOW:
|
|
||||||
m_show = true;
|
|
||||||
if (wParam != 0 || !m_buffer.empty()) {
|
|
||||||
ShowWindow(m_frame, TRUE);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case SYNERGY_MSG_CONSOLE_WRITE:
|
|
||||||
appendBuffer(reinterpret_cast<const char*>(wParam));
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case SYNERGY_MSG_CONSOLE_CLEAR:
|
|
||||||
clearBuffer();
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case WM_SIZE:
|
|
||||||
if (hwnd == m_frame) {
|
|
||||||
MoveWindow(m_hwnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SIZING:
|
|
||||||
if (hwnd == m_frame) {
|
|
||||||
// get window vs client area info
|
|
||||||
int wBase = 40 * m_wChar;
|
|
||||||
int hBase = 40 * m_hChar;
|
|
||||||
DWORD style = GetWindowLong(m_frame, GWL_STYLE);
|
|
||||||
DWORD exStyle = GetWindowLong(m_frame, GWL_EXSTYLE);
|
|
||||||
RECT rect;
|
|
||||||
rect.left = 100;
|
|
||||||
rect.top = 100;
|
|
||||||
rect.right = rect.left + wBase;
|
|
||||||
rect.bottom = rect.top + hBase;
|
|
||||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
|
||||||
wBase = rect.right - rect.left - wBase;
|
|
||||||
hBase = rect.bottom - rect.top - hBase;
|
|
||||||
|
|
||||||
// get closest size that's a multiple of the character size
|
|
||||||
RECT* newRect = (RECT*)lParam;
|
|
||||||
int width = (newRect->right - newRect->left - wBase) / m_wChar;
|
|
||||||
int height = (newRect->bottom - newRect->top - hBase) / m_hChar;
|
|
||||||
width = width * m_wChar + wBase;
|
|
||||||
height = height * m_hChar + hBase;
|
|
||||||
|
|
||||||
// adjust sizing rect
|
|
||||||
switch (wParam) {
|
|
||||||
case WMSZ_LEFT:
|
|
||||||
case WMSZ_TOPLEFT:
|
|
||||||
case WMSZ_BOTTOMLEFT:
|
|
||||||
newRect->left = newRect->right - width;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMSZ_RIGHT:
|
|
||||||
case WMSZ_TOPRIGHT:
|
|
||||||
case WMSZ_BOTTOMRIGHT:
|
|
||||||
newRect->right = newRect->left + width;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (wParam) {
|
|
||||||
case WMSZ_TOP:
|
|
||||||
case WMSZ_TOPLEFT:
|
|
||||||
case WMSZ_TOPRIGHT:
|
|
||||||
newRect->top = newRect->bottom - height;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WMSZ_BOTTOM:
|
|
||||||
case WMSZ_BOTTOMLEFT:
|
|
||||||
case WMSZ_BOTTOMRIGHT:
|
|
||||||
newRect->bottom = newRect->top + height;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT CALLBACK
|
|
||||||
CArchConsoleWindows::staticWndProc(HWND hwnd, UINT msg,
|
|
||||||
WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
|
||||||
// forward the message
|
|
||||||
if (s_instance != NULL) {
|
|
||||||
return s_instance->wndProc(hwnd, msg, wParam, lParam);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CArchConsoleWindows::threadMainLoop()
|
|
||||||
{
|
|
||||||
LoadLibrary("RICHED32.DLL");
|
|
||||||
|
|
||||||
// get the app icons
|
|
||||||
HICON largeIcon, smallIcon;
|
|
||||||
CArchMiscWindows::getIcons(largeIcon, smallIcon);
|
|
||||||
|
|
||||||
// register a window class
|
|
||||||
WNDCLASSEX classInfo;
|
|
||||||
classInfo.cbSize = sizeof(classInfo);
|
|
||||||
classInfo.style = 0;
|
|
||||||
classInfo.lpfnWndProc = &CArchConsoleWindows::staticWndProc;
|
|
||||||
classInfo.cbClsExtra = 0;
|
|
||||||
classInfo.cbWndExtra = sizeof(CArchConsoleWindows*);
|
|
||||||
classInfo.hInstance = s_appInstance;
|
|
||||||
classInfo.hIcon = largeIcon;
|
|
||||||
classInfo.hCursor = NULL;
|
|
||||||
classInfo.hbrBackground = NULL;
|
|
||||||
classInfo.lpszMenuName = NULL;
|
|
||||||
classInfo.lpszClassName = TEXT("SynergyConsole");
|
|
||||||
classInfo.hIconSm = smallIcon;
|
|
||||||
ATOM windowClass = RegisterClassEx(&classInfo);
|
|
||||||
|
|
||||||
// create frame window
|
|
||||||
m_frame = CreateWindowEx(0,
|
|
||||||
reinterpret_cast<LPCTSTR>(windowClass),
|
|
||||||
TEXT("Synergy Log"),
|
|
||||||
WS_OVERLAPPEDWINDOW,
|
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
s_appInstance,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
// create log window
|
|
||||||
m_hwnd = CreateWindowEx(0,
|
|
||||||
"RichEdit",
|
|
||||||
TEXT(""),
|
|
||||||
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
|
|
||||||
ES_MULTILINE | ES_READONLY,
|
|
||||||
0, 0, 1, 1,
|
|
||||||
m_frame,
|
|
||||||
(HMENU)1,
|
|
||||||
s_appInstance,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
// select font and get info
|
|
||||||
HDC hdc = GetDC(m_hwnd);
|
|
||||||
HGDIOBJ oldFont = SelectObject(hdc, GetStockObject(ANSI_FIXED_FONT));
|
|
||||||
TEXTMETRIC metrics;
|
|
||||||
GetTextMetrics(hdc, &metrics);
|
|
||||||
CHARFORMAT format;
|
|
||||||
format.cbSize = sizeof(format);
|
|
||||||
format.dwMask = CFM_CHARSET | CFM_COLOR | CFM_FACE |
|
|
||||||
CFM_OFFSET | CFM_SIZE | CFM_PROTECTED |
|
|
||||||
CFM_BOLD | CFM_ITALIC |
|
|
||||||
CFM_STRIKEOUT | CFM_UNDERLINE;
|
|
||||||
format.dwEffects = 0;
|
|
||||||
format.yHeight = metrics.tmHeight * TWIPS_PER_POINT; // this is in 1/1440 in (twips)
|
|
||||||
format.yOffset = 0;
|
|
||||||
format.crTextColor = RGB(0, 0, 0);
|
|
||||||
format.bCharSet = DEFAULT_CHARSET;
|
|
||||||
format.bPitchAndFamily = FIXED_PITCH | FF_MODERN;
|
|
||||||
GetTextFace(hdc, sizeof(format.szFaceName), format.szFaceName);
|
|
||||||
SelectObject(hdc, oldFont);
|
|
||||||
ReleaseDC(m_hwnd, hdc);
|
|
||||||
|
|
||||||
// prep window
|
|
||||||
SendMessage(m_hwnd, EM_EXLIMITTEXT, 0, m_maxCharacters);
|
|
||||||
SendMessage(m_hwnd, EM_SETCHARFORMAT, 0, reinterpret_cast<LPARAM>(&format));
|
|
||||||
SendMessage(m_hwnd, EM_SETBKGNDCOLOR, 0, RGB(255, 255, 255));
|
|
||||||
m_wChar = metrics.tmAveCharWidth;
|
|
||||||
m_hChar = metrics.tmHeight + metrics.tmExternalLeading;
|
|
||||||
setSize(80, 25);
|
|
||||||
|
|
||||||
// signal ready
|
|
||||||
ARCH->lockMutex(m_mutex);
|
|
||||||
m_ready = true;
|
|
||||||
ARCH->broadcastCondVar(m_condVar);
|
|
||||||
ARCH->unlockMutex(m_mutex);
|
|
||||||
|
|
||||||
// handle failure
|
|
||||||
if (m_hwnd == NULL) {
|
|
||||||
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_appInstance);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// main loop
|
|
||||||
MSG msg;
|
|
||||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
DestroyWindow(m_hwnd);
|
|
||||||
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_appInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
CArchConsoleWindows::threadEntry(void* self)
|
|
||||||
{
|
|
||||||
reinterpret_cast<CArchConsoleWindows*>(self)->threadMainLoop();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,66 +12,14 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CARCHCONSOLEWINDOWS_H
|
#pragma once
|
||||||
#define CARCHCONSOLEWINDOWS_H
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#include "CArchConsoleStd.h"
|
||||||
|
|
||||||
#include "IArchConsole.h"
|
|
||||||
#include "IArchMultithread.h"
|
|
||||||
#include "stddeque.h"
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#define ARCH_CONSOLE CArchConsoleWindows
|
#define ARCH_CONSOLE CArchConsoleWindows
|
||||||
|
|
||||||
//! Win32 implementation of IArchConsole
|
class CArchConsoleWindows : public CArchConsoleStd {
|
||||||
class CArchConsoleWindows : public IArchConsole {
|
|
||||||
public:
|
public:
|
||||||
CArchConsoleWindows(void*);
|
CArchConsoleWindows();
|
||||||
virtual ~CArchConsoleWindows();
|
virtual ~CArchConsoleWindows();
|
||||||
|
|
||||||
// IArchConsole overrides
|
|
||||||
virtual void openConsole(const char* title);
|
|
||||||
virtual void closeConsole();
|
|
||||||
virtual void showConsole(bool showIfEmpty);
|
|
||||||
virtual void writeConsole(const char*);
|
|
||||||
virtual const char* getNewlineForConsole();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void clearBuffer();
|
|
||||||
void appendBuffer(const char*);
|
|
||||||
void setSize(int width, int height);
|
|
||||||
|
|
||||||
LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
|
|
||||||
static LRESULT CALLBACK
|
|
||||||
staticWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
||||||
void threadMainLoop();
|
|
||||||
static void* threadEntry(void*);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::deque<std::string> MessageBuffer;
|
|
||||||
|
|
||||||
static CArchConsoleWindows* s_instance;
|
|
||||||
static HINSTANCE s_appInstance;
|
|
||||||
|
|
||||||
// multithread data
|
|
||||||
CArchMutex m_mutex;
|
|
||||||
CArchCond m_condVar;
|
|
||||||
bool m_ready;
|
|
||||||
CArchThread m_thread;
|
|
||||||
|
|
||||||
// child thread data
|
|
||||||
HWND m_frame;
|
|
||||||
HWND m_hwnd;
|
|
||||||
LONG m_wChar;
|
|
||||||
LONG m_hChar;
|
|
||||||
bool m_show;
|
|
||||||
|
|
||||||
// messages
|
|
||||||
size_t m_maxLines;
|
|
||||||
size_t m_maxCharacters;
|
|
||||||
size_t m_numCharacters;
|
|
||||||
MessageBuffer m_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -142,9 +142,12 @@ CArchDaemonWindows::installDaemon(const char* name,
|
||||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// done with service (but only try to close if not null)
|
||||||
|
CloseServiceHandle(service);
|
||||||
|
}
|
||||||
|
|
||||||
// done with service and manager
|
// done with manager
|
||||||
CloseServiceHandle(service);
|
|
||||||
CloseServiceHandle(mgr);
|
CloseServiceHandle(mgr);
|
||||||
|
|
||||||
// open the registry key for this service
|
// open the registry key for this service
|
||||||
|
|
|
@ -14,6 +14,16 @@
|
||||||
|
|
||||||
#include "CArchMiscWindows.h"
|
#include "CArchMiscWindows.h"
|
||||||
#include "CArchDaemonWindows.h"
|
#include "CArchDaemonWindows.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
|
||||||
|
#include <Wtsapi32.h>
|
||||||
|
#pragma warning(disable: 4099)
|
||||||
|
#include <Userenv.h>
|
||||||
|
#pragma warning(default: 4099)
|
||||||
|
#include "Version.h"
|
||||||
|
|
||||||
|
// parent process name for services in Vista
|
||||||
|
#define SERVICE_LAUNCHER "services.exe"
|
||||||
|
|
||||||
#ifndef ES_SYSTEM_REQUIRED
|
#ifndef ES_SYSTEM_REQUIRED
|
||||||
#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001)
|
#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001)
|
||||||
|
@ -35,6 +45,7 @@ DWORD CArchMiscWindows::s_busyState = 0;
|
||||||
CArchMiscWindows::STES_t CArchMiscWindows::s_stes = NULL;
|
CArchMiscWindows::STES_t CArchMiscWindows::s_stes = NULL;
|
||||||
HICON CArchMiscWindows::s_largeIcon = NULL;
|
HICON CArchMiscWindows::s_largeIcon = NULL;
|
||||||
HICON CArchMiscWindows::s_smallIcon = NULL;
|
HICON CArchMiscWindows::s_smallIcon = NULL;
|
||||||
|
HINSTANCE CArchMiscWindows::s_instanceWin32 = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
CArchMiscWindows::init()
|
CArchMiscWindows::init()
|
||||||
|
@ -193,6 +204,7 @@ void
|
||||||
CArchMiscWindows::closeKey(HKEY key)
|
CArchMiscWindows::closeKey(HKEY key)
|
||||||
{
|
{
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
|
if (key==NULL) return;
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +213,7 @@ CArchMiscWindows::deleteKey(HKEY key, const TCHAR* name)
|
||||||
{
|
{
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
assert(name != NULL);
|
assert(name != NULL);
|
||||||
|
if (key==NULL || name==NULL) return;
|
||||||
RegDeleteKey(key, name);
|
RegDeleteKey(key, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +222,7 @@ CArchMiscWindows::deleteValue(HKEY key, const TCHAR* name)
|
||||||
{
|
{
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
assert(name != NULL);
|
assert(name != NULL);
|
||||||
|
if (key==NULL || name==NULL) return;
|
||||||
RegDeleteValue(key, name);
|
RegDeleteValue(key, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +264,7 @@ CArchMiscWindows::setValue(HKEY key,
|
||||||
{
|
{
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
assert(name != NULL);
|
assert(name != NULL);
|
||||||
|
if(key ==NULL || name==NULL) return; // TODO: throw exception
|
||||||
RegSetValueEx(key, name, 0, REG_SZ,
|
RegSetValueEx(key, name, 0, REG_SZ,
|
||||||
reinterpret_cast<const BYTE*>(value.c_str()),
|
reinterpret_cast<const BYTE*>(value.c_str()),
|
||||||
(DWORD)value.size() + 1);
|
(DWORD)value.size() + 1);
|
||||||
|
@ -260,6 +275,7 @@ CArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value)
|
||||||
{
|
{
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
assert(name != NULL);
|
assert(name != NULL);
|
||||||
|
if(key ==NULL || name==NULL) return; // TODO: throw exception
|
||||||
RegSetValueEx(key, name, 0, REG_DWORD,
|
RegSetValueEx(key, name, 0, REG_DWORD,
|
||||||
reinterpret_cast<CONST BYTE*>(&value),
|
reinterpret_cast<CONST BYTE*>(&value),
|
||||||
sizeof(DWORD));
|
sizeof(DWORD));
|
||||||
|
@ -271,6 +287,7 @@ CArchMiscWindows::setValueBinary(HKEY key,
|
||||||
{
|
{
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
assert(name != NULL);
|
assert(name != NULL);
|
||||||
|
if(key ==NULL || name==NULL) return; // TODO: throw exception
|
||||||
RegSetValueEx(key, name, 0, REG_BINARY,
|
RegSetValueEx(key, name, 0, REG_BINARY,
|
||||||
reinterpret_cast<const BYTE*>(value.data()),
|
reinterpret_cast<const BYTE*>(value.data()),
|
||||||
(DWORD)value.size());
|
(DWORD)value.size());
|
||||||
|
@ -437,3 +454,98 @@ CArchMiscWindows::wakeupDisplay()
|
||||||
// restore the original execution states
|
// restore the original execution states
|
||||||
setThreadExecutionState(s_busyState);
|
setThreadExecutionState(s_busyState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMiscWindows::wasLaunchedAsService()
|
||||||
|
{
|
||||||
|
CString name;
|
||||||
|
if (!getParentProcessName(name)) {
|
||||||
|
LOG((CLOG_ERR "cannot determine if process was launched as service"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (name == SERVICE_LAUNCHER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CArchMiscWindows::getParentProcessName(CString &name)
|
||||||
|
{
|
||||||
|
PROCESSENTRY32 parentEntry;
|
||||||
|
if (!getParentProcessEntry(parentEntry)){
|
||||||
|
LOG((CLOG_ERR "could not get entry for parent process"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = parentEntry.szExeFile;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI
|
||||||
|
CArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32& entry)
|
||||||
|
{
|
||||||
|
// get entry from current PID
|
||||||
|
return getProcessEntry(entry, GetCurrentProcessId());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI
|
||||||
|
CArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry)
|
||||||
|
{
|
||||||
|
// get the current process, so we can get parent PID
|
||||||
|
PROCESSENTRY32 selfEntry;
|
||||||
|
if (!getSelfProcessEntry(selfEntry)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get entry from parent PID
|
||||||
|
return getProcessEntry(entry, selfEntry.th32ParentProcessID);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI
|
||||||
|
CArchMiscWindows::getProcessEntry(PROCESSENTRY32& entry, DWORD processID)
|
||||||
|
{
|
||||||
|
// first we need to take a snapshot of the running processes
|
||||||
|
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (snapshot == INVALID_HANDLE_VALUE) {
|
||||||
|
LOG((CLOG_ERR "could not get process snapshot (error: %i)",
|
||||||
|
GetLastError()));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
|
||||||
|
// get the first process, and if we can't do that then it's
|
||||||
|
// unlikely we can go any further
|
||||||
|
BOOL gotEntry = Process32First(snapshot, &entry);
|
||||||
|
if (!gotEntry) {
|
||||||
|
LOG((CLOG_ERR "could not get first process entry (error: %i)",
|
||||||
|
GetLastError()));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(gotEntry) {
|
||||||
|
|
||||||
|
if (entry.th32ProcessID == processID) {
|
||||||
|
// found current process
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now move on to the next entry (when we reach end, loop will stop)
|
||||||
|
gotEntry = Process32Next(snapshot, &entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HINSTANCE
|
||||||
|
CArchMiscWindows::instanceWin32()
|
||||||
|
{
|
||||||
|
assert(s_instanceWin32 != NULL);
|
||||||
|
return s_instanceWin32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CArchMiscWindows::setInstanceWin32(HINSTANCE instance)
|
||||||
|
{
|
||||||
|
assert(instance != NULL);
|
||||||
|
s_instanceWin32 = instance;
|
||||||
|
}
|
|
@ -21,6 +21,8 @@
|
||||||
#include "stdstring.h"
|
#include "stdstring.h"
|
||||||
#include "stdset.h"
|
#include "stdset.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <Tlhelp32.h>
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
//! Miscellaneous win32 functions.
|
//! Miscellaneous win32 functions.
|
||||||
class CArchMiscWindows {
|
class CArchMiscWindows {
|
||||||
|
@ -164,6 +166,16 @@ public:
|
||||||
//! Briefly interrupt power saving
|
//! Briefly interrupt power saving
|
||||||
static void wakeupDisplay();
|
static void wakeupDisplay();
|
||||||
|
|
||||||
|
//! Returns true if this process was launched via NT service host.
|
||||||
|
static bool wasLaunchedAsService();
|
||||||
|
|
||||||
|
//! Returns true if we got the parent process name.
|
||||||
|
static bool getParentProcessName(CString &name);
|
||||||
|
|
||||||
|
static HINSTANCE instanceWin32();
|
||||||
|
|
||||||
|
static void setInstanceWin32(HINSTANCE instance);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! 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, bool create);
|
static HKEY openKey(HKEY parent, const TCHAR* child, bool create);
|
||||||
|
@ -180,6 +192,10 @@ private:
|
||||||
|
|
||||||
static DWORD WINAPI dummySetThreadExecutionState(DWORD);
|
static DWORD WINAPI dummySetThreadExecutionState(DWORD);
|
||||||
|
|
||||||
|
static BOOL WINAPI getProcessEntry(PROCESSENTRY32& entry, DWORD processID);
|
||||||
|
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32& entry);
|
||||||
|
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32& entry);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::set<HWND> CDialogs;
|
typedef std::set<HWND> CDialogs;
|
||||||
typedef DWORD (WINAPI *STES_t)(DWORD);
|
typedef DWORD (WINAPI *STES_t)(DWORD);
|
||||||
|
@ -189,6 +205,7 @@ private:
|
||||||
static STES_t s_stes;
|
static STES_t s_stes;
|
||||||
static HICON s_largeIcon;
|
static HICON s_largeIcon;
|
||||||
static HICON s_smallIcon;
|
static HICON s_smallIcon;
|
||||||
|
static HINSTANCE s_instanceWin32;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "XArch.h"
|
#include "XArch.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
#include "CArchAppUtilWindows.h"
|
||||||
|
|
||||||
static const UINT kAddReceiver = WM_USER + 10;
|
static const UINT kAddReceiver = WM_USER + 10;
|
||||||
static const UINT kRemoveReceiver = WM_USER + 11;
|
static const UINT kRemoveReceiver = WM_USER + 11;
|
||||||
|
@ -31,17 +32,13 @@ static const UINT kFirstReceiverID = WM_USER + 14;
|
||||||
//
|
//
|
||||||
|
|
||||||
CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
|
CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
|
||||||
HINSTANCE CArchTaskBarWindows::s_appInstance = NULL;
|
|
||||||
|
|
||||||
CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) :
|
CArchTaskBarWindows::CArchTaskBarWindows() :
|
||||||
m_nextID(kFirstReceiverID)
|
m_nextID(kFirstReceiverID)
|
||||||
{
|
{
|
||||||
// save the singleton instance
|
// save the singleton instance
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
|
||||||
// save app instance
|
|
||||||
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
|
|
||||||
|
|
||||||
// we need a mutex
|
// we need a mutex
|
||||||
m_mutex = ARCH->newMutex();
|
m_mutex = ARCH->newMutex();
|
||||||
|
|
||||||
|
@ -437,7 +434,7 @@ CArchTaskBarWindows::threadMainLoop()
|
||||||
classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
|
classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
|
||||||
classInfo.cbClsExtra = 0;
|
classInfo.cbClsExtra = 0;
|
||||||
classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
|
classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
|
||||||
classInfo.hInstance = s_appInstance;
|
classInfo.hInstance = instanceWin32();
|
||||||
classInfo.hIcon = NULL;
|
classInfo.hIcon = NULL;
|
||||||
classInfo.hCursor = NULL;
|
classInfo.hCursor = NULL;
|
||||||
classInfo.hbrBackground = NULL;
|
classInfo.hbrBackground = NULL;
|
||||||
|
@ -454,7 +451,7 @@ CArchTaskBarWindows::threadMainLoop()
|
||||||
0, 0, 1, 1,
|
0, 0, 1, 1,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
s_appInstance,
|
instanceWin32(),
|
||||||
reinterpret_cast<void*>(this));
|
reinterpret_cast<void*>(this));
|
||||||
|
|
||||||
// signal ready
|
// signal ready
|
||||||
|
@ -465,7 +462,7 @@ CArchTaskBarWindows::threadMainLoop()
|
||||||
|
|
||||||
// handle failure
|
// handle failure
|
||||||
if (m_hwnd == NULL) {
|
if (m_hwnd == NULL) {
|
||||||
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_appInstance);
|
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), instanceWin32());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +478,7 @@ CArchTaskBarWindows::threadMainLoop()
|
||||||
// clean up
|
// clean up
|
||||||
removeAllIcons();
|
removeAllIcons();
|
||||||
DestroyWindow(m_hwnd);
|
DestroyWindow(m_hwnd);
|
||||||
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), s_appInstance);
|
UnregisterClass(reinterpret_cast<LPCTSTR>(windowClass), instanceWin32());
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
|
@ -490,3 +487,8 @@ CArchTaskBarWindows::threadEntry(void* self)
|
||||||
reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
|
reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HINSTANCE CArchTaskBarWindows::instanceWin32()
|
||||||
|
{
|
||||||
|
return CArchMiscWindows::instanceWin32();
|
||||||
|
}
|
|
@ -28,7 +28,7 @@
|
||||||
//! Win32 implementation of IArchTaskBar
|
//! Win32 implementation of IArchTaskBar
|
||||||
class CArchTaskBarWindows : public IArchTaskBar {
|
class CArchTaskBarWindows : public IArchTaskBar {
|
||||||
public:
|
public:
|
||||||
CArchTaskBarWindows(void*);
|
CArchTaskBarWindows();
|
||||||
virtual ~CArchTaskBarWindows();
|
virtual ~CArchTaskBarWindows();
|
||||||
|
|
||||||
//! Add a dialog window
|
//! Add a dialog window
|
||||||
|
@ -81,9 +81,10 @@ private:
|
||||||
void threadMainLoop();
|
void threadMainLoop();
|
||||||
static void* threadEntry(void*);
|
static void* threadEntry(void*);
|
||||||
|
|
||||||
|
HINSTANCE instanceWin32();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static CArchTaskBarWindows* s_instance;
|
static CArchTaskBarWindows* s_instance;
|
||||||
static HINSTANCE s_appInstance;
|
|
||||||
|
|
||||||
// multithread data
|
// multithread data
|
||||||
CArchMutex m_mutex;
|
CArchMutex m_mutex;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
// CArchTaskBarXWindows
|
// CArchTaskBarXWindows
|
||||||
//
|
//
|
||||||
|
|
||||||
CArchTaskBarXWindows::CArchTaskBarXWindows(void*)
|
CArchTaskBarXWindows::CArchTaskBarXWindows()
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
//! X11 implementation of IArchTaskBar
|
//! X11 implementation of IArchTaskBar
|
||||||
class CArchTaskBarXWindows : public IArchTaskBar {
|
class CArchTaskBarXWindows : public IArchTaskBar {
|
||||||
public:
|
public:
|
||||||
CArchTaskBarXWindows(void*);
|
CArchTaskBarXWindows();
|
||||||
virtual ~CArchTaskBarXWindows();
|
virtual ~CArchTaskBarXWindows();
|
||||||
|
|
||||||
// IArchTaskBar overrides
|
// IArchTaskBar overrides
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
// TODO: replace with forward declaration if possible
|
||||||
|
// we need to decouple these classes!
|
||||||
|
#include "CApp.h"
|
||||||
|
|
||||||
|
class IArchAppUtil : public IInterface {
|
||||||
|
public:
|
||||||
|
virtual bool parseArg(const int& argc, const char* const* argv, int& i) = 0;
|
||||||
|
virtual void adoptApp(CApp* app) = 0;
|
||||||
|
virtual CApp& app() const = 0;
|
||||||
|
virtual int run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver) = 0;
|
||||||
|
};
|
|
@ -58,13 +58,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void writeConsole(const char*) = 0;
|
virtual void writeConsole(const char*) = 0;
|
||||||
|
|
||||||
//! Returns the newline sequence for the console
|
|
||||||
/*!
|
|
||||||
Different consoles use different character sequences for newlines.
|
|
||||||
This method returns the appropriate newline sequence for the console.
|
|
||||||
*/
|
|
||||||
virtual const char* getNewlineForConsole() = 0;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "IInterface.h"
|
#include "IInterface.h"
|
||||||
#include "stdstring.h"
|
#include "stdstring.h"
|
||||||
|
|
||||||
|
class IScreen;
|
||||||
|
class INode;
|
||||||
|
|
||||||
//! Interface for architecture dependent task bar event handling
|
//! Interface for architecture dependent task bar event handling
|
||||||
/*!
|
/*!
|
||||||
This interface defines the task bar icon event handlers required
|
This interface defines the task bar icon event handlers required
|
||||||
|
@ -84,6 +87,8 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual std::string getToolTip() const = 0;
|
virtual std::string getToolTip() const = 0;
|
||||||
|
|
||||||
|
virtual void updateStatus(INode*, const CString& errorMsg) = 0;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,16 @@ static const char* g_priority[] = {
|
||||||
"WARNING",
|
"WARNING",
|
||||||
"NOTE",
|
"NOTE",
|
||||||
"INFO",
|
"INFO",
|
||||||
"DEBUG",
|
"DEBUG",
|
||||||
"DEBUG1",
|
"DEBUG1",
|
||||||
"DEBUG2"
|
"DEBUG2",
|
||||||
|
"DEBUG3",
|
||||||
|
"DEBUG4",
|
||||||
|
"DEBUG5"
|
||||||
};
|
};
|
||||||
|
|
||||||
// number of priorities
|
// number of priorities
|
||||||
static const int g_numPriority = (int)(sizeof(g_priority) /
|
static const int g_numPriority = (int)(sizeof(g_priority) / sizeof(g_priority[0]));
|
||||||
sizeof(g_priority[0]));
|
|
||||||
|
|
||||||
// the default priority
|
// the default priority
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
|
@ -101,14 +103,32 @@ CLog::getInstance()
|
||||||
return s_log;
|
return s_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CLog::getFilterName() const
|
||||||
|
{
|
||||||
|
return getFilterName(getFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CLog::getFilterName(int level) const
|
||||||
|
{
|
||||||
|
return g_priority[level];
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::print(const char* file, int line, const char* fmt, ...) const
|
CLog::print(const char* file, int line, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
// check if fmt begins with a priority argument
|
// check if fmt begins with a priority argument
|
||||||
int priority = 4;
|
ELevel priority = kINFO;
|
||||||
if (fmt[0] == '%' && fmt[1] == 'z') {
|
if (fmt[0] == '%' && fmt[1] == 'z') {
|
||||||
priority = fmt[2] - '\060';
|
|
||||||
fmt += 3;
|
// 060 in octal is 0 (48 in decimal), so subtracting this converts ascii
|
||||||
|
// number it a true number. we could use atoi instead, but this is how
|
||||||
|
// it was done originally.
|
||||||
|
priority = (ELevel)(fmt[2] - '\060'); // TODO: fix this shit
|
||||||
|
|
||||||
|
// move the pointer on past the debug priority char
|
||||||
|
fmt += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// done if below priority threshold
|
// done if below priority threshold
|
||||||
|
@ -183,8 +203,7 @@ CLog::print(const char* file, int line, const char* fmt, ...) const
|
||||||
void
|
void
|
||||||
CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
|
CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
|
||||||
{
|
{
|
||||||
assert(outputter != NULL);
|
assert(outputter != NULL);
|
||||||
assert(outputter->getNewline() != NULL);
|
|
||||||
|
|
||||||
CArchMutexLock lock(m_mutex);
|
CArchMutexLock lock(m_mutex);
|
||||||
if (alwaysAtHead) {
|
if (alwaysAtHead) {
|
||||||
|
@ -193,10 +212,7 @@ CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
|
||||||
else {
|
else {
|
||||||
m_outputters.push_front(outputter);
|
m_outputters.push_front(outputter);
|
||||||
}
|
}
|
||||||
int newlineLength = (int)strlen(outputter->getNewline());
|
|
||||||
if (newlineLength > m_maxNewlineLength) {
|
|
||||||
m_maxNewlineLength = newlineLength;
|
|
||||||
}
|
|
||||||
outputter->open(kAppVersion);
|
outputter->open(kAppVersion);
|
||||||
|
|
||||||
// Issue 41
|
// Issue 41
|
||||||
|
@ -258,62 +274,27 @@ CLog::getFilter() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CLog::output(int priority, char* msg) const
|
CLog::output(ELevel priority, char* msg)
|
||||||
{
|
{
|
||||||
assert(priority >= -1 && priority < g_numPriority);
|
assert(priority >= -1 && priority < g_numPriority);
|
||||||
assert(msg != NULL);
|
assert(msg != NULL);
|
||||||
|
if (!msg) return;
|
||||||
|
|
||||||
// insert priority label
|
|
||||||
//int n = -g_prioritySuffixLength;
|
|
||||||
/*
|
|
||||||
if (priority >= 0) {
|
|
||||||
|
|
||||||
|
|
||||||
n = strlen(g_priority[priority]);
|
|
||||||
strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
|
|
||||||
msg[g_maxPriorityLength + 0] = ':';
|
|
||||||
msg[g_maxPriorityLength + 1] = ' ';
|
|
||||||
msg[g_maxPriorityLength + 1] = ' ';
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// find end of message
|
|
||||||
//char* end = msg + g_priorityPad + strlen(msg + g_priorityPad);
|
|
||||||
int len = (int)strlen(msg);
|
|
||||||
char* tmp = new char[len+m_maxNewlineLength+1];
|
|
||||||
char* end = tmp + len;
|
|
||||||
strcpy(tmp, msg);
|
|
||||||
|
|
||||||
// write to each outputter
|
|
||||||
CArchMutexLock lock(m_mutex);
|
CArchMutexLock lock(m_mutex);
|
||||||
for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
|
|
||||||
index != m_alwaysOutputters.end();
|
|
||||||
++index) {
|
|
||||||
// get outputter
|
|
||||||
ILogOutputter* outputter = *index;
|
|
||||||
|
|
||||||
// put an appropriate newline at the end
|
COutputterList::const_iterator i;
|
||||||
strcpy(end, outputter->getNewline());
|
|
||||||
|
|
||||||
// write message
|
for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) {
|
||||||
outputter->write(static_cast<ILogOutputter::ELevel>(priority),
|
|
||||||
tmp /*+ g_maxPriorityLength - n*/);
|
|
||||||
}
|
|
||||||
for (COutputterList::const_iterator index = m_outputters.begin();
|
|
||||||
index != m_outputters.end(); ++index) {
|
|
||||||
// get outputter
|
|
||||||
ILogOutputter* outputter = *index;
|
|
||||||
|
|
||||||
// put an appropriate newline at the end
|
// write to outputter
|
||||||
strcpy(end, outputter->getNewline());
|
(*i)->write(priority, msg);
|
||||||
|
|
||||||
// write message and break out of loop if it returns false
|
|
||||||
if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
|
|
||||||
tmp /*+ g_maxPriorityLength - n*/)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] tmp;
|
for (i = m_outputters.begin(); i != m_outputters.end(); ++i) {
|
||||||
|
|
||||||
|
// write to outputter and break out of loop if it returns false
|
||||||
|
if (!(*i)->write(priority, msg)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -19,10 +19,12 @@
|
||||||
#include "IArchMultithread.h"
|
#include "IArchMultithread.h"
|
||||||
#include "stdlist.h"
|
#include "stdlist.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
#define CLOG (CLog::getInstance())
|
#define CLOG (CLog::getInstance())
|
||||||
|
|
||||||
class ILogOutputter;
|
class ILogOutputter;
|
||||||
|
class CThread;
|
||||||
|
|
||||||
//! Logging facility
|
//! Logging facility
|
||||||
/*!
|
/*!
|
||||||
|
@ -44,8 +46,11 @@ public:
|
||||||
kNOTE, //!< For messages about notable events
|
kNOTE, //!< For messages about notable events
|
||||||
kINFO, //!< For informational messages
|
kINFO, //!< For informational messages
|
||||||
kDEBUG, //!< For important debugging messages
|
kDEBUG, //!< For important debugging messages
|
||||||
kDEBUG1, //!< For more detailed debugging messages
|
kDEBUG1, //!< For verbosity +1 debugging messages
|
||||||
kDEBUG2 //!< For even more detailed debugging messages
|
kDEBUG2, //!< For verbosity +2 debugging messages
|
||||||
|
kDEBUG3, //!< For verbosity +3 debugging messages
|
||||||
|
kDEBUG4, //!< For verbosity +4 debugging messages
|
||||||
|
kDEBUG5 //!< For verbosity +5 debugging messages
|
||||||
};
|
};
|
||||||
|
|
||||||
~CLog();
|
~CLog();
|
||||||
|
@ -109,20 +114,28 @@ public:
|
||||||
neither the file nor the line are printed.
|
neither the file nor the line are printed.
|
||||||
*/
|
*/
|
||||||
void print(const char* file, int line,
|
void print(const char* file, int line,
|
||||||
const char* format, ...) const;
|
const char* format, ...);
|
||||||
|
|
||||||
//! Get the minimum priority level.
|
//! Get the minimum priority level.
|
||||||
int getFilter() const;
|
int getFilter() const;
|
||||||
|
|
||||||
|
//! Get the filter name of the current filter level.
|
||||||
|
const char* getFilterName() const;
|
||||||
|
|
||||||
|
//! Get the filter name of a specified filter level.
|
||||||
|
const char* getFilterName(int level) const;
|
||||||
|
|
||||||
//! Get the singleton instance of the log
|
//! Get the singleton instance of the log
|
||||||
static CLog* getInstance();
|
static CLog* getInstance();
|
||||||
|
|
||||||
|
//! Get the console filter level (messages above this are not sent to console).
|
||||||
|
int getConsoleMaxLevel() const { return kDEBUG1; }
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CLog();
|
CLog();
|
||||||
|
|
||||||
void output(int priority, char* msg) const;
|
void output(ELevel priority, char* msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::list<ILogOutputter*> COutputterList;
|
typedef std::list<ILogOutputter*> COutputterList;
|
||||||
|
@ -189,8 +202,13 @@ otherwise it expands to a call that doesn't.
|
||||||
#define CLOG_TRACE __FILE__, __LINE__,
|
#define CLOG_TRACE __FILE__, __LINE__,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CLOG_PRINT CLOG_TRACE "%z\057"
|
// the CLOG_* defines are line and file plus %z and an octal number (060=0,
|
||||||
#define CLOG_CRIT CLOG_TRACE "%z\060"
|
// 071=9), but the limitation is that once we run out of numbers at either
|
||||||
|
// end, then we resort to using non-numerical chars. this still works (since
|
||||||
|
// to deduce the number we subtract octal \060, so '/' is -1, and ':' is 10
|
||||||
|
|
||||||
|
#define CLOG_PRINT CLOG_TRACE "%z\057" // char is '/'
|
||||||
|
#define CLOG_CRIT CLOG_TRACE "%z\060" // char is '0'
|
||||||
#define CLOG_ERR CLOG_TRACE "%z\061"
|
#define CLOG_ERR CLOG_TRACE "%z\061"
|
||||||
#define CLOG_WARN CLOG_TRACE "%z\062"
|
#define CLOG_WARN CLOG_TRACE "%z\062"
|
||||||
#define CLOG_NOTE CLOG_TRACE "%z\063"
|
#define CLOG_NOTE CLOG_TRACE "%z\063"
|
||||||
|
@ -198,5 +216,8 @@ otherwise it expands to a call that doesn't.
|
||||||
#define CLOG_DEBUG CLOG_TRACE "%z\065"
|
#define CLOG_DEBUG CLOG_TRACE "%z\065"
|
||||||
#define CLOG_DEBUG1 CLOG_TRACE "%z\066"
|
#define CLOG_DEBUG1 CLOG_TRACE "%z\066"
|
||||||
#define CLOG_DEBUG2 CLOG_TRACE "%z\067"
|
#define CLOG_DEBUG2 CLOG_TRACE "%z\067"
|
||||||
|
#define CLOG_DEBUG3 CLOG_TRACE "%z\070"
|
||||||
|
#define CLOG_DEBUG4 CLOG_TRACE "%z\071" // char is '9'
|
||||||
|
#define CLOG_DEBUG5 CLOG_TRACE "%z\072" // char is ':'
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -63,18 +63,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual bool write(ELevel level, const char* message) = 0;
|
virtual bool write(ELevel level, const char* message) = 0;
|
||||||
|
|
||||||
//@}
|
|
||||||
//! @name accessors
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//! Returns the newline sequence for the outputter
|
|
||||||
/*!
|
|
||||||
Different outputters use different character sequences for newlines.
|
|
||||||
This method returns the appropriate newline sequence for this
|
|
||||||
outputter.
|
|
||||||
*/
|
|
||||||
virtual const char* getNewline() const = 0;
|
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "LogOutputters.h"
|
#include "LogOutputters.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
#include "TMethodJob.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
//
|
//
|
||||||
|
@ -54,12 +55,6 @@ CStopLogOutputter::write(ELevel, const char*)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
|
||||||
CStopLogOutputter::getNewline() const
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CConsoleLogOutputter
|
// CConsoleLogOutputter
|
||||||
|
@ -67,12 +62,10 @@ CStopLogOutputter::getNewline() const
|
||||||
|
|
||||||
CConsoleLogOutputter::CConsoleLogOutputter()
|
CConsoleLogOutputter::CConsoleLogOutputter()
|
||||||
{
|
{
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CConsoleLogOutputter::~CConsoleLogOutputter()
|
CConsoleLogOutputter::~CConsoleLogOutputter()
|
||||||
{
|
{
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -94,16 +87,16 @@ CConsoleLogOutputter::show(bool showIfEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CConsoleLogOutputter::write(ELevel, const char* msg)
|
CConsoleLogOutputter::write(ELevel level, const char* msg)
|
||||||
{
|
{
|
||||||
ARCH->writeConsole(msg);
|
ARCH->writeConsole(msg);
|
||||||
return true;
|
return true; // wtf?
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
void
|
||||||
CConsoleLogOutputter::getNewline() const
|
CConsoleLogOutputter::flush()
|
||||||
{
|
{
|
||||||
return ARCH->getNewlineForConsole();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,13 +163,6 @@ CSystemLogOutputter::write(ELevel level, const char* msg)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
|
||||||
CSystemLogOutputter::getNewline() const
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CSystemLogger
|
// CSystemLogger
|
||||||
//
|
//
|
||||||
|
@ -261,12 +247,6 @@ CBufferedLogOutputter::write(ELevel, const char* message)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
|
||||||
CBufferedLogOutputter::getNewline() const
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CFileLogOutputter
|
// CFileLogOutputter
|
||||||
|
@ -287,17 +267,11 @@ CFileLogOutputter::~CFileLogOutputter()
|
||||||
m_handle.close();
|
m_handle.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
|
||||||
CFileLogOutputter::getNewline() const
|
|
||||||
{
|
|
||||||
return "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CFileLogOutputter::write(ILogOutputter::ELevel level, const char *message)
|
CFileLogOutputter::write(ILogOutputter::ELevel level, const char *message)
|
||||||
{
|
{
|
||||||
if (m_handle.is_open() && m_handle.fail() != true) {
|
if (m_handle.is_open() && m_handle.fail() != true) {
|
||||||
m_handle << message;
|
m_handle << message << std::endl;
|
||||||
|
|
||||||
// write buffer to file
|
// write buffer to file
|
||||||
m_handle.flush();
|
m_handle.flush();
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
#include "ILogOutputter.h"
|
#include "ILogOutputter.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "stddeque.h"
|
#include "stddeque.h"
|
||||||
|
#include "CThread.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
//! Stop traversing log chain outputter
|
//! Stop traversing log chain outputter
|
||||||
/*!
|
/*!
|
||||||
This outputter performs no output and returns false from \c write(),
|
This outputter performs no output and returns false from \c write(),
|
||||||
|
@ -37,7 +40,6 @@ public:
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual void show(bool showIfEmpty);
|
virtual void show(bool showIfEmpty);
|
||||||
virtual bool write(ELevel level, const char* message);
|
virtual bool write(ELevel level, const char* message);
|
||||||
virtual const char* getNewline() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Write log to console
|
//! Write log to console
|
||||||
|
@ -55,7 +57,7 @@ public:
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual void show(bool showIfEmpty);
|
virtual void show(bool showIfEmpty);
|
||||||
virtual bool write(ELevel level, const char* message);
|
virtual bool write(ELevel level, const char* message);
|
||||||
virtual const char* getNewline() const;
|
virtual void flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Write log to file
|
//! Write log to file
|
||||||
|
@ -74,7 +76,6 @@ public:
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual void show(bool showIfEmpty);
|
virtual void show(bool showIfEmpty);
|
||||||
virtual bool write(ELevel level, const char* message);
|
virtual bool write(ELevel level, const char* message);
|
||||||
virtual const char* getNewline() const;
|
|
||||||
private:
|
private:
|
||||||
std::ofstream m_handle;
|
std::ofstream m_handle;
|
||||||
};
|
};
|
||||||
|
@ -93,7 +94,6 @@ public:
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual void show(bool showIfEmpty);
|
virtual void show(bool showIfEmpty);
|
||||||
virtual bool write(ELevel level, const char* message);
|
virtual bool write(ELevel level, const char* message);
|
||||||
virtual const char* getNewline() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Write log to system log only
|
//! Write log to system log only
|
||||||
|
@ -144,8 +144,6 @@ public:
|
||||||
virtual void close();
|
virtual void close();
|
||||||
virtual void show(bool showIfEmpty);
|
virtual void show(bool showIfEmpty);
|
||||||
virtual bool write(ELevel level, const char* message);
|
virtual bool write(ELevel level, const char* message);
|
||||||
virtual const char* getNewline() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UInt32 m_maxBufferSize;
|
UInt32 m_maxBufferSize;
|
||||||
CBuffer m_buffer;
|
CBuffer m_buffer;
|
||||||
|
|
|
@ -390,10 +390,10 @@ CClient::sendEvent(CEvent::Type type, void* data)
|
||||||
void
|
void
|
||||||
CClient::sendConnectionFailedEvent(const char* msg)
|
CClient::sendConnectionFailedEvent(const char* msg)
|
||||||
{
|
{
|
||||||
CFailInfo* info = (CFailInfo*)malloc(sizeof(CFailInfo) + strlen(msg));
|
CFailInfo* info = new CFailInfo(msg);
|
||||||
info->m_retry = true;
|
info->m_retry = true;
|
||||||
strcpy(info->m_what, msg);
|
CEvent event(getConnectionFailedEvent(), getEventTarget(), info, CEvent::kDontFreeData);
|
||||||
sendEvent(getConnectionFailedEvent(), info);
|
EVENTQUEUE->addEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -549,7 +549,8 @@ CClient::handleConnectionFailed(const CEvent& event, void*)
|
||||||
delete m_stream;
|
delete m_stream;
|
||||||
m_stream = NULL;
|
m_stream = NULL;
|
||||||
LOG((CLOG_DEBUG1 "connection failed"));
|
LOG((CLOG_DEBUG1 "connection failed"));
|
||||||
sendConnectionFailedEvent(info->m_what);
|
sendConnectionFailedEvent(info->m_what.c_str());
|
||||||
|
delete info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "IClient.h"
|
#include "IClient.h"
|
||||||
#include "IClipboard.h"
|
#include "IClipboard.h"
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
|
#include "INode.h"
|
||||||
|
|
||||||
class CEventQueueTimer;
|
class CEventQueueTimer;
|
||||||
class CScreen;
|
class CScreen;
|
||||||
|
@ -31,12 +32,13 @@ class IStreamFilterFactory;
|
||||||
/*!
|
/*!
|
||||||
This class implements the top-level client algorithms for synergy.
|
This class implements the top-level client algorithms for synergy.
|
||||||
*/
|
*/
|
||||||
class CClient : public IClient {
|
class CClient : public IClient, public INode {
|
||||||
public:
|
public:
|
||||||
class CFailInfo {
|
class CFailInfo {
|
||||||
public:
|
public:
|
||||||
|
CFailInfo(const char* what) : m_retry(false), m_what(what) { }
|
||||||
bool m_retry;
|
bool m_retry;
|
||||||
char m_what[1];
|
CString m_what;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -98,6 +98,10 @@
|
||||||
// this one's a little too aggressive
|
// this one's a little too aggressive
|
||||||
# pragma warning(disable: 4127) // conditional expression is constant
|
# pragma warning(disable: 4127) // conditional expression is constant
|
||||||
|
|
||||||
|
// Code Analysis
|
||||||
|
# pragma warning(disable: 6011)
|
||||||
|
|
||||||
|
|
||||||
// emitted incorrectly under release build in some circumstances
|
// emitted incorrectly under release build in some circumstances
|
||||||
# if defined(NDEBUG)
|
# if defined(NDEBUG)
|
||||||
# pragma warning(disable: 4702) // unreachable code
|
# pragma warning(disable: 4702) // unreachable code
|
||||||
|
@ -129,6 +133,15 @@
|
||||||
// define NULL
|
// define NULL
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// we don't want to use NULL since it's old and nasty, so replace any
|
||||||
|
// usages with nullptr (warning: this could break many things).
|
||||||
|
// if not c++0x yet, future proof code by allowing use of nullptr
|
||||||
|
#ifdef nullptr
|
||||||
|
#define NULL nullptr
|
||||||
|
#else
|
||||||
|
#define nullptr NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
// make assert available since we use it a lot
|
// make assert available since we use it a lot
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
|
@ -101,9 +101,9 @@ CTCPListenSocket::getEventTarget() const
|
||||||
IDataSocket*
|
IDataSocket*
|
||||||
CTCPListenSocket::accept()
|
CTCPListenSocket::accept()
|
||||||
{
|
{
|
||||||
|
IDataSocket* socket = NULL;
|
||||||
try {
|
try {
|
||||||
IDataSocket* socket =
|
socket = new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
|
||||||
new CTCPSocket(ARCH->acceptSocket(m_socket, NULL));
|
|
||||||
if (socket != NULL) {
|
if (socket != NULL) {
|
||||||
CSocketMultiplexer::getInstance()->addSocket(this,
|
CSocketMultiplexer::getInstance()->addSocket(this,
|
||||||
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
new TSocketMultiplexerMethodJob<CTCPListenSocket>(
|
||||||
|
@ -113,8 +113,17 @@ CTCPListenSocket::accept()
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork&) {
|
||||||
|
if (socket != NULL) {
|
||||||
|
delete socket;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
catch (std::exception &ex) {
|
||||||
|
if (socket != NULL) {
|
||||||
|
delete socket;
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ISocketMultiplexerJob*
|
ISocketMultiplexerJob*
|
||||||
|
|
|
@ -346,11 +346,9 @@ CTCPSocket::newJob()
|
||||||
void
|
void
|
||||||
CTCPSocket::sendConnectionFailedEvent(const char* msg)
|
CTCPSocket::sendConnectionFailedEvent(const char* msg)
|
||||||
{
|
{
|
||||||
CConnectionFailedInfo* info = (CConnectionFailedInfo*)malloc(
|
CConnectionFailedInfo* info = new CConnectionFailedInfo(msg);
|
||||||
sizeof(CConnectionFailedInfo) + strlen(msg));
|
|
||||||
strcpy(info->m_what, msg);
|
|
||||||
EVENTQUEUE->addEvent(CEvent(getConnectionFailedEvent(),
|
EVENTQUEUE->addEvent(CEvent(getConnectionFailedEvent(),
|
||||||
getEventTarget(), info));
|
getEventTarget(), info, CEvent::kDontFreeData));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "ISocket.h"
|
#include "ISocket.h"
|
||||||
#include "IStream.h"
|
#include "IStream.h"
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
//! Data stream socket interface
|
//! Data stream socket interface
|
||||||
/*!
|
/*!
|
||||||
|
@ -27,8 +28,8 @@ class IDataSocket : public ISocket, public IStream {
|
||||||
public:
|
public:
|
||||||
class CConnectionFailedInfo {
|
class CConnectionFailedInfo {
|
||||||
public:
|
public:
|
||||||
// pointer to a string describing the failure
|
CConnectionFailedInfo(const char* what) : m_what(what) { }
|
||||||
char m_what[1];
|
CString m_what;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
CMSWindowsDesks::CMSWindowsDesks(
|
CMSWindowsDesks::CMSWindowsDesks(
|
||||||
bool isPrimary, HINSTANCE hookLibrary,
|
bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
|
||||||
const IScreenSaver* screensaver, IJob* updateKeys) :
|
const IScreenSaver* screensaver, IJob* updateKeys) :
|
||||||
m_isPrimary(isPrimary),
|
m_isPrimary(isPrimary),
|
||||||
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
||||||
|
@ -361,7 +361,7 @@ void
|
||||||
CMSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary)
|
CMSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary)
|
||||||
{
|
{
|
||||||
// look up functions
|
// look up functions
|
||||||
if (m_isPrimary) {
|
if (m_isPrimary && !m_noHooks) {
|
||||||
m_install = (InstallFunc)GetProcAddress(hookLibrary, "install");
|
m_install = (InstallFunc)GetProcAddress(hookLibrary, "install");
|
||||||
m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall");
|
m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall");
|
||||||
m_installScreensaver =
|
m_installScreensaver =
|
||||||
|
@ -736,7 +736,7 @@ CMSWindowsDesks::deskThread(void* vdesk)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case SYNERGY_MSG_SWITCH:
|
case SYNERGY_MSG_SWITCH:
|
||||||
if (m_isPrimary) {
|
if (m_isPrimary && !m_noHooks) {
|
||||||
m_uninstall();
|
m_uninstall();
|
||||||
if (m_screensaverNotify) {
|
if (m_screensaverNotify) {
|
||||||
m_uninstallScreensaver();
|
m_uninstallScreensaver();
|
||||||
|
@ -816,11 +816,13 @@ CMSWindowsDesks::deskThread(void* vdesk)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYNERGY_MSG_SCREENSAVER:
|
case SYNERGY_MSG_SCREENSAVER:
|
||||||
if (msg.wParam != 0) {
|
if (!m_noHooks) {
|
||||||
m_installScreensaver();
|
if (msg.wParam != 0) {
|
||||||
}
|
m_installScreensaver();
|
||||||
else {
|
}
|
||||||
m_uninstallScreensaver();
|
else {
|
||||||
|
m_uninstallScreensaver();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ public:
|
||||||
updated in a thread attached to the current desk.
|
updated in a thread attached to the current desk.
|
||||||
\p hookLibrary must be a handle to the hook library.
|
\p hookLibrary must be a handle to the hook library.
|
||||||
*/
|
*/
|
||||||
CMSWindowsDesks(bool isPrimary, HINSTANCE hookLibrary,
|
CMSWindowsDesks(bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
|
||||||
const IScreenSaver* screensaver, IJob* updateKeys);
|
const IScreenSaver* screensaver, IJob* updateKeys);
|
||||||
~CMSWindowsDesks();
|
~CMSWindowsDesks();
|
||||||
|
|
||||||
|
@ -241,6 +241,9 @@ private:
|
||||||
// true if screen is being used as a primary screen, false otherwise
|
// true if screen is being used as a primary screen, false otherwise
|
||||||
bool m_isPrimary;
|
bool m_isPrimary;
|
||||||
|
|
||||||
|
// true if hooks are not to be installed (useful for debugging)
|
||||||
|
bool m_noHooks;
|
||||||
|
|
||||||
// true if windows 95/98/me
|
// true if windows 95/98/me
|
||||||
bool m_is95Family;
|
bool m_is95Family;
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,9 @@
|
||||||
HINSTANCE CMSWindowsScreen::s_instance = NULL;
|
HINSTANCE CMSWindowsScreen::s_instance = NULL;
|
||||||
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
|
CMSWindowsScreen* CMSWindowsScreen::s_screen = NULL;
|
||||||
|
|
||||||
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) :
|
CMSWindowsScreen::CMSWindowsScreen(bool isPrimary, bool noHooks) :
|
||||||
m_isPrimary(isPrimary),
|
m_isPrimary(isPrimary),
|
||||||
|
m_noHooks(noHooks),
|
||||||
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
m_is95Family(CArchMiscWindows::isWindows95Family()),
|
||||||
m_isOnScreen(m_isPrimary),
|
m_isOnScreen(m_isPrimary),
|
||||||
m_class(0),
|
m_class(0),
|
||||||
|
@ -118,7 +119,8 @@ CMSWindowsScreen::CMSWindowsScreen(bool isPrimary) :
|
||||||
m_hookLibrary = openHookLibrary("synrgyhk");
|
m_hookLibrary = openHookLibrary("synrgyhk");
|
||||||
}
|
}
|
||||||
m_screensaver = new CMSWindowsScreenSaver();
|
m_screensaver = new CMSWindowsScreenSaver();
|
||||||
m_desks = new CMSWindowsDesks(m_isPrimary,
|
m_desks = new CMSWindowsDesks(
|
||||||
|
m_isPrimary, m_noHooks,
|
||||||
m_hookLibrary, m_screensaver,
|
m_hookLibrary, m_screensaver,
|
||||||
new TMethodJob<CMSWindowsScreen>(this,
|
new TMethodJob<CMSWindowsScreen>(this,
|
||||||
&CMSWindowsScreen::updateKeysCB));
|
&CMSWindowsScreen::updateKeysCB));
|
||||||
|
@ -491,7 +493,7 @@ void CMSWindowsScreen::saveMousePosition(SInt32 x, SInt32 y) {
|
||||||
m_xCursor = x;
|
m_xCursor = x;
|
||||||
m_yCursor = y;
|
m_yCursor = y;
|
||||||
|
|
||||||
LOG((CLOG_DEBUG2 "saved mouse position for next delta: %+d,%+d", x,y));
|
LOG((CLOG_DEBUG5 "saved mouse position for next delta: %+d,%+d", x,y));
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
|
@ -763,6 +765,7 @@ CMSWindowsScreen::createBlankCursor() const
|
||||||
// create a transparent cursor
|
// create a transparent cursor
|
||||||
int cw = GetSystemMetrics(SM_CXCURSOR);
|
int cw = GetSystemMetrics(SM_CXCURSOR);
|
||||||
int ch = GetSystemMetrics(SM_CYCURSOR);
|
int ch = GetSystemMetrics(SM_CYCURSOR);
|
||||||
|
|
||||||
UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
|
UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)];
|
||||||
UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
|
UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)];
|
||||||
memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
|
memset(cursorAND, 0xff, ch * ((cw + 31) >> 2));
|
||||||
|
@ -916,7 +919,7 @@ bool
|
||||||
CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
CMSWindowsScreen::onPreDispatchPrimary(HWND,
|
||||||
UINT message, WPARAM wParam, LPARAM lParam)
|
UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG2 "handling pre-dispatch primary"));
|
LOG((CLOG_DEBUG5 "handling pre-dispatch primary"));
|
||||||
|
|
||||||
// handle event
|
// handle event
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
@ -1298,8 +1301,8 @@ CMSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
|
||||||
SInt32 x = mx - m_xCursor;
|
SInt32 x = mx - m_xCursor;
|
||||||
SInt32 y = my - m_yCursor;
|
SInt32 y = my - m_yCursor;
|
||||||
|
|
||||||
LOG((CLOG_DEBUG2
|
LOG((CLOG_DEBUG3
|
||||||
"handling mouse move; delta motion calc: %+d=(%+d - %+d),%+d=(%+d - %+d)",
|
"mouse move - motion delta: %+d=(%+d - %+d),%+d=(%+d - %+d)",
|
||||||
x, mx, m_xCursor, y, my, m_yCursor));
|
x, mx, m_xCursor, y, my, m_yCursor));
|
||||||
|
|
||||||
// ignore if the mouse didn't move or if message posted prior
|
// ignore if the mouse didn't move or if message posted prior
|
||||||
|
@ -1324,7 +1327,7 @@ CMSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my)
|
||||||
// center on the server screen. if we don't do this, then the mouse
|
// center on the server screen. if we don't do this, then the mouse
|
||||||
// will always try to return to the original entry point on the
|
// will always try to return to the original entry point on the
|
||||||
// secondary screen.
|
// secondary screen.
|
||||||
LOG((CLOG_DEBUG2 "warping server cursor to center: %+d,%+d", m_xCenter, m_yCenter));
|
LOG((CLOG_DEBUG5 "warping server cursor to center: %+d,%+d", m_xCenter, m_yCenter));
|
||||||
warpCursorNoFlush(m_xCenter, m_yCenter);
|
warpCursorNoFlush(m_xCenter, m_yCenter);
|
||||||
|
|
||||||
// examine the motion. if it's about the distance
|
// examine the motion. if it's about the distance
|
||||||
|
|
|
@ -32,7 +32,7 @@ class CThread;
|
||||||
//! Implementation of IPlatformScreen for Microsoft Windows
|
//! Implementation of IPlatformScreen for Microsoft Windows
|
||||||
class CMSWindowsScreen : public CPlatformScreen {
|
class CMSWindowsScreen : public CPlatformScreen {
|
||||||
public:
|
public:
|
||||||
CMSWindowsScreen(bool isPrimary);
|
CMSWindowsScreen(bool isPrimary, bool noHooks);
|
||||||
virtual ~CMSWindowsScreen();
|
virtual ~CMSWindowsScreen();
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
|
@ -216,6 +216,9 @@ private:
|
||||||
// true if screen is being used as a primary screen, false otherwise
|
// true if screen is being used as a primary screen, false otherwise
|
||||||
bool m_isPrimary;
|
bool m_isPrimary;
|
||||||
|
|
||||||
|
// true if hooks are not to be installed (useful for debugging)
|
||||||
|
bool m_noHooks;
|
||||||
|
|
||||||
// true if windows 95/98/me
|
// true if windows 95/98/me
|
||||||
bool m_is95Family;
|
bool m_is95Family;
|
||||||
|
|
||||||
|
|
|
@ -293,7 +293,7 @@ CServer::adoptClient(CBaseClientProxy* client)
|
||||||
|
|
||||||
// send notification
|
// send notification
|
||||||
CServer::CScreenConnectedInfo* info =
|
CServer::CScreenConnectedInfo* info =
|
||||||
CServer::CScreenConnectedInfo::alloc(getName(client));
|
new CServer::CScreenConnectedInfo(getName(client));
|
||||||
EVENTQUEUE->addEvent(CEvent(CServer::getConnectedEvent(),
|
EVENTQUEUE->addEvent(CEvent(CServer::getConnectedEvent(),
|
||||||
m_primaryClient->getEventTarget(), info));
|
m_primaryClient->getEventTarget(), info));
|
||||||
}
|
}
|
||||||
|
@ -1638,7 +1638,7 @@ CServer::onMouseUp(ButtonID id)
|
||||||
bool
|
bool
|
||||||
CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
|
CServer::onMouseMovePrimary(SInt32 x, SInt32 y)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG2 "onMouseMovePrimary %d,%d", x, y));
|
LOG((CLOG_DEBUG4 "onMouseMovePrimary %d,%d", x, y));
|
||||||
|
|
||||||
// mouse move on primary (server's) screen
|
// mouse move on primary (server's) screen
|
||||||
if (m_active != m_primaryClient) {
|
if (m_active != m_primaryClient) {
|
||||||
|
@ -2133,22 +2133,6 @@ CServer::CSwitchInDirectionInfo::alloc(EDirection direction)
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// CServer::CScreenConnectedInfo
|
|
||||||
//
|
|
||||||
|
|
||||||
CServer::CScreenConnectedInfo*
|
|
||||||
CServer::CScreenConnectedInfo::alloc(const CString& screen)
|
|
||||||
{
|
|
||||||
CScreenConnectedInfo* info =
|
|
||||||
(CScreenConnectedInfo*)malloc(sizeof(CScreenConnectedInfo) +
|
|
||||||
screen.size());
|
|
||||||
strcpy(info->m_screen, screen.c_str());
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CServer::CKeyboardBroadcastInfo
|
// CServer::CKeyboardBroadcastInfo
|
||||||
//
|
//
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
#include "stdset.h"
|
#include "stdset.h"
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
|
#include "INode.h"
|
||||||
|
|
||||||
class CBaseClientProxy;
|
class CBaseClientProxy;
|
||||||
class CEventQueueTimer;
|
class CEventQueueTimer;
|
||||||
|
@ -35,7 +36,7 @@ class CInputFilter;
|
||||||
/*!
|
/*!
|
||||||
This class implements the top-level server algorithms for synergy.
|
This class implements the top-level server algorithms for synergy.
|
||||||
*/
|
*/
|
||||||
class CServer {
|
class CServer : public INode {
|
||||||
public:
|
public:
|
||||||
//! Lock cursor to screen data
|
//! Lock cursor to screen data
|
||||||
class CLockCursorToScreenInfo {
|
class CLockCursorToScreenInfo {
|
||||||
|
@ -70,11 +71,10 @@ public:
|
||||||
//! Screen connected data
|
//! Screen connected data
|
||||||
class CScreenConnectedInfo {
|
class CScreenConnectedInfo {
|
||||||
public:
|
public:
|
||||||
static CScreenConnectedInfo* alloc(const CString& screen);
|
CScreenConnectedInfo(CString screen) : m_screen(screen) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// this is a C-string; this type is a variable size structure
|
CString m_screen; // was char[1]
|
||||||
char m_screen[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Keyboard broadcast data
|
//! Keyboard broadcast data
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CApp.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
#include "Version.h"
|
||||||
|
#include "ProtocolTypes.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XBase.h"
|
||||||
|
#include "XArch.h"
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
CApp* CApp::s_instance = nullptr;
|
||||||
|
|
||||||
|
CApp::CApp(CArgsBase* args) :
|
||||||
|
m_args(args),
|
||||||
|
m_bye(&exit),
|
||||||
|
s_taskBarReceiver(NULL),
|
||||||
|
s_suspended(false)
|
||||||
|
{
|
||||||
|
assert(s_instance == nullptr);
|
||||||
|
s_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CApp::~CApp()
|
||||||
|
{
|
||||||
|
delete m_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
CApp::CArgsBase::CArgsBase() :
|
||||||
|
m_daemon(true),
|
||||||
|
m_backend(false),
|
||||||
|
m_restartable(true),
|
||||||
|
m_noHooks(false),
|
||||||
|
m_pname(NULL),
|
||||||
|
m_logFilter(NULL),
|
||||||
|
m_logFile(NULL),
|
||||||
|
m_display(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CApp::CArgsBase::~CArgsBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CApp::isArg(
|
||||||
|
int argi, int argc, const char* const* argv,
|
||||||
|
const char* name1, const char* name2,
|
||||||
|
int minRequiredParameters)
|
||||||
|
{
|
||||||
|
if ((name1 != NULL && strcmp(argv[argi], name1) == 0) ||
|
||||||
|
(name2 != NULL && strcmp(argv[argi], name2) == 0)) {
|
||||||
|
// match. check args left.
|
||||||
|
if (argi + minRequiredParameters >= argc) {
|
||||||
|
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||||
|
argsBase().m_pname, argv[argi], argsBase().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no match
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CApp::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
if (ARCH->parseArg(argc, argv, i)) {
|
||||||
|
// handled by platform util
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||||
|
// change logging level
|
||||||
|
argsBase().m_logFilter = argv[++i];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-l", "--log", 1)) {
|
||||||
|
argsBase().m_logFile = argv[++i];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||||
|
// not a daemon
|
||||||
|
argsBase().m_daemon = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||||
|
// daemonize
|
||||||
|
argsBase().m_daemon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||||
|
// save screen name
|
||||||
|
argsBase().m_name = argv[++i];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||||
|
// don't try to restart
|
||||||
|
argsBase().m_restartable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||||
|
// try to restart
|
||||||
|
argsBase().m_restartable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||||
|
argsBase().m_backend = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--no-hooks")) {
|
||||||
|
argsBase().m_noHooks = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||||
|
help();
|
||||||
|
m_bye(kExitSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--version")) {
|
||||||
|
version();
|
||||||
|
m_bye(kExitSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// option not supported here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CApp::parseArgs(int argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
// about these use of assert() here:
|
||||||
|
// previously an /analyze warning was displayed if we only used assert and
|
||||||
|
// did not return on failure. however, this warning does not appear to show
|
||||||
|
// any more (could be because new compiler args have been added).
|
||||||
|
// the asserts are programmer benefit only; the os should never pass 0 args,
|
||||||
|
// because the first is always the binary name. the only way assert would
|
||||||
|
// evaluate to true, is if this parse function were implemented incorrectly,
|
||||||
|
// which is unlikely because it's old code and has a specific use.
|
||||||
|
// we should avoid using anything other than assert here, because it will
|
||||||
|
// look like important code, which it's not really.
|
||||||
|
assert(argsBase().m_pname != NULL);
|
||||||
|
assert(argv != NULL);
|
||||||
|
assert(argc >= 1);
|
||||||
|
|
||||||
|
// set defaults
|
||||||
|
argsBase().m_name = ARCH->getHostName();
|
||||||
|
|
||||||
|
// parse options
|
||||||
|
for (i = 1; i < argc; ++i) {
|
||||||
|
|
||||||
|
if (parseArg(argc, argv, i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "--", NULL)) {
|
||||||
|
// remaining arguments are not options
|
||||||
|
++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (argv[i][0] == '-') {
|
||||||
|
std::cerr << "Unrecognized option: " << argv[i] << std::endl;
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// this and remaining arguments are not options
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// increase default filter level for daemon. the user must
|
||||||
|
// explicitly request another level for a daemon.
|
||||||
|
if (argsBase().m_daemon && argsBase().m_logFilter == NULL) {
|
||||||
|
argsBase().m_logFilter = "NOTE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CApp::version()
|
||||||
|
{
|
||||||
|
char buffer[500];
|
||||||
|
sprintf(
|
||||||
|
buffer,
|
||||||
|
"%s %s, protocol version %d.%d\n%s",
|
||||||
|
argsBase().m_pname,
|
||||||
|
kVersion,
|
||||||
|
kProtocolMajorVersion,
|
||||||
|
kProtocolMinorVersion,
|
||||||
|
kCopyright
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << buffer << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CApp::run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver)
|
||||||
|
{
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
// record window instance for tray icon, etc
|
||||||
|
CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CArch arch;
|
||||||
|
|
||||||
|
// install application in to arch
|
||||||
|
ARCH->adoptApp(this);
|
||||||
|
|
||||||
|
// create an instance of log
|
||||||
|
CLOG;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
try {
|
||||||
|
result = ARCH->run(argc, argv, createTaskBarReceiver);
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
|
||||||
|
result = kExitFailed;
|
||||||
|
}
|
||||||
|
catch (XArch& e) {
|
||||||
|
LOG((CLOG_CRIT "Initialization failed: %s" BYE, e.what().c_str(), argsBase().m_pname));
|
||||||
|
result = kExitFailed;
|
||||||
|
}
|
||||||
|
catch (std::exception& e) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: %s\n", e.what()));
|
||||||
|
result = kExitFailed;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
LOG((CLOG_CRIT "Uncaught exception: <unknown exception>\n"));
|
||||||
|
result = kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete CLOG;
|
||||||
|
|
||||||
|
// not sure i like what's going on here; m_bye could call exit, but it also does
|
||||||
|
// some other stuff - if we don't return then we get compiler warning (and it's
|
||||||
|
// not good practice anyway), but the return will never get hit.
|
||||||
|
m_bye(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CApp::daemonMainLoop(int, const char**)
|
||||||
|
{
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
CSystemLogger sysLogger(daemonName(), false);
|
||||||
|
#else
|
||||||
|
CSystemLogger sysLogger(daemonName(), true);
|
||||||
|
#endif
|
||||||
|
return mainLoop();
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
|
class IArchTaskBarReceiver;
|
||||||
|
class CBufferedLogOutputter;
|
||||||
|
class ILogOutputter;
|
||||||
|
|
||||||
|
typedef IArchTaskBarReceiver* (*CreateTaskBarReceiverFunc)(const CBufferedLogOutputter*);
|
||||||
|
typedef int (*StartupFunc)(int, char**);
|
||||||
|
|
||||||
|
class CApp {
|
||||||
|
public:
|
||||||
|
class CArgsBase {
|
||||||
|
public:
|
||||||
|
CArgsBase();
|
||||||
|
virtual ~CArgsBase();
|
||||||
|
bool m_daemon;
|
||||||
|
bool m_backend;
|
||||||
|
bool m_restartable;
|
||||||
|
bool m_noHooks;
|
||||||
|
const char* m_pname;
|
||||||
|
const char* m_logFilter;
|
||||||
|
const char* m_logFile;
|
||||||
|
const char* m_display;
|
||||||
|
CString m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
CApp(CArgsBase* args);
|
||||||
|
virtual ~CApp();
|
||||||
|
|
||||||
|
// Returns args that are common between server and client.
|
||||||
|
CArgsBase& argsBase() const { return *m_args; }
|
||||||
|
|
||||||
|
// Prints the current compiled version.
|
||||||
|
virtual void version();
|
||||||
|
|
||||||
|
// Prints help specific to client or server.
|
||||||
|
virtual void help() = 0;
|
||||||
|
|
||||||
|
// Parse command line arguments.
|
||||||
|
virtual void parseArgs(int argc, const char* const* argv) = 0;
|
||||||
|
|
||||||
|
int run(int argc, char** argv, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||||
|
|
||||||
|
int daemonMainLoop(int, const char**);
|
||||||
|
|
||||||
|
virtual void loadConfig() = 0;
|
||||||
|
virtual bool loadConfig(const CString& pathname) = 0;
|
||||||
|
virtual int mainLoop() = 0;
|
||||||
|
virtual int foregroundStartup(int argc, char** argv) = 0;
|
||||||
|
virtual int standardStartup(int argc, char** argv) = 0;
|
||||||
|
virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup, CreateTaskBarReceiverFunc createTaskBarReceiver) = 0;
|
||||||
|
|
||||||
|
// Name of the daemon (used for Unix and Windows).
|
||||||
|
virtual const char* daemonName() const = 0;
|
||||||
|
|
||||||
|
// A description of the daemon (used only on Windows).
|
||||||
|
virtual const char* daemonInfo() const = 0;
|
||||||
|
|
||||||
|
// Function pointer for function to exit immediately.
|
||||||
|
// TODO: this is old C code - use inheritance to normalize
|
||||||
|
void (*m_bye)(int);
|
||||||
|
|
||||||
|
// Returns true if argv[argi] is equal to name1 or name2.
|
||||||
|
bool isArg(int argi, int argc, const char* const* argv,
|
||||||
|
const char* name1, const char* name2,
|
||||||
|
int minRequiredParameters = 0);
|
||||||
|
|
||||||
|
static CApp& instance() { assert(s_instance != nullptr); return *s_instance; }
|
||||||
|
|
||||||
|
bool s_suspended;
|
||||||
|
IArchTaskBarReceiver* s_taskBarReceiver;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void parseArgs(int argc, const char* const* argv, int &i);
|
||||||
|
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CArgsBase* m_args;
|
||||||
|
static CApp* s_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BYE "\nTry `%s --help' for more information."
|
||||||
|
|
||||||
|
#if WINAPI_MSWINDOWS
|
||||||
|
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||||
|
#else
|
||||||
|
#define DAEMON_RUNNING(running_)
|
||||||
|
#endif
|
|
@ -0,0 +1,616 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CClientApp.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XSocket.h"
|
||||||
|
#include "Version.h"
|
||||||
|
#include "ProtocolTypes.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "CScreen.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
#include "CClient.h"
|
||||||
|
#include "CNetworkAddress.h"
|
||||||
|
#include "IArchTaskBarReceiver.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
|
#include "TMethodEventJob.h"
|
||||||
|
#include "CTCPSocketFactory.h"
|
||||||
|
#include "XScreen.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
|
#include "CSocketMultiplexer.h"
|
||||||
|
#include "CEventQueue.h"
|
||||||
|
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WINAPI_MSWINDOWS
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
|
#elif WINAPI_XWINDOWS
|
||||||
|
#include "CXWindowsScreen.h"
|
||||||
|
#elif WINAPI_CARBON
|
||||||
|
#include "COSXScreen.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define RETRY_TIME 1.0
|
||||||
|
|
||||||
|
CClientApp::CClientApp() :
|
||||||
|
CApp(new CArgs()),
|
||||||
|
s_client(NULL),
|
||||||
|
s_clientScreen(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientApp::~CClientApp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientApp::CArgs::CArgs() :
|
||||||
|
m_yscroll(0),
|
||||||
|
m_serverAddress(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientApp::CArgs::~CArgs()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CClientApp::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
if (CApp::parseArg(argc, argv, i)) {
|
||||||
|
// found common arg
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
||||||
|
// ignore -- included for backwards compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
||||||
|
// ignore -- included for backwards compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) {
|
||||||
|
// define scroll
|
||||||
|
args().m_yscroll = atoi(argv[++i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// option not supported here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// argument was valid
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::parseArgs(int argc, const char* const* argv)
|
||||||
|
{
|
||||||
|
// asserts values, sets defaults, and parses args
|
||||||
|
int i;
|
||||||
|
CApp::parseArgs(argc, argv, i);
|
||||||
|
|
||||||
|
// exactly one non-option argument (server-address)
|
||||||
|
if (i == argc) {
|
||||||
|
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
||||||
|
args().m_pname, args().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
if (i + 1 != argc) {
|
||||||
|
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||||
|
args().m_pname, argv[i], args().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save server address
|
||||||
|
try {
|
||||||
|
*args().m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
||||||
|
args().m_serverAddress->resolve();
|
||||||
|
}
|
||||||
|
catch (XSocketAddress& e) {
|
||||||
|
// allow an address that we can't look up if we're restartable.
|
||||||
|
// we'll try to resolve the address each time we connect to the
|
||||||
|
// server. a bad port will never get better. patch by Brent
|
||||||
|
// Priddy.
|
||||||
|
if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) {
|
||||||
|
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||||
|
args().m_pname, e.what(), args().m_pname));
|
||||||
|
m_bye(kExitFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set log filter
|
||||||
|
if (!CLOG->setFilter(args().m_logFilter)) {
|
||||||
|
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||||
|
args().m_pname, args().m_logFilter, args().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// identify system
|
||||||
|
LOG((CLOG_INFO "%s Client on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str()));
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#ifdef _AMD64_
|
||||||
|
LOG((CLOG_WARN "This is an experimental x64 build of %s. Use it at your own risk.", kApplication));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (CLOG->getFilter() > CLOG->getConsoleMaxLevel()) {
|
||||||
|
if (args().m_logFile == NULL) {
|
||||||
|
LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)",
|
||||||
|
CLOG->getFilterName(CLOG->getConsoleMaxLevel())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::help()
|
||||||
|
{
|
||||||
|
#if WINAPI_XWINDOWS
|
||||||
|
# define USAGE_DISPLAY_ARG \
|
||||||
|
" [--display <display>]"
|
||||||
|
# define USAGE_DISPLAY_INFO \
|
||||||
|
" --display <display> connect to the X server at <display>\n"
|
||||||
|
#else
|
||||||
|
# define USAGE_DISPLAY_ARG
|
||||||
|
# define USAGE_DISPLAY_INFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char buffer[2000];
|
||||||
|
sprintf(
|
||||||
|
buffer,
|
||||||
|
"Usage: %s"
|
||||||
|
" [--daemon|--no-daemon]"
|
||||||
|
" [--debug <level>]"
|
||||||
|
USAGE_DISPLAY_ARG
|
||||||
|
" [--name <screen-name>]"
|
||||||
|
" [--yscroll <delta>]"
|
||||||
|
" [--restart|--no-restart]"
|
||||||
|
" <server-address>"
|
||||||
|
"\n\n"
|
||||||
|
"Start the synergy mouse/keyboard sharing server.\n"
|
||||||
|
"\n"
|
||||||
|
" -d, --debug <level> filter out log messages with priorty below level.\n"
|
||||||
|
" level may be: FATAL, ERROR, WARNING, NOTE, INFO,\n"
|
||||||
|
" DEBUG, DEBUG1, DEBUG2.\n"
|
||||||
|
USAGE_DISPLAY_INFO
|
||||||
|
" -f, --no-daemon run the client in the foreground.\n"
|
||||||
|
"* --daemon run the client as a daemon.\n"
|
||||||
|
" -n, --name <screen-name> use screen-name instead the hostname to identify\n"
|
||||||
|
" ourself to the server.\n"
|
||||||
|
" --yscroll <delta> defines the vertical scrolling delta, which is\n"
|
||||||
|
" 120 by default.\n"
|
||||||
|
" -1, --no-restart do not try to restart the client if it fails for\n"
|
||||||
|
" some reason.\n"
|
||||||
|
"* --restart restart the client automatically if it fails.\n"
|
||||||
|
" -l --log <file> write log messages to file.\n"
|
||||||
|
" -h, --help display this help and exit.\n"
|
||||||
|
" --version display version information and exit.\n"
|
||||||
|
"\n"
|
||||||
|
"* marks defaults.\n"
|
||||||
|
"\n"
|
||||||
|
"The server address is of the form: [<hostname>][:<port>]. The hostname\n"
|
||||||
|
"must be the address or hostname of the server. The port overrides the\n"
|
||||||
|
"default port, %d.\n"
|
||||||
|
"\n"
|
||||||
|
"Where log messages go depends on the platform and whether or not the\n"
|
||||||
|
"client is running as a daemon.",
|
||||||
|
args().m_pname, kDefaultPort
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << buffer << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CClientApp::daemonName() const
|
||||||
|
{
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
return "Synergy+ Client";
|
||||||
|
#elif SYSAPI_UNIX
|
||||||
|
return "synergyc";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CClientApp::daemonInfo() const
|
||||||
|
{
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
return "Allows another computer to share it's keyboard and mouse with this computer.";
|
||||||
|
#elif SYSAPI_UNIX
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CScreen*
|
||||||
|
CClientApp::createScreen()
|
||||||
|
{
|
||||||
|
#if WINAPI_MSWINDOWS
|
||||||
|
return new CScreen(new CMSWindowsScreen(false, args().m_noHooks));
|
||||||
|
#elif WINAPI_XWINDOWS
|
||||||
|
return new CScreen(new CXWindowsScreen(args().m_display, false, args().m_yscroll));
|
||||||
|
#elif WINAPI_CARBON
|
||||||
|
return new CScreen(new COSXScreen(false));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::updateStatus()
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_client, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::updateStatus(const CString& msg)
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_client, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::resetRestartTimeout()
|
||||||
|
{
|
||||||
|
// retry time can nolonger be changed
|
||||||
|
//s_retryTime = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
CClientApp::nextRestartTimeout()
|
||||||
|
{
|
||||||
|
// retry at a constant rate (Issue 52)
|
||||||
|
return RETRY_TIME;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// choose next restart timeout. we start with rapid retries
|
||||||
|
// then slow down.
|
||||||
|
if (s_retryTime < 1.0) {
|
||||||
|
s_retryTime = 1.0;
|
||||||
|
}
|
||||||
|
else if (s_retryTime < 3.0) {
|
||||||
|
s_retryTime = 3.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_retryTime = 5.0;
|
||||||
|
}
|
||||||
|
return s_retryTime;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::handleScreenError(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_CRIT "error on screen"));
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CScreen*
|
||||||
|
CClientApp::openClientScreen()
|
||||||
|
{
|
||||||
|
CScreen* screen = createScreen();
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientApp>(
|
||||||
|
this, &CClientApp::handleScreenError));
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::closeClientScreen(CScreen* screen)
|
||||||
|
{
|
||||||
|
if (screen != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget());
|
||||||
|
delete screen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::handleClientRestart(const CEvent&, void* vtimer)
|
||||||
|
{
|
||||||
|
// discard old timer
|
||||||
|
CEventQueueTimer* timer = reinterpret_cast<CEventQueueTimer*>(vtimer);
|
||||||
|
EVENTQUEUE->deleteTimer(timer);
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
|
||||||
|
|
||||||
|
// reconnect
|
||||||
|
startClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::scheduleClientRestart(double retryTime)
|
||||||
|
{
|
||||||
|
// install a timer and handler to retry later
|
||||||
|
LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
|
||||||
|
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
||||||
|
new TMethodEventJob<CClientApp>(this, &CClientApp::handleClientRestart, timer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::handleClientConnected(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_NOTE "connected to server"));
|
||||||
|
resetRestartTimeout();
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::handleClientFailed(const CEvent& e, void*)
|
||||||
|
{
|
||||||
|
CClient::CFailInfo* info =
|
||||||
|
reinterpret_cast<CClient::CFailInfo*>(e.getData());
|
||||||
|
|
||||||
|
updateStatus(CString("Failed to connect to server: ") + info->m_what);
|
||||||
|
if (!args().m_restartable || !info->m_retry) {
|
||||||
|
LOG((CLOG_ERR "failed to connect to server: %s", info->m_what.c_str()));
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((CLOG_WARN "failed to connect to server: %s", info->m_what.c_str()));
|
||||||
|
if (!s_suspended) {
|
||||||
|
scheduleClientRestart(nextRestartTimeout());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::handleClientDisconnected(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_NOTE "disconnected from server"));
|
||||||
|
if (!args().m_restartable) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
else if (!s_suspended) {
|
||||||
|
s_client->connect();
|
||||||
|
}
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CClient*
|
||||||
|
CClientApp::openClient(const CString& name, const CNetworkAddress& address, CScreen* screen)
|
||||||
|
{
|
||||||
|
CClient* client = new CClient(
|
||||||
|
name, address, new CTCPSocketFactory, NULL, screen);
|
||||||
|
|
||||||
|
try {
|
||||||
|
EVENTQUEUE->adoptHandler(
|
||||||
|
CClient::getConnectedEvent(),
|
||||||
|
client->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientApp>(this, &CClientApp::handleClientConnected));
|
||||||
|
|
||||||
|
EVENTQUEUE->adoptHandler(
|
||||||
|
CClient::getConnectionFailedEvent(),
|
||||||
|
client->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientApp>(this, &CClientApp::handleClientFailed));
|
||||||
|
|
||||||
|
EVENTQUEUE->adoptHandler(
|
||||||
|
CClient::getDisconnectedEvent(),
|
||||||
|
client->getEventTarget(),
|
||||||
|
new TMethodEventJob<CClientApp>(this, &CClientApp::handleClientDisconnected));
|
||||||
|
|
||||||
|
} catch (std::bad_alloc &ba) {
|
||||||
|
delete client;
|
||||||
|
throw ba;
|
||||||
|
}
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::closeClient(CClient* client)
|
||||||
|
{
|
||||||
|
if (client == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVENTQUEUE->removeHandler(CClient::getConnectedEvent(), client);
|
||||||
|
EVENTQUEUE->removeHandler(CClient::getConnectionFailedEvent(), client);
|
||||||
|
EVENTQUEUE->removeHandler(CClient::getDisconnectedEvent(), client);
|
||||||
|
delete client;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CClientApp::foregroundStartup(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// parse command line
|
||||||
|
parseArgs(argc, argv);
|
||||||
|
|
||||||
|
// never daemonize
|
||||||
|
return mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CClientApp::startClient()
|
||||||
|
{
|
||||||
|
double retryTime;
|
||||||
|
CScreen* clientScreen = NULL;
|
||||||
|
try {
|
||||||
|
if (s_clientScreen == NULL) {
|
||||||
|
clientScreen = openClientScreen();
|
||||||
|
s_client = openClient(args().m_name,
|
||||||
|
*args().m_serverAddress, clientScreen);
|
||||||
|
s_clientScreen = clientScreen;
|
||||||
|
LOG((CLOG_NOTE "started client"));
|
||||||
|
}
|
||||||
|
s_client->connect();
|
||||||
|
updateStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XScreenUnavailable& e) {
|
||||||
|
LOG((CLOG_WARN "cannot open secondary screen: %s", e.what()));
|
||||||
|
closeClientScreen(clientScreen);
|
||||||
|
updateStatus(CString("Cannot open secondary screen: ") + e.what());
|
||||||
|
retryTime = e.getRetryTime();
|
||||||
|
}
|
||||||
|
catch (XScreenOpenFailure& e) {
|
||||||
|
LOG((CLOG_CRIT "cannot open secondary screen: %s", e.what()));
|
||||||
|
closeClientScreen(clientScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start client: %s", e.what()));
|
||||||
|
closeClientScreen(clientScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args().m_restartable) {
|
||||||
|
scheduleClientRestart(retryTime);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// don't try again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientApp::stopClient()
|
||||||
|
{
|
||||||
|
closeClient(s_client);
|
||||||
|
closeClientScreen(s_clientScreen);
|
||||||
|
s_client = NULL;
|
||||||
|
s_clientScreen = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
CClientApp::mainLoop()
|
||||||
|
{
|
||||||
|
// logging to files
|
||||||
|
CFileLogOutputter* fileLog = NULL;
|
||||||
|
|
||||||
|
if (args().m_logFile != NULL) {
|
||||||
|
fileLog = new CFileLogOutputter(args().m_logFile);
|
||||||
|
|
||||||
|
CLOG->insert(fileLog);
|
||||||
|
|
||||||
|
LOG((CLOG_DEBUG1 "Logging to file (%s) enabled", args().m_logFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create socket multiplexer. this must happen after daemonization
|
||||||
|
// on unix because threads evaporate across a fork().
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
|
||||||
|
// create the event queue
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
|
||||||
|
// start the client. if this return false then we've failed and
|
||||||
|
// we shouldn't retry.
|
||||||
|
LOG((CLOG_DEBUG1 "starting client"));
|
||||||
|
if (!startClient()) {
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run event loop. if startClient() failed we're supposed to retry
|
||||||
|
// later. the timer installed by startClient() will take care of
|
||||||
|
// that.
|
||||||
|
CEvent event;
|
||||||
|
DAEMON_RUNNING(true);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
while (event.getType() != CEvent::kQuit) {
|
||||||
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
CEvent::deleteData(event);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
}
|
||||||
|
DAEMON_RUNNING(false);
|
||||||
|
|
||||||
|
// close down
|
||||||
|
LOG((CLOG_DEBUG1 "stopping client"));
|
||||||
|
stopClient();
|
||||||
|
updateStatus();
|
||||||
|
LOG((CLOG_NOTE "stopped client"));
|
||||||
|
|
||||||
|
if (fileLog) {
|
||||||
|
CLOG->remove(fileLog);
|
||||||
|
delete fileLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kExitSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
daemonMainLoopStatic(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
return CClientApp::instance().daemonMainLoop(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CClientApp::standardStartup(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (!args().m_daemon) {
|
||||||
|
ARCH->showConsole(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse command line
|
||||||
|
parseArgs(argc, argv);
|
||||||
|
|
||||||
|
// daemonize if requested
|
||||||
|
if (args().m_daemon) {
|
||||||
|
return ARCH->daemonize(daemonName(), &daemonMainLoopStatic);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return mainLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup, CreateTaskBarReceiverFunc createTaskBarReceiver)
|
||||||
|
{
|
||||||
|
// general initialization
|
||||||
|
args().m_serverAddress = new CNetworkAddress;
|
||||||
|
args().m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
|
// install caller's output filter
|
||||||
|
if (outputter != NULL) {
|
||||||
|
CLOG->insert(outputter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save log messages
|
||||||
|
// use heap memory because CLog deletes outputters on destruction
|
||||||
|
CBufferedLogOutputter* logBuffer = new CBufferedLogOutputter(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;
|
||||||
|
|
||||||
|
delete args().m_serverAddress;
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CApp.h"
|
||||||
|
|
||||||
|
class CScreen;
|
||||||
|
class CEvent;
|
||||||
|
class CClient;
|
||||||
|
class CNetworkAddress;
|
||||||
|
|
||||||
|
class CClientApp : public CApp {
|
||||||
|
public:
|
||||||
|
class CArgs : public CApp::CArgsBase {
|
||||||
|
public:
|
||||||
|
CArgs();
|
||||||
|
~CArgs();
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_yscroll;
|
||||||
|
CNetworkAddress* m_serverAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
CClientApp();
|
||||||
|
virtual ~CClientApp();
|
||||||
|
|
||||||
|
// Parse client specific command line arguments.
|
||||||
|
void parseArgs(int argc, const char* const* argv);
|
||||||
|
|
||||||
|
// Prints help specific to client.
|
||||||
|
void help();
|
||||||
|
|
||||||
|
// Returns arguments that are common and for client.
|
||||||
|
CArgs& args() const { return (CArgs&)argsBase(); }
|
||||||
|
|
||||||
|
const char* daemonName() const;
|
||||||
|
const char* daemonInfo() const;
|
||||||
|
|
||||||
|
// TODO: move to server only (not supported on client)
|
||||||
|
void loadConfig() { }
|
||||||
|
bool loadConfig(const CString& pathname) { return false; }
|
||||||
|
|
||||||
|
int foregroundStartup(int argc, char** argv);
|
||||||
|
int standardStartup(int argc, char** argv);
|
||||||
|
int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||||
|
CScreen* createScreen();
|
||||||
|
void updateStatus();
|
||||||
|
void updateStatus(const CString& msg);
|
||||||
|
void resetRestartTimeout();
|
||||||
|
double nextRestartTimeout();
|
||||||
|
void handleScreenError(const CEvent&, void*);
|
||||||
|
CScreen* openClientScreen();
|
||||||
|
void closeClientScreen(CScreen* screen);
|
||||||
|
void handleClientRestart(const CEvent&, void* vtimer);
|
||||||
|
void scheduleClientRestart(double retryTime);
|
||||||
|
void handleClientConnected(const CEvent&, void*);
|
||||||
|
void handleClientFailed(const CEvent& e, void*);
|
||||||
|
void handleClientDisconnected(const CEvent&, void*);
|
||||||
|
CClient* openClient(const CString& name, const CNetworkAddress& address, CScreen* screen);
|
||||||
|
void closeClient(CClient* client);
|
||||||
|
bool startClient();
|
||||||
|
void stopClient();
|
||||||
|
int mainLoop();
|
||||||
|
|
||||||
|
static CClientApp& instance() { return (CClientApp&)CApp::instance(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CClient* s_client;
|
||||||
|
CScreen* s_clientScreen;
|
||||||
|
|
||||||
|
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
};
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "IArchTaskBarReceiver.h"
|
#include "IArchTaskBarReceiver.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
class CClient;
|
#include "CClient.h"
|
||||||
|
|
||||||
//! Implementation of IArchTaskBarReceiver for the synergy server
|
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||||
class CClientTaskBarReceiver : public IArchTaskBarReceiver {
|
class CClientTaskBarReceiver : public IArchTaskBarReceiver {
|
||||||
|
@ -35,6 +35,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void updateStatus(CClient*, const CString& errorMsg);
|
void updateStatus(CClient*, const CString& errorMsg);
|
||||||
|
|
||||||
|
void updateStatus(INode* n, const CString& errorMsg) { updateStatus((CClient*)n, errorMsg); }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IArchTaskBarReceiver overrides
|
// IArchTaskBarReceiver overrides
|
||||||
|
@ -80,4 +82,6 @@ private:
|
||||||
CString m_server;
|
CString m_server;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IArchTaskBarReceiver* createTaskBarReceiver(const CBufferedLogOutputter* logBuffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -98,7 +98,7 @@ CKeyMap::addKeyEntry(const KeyItem& item)
|
||||||
|
|
||||||
// add item list
|
// add item list
|
||||||
entries.push_back(items);
|
entries.push_back(items);
|
||||||
LOG((CLOG_DEBUG1 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : ""));
|
LOG((CLOG_DEBUG3 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -0,0 +1,969 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CServerApp.h"
|
||||||
|
#include "CLog.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "XSocket.h"
|
||||||
|
#include "Version.h"
|
||||||
|
#include "IEventQueue.h"
|
||||||
|
#include "CServer.h"
|
||||||
|
#include "CClientListener.h"
|
||||||
|
#include "CClientProxy.h"
|
||||||
|
#include "TMethodEventJob.h"
|
||||||
|
#include "CServerTaskBarReceiver.h"
|
||||||
|
#include "CPrimaryClient.h"
|
||||||
|
#include "CScreen.h"
|
||||||
|
#include "CSocketMultiplexer.h"
|
||||||
|
#include "CEventQueue.h"
|
||||||
|
#include "LogOutputters.h"
|
||||||
|
#include "CFunctionEventJob.h"
|
||||||
|
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
#include "CArchMiscWindows.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WINAPI_MSWINDOWS
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
|
#elif WINAPI_XWINDOWS
|
||||||
|
#include "CXWindowsScreen.h"
|
||||||
|
#elif WINAPI_CARBON
|
||||||
|
#include "COSXScreen.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include "XScreen.h"
|
||||||
|
#include "CTCPSocketFactory.h"
|
||||||
|
|
||||||
|
CEvent::Type CServerApp::s_reloadConfigEvent = CEvent::kUnknown;
|
||||||
|
|
||||||
|
CServerApp::CServerApp() :
|
||||||
|
CApp(new CArgs()),
|
||||||
|
s_server(NULL),
|
||||||
|
s_forceReconnectEvent(CEvent::kUnknown),
|
||||||
|
s_resetServerEvent(CEvent::kUnknown),
|
||||||
|
s_serverState(kUninitialized),
|
||||||
|
s_serverScreen(NULL),
|
||||||
|
s_primaryClient(NULL),
|
||||||
|
s_listener(NULL),
|
||||||
|
s_timer(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerApp::~CServerApp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerApp::CArgs::CArgs() :
|
||||||
|
m_synergyAddress(NULL),
|
||||||
|
m_config(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerApp::CArgs::~CArgs()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CServerApp::parseArg(const int& argc, const char* const* argv, int& i)
|
||||||
|
{
|
||||||
|
if (CApp::parseArg(argc, argv, i)) {
|
||||||
|
// found common arg
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
||||||
|
// save listen address
|
||||||
|
try {
|
||||||
|
*args().m_synergyAddress = CNetworkAddress(argv[i + 1],
|
||||||
|
kDefaultPort);
|
||||||
|
args().m_synergyAddress->resolve();
|
||||||
|
}
|
||||||
|
catch (XSocketAddress& e) {
|
||||||
|
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||||
|
args().m_pname, e.what(), args().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
||||||
|
// save configuration file path
|
||||||
|
args().m_configFile = argv[++i];
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
// option not supported here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// argument was valid
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::parseArgs(int argc, const char* const* argv)
|
||||||
|
{
|
||||||
|
// asserts values, sets defaults, and parses args
|
||||||
|
int i;
|
||||||
|
CApp::parseArgs(argc, argv, i);
|
||||||
|
|
||||||
|
// no non-option arguments are allowed
|
||||||
|
if (i != argc) {
|
||||||
|
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||||
|
args().m_pname, argv[i], args().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
// if user wants to run as daemon, but process not launched from service launcher...
|
||||||
|
if (args().m_daemon && !CArchMiscWindows::wasLaunchedAsService()) {
|
||||||
|
LOG((CLOG_ERR "cannot launch as daemon if process not started through "
|
||||||
|
"service host (use '--service start' argument instead)"));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// set log filter
|
||||||
|
if (!CLOG->setFilter(args().m_logFilter)) {
|
||||||
|
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||||
|
args().m_pname, args().m_logFilter, args().m_pname));
|
||||||
|
m_bye(kExitArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// identify system
|
||||||
|
LOG((CLOG_INFO "%s Server on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str()));
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#ifdef _AMD64_
|
||||||
|
LOG((CLOG_WARN "This is an experimental x64 build of %s. Use it at your own risk.", kApplication));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (CLOG->getFilter() > CLOG->getConsoleMaxLevel()) {
|
||||||
|
if (args().m_logFile == NULL) {
|
||||||
|
LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)",
|
||||||
|
CLOG->getFilterName(CLOG->getConsoleMaxLevel())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::help()
|
||||||
|
{
|
||||||
|
#if WINAPI_XWINDOWS
|
||||||
|
# define USAGE_DISPLAY_ARG \
|
||||||
|
" [--display <display>]"
|
||||||
|
# define USAGE_DISPLAY_INFO \
|
||||||
|
" --display <display> connect to the X server at <display>\n"
|
||||||
|
#else
|
||||||
|
# define USAGE_DISPLAY_ARG
|
||||||
|
# define USAGE_DISPLAY_INFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
|
||||||
|
# define PLATFORM_ARGS \
|
||||||
|
" [--daemon|--no-daemon]"
|
||||||
|
# define PLATFORM_DESC
|
||||||
|
# define PLATFORM_EXTRA \
|
||||||
|
"At least one command line argument is required. If you don't otherwise\n" \
|
||||||
|
"need an argument use `--daemon'.\n" \
|
||||||
|
"\n"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# define PLATFORM_ARGS \
|
||||||
|
" [--daemon|--no-daemon]"
|
||||||
|
# define PLATFORM_DESC
|
||||||
|
# define PLATFORM_EXTRA
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char buffer[2000];
|
||||||
|
sprintf(
|
||||||
|
buffer,
|
||||||
|
"Usage: %s"
|
||||||
|
" [--address <address>]"
|
||||||
|
" [--config <pathname>]"
|
||||||
|
" [--debug <level>]"
|
||||||
|
USAGE_DISPLAY_ARG
|
||||||
|
" [--name <screen-name>]"
|
||||||
|
" [--restart|--no-restart]"
|
||||||
|
PLATFORM_ARGS
|
||||||
|
"\n\n"
|
||||||
|
"Start the synergy mouse/keyboard sharing server.\n"
|
||||||
|
"\n"
|
||||||
|
" -a, --address <address> listen for clients on the given address.\n"
|
||||||
|
" -c, --config <pathname> use the named configuration file instead.\n"
|
||||||
|
" -d, --debug <level> filter out log messages with priorty below level.\n"
|
||||||
|
" level may be: FATAL, ERROR, WARNING, NOTE, INFO,\n"
|
||||||
|
" DEBUG, DEBUG1, DEBUG2.\n"
|
||||||
|
USAGE_DISPLAY_INFO
|
||||||
|
" -f, --no-daemon run the server in the foreground.\n"
|
||||||
|
"* --daemon run the server as a daemon.\n"
|
||||||
|
" -n, --name <screen-name> use screen-name instead the hostname to identify\n"
|
||||||
|
" this screen in the configuration.\n"
|
||||||
|
" -1, --no-restart do not try to restart the server if it fails for\n"
|
||||||
|
" some reason.\n"
|
||||||
|
"* --restart restart the server automatically if it fails.\n"
|
||||||
|
" -l --log <file> write log messages to file.\n"
|
||||||
|
PLATFORM_DESC
|
||||||
|
" -h, --help display this help and exit.\n"
|
||||||
|
" --version display version information and exit.\n"
|
||||||
|
"\n"
|
||||||
|
"* marks defaults.\n"
|
||||||
|
"\n"
|
||||||
|
PLATFORM_EXTRA
|
||||||
|
"The argument for --address is of the form: [<hostname>][:<port>]. The\n"
|
||||||
|
"hostname must be the address or hostname of an interface on the system.\n"
|
||||||
|
"The default is to listen on all interfaces. The port overrides the\n"
|
||||||
|
"default port, %d.\n"
|
||||||
|
"\n"
|
||||||
|
"If no configuration file pathname is provided then the first of the\n"
|
||||||
|
"following to load successfully sets the configuration:\n"
|
||||||
|
" %s\n"
|
||||||
|
" %s\n"
|
||||||
|
"If no configuration file can be loaded then the configuration uses its\n"
|
||||||
|
"defaults with just the server screen.\n"
|
||||||
|
"\n"
|
||||||
|
"Where log messages go depends on the platform and whether or not the\n"
|
||||||
|
"server is running as a daemon.",
|
||||||
|
args().m_pname, kDefaultPort,
|
||||||
|
ARCH->concatPath(ARCH->getUserDirectory(), USR_CONFIG_NAME).c_str(),
|
||||||
|
ARCH->concatPath(ARCH->getSystemDirectory(), SYS_CONFIG_NAME).c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << buffer << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::reloadSignalHandler(CArch::ESignal, void*)
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(getReloadConfigEvent(),
|
||||||
|
IEventQueue::getSystemTarget()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::reloadConfig(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG "reload configuration"));
|
||||||
|
if (loadConfig(args().m_configFile)) {
|
||||||
|
if (s_server != NULL) {
|
||||||
|
s_server->setConfig(*args().m_config);
|
||||||
|
}
|
||||||
|
LOG((CLOG_NOTE "reloaded configuration"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::loadConfig()
|
||||||
|
{
|
||||||
|
bool loaded = false;
|
||||||
|
|
||||||
|
// load the config file, if specified
|
||||||
|
if (!args().m_configFile.empty()) {
|
||||||
|
loaded = loadConfig(args().m_configFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the default configuration if no explicit file given
|
||||||
|
else {
|
||||||
|
// get the user's home directory
|
||||||
|
CString path = ARCH->getUserDirectory();
|
||||||
|
if (!path.empty()) {
|
||||||
|
// complete path
|
||||||
|
path = ARCH->concatPath(path, USR_CONFIG_NAME);
|
||||||
|
|
||||||
|
// now try loading the user's configuration
|
||||||
|
if (loadConfig(path)) {
|
||||||
|
loaded = true;
|
||||||
|
args().m_configFile = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loaded) {
|
||||||
|
// try the system-wide config file
|
||||||
|
path = ARCH->getSystemDirectory();
|
||||||
|
if (!path.empty()) {
|
||||||
|
path = ARCH->concatPath(path, SYS_CONFIG_NAME);
|
||||||
|
if (loadConfig(path)) {
|
||||||
|
loaded = true;
|
||||||
|
args().m_configFile = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
LOG((CLOG_PRINT "%s: no configuration available", args().m_pname));
|
||||||
|
m_bye(kExitConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CServerApp::loadConfig(const CString& pathname)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// load configuration
|
||||||
|
LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str()));
|
||||||
|
std::ifstream configStream(pathname.c_str());
|
||||||
|
if (!configStream.is_open()) {
|
||||||
|
// report failure to open configuration as a debug message
|
||||||
|
// since we try several paths and we expect some to be
|
||||||
|
// missing.
|
||||||
|
LOG((CLOG_DEBUG "cannot open configuration \"%s\"",
|
||||||
|
pathname.c_str()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
configStream >> *args().m_config;
|
||||||
|
LOG((CLOG_DEBUG "configuration read successfully"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XConfigRead& e) {
|
||||||
|
// report error in configuration file
|
||||||
|
LOG((CLOG_ERR "cannot read configuration \"%s\": %s",
|
||||||
|
pathname.c_str(), e.what()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CServerApp::getReloadConfigEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_reloadConfigEvent, "reloadConfig");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::forceReconnect(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
if (s_server != NULL) {
|
||||||
|
s_server->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CServerApp::getForceReconnectEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_forceReconnectEvent, "forceReconnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CServerApp::getResetServerEvent()
|
||||||
|
{
|
||||||
|
return CEvent::registerTypeOnce(s_resetServerEvent, "resetServer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::handleClientConnected(const CEvent&, void* vlistener)
|
||||||
|
{
|
||||||
|
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
|
||||||
|
CClientProxy* client = listener->getNextClient();
|
||||||
|
if (client != NULL) {
|
||||||
|
s_server->adoptClient(client);
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::handleClientsDisconnected(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::closeServer(CServer* server)
|
||||||
|
{
|
||||||
|
if (server == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell all clients to disconnect
|
||||||
|
server->disconnect();
|
||||||
|
|
||||||
|
// wait for clients to disconnect for up to timeout seconds
|
||||||
|
double timeout = 3.0;
|
||||||
|
CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(timeout, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::handleClientsDisconnected));
|
||||||
|
EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::handleClientsDisconnected));
|
||||||
|
CEvent event;
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
while (event.getType() != CEvent::kQuit) {
|
||||||
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
CEvent::deleteData(event);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
}
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
|
||||||
|
EVENTQUEUE->deleteTimer(timer);
|
||||||
|
EVENTQUEUE->removeHandler(CServer::getDisconnectedEvent(), server);
|
||||||
|
|
||||||
|
// done with server
|
||||||
|
delete server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::stopRetryTimer()
|
||||||
|
{
|
||||||
|
if (s_timer != NULL) {
|
||||||
|
EVENTQUEUE->deleteTimer(s_timer);
|
||||||
|
EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
|
||||||
|
s_timer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::updateStatus()
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_server, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerApp::updateStatus( const CString& msg )
|
||||||
|
{
|
||||||
|
s_taskBarReceiver->updateStatus(s_server, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::closeClientListener(CClientListener* listen)
|
||||||
|
{
|
||||||
|
if (listen != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(CClientListener::getConnectedEvent(), listen);
|
||||||
|
delete listen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::stopServer()
|
||||||
|
{
|
||||||
|
if (s_serverState == kStarted) {
|
||||||
|
closeClientListener(s_listener);
|
||||||
|
closeServer(s_server);
|
||||||
|
s_server = NULL;
|
||||||
|
s_listener = NULL;
|
||||||
|
s_serverState = kInitialized;
|
||||||
|
}
|
||||||
|
else if (s_serverState == kStarting) {
|
||||||
|
stopRetryTimer();
|
||||||
|
s_serverState = kInitialized;
|
||||||
|
}
|
||||||
|
assert(s_server == NULL);
|
||||||
|
assert(s_listener == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::closePrimaryClient(CPrimaryClient* primaryClient)
|
||||||
|
{
|
||||||
|
delete primaryClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::closeServerScreen(CScreen* screen)
|
||||||
|
{
|
||||||
|
if (screen != NULL) {
|
||||||
|
EVENTQUEUE->removeHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget());
|
||||||
|
EVENTQUEUE->removeHandler(IScreen::getSuspendEvent(),
|
||||||
|
screen->getEventTarget());
|
||||||
|
EVENTQUEUE->removeHandler(IScreen::getResumeEvent(),
|
||||||
|
screen->getEventTarget());
|
||||||
|
delete screen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerApp::cleanupServer()
|
||||||
|
{
|
||||||
|
stopServer();
|
||||||
|
if (s_serverState == kInitialized) {
|
||||||
|
closePrimaryClient(s_primaryClient);
|
||||||
|
closeServerScreen(s_serverScreen);
|
||||||
|
s_primaryClient = NULL;
|
||||||
|
s_serverScreen = NULL;
|
||||||
|
s_serverState = kUninitialized;
|
||||||
|
}
|
||||||
|
else if (s_serverState == kInitializing ||
|
||||||
|
s_serverState == kInitializingToStart) {
|
||||||
|
stopRetryTimer();
|
||||||
|
s_serverState = kUninitialized;
|
||||||
|
}
|
||||||
|
assert(s_primaryClient == NULL);
|
||||||
|
assert(s_serverScreen == NULL);
|
||||||
|
assert(s_serverState == kUninitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::retryHandler(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
// discard old timer
|
||||||
|
assert(s_timer != NULL);
|
||||||
|
stopRetryTimer();
|
||||||
|
|
||||||
|
// try initializing/starting the server again
|
||||||
|
switch (s_serverState) {
|
||||||
|
case kUninitialized:
|
||||||
|
case kInitialized:
|
||||||
|
case kStarted:
|
||||||
|
assert(0 && "bad internal server state");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kInitializing:
|
||||||
|
LOG((CLOG_DEBUG1 "retry server initialization"));
|
||||||
|
s_serverState = kUninitialized;
|
||||||
|
if (!initServer()) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kInitializingToStart:
|
||||||
|
LOG((CLOG_DEBUG1 "retry server initialization"));
|
||||||
|
s_serverState = kUninitialized;
|
||||||
|
if (!initServer()) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
else if (s_serverState == kInitialized) {
|
||||||
|
LOG((CLOG_DEBUG1 "starting server"));
|
||||||
|
if (!startServer()) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kStarting:
|
||||||
|
LOG((CLOG_DEBUG1 "retry starting server"));
|
||||||
|
s_serverState = kInitialized;
|
||||||
|
if (!startServer()) {
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CServerApp::initServer()
|
||||||
|
{
|
||||||
|
// skip if already initialized or initializing
|
||||||
|
if (s_serverState != kUninitialized) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double retryTime;
|
||||||
|
CScreen* serverScreen = NULL;
|
||||||
|
CPrimaryClient* primaryClient = NULL;
|
||||||
|
try {
|
||||||
|
CString name = args().m_config->getCanonicalName(args().m_name);
|
||||||
|
serverScreen = openServerScreen();
|
||||||
|
primaryClient = openPrimaryClient(name, serverScreen);
|
||||||
|
s_serverScreen = serverScreen;
|
||||||
|
s_primaryClient = primaryClient;
|
||||||
|
s_serverState = kInitialized;
|
||||||
|
updateStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XScreenUnavailable& e) {
|
||||||
|
LOG((CLOG_WARN "cannot open primary screen: %s", e.what()));
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
closeServerScreen(serverScreen);
|
||||||
|
updateStatus(CString("cannot open primary screen: ") + e.what());
|
||||||
|
retryTime = e.getRetryTime();
|
||||||
|
}
|
||||||
|
catch (XScreenOpenFailure& e) {
|
||||||
|
LOG((CLOG_CRIT "cannot open primary screen: %s", e.what()));
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
closeServerScreen(serverScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start server: %s", e.what()));
|
||||||
|
closePrimaryClient(primaryClient);
|
||||||
|
closeServerScreen(serverScreen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args().m_restartable) {
|
||||||
|
// install a timer and handler to retry later
|
||||||
|
assert(s_timer == NULL);
|
||||||
|
LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
|
||||||
|
s_timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, s_timer,
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::retryHandler));
|
||||||
|
s_serverState = kInitializing;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// don't try again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CScreen* CServerApp::openServerScreen()
|
||||||
|
{
|
||||||
|
CScreen* screen = createScreen();
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
|
||||||
|
screen->getEventTarget(),
|
||||||
|
new TMethodEventJob<CServerApp>(
|
||||||
|
this, &CServerApp::handleScreenError));
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getSuspendEvent(),
|
||||||
|
screen->getEventTarget(),
|
||||||
|
new TMethodEventJob<CServerApp>(
|
||||||
|
this, &CServerApp::handleSuspend));
|
||||||
|
EVENTQUEUE->adoptHandler(IScreen::getResumeEvent(),
|
||||||
|
screen->getEventTarget(),
|
||||||
|
new TMethodEventJob<CServerApp>(
|
||||||
|
this, &CServerApp::handleResume));
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CServerApp::startServer()
|
||||||
|
{
|
||||||
|
// skip if already started or starting
|
||||||
|
if (s_serverState == kStarting || s_serverState == kStarted) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize if necessary
|
||||||
|
if (s_serverState != kInitialized) {
|
||||||
|
if (!initServer()) {
|
||||||
|
// hard initialization failure
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (s_serverState == kInitializing) {
|
||||||
|
// not ready to start
|
||||||
|
s_serverState = kInitializingToStart;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
assert(s_serverState == kInitialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
double retryTime;
|
||||||
|
CClientListener* listener = NULL;
|
||||||
|
try {
|
||||||
|
listener = openClientListener(args().m_config->getSynergyAddress());
|
||||||
|
s_server = openServer(*args().m_config, s_primaryClient);
|
||||||
|
s_listener = listener;
|
||||||
|
updateStatus();
|
||||||
|
LOG((CLOG_NOTE "started server"));
|
||||||
|
s_serverState = kStarted;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (XSocketAddressInUse& e) {
|
||||||
|
LOG((CLOG_WARN "cannot listen for clients: %s", e.what()));
|
||||||
|
closeClientListener(listener);
|
||||||
|
updateStatus(CString("cannot listen for clients: ") + e.what());
|
||||||
|
retryTime = 10.0;
|
||||||
|
}
|
||||||
|
catch (XBase& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start server: %s", e.what()));
|
||||||
|
closeClientListener(listener);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args().m_restartable) {
|
||||||
|
// install a timer and handler to retry later
|
||||||
|
assert(s_timer == NULL);
|
||||||
|
LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime));
|
||||||
|
s_timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CEvent::kTimer, s_timer,
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::retryHandler));
|
||||||
|
s_serverState = kStarting;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// don't try again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CScreen*
|
||||||
|
CServerApp::createScreen()
|
||||||
|
{
|
||||||
|
#if WINAPI_MSWINDOWS
|
||||||
|
return new CScreen(new CMSWindowsScreen(true, args().m_noHooks));
|
||||||
|
#elif WINAPI_XWINDOWS
|
||||||
|
return new CScreen(new CXWindowsScreen(args().m_display, true));
|
||||||
|
#elif WINAPI_CARBON
|
||||||
|
return new CScreen(new COSXScreen(true));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CPrimaryClient*
|
||||||
|
CServerApp::openPrimaryClient(const CString& name, CScreen* screen)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG1 "creating primary screen"));
|
||||||
|
return new CPrimaryClient(name, screen);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::handleScreenError(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_CRIT "error on screen"));
|
||||||
|
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::handleSuspend(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
if (!s_suspended) {
|
||||||
|
LOG((CLOG_INFO "suspend"));
|
||||||
|
stopServer();
|
||||||
|
s_suspended = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerApp::handleResume(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
if (s_suspended) {
|
||||||
|
LOG((CLOG_INFO "resume"));
|
||||||
|
startServer();
|
||||||
|
s_suspended = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientListener*
|
||||||
|
CServerApp::openClientListener(const CNetworkAddress& address)
|
||||||
|
{
|
||||||
|
CClientListener* listen =
|
||||||
|
new CClientListener(address, new CTCPSocketFactory, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen,
|
||||||
|
new TMethodEventJob<CServerApp>(
|
||||||
|
this, &CServerApp::handleClientConnected, listen));
|
||||||
|
return listen;
|
||||||
|
}
|
||||||
|
|
||||||
|
CServer*
|
||||||
|
CServerApp::openServer(const CConfig& config, CPrimaryClient* primaryClient)
|
||||||
|
{
|
||||||
|
CServer* server = new CServer(config, primaryClient);
|
||||||
|
|
||||||
|
try {
|
||||||
|
EVENTQUEUE->adoptHandler(
|
||||||
|
CServer::getDisconnectedEvent(), server,
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::handleNoClients));
|
||||||
|
|
||||||
|
} catch (std::bad_alloc &ba) {
|
||||||
|
delete server;
|
||||||
|
throw ba;
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerApp::handleNoClients( const CEvent&, void* )
|
||||||
|
{
|
||||||
|
updateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CServerApp::mainLoop()
|
||||||
|
{
|
||||||
|
// create socket multiplexer. this must happen after daemonization
|
||||||
|
// on unix because threads evaporate across a fork().
|
||||||
|
CSocketMultiplexer multiplexer;
|
||||||
|
|
||||||
|
// create the event queue
|
||||||
|
CEventQueue eventQueue;
|
||||||
|
|
||||||
|
// logging to files
|
||||||
|
CFileLogOutputter* fileLog = NULL;
|
||||||
|
|
||||||
|
if (args().m_logFile != NULL) {
|
||||||
|
fileLog = new CFileLogOutputter(args().m_logFile);
|
||||||
|
|
||||||
|
CLOG->insert(fileLog);
|
||||||
|
|
||||||
|
LOG((CLOG_DEBUG1 "Logging to file (%s) enabled", args().m_logFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if configuration has no screens then add this system
|
||||||
|
// as the default
|
||||||
|
if (args().m_config->begin() == args().m_config->end()) {
|
||||||
|
args().m_config->addScreen(args().m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the contact address, if provided, in the config.
|
||||||
|
// otherwise, if the config doesn't have an address, use
|
||||||
|
// the default.
|
||||||
|
if (args().m_synergyAddress->isValid()) {
|
||||||
|
args().m_config->setSynergyAddress(*args().m_synergyAddress);
|
||||||
|
}
|
||||||
|
else if (!args().m_config->getSynergyAddress().isValid()) {
|
||||||
|
args().m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||||
|
}
|
||||||
|
|
||||||
|
// canonicalize the primary screen name
|
||||||
|
CString primaryName = args().m_config->getCanonicalName(args().m_name);
|
||||||
|
if (primaryName.empty()) {
|
||||||
|
LOG((CLOG_CRIT "unknown screen name `%s'", args().m_name.c_str()));
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the server. if this return false then we've failed and
|
||||||
|
// we shouldn't retry.
|
||||||
|
LOG((CLOG_DEBUG1 "starting server"));
|
||||||
|
if (!startServer()) {
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle hangup signal by reloading the server's configuration
|
||||||
|
ARCH->setSignalHandler(CArch::kHANGUP, &reloadSignalHandler, NULL);
|
||||||
|
EVENTQUEUE->adoptHandler(getReloadConfigEvent(),
|
||||||
|
IEventQueue::getSystemTarget(),
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::reloadConfig));
|
||||||
|
|
||||||
|
// handle force reconnect event by disconnecting clients. they'll
|
||||||
|
// reconnect automatically.
|
||||||
|
EVENTQUEUE->adoptHandler(getForceReconnectEvent(),
|
||||||
|
IEventQueue::getSystemTarget(),
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::forceReconnect));
|
||||||
|
|
||||||
|
// to work around the sticky meta keys problem, we'll give users
|
||||||
|
// the option to reset the state of synergys
|
||||||
|
EVENTQUEUE->adoptHandler(getResetServerEvent(),
|
||||||
|
IEventQueue::getSystemTarget(),
|
||||||
|
new TMethodEventJob<CServerApp>(this, &CServerApp::resetServer));
|
||||||
|
|
||||||
|
// run event loop. if startServer() failed we're supposed to retry
|
||||||
|
// later. the timer installed by startServer() will take care of
|
||||||
|
// that.
|
||||||
|
CEvent event;
|
||||||
|
DAEMON_RUNNING(true);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
while (event.getType() != CEvent::kQuit) {
|
||||||
|
EVENTQUEUE->dispatchEvent(event);
|
||||||
|
CEvent::deleteData(event);
|
||||||
|
EVENTQUEUE->getEvent(event);
|
||||||
|
}
|
||||||
|
DAEMON_RUNNING(false);
|
||||||
|
|
||||||
|
// close down
|
||||||
|
LOG((CLOG_DEBUG1 "stopping server"));
|
||||||
|
EVENTQUEUE->removeHandler(getForceReconnectEvent(),
|
||||||
|
IEventQueue::getSystemTarget());
|
||||||
|
EVENTQUEUE->removeHandler(getReloadConfigEvent(),
|
||||||
|
IEventQueue::getSystemTarget());
|
||||||
|
cleanupServer();
|
||||||
|
updateStatus();
|
||||||
|
LOG((CLOG_NOTE "stopped server"));
|
||||||
|
|
||||||
|
if (fileLog) {
|
||||||
|
CLOG->remove(fileLog);
|
||||||
|
delete fileLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kExitSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServerApp::resetServer(const CEvent&, void*)
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG1 "resetting server"));
|
||||||
|
stopServer();
|
||||||
|
cleanupServer();
|
||||||
|
startServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup, CreateTaskBarReceiverFunc createTaskBarReceiver)
|
||||||
|
{
|
||||||
|
// general initialization
|
||||||
|
args().m_synergyAddress = new CNetworkAddress;
|
||||||
|
args().m_config = new CConfig;
|
||||||
|
args().m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
|
// install caller's output filter
|
||||||
|
if (outputter != NULL) {
|
||||||
|
CLOG->insert(outputter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save log messages
|
||||||
|
// use heap memory because CLog deletes outputters on destruction
|
||||||
|
CBufferedLogOutputter* logBuffer = new CBufferedLogOutputter(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;
|
||||||
|
|
||||||
|
delete args().m_config;
|
||||||
|
delete args().m_synergyAddress;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int daemonMainLoopStatic(int argc, const char** argv) {
|
||||||
|
return CServerApp::instance().daemonMainLoop(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CServerApp::standardStartup(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// parse command line
|
||||||
|
parseArgs(argc, argv);
|
||||||
|
|
||||||
|
// load configuration
|
||||||
|
loadConfig();
|
||||||
|
|
||||||
|
// daemonize if requested
|
||||||
|
if (args().m_daemon) {
|
||||||
|
return ARCH->daemonize(daemonName(), daemonMainLoopStatic);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return mainLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CServerApp::foregroundStartup(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// parse command line
|
||||||
|
parseArgs(argc, argv);
|
||||||
|
|
||||||
|
// load configuration
|
||||||
|
loadConfig();
|
||||||
|
|
||||||
|
// never daemonize
|
||||||
|
return mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
mainLoopStatic()
|
||||||
|
{
|
||||||
|
return CServerApp::instance().mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CServerApp::daemonName() const
|
||||||
|
{
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
return "Synergy+ Server";
|
||||||
|
#elif SYSAPI_UNIX
|
||||||
|
return "synergys";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CServerApp::daemonInfo() const
|
||||||
|
{
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
return "Shares this computers mouse and keyboard with other computers.";
|
||||||
|
#elif SYSAPI_UNIX
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CApp.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "CConfig.h"
|
||||||
|
#include "CNetworkAddress.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
|
||||||
|
enum EServerState {
|
||||||
|
kUninitialized,
|
||||||
|
kInitializing,
|
||||||
|
kInitializingToStart,
|
||||||
|
kInitialized,
|
||||||
|
kStarting,
|
||||||
|
kStarted
|
||||||
|
};
|
||||||
|
|
||||||
|
class CServer;
|
||||||
|
class CScreen;
|
||||||
|
class CClientListener;
|
||||||
|
class CEventQueueTimer;
|
||||||
|
class ILogOutputter;
|
||||||
|
|
||||||
|
class CServerApp : public CApp {
|
||||||
|
public:
|
||||||
|
class CArgs : public CApp::CArgsBase {
|
||||||
|
public:
|
||||||
|
CArgs();
|
||||||
|
~CArgs();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CString m_configFile;
|
||||||
|
CNetworkAddress* m_synergyAddress;
|
||||||
|
CConfig* m_config;
|
||||||
|
};
|
||||||
|
|
||||||
|
CServerApp();
|
||||||
|
virtual ~CServerApp();
|
||||||
|
|
||||||
|
// Parse server specific command line arguments.
|
||||||
|
void parseArgs(int argc, const char* const* argv);
|
||||||
|
|
||||||
|
// Prints help specific to server.
|
||||||
|
void help();
|
||||||
|
|
||||||
|
// Returns arguments that are common and for server.
|
||||||
|
CArgs& args() const { return (CArgs&)argsBase(); }
|
||||||
|
|
||||||
|
const char* daemonName() const;
|
||||||
|
const char* daemonInfo() const;
|
||||||
|
|
||||||
|
// TODO: Document these functions.
|
||||||
|
static void reloadSignalHandler(CArch::ESignal, void*);
|
||||||
|
static CEvent::Type getReloadConfigEvent();
|
||||||
|
|
||||||
|
void reloadConfig(const CEvent&, void*);
|
||||||
|
void loadConfig();
|
||||||
|
bool loadConfig(const CString& pathname);
|
||||||
|
void forceReconnect(const CEvent&, void*);
|
||||||
|
CEvent::Type getForceReconnectEvent();
|
||||||
|
void resetServer(const CEvent&, void*);
|
||||||
|
CEvent::Type getResetServerEvent();
|
||||||
|
void handleClientConnected(const CEvent&, void* vlistener);
|
||||||
|
void handleClientsDisconnected(const CEvent&, void*);
|
||||||
|
void closeServer(CServer* server);
|
||||||
|
void stopRetryTimer();
|
||||||
|
void updateStatus();
|
||||||
|
void updateStatus(const CString& msg);
|
||||||
|
void closeClientListener(CClientListener* listen);
|
||||||
|
void stopServer();
|
||||||
|
void closePrimaryClient(CPrimaryClient* primaryClient);
|
||||||
|
void closeServerScreen(CScreen* screen);
|
||||||
|
void cleanupServer();
|
||||||
|
bool initServer();
|
||||||
|
void retryHandler(const CEvent&, void*);
|
||||||
|
CScreen* openServerScreen();
|
||||||
|
CScreen* createScreen();
|
||||||
|
CPrimaryClient* openPrimaryClient(const CString& name, CScreen* screen);
|
||||||
|
void handleScreenError(const CEvent&, void*);
|
||||||
|
void handleSuspend(const CEvent&, void*);
|
||||||
|
void handleResume(const CEvent&, void*);
|
||||||
|
CClientListener* openClientListener(const CNetworkAddress& address);
|
||||||
|
CServer* openServer(const CConfig& config, CPrimaryClient* primaryClient);
|
||||||
|
void handleNoClients(const CEvent&, void*);
|
||||||
|
bool startServer();
|
||||||
|
int mainLoop();
|
||||||
|
int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||||
|
int standardStartup(int argc, char** argv);
|
||||||
|
int foregroundStartup(int argc, char** argv);
|
||||||
|
|
||||||
|
static CServerApp& instance() { return (CServerApp&)CApp::instance(); }
|
||||||
|
|
||||||
|
// TODO: change s_ to m_
|
||||||
|
CServer* s_server;
|
||||||
|
static CEvent::Type s_reloadConfigEvent;
|
||||||
|
CEvent::Type s_forceReconnectEvent;
|
||||||
|
CEvent::Type s_resetServerEvent;
|
||||||
|
EServerState s_serverState;
|
||||||
|
CScreen* s_serverScreen;
|
||||||
|
CPrimaryClient* s_primaryClient;
|
||||||
|
CClientListener* s_listener;
|
||||||
|
CEventQueueTimer* s_timer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||||
|
};
|
||||||
|
|
||||||
|
// configuration file name
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
#define USR_CONFIG_NAME "synergy.sgc"
|
||||||
|
#define SYS_CONFIG_NAME "synergy.sgc"
|
||||||
|
#elif SYSAPI_UNIX
|
||||||
|
#define USR_CONFIG_NAME ".synergy.conf"
|
||||||
|
#define SYS_CONFIG_NAME "synergy.conf"
|
||||||
|
#endif
|
|
@ -131,3 +131,21 @@ CServerTaskBarReceiver::getToolTip() const
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CServerTaskBarReceiver::getReloadConfigEvent()
|
||||||
|
{
|
||||||
|
return CServerApp::instance().getReloadConfigEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CServerTaskBarReceiver::getForceReconnectEvent()
|
||||||
|
{
|
||||||
|
return CServerApp::instance().getForceReconnectEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
CEvent::Type
|
||||||
|
CServerTaskBarReceiver::getResetServerEvent()
|
||||||
|
{
|
||||||
|
return CServerApp::instance().getResetServerEvent();
|
||||||
|
}
|
|
@ -18,8 +18,9 @@
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include "IArchTaskBarReceiver.h"
|
#include "IArchTaskBarReceiver.h"
|
||||||
#include "stdvector.h"
|
#include "stdvector.h"
|
||||||
|
#include "CEvent.h"
|
||||||
class CServer;
|
#include "CServerApp.h"
|
||||||
|
#include "CServer.h"
|
||||||
|
|
||||||
//! Implementation of IArchTaskBarReceiver for the synergy server
|
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||||
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
|
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
|
||||||
|
@ -36,6 +37,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void updateStatus(CServer*, const CString& errorMsg);
|
void updateStatus(CServer*, const CString& errorMsg);
|
||||||
|
|
||||||
|
void updateStatus(INode* n, const CString& errorMsg) { updateStatus((CServer*)n, errorMsg); }
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IArchTaskBarReceiver overrides
|
// IArchTaskBarReceiver overrides
|
||||||
|
@ -79,10 +82,17 @@ protected:
|
||||||
*/
|
*/
|
||||||
virtual void onStatusChanged(CServer* server);
|
virtual void onStatusChanged(CServer* server);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CEvent::Type getReloadConfigEvent();
|
||||||
|
CEvent::Type getForceReconnectEvent();
|
||||||
|
CEvent::Type getResetServerEvent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EState m_state;
|
EState m_state;
|
||||||
CString m_errorMessage;
|
CString m_errorMessage;
|
||||||
CClients m_clients;
|
CClients m_clients;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IArchTaskBarReceiver* createTaskBarReceiver(const CBufferedLogOutputter* logBuffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
|
*
|
||||||
|
* This package is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* found in the file COPYING that should have accompanied this file.
|
||||||
|
*
|
||||||
|
* This package is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "IInterface.h"
|
||||||
|
|
||||||
|
class INode : IInterface {
|
||||||
|
|
||||||
|
};
|
Loading…
Reference in New Issue