From 958fa80d1d7ec091a1dba77aa80f00b6226cd1dc Mon Sep 17 00:00:00 2001
From: Sorin Sbarnea
Date: Fri, 27 Feb 2009 11:54:59 +0000
Subject: [PATCH] Initial commit of the synergy trunk sources from sf.net
---
AUTHORS | 1 +
COPYING | 286 +
ChangeLog | 11453 ++++++++++++++++
INSTALL | 1 +
Makefile.am | 97 +
Makefile.win | 145 +
NEWS | 1 +
README | 21 +
acinclude.m4 | 571 +
cmd/Makefile.am | 27 +
cmd/launcher/CAddScreen.cpp | 427 +
cmd/launcher/CAddScreen.h | 74 +
cmd/launcher/CAdvancedOptions.cpp | 269 +
cmd/launcher/CAdvancedOptions.h | 80 +
cmd/launcher/CAutoStart.cpp | 361 +
cmd/launcher/CAutoStart.h | 90 +
cmd/launcher/CGlobalOptions.cpp | 281 +
cmd/launcher/CGlobalOptions.h | 67 +
cmd/launcher/CHotkeyOptions.cpp | 1938 +++
cmd/launcher/CHotkeyOptions.h | 227 +
cmd/launcher/CInfo.cpp | 111 +
cmd/launcher/CInfo.h | 57 +
cmd/launcher/CScreensLinks.cpp | 855 ++
cmd/launcher/CScreensLinks.h | 138 +
cmd/launcher/LaunchUtil.cpp | 261 +
cmd/launcher/LaunchUtil.h | 61 +
cmd/launcher/Makefile.am | 75 +
cmd/launcher/Makefile.win | 101 +
cmd/launcher/launcher.cpp | 755 +
cmd/launcher/launcher.rc | 617 +
cmd/launcher/resource.h | 186 +
cmd/launcher/synergy.ico | Bin 0 -> 8478 bytes
cmd/synergyc/CClientTaskBarReceiver.cpp | 136 +
cmd/synergyc/CClientTaskBarReceiver.h | 83 +
.../CMSWindowsClientTaskBarReceiver.cpp | 346 +
.../CMSWindowsClientTaskBarReceiver.h | 64 +
cmd/synergyc/COSXClientTaskBarReceiver.cpp | 56 +
cmd/synergyc/COSXClientTaskBarReceiver.h | 35 +
.../CXWindowsClientTaskBarReceiver.cpp | 56 +
cmd/synergyc/CXWindowsClientTaskBarReceiver.h | 35 +
cmd/synergyc/Makefile.am | 98 +
cmd/synergyc/Makefile.win | 89 +
cmd/synergyc/resource.h | 37 +
cmd/synergyc/synergyc.cpp | 910 ++
cmd/synergyc/synergyc.ico | Bin 0 -> 8478 bytes
cmd/synergyc/synergyc.rc | 141 +
cmd/synergyc/tb_error.ico | Bin 0 -> 318 bytes
cmd/synergyc/tb_idle.ico | Bin 0 -> 318 bytes
cmd/synergyc/tb_run.ico | Bin 0 -> 318 bytes
cmd/synergyc/tb_wait.ico | Bin 0 -> 318 bytes
.../CMSWindowsServerTaskBarReceiver.cpp | 374 +
.../CMSWindowsServerTaskBarReceiver.h | 64 +
cmd/synergys/COSXServerTaskBarReceiver.cpp | 56 +
cmd/synergys/COSXServerTaskBarReceiver.h | 35 +
cmd/synergys/CServerTaskBarReceiver.cpp | 133 +
cmd/synergys/CServerTaskBarReceiver.h | 88 +
.../CXWindowsServerTaskBarReceiver.cpp | 56 +
cmd/synergys/CXWindowsServerTaskBarReceiver.h | 35 +
cmd/synergys/Makefile.am | 98 +
cmd/synergys/Makefile.win | 89 +
cmd/synergys/resource.h | 40 +
cmd/synergys/synergys.cpp | 1312 ++
cmd/synergys/synergys.ico | Bin 0 -> 8478 bytes
cmd/synergys/synergys.rc | 146 +
cmd/synergys/tb_error.ico | Bin 0 -> 318 bytes
cmd/synergys/tb_idle.ico | Bin 0 -> 318 bytes
cmd/synergys/tb_run.ico | Bin 0 -> 318 bytes
cmd/synergys/tb_wait.ico | Bin 0 -> 318 bytes
config/config.guess | 1327 ++
config/config.sub | 1410 ++
config/depcomp | 411 +
config/install-sh | 251 +
config/missing | 283 +
config/mkinstalldirs | 40 +
configure.in | 289 +
dist/Makefile.am | 26 +
dist/nullsoft/Makefile.am | 24 +
dist/nullsoft/Makefile.win | 63 +
dist/nullsoft/dosify.c | 99 +
dist/nullsoft/synergy.nsi | 179 +
dist/rpm/Makefile.am | 22 +
dist/rpm/synergy.spec.in | 66 +
doc/Makefile.am | 49 +
doc/PORTING | 419 +
doc/about.html | 55 +
doc/authors.html | 72 +
doc/autostart.html | 428 +
doc/banner.html | 16 +
doc/border.html | 14 +
doc/compiling.html | 112 +
doc/configuration.html | 686 +
doc/contact.html | 44 +
doc/developer.html | 81 +
doc/doxygen.cfg.in | 898 ++
doc/faq.html | 266 +
doc/history.html | 30 +
doc/home.html | 61 +
doc/images/logo.gif | Bin 0 -> 1827 bytes
doc/images/warp.gif | Bin 0 -> 68841 bytes
doc/index.html | 33 +
doc/license.html | 313 +
doc/news.html | 599 +
doc/roadmap.html | 92 +
doc/running.html | 394 +
doc/security.html | 55 +
doc/synergy.css | 166 +
doc/tips.html | 81 +
doc/toc.html | 43 +
doc/todo.html | 70 +
doc/trouble.html | 204 +
examples/synergy.conf | 37 +
lib/Makefile.am | 34 +
lib/arch/CArch.cpp | 639 +
lib/arch/CArch.h | 218 +
lib/arch/CArchConsoleUnix.cpp | 60 +
lib/arch/CArchConsoleUnix.h | 36 +
lib/arch/CArchConsoleWindows.cpp | 438 +
lib/arch/CArchConsoleWindows.h | 77 +
lib/arch/CArchDaemonNone.cpp | 66 +
lib/arch/CArchDaemonNone.h | 47 +
lib/arch/CArchDaemonUnix.cpp | 78 +
lib/arch/CArchDaemonUnix.h | 33 +
lib/arch/CArchDaemonWindows.cpp | 770 ++
lib/arch/CArchDaemonWindows.h | 134 +
lib/arch/CArchFileUnix.cpp | 98 +
lib/arch/CArchFileUnix.h | 36 +
lib/arch/CArchFileWindows.cpp | 132 +
lib/arch/CArchFileWindows.h | 36 +
lib/arch/CArchLogUnix.cpp | 79 +
lib/arch/CArchLogUnix.h | 35 +
lib/arch/CArchLogWindows.cpp | 90 +
lib/arch/CArchLogWindows.h | 41 +
lib/arch/CArchMiscWindows.cpp | 416 +
lib/arch/CArchMiscWindows.h | 191 +
lib/arch/CArchMultithreadPosix.cpp | 806 ++
lib/arch/CArchMultithreadPosix.h | 113 +
lib/arch/CArchMultithreadWindows.cpp | 699 +
lib/arch/CArchMultithreadWindows.h | 115 +
lib/arch/CArchNetworkBSD.cpp | 974 ++
lib/arch/CArchNetworkBSD.h | 101 +
lib/arch/CArchNetworkWinsock.cpp | 934 ++
lib/arch/CArchNetworkWinsock.h | 99 +
lib/arch/CArchSleepUnix.cpp | 88 +
lib/arch/CArchSleepUnix.h | 32 +
lib/arch/CArchSleepWindows.cpp | 57 +
lib/arch/CArchSleepWindows.h | 32 +
lib/arch/CArchStringUnix.cpp | 29 +
lib/arch/CArchStringUnix.h | 39 +
lib/arch/CArchStringWindows.cpp | 34 +
lib/arch/CArchStringWindows.h | 39 +
lib/arch/CArchSystemUnix.cpp | 50 +
lib/arch/CArchSystemUnix.h | 32 +
lib/arch/CArchSystemWindows.cpp | 86 +
lib/arch/CArchSystemWindows.h | 32 +
lib/arch/CArchTaskBarWindows.cpp | 492 +
lib/arch/CArchTaskBarWindows.h | 110 +
lib/arch/CArchTaskBarXWindows.cpp | 47 +
lib/arch/CArchTaskBarXWindows.h | 34 +
lib/arch/CArchTimeUnix.cpp | 47 +
lib/arch/CArchTimeUnix.h | 32 +
lib/arch/CArchTimeWindows.cpp | 86 +
lib/arch/CArchTimeWindows.h | 32 +
lib/arch/CMultibyte.cpp | 219 +
lib/arch/IArchConsole.h | 71 +
lib/arch/IArchDaemon.h | 107 +
lib/arch/IArchFile.h | 64 +
lib/arch/IArchLog.h | 73 +
lib/arch/IArchMultithread.h | 272 +
lib/arch/IArchNetwork.h | 279 +
lib/arch/IArchSleep.h | 43 +
lib/arch/IArchString.h | 68 +
lib/arch/IArchSystem.h | 39 +
lib/arch/IArchTaskBar.h | 60 +
lib/arch/IArchTaskBarReceiver.h | 90 +
lib/arch/IArchTime.h | 40 +
lib/arch/Makefile.am | 118 +
lib/arch/Makefile.win | 84 +
lib/arch/XArch.cpp | 33 +
lib/arch/XArch.h | 170 +
lib/arch/XArchUnix.cpp | 33 +
lib/arch/XArchUnix.h | 34 +
lib/arch/XArchWindows.cpp | 127 +
lib/arch/XArchWindows.h | 52 +
lib/arch/vsnprintf.cpp | 61 +
lib/base/CEvent.cpp | 98 +
lib/base/CEvent.h | 123 +
lib/base/CEventQueue.cpp | 526 +
lib/base/CEventQueue.h | 123 +
lib/base/CFunctionEventJob.cpp | 40 +
lib/base/CFunctionEventJob.h | 38 +
lib/base/CFunctionJob.cpp | 39 +
lib/base/CFunctionJob.h | 38 +
lib/base/CLog.cpp | 293 +
lib/base/CLog.h | 202 +
lib/base/CPriorityQueue.h | 136 +
lib/base/CSimpleEventQueueBuffer.cpp | 97 +
lib/base/CSimpleEventQueueBuffer.h | 49 +
lib/base/CStopwatch.cpp | 126 +
lib/base/CStopwatch.h | 108 +
lib/base/CString.h | 25 +
lib/base/CStringUtil.cpp | 194 +
lib/base/CStringUtil.h | 77 +
lib/base/CUnicode.cpp | 779 ++
lib/base/CUnicode.h | 143 +
lib/base/IEventJob.h | 32 +
lib/base/IEventQueue.cpp | 43 +
lib/base/IEventQueue.h | 213 +
lib/base/IEventQueueBuffer.h | 94 +
lib/base/IJob.h | 30 +
lib/base/ILogOutputter.h | 81 +
lib/base/LogOutputters.cpp | 267 +
lib/base/LogOutputters.h | 132 +
lib/base/Makefile.am | 62 +
lib/base/Makefile.win | 77 +
lib/base/TMethodEventJob.h | 70 +
lib/base/TMethodJob.h | 67 +
lib/base/XBase.cpp | 69 +
lib/base/XBase.h | 121 +
lib/client/CClient.cpp | 662 +
lib/client/CClient.h | 198 +
lib/client/CServerProxy.cpp | 816 ++
lib/client/CServerProxy.h | 115 +
lib/client/Makefile.am | 40 +
lib/client/Makefile.win | 63 +
lib/common/BasicTypes.h | 86 +
lib/common/IInterface.h | 31 +
lib/common/MacOSXPrecomp.h | 8 +
lib/common/Makefile.am | 48 +
lib/common/Makefile.win | 53 +
lib/common/Version.cpp | 22 +
lib/common/Version.h | 45 +
lib/common/common.h | 135 +
lib/common/stdbitset.h | 17 +
lib/common/stddeque.h | 17 +
lib/common/stdfstream.h | 18 +
lib/common/stdistream.h | 43 +
lib/common/stdlist.h | 17 +
lib/common/stdmap.h | 17 +
lib/common/stdostream.h | 21 +
lib/common/stdpost.h | 17 +
lib/common/stdpre.h | 27 +
lib/common/stdset.h | 17 +
lib/common/stdsstream.h | 371 +
lib/common/stdstring.h | 17 +
lib/common/stdvector.h | 17 +
lib/io/CStreamBuffer.cpp | 142 +
lib/io/CStreamBuffer.h | 78 +
lib/io/CStreamFilter.cpp | 113 +
lib/io/CStreamFilter.h | 70 +
lib/io/IStream.cpp | 60 +
lib/io/IStream.h | 157 +
lib/io/IStreamFilterFactory.h | 36 +
lib/io/Makefile.am | 41 +
lib/io/Makefile.win | 63 +
lib/io/XIO.cpp | 47 +
lib/io/XIO.h | 48 +
lib/mt/CCondVar.cpp | 81 +
lib/mt/CCondVar.h | 224 +
lib/mt/CLock.cpp | 38 +
lib/mt/CLock.h | 48 +
lib/mt/CMutex.cpp | 53 +
lib/mt/CMutex.h | 78 +
lib/mt/CThread.cpp | 183 +
lib/mt/CThread.h | 209 +
lib/mt/Makefile.am | 42 +
lib/mt/Makefile.win | 64 +
lib/mt/XMT.cpp | 25 +
lib/mt/XMT.h | 29 +
lib/mt/XThread.h | 36 +
lib/net/CNetworkAddress.cpp | 208 +
lib/net/CNetworkAddress.h | 122 +
lib/net/CSocketMultiplexer.cpp | 359 +
lib/net/CSocketMultiplexer.h | 111 +
lib/net/CTCPListenSocket.cpp | 134 +
lib/net/CTCPListenSocket.h | 51 +
lib/net/CTCPSocket.cpp | 542 +
lib/net/CTCPSocket.h | 86 +
lib/net/CTCPSocketFactory.cpp | 43 +
lib/net/CTCPSocketFactory.h | 31 +
lib/net/IDataSocket.cpp | 51 +
lib/net/IDataSocket.h | 90 +
lib/net/IListenSocket.cpp | 28 +
lib/net/IListenSocket.h | 62 +
lib/net/ISocket.cpp | 28 +
lib/net/ISocket.h | 69 +
lib/net/ISocketFactory.h | 42 +
lib/net/ISocketMultiplexerJob.h | 75 +
lib/net/Makefile.am | 54 +
lib/net/Makefile.win | 74 +
lib/net/TSocketMultiplexerMethodJob.h | 108 +
lib/net/XSocket.cpp | 113 +
lib/net/XSocket.h | 96 +
lib/platform/CMSWindowsClipboard.cpp | 209 +
lib/platform/CMSWindowsClipboard.h | 104 +
.../CMSWindowsClipboardAnyTextConverter.cpp | 145 +
.../CMSWindowsClipboardAnyTextConverter.h | 56 +
.../CMSWindowsClipboardBitmapConverter.cpp | 146 +
.../CMSWindowsClipboardBitmapConverter.h | 35 +
.../CMSWindowsClipboardHTMLConverter.cpp | 107 +
.../CMSWindowsClipboardHTMLConverter.h | 44 +
.../CMSWindowsClipboardTextConverter.cpp | 55 +
.../CMSWindowsClipboardTextConverter.h | 36 +
.../CMSWindowsClipboardUTF16Converter.cpp | 55 +
.../CMSWindowsClipboardUTF16Converter.h | 36 +
lib/platform/CMSWindowsDesks.cpp | 1033 ++
lib/platform/CMSWindowsDesks.h | 296 +
lib/platform/CMSWindowsEventQueueBuffer.cpp | 138 +
lib/platform/CMSWindowsEventQueueBuffer.h | 44 +
lib/platform/CMSWindowsKeyState.cpp | 1420 ++
lib/platform/CMSWindowsKeyState.h | 216 +
lib/platform/CMSWindowsScreen.cpp | 1738 +++
lib/platform/CMSWindowsScreen.h | 308 +
lib/platform/CMSWindowsScreenSaver.cpp | 498 +
lib/platform/CMSWindowsScreenSaver.h | 92 +
lib/platform/CMSWindowsUtil.cpp | 75 +
lib/platform/CMSWindowsUtil.h | 38 +
lib/platform/COSXClipboard.cpp | 220 +
lib/platform/COSXClipboard.h | 94 +
.../COSXClipboardAnyTextConverter.cpp | 85 +
lib/platform/COSXClipboardAnyTextConverter.h | 52 +
lib/platform/COSXClipboardTextConverter.cpp | 88 +
lib/platform/COSXClipboardTextConverter.h | 41 +
lib/platform/COSXClipboardUTF16Converter.cpp | 50 +
lib/platform/COSXClipboardUTF16Converter.h | 36 +
lib/platform/COSXEventQueueBuffer.cpp | 124 +
lib/platform/COSXEventQueueBuffer.h | 40 +
lib/platform/COSXKeyState.cpp | 1237 ++
lib/platform/COSXKeyState.h | 235 +
lib/platform/COSXScreen.cpp | 1699 +++
lib/platform/COSXScreen.h | 252 +
lib/platform/COSXScreenSaver.cpp | 175 +
lib/platform/COSXScreenSaver.h | 54 +
lib/platform/COSXScreenSaverUtil.h | 39 +
lib/platform/COSXScreenSaverUtil.m | 81 +
lib/platform/CSynergyHook.cpp | 1110 ++
lib/platform/CSynergyHook.h | 81 +
lib/platform/CXWindowsClipboard.cpp | 1507 ++
lib/platform/CXWindowsClipboard.h | 376 +
.../CXWindowsClipboardAnyBitmapConverter.cpp | 187 +
.../CXWindowsClipboardAnyBitmapConverter.h | 59 +
.../CXWindowsClipboardBMPConverter.cpp | 139 +
lib/platform/CXWindowsClipboardBMPConverter.h | 39 +
.../CXWindowsClipboardHTMLConverter.cpp | 62 +
.../CXWindowsClipboardHTMLConverter.h | 41 +
.../CXWindowsClipboardTextConverter.cpp | 74 +
.../CXWindowsClipboardTextConverter.h | 41 +
.../CXWindowsClipboardUCS2Converter.cpp | 62 +
.../CXWindowsClipboardUCS2Converter.h | 41 +
.../CXWindowsClipboardUTF8Converter.cpp | 61 +
.../CXWindowsClipboardUTF8Converter.h | 41 +
lib/platform/CXWindowsEventQueueBuffer.cpp | 208 +
lib/platform/CXWindowsEventQueueBuffer.h | 57 +
lib/platform/CXWindowsKeyState.cpp | 826 ++
lib/platform/CXWindowsKeyState.h | 155 +
lib/platform/CXWindowsScreen.cpp | 1901 +++
lib/platform/CXWindowsScreen.h | 229 +
lib/platform/CXWindowsScreenSaver.cpp | 598 +
lib/platform/CXWindowsScreenSaver.h | 164 +
lib/platform/CXWindowsUtil.cpp | 1766 +++
lib/platform/CXWindowsUtil.h | 185 +
lib/platform/Makefile.am | 123 +
lib/platform/Makefile.win | 119 +
lib/platform/OSXScreenSaverControl.h | 36 +
lib/server/CBaseClientProxy.cpp | 52 +
lib/server/CBaseClientProxy.h | 85 +
lib/server/CClientListener.cpp | 194 +
lib/server/CClientListener.h | 76 +
lib/server/CClientProxy.cpp | 81 +
lib/server/CClientProxy.h | 113 +
lib/server/CClientProxy1_0.cpp | 498 +
lib/server/CClientProxy1_0.h | 100 +
lib/server/CClientProxy1_1.cpp | 55 +
lib/server/CClientProxy1_1.h | 33 +
lib/server/CClientProxy1_2.cpp | 39 +
lib/server/CClientProxy1_2.h | 30 +
lib/server/CClientProxy1_3.cpp | 114 +
lib/server/CClientProxy1_3.h | 47 +
lib/server/CClientProxyUnknown.cpp | 287 +
lib/server/CClientProxyUnknown.h | 83 +
lib/server/CConfig.cpp | 2277 +++
lib/server/CConfig.h | 536 +
lib/server/CInputFilter.cpp | 1066 ++
lib/server/CInputFilter.h | 344 +
lib/server/CPrimaryClient.cpp | 257 +
lib/server/CPrimaryClient.h | 145 +
lib/server/CServer.cpp | 2176 +++
lib/server/CServer.h | 464 +
lib/server/Makefile.am | 60 +
lib/server/Makefile.win | 83 +
lib/synergy/CClipboard.cpp | 114 +
lib/synergy/CClipboard.h | 70 +
lib/synergy/CKeyMap.cpp | 1330 ++
lib/synergy/CKeyMap.h | 491 +
lib/synergy/CKeyState.cpp | 886 ++
lib/synergy/CKeyState.h | 216 +
lib/synergy/CPacketStreamFilter.cpp | 190 +
lib/synergy/CPacketStreamFilter.h | 55 +
lib/synergy/CPlatformScreen.cpp | 106 +
lib/synergy/CPlatformScreen.h | 109 +
lib/synergy/CProtocolUtil.cpp | 538 +
lib/synergy/CProtocolUtil.h | 95 +
lib/synergy/CScreen.cpp | 488 +
lib/synergy/CScreen.h | 304 +
lib/synergy/ClipboardTypes.h | 41 +
lib/synergy/IClient.h | 175 +
lib/synergy/IClipboard.cpp | 155 +
lib/synergy/IClipboard.h | 168 +
lib/synergy/IKeyState.cpp | 176 +
lib/synergy/IKeyState.h | 174 +
lib/synergy/IPlatformScreen.h | 210 +
lib/synergy/IPrimaryScreen.cpp | 178 +
lib/synergy/IPrimaryScreen.h | 206 +
lib/synergy/IScreen.cpp | 60 +
lib/synergy/IScreen.h | 112 +
lib/synergy/IScreenSaver.h | 74 +
lib/synergy/ISecondaryScreen.h | 58 +
lib/synergy/KeyTypes.cpp | 204 +
lib/synergy/KeyTypes.h | 306 +
lib/synergy/Makefile.am | 71 +
lib/synergy/Makefile.win | 87 +
lib/synergy/MouseTypes.h | 35 +
lib/synergy/OptionTypes.h | 92 +
lib/synergy/ProtocolTypes.cpp | 47 +
lib/synergy/ProtocolTypes.h | 308 +
lib/synergy/XScreen.cpp | 53 +
lib/synergy/XScreen.h | 61 +
lib/synergy/XSynergy.cpp | 104 +
lib/synergy/XSynergy.h | 105 +
win32util/autodep.cpp | 149 +
429 files changed, 96848 insertions(+)
create mode 100644 AUTHORS
create mode 100644 COPYING
create mode 100644 ChangeLog
create mode 100644 INSTALL
create mode 100644 Makefile.am
create mode 100644 Makefile.win
create mode 100644 NEWS
create mode 100644 README
create mode 100644 acinclude.m4
create mode 100644 cmd/Makefile.am
create mode 100644 cmd/launcher/CAddScreen.cpp
create mode 100644 cmd/launcher/CAddScreen.h
create mode 100644 cmd/launcher/CAdvancedOptions.cpp
create mode 100644 cmd/launcher/CAdvancedOptions.h
create mode 100644 cmd/launcher/CAutoStart.cpp
create mode 100644 cmd/launcher/CAutoStart.h
create mode 100644 cmd/launcher/CGlobalOptions.cpp
create mode 100644 cmd/launcher/CGlobalOptions.h
create mode 100644 cmd/launcher/CHotkeyOptions.cpp
create mode 100644 cmd/launcher/CHotkeyOptions.h
create mode 100644 cmd/launcher/CInfo.cpp
create mode 100644 cmd/launcher/CInfo.h
create mode 100644 cmd/launcher/CScreensLinks.cpp
create mode 100644 cmd/launcher/CScreensLinks.h
create mode 100644 cmd/launcher/LaunchUtil.cpp
create mode 100644 cmd/launcher/LaunchUtil.h
create mode 100644 cmd/launcher/Makefile.am
create mode 100644 cmd/launcher/Makefile.win
create mode 100644 cmd/launcher/launcher.cpp
create mode 100644 cmd/launcher/launcher.rc
create mode 100644 cmd/launcher/resource.h
create mode 100644 cmd/launcher/synergy.ico
create mode 100644 cmd/synergyc/CClientTaskBarReceiver.cpp
create mode 100644 cmd/synergyc/CClientTaskBarReceiver.h
create mode 100644 cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
create mode 100644 cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
create mode 100644 cmd/synergyc/COSXClientTaskBarReceiver.cpp
create mode 100644 cmd/synergyc/COSXClientTaskBarReceiver.h
create mode 100644 cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
create mode 100644 cmd/synergyc/CXWindowsClientTaskBarReceiver.h
create mode 100644 cmd/synergyc/Makefile.am
create mode 100644 cmd/synergyc/Makefile.win
create mode 100644 cmd/synergyc/resource.h
create mode 100644 cmd/synergyc/synergyc.cpp
create mode 100644 cmd/synergyc/synergyc.ico
create mode 100644 cmd/synergyc/synergyc.rc
create mode 100644 cmd/synergyc/tb_error.ico
create mode 100644 cmd/synergyc/tb_idle.ico
create mode 100644 cmd/synergyc/tb_run.ico
create mode 100644 cmd/synergyc/tb_wait.ico
create mode 100644 cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
create mode 100644 cmd/synergys/CMSWindowsServerTaskBarReceiver.h
create mode 100644 cmd/synergys/COSXServerTaskBarReceiver.cpp
create mode 100644 cmd/synergys/COSXServerTaskBarReceiver.h
create mode 100644 cmd/synergys/CServerTaskBarReceiver.cpp
create mode 100644 cmd/synergys/CServerTaskBarReceiver.h
create mode 100644 cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
create mode 100644 cmd/synergys/CXWindowsServerTaskBarReceiver.h
create mode 100644 cmd/synergys/Makefile.am
create mode 100644 cmd/synergys/Makefile.win
create mode 100644 cmd/synergys/resource.h
create mode 100644 cmd/synergys/synergys.cpp
create mode 100644 cmd/synergys/synergys.ico
create mode 100644 cmd/synergys/synergys.rc
create mode 100644 cmd/synergys/tb_error.ico
create mode 100644 cmd/synergys/tb_idle.ico
create mode 100644 cmd/synergys/tb_run.ico
create mode 100644 cmd/synergys/tb_wait.ico
create mode 100644 config/config.guess
create mode 100644 config/config.sub
create mode 100644 config/depcomp
create mode 100644 config/install-sh
create mode 100644 config/missing
create mode 100644 config/mkinstalldirs
create mode 100644 configure.in
create mode 100644 dist/Makefile.am
create mode 100644 dist/nullsoft/Makefile.am
create mode 100644 dist/nullsoft/Makefile.win
create mode 100644 dist/nullsoft/dosify.c
create mode 100644 dist/nullsoft/synergy.nsi
create mode 100644 dist/rpm/Makefile.am
create mode 100644 dist/rpm/synergy.spec.in
create mode 100644 doc/Makefile.am
create mode 100644 doc/PORTING
create mode 100644 doc/about.html
create mode 100644 doc/authors.html
create mode 100644 doc/autostart.html
create mode 100644 doc/banner.html
create mode 100644 doc/border.html
create mode 100644 doc/compiling.html
create mode 100644 doc/configuration.html
create mode 100644 doc/contact.html
create mode 100644 doc/developer.html
create mode 100644 doc/doxygen.cfg.in
create mode 100644 doc/faq.html
create mode 100644 doc/history.html
create mode 100644 doc/home.html
create mode 100644 doc/images/logo.gif
create mode 100644 doc/images/warp.gif
create mode 100644 doc/index.html
create mode 100644 doc/license.html
create mode 100644 doc/news.html
create mode 100644 doc/roadmap.html
create mode 100644 doc/running.html
create mode 100644 doc/security.html
create mode 100644 doc/synergy.css
create mode 100644 doc/tips.html
create mode 100644 doc/toc.html
create mode 100644 doc/todo.html
create mode 100644 doc/trouble.html
create mode 100644 examples/synergy.conf
create mode 100644 lib/Makefile.am
create mode 100644 lib/arch/CArch.cpp
create mode 100644 lib/arch/CArch.h
create mode 100644 lib/arch/CArchConsoleUnix.cpp
create mode 100644 lib/arch/CArchConsoleUnix.h
create mode 100644 lib/arch/CArchConsoleWindows.cpp
create mode 100644 lib/arch/CArchConsoleWindows.h
create mode 100644 lib/arch/CArchDaemonNone.cpp
create mode 100644 lib/arch/CArchDaemonNone.h
create mode 100644 lib/arch/CArchDaemonUnix.cpp
create mode 100644 lib/arch/CArchDaemonUnix.h
create mode 100644 lib/arch/CArchDaemonWindows.cpp
create mode 100644 lib/arch/CArchDaemonWindows.h
create mode 100644 lib/arch/CArchFileUnix.cpp
create mode 100644 lib/arch/CArchFileUnix.h
create mode 100644 lib/arch/CArchFileWindows.cpp
create mode 100644 lib/arch/CArchFileWindows.h
create mode 100644 lib/arch/CArchLogUnix.cpp
create mode 100644 lib/arch/CArchLogUnix.h
create mode 100644 lib/arch/CArchLogWindows.cpp
create mode 100644 lib/arch/CArchLogWindows.h
create mode 100644 lib/arch/CArchMiscWindows.cpp
create mode 100644 lib/arch/CArchMiscWindows.h
create mode 100644 lib/arch/CArchMultithreadPosix.cpp
create mode 100644 lib/arch/CArchMultithreadPosix.h
create mode 100644 lib/arch/CArchMultithreadWindows.cpp
create mode 100644 lib/arch/CArchMultithreadWindows.h
create mode 100644 lib/arch/CArchNetworkBSD.cpp
create mode 100644 lib/arch/CArchNetworkBSD.h
create mode 100644 lib/arch/CArchNetworkWinsock.cpp
create mode 100644 lib/arch/CArchNetworkWinsock.h
create mode 100644 lib/arch/CArchSleepUnix.cpp
create mode 100644 lib/arch/CArchSleepUnix.h
create mode 100644 lib/arch/CArchSleepWindows.cpp
create mode 100644 lib/arch/CArchSleepWindows.h
create mode 100644 lib/arch/CArchStringUnix.cpp
create mode 100644 lib/arch/CArchStringUnix.h
create mode 100644 lib/arch/CArchStringWindows.cpp
create mode 100644 lib/arch/CArchStringWindows.h
create mode 100644 lib/arch/CArchSystemUnix.cpp
create mode 100644 lib/arch/CArchSystemUnix.h
create mode 100644 lib/arch/CArchSystemWindows.cpp
create mode 100644 lib/arch/CArchSystemWindows.h
create mode 100644 lib/arch/CArchTaskBarWindows.cpp
create mode 100644 lib/arch/CArchTaskBarWindows.h
create mode 100644 lib/arch/CArchTaskBarXWindows.cpp
create mode 100644 lib/arch/CArchTaskBarXWindows.h
create mode 100644 lib/arch/CArchTimeUnix.cpp
create mode 100644 lib/arch/CArchTimeUnix.h
create mode 100644 lib/arch/CArchTimeWindows.cpp
create mode 100644 lib/arch/CArchTimeWindows.h
create mode 100644 lib/arch/CMultibyte.cpp
create mode 100644 lib/arch/IArchConsole.h
create mode 100644 lib/arch/IArchDaemon.h
create mode 100644 lib/arch/IArchFile.h
create mode 100644 lib/arch/IArchLog.h
create mode 100644 lib/arch/IArchMultithread.h
create mode 100644 lib/arch/IArchNetwork.h
create mode 100644 lib/arch/IArchSleep.h
create mode 100644 lib/arch/IArchString.h
create mode 100644 lib/arch/IArchSystem.h
create mode 100644 lib/arch/IArchTaskBar.h
create mode 100644 lib/arch/IArchTaskBarReceiver.h
create mode 100644 lib/arch/IArchTime.h
create mode 100644 lib/arch/Makefile.am
create mode 100644 lib/arch/Makefile.win
create mode 100644 lib/arch/XArch.cpp
create mode 100644 lib/arch/XArch.h
create mode 100644 lib/arch/XArchUnix.cpp
create mode 100644 lib/arch/XArchUnix.h
create mode 100644 lib/arch/XArchWindows.cpp
create mode 100644 lib/arch/XArchWindows.h
create mode 100644 lib/arch/vsnprintf.cpp
create mode 100644 lib/base/CEvent.cpp
create mode 100644 lib/base/CEvent.h
create mode 100644 lib/base/CEventQueue.cpp
create mode 100644 lib/base/CEventQueue.h
create mode 100644 lib/base/CFunctionEventJob.cpp
create mode 100644 lib/base/CFunctionEventJob.h
create mode 100644 lib/base/CFunctionJob.cpp
create mode 100644 lib/base/CFunctionJob.h
create mode 100644 lib/base/CLog.cpp
create mode 100644 lib/base/CLog.h
create mode 100644 lib/base/CPriorityQueue.h
create mode 100644 lib/base/CSimpleEventQueueBuffer.cpp
create mode 100644 lib/base/CSimpleEventQueueBuffer.h
create mode 100644 lib/base/CStopwatch.cpp
create mode 100644 lib/base/CStopwatch.h
create mode 100644 lib/base/CString.h
create mode 100644 lib/base/CStringUtil.cpp
create mode 100644 lib/base/CStringUtil.h
create mode 100644 lib/base/CUnicode.cpp
create mode 100644 lib/base/CUnicode.h
create mode 100644 lib/base/IEventJob.h
create mode 100644 lib/base/IEventQueue.cpp
create mode 100644 lib/base/IEventQueue.h
create mode 100644 lib/base/IEventQueueBuffer.h
create mode 100644 lib/base/IJob.h
create mode 100644 lib/base/ILogOutputter.h
create mode 100644 lib/base/LogOutputters.cpp
create mode 100644 lib/base/LogOutputters.h
create mode 100644 lib/base/Makefile.am
create mode 100644 lib/base/Makefile.win
create mode 100644 lib/base/TMethodEventJob.h
create mode 100644 lib/base/TMethodJob.h
create mode 100644 lib/base/XBase.cpp
create mode 100644 lib/base/XBase.h
create mode 100644 lib/client/CClient.cpp
create mode 100644 lib/client/CClient.h
create mode 100644 lib/client/CServerProxy.cpp
create mode 100644 lib/client/CServerProxy.h
create mode 100644 lib/client/Makefile.am
create mode 100644 lib/client/Makefile.win
create mode 100644 lib/common/BasicTypes.h
create mode 100644 lib/common/IInterface.h
create mode 100644 lib/common/MacOSXPrecomp.h
create mode 100644 lib/common/Makefile.am
create mode 100644 lib/common/Makefile.win
create mode 100644 lib/common/Version.cpp
create mode 100644 lib/common/Version.h
create mode 100644 lib/common/common.h
create mode 100644 lib/common/stdbitset.h
create mode 100644 lib/common/stddeque.h
create mode 100644 lib/common/stdfstream.h
create mode 100644 lib/common/stdistream.h
create mode 100644 lib/common/stdlist.h
create mode 100644 lib/common/stdmap.h
create mode 100644 lib/common/stdostream.h
create mode 100644 lib/common/stdpost.h
create mode 100644 lib/common/stdpre.h
create mode 100644 lib/common/stdset.h
create mode 100644 lib/common/stdsstream.h
create mode 100644 lib/common/stdstring.h
create mode 100644 lib/common/stdvector.h
create mode 100644 lib/io/CStreamBuffer.cpp
create mode 100644 lib/io/CStreamBuffer.h
create mode 100644 lib/io/CStreamFilter.cpp
create mode 100644 lib/io/CStreamFilter.h
create mode 100644 lib/io/IStream.cpp
create mode 100644 lib/io/IStream.h
create mode 100644 lib/io/IStreamFilterFactory.h
create mode 100644 lib/io/Makefile.am
create mode 100644 lib/io/Makefile.win
create mode 100644 lib/io/XIO.cpp
create mode 100644 lib/io/XIO.h
create mode 100644 lib/mt/CCondVar.cpp
create mode 100644 lib/mt/CCondVar.h
create mode 100644 lib/mt/CLock.cpp
create mode 100644 lib/mt/CLock.h
create mode 100644 lib/mt/CMutex.cpp
create mode 100644 lib/mt/CMutex.h
create mode 100644 lib/mt/CThread.cpp
create mode 100644 lib/mt/CThread.h
create mode 100644 lib/mt/Makefile.am
create mode 100644 lib/mt/Makefile.win
create mode 100644 lib/mt/XMT.cpp
create mode 100644 lib/mt/XMT.h
create mode 100644 lib/mt/XThread.h
create mode 100644 lib/net/CNetworkAddress.cpp
create mode 100644 lib/net/CNetworkAddress.h
create mode 100644 lib/net/CSocketMultiplexer.cpp
create mode 100644 lib/net/CSocketMultiplexer.h
create mode 100644 lib/net/CTCPListenSocket.cpp
create mode 100644 lib/net/CTCPListenSocket.h
create mode 100644 lib/net/CTCPSocket.cpp
create mode 100644 lib/net/CTCPSocket.h
create mode 100644 lib/net/CTCPSocketFactory.cpp
create mode 100644 lib/net/CTCPSocketFactory.h
create mode 100644 lib/net/IDataSocket.cpp
create mode 100644 lib/net/IDataSocket.h
create mode 100644 lib/net/IListenSocket.cpp
create mode 100644 lib/net/IListenSocket.h
create mode 100644 lib/net/ISocket.cpp
create mode 100644 lib/net/ISocket.h
create mode 100644 lib/net/ISocketFactory.h
create mode 100644 lib/net/ISocketMultiplexerJob.h
create mode 100644 lib/net/Makefile.am
create mode 100644 lib/net/Makefile.win
create mode 100644 lib/net/TSocketMultiplexerMethodJob.h
create mode 100644 lib/net/XSocket.cpp
create mode 100644 lib/net/XSocket.h
create mode 100644 lib/platform/CMSWindowsClipboard.cpp
create mode 100644 lib/platform/CMSWindowsClipboard.h
create mode 100644 lib/platform/CMSWindowsClipboardAnyTextConverter.cpp
create mode 100644 lib/platform/CMSWindowsClipboardAnyTextConverter.h
create mode 100644 lib/platform/CMSWindowsClipboardBitmapConverter.cpp
create mode 100644 lib/platform/CMSWindowsClipboardBitmapConverter.h
create mode 100644 lib/platform/CMSWindowsClipboardHTMLConverter.cpp
create mode 100644 lib/platform/CMSWindowsClipboardHTMLConverter.h
create mode 100644 lib/platform/CMSWindowsClipboardTextConverter.cpp
create mode 100644 lib/platform/CMSWindowsClipboardTextConverter.h
create mode 100644 lib/platform/CMSWindowsClipboardUTF16Converter.cpp
create mode 100644 lib/platform/CMSWindowsClipboardUTF16Converter.h
create mode 100644 lib/platform/CMSWindowsDesks.cpp
create mode 100644 lib/platform/CMSWindowsDesks.h
create mode 100644 lib/platform/CMSWindowsEventQueueBuffer.cpp
create mode 100644 lib/platform/CMSWindowsEventQueueBuffer.h
create mode 100644 lib/platform/CMSWindowsKeyState.cpp
create mode 100644 lib/platform/CMSWindowsKeyState.h
create mode 100644 lib/platform/CMSWindowsScreen.cpp
create mode 100644 lib/platform/CMSWindowsScreen.h
create mode 100644 lib/platform/CMSWindowsScreenSaver.cpp
create mode 100644 lib/platform/CMSWindowsScreenSaver.h
create mode 100644 lib/platform/CMSWindowsUtil.cpp
create mode 100644 lib/platform/CMSWindowsUtil.h
create mode 100644 lib/platform/COSXClipboard.cpp
create mode 100644 lib/platform/COSXClipboard.h
create mode 100644 lib/platform/COSXClipboardAnyTextConverter.cpp
create mode 100644 lib/platform/COSXClipboardAnyTextConverter.h
create mode 100644 lib/platform/COSXClipboardTextConverter.cpp
create mode 100644 lib/platform/COSXClipboardTextConverter.h
create mode 100644 lib/platform/COSXClipboardUTF16Converter.cpp
create mode 100644 lib/platform/COSXClipboardUTF16Converter.h
create mode 100644 lib/platform/COSXEventQueueBuffer.cpp
create mode 100644 lib/platform/COSXEventQueueBuffer.h
create mode 100644 lib/platform/COSXKeyState.cpp
create mode 100644 lib/platform/COSXKeyState.h
create mode 100644 lib/platform/COSXScreen.cpp
create mode 100644 lib/platform/COSXScreen.h
create mode 100644 lib/platform/COSXScreenSaver.cpp
create mode 100644 lib/platform/COSXScreenSaver.h
create mode 100644 lib/platform/COSXScreenSaverUtil.h
create mode 100644 lib/platform/COSXScreenSaverUtil.m
create mode 100644 lib/platform/CSynergyHook.cpp
create mode 100644 lib/platform/CSynergyHook.h
create mode 100644 lib/platform/CXWindowsClipboard.cpp
create mode 100644 lib/platform/CXWindowsClipboard.h
create mode 100644 lib/platform/CXWindowsClipboardAnyBitmapConverter.cpp
create mode 100644 lib/platform/CXWindowsClipboardAnyBitmapConverter.h
create mode 100644 lib/platform/CXWindowsClipboardBMPConverter.cpp
create mode 100644 lib/platform/CXWindowsClipboardBMPConverter.h
create mode 100644 lib/platform/CXWindowsClipboardHTMLConverter.cpp
create mode 100644 lib/platform/CXWindowsClipboardHTMLConverter.h
create mode 100644 lib/platform/CXWindowsClipboardTextConverter.cpp
create mode 100644 lib/platform/CXWindowsClipboardTextConverter.h
create mode 100644 lib/platform/CXWindowsClipboardUCS2Converter.cpp
create mode 100644 lib/platform/CXWindowsClipboardUCS2Converter.h
create mode 100644 lib/platform/CXWindowsClipboardUTF8Converter.cpp
create mode 100644 lib/platform/CXWindowsClipboardUTF8Converter.h
create mode 100644 lib/platform/CXWindowsEventQueueBuffer.cpp
create mode 100644 lib/platform/CXWindowsEventQueueBuffer.h
create mode 100644 lib/platform/CXWindowsKeyState.cpp
create mode 100644 lib/platform/CXWindowsKeyState.h
create mode 100644 lib/platform/CXWindowsScreen.cpp
create mode 100644 lib/platform/CXWindowsScreen.h
create mode 100644 lib/platform/CXWindowsScreenSaver.cpp
create mode 100644 lib/platform/CXWindowsScreenSaver.h
create mode 100644 lib/platform/CXWindowsUtil.cpp
create mode 100644 lib/platform/CXWindowsUtil.h
create mode 100644 lib/platform/Makefile.am
create mode 100644 lib/platform/Makefile.win
create mode 100644 lib/platform/OSXScreenSaverControl.h
create mode 100644 lib/server/CBaseClientProxy.cpp
create mode 100644 lib/server/CBaseClientProxy.h
create mode 100644 lib/server/CClientListener.cpp
create mode 100644 lib/server/CClientListener.h
create mode 100644 lib/server/CClientProxy.cpp
create mode 100644 lib/server/CClientProxy.h
create mode 100644 lib/server/CClientProxy1_0.cpp
create mode 100644 lib/server/CClientProxy1_0.h
create mode 100644 lib/server/CClientProxy1_1.cpp
create mode 100644 lib/server/CClientProxy1_1.h
create mode 100644 lib/server/CClientProxy1_2.cpp
create mode 100644 lib/server/CClientProxy1_2.h
create mode 100644 lib/server/CClientProxy1_3.cpp
create mode 100644 lib/server/CClientProxy1_3.h
create mode 100644 lib/server/CClientProxyUnknown.cpp
create mode 100644 lib/server/CClientProxyUnknown.h
create mode 100644 lib/server/CConfig.cpp
create mode 100644 lib/server/CConfig.h
create mode 100644 lib/server/CInputFilter.cpp
create mode 100644 lib/server/CInputFilter.h
create mode 100644 lib/server/CPrimaryClient.cpp
create mode 100644 lib/server/CPrimaryClient.h
create mode 100644 lib/server/CServer.cpp
create mode 100644 lib/server/CServer.h
create mode 100644 lib/server/Makefile.am
create mode 100644 lib/server/Makefile.win
create mode 100644 lib/synergy/CClipboard.cpp
create mode 100644 lib/synergy/CClipboard.h
create mode 100644 lib/synergy/CKeyMap.cpp
create mode 100644 lib/synergy/CKeyMap.h
create mode 100644 lib/synergy/CKeyState.cpp
create mode 100644 lib/synergy/CKeyState.h
create mode 100644 lib/synergy/CPacketStreamFilter.cpp
create mode 100644 lib/synergy/CPacketStreamFilter.h
create mode 100644 lib/synergy/CPlatformScreen.cpp
create mode 100644 lib/synergy/CPlatformScreen.h
create mode 100644 lib/synergy/CProtocolUtil.cpp
create mode 100644 lib/synergy/CProtocolUtil.h
create mode 100644 lib/synergy/CScreen.cpp
create mode 100644 lib/synergy/CScreen.h
create mode 100644 lib/synergy/ClipboardTypes.h
create mode 100644 lib/synergy/IClient.h
create mode 100644 lib/synergy/IClipboard.cpp
create mode 100644 lib/synergy/IClipboard.h
create mode 100644 lib/synergy/IKeyState.cpp
create mode 100644 lib/synergy/IKeyState.h
create mode 100644 lib/synergy/IPlatformScreen.h
create mode 100644 lib/synergy/IPrimaryScreen.cpp
create mode 100644 lib/synergy/IPrimaryScreen.h
create mode 100644 lib/synergy/IScreen.cpp
create mode 100644 lib/synergy/IScreen.h
create mode 100644 lib/synergy/IScreenSaver.h
create mode 100644 lib/synergy/ISecondaryScreen.h
create mode 100644 lib/synergy/KeyTypes.cpp
create mode 100644 lib/synergy/KeyTypes.h
create mode 100644 lib/synergy/Makefile.am
create mode 100644 lib/synergy/Makefile.win
create mode 100644 lib/synergy/MouseTypes.h
create mode 100644 lib/synergy/OptionTypes.h
create mode 100644 lib/synergy/ProtocolTypes.cpp
create mode 100644 lib/synergy/ProtocolTypes.h
create mode 100644 lib/synergy/XScreen.cpp
create mode 100644 lib/synergy/XScreen.h
create mode 100644 lib/synergy/XSynergy.cpp
create mode 100644 lib/synergy/XSynergy.h
create mode 100644 win32util/autodep.cpp
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..ea648387
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+See doc/authors.html.
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..ce0fb161
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,286 @@
+Synergy is copyright (C) 2002-2007 Chris Schoeneman.
+Synergy is distributed under the following license.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE
+IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
+COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
+"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED
+TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY
+WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED
+ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT
+LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
+HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..5b101ca1
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,11453 @@
+2007/08/22 22:33:43 crs
+all.dsp
+ChangeLog
+cmd/exec.dsp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/launcher/Makefile.am
+cmd/launcher/nmake.mak
+cmd/synergyc/Makefile.am
+cmd/synergyc/nmake.mak
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.dsp
+cmd/synergyc/synergyc.rc
+cmd/synergys/Makefile.am
+cmd/synergys/nmake.mak
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.dsp
+cmd/synergys/synergys.rc
+COPYING
+dist/nullsoft/installer.dsp
+dist/nullsoft/installer.mak
+dist/nullsoft/Makefile.am
+dist/nullsoft/nmake.mak
+dist/nullsoft/synergy.nsi
+doc/authors.html
+lib/arch/arch.dsp
+lib/arch/CArchDaemonNone.cpp
+lib/arch/Makefile.am
+lib/arch/nmake.mak
+lib/base/base.dsp
+lib/base/Makefile.am
+lib/base/nmake.mak
+lib/client/client.dsp
+lib/client/Makefile.am
+lib/client/nmake.mak
+lib/common/common.dsp
+lib/common/Makefile.am
+lib/common/nmake.mak
+lib/io/io.dsp
+lib/io/Makefile.am
+lib/io/nmake.mak
+lib/mt/Makefile.am
+lib/mt/mt.dsp
+lib/mt/nmake.mak
+lib/net/CSocketMultiplexer.cpp
+lib/net/CTCPSocket.cpp
+lib/net/Makefile.am
+lib/net/net.dsp
+lib/net/nmake.mak
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CSynergyHook.cpp
+lib/platform/Makefile.am
+lib/platform/makehook.dsp
+lib/platform/nmake.mak
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/Makefile.am
+lib/server/nmake.mak
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+lib/synergy/Makefile.am
+lib/synergy/nmake.mak
+Makefile.am
+nmake.mak
+synergy.dsw
+synergy.xcode/project.pbxproj
+win32util/autodep.cpp
+
+Applied patch by maruel:
+- Fixed taking the address of begin() on an empty std::vector.
+- Fixed nsis makefile to use %ProgramFiles% environment variable.
+- Fixed nsis makefile to pass the output directory and file to makensis.
+- Fixed synergy.nsi to get the files from the output directory. That
+ enables a debug build of the installer.
+- Fixes to compile under VS2005.
+
+I did not apply VS2005 project files, instead adding nmake files. nmake is
+pretty weak but the makefiles can be modified without having visual studio.
+Also modified the .rc files to not use winres.h. This plus nmake means
+synergy can now be built using the freely downloadable Microsoft Windows
+SDK for Vista, available from microsoft's web site. This change removes
+all of the old VC++6 project files in favor of the nmake files. It also
+removes the XCode project in favor of ./configure and make.
+
+All of the nmake files are named nmake.mak. Only the top level makefile
+is directly useful (the rest are included by it) so all builds are from
+the top level directory. nmake knows the following targets:
+
+ all: build synergy.exe, synergyc.exe and synergys.exe
+ clean: remove all intermediate files, keep programs
+ clobber: clean and remove programs
+ installer: build programs and an installer
+ debug: build a debug version of 'all'
+ release: build a release version of 'all'
+ debug-installer: build an installer of the debug build
+ release-installer: build an installer of the release build
+
+The default build version is release so 'all' and 'installer' will build
+a release version. The installer itself never has debug symbols, just
+the stuff it installs. The default target is 'all'. To build use:
+
+ nmake /nologo /f nmake.mak
+
+VC++ and VisualStudio users may need to manually run vcvars.bat in a
+command.exe or cmd.exe window before invoking nmake. The Window 98/Me
+command.exe may not handle potentially long command lines; I haven't
+tried to verify if that works.
+
+----------
+2007/08/22 21:42:09 crs
+lib/platform/COSXKeyState.cpp
+
+Allow input scripts other than roman on OS X.
+
+----------
+2007/06/22 19:17:24 crs
+lib/platform/CXWindowsClipboard.cpp
+
+Applied patch 1731039. Fixes a bug in testing if X clipboard
+was owned at a given time.
+
+----------
+2006/04/02 12:16:23 crs
+lib/platform/CXWindowsKeyState.cpp
+
+Fixed non-XKB handling of Mode_switch. There were two problems.
+First the XkbLockGroup function was being called even for non-XKB
+layouts. (And was being included in the compile even if the XKB
+headers were not available!) Second, modifiers were assumed to
+exist only the group in which a keysym was found and when looking
+for modifiers for a key we only check modifiers in the same group.
+So keys that needed Mode_switch (in group 1) would check to see if
+Mode_switch was explictly mapped in group 1. It never is so that
+would never work. Now we handle implicitly mapped modifiers. I
+hadn't noticed this problem because my system (like most others)
+uses XKB and when I forced non-XKB, the keys I tested worked anyway
+through Multi_key.
+
+----------
+2006/04/01 22:25:33 crs
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+
+Fixed autorepeat on X11. Was autorepeating all keys sent from
+server. Now autorepeating only those keys which are locally
+configured in X to autorepeat.
+
+----------
+2006/04/01 21:37:24 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Fixed autorepeat on win32 clients. Was synthesizing a key release
+for each repeat. Win32 wants only repeat press events.
+
+----------
+2006/04/01 21:36:50 crs
+cmd/launcher/CScreensLinks.cpp
+
+Fixed two bugs in screens and link dialog. First, the link controls
+were not updated when reopening the dialog. Second, a change in any
+link edit control would be discarded if the user pressed enter.
+
+----------
+2006/04/01 21:35:10 crs
+cmd/launcher/CHotkeyOptions.cpp
+
+Fixed crash when creating a new hotkey but picking a key or mouse
+button combination before clicking OK.
+
+----------
+2006/04/01 21:30:43 crs
+configure.in
+lib/arch/CArchNetworkBSD.cpp
+lib/common/common.h
+
+Removed use of alloca() from unix and portable code. It's still
+in win32 code but i don't have to play guessing games about
+whether it's there or not on that platform.
+
+----------
+2006/04/01 17:53:27 crs
+synergy.xcode/project.pbxproj
+
+Added new files to Xcode project.
+
+----------
+2006/04/01 17:41:59 crs
+lib/client/CServerProxy.cpp
+lib/net/CTCPSocket.cpp
+lib/server/CClientProxy1_0.cpp
+
+Added more debugging output for network problems.
+
+----------
+2006/04/01 17:01:56 crs
+lib/platform/COSXKeyState.cpp
+
+Fixed keymapping on OSX. Was checking keyboard tables for all
+modifier combinations, including right-handed modifiers. It
+turns out OSX doesn't set up the tables correctly for those
+modifiers and acts if they have no effect. Since OSX never
+generates right-handed modifiers this isn't too surprising.
+
+----------
+2006/04/01 15:32:19 crs
+lib/server/CBaseClientProxy.cpp
+lib/server/CBaseClientProxy.h
+lib/server/CClientProxy.cpp
+lib/server/CClientProxy.h
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/Makefile.am
+lib/server/server.dsp
+
+Added new class to allow the server to keep information that every
+screen has. The first such info is the cursor position when last
+jumping from the screen. Using a hotkey to jump to a screen now
+puts the cursor where it was the last time the user jumped from
+that screen.
+
+----------
+2006/04/01 14:51:22 crs
+lib/server/CInputFilter.cpp
+
+Fixed bug in reloading configurations. Was losing hotkeys.
+
+----------
+2006/04/01 14:49:41 crs
+lib/platform/CXWindowsKeyState.cpp
+
+Fixed bug when recollecting the keyboard map on non-XKB keyboards.
+Wasn't reseting a key map. It's unlikely anyone ever hit this bug.
+
+----------
+2006/04/01 13:39:09 crs
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreenSaver.cpp
+
+Fixed several uses of CXWindowsUtil::CErrorLock that take a flag.
+Was checking the flag before destroying the lock object. That
+doesn't reliably work because the X protocol is asynchronous. The
+lock object ensures that the flag is correctly set in its d'tor by
+synchronizing with the server. The X11 hotkey (un)registration was
+one place where this was done. There were places in the X11
+screensaver and clipboard handling, too.
+
+----------
+2006/04/01 12:55:17 crs
+lib/synergy/CKeyState.cpp
+
+Fixed failure to clear the state of which keys are pressed in
+fakeAllKeysUp(). This fixes problems with synergy clients
+thinking some keys are still down, causing weird key behavior.
+
+----------
+2006/04/01 12:53:31 crs
+lib/common/Version.h
+
+Changed version to 1.3.1.
+
+----------
+2006/03/21 21:54:16 crs
+lib/platform/CXWindowsUtil.cpp
+
+Add all #defines for including keysyms that we use. The #defines in
+X11/keysym.h vary from platform to platform and cannot be relied on.
+
+----------
+2006/03/21 21:42:53 crs
+lib/common/Version.h
+
+Changed version to 1.3.0.
+
+----------
+2006/03/21 21:38:52 crs
+cmd/launcher/Makefile.am
+
+Added new files to makefile.
+
+----------
+2006/03/21 21:38:02 crs
+cmd/launcher/CAutoStart.cpp
+cmd/launcher/CAutoStart.h
+cmd/launcher/CHotkeyOptions.cpp
+cmd/launcher/CHotkeyOptions.h
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+cmd/synergyc/synergyc.dsp
+cmd/synergys/synergys.dsp
+lib/arch/arch.dsp
+lib/base/base.dsp
+lib/client/client.dsp
+lib/common/common.dsp
+lib/io/io.dsp
+lib/mt/mt.dsp
+lib/net/net.dsp
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/CConfig.cpp
+lib/server/CInputFilter.cpp
+lib/server/CInputFilter.h
+lib/server/server.dsp
+lib/synergy/IKeyState.cpp
+lib/synergy/IKeyState.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+lib/synergy/libsynergy.dsp
+
+Added a hot key dialog to the win32 launcher, providing full support
+for all features of hot keys. This required a bunch of small changes
+to CInputFilter and stuff used by it (mainly getter methods).
+
+The hot key dialog uses dynamic_cast<> to determine the kinds of
+conditions and actions for each rule in the configuration. This
+required enabling RTTI in the project files.
+
+Also changed the 'Start' button to start the synergy service if
+installed (i.e. synergy is configured to start when the computer
+starts).
+
+----------
+2006/03/21 21:37:59 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+
+Changed AltGr handling on win32. Previously the server would send
+ctrl and alt up events when sending a key that used AltGr then send
+matching down events. Now we just clear the ctrl and alt bits in
+the mask sent with the key; clients will temporarily release the
+ctrl and alt modifiers as necessary to yield the key. If the key
+doesn't need AltGr then the ctrl and alt bits are kept. We also
+used to reserve the right alt key for AltGr even if the keyboard
+layout didn't use it that way. This has been removed. The keyboard
+mapping now presses the ctrl and alt keys for AltGr rather than use
+the right alt.
+
+Also made getKeyID() a public method.
+
+----------
+2006/03/21 21:37:57 crs
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/COSXScreen.cpp
+lib/platform/CXWindowsScreen.cpp
+
+Improved log output when registering hot keys.
+
+----------
+2006/03/21 21:37:53 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Added "server" and "client" to synergy log windows.
+
+----------
+2006/03/21 21:37:52 crs
+lib/synergy/CKeyMap.cpp
+
+Fixed bug in keyboard mapping when releasing modifiers. This caused
+a problem with AltGr on win32. The left alt key was being
+(synthetically) released but it was the right alt key that was down.
+
+----------
+2006/03/21 21:37:49 crs
+doc/configuration.html
+
+Documentation fix.
+
+----------
+2006/03/20 23:13:11 crs
+doc/images/warp.gif
+
+Replaced animated GIF demonstrating cursor warp with one that
+doesn't show the cursor in the region between the monitors.
+This is the original GIF with frames removed. Supplied by
+user Brian A.
+
+----------
+2006/03/18 19:17:46 crs
+synergy.xcode/project.pbxproj
+
+Updated Xcode project to build universal binaries. The PPC build
+uses the 10.2.8 SDK while the i386 build uses the 10.4u SDK. Also
+removed the "Default" configuration; "Development" is now the
+default.
+
+----------
+2006/03/18 16:39:43 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+
+Improved handling of option key on OS X servers. Previously it
+was always treated as the super modifier. Now it's treated as
+AltGr if it generates a glyph, though AltGr is not sent to the
+clients. So if option+key produces a glyph then key is sent
+without the option or AltGr modifiers. If option+key does not
+produce a glpyh then option is sent as the super modifier.
+Note that combining an option+key combination that would produce
+a glyph with the command or control modifiers will cause it to
+not produce a glyph. In that case we send option as the super
+modifier and we send the glyph that would've been produced on
+the server had the option key not been pressed. So option+s
+sends the beta key id with no modifiers but command+option+s
+sends the "s" key id with the alt and super modifiers.
+
+This seems to handle the user expectations. However some users
+may expect option+L to produce win+L on win32 clients. These
+same users probably expect option+? to produce an upside down
+question mark. But these two expectations are fundamentally at
+odds. We cannot satisfy everyone because OS X doesn't have
+enough modifier keys.
+
+----------
+2006/03/18 13:20:18 crs
+lib/server/CInputFilter.cpp
+
+Fixed mousebutton condition. Wasn't working if num lock, caps lock
+or scroll lock was on.
+
+----------
+2006/03/18 12:05:34 crs
+lib/platform/CXWindowsScreen.cpp
+
+Applied patch from Jaco Kroon to fix a problem with mouse focus
+on X11.
+
+----------
+2006/03/18 11:54:40 crs
+doc/index.html
+
+Added support for index.html?child#anchor syntax. This will open
+the index.html page then child in the page frame and jump to anchor.
+
+----------
+2006/03/12 20:24:43 crs
+cmd/launcher/CAutoStart.cpp
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/synergyc.cpp
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/synergys.cpp
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchConsoleUnix.cpp
+lib/arch/CArchConsoleUnix.h
+lib/arch/CArchConsoleWindows.cpp
+lib/arch/CArchConsoleWindows.h
+lib/arch/CArchLogUnix.cpp
+lib/arch/CArchLogUnix.h
+lib/arch/CArchLogWindows.cpp
+lib/arch/CArchLogWindows.h
+lib/arch/IArchConsole.h
+lib/arch/IArchLog.h
+lib/base/CLog.cpp
+lib/base/ILogOutputter.h
+lib/base/LogOutputters.cpp
+lib/base/LogOutputters.h
+
+Added show() method to console and logs.
+
+----------
+2006/03/12 20:24:14 crs
+dist/nullsoft/synergy.nsi
+
+Updated windows installer to install new documentation pages and
+to put a shortcut on the desktop.
+
+----------
+2006/03/12 20:23:46 crs
+cmd/launcher/synergy.ico
+cmd/synergyc/synergyc.ico
+cmd/synergyc/tb_error.ico
+cmd/synergyc/tb_idle.ico
+cmd/synergyc/tb_run.ico
+cmd/synergyc/tb_wait.ico
+cmd/synergys/synergys.ico
+cmd/synergys/tb_error.ico
+cmd/synergys/tb_idle.ico
+cmd/synergys/tb_run.ico
+cmd/synergys/tb_wait.ico
+
+Updated icons on win32.
+
+----------
+2006/03/12 12:42:18 crs
+doc/configuration.html
+doc/faq.html
+doc/running.html
+doc/trouble.html
+
+More documentation fixes.
+
+----------
+2006/03/12 12:19:02 crs
+doc/configuration.html
+doc/faq.html
+doc/Makefile.am
+doc/toc.html
+doc/trouble.html
+
+Added a page with typical problems and solutions.
+
+----------
+2006/03/12 10:25:15 crs
+doc/tips.html
+
+More documentation fixes.
+
+----------
+2006/03/12 10:20:14 crs
+doc/about.html
+doc/configuration.html
+doc/faq.html
+
+Documentation fixes.
+
+----------
+2006/03/12 09:34:16 crs
+doc/toc.html
+
+Fixed link in table of contents.
+
+----------
+2006/03/11 15:01:00 crs
+doc/banner.html
+doc/border.html
+doc/index.html
+doc/synergy.css
+
+Adjusted how the border under the banner is drawn.
+
+----------
+2006/03/11 14:49:38 crs
+doc/images/logo.gif
+
+Updated logo.
+
+----------
+2006/03/11 14:42:00 crs
+doc/about.html
+doc/authors.html
+doc/autostart.html
+doc/banner.html
+doc/compiling.html
+doc/configuration.html
+doc/contact.html
+doc/developer.html
+doc/faq.html
+doc/history.html
+doc/home.html
+doc/images/logo.gif
+doc/images/warp.gif
+doc/index.html
+doc/license.html
+doc/Makefile.am
+doc/news.html
+doc/roadmap.html
+doc/running.html
+doc/security.html
+doc/synergy.css
+doc/tips.html
+doc/toc.html
+doc/todo.html
+
+Updated documentation pages. They're now the web site pages except
+they now use frames.
+
+----------
+2006/03/08 20:07:09 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CSynergyHook.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/server/CInputFilter.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+
+Added beginnings of support for synthesizing keystrokes on server's
+screen. It's partly implemented on win32; it just needs to track
+the modifier keys and adjust them as appropriate when synthesizing
+keys. It's not implemented on X11 or OS X. It's also currently
+disabled (in CPrimaryClient.cpp).
+
+----------
+2006/03/08 20:05:38 crs
+cmd/synergyc/CClientTaskBarReceiver.cpp
+cmd/synergyc/CClientTaskBarReceiver.h
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.rc
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CServerTaskBarReceiver.cpp
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.rc
+lib/arch/CArch.cpp
+lib/arch/CArchConsoleUnix.cpp
+lib/arch/CArchConsoleUnix.h
+lib/arch/CArchConsoleWindows.cpp
+lib/arch/CArchConsoleWindows.h
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/base/CLog.cpp
+lib/base/LogOutputters.cpp
+lib/base/LogOutputters.h
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/common/Version.cpp
+
+Replaced using win32 console for log with a dialog containing a rich
+edit control. The user can close this window without quiting synergy
+and can reopen the window using the tray icon menu. Also added menu
+items to switch the current logging level.
+
+----------
+2006/02/22 19:21:21 crs
+lib/platform/COSXScreen.cpp
+
+Removed bogus logging call.
+
+----------
+2006/02/20 19:46:47 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/LaunchUtil.h
+
+Fixed infinite loop of error dialogs in win32 launcher.
+
+----------
+2006/02/20 12:59:20 crs
+doc/faq.html
+
+Added firewall info to faq12. Added faq19, a discussion of not taking
+the foreground on win32.
+
+----------
+2006/02/20 12:46:18 crs
+doc/authors.html
+doc/autostart.html
+doc/compiling.html
+doc/configuration.html
+doc/developer.html
+doc/faq.html
+doc/history.html
+doc/index.html
+doc/license.html
+doc/news.html
+doc/running.html
+doc/security.html
+doc/tips.html
+doc/todo.html
+
+Changed !DOCTYPE to HTML 4.0 (from 3.2).
+
+----------
+2006/02/20 12:21:34 crs
+doc/configuration.html
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CInputFilter.cpp
+lib/server/CInputFilter.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+
+Hot key overhaul. Added support for multiple actions per hot key.
+Actions and conditions are now idempotent so they no longer track
+the active state (on, off, toggled, etc). Actions can be assigned
+to the activation or deactivation of a condition, basically a hot
+key or mouse button being pressed (activation) or released
+(deactivation). The keystroke and mousebutton actions map to both
+and the new keyDown, keyUp, mouseDown and mouseUp map to one or the
+other. The lock cursor to screen action now takes a mode: on, off
+or toggle and the corresponding event state is respected by the
+server. Removed the modifiers action. Mouse button actions now use
+the new kKeySetModifiers and kKeyClearModifiers keys to set/reset
+modifier state directly on the client.
+
+Conditions and actions are much simpler now that they're idempotent
+and so is CInputFilter. Refactored CRule into a class since there's
+now more to a rule than a condition and action.
+
+----------
+2006/02/20 11:29:41 crs
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+lib/synergy/CKeyState.cpp
+
+Added support for kKeySetModifiers and kKeyClearModifiers keys.
+The former activates the given modifiers and the latter deactivates
+them.
+
+----------
+2006/02/20 11:25:44 crs
+lib/synergy/KeyTypes.h
+
+Added special keys for setting/clearing modifiers. The intent
+is to use these to set/reset modifiers for mouse button hot key
+actions.
+
+----------
+2006/02/19 21:01:08 crs
+lib/platform/COSXScreen.cpp
+
+Fixed OS X to send current keyboard modifiers with mouse button events.
+
+----------
+2006/02/19 13:26:54 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+
+Fixed two clipboard problems.
+
+First, synergy would blow an assert given the following sequence
+of events:
+ enter client screen A
+ A takes clipboard
+ enter server screen B
+ B takes clipboard
+ clipboard on A changes (while we're not on the screen)
+ enter A
+ enter B
+On entering B we find that the clipboard sender is not the owner
+of the clipboard. This is because when A changed the clipboard
+while we were on B, B ignored the grab from A. A now thinks it
+owns the clipboard (even though B does). So when we leave A the
+second time, it sends the clipboard (which contains what B sent
+it) to B. The assertion is blown because B owns the clipboard
+but A sends a clipboard with a valid sequence number. The fix
+is simply that clients must reset their internal clipboard
+ownership flag when told to set the clipboard by the server.
+
+Second, synergy clients would fail to send the clipboard to the
+server given the following sequence of events:
+ enter client A
+ A takes the clipboard
+ enter screen B
+ B takes the clipboard
+ enter A
+ A takes the clipboard with the same contents as before
+In an effort to reduce bandwidth, clients don't send unchanged
+clipboard contents. Clients were incorrectly treating this
+case as unchanged contents when, in fact, the contents are those
+set by B not those of A. Clients now handle this case.
+
+----------
+2006/02/19 13:13:55 crs
+lib/server/CServer.cpp
+
+Fixed error in log message. Was trying to report the sender of
+a clipboard but was reporting the owner of the clipboard.
+
+----------
+2006/02/16 22:12:37 crs
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+
+Added a hack to work around how VMware handles modifier keys on X11
+when a virtual machine has focus. VMware removes all of the modifier
+mappings so synergy doesn't know about any modifiers. The hack is to
+use the last known good modifiers when there aren't any active
+modifiers.
+
+----------
+2006/02/14 18:10:12 crs
+lib/server/CServer.cpp
+
+Made switch in direction hot keys use the cursor's current position
+when calculating what the neighbor is. This only affects layouts
+using fractional edges.
+
+----------
+2006/02/12 16:49:16 crs
+synergy.xcode/project.pbxproj
+
+Updated Xcode project.
+
+----------
+2006/02/12 16:40:02 crs
+doc/configuration.html
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/KeyTypes.cpp
+
+Removed onCommandKey() from server. This was used only for handling
+the ScrollLock key to lock the cursor to the screen but this has been
+obsoleted by the hotkey support for locking the cursor. Also,
+ScrollLock is now only added as a hotkey to lock the cursor if the
+user hasn't configured some other hotkey to lock the cursor.
+
+----------
+2006/02/12 16:22:41 crs
+doc/configuration.html
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CInputFilter.cpp
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/IKeyState.cpp
+lib/synergy/IKeyState.h
+
+Added support for directing hotkey key actions to a particular screen
+or screens or to broadcast to all screens. However, key action
+keystrokes are never sent to the server screen. This should be fixed.
+
+----------
+2006/02/12 16:16:11 crs
+doc/configuration.html
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+lib/synergy/KeyTypes.cpp
+lib/synergy/KeyTypes.h
+lib/synergy/libsynergy.dsp
+lib/synergy/Makefile.am
+lib/synergy/mkspecialkeynames.pl
+lib/synergy/SpecialKeyNameMap.h
+
+Moved and restructed key name maps. Also added names for all
+non-alphanumeric ASCII characters and added support for \uXXXX
+unicode character codes.
+
+----------
+2006/02/12 14:47:23 crs
+lib/synergy/CKeyState.cpp
+
+Now allowing fake key presses from server with a server button ID
+of 0. Hot keys that synthesize key events use a server button ID
+of 0. Note that other code will prevent a client from processing
+a hotkey press while another hotkey is pressed. The nature of
+hotkeys should ensure that never happens except for modifier only
+hotkeys. Worry about that later.
+
+----------
+2006/02/12 12:06:50 crs
+lib/platform/COSXScreen.cpp
+
+Fixed 2 axis scrolling on OS X.
+
+----------
+2006/02/12 11:53:35 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CServerProxy.cpp
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxy1_3.cpp
+lib/server/CClientProxy1_3.h
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IClient.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+lib/synergy/ISecondaryScreen.h
+lib/synergy/ProtocolTypes.cpp
+lib/synergy/ProtocolTypes.h
+
+Added support for horizontal scrolling.
+
+----------
+2006/02/12 10:08:49 crs
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Applied patch from stkamp@users.sf.net that clamps mouse positions
+to valid areas on OS X. It also improves using the local keyboard
+with the remote mouse on OS X.
+
+----------
+2006/02/11 20:01:42 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/CMSWindowsScreen.cpp
+
+Fixed synthesis of ctrl+alt+del and handling of AltGr on win32
+client.
+
+----------
+2006/02/11 20:00:32 crs
+lib/server/server.dsp
+
+Added CClientProxy1_3 to project.
+
+----------
+2006/02/06 19:27:45 crs
+lib/server/CConfig.cpp
+
+Fixed handling of comments when parsing the configuration.
+Had changed leading whitespace stripping which broke it.
+
+----------
+2006/02/05 19:42:55 crs
+synergy.xcode/project.pbxproj
+
+Updated Xcode project.
+
+----------
+2006/02/05 18:48:35 crs
+lib/server/CClientProxy1_3.cpp
+
+Fixed warning.
+
+----------
+2006/02/05 18:02:47 crs
+lib/server/CInputFilter.cpp
+
+Fixed updates of input filters when configuration is changed.
+
+----------
+2006/02/05 17:55:45 crs
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_3.cpp
+
+More fixes for server side keep alives.
+
+----------
+2006/02/05 17:55:19 crs
+lib/server/CServer.cpp
+
+Fixed sending of options to client. Wasn't reseting options first.
+
+----------
+2006/02/05 17:39:20 crs
+lib/client/CServerProxy.cpp
+
+Fixed memory bug in releasing keep alive timer.
+
+----------
+2006/02/05 17:36:17 crs
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxy1_3.cpp
+lib/server/CClientProxy1_3.h
+lib/server/CClientProxyUnknown.cpp
+
+Fixed server side handling of keep alives.
+
+----------
+2006/02/05 17:34:14 crs
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+
+Fixed client side handling of keep alives.
+
+----------
+2006/02/05 16:56:00 crs
+lib/synergy/ProtocolTypes.h
+
+Added comment for protocol version 1.3.
+
+----------
+2006/02/05 16:54:39 crs
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxy1_3.cpp
+lib/server/CClientProxy1_3.h
+lib/server/Makefile.am
+lib/synergy/ProtocolTypes.cpp
+lib/synergy/ProtocolTypes.h
+
+Deprecated heartbeat and added keep alive to replace it. While a
+heartbeat was generated by clients and sent to the server, a keep
+alive is sent from the server and echoed by the client. This
+checks both directions of the connection. Either side will hang
+up if the other hasn't been heard from in a reasonable amount of
+time. This fixes a problem where clients would not hang up on
+an unavailable server.
+
+----------
+2006/02/05 16:29:01 crs
+cmd/launcher/Makefile.am
+
+Added CInfo files to makefile.
+
+----------
+2006/02/05 15:30:49 crs
+lib/synergy/CKeyState.cpp
+
+Fixed handling of modifier keys that are held down while leaving
+a client screen. Was correctly releasing those keys on the client
+but wasn't reseting the active modifier state so as soon as a key
+was pressed after reentering the client the modifiers were
+reactivated. However, the user could only see the problem by
+typing on the local keyboard because the modifier was correctly
+adjusted for keys from the server. Now reseting modifier state
+when leaving a client screen.
+
+----------
+2006/02/05 14:47:59 crs
+cmd/launcher/CInfo.cpp
+cmd/launcher/CInfo.h
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/LaunchUtil.h
+cmd/launcher/resource.h
+
+Added two features to the win32 launcher. First there's now a
+info dialog which reports some useful information. The other is
+that configuration files are now re-read when the application is
+activated and the file's modification time has changed. This
+should help when users are hand editing the configuration file
+while the launcher is running.
+
+----------
+2006/02/05 14:45:39 crs
+lib/server/CConfig.cpp
+
+Fixed a bug in writing configuration files with fractional edges.
+
+----------
+2006/02/05 14:43:17 crs
+cmd/launcher/CAddScreen.cpp
+cmd/launcher/CScreensLinks.cpp
+cmd/launcher/CScreensLinks.h
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+doc/configuration.html
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+
+Added support for fractional edge links. This allows users to
+configure a portion of an edge to map to a portion of another
+edge, rather than linking entire edges. This does not allow
+users to split a (presumably multimonitor) screen to allow
+switching on reaching an interior edge.
+
+----------
+2006/02/01 21:34:28 crs
+lib/synergy/CKeyMap.cpp
+
+Fixed parsing of modifier plus single character keystroke and
+mousebutton entries in the configuration. Was discarding single
+characters.
+
+----------
+2006/02/01 21:20:46 crs
+lib/platform/COSXKeyState.cpp
+
+Fixed OS X keypad enter key.
+
+----------
+2006/01/29 20:50:54 crs
+lib/server/CConfig.cpp
+lib/server/CInputFilter.cpp
+lib/server/CInputFilter.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+
+Added support for performing an action when a screen connects.
+Also added support for jumping to the screen that just connected.
+The line 'connect() = switchToScreen()' in the global options will
+cause the cursor to jump to a screen as soon as it connects. This
+isn't especially useful but serves as an example.
+
+----------
+2006/01/29 19:56:31 crs
+lib/platform/CXWindowsScreen.cpp
+
+Fixed X11 hot key grabbing. Previously was sensitive to CapsLock,
+NumLock and ScrollLock and is now insensitive to all of those.
+
+----------
+2006/01/29 17:54:08 crs
+lib/platform/COSXScreen.cpp
+
+Changed input suppress delay to 0. This might be right or it
+might need to be a small positive value like 0.1.
+
+----------
+2006/01/29 15:52:44 crs
+lib/server/CConfig.h
+lib/server/CInputFilter.cpp
+lib/server/CInputFilter.h
+lib/server/CServer.cpp
+
+Fixed support for ScrollLock to lock the cursor to the screen.
+It now works via the hotkey mechanism.
+
+----------
+2006/01/29 15:51:59 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+
+Fixed failure to run on win95 family. Was linked against
+ToUnicodeEx which is not available on that family. Now looking
+up that symbol at run time.
+
+----------
+2006/01/29 15:50:29 crs
+lib/platform/COSXScreen.cpp
+
+Fixed minor bug in call to CGSetLocalEventsSuppressionInterval.
+
+----------
+2006/01/29 13:26:48 crs
+lib/platform/CSynergyHook.cpp
+
+Win32 reports VK_RSHIFT as an extended key, which it is not.
+We now correct this which fixes the right shift key when using
+win32 servers.
+
+----------
+2006/01/29 12:47:31 crs
+lib/synergy/CKeyMap.cpp
+
+Fixed handling of modifiers when synthesizing a modifier. We
+were previously trying to match the desired modifier state
+when synthesizing any key, even if some of those modifiers
+weren't required (i.e. the key was insensitive to the state
+of some of those modifiers). We no longer try to match the
+state of non-required modifiers because doing so can break
+the synthesis of some keys, particularly modifiers. For
+example, previously pressing Control with NumLock on would
+turn NumLock off, press Control, then turn NumLock back on.
+If this Control was used with Alt on win32 to effect AltGr
+then AltGr would not take effect. On X11 the Shift key was
+improperly combined with NumLock, causing mouse keys to take
+effect.
+
+----------
+2006/01/29 12:37:30 crs
+lib/common/Version.h
+
+Changed to version 1.2.8.
+
+----------
+2005/12/18 18:00:56 crs
+synergy.xcode/project.pbxproj
+
+Added new files to xcode project.
+
+----------
+2005/12/18 17:35:57 crs
+doc/configuration.html
+doc/news.html
+
+More documentation for 1.2.7.
+
+----------
+2005/12/18 16:51:52 crs
+doc/news.html
+
+Fixed error in documentation.
+
+----------
+2005/12/18 16:15:42 crs
+lib/platform/CSynergyHook.cpp
+
+Removed use of function from C standard library in the hook DLL.
+
+----------
+2005/12/18 16:11:15 crs
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Added workaround for not receiving drag events for any mouse buttons
+besides 1 and 2 (left and right). That appears to be a limitation
+of the OS so we simply start polling the position while any buttons
+besides 1 and 2 are down. Code based on a patch by Brian Kendall.
+
+----------
+2005/12/18 15:29:25 crs
+lib/common/Version.h
+
+Changed version to 1.2.7.
+
+----------
+2005/12/18 15:12:39 crs
+lib/platform/COSXKeyState.cpp
+
+Fixed mapping of unicode key layouts. Was discarding some
+characters (backspace and return, in particular) that should
+not have been discarded.
+
+----------
+2005/12/18 10:49:23 crs
+cmd/launcher/launcher.rc
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CInputFilter.cpp
+lib/server/CInputFilter.h
+lib/server/CServer.cpp
+lib/server/server.dsp
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+lib/synergy/IKeyState.cpp
+lib/synergy/IKeyState.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+lib/synergy/libsynergy.dsp
+lib/synergy/SpecialKeyNameMap.h
+synergy.dsw
+
+Added support for hot keys on win32. Also fixed memory leaks in
+CInputFilter and changed CConfig to write hot keys in its
+CInputFilter object to the options section.
+
+----------
+2005/12/15 18:57:38 crs
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Fixed hot keys on OS X when on a secondary screen. This worked
+in the original patch but broken during the modify/merge. It
+was broken because we turn off all hot key processing by the OS
+while on a secondary screen. The fix is to check on key press
+and release if the key and modifier state matches a hot key.
+
+This is known to be broken on hot key release if you press the
+hot key then change the modifiers before releasing the provoking
+key.
+
+----------
+2005/12/14 21:51:01 crs
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+
+Added support for hotkeys on X11.
+
+----------
+2005/12/14 21:50:49 crs
+lib/server/CServer.cpp
+
+When jumping to another screen was computing the center using the
+size of the active screen instead of the size of the destination
+screen.
+
+----------
+2005/12/14 21:50:09 crs
+lib/server/CConfig.cpp
+
+Switched to ctype.h from cctype to fix linux build.
+
+----------
+2005/12/14 09:33:25 crs
+lib/base/CLog.cpp
+lib/base/CLog.h
+lib/base/CStringUtil.cpp
+lib/base/CStringUtil.h
+
+Fixed bug in CStringUtil::vsprint. Was reusing va_list across
+calls to vnsprintf, which is not allowed. Modified CStringUtil
+and CLog to avoid doing that. This should fix a crash when
+using --help on some platforms. Tthe --help message was the
+only message long enough to exceed the static buffer length
+which caused a va_list to get reused.
+
+----------
+2005/12/14 08:43:36 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CInputFilter.cpp
+lib/server/CInputFilter.h
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/Makefile.am
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+lib/synergy/Makefile.am
+lib/synergy/mkspecialkeynames.pl
+lib/synergy/SpecialKeyNameMap.h
+
+Checkpoint of configurable hotkey support. Authored by Lorenz
+Schori, modified and merged by me. Hotkeys are only implemented
+on OS X so far; this change breaks the build on linux and win32.
+
+----------
+2005/11/29 21:22:02 crs
+lib/platform/CXWindowsKeyState.cpp
+
+Fixed bug in X11 keyboard code. Wasn't checking for a NULL pointer.
+
+----------
+2005/11/28 22:12:49 crs
+doc/running.html
+
+Added a little more detail to the documentation for for OS X users
+not familiar with the shell.
+
+----------
+2005/11/28 20:59:39 crs
+doc/autostart.html
+
+Added X11 autostart info for kdm.
+
+----------
+2005/11/27 16:41:06 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CSynergyHook.cpp
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyState.cpp
+
+Fixed several win32 keyboard bugs.
+
+----------
+2005/11/27 16:30:50 crs
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+
+Fixed a couple of problems with key event synthesis.
+
+----------
+2005/11/25 18:19:28 crs
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+
+Now sending a more significant fake mouse motion to xscreensaver
+to keep it from activating. xscreensaver since 2.21 requires a
+motion of at least 10 pixels to be considered significant.
+
+----------
+2005/11/25 14:42:30 crs
+lib/platform/COSXClipboard.cpp
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Added periodic check for clipboard change on OS X. We're polling
+because there doesn't seem to be any event to notify of a clipboard
+change.
+
+----------
+2005/11/24 11:00:39 crs
+cmd/launcher/launcher.cpp
+
+Fixed bug in win32 GUI. If synergy wasn't previously installed for
+autostart then the GUI would incorrectly install it for autostart.
+It was incorrectly installed in such a way that synergy would think
+it wasn't installed and it would not function when the service
+manager tried to start it.
+
+----------
+2005/11/20 22:34:06 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/CXWindowsScreen.cpp
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.cpp
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.h
+
+Converted OS X to new keyboard handling. Two known problems
+with OS X: the thorn character is mapped incorrectly (because
+OS X lies) and we're using every keyboard layout, not just the
+enabled one, because we have no idea how to detect if a layout
+is enabled or not. The latter problem only causes some startup
+slowness.
+
+----------
+2005/11/20 22:29:01 crs
+configure.in
+lib/arch/CMultibyte.cpp
+
+Added support for converting clipboard data to Latin-1 encoding
+if the default encoding is ASCII by switching to the en_US locale
+at startup.
+
+----------
+2005/11/14 18:35:07 crs
+lib/synergy/CKeyState.h
+
+Removed unnecessary headers.
+
+----------
+2005/11/13 17:08:45 crs
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+
+Added improved support for key combinations intended to perform a
+keyboard shortcut rather than synthesize a particular key.
+
+----------
+2005/11/13 12:52:16 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+
+Finished X11 non-XKB keyboard mapping. Also added a convenience
+function to CKeyMap used by both the X11 and win32 implemenetations.
+
+----------
+2005/11/13 10:31:32 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsUtil.cpp
+lib/platform/CXWindowsUtil.h
+lib/synergy/CKeyMap.cpp
+lib/synergy/CKeyMap.h
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.cpp
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/KeyTypes.h
+lib/synergy/libsynergy.dsp
+lib/synergy/Makefile.am
+
+Checkpointing keyboard handling refactoring. This is a major change
+to the client side handling of key events. This change converts the
+X11 and win32 handling but not the OS X handling.
+
+The new class CKeyMap contains the information necessary to convert
+a synergy key event to the platform events necessary to synthesize
+the key. Platforms fill in a CKeyMap whenever their keyboard layouts
+change using the addKeyEntry(), calling it once for each unique way
+to synthesize a particular KeyID on the keyboard. The CKeyMap takes
+it from there, first adding dead-key combinations and some other keys,
+then doing the translation from KeyID to platform keystroke sequences.
+Platforms no longer need to implement the KeyID to keystroke sequence
+conversion, simplifying the platform implementations.
+
+This change also supports multiple keyboard layouts, typically used
+to support various languages. If a key is not available on the active
+layout but is on a different installed layout then synergy will switch
+layouts automatically.
+
+The X11 version now fully supports the XKB extension. This should fix
+problems with Mode_switch vs ISO_Level3_Shift. Non-XKB support is
+incomplete in this checkpoint.
+
+----------
+2005/11/12 11:43:54 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Disabled code to periodically reinstall synergy in the clipboard
+chain. It was causing an infinite recursion in the WM_DRAWCLIPBOARD
+message handler.
+
+----------
+2005/11/12 11:28:25 crs
+lib/platform/CMSWindowsScreenSaver.cpp
+
+Changed a couple of logging messages to DEBUG2 from DEBUG.
+
+----------
+2005/11/12 11:27:55 crs
+cmd/launcher/CAutoStart.cpp
+cmd/launcher/CAutoStart.h
+cmd/launcher/launcher.cpp
+
+Fixed saving of autostart configuration in win32 launcher. It
+was erroring out when the user did not have permission to write
+to that portion of the registry. Now it will only write the
+configuration if synergy is installed for autostart. This is
+still not quite right since it'll still error out if some other
+user with sufficient permission has installed the autostart and
+this user doesn't have enough permission.
+
+----------
+2005/11/12 11:22:34 crs
+lib/common/Version.h
+
+Changed version to 1.2.6.
+
+----------
+2005/11/01 19:58:21 crs
+acinclude.m4
+
+Restored pthread signal configuration checks accidentally removed
+in previous version.
+
+----------
+2005/10/12 21:37:58 crs
+doc/running.html
+
+Updated setup documentation.
+
+----------
+2005/10/11 21:12:18 crs
+lib/arch/CArchMultithreadPosix.cpp
+
+Fixed warning in posix multithread code.
+
+----------
+2005/10/11 20:59:29 crs
+acinclude.m4
+
+Updated autoconf script for detecting pthreads.
+
+----------
+2005/10/06 21:45:01 crs
+configure.in
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+
+Added initial XKB code. This only checks for the extension in
+the configuration, queries the extension at runtime and handles
+mapping notify events. Still need to use the extension to get
+the keyboard map.
+
+----------
+2005/10/02 17:40:56 crs
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsClipboard.h
+lib/platform/CXWindowsUtil.cpp
+lib/platform/CXWindowsUtil.h
+
+Fixed X11 clipboard handling on 64-bit systems. Also fixed a
+problem with detecting when a clipboard owner says a format is
+unavailable.
+
+----------
+2005/10/01 19:26:57 crs
+lib/server/CServer.cpp
+
+Fixed unnecessary comparison to NULL that chokes some compilers.
+
+----------
+2005/10/01 19:23:38 crs
+cmd/launcher/CAdvancedOptions.cpp
+cmd/launcher/CAutoStart.cpp
+cmd/launcher/CAutoStart.h
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+dist/nullsoft/synergy.nsi
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CSynergyHook.cpp
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.cpp
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.h
+
+Fixed several win32 bugs. Removed the 'Save' button from the
+launcher; configuration is now saved transparently. Autostart
+configuration is now saved transparently whenever it changes
+and autostart is enabled. Configuration is now saved when the
+debug logging level changes.
+
+Now releasing synthetically pressed keys when leaving the client.
+The existing code was checking for key down using a local key
+button id then trying to release it using the same id as a server
+key button id.
+
+Now looking up a local button id for key events that have a scan
+code of 0. These are sent by some programs that synthesize events.
+
+Now periodically reinstalling the clipboard chain viewer. It appears
+that the chain is breaking sometimes (probably due a badly behaved
+or killed app) but there's no way to detect that so this is a
+workaround.
+
+Now stopping and deleting the autostart services during uninstall.
+
+----------
+2005/10/01 18:55:59 crs
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Added support for apple's mighty mouse. We now correctly handle
+button 4 (and 5 if it exists). We now detect the mighty mouse's
+scroll ball and convert vertical motion into scroll wheel events.
+Also changed handling of scroll wheel scaling; the mac works
+differently from other platforms so it's not perfect.
+
+----------
+2005/10/01 15:01:15 crs
+cmd/launcher/Makefile.am
+
+Added new files to makefiles.
+
+----------
+2005/09/26 20:58:53 crs
+lib/server/CConfig.cpp
+
+Fixed bug in output of configuration files. Was writing bottom-right
+corner as "bottom-left" instead of "bottom-right".
+
+----------
+2005/09/26 20:55:24 crs
+cmd/launcher/CAddScreen.cpp
+cmd/launcher/CAddScreen.h
+cmd/launcher/CScreensLinks.cpp
+cmd/launcher/CScreensLinks.h
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Refactored code in win32 launcher GUI.
+
+----------
+2005/08/22 19:40:34 crs
+lib/common/Version.h
+
+Changed version to 1.2.5.
+
+----------
+2005/08/07 10:32:54 crs
+doc/autostart.html
+
+Updated OS X autostart documentation.
+
+----------
+2005/08/07 10:32:19 crs
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/IArchMultithread.h
+
+Added support for SIGUSR2. Not using it yet, though.
+
+----------
+2005/08/03 21:03:49 crs
+cmd/synergyc/synergyc.cpp
+
+Client now quits after failing to connect if not restartable.
+Was failing to quit.
+
+----------
+2005/08/03 20:14:42 crs
+cmd/synergyc/Makefile.am
+cmd/synergys/Makefile.am
+configure.in
+lib/arch/Makefile.am
+lib/platform/Makefile.am
+
+Changed how we export MACOSX_DEPLOYMENT_TARGET to a hopefully more
+portable solution.
+
+----------
+2005/08/02 21:42:12 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Fixed --daemon fix when compiled on unix.
+
+----------
+2005/08/02 20:57:52 crs
+cmd/launcher/CGlobalOptions.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsScreen.cpp
+lib/server/CConfig.cpp
+lib/synergy/OptionTypes.h
+
+Added option to suppress grabbing of the foreground window on win32
+synergy servers. Grabbing the foreground window prevents certain
+apps from messing up low level keyboard events but doing that can
+break certain workflow, particularly with games. Since the option
+is only for win32 and it's in the launcher GUI and I hope to get rid
+of it someday, there is no configuration documentation for it.
+
+----------
+2005/08/02 20:55:35 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Fixed '--daemon' command line option on Windows NT family client and
+server. Those platforms now ignore --daemon and --no-daemon like
+they should.
+
+----------
+2005/08/01 22:34:05 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/server/CPrimaryClient.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.cpp
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.h
+
+Fixed scroll-lock screen locking on linux servers. An earlier
+change made the function that returns modifier state return the
+shadowed state not the current state. On X windows we don't
+shadow the state when on the primary screen so the synergy server
+would never see the scroll-lock state turned on until it left the
+primary screen. As a result scroll-lock would not lock to the
+primary screen but would lock you to whatever secondary screen
+you ended up on.
+
+Changed win32 and OSX versions to work like the linux version.
+Win32 used to work anyway because we constantly shadow keyboard
+state on that. OSX did not query current keyboard state at all
+before and it still doesn't; this needs to be fixed.
+
+----------
+2005/08/01 22:29:48 crs
+lib/synergy/libsynergy.dsp
+
+Added ProtocolTypes.cpp to VC++ project.
+
+----------
+2005/08/01 21:02:07 crs
+lib/common/common.h
+synergy.xcode/project.pbxproj
+
+Changes to get gcc3.3, 10.2.8 SDK builds working on OS X.
+
+----------
+2005/07/31 22:50:10 crs
+configure.in
+lib/platform/COSXScreenSaver.cpp
+lib/platform/COSXScreenSaver.mm
+lib/platform/COSXScreenSaverUtil.h
+lib/platform/COSXScreenSaverUtil.m
+lib/platform/Makefile.am
+
+Removed Objective-C++ file. Now using an Objective-C file instead
+which works better with autoconf/automake.
+
+----------
+2005/07/31 22:49:03 crs
+lib/synergy/Makefile.am
+lib/synergy/ProtocolTypes.cpp
+lib/synergy/ProtocolTypes.h
+
+Fixed warnings on gcc 4.0.
+
+----------
+2005/07/31 22:48:30 crs
+lib/common/Version.h
+
+Changed version to 1.2.4.
+
+----------
+2005/07/26 21:37:41 crs
+lib/common/Version.h
+
+Changed version to 1.2.3.
+
+----------
+2005/07/26 21:37:27 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+
+Now disabling the win32 foreground window on the server when
+leaving the server screen. This prevents the system from
+messing up keyboard events. The console (command prompt) and
+remote desktop are known to interfere with the shift key when
+they have the focus. This introduces a bug where the window
+that was the foreground is raised to the top of the stacking
+order when the cursor enters the server screen. This should
+only be a problem for Mouse-X (activation follows mouse) users.
+I don't know how Mouse-X changes the foreground/active window
+without raising it; if I did I'd fix this bug.
+
+----------
+2005/07/26 21:24:13 crs
+doc/configuration.html
+
+Fixed typo in documentation.
+
+----------
+2005/07/26 19:58:37 crs
+cmd/launcher/launcher.cpp
+
+Now defaulting to WARNING as the default debug level on win32.
+This is a workaround for NOTE and higher always popping up the
+command window, which can't be hidden or closed. When the
+user clicks 'Test', the debug level is forced to be at least
+INFO to workaround this workaround. Future versions will do
+away with the command window altogether so this weirdness isn't
+too much of a problem.
+
+----------
+2005/07/26 19:50:44 crs
+doc/faq.html
+doc/tips.html
+
+Improved documentation of how to get ctrl+alt+pause working on
+Windows NT,2k,XP.
+
+----------
+2005/07/21 21:25:51 crs
+lib/common/common.h
+
+Forcing use of select() rather than poll() on OS X. Wasn't
+getting a read event on a socket when the remote side closed
+down when using poll(). Probably a bug in synergy code but
+I couldn't find it.
+
+----------
+2005/07/21 21:24:28 crs
+lib/arch/CArchNetworkBSD.cpp
+
+Fixed "resource temporarily unavailable" exception on OS X when
+using the unblock pipe.
+
+----------
+2005/07/20 22:09:05 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+cmd/synergys/synergys.cpp
+doc/configuration.html
+lib/client/CClient.cpp
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/OptionTypes.h
+
+Added "dead" corners support. The cursor can't switch screens
+from a dead corner.
+
+----------
+2005/07/19 20:43:51 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+
+Applied patch (from Lorenz Schori) to fix getting the keyboard
+layout. It previously was failing for non-Apple keyboards.
+
+----------
+2005/07/19 20:23:29 crs
+lib/platform/COSXKeyState.cpp
+
+Replaced NULL with 0 in arithmetic expression.
+
+----------
+2005/05/08 11:40:26 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Applied patch 1113363 to support the kanji key on win32.
+
+----------
+2005/05/08 11:08:12 crs
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/arch/CArchNetworkWinsock.cpp
+lib/arch/CArchNetworkWinsock.h
+lib/arch/IArchNetwork.h
+lib/net/CTCPListenSocket.cpp
+
+Added support for SO_REUSEADDR. It is always enabled.
+
+----------
+2005/05/08 11:00:42 crs
+cmd/synergys/synergys.cpp
+
+Fixed bug in retrying to initialize or start the server. Was
+waiting the retry interval then doing nothing.
+
+----------
+2005/04/29 21:27:10 crs
+lib/common/common.h
+lib/platform/COSXScreen.cpp
+synergy.xcode/project.pbxproj
+
+A few OSX build fixes.
+
+----------
+2005/04/28 22:05:51 crs
+lib/common/common.h
+
+Now setting HAVE_SOCKLEN_T to 1 when on OSX and _SOCKLEN_T is
+defined and HAVE_CONFIG_H isn't is set.
+
+----------
+2005/04/28 22:04:23 crs
+cmd/synergyc/Makefile.am
+cmd/synergys/Makefile.am
+configure.in
+lib/arch/Makefile.am
+lib/platform/Makefile.am
+
+Added support for MACOSX_DEPLOYMENT_TARGET. It's set to 10.2.
+
+----------
+2005/04/28 22:02:47 crs
+cmd/synergys/synergys.cpp
+lib/client/CClient.cpp
+
+Now reporting sleep suspend/resume at INFO level.
+
+----------
+2005/04/25 22:12:04 crs
+cmd/synergyc/Makefile.am
+cmd/synergyc/synergyc.cpp
+cmd/synergys/Makefile.am
+cmd/synergys/synergys.cpp
+configure.in
+lib/base/CEvent.cpp
+lib/base/CEvent.h
+lib/base/CEventQueue.cpp
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/COSXScreenSaver.cpp
+lib/platform/COSXScreenSaver.h
+lib/platform/COSXScreenSaver.mm
+lib/platform/Makefile.am
+lib/platform/OSXScreenSaverControl.h
+lib/server/CServer.cpp
+lib/synergy/IScreen.cpp
+lib/synergy/IScreen.h
+synergy.xcode/project.pbxproj
+
+Added support on OS X for screensaver synchronization,
+sleeping and fast user switching. OS X Server also now
+captures global hot keys (cmd+tab, F9, etc.) and sends them
+to the client. Changes mostly due to lorenz schori. Some
+bug fixes (in lorenz's code and in synergy) and integration
+into automake by crs (had to add support for Objective C++
+files) and the XCode project.
+
+This change also adds flags to events. Flags can cause events
+to be dispatched immediately and to not free event data. Both
+features are used in the new code.
+
+This change adds events on IScreen for notification of the
+system going to sleep or waking up (or the user's session
+being somehow suspended and restored). CClient and synergys
+now listen for and respond to these events. CMSWindowsScreen
+used to use IJobs for handling these events synchronously. It
+now uses the new IScreen events and delivers them immediately.
+
+----------
+2005/01/26 18:45:45 crs
+lib/common/Version.h
+
+Changed version to 1.2.2.
+
+----------
+2005/01/26 18:43:33 crs
+lib/platform/COSXKeyState.cpp
+
+Fixed bug in handling modifier keys on OS X clients. Was applying
+modifiers to modifiers yielding, for example: ctrl down, ctrl down,
+ctrl up for press of the control key. The first down and the up were
+there because we were applying the control modifier to the control
+key.
+
+----------
+2005/01/26 18:41:28 crs
+lib/platform/CXWindowsKeyState.cpp
+
+Fixed handling of ISO_Level3_Shift. We now prefer ISO_Level3_Shift
+over Mode_switch if it's mapped to any key. ISO_Level3_Shift
+replaces Mode_switch in newer versions of X and Mode_switch does
+nothing, so we have to use ISO_Level3_Shift if it's there.
+
+----------
+2005/01/04 19:29:58 crs
+lib/platform/COSXKeyState.cpp
+
+Fixed bug in OS X server key translation which pretty much broke any
+keystroke with a modifier key.
+
+----------
+2005/01/01 20:52:43 crs
+doc/compiling.html
+
+Merged documentation fixes.
+
+----------
+2005/01/01 20:19:42 crs
+doc/running.html
+
+Merged documentation fix from mainline.
+
+----------
+2004/12/30 13:28:51 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+doc/authors.html
+lib/client/CClient.cpp
+lib/net/CNetworkAddress.cpp
+lib/net/CNetworkAddress.h
+lib/server/CConfig.cpp
+
+Adapted and applied patch by Brent Priddy for re-resolving the server
+hostname on each connection. This allows the client to startup
+without being able to resolve the server's hostname. It also lets
+it handle changes in the server's address, a typical scenario when
+the client is a laptop moving between networks.
+
+----------
+2004/12/30 12:10:47 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/synergy/KeyTypes.h
+
+Added Henkan key. Patch from rniitani at sourceforge.net.
+
+----------
+2004/12/30 11:54:23 crs
+doc/authors.html
+lib/platform/CXWindowsScreen.cpp
+
+Applied patch from Tom Chadwick to synthesize PageUp/PageDown on
+X servers that don't support the mouse wheel.
+
+----------
+2004/12/29 21:12:05 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Now ignoring 4th and 5th mouse buttons if they don't exist. Was
+previously querying their state, sometimes getting the wrong
+answer from the OS that they were down, which prevented switching
+screens.
+
+----------
+2004/12/29 21:10:49 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Fixed handling of number pad number and decimal point keys when
+NumLock is on on client on windows 95 family.
+
+----------
+2004/12/29 17:53:44 crs
+lib/platform/CXWindowsScreen.cpp
+
+Added support for ISO_Level3_Shift on X windows server. It's
+treated as if it were Mode_switch.
+
+----------
+2004/12/29 17:07:08 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+
+Added support for unicode keyboard layouts on OS X.
+
+----------
+2004/12/29 17:06:49 crs
+lib/platform/COSXScreen.cpp
+
+Removed calls to show/hide mouse because they only work if we've
+taken exclusive access to the display and we don't do that.
+
+----------
+2004/12/29 17:06:00 crs
+lib/platform/COSXEventQueueBuffer.cpp
+lib/platform/COSXEventQueueBuffer.h
+
+Fixed leak of event objects on OS X.
+
+----------
+2004/12/29 17:00:17 crs
+//depot/project/synergy-web/Makefile
+//depot/project/synergy-web/autostart.htmls
+//depot/project/synergy-web/synergy.css
+doc/autostart.html
+doc/synergy.css
+
+Added Mac OS X autostart documentation from Tor Slettnes (tor@slett.net).
+
+----------
+2004/11/12 15:50:04 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+
+Now suppressing shift key when caps-lock is enabled on OSX. This
+fixes handling of, say, Command+N with caps-lock enabled which
+was being synthesized as Command+Shift+N.
+
+----------
+2004/11/11 19:23:14 crs
+lib/arch/CArchMultithreadPosix.cpp
+
+Fixed a serious flaw in wrapper for posix condition variable wait
+function. Because synergy doesn't use posix cancellation, it
+cannot wake up a thread waiting on a condition variable. So
+the wrapper would wake up periodically to test if the thread was
+cancelled (according to synergy's cancellation state) then go
+back to waiting. Well the condition could be signalled while
+we're testing and be lost and we'd never return from the wait.
+So now we wake up after a maximum timeout and return to the
+caller. The caller must check for this spurious wakeup but all
+callers should do this anyway so we're okay there.
+
+----------
+2004/11/11 19:17:03 crs
+lib/net/CSocketMultiplexer.cpp
+lib/net/CSocketMultiplexer.h
+
+Changed scheme used to lock the socket multiplexer's job list.
+I think the new scheme is easier to understand. It should have
+exactly the same behavior.
+
+----------
+2004/11/10 21:00:30 crs
+lib/mt/CCondVar.h
+
+Made condition variable data volatile. This will hopefully fix
+an strange deadlock seen on OSX. The CSocketMultiplexer deadlocks
+with two threads, one waiting for m_polling to become false and
+the other waiting for m_pollable to become true. The weird part
+is that they're both false so the first thread should proceed.
+It either didn't receive the broadcast when m_polling went to
+false or it's not really checking the actual value of that flag.
+I can't see how the former is possible and this change fixes the
+latter.
+
+----------
+2004/11/10 19:11:33 crs
+lib/platform/CXWindowsUtil.cpp
+
+Fixed typo.
+
+----------
+2004/11/09 20:05:33 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+
+Fixed modifier handling on OSX client. Had hardcoded one set of
+modifiers for all keys for testing purposes and forgotton to fix
+that. Now choosing required modifiers per key. This fixes
+shift+arrow keys suppressing the shift key and, i think, the
+option key not working.
+
+----------
+2004/11/09 18:42:47 crs
+lib/common/Version.h
+
+Changed version to 1.1.10.
+
+----------
+2004/11/09 18:38:14 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Added synergy version number to first log message.
+
+----------
+2004/11/09 18:31:54 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Moved log message that prints system info to after installation
+of user requested log level so it can be filtered.
+
+----------
+2004/11/06 16:29:06 crs
+lib/client/CServerProxy.cpp
+
+Attempt to workaround laggy mouse on OS X with linux as server.
+
+----------
+2004/11/06 16:13:52 crs
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+
+Fixed screensaver detection on XP.
+
+----------
+2004/11/06 16:13:01 crs
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+
+Fixed handling of number pad keys with num-lock off. Was
+synthesizing events for the numbers even with num-lock off. Now
+synthesizing the cursor movements.
+
+----------
+2004/11/06 16:11:39 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Fixed console appearing when running synergy as a service. This
+was introduced with the change to print system info to the start
+of the log. This message was printed before the service installed
+the log handler that directs messages to the event log.
+
+----------
+2004/11/04 21:26:43 crs
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/CXWindowsUtil.cpp
+lib/platform/CXWindowsUtil.h
+
+Added support for X11 compose key (Multi_key). This change fixes
+the handling of compose key sequences. The key presses were
+suppressed but not the corresponding releases, confusing the
+clients. It also adds support for generating keysyms via the
+compose key if the necessary dead keys or Mode_switch are not
+available.
+
+----------
+2004/11/02 20:50:36 crs
+doc/running.html
+
+Added documentation for -display option.
+
+----------
+2004/11/02 20:43:55 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+
+Added -display option for X11 version.
+
+----------
+2004/11/01 22:26:52 crs
+lib/platform/CSynergyHook.cpp
+
+Reverted change to detach threads in hook DLL. It was breaking
+double clicking.
+
+----------
+2004/11/01 22:26:02 crs
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/resource.h
+cmd/synergys/synergys.rc
+
+Added tray menu item on win32 to force clients to reconnect.
+
+----------
+2004/11/01 22:25:39 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+configure.in
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchFileWindows.cpp
+lib/arch/CArchSystemWindows.cpp
+lib/arch/CArchSystemWindows.h
+lib/arch/IArchSystem.h
+lib/arch/Makefile.am
+lib/arch/arch.dsp
+
+Added operating system identification log message for debugging
+purposes.
+
+----------
+2004/11/01 22:10:34 crs
+lib/platform/CMSWindowsDesks.cpp
+
+Added debugging output to check window class of active window
+when leaving screen. This may help determine how to avoid
+DOS command prompt windows being in the foreground when leaving
+the screen since they suppress handling of the shift key.
+
+----------
+2004/11/01 18:26:29 crs
+lib/platform/CMSWindowsEventQueueBuffer.cpp
+
+Fixed synergy quiting when powerdvd stops playing a DVD. This may
+fix some other bugs that involve unexpectedly quiting. The problem
+was that synergy would (cleanly) quit when receiving an event with
+a message id of 0 when not running as a service.
+
+----------
+2004/11/01 18:24:37 crs
+lib/platform/CMSWindowsDesks.cpp
+
+Fixed multimon support for win NT/2000/XP running as client. Mouse
+would jump between two points.
+
+----------
+2004/11/01 18:22:45 crs
+lib/platform/CMSWindowsScreenSaver.cpp
+
+Fixed a resource leak. Also fixed the detection of the screen saver
+closing on windows 2000 and XP.
+
+----------
+2004/11/01 18:21:00 crs
+cmd/launcher/CAdvancedOptions.cpp
+cmd/launcher/CAdvancedOptions.h
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Added option to set the listen address via the win32 GUI. This
+allows the user to specify one (and only one) network interface
+to listen on.
+
+----------
+2004/10/30 16:41:36 crs
+lib/platform/CXWindowsKeyState.cpp
+
+Changed X11 key mapping to fallback to the modifier keysym with
+the opposite handedness if the desired handedness is missing.
+For example, if Alt_R is unmapped as it often is on keyboards
+with Mode_switch, the client will use Alt_L if it is mapped
+when told to synthesize Alt_R. This should fix handling of
+AltGr sent from a win32 server. AltGr is literally just
+Control_L and Alt_R and, previously, an X11 client without
+Alt_R mapped would only simulate Control_L. This does not
+address the fact that the user may really just want the Alt
+modifier; there are already hueristics to attempt to figure
+that out.
+
+----------
+2004/10/30 16:16:32 crs
+configure.in
+lib/platform/CXWindowsScreenSaver.cpp
+
+Improved X extension detection in configure and added handling
+of dpms.h headers that don't have function prototypes.
+
+----------
+2004/10/28 21:40:56 crs
+configure.in
+lib/arch/CArchNetworkBSD.h
+lib/common/stdistream.h
+lib/common/stdostream.h
+lib/common/stdsstream.h
+lib/platform/CXWindowsClipboard.h
+lib/platform/CXWindowsEventQueueBuffer.h
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+lib/platform/CXWindowsUtil.h
+
+Fixed bugs in configuration. Wasn't doing configuration for DPMS
+and Xinerama correctly. Also was using '#if defined(...)' instead
+of '#if ...' for testing configure macros in some places. This
+yields the wrong answer if the macro is set to 0, which means
+missing/disabled.
+
+----------
+2004/10/27 21:46:22 crs
+lib/arch/CArchFileUnix.cpp
+
+Fixed use of freed memory.
+
+----------
+2004/10/27 21:38:05 crs
+lib/platform/CSynergyHook.cpp
+
+Now detaching hook thread after event processing. This may fix
+problems with the Alt key being synthetically down when using
+the back and forward bindings on a mouse with extra buttons.
+
+----------
+2004/10/27 21:29:19 crs
+lib/platform/CSynergyHook.cpp
+
+Fixed bug in mouse wheel handling. Was reacting with mouse wheel
+events when receiving any event with message == 0 when the system
+doesn't use old style mouse wheel events. Some programs (especially
+the flash plugin) would send events with message == 0 causing
+undesired wheel scrolling.
+
+----------
+2004/10/27 21:22:36 crs
+lib/platform/COSXScreen.cpp
+
+Fixed problem with multimonitor on OS X. The bug was simply that
+the cursor wasn't being parked in the center of the main screen
+but instead at the center of the total display surface. This could
+place it off or dangerously close to the edge of the transparent
+window that covers the main screen and prevent synergy from capturing
+mouse motion.
+
+----------
+2004/10/24 18:18:21 crs
+lib/platform/CXWindowsScreen.cpp
+
+Added eject key mapping.
+
+----------
+2004/10/24 18:18:11 crs
+lib/platform/CXWindowsUtil.cpp
+
+Fixed comment.
+
+----------
+2004/10/24 18:18:01 crs
+lib/platform/CXWindowsKeyState.cpp
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+
+Fixed dead key and AltGr+shift handling on X windows. Also fixed
+bug with decomposing characters that have no direct key mapping
+but do have a direct key mapping for the character with the opposite
+case.
+
+----------
+2004/10/24 18:15:33 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+
+Made OS X key mapping dynamic based on current key layout. It
+now includes full support for dead keys and non-ascii glyph keys.
+
+----------
+2004/10/24 18:14:18 crs
+lib/synergy/KeyTypes.h
+
+Added eject and sleep key IDs.
+
+----------
+2004/10/24 18:12:38 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Added VK_SLEEP.
+
+----------
+2004/10/23 19:43:37 crs
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CScreen.cpp
+
+Previous half-duplex fix fixed secondary screens with half
+duplex keys but broke primary screens. This fixes both and
+also ensures that the primary screen updates its shadow toggle
+modifier state when leaving so the secondary screens get the
+correct toggle modifier state. Together these fix some strange
+inconsistencies in toggle state across screens.
+
+----------
+2004/10/23 18:40:31 crs
+lib/synergy/CKeyState.cpp
+
+Fixed bug in half-duplex keys. Was updating their toggled state
+om every release as well as press.
+
+----------
+2004/10/13 20:39:22 crs
+doc/configuration.html
+
+Fixed typo in the documentation of configuration options.
+
+----------
+2004/09/29 21:59:26 crs
+cmd/synergyc/CClientTaskBarReceiver.cpp
+cmd/synergyc/CClientTaskBarReceiver.h
+cmd/synergys/CServerTaskBarReceiver.cpp
+cmd/synergys/CServerTaskBarReceiver.h
+configure.in
+lib/arch/CArchMultithreadPosix.cpp
+lib/base/CEventQueue.cpp
+lib/base/CEventQueue.h
+lib/base/IEventQueue.h
+lib/io/CStreamFilter.cpp
+lib/io/CStreamFilter.h
+lib/io/IStream.h
+lib/net/CTCPSocket.cpp
+lib/net/CTCPSocket.h
+lib/net/IDataSocket.h
+lib/server/CClientListener.cpp
+lib/synergy/CPacketStreamFilter.cpp
+lib/synergy/CPacketStreamFilter.h
+
+Removed recursive mutexes. Simplified stream filters as a side
+effect. Removed -D_BSD_SOURCE and -D_XOPEN_SOURCE=500 from
+compile since they're not longer necessary.
+
+----------
+2004/09/28 22:25:35 crs
+lib/server/CConfig.cpp
+
+Now accepting screen names that end in a dot since many OS X
+users have misconfigured their systems to have hostnames that
+end in a dot.
+
+----------
+2004/09/28 22:19:24 crs
+dist/nullsoft/installer.mak
+
+Fixed error in win32 installer packaging.
+
+----------
+2004/09/28 22:19:11 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+doc/configuration.html
+doc/faq.html
+lib/server/CConfig.cpp
+lib/synergy/CScreen.cpp
+
+Added half-duplex option for scroll lock key.
+
+----------
+2004/09/27 21:54:49 crs
+lib/platform/CXWindowsScreen.cpp
+lib/synergy/IPlatformScreen.h
+
+Fixed compile on gcc 3.4 and later. gcc started doing access checks
+for class visibility on pointers to member function 'using the
+qualifying scope of the name itself.' what this means is if method
+'prot' is declared protected in class A and B inherits from A then
+a method in B cannot use &A::prot but can use &B::prot. Synergy
+now does this in the one place it had not.
+
+----------
+2004/09/27 21:23:47 crs
+lib/arch/CArchMultithreadPosix.cpp
+
+Worked around minor gcc 3.3.2 -O3 compiler bug.
+
+----------
+2004/09/27 21:04:37 crs
+cmd/synergys/synergys.cpp
+
+Server now reports configuration file errors as ERROR level log
+messages rather than DEBUG level. Missing files are still reported
+as DEBUG level messages since we expect some to be missing.
+
+----------
+2004/09/27 20:53:54 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.9. Changed configure.in to get version
+number from lib/common/Version.h so it only has to be changed
+there.
+
+----------
+2004/08/05 20:42:51 crs
+dist/nullsoft/synergy.nsi
+
+Fixed missing license file and PORTING in win32 installer build.
+
+----------
+2004/08/04 22:48:30 crs
+synergy.xcode/project.pbxproj
+
+Removed cross-compile setting from project.
+
+----------
+2004/08/04 22:48:08 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/synergy/KeyTypes.h
+
+Fixed handling of auto-repeat, ctrl + character key, and button
+to KeyCode translation.
+
+----------
+2004/08/03 22:02:57 crs
+lib/platform/COSXKeyState.cpp
+
+Fixed space key on OS X server -> client.
+
+----------
+2004/08/03 21:14:30 crs
+lib/arch/CArchMultithreadPosix.cpp
+
+Fixed warnings in deployment build style on OS X.
+
+----------
+2004/08/01 17:37:28 crs
+doc/faq.html
+doc/index.html
+doc/running.html
+
+Fixed errors in new docs markup.
+
+----------
+2004/08/01 17:37:11 crs
+dist/nullsoft/synergy.nsi
+
+Updated win32 installer to use new docs.
+
+----------
+2004/08/01 17:36:53 crs
+COPYING
+
+Reverted COPYING so win32 installer build can use it.
+
+----------
+2004/08/01 16:31:47 crs
+Makefile.am
+dist/nullsoft/installer.mak
+dist/nullsoft/synergy.nsi
+dist/rpm/synergy.spec.in
+
+Updated packagers to handle new documentation.
+
+----------
+2004/08/01 16:04:21 crs
+AUTHORS
+COPYING
+INSTALL
+NEWS
+
+Added files required by automake. They simply reference the
+corresponding HTML file.
+
+----------
+2004/08/01 16:00:18 crs
+AUTHORS
+BUGS
+COPYING
+FAQ
+HISTORY
+INSTALL
+Makefile.am
+NEWS
+PORTING
+README
+TODO
+configure.in
+doc/Makefile.am
+doc/PORTING
+doc/authors.html
+doc/autostart.html
+doc/compiling.html
+doc/configuration.html
+doc/developer.html
+doc/faq.html
+doc/history.html
+doc/index.html
+doc/license.html
+doc/news.html
+doc/running.html
+doc/security.html
+doc/synergy.css
+doc/tips.html
+doc/todo.html
+
+Updated documentation. Converted most documation to HTML.
+
+----------
+2004/07/31 14:34:02 crs
+INSTALL
+PORTING
+README
+TODO
+
+Documentation changes.
+
+----------
+2004/07/31 11:19:39 crs
+acinclude.m4
+lib/arch/CArchNetworkBSD.cpp
+lib/platform/CXWindowsEventQueueBuffer.cpp
+
+Now using instead of . Also added a bit
+to autoconf to ensure we don't use poll on OS X.
+
+----------
+2004/07/29 22:11:27 crs
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Fixed handling of modifier keys on OS X. Also made OS X client
+ignore small mouse wheel events (which seem to get sent by some
+win32 systems). Other platforms were already ignoring them.
+
+----------
+2004/07/29 22:09:28 crs
+cmd/synergys/synergys.cpp
+
+Worked around bug in ifstream::operator!() on OS X.
+
+----------
+2004/07/29 21:59:26 crs
+lib/platform/CSynergyHook.cpp
+
+Fixed handling of ctrl and alt keys when using low level hooks.
+They were being discarded so the server wouldn't correctly send
+ctrl, alt, or AltGr to clients.
+
+----------
+2004/07/29 21:57:42 crs
+lib/platform/CMSWindowsScreenSaver.cpp
+
+Added comment about a problem detecting the screen saver.
+
+----------
+2004/07/29 21:53:30 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Worked around bogus key mapping on 95/98/me where multiple virtual
+keys are mapped to the same button. For example, the backslash
+virtual key shares a button with some other virtual key on british
+english key mappings. Synergy could end up using the wrong virtual
+key. In the given case, the other virtual key produced no character
+at all. To determine which virtual key should really be mapped to
+a button we map the button back to a virtual key and see if it's the
+virtual key we started with.
+
+Also fixed mapping of pause key. Previously, windows+pause sent to
+a win32 client wouldn't bring up system properties like it should.
+
+----------
+2004/07/29 21:50:17 crs
+lib/platform/CMSWindowsDesks.cpp
+
+Synergy now steals window activation when using low level hooks
+and a console window is the active window. This is to work around
+console windows preventing the hook from detecting the shift key.
+
+----------
+2004/07/29 21:48:40 crs
+lib/net/CTCPSocket.cpp
+
+Worked around bug/weirdness on OS X. It's reporting that a
+non-blocking connect is available for writing (i.e. the connection
+was successful) when the connection has actually failed. This
+caused synergy to rapidly retry connecting. This change makes
+synergy check for a connection error whether one was reported or
+not. Thankfully, OS X does correctly set the socket error state
+when it bogusly reports a successful connection so we can tell the
+connection failed.
+
+----------
+2004/07/28 21:54:39 crs
+lib/net/CTCPSocket.cpp
+
+Added workaround for apparent bug in OS X 10.3.4. If you started
+a synergy client on that OS and pointed it at a system that wasn't
+listening for connections then instead of the connection attempt
+failing with 'connection refused' the system would claim the
+connection succeeded. A subsequent read would reveal the problem
+and synergy would "disconnect" and retry, causing the CPU to spin.
+The system does correctly set the socket error state so this
+workaround checks for socket errors when connecting whether or not
+select reports an error state.
+
+Also, sometimes the system doesn't claim success but doesn't report
+an error. Synergy eventually times out these attempts.
+
+----------
+2004/07/25 14:18:50 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.8.
+
+----------
+2004/06/22 21:11:14 crs
+lib/platform/CXWindowsScreen.cpp
+
+Disable key event capture on X11. This was going to be used to
+detect synergy hotkeys but a design flaw in X11 makes it problematic
+with many applications. We'll have to fall back to the more
+traditional XGrabKey when the time comes.
+
+----------
+2004/06/16 21:07:48 crs
+synergy.xcode/project.pbxproj
+
+Added NDEBUG to and removed debugging symbols from XCode deployment
+project.
+
+----------
+2004/06/13 17:11:19 crs
+ChangeLog
+NEWS
+
+Updated documentation.
+
+----------
+2004/06/12 20:48:04 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CMSWindowsScreenSaver.h
+
+(Maybe) fixed a problem detecting when win32 screen saver started.
+
+----------
+2004/06/12 20:46:35 crs
+lib/arch/CMultibyte.cpp
+
+Fixed bug in converting wide characters to multibyte.
+
+----------
+2004/06/10 21:25:09 crs
+lib/client/CClient.cpp
+
+Fixed assertion failure when client connection fails immediately.
+
+----------
+2004/06/10 19:56:35 crs
+lib/arch/CArchNetworkBSD.cpp
+
+Changed O_NDELAY to O_NONBLOCK. On some versions of Unix, read
+return 0 when O_NDELAY is set and there is nothing to read. We
+want the O_NONBLOCK behavior where read returns -1 and sets
+errno to EAGAIN when there is nothing to read.
+
+----------
+2004/06/10 19:42:01 crs
+lib/common/Makefile.am
+
+Added OS X precompiled header file for XCode compiles.
+
+----------
+2004/06/10 19:39:07 crs
+cmd/launcher/CAutoStart.cpp
+
+Removed dependency of service on Browser. Browser isn't always
+available and, if it's not, synergy won't start. Users may have
+to use an IP server address instead of a hostname since the
+service may start before the service that resolves hostnames.
+If I knew what that service was I'd depend on it instead.
+
+----------
+2004/06/10 19:32:40 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.7.
+
+----------
+2004/06/07 21:06:49 crs
+lib/platform/CXWindowsEventQueueBuffer.cpp
+
+Failed to reset flag in X11 event queue buffer and that could cause
+multiple threads to access the X display connection simultaneously
+which causes synergy to die.
+
+----------
+2004/05/26 19:23:32 crs
+lib/common/MacOSXPrecomp.h
+lib/common/common.h
+lib/platform/COSXClipboardTextConverter.cpp
+lib/platform/COSXClipboardTextConverter.h
+lib/platform/COSXEventQueueBuffer.cpp
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+synergy.xcode/project.pbxproj
+
+Merged Bertrand's OS X changes. Also added support for mouse wheel
+on OS X server.
+
+----------
+2004/05/18 20:32:13 crs
+lib/platform/CMSWindowsScreen.cpp
+
+If the server manages to detect ctrl+alt+del it will no longer send
+that to the client. If it did then the user could see the effect of
+ctrl+alt+del on both the server and client which we never want. The
+user can use ctrl+alt+pause to emulate ctrl+alt+del on the client.
+
+----------
+2004/05/18 20:26:48 crs
+lib/platform/CXWindowsEventQueueBuffer.cpp
+lib/platform/CXWindowsEventQueueBuffer.h
+
+Fixed bug that could allow multiple threads to simultaneously access
+the X11 display connection. The only problematic method was
+CXWindowsEventQueueBuffer::addEvent given that the other event queue
+methods are only called from the main thread.
+
+----------
+2004/05/17 21:55:55 crs
+cmd/synergyc/synergyc.cpp
+
+Fixed logging of connection to server. Was DEBUG now NOTE.
+
+----------
+2004/05/17 21:55:38 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Fixed ctrl+alt+del emulation on win32 server. It was mapping
+VK_DELETE to the keypad delete key. This key is not interpreted
+on the client as causing ctrl+alt+del.
+
+----------
+2004/05/16 18:04:36 crs
+lib/client/CServerProxy.cpp
+lib/server/CClientProxy1_0.cpp
+lib/synergy/ProtocolTypes.h
+
+Fixed handling of screen resolution changes.
+
+----------
+2004/05/16 18:03:36 crs
+cmd/launcher/CAutoStart.cpp
+
+Changed (win NT) service to depend on the 'Browser' service to
+ensure correct startup order.
+
+----------
+2004/05/16 18:02:49 crs
+all.dsp
+cmd/exec.dsp
+cmd/launcher/launcher.dsp
+cmd/synergyc/synergyc.dsp
+cmd/synergys/synergys.dsp
+dist/nullsoft/installer.dsp
+dist/nullsoft/synergy.nsi
+lib/arch/arch.dsp
+lib/base/base.dsp
+lib/client/client.dsp
+lib/common/common.dsp
+lib/io/io.dsp
+lib/mt/mt.dsp
+lib/net/net.dsp
+lib/platform/makehook.dsp
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+
+Changed VC++ projects to put release targets in ./build, debug
+targets in ./debug, and intermediate files under ./gen.
+
+----------
+2004/05/15 19:44:05 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.6.
+
+----------
+2004/05/15 19:43:33 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Avoided duplicate logging of screen size on win32.
+
+----------
+2004/05/15 19:41:46 crs
+Makefile.am
+configure.in
+lib/common/common.h
+lib/platform/COSXClipboard.cpp
+lib/platform/COSXClipboard.h
+lib/platform/COSXClipboardAnyTextConverter.cpp
+lib/platform/COSXClipboardAnyTextConverter.h
+lib/platform/COSXClipboardTextConverter.cpp
+lib/platform/COSXClipboardTextConverter.h
+lib/platform/COSXClipboardUTF16Converter.cpp
+lib/platform/COSXClipboardUTF16Converter.h
+lib/platform/COSXEventQueueBuffer.cpp
+lib/platform/COSXEventQueueBuffer.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/Makefile.am
+synergy.xcode/project.pbxproj
+
+Added bertrand landry hetu's mac OS X port to date.
+
+----------
+2004/05/12 20:28:00 crs
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+
+Now restoring input focus when entering the screen to the window
+that had the focus when the screen was left.
+
+----------
+2004/05/12 19:50:58 crs
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkWinsock.cpp
+
+Fixed thread reference leak in network code.
+
+----------
+2004/05/12 19:12:28 crs
+configure.in
+
+Added configure option to enable debug builds. If not enabled then
+asserts are disabled.
+
+----------
+2004/05/12 18:54:03 crs
+lib/platform/CXWindowsClipboardBMPConverter.cpp
+
+Fixed build error in gcc 3.3.
+
+----------
+2004/05/26 19:23:32 crs
+lib/common/MacOSXPrecomp.h
+lib/common/common.h
+lib/platform/COSXClipboardTextConverter.cpp
+lib/platform/COSXClipboardTextConverter.h
+lib/platform/COSXEventQueueBuffer.cpp
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+synergy.xcode/project.pbxproj
+
+Merged Bertrand's OS X changes. Also added support for mouse wheel
+on OS X server.
+
+----------
+2004/05/18 20:32:13 crs
+lib/platform/CMSWindowsScreen.cpp
+
+If the server manages to detect ctrl+alt+del it will no longer send
+that to the client. If it did then the user could see the effect of
+ctrl+alt+del on both the server and client which we never want. The
+user can use ctrl+alt+pause to emulate ctrl+alt+del on the client.
+
+----------
+2004/05/18 20:26:48 crs
+lib/platform/CXWindowsEventQueueBuffer.cpp
+lib/platform/CXWindowsEventQueueBuffer.h
+
+Fixed bug that could allow multiple threads to simultaneously access
+the X11 display connection. The only problematic method was
+CXWindowsEventQueueBuffer::addEvent given that the other event queue
+methods are only called from the main thread.
+
+----------
+2004/05/17 21:55:55 crs
+cmd/synergyc/synergyc.cpp
+
+Fixed logging of connection to server. Was DEBUG now NOTE.
+
+----------
+2004/05/17 21:55:38 crs
+lib/platform/CMSWindowsKeyState.cpp
+
+Fixed ctrl+alt+del emulation on win32 server. It was mapping
+VK_DELETE to the keypad delete key. This key is not interpreted
+on the client as causing ctrl+alt+del.
+
+----------
+2004/05/16 18:04:36 crs
+lib/client/CServerProxy.cpp
+lib/server/CClientProxy1_0.cpp
+lib/synergy/ProtocolTypes.h
+
+Fixed handling of screen resolution changes.
+
+----------
+2004/05/16 18:03:36 crs
+cmd/launcher/CAutoStart.cpp
+
+Changed (win NT) service to depend on the 'Browser' service to
+ensure correct startup order.
+
+----------
+2004/05/16 18:02:49 crs
+all.dsp
+cmd/exec.dsp
+cmd/launcher/launcher.dsp
+cmd/synergyc/synergyc.dsp
+cmd/synergys/synergys.dsp
+dist/nullsoft/installer.dsp
+dist/nullsoft/synergy.nsi
+lib/arch/arch.dsp
+lib/base/base.dsp
+lib/client/client.dsp
+lib/common/common.dsp
+lib/io/io.dsp
+lib/mt/mt.dsp
+lib/net/net.dsp
+lib/platform/makehook.dsp
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+
+Changed VC++ projects to put release targets in ./build, debug
+targets in ./debug, and intermediate files under ./gen.
+
+----------
+2004/05/15 19:44:05 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.6.
+
+----------
+2004/05/15 19:43:33 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Avoided duplicate logging of screen size on win32.
+
+----------
+2004/05/15 19:41:46 crs
+Makefile.am
+configure.in
+lib/common/common.h
+lib/platform/COSXClipboard.cpp
+lib/platform/COSXClipboard.h
+lib/platform/COSXClipboardAnyTextConverter.cpp
+lib/platform/COSXClipboardAnyTextConverter.h
+lib/platform/COSXClipboardTextConverter.cpp
+lib/platform/COSXClipboardTextConverter.h
+lib/platform/COSXClipboardUTF16Converter.cpp
+lib/platform/COSXClipboardUTF16Converter.h
+lib/platform/COSXEventQueueBuffer.cpp
+lib/platform/COSXEventQueueBuffer.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/Makefile.am
+synergy.xcode/project.pbxproj
+
+Added bertrand landry hetu's mac OS X port to date.
+
+----------
+2004/05/12 20:28:00 crs
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+
+Now restoring input focus when entering the screen to the window
+that had the focus when the screen was left.
+
+----------
+2004/05/12 19:50:58 crs
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkWinsock.cpp
+
+Fixed thread reference leak in network code.
+
+----------
+2004/05/12 19:12:28 crs
+configure.in
+
+Added configure option to enable debug builds. If not enabled then
+asserts are disabled.
+
+----------
+2004/05/12 18:54:03 crs
+lib/platform/CXWindowsClipboardBMPConverter.cpp
+
+Fixed build error in gcc 3.3.
+
+----------
+2004/05/04 20:45:06 crs
+cmd/launcher/CGlobalOptions.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Added GUI for relative mouse moves option on win32.
+
+----------
+2004/05/04 19:44:51 crs
+configure.in
+
+Configured default mac to build for X windows instead of the incomplete
+carbon implementation.
+
+----------
+2004/05/04 19:37:46 crs
+lib/net/CTCPSocket.cpp
+
+Fixed bug in TCP socket that caused a busy loop in the socket
+multiplexer. That caused a lock up on windows when quitting
+the server with a client connected.
+
+----------
+2004/05/03 21:14:01 crs
+lib/platform/CXWindowsClipboardAnyBitmapConverter.cpp
+lib/platform/CXWindowsClipboardBMPConverter.cpp
+
+Fixed X11 BMP and other bitmap conversion. Had data alignment
+problems.
+
+----------
+2004/05/02 21:31:19 crs
+lib/base/CUnicode.cpp
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsClipboardAnyBitmapConverter.cpp
+lib/platform/CXWindowsClipboardAnyBitmapConverter.h
+lib/platform/CXWindowsClipboardBMPConverter.cpp
+lib/platform/CXWindowsClipboardBMPConverter.h
+lib/platform/CXWindowsClipboardHTMLConverter.cpp
+lib/platform/CXWindowsClipboardHTMLConverter.h
+lib/platform/Makefile.am
+lib/synergy/IClipboard.h
+
+Added image/bmp and text/html support to X11.
+
+----------
+2004/05/02 16:13:11 crs
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+
+Relative mouse motion for OS X.
+
+----------
+2004/05/02 16:06:04 crs
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+
+Used MouseKeys accessibility function to show the mouse cursor
+on a secondary screen when there's no physical mouse attached to
+the system. Kinda flaky when a mouse is attached or detached but
+seems to work well enough when the device is not attached to start
+with and not attached while running synergy.
+
+----------
+2004/05/02 16:01:59 crs
+cmd/launcher/CAutoStart.cpp
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchDaemonNone.cpp
+lib/arch/CArchDaemonNone.h
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchDaemonWindows.h
+lib/arch/IArchDaemon.h
+
+Added support for daemon startup dependencies. Made synergy
+dependent on NetBT, which I hope is right.
+
+----------
+2004/05/02 16:00:45 crs
+lib/synergy/IClipboard.h
+
+Fixed comment about canonical bitmap clipboard format.
+
+----------
+2004/05/02 08:04:48 crs
+lib/platform/CMSWindowsClipboard.cpp
+lib/platform/CMSWindowsClipboardBitmapConverter.cpp
+lib/platform/CMSWindowsClipboardBitmapConverter.h
+lib/platform/CMSWindowsClipboardHTMLConverter.cpp
+lib/platform/CMSWindowsClipboardHTMLConverter.h
+lib/platform/platform.dsp
+lib/server/server.dsp
+lib/synergy/IClipboard.h
+
+Added win32 clipboard support for images and HTML. Still need X11
+support.
+
+----------
+2004/05/02 08:04:15 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+
+Added relative mouse move support to win32.
+
+----------
+2004/05/02 08:03:49 crs
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+
+Forgot to change the client to handle relative moves.
+
+----------
+2004/05/01 16:10:09 crs
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsUtil.cpp
+lib/platform/CXWindowsUtil.h
+
+X11 clipboard logging now also prints atom names, not just numbers.
+
+----------
+2004/05/01 15:19:53 crs
+lib/server/CClientProxy1_2.cpp
+lib/server/CClientProxy1_2.h
+
+Added files forgotten in previous checkin.
+
+----------
+2004/05/01 15:18:59 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxyUnknown.cpp
+lib/server/CConfig.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/Makefile.am
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IClient.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/ISecondaryScreen.h
+lib/synergy/OptionTypes.h
+lib/synergy/ProtocolTypes.h
+
+Added support for a global relative mouse motion option. When true
+and on a secondary screen and locked to the screen (via scroll lock)
+mouse motion is sent as motion deltas. When true and scroll lock
+is toggled off the mouse is warped to the secondary screen's center
+so the server knows where it is. This option is intended to support
+games and other programs that repeatedly warp the mouse to the center
+of the screen. This change adds general and X11 support but not
+win32. The option name is "relativeMouseMoves".
+
+----------
+2004/05/01 12:11:28 crs
+configure.in
+lib/arch/CArchNetworkBSD.cpp
+lib/common/common.h
+
+Better fixes for compiling on FreeBSD and OpenBSD.
+
+----------
+2004/05/01 11:01:40 crs
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/common/common.h
+
+Fixes for FreeBSD.
+
+----------
+2004/05/01 10:12:06 crs
+acinclude.m4
+configure.in
+lib/arch/CArchNetworkBSD.cpp
+lib/platform/CXWindowsScreenSaver.cpp
+
+Fixes to compile on solaris 9 using g++.
+
+----------
+2004/05/01 08:56:24 crs
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+
+Fixed regression where cursor wasn't locked to screen when a mouse
+button is down on win32.
+
+----------
+2004/05/01 08:54:42 crs
+lib/arch/CMultibyte.cpp
+
+Fixed type cast warnings.
+
+----------
+2004/04/13 19:39:04 crs
+configure.in
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchStringUnix.cpp
+lib/arch/CArchStringUnix.h
+lib/arch/CArchStringWindows.cpp
+lib/arch/CArchStringWindows.h
+lib/arch/CMultibyte.cpp
+lib/arch/CMultibyteEmu.cpp
+lib/arch/CMultibyteOS.cpp
+lib/arch/IArchString.h
+lib/arch/Makefile.am
+lib/arch/arch.dsp
+lib/base/CUnicode.cpp
+
+Removed use of mbrtowc, wcrtomb, and mbsinit. Many platforms
+didn't support them and the emulated versions were just as good
+except for a performance problem with excessive locking and
+unlocking of a mutex. So this also changes IArchString to
+provide string rather than character conversion so we can lock
+the mutex once per string rather than once per character.
+
+----------
+2004/04/11 20:01:18 crs
+cmd/launcher/Makefile.am
+
+Oops, broke build in launcher on non-win32 platforms.
+
+----------
+2004/04/11 19:43:16 crs
+cmd/launcher/Makefile.am
+lib/platform/Makefile.am
+
+More changes for MSYS/MinGW builds. Added makefile for launcher.
+Still need hook library and resource compiling.
+
+----------
+2004/04/11 19:15:09 crs
+cmd/launcher/launcher.rc
+cmd/synergyc/synergyc.rc
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.rc
+configure.in
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchNetworkWinsock.cpp
+lib/arch/CArchStringWindows.cpp
+lib/arch/CArchTaskBarWindows.cpp
+lib/arch/CMultibyte.cpp
+lib/arch/XArchWindows.cpp
+lib/arch/arch.dsp
+lib/common/common.h
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CSynergyHook.cpp
+lib/synergy/CProtocolUtil.cpp
+
+Preliminary support for MSYS/MinGW builds. Doesn't yet build
+CSynergyHook as a DLL and does not compile or link in the
+resources for the binaries.
+
+----------
+2004/04/11 14:58:08 crs
+PORTING
+cmd/synergyc/COSXClientTaskBarReceiver.cpp
+cmd/synergyc/COSXClientTaskBarReceiver.h
+cmd/synergyc/Makefile.am
+cmd/synergyc/synergyc.cpp
+cmd/synergys/COSXServerTaskBarReceiver.cpp
+cmd/synergys/COSXServerTaskBarReceiver.h
+cmd/synergys/Makefile.am
+cmd/synergys/synergys.cpp
+configure.in
+lib/arch/CArch.cpp
+lib/arch/CArchDaemonUnix.cpp
+lib/arch/CArchFileUnix.cpp
+lib/arch/CArchImpl.cpp
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CMultibyte.cpp
+lib/arch/CMultibyteOS.cpp
+lib/arch/Makefile.am
+lib/arch/vsnprintf.cpp
+lib/base/CPriorityQueue.h
+lib/common/BasicTypes.h
+lib/common/common.h
+lib/platform/COSXClipboard.cpp
+lib/platform/COSXClipboard.h
+lib/platform/COSXEventQueueBuffer.cpp
+lib/platform/COSXEventQueueBuffer.h
+lib/platform/COSXKeyState.cpp
+lib/platform/COSXKeyState.h
+lib/platform/COSXScreen.cpp
+lib/platform/COSXScreen.h
+lib/platform/COSXScreenSaver.cpp
+lib/platform/COSXScreenSaver.h
+lib/platform/CSynergyHook.h
+lib/platform/CXWindowsEventQueueBuffer.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/Makefile.am
+
+Updates to support OS X. This improves support for building on
+multiple systems with automake, with X Windows and Carbon window
+system APIs supported. It's also a starting port for supporting
+win32 builds using mingw. OS X support is incomplete; the tree
+will compile and link but the binaries will not function.
+
+----------
+2004/04/06 22:09:38 crs
+lib/arch/CArchMultithreadPosix.cpp
+
+Added missing initialization of mutex attribute call.
+
+----------
+2004/04/05 21:23:44 crs
+lib/server/CServer.cpp
+
+Fixed bug in handling rejection of screen with name that's already
+in use. The client was being correctly rejected but the already
+connected client was being forcefully disconnected too because the
+client to disconnect was found by looking up the client by name.
+We now instead look up the client by IClient*.
+
+----------
+2004/04/05 21:10:06 crs
+lib/platform/CSynergyHook.cpp
+lib/server/CServer.cpp
+lib/server/CServer.h
+
+Added workaround for win32 low-level mouse hook position weirdness.
+The low-level hook can report mouse positions outside the boundaries
+of the screen and bogus retrograde motion. This messes up switch on
+double tap. This change attempts to detect and suppress the bogus
+events.
+
+----------
+2004/04/05 21:08:49 crs
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+
+Made hook debug logging print at DEBUG1 rather than INFO level.
+
+----------
+2004/04/04 12:12:32 crs
+Makefile.am
+cmd/Makefile.am
+cmd/launcher/Makefile.am
+cmd/synergyc/Makefile.am
+cmd/synergys/Makefile.am
+dist/Makefile.am
+dist/nullsoft/Makefile.am
+dist/rpm/Makefile.am
+lib/Makefile.am
+lib/arch/Makefile.am
+lib/base/Makefile.am
+lib/client/Makefile.am
+lib/common/Makefile.am
+lib/io/Makefile.am
+lib/mt/Makefile.am
+lib/net/Makefile.am
+lib/platform/Makefile.am
+lib/server/Makefile.am
+lib/synergy/Makefile.am
+
+Removed DEPTH, VDEPTH, and VPATH from makefiles.
+
+----------
+2004/04/04 12:12:30 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.5.
+
+----------
+2004/03/31 22:30:49 crs
+dist/nullsoft/synergy.nsi
+
+Minor win32 installer tweaks.
+
+----------
+2004/03/31 22:15:13 crs
+lib/arch/CArchTaskBarWindows.cpp
+lib/arch/CArchTaskBarWindows.h
+lib/arch/IArchTaskBar.h
+
+Reverted task bar code to 1.0.15 version. That used a window in
+its own thread for handling messages. It seems to fix most of
+the task bar bugs but there's still an hourglass cursor on NT
+when using the popup menu.
+
+----------
+2004/03/31 22:14:15 crs
+lib/arch/CArchNetworkWinsock.cpp
+
+Fixed lookup of hosts by name on win32.
+
+----------
+2004/03/31 22:14:01 crs
+cmd/launcher/launcher.rc
+
+Make screen drop down lists longer in the launcher. They're now
+long enough for the scroll bar to show up properly (with the
+thumb) and they have enough space for 6 screens without needing
+the scroll bar.
+
+----------
+2004/03/31 22:12:53 crs
+lib/server/CServer.cpp
+
+Fixed failure to initialize double tap and wait to switch timeouts.
+
+----------
+2004/03/30 18:55:58 crs
+lib/synergy/CKeyState.cpp
+
+Fixed crash bug in CKeyState. Would deference bogus pointer in
+isModifierActive if there's an unmapped toggle modifier.
+
+----------
+2004/03/30 18:54:56 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.1.4. This time changing the version before
+making any other changes.
+
+----------
+2004/03/28 14:53:01 crs
+lib/platform/CXWindowsKeyState.cpp
+
+Added ISO_Level3_Shift as a synonym for Mode_switch. I've no idea
+if this will work as hoped but I've seen documentation that XFree
+4.3 uses ISO_Level3_Shift rather than Mode_switch.
+
+----------
+2004/03/28 14:07:58 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CSynergyHook.h
+lib/synergy/CKeyState.h
+
+Fixed keyboard handling on windows 95 family.
+
+----------
+2004/03/28 14:07:37 crs
+lib/platform/Makefile.am
+
+Updated makefile to reflect renaming of platform files for win32.
+
+----------
+2004/03/28 14:06:40 crs
+lib/platform/CMSWindowsScreenSaver.cpp
+
+Fixed windows 95 family screen saver stuff.
+
+----------
+2004/03/28 14:05:52 crs
+lib/client/CServerProxy.cpp
+
+Changed debug logging of key IDs to use hex.
+
+----------
+2004/03/28 14:05:31 crs
+cmd/launcher/CAutoStart.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+lib/arch/CArchDaemonWindows.cpp
+
+Fixed bugs in installing per-user startup programs on windows 95
+family.
+
+----------
+2004/03/26 20:59:26 crs
+lib/platform/CMSWindowsDesks.cpp
+lib/platform/CMSWindowsDesks.h
+lib/platform/CMSWindowsDesktop.cpp
+lib/platform/CMSWindowsDesktop.h
+lib/platform/CMSWindowsKeyMapper.cpp
+lib/platform/CMSWindowsKeyMapper.h
+lib/platform/CMSWindowsKeyState.cpp
+lib/platform/CMSWindowsKeyState.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/platform.dsp
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.cpp
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/ISecondaryScreen.h
+lib/synergy/libsynergy.dsp
+
+Converted win32 to new keyboard state tracking design. Also
+changed locking to screen so that keys no longer count (only
+mouse buttons and scroll lock toggled on). This is to deal
+with the unreliability of key event reporting which can leave
+us locked to a screen with no key physically pressed. The
+result of this is that clients get key repeats and releases
+without the corresponding key press. CKeyState handles this
+by discarding repeat/release events on keys it hasn't seen go
+down. Also made a few other minor fixes to win32 keyboard
+handling.
+
+----------
+2004/03/26 20:59:21 crs
+lib/arch/CArchMiscWindows.cpp
+
+Fixed handling of reading strings from the registry. This was
+broken when support for binary data was added. The terminating
+NUL was included in the string as a character (that's in addition
+to the terminating NUL added by std::string).
+
+----------
+2004/03/21 20:01:41 crs
+lib/client/CClient.cpp
+lib/platform/CXWindowsKeyMapper.cpp
+lib/platform/CXWindowsKeyMapper.h
+lib/platform/CXWindowsKeyState.cpp
+lib/platform/CXWindowsKeyState.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/Makefile.am
+lib/server/CPrimaryClient.cpp
+lib/synergy/CKeyState.cpp
+lib/synergy/CKeyState.h
+lib/synergy/CPlatformScreen.cpp
+lib/synergy/CPlatformScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IKeyState.cpp
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+lib/synergy/ISecondaryScreen.h
+lib/synergy/Makefile.am
+
+Checkpoint. Converted X11 to new keyboard state tracking design.
+This new design is simpler. For keyboard support, clients need only
+implement 4 virtual methods on a class derived from CKeyState and
+one trivial method in the class derived from CPlatformScreen, which
+is now the superclass of platform screens instead of IPlatformScreen.
+Keyboard methods have been removed from IPlatformScreen, IPrimaryScreen
+and ISecondaryScreen. Also, all keyboard state tracking is now in
+exactly one place (the CKeyState subclass) rather than in CScreen,
+the platform screen, and the key mapper. Still need to convert Win32.
+
+----------
+2004/03/17 20:59:25 crs
+lib/platform/CMSWindowsKeyMapper.cpp
+lib/platform/CMSWindowsKeyMapper.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IKeyState.h
+lib/synergy/libsynergy.dsp
+
+Updated keyboard handling on win32. Still needs some work to
+avoid shadowing key state in multiple places. Also got locked
+to screen and reported key appeared to be wrong.
+
+----------
+2004/03/14 17:55:53 crs
+lib/platform/CXWindowsKeyMapper.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IKeyState.h
+lib/synergy/IPlatformScreen.cpp
+lib/synergy/IPlatformScreen.h
+lib/synergy/IPrimaryScreen.cpp
+lib/synergy/IPrimaryScreen.h
+lib/synergy/Makefile.am
+
+Changed how key state is tracked on X11. Now updating key state
+on every key press and release so we don't have to updateKeys()
+in isLockedToScreen(). However, if any key appears to be down
+we still call updateKeys() to double check that it's really down.
+If not we note the spurious lock and don't lock to the screen.
+
+----------
+2004/03/14 17:50:37 crs
+lib/io/IStream.h
+
+Fixed doxygen formatting error.
+
+----------
+2004/03/13 19:01:27 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Improved handling of active window on win32. Synergy no longer
+takes activation so the previously active window doesn't pop to
+the top of the window stack when it regains activation. One
+drawback of this is that the mouse cursor isn't shown when
+a window (other than synergy's) is activated. However, synergy
+does detect mouse motion as before and shows the cursor when it
+sees any.
+
+----------
+2004/03/13 18:58:20 crs
+lib/platform/CMSWindowsScreen.h
+
+Fixed error in previous submit.
+
+----------
+2004/03/13 17:16:24 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+
+Fixed handling of handshake complete. Was posting an event for it
+but making direct calls for other messages from the server. This
+could cause messages to be handled out of order. Now making a
+direct call for handshake complete.
+
+----------
+2004/03/13 17:14:32 crs
+lib/platform/CMSWindowsEventQueueBuffer.cpp
+
+Fixed win32 taskbar icon event handling. Wasn't responding to
+messages sent via SendMessage (rather than PostMessage).
+
+----------
+2004/03/13 17:13:55 crs
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CMSWindowsScreenSaver.h
+
+Added win32 support for power management.
+
+----------
+2004/03/10 22:03:01 crs
+configure.in
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+
+Added support for DPMS in X11 screen saver. DPMS is the extension
+that allows you to power down the display. Previously, synergy
+would not power on the display if DPMS was enabled and activated
+and xscreensaver was not running. It also wouldn't disable DPMS
+so the display would power down normally on a synergy client if
+there was no input activity.
+
+----------
+2004/03/10 20:35:03 crs
+acinclude.m4
+lib/arch/CArchNetworkBSD.cpp
+
+Added check for inet_aton and a simple implementation for platforms
+that are missing it.
+
+----------
+2004/03/08 21:18:36 crs
+configure.in
+lib/platform/CXWindowsKeyMapper.cpp
+
+Removed dependency on X11/XF86keysym.h. There are several versions
+of that file in existance, not all of which have all the symbols we
+require and none of which provide any convenient means of telling
+what groups of symbols they define.
+
+----------
+2004/03/08 20:53:32 crs
+lib/platform/CMSWindowsKeyMapper.cpp
+lib/platform/CMSWindowsKeyMapper.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CSynergyHook.cpp
+lib/server/CServer.cpp
+
+Win32 fixes. Fixed slightly off cursor positioning when using
+absolute mouse_event(). Improved keyboard handling: now using
+keyboard layout of last foreground window when leaving server
+so users can meaningfully choose the locale, moved dead key
+handling into hook library so there should be no more race
+conditions involving the keyboard dead key buffer, simplified
+keyboard and cursor handling by using a full screen transparent
+window when not using low level hooks, fixed error in restoring
+buffered dead key when checking for dead keys. This hopefully
+fixes all known keyboard bugs on win32.
+
+----------
+2004/03/08 20:45:53 crs
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+
+Typecasting fix to compile on old solaris.
+
+----------
+2004/03/06 16:20:08 crs
+lib/platform/CXWindowsScreen.cpp
+lib/server/CServer.cpp
+
+Server now disables jump zones when scroll lock is active.
+
+----------
+2004/02/29 21:34:30 crs
+lib/platform/CMSWindowsEventQueueBuffer.cpp
+
+Fixed processing of events. Was waking up on a sent (rather than
+posted) message but then blocking in GetMessage() which handles
+the sent message directly. No longer blocking on sent messages.
+
+----------
+2004/02/29 21:33:20 crs
+lib/arch/CArchNetworkWinsock.cpp
+
+Fixed handling of winsock connect event. Was always immediately
+indicating socket had connected.
+
+----------
+2004/02/29 21:32:00 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Fixed cursor hiding on win32. Still fails occassionally.
+
+----------
+2004/02/29 21:31:24 crs
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.rc
+
+Added reload configuration menu item to win32 task bar.
+
+----------
+2004/02/29 17:36:32 crs
+lib/arch/IArchMultithread.h
+
+Fixed comment.
+
+----------
+2004/02/29 17:29:01 crs
+lib/arch/CArchMultithreadWindows.h
+
+Switched to doxygen comments.
+
+----------
+2004/02/29 17:28:51 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/server/CClientProxy.cpp
+lib/server/CClientProxy.h
+lib/server/CServer.cpp
+lib/synergy/IScreen.cpp
+lib/synergy/IScreen.h
+
+Moved clipboard changed event to CClientProxy because only it
+and CServer use it. CServerProxy instead makes a direct call
+to CClient, like it does for most other messages.
+
+----------
+2004/02/29 16:48:22 crs
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+
+Fixed BSD unblockPollSocket(). Was signaling to break out of
+poll() but there was a race condition where the thread trying
+to unblock poll() could send the signal before the polling
+thread had entered poll(). Now using a pipe and polling on
+that and the client's sockets, and just writing a byte into
+the pipe to unblock poll. This persists until the next call
+to poll() so we might force poll() to return once unnecessarily
+but that's not a problem. This change makes the BSD code
+similar to the winsock code, which uses a winsock event instead
+of a pipe.
+
+----------
+2004/02/29 16:11:17 crs
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/arch/CArchNetworkWinsock.cpp
+lib/arch/CArchNetworkWinsock.h
+lib/arch/IArchNetwork.h
+lib/arch/XArch.h
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPSocket.cpp
+
+Made all arch sockets non-blocking.
+
+----------
+2004/02/28 17:51:55 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Enabled running at high priority on windows.
+
+----------
+2004/02/28 17:49:29 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchConsoleWindows.cpp
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchMultithreadWindows.h
+lib/arch/IArchMultithread.h
+lib/base/CEventQueue.cpp
+
+Generalized signal handling. Now handling SIGHUP in addition
+to SIGINT and SIGTERM. Setup SIGHUP to reload the server's
+configuration.
+
+----------
+2004/02/28 16:06:00 crs
+lib/base/CLog.cpp
+
+Fixed incorrect accumulation of newlines in log.
+
+----------
+2004/02/28 16:00:54 crs
+lib/client/CServerProxy.cpp
+
+Now using first set options message as end of handshake.
+
+----------
+2004/02/28 12:30:52 crs
+lib/platform/CMSWindowsUtil.cpp
+lib/platform/CMSWindowsUtil.h
+
+Added missing files.
+
+----------
+2004/02/28 12:24:47 crs
+lib/common/Version.cpp
+
+Added missing file.
+
+----------
+2004/02/28 12:19:49 crs
+acinclude.m4
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
+cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/CXWindowsClientTaskBarReceiver.h
+cmd/synergyc/Makefile.am
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.rc
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CMSWindowsServerTaskBarReceiver.h
+cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CXWindowsServerTaskBarReceiver.h
+cmd/synergys/Makefile.am
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.rc
+configure.in
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchConsoleWindows.cpp
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchDaemonWindows.h
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchMultithreadWindows.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/arch/CArchNetworkWinsock.cpp
+lib/arch/CArchNetworkWinsock.h
+lib/arch/CArchTaskBarWindows.cpp
+lib/arch/CArchTaskBarWindows.h
+lib/arch/IArchMultithread.h
+lib/arch/IArchNetwork.h
+lib/arch/arch.dsp
+lib/base/CEventQueue.cpp
+lib/base/CPriorityQueue.h
+lib/base/CSimpleEventQueueBuffer.cpp
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/common/Makefile.am
+lib/common/Version.h
+lib/common/common.dsp
+lib/mt/CThread.cpp
+lib/mt/CThread.h
+lib/net/CSocketMultiplexer.cpp
+lib/net/IDataSocket.cpp
+lib/net/IDataSocket.h
+lib/platform/CMSWindowsDesktop.h
+lib/platform/CMSWindowsEventQueueBuffer.cpp
+lib/platform/CMSWindowsEventQueueBuffer.h
+lib/platform/CMSWindowsKeyMapper.cpp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CSynergyHook.h
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsEventQueueBuffer.cpp
+lib/platform/CXWindowsKeyMapper.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/Makefile.am
+lib/platform/platform.dsp
+lib/server/CClientListener.cpp
+lib/server/CServer.cpp
+lib/synergy/CProtocolUtil.cpp
+lib/synergy/CProtocolUtil.h
+lib/synergy/CScreen.cpp
+lib/synergy/IScreen.h
+
+Merged Win32 updates. Added full warnings on g++. Fixed bug in
+client when handling server rejection.
+
+----------
+2004/02/15 18:12:35 crs
+lib/base/CFunctionEventJob.cpp
+lib/base/CJobList.cpp
+lib/base/CJobList.h
+lib/base/Makefile.am
+lib/base/base.dsp
+lib/io/io.dsp
+lib/mt/CTimerThread.cpp
+lib/mt/CTimerThread.h
+lib/mt/Makefile.am
+lib/mt/mt.dsp
+lib/net/net.dsp
+lib/platform/CMSWindowsEventQueueBuffer.cpp
+lib/platform/CMSWindowsEventQueueBuffer.h
+lib/platform/Makefile.am
+lib/platform/platform.dsp
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+
+Updated Makefiles and win32 projects and removed dead classes.
+
+----------
+2004/02/15 17:32:11 crs
+cmd/synergyc/CClientTaskBarReceiver.cpp
+cmd/synergyc/CClientTaskBarReceiver.h
+cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/CXWindowsClientTaskBarReceiver.h
+cmd/synergyc/synergyc.cpp
+cmd/synergys/CServerTaskBarReceiver.cpp
+cmd/synergys/synergys.cpp
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/XArch.h
+lib/base/CEvent.cpp
+lib/base/CEvent.h
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/io/CStreamFilter.cpp
+lib/net/CNetworkAddress.cpp
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPSocket.cpp
+lib/net/CTCPSocket.h
+lib/net/IDataSocket.h
+lib/net/XSocket.cpp
+lib/net/XSocket.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CConfig.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/synergy/CClipboard.cpp
+lib/synergy/CClipboard.h
+lib/synergy/CPacketStreamFilter.cpp
+lib/synergy/IClient.h
+lib/synergy/IClipboard.cpp
+lib/synergy/IClipboard.h
+lib/synergy/IPlatformScreen.cpp
+lib/synergy/IPlatformScreen.h
+lib/synergy/Makefile.am
+lib/synergy/ProtocolTypes.h
+
+Checkpoint. Conversion to event driven system complete for Unix.
+Still need to convert win32 platform specific files.
+
+----------
+2004/02/14 16:30:27 crs
+cmd/synergys/CServerTaskBarReceiver.cpp
+cmd/synergys/synergys.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+
+Minor cleanup.
+
+----------
+2004/02/14 14:04:36 crs
+cmd/synergys/CServerTaskBarReceiver.cpp
+cmd/synergys/CServerTaskBarReceiver.h
+cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CXWindowsServerTaskBarReceiver.h
+cmd/synergys/Makefile.am
+cmd/synergys/synergys.cpp
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/arch/IArchNetwork.h
+lib/arch/vsnprintf.cpp
+lib/base/CEvent.cpp
+lib/base/CEvent.h
+lib/base/CEventQueue.cpp
+lib/base/CEventQueue.h
+lib/base/CSimpleEventQueueBuffer.cpp
+lib/base/CSimpleEventQueueBuffer.h
+lib/base/CStringUtil.cpp
+lib/base/IEventQueue.h
+lib/base/IEventQueueBuffer.h
+lib/io/IStream.cpp
+lib/net/CNetworkAddress.cpp
+lib/net/CNetworkAddress.h
+lib/net/CSocketMultiplexer.cpp
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPSocket.cpp
+lib/net/IDataSocket.cpp
+lib/net/IListenSocket.cpp
+lib/net/ISocket.cpp
+lib/platform/CXWindowsEventQueue.cpp
+lib/platform/CXWindowsEventQueue.h
+lib/platform/CXWindowsEventQueueBuffer.cpp
+lib/platform/CXWindowsEventQueueBuffer.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+lib/platform/Makefile.am
+lib/server/CClientListener.cpp
+lib/server/CClientListener.h
+lib/server/CClientProxy.cpp
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxy1_1.cpp
+lib/server/CClientProxy1_1.h
+lib/server/CClientProxyUnknown.cpp
+lib/server/CClientProxyUnknown.h
+lib/server/CConfig.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/Makefile.am
+lib/synergy/CProtocolUtil.cpp
+lib/synergy/CScreen.cpp
+lib/synergy/CScreen.h
+lib/synergy/IClient.h
+lib/synergy/IPlatformScreen.cpp
+lib/synergy/IPlatformScreen.h
+lib/synergy/IPrimaryScreen.h
+lib/synergy/IPrimaryScreenReceiver.h
+lib/synergy/IScreen.cpp
+lib/synergy/IScreen.h
+lib/synergy/IScreenFactory.h
+lib/synergy/IScreenReceiver.h
+lib/synergy/IScreenSaver.h
+lib/synergy/IServer.h
+lib/synergy/Makefile.am
+
+Checkpoint. synergys now works. Still need to do lib/client and
+synergyc.
+
+----------
+2004/02/08 17:07:11 crs
+lib/base/CEventQueue.cpp
+lib/base/CEventQueue.h
+lib/base/CSimpleEventQueue.cpp
+lib/base/CSimpleEventQueue.h
+lib/base/IEventQueue.h
+lib/base/Makefile.am
+
+Refactored event queue. The event queue is now separated from the
+buffer that holds the events and generates system events. This
+allows us to switch in/out a platform specific event handler as
+necessary without losing our timers and handlers.
+
+----------
+2004/02/08 16:51:45 crs
+lib/net/CTCPSocket.cpp
+
+No longer sending incorrect disconnect events in read() and
+removed redundant sending of disconnect event in close().
+
+----------
+2004/02/01 21:09:22 crs
+cmd/synergys/synergys.cpp
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/IArchMultithread.h
+lib/arch/XArch.h
+lib/base/CEventQueue.cpp
+lib/base/CEventQueue.h
+lib/base/IEventQueue.cpp
+lib/base/IEventQueue.h
+lib/base/Makefile.am
+lib/io/CBufferedInputStream.cpp
+lib/io/CBufferedInputStream.h
+lib/io/CBufferedOutputStream.cpp
+lib/io/CBufferedOutputStream.h
+lib/io/CInputStreamFilter.cpp
+lib/io/CInputStreamFilter.h
+lib/io/COutputStreamFilter.cpp
+lib/io/COutputStreamFilter.h
+lib/io/CStreamFilter.cpp
+lib/io/CStreamFilter.h
+lib/io/IInputStream.h
+lib/io/IOutputStream.h
+lib/io/IStream.cpp
+lib/io/IStream.h
+lib/io/IStreamFilterFactory.h
+lib/io/Makefile.am
+lib/io/XIO.cpp
+lib/io/XIO.h
+lib/net/CSocketMultiplexer.cpp
+lib/net/CSocketMultiplexer.h
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPListenSocket.h
+lib/net/CTCPSocket.cpp
+lib/net/CTCPSocket.h
+lib/net/IDataSocket.cpp
+lib/net/IDataSocket.h
+lib/net/IListenSocket.h
+lib/net/ISocket.h
+lib/net/ISocketMultiplexerJob.h
+lib/net/Makefile.am
+lib/net/TSocketMultiplexerMethodJob.h
+lib/server/CClientProxy.cpp
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxy1_1.cpp
+lib/server/CClientProxy1_1.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CHTTPServer.cpp
+lib/server/CHTTPServer.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/Makefile.am
+lib/synergy/CInputPacketStream.cpp
+lib/synergy/CInputPacketStream.h
+lib/synergy/COutputPacketStream.cpp
+lib/synergy/COutputPacketStream.h
+lib/synergy/CPacketStreamFilter.cpp
+lib/synergy/CPacketStreamFilter.h
+lib/synergy/CProtocolUtil.cpp
+lib/synergy/CProtocolUtil.h
+lib/synergy/Makefile.am
+
+Checkpoint. Code does not run. Still converting over to new
+event loop model. Streams, stream filters, and sockets are
+converted. Client proxies are almost converted. CServer is
+in progress. Removed all HTTP code. Haven't converted the
+necessary win32 arch stuff.
+
+----------
+2004/02/01 20:56:52 crs
+cmd/launcher/launcher.dsp
+cmd/synergys/Makefile.am
+cmd/synergys/synergys.dsp
+configure.in
+lib/Makefile.am
+lib/http/CHTTPProtocol.cpp
+lib/http/CHTTPProtocol.h
+lib/http/Makefile.am
+lib/http/XHTTP.cpp
+lib/http/XHTTP.h
+lib/http/http.dsp
+lib/server/server.dsp
+synergy.dsw
+
+Removed most HTTP stuff. It doesn't seem like the appropriate
+choice for server control. May later provide some other means
+for controlling the synergy server remotely.
+
+----------
+2004/01/24 16:09:25 crs
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/IArchMultithread.h
+lib/base/CEvent.cpp
+lib/base/CEvent.h
+lib/base/CEventQueue.cpp
+lib/base/CEventQueue.h
+lib/base/CFunctionEventJob.cpp
+lib/base/CFunctionEventJob.h
+lib/base/CLog.cpp
+lib/base/CPriorityQueue.h
+lib/base/CSimpleEventQueue.cpp
+lib/base/CSimpleEventQueue.h
+lib/base/IEventJob.h
+lib/base/IEventQueue.h
+lib/base/Makefile.am
+lib/base/TMethodEventJob.h
+lib/io/CBufferedInputStream.cpp
+lib/io/CBufferedInputStream.h
+lib/io/CBufferedOutputStream.cpp
+lib/io/CBufferedOutputStream.h
+lib/mt/CThread.cpp
+lib/mt/CThread.h
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPListenSocket.h
+lib/net/CTCPSocket.cpp
+lib/net/CTCPSocket.h
+lib/net/IDataSocket.cpp
+lib/net/IDataSocket.h
+lib/net/IListenSocket.cpp
+lib/net/IListenSocket.h
+lib/net/ISocket.cpp
+lib/net/ISocket.h
+lib/net/Makefile.am
+lib/platform/CXWindowsEventQueue.cpp
+lib/platform/CXWindowsEventQueue.h
+lib/platform/Makefile.am
+
+Checkpointing centralized event queue stuff. Currently have:
+an event queue and events, TCP sockets converted to use events,
+unix multithreading and network stuff converted, and an X Windows
+event queue subclass.
+
+----------
+2003/07/19 17:22:06 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+cmd/synergyc/synergyc.cpp
+configure.in
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/common/Version.h
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/server/CConfig.cpp
+lib/synergy/OptionTypes.h
+
+Merge synergy 1.1 fixes into 1.0 branch.
+
+----------
+2003/07/19 17:19:26 crs
+
+Branched synergy 1.0 from 1.0.11.
+
+----------
+2003/07/17 21:16:58 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Fixed handling of a dead key followed by space on win32 and X11.
+A dead key followed by space should convert the dead key to a
+regular character.
+
+----------
+2003/07/16 22:38:43 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+
+Fixed handling of some non-ASCII but directly mapped characters
+on win32. The o, a, and u with diaeresis in the german keyboard
+mapping are examples.
+
+----------
+2003/07/16 21:40:57 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+
+Fixed handling of shift/ctrl/alt on special keys on win32 server.
+
+----------
+2003/07/13 20:42:11 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+
+Fixed handling of some keystrokes on win32. Pressing a dead key
+and then space should convert the dead key to a non-dead key but
+previous the key was discarded. Fixed that but VkKeyScan() fails
+in this case so added special case to fix that (assuming AltGr is
+required). VkKeyScan() can return the wrong result for characters
+that have more than one virtual key mapped to them. AltGr+9 (^)
+on the French layout has this problem. Now detecting that problem
+and using the current keyboard state to decide if AltGr is
+required.
+
+----------
+2003/07/13 17:03:41 crs
+cmd/synergyc/synergyc.cpp
+
+Forgot to remove --camp and --no-camp from brief usage message.
+
+----------
+2003/07/13 16:57:08 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Changed XSync() to XFlush() in X windows secondary screen. This
+doesn't appear to have any negative consequences and may prevent
+synergy from freezing when some X client (probably the window
+manager) grabs the server.
+
+----------
+2003/07/12 17:57:31 crs
+cmd/synergyc/synergyc.cpp
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CXWindowsScreen.cpp
+
+Prevent INFO level log messages when client is repeatedly trying
+to connect. This prevents a log from filling up while the client
+can't connect for no useful reason. Also removed --camp option
+and cleaned up handling of client connection. Users must now use
+--restart instead of --camp.
+
+----------
+2003/07/08 18:40:46 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+
+Changed windows server to release ctrl and alt keys when it's
+sending a key that requires AltGr. That's because AltGr *is*
+ctrl and alt but AltGr should be seen on clients as mode
+switch without the ctrl and alt. I can't think of a better
+way to do this other than to not send modifier keystrokes to
+the clients at all.
+
+----------
+2003/07/05 17:06:18 crs
+configure.in
+lib/common/Version.h
+
+Change version to 1.0.11. Skipping version 1.0.10 because there
+have been too many major changes since 1.0.8. A new experimental
+release will provide a stable starting point for testing.
+
+----------
+2003/07/05 17:05:12 crs
+lib/synergy/CSecondaryScreen.cpp
+
+Fix to avoid warping mouse until client successfully connects to
+the server.
+
+----------
+2003/07/05 17:04:26 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+
+Keyboard fixes on win32.
+
+----------
+2003/07/05 17:04:06 crs
+lib/server/CConfig.h
+
+Fix for new template syntax.
+
+----------
+2003/07/05 14:49:08 crs
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsPrimaryScreen.h
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Minor X11 keyboard code cleanup. Also now handling KeyPress with
+keycode == 0 generated by XFilterEvent() by using the keycode from
+the previous KeyPress.
+
+----------
+2003/07/05 14:47:41 crs
+lib/platform/CXWindowsScreen.cpp
+
+Compress sequential MappingNotify events into one.
+
+----------
+2003/07/01 19:35:28 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Rewrote key handling on X11 client. This should fix problems
+with applying the incorrect shift and mode switch modifiers to
+some keycodes, such as getting Pointer_EnableKeys when pressing
+shift with NumLock enabled.
+
+----------
+2003/06/22 21:27:38 crs
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsPrimaryScreen.h
+
+Added support for input methods. Only handling IMs that don't
+need a precompose area or status area. This includes IMs that
+do simple dead key composition. This only changes the server.
+The client still does not decompose a character it cannot
+generate directly into the keysyms to compose the character.
+
+----------
+2003/06/22 16:39:25 crs
+lib/client/CServerProxy.cpp
+
+More fixes for X11 client keyboard handling.
+
+----------
+2003/06/22 16:39:02 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+More fixes for X11 client keyboard handling.
+
+----------
+2003/06/22 15:01:44 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Checkpoint for improving X11 client key handling. Should prevent
+unintentional Pointer_EnableKeys (i.e. generating NumLock press
+and release around a shift press).
+
+----------
+2003/06/08 22:20:01 crs
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Another ctrl+alt+del checkpoint.
+
+----------
+2003/06/08 22:12:12 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+ctrl+alt+del emulation checkpoint.
+
+----------
+2003/06/08 16:31:52 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+More DEBUG2 level debugging of keyboard handling.
+
+----------
+2003/06/08 15:42:05 crs
+lib/common/Makefile.am
+
+Added new file to Makefile.
+
+----------
+2003/06/02 20:07:16 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+
+Fixed ctrl and alt keys on win32 clients. Was broken by a recent
+fix to character handling.
+
+----------
+2003/06/02 20:06:20 crs
+lib/client/CServerProxy.cpp
+
+Fixed errors in log strings.
+
+----------
+2003/06/02 20:06:03 crs
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.rc
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CMSWindowsServerTaskBarReceiver.h
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.rc
+lib/base/CLog.cpp
+lib/base/CLog.h
+lib/base/LogOutputters.cpp
+lib/base/LogOutputters.h
+lib/common/common.dsp
+lib/common/stddeque.h
+
+Added menu item on win32 tray icon to copy the last 1000 lines from
+the log to the clipboard.
+
+----------
+2003/05/26 09:50:35 crs
+lib/platform/CXWindowsClipboard.cpp
+
+Added workaround for broken clipboard owners that report the
+type of TARGETS as TARGETS instead of ATOM.
+
+----------
+2003/05/26 09:49:38 crs
+lib/platform/CMSWindowsClipboard.cpp
+
+No longer installing clibboard format for plain text on windows nt
+family because nt automatically converts to and from the unicode
+format. This may fix text encoding errors when synergy puts
+non-ascii text on the clipboard and other clients prefer CF_TEXT
+to CF_UNICODE (which they should not because synergy lists
+CF_UNICODE first).
+
+----------
+2003/05/26 09:46:52 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsScreen.cpp
+
+Fixed loss of ctrl+alt+del key releases when the Winlogin desktop
+is accessible (was already fixed when inaccessible). This change
+also ignores press and release of virtual key 0, which should never
+happen but does according to one user.
+
+----------
+2003/05/21 21:22:14 crs
+lib/arch/CArchMultithreadWindows.cpp
+lib/synergy/CPrimaryScreen.cpp
+lib/synergy/CSecondaryScreen.cpp
+
+Fixed unsigned compare against zero. Changed win32 priority to
+maximum.
+
+----------
+2003/05/21 19:38:11 crs
+lib/server/CServer.cpp
+lib/server/CServer.h
+
+Made double tap require moving farther away from the tapped edge
+before arming. This should reduce spurious double taps.
+
+----------
+2003/05/20 19:15:58 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+
+Attempt to improve key event synthesis. This change adds support
+for dead keys and attempts to choose the correct code page for the
+thread that will (probably) receive synthesized events.
+
+----------
+2003/05/20 19:14:40 crs
+lib/platform/CSynergyHook.cpp
+
+Minor thread ID compare fix.
+
+----------
+2003/05/20 19:14:24 crs
+lib/arch/CArchMultithreadWindows.cpp
+
+Reduced maximum priority in debug build.
+
+----------
+2003/05/17 20:58:27 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/IMSWindowsScreenEventHandler.h
+lib/synergy/CPrimaryScreen.cpp
+
+Fixed getting locked to screen after ctrl+alt+del. Also fixed
+cursor not being hidden on win32 server when on client screens
+(which happened when using low-level hooks).
+
+----------
+2003/05/17 14:10:11 crs
+INSTALL
+
+Added documentation for xtestIsXineramaUnaware option.
+
+----------
+2003/05/17 14:03:32 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Fixed previous fix. Was trying to avoid using XWarpPointer() when
+warping on screen 0. That just doesn't work if screen 0 is not at
+0,0. So now always use XWarpPointer() if there are multiple
+xinerama screens and the appropriate option is enabled.
+
+----------
+2003/05/17 13:44:24 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/server/CConfig.cpp
+lib/synergy/OptionTypes.h
+
+Added workaround for when XTest is unaware of Xinerama. When that's
+true, faking a mouse motion outside screen 0 is clamped onto screen 0.
+When the workaround is enabled, we use XWarpPointer() instead of an
+XTest fake motion. This isn't perfect but the only real fix requires
+patching XTest.
+
+----------
+2003/05/17 12:48:32 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Added support for old versions of XF86keysym.h that are missing
+some expected #defines.
+
+----------
+2003/05/10 17:27:05 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.0.8.
+
+----------
+2003/05/10 17:26:42 crs
+INSTALL
+README
+
+Updated documentation.
+
+----------
+2003/05/08 21:59:35 crs
+lib/server/CServer.cpp
+
+Fixed jumping to same client screen. It was broken by an earlier
+change (probably double tap). Jumping to the same server screen
+worked correctly.
+
+----------
+2003/05/04 21:40:42 crs
+configure.in
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/synergy/KeyTypes.h
+lib/synergy/MouseTypes.h
+
+Added support for 4th and 5th (non-mouse-wheel) buttons and
+"Internet" keyboard keys.
+
+----------
+2003/05/03 15:16:30 crs
+cmd/launcher/CGlobalOptions.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Added screen saver synchronization option to win32 launcher dialog.
+
+----------
+2003/05/03 14:54:03 crs
+lib/synergy/CSecondaryScreen.cpp
+
+Removed accidental debugging code.
+
+----------
+2003/05/03 14:38:36 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/server/CConfig.cpp
+lib/synergy/CSecondaryScreen.cpp
+lib/synergy/CSecondaryScreen.h
+lib/synergy/OptionTypes.h
+
+Added global configuration option to disable screen saver
+synchronization.
+
+----------
+2003/05/03 13:57:52 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Forgot to restore global auto-repeat configuration on exit.
+
+----------
+2003/05/03 13:50:06 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/synergy/CSecondaryScreen.cpp
+lib/synergy/CSecondaryScreen.h
+
+Now warping mouse to center of screen when leaving client screens.
+Some users requested this. Also, the hider window is mapped before
+warping the mouse so the active window shouldn't change if the focus
+policy is point-to-focus. Showing the window first can also reduce
+the likelihood of seeing the cursor briefly in its hidden position.
+
+----------
+2003/05/03 13:28:21 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Now turning off auto-repeat when on an X11 client. This prevents
+the server from auto-repeating fake events, which is undesired
+since synergy will do the auto-repeating itself. This also
+disables auto-repeat on any keys locally configured on X11 to not
+auto-repeat. That's mainly to suppress auto-repeat on modifier
+keys, which auto-repeat on win32 but not X11.
+
+----------
+2003/05/03 12:54:22 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CSynergyHook.h
+
+Fixed a few win32 keyboard/mouse problems. First, the mouse hook
+now captures non-client area mouse messages. Previously, these
+were ignored (because i forgot about them) and they caused all
+kinds of problems because they weren't forwarded. For example,
+clicking on a window border would cause the window to start
+resizing when the mouse came back to the server screen. Moving
+inside a title bar meant that the mouse wouldn't move on the
+client screen.
+
+Second, because non-client messages are now handled, the full
+screen transparent window is no longer necessary to capture
+input so it's never displayed. (The window is still necessary
+for clipboard ownership so it's still created.) No transparent
+window means no screen flashing. It also means we don't have to
+become the foreground and active window. This plays better with
+apps that minimize or restore when they're no longer the
+foreground application/active window.
+
+Third, fixed the low level keyboard hook to forward toggle key
+updates, which it was neglecting to do.
+
+Finally, keyboard and mouse input is always forwarded from the hook
+to the primary screen handler which then shadows the current key
+and mouse button state. If we're using low level hooks then this
+isn't really necessary and GetKeyState() always returns the right
+info but without low level hooks it means we can just use the
+shadow state. It also means we don't have to show our window in
+order to get the system's key state table up to date, fixing the
+screen flash when checking for the scroll lock state.
+
+----------
+2003/05/03 12:37:03 crs
+lib/arch/CArchMultithreadWindows.cpp
+lib/synergy/CPrimaryScreen.cpp
+lib/synergy/CSecondaryScreen.cpp
+
+Boosted priority of main synergy threads to be very high (highest
+realtime priority). After some testing it appears that anything
+less than this can starve synergy in some circumstances, preventing
+it from forwarding messages to clients. This is a rather risky
+change since synergy can now virtually take over a system if it
+behaves badly. This change only affects windows systems since
+lib/arch of other platforms don't yet attempt to boost priority.
+
+----------
+2003/04/27 18:05:32 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/server/Makefile.am
+lib/server/server.dsp
+
+Fixes to previous checkpoint. Non-ascii keys seem to work correctly.
+Still not supporting key composition on X11.
+
+----------
+2003/04/27 17:01:14 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CServerProxy.cpp
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CClientProxy1_1.cpp
+lib/server/CClientProxy1_1.h
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/Makefile.am
+lib/synergy/CSecondaryScreen.h
+lib/synergy/IClient.h
+lib/synergy/IPrimaryScreenReceiver.h
+lib/synergy/KeyTypes.h
+lib/synergy/ProtocolTypes.h
+
+Checkpointing improved key handling. This change adds non-ASCII
+key handling to win32 on both client and server. It also changes
+the protocol and adds code to ensure every key pressed also gets
+released and that that doesn't get confused when the KeyID for
+the press is different from the KeyID of the release (or repeat).
+
+----------
+2003/04/24 20:11:38 crs
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsUtil.cpp
+lib/platform/CXWindowsUtil.h
+
+Added KeySym <-> Unicode mappings. Changed code to use those
+mappings to better support Unicode key events.
+
+----------
+2003/04/24 20:10:13 crs
+cmd/Makefile.am
+
+Added exec.dsp to EXTRA_DIST.
+
+----------
+2003/04/16 20:59:25 crs
+all.dsp
+cmd/exec.dsp
+lib/platform/makehook.dsp
+lib/platform/synrgyhk.dsp
+synergy.dsw
+
+Win32 project configuration fixes.
+
+----------
+2003/04/16 20:59:14 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/platform/CMSWindowsPrimaryScreen.cpp
+
+Minor win32 fixes.
+
+----------
+2003/04/16 20:05:00 crs
+lib/server/CConfig.cpp
+
+Now allowing screen names with underscores.
+
+----------
+2003/04/14 22:16:21 crs
+lib/platform/CXWindowsPrimaryScreen.cpp
+
+Fixed incorrect initialization of an XMotionEvent.
+
+----------
+2003/04/14 22:15:56 crs
+configure.in
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+
+Added workaround for apparent Xinerama bug when warping the pointer.
+This should allow synergy to be used on a system using Xinerama to
+create a single logical screen from multiple physical screens.
+
+----------
+2003/04/13 18:14:01 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Fixed problem with type casting void* to int.
+
+----------
+2003/04/13 17:13:27 crs
+lib/platform/CXWindowsScreenSaver.cpp
+
+Removed periodic call to XForceScreenSaver() to prevent the built-in
+screen saver from activating. It was unnecessary since the built-in
+screen saver is disabled as appropriate; this call was just to
+ensure that the screen saver wouldn't start if an external program
+reactivated the screen saver after synergy disabled it.
+
+It's possible that this was causing screen flicker under gnome, though
+i don't know why. It's also possible that periodically sending events
+to xscreensaver is causing the flicker but removing that code is more
+difficult because xscreensaver can't be disabled, only deactivated or
+killed.
+
+----------
+2003/04/13 14:59:53 crs
+lib/platform/CMSWindowsClipboard.cpp
+lib/platform/CMSWindowsClipboard.h
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CSynergyHook.cpp
+
+Fixed several win32 bugs. First, synergy wasn't forwarding mouse
+events to other hook functions, which broke some tools like objectbar.
+Second, windows key processing was fixed. Previously pressing and
+release the key would only send a press event, locking the user onto
+the client window; also, the win32 server treated as a Meta modifier
+instead of a Super modifier, which broke any use of it as any kind of
+modifier key. Third, added hacks to support several key combinations
+on windows 95/98/me that are treated specially by windows, including
+Alt+Tab, Alt+Shift+Tab, Alt+Esc, Alt+Shift+Esc, Ctrl+Esc, and any
+combination using the windows key like Win+E and Win+F but not
+Ctrl+Alt+Del. Fourth, scroll lock only locking to the client (which
+only happened when using a synergy server on windows) has been fixed;
+unfortunately the solution causes a lot of screen redraws for some
+reason. Finally, there's been a fix to clipboard handling that may
+or may not fix a problem where the clipboard would stop transferring
+between systems after a little while. I can't be sure if it fixes
+the problem because I can't reproduce the problem.
+
+----------
+2003/04/13 14:39:17 crs
+cmd/launcher/launcher.rc
+
+Added mention of tray icon to launcher start message box.
+
+----------
+2003/03/26 21:03:58 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.0.6.
+
+----------
+2003/03/25 21:31:39 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CSynergyHook.cpp
+
+This should fix multimon support on win32.
+
+----------
+2003/03/22 11:49:23 crs
+FAQ
+INSTALL
+PORTING
+README
+TODO
+
+Documentation updates.
+
+----------
+2003/03/22 11:49:13 crs
+cmd/launcher/CGlobalOptions.cpp
+cmd/launcher/CGlobalOptions.h
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Added key modifier and heartbeat options to GUI.
+
+----------
+2003/03/21 19:34:08 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+
+Oops, included a windows only header in non-windows builds.
+
+----------
+2003/03/21 19:16:37 crs
+lib/platform/CMSWindowsScreenSaver.cpp
+
+Added check for the screen saver actually being active before
+entering the loop waiting for it to deactivate. The failure
+to check was causing the screen saver code to kick in when
+the screen saver timeout occurred, even if the screen saver
+wasn't enabled (because Windows still sends the screen saver
+activating message for no good reason when the screen saver
+is disabled).
+
+----------
+2003/03/21 19:14:32 crs
+lib/arch/CArchMiscWindows.cpp
+
+Fixed errors in merge causing infinite loops.
+
+----------
+2003/03/21 19:14:10 crs
+cmd/synergyc/tb_idle.ico
+cmd/synergyc/tb_run.ico
+cmd/synergyc/tb_wait.ico
+cmd/synergys/tb_idle.ico
+cmd/synergys/tb_run.ico
+cmd/synergys/tb_wait.ico
+
+Fixed icons.
+
+----------
+2003/03/21 19:13:15 crs
+lib/platform/CXWindowsUtil.cpp
+
+Fixed getWindowProperty(). It wasn't catching all failure
+cases correctly.
+
+----------
+2003/03/17 22:32:10 crs
+cmd/launcher/CAdvancedOptions.cpp
+cmd/launcher/CAdvancedOptions.h
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/LaunchUtil.h
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchDaemonWindows.h
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+
+Added options and advanced options dialogs which should've been
+part of an earlier checkin. Also now saving and restoring
+options that aren't in the configuration file to/from the
+registry.
+
+----------
+2003/03/17 22:32:01 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/server/CServer.cpp
+lib/synergy/CPrimaryScreen.h
+
+Added a log message why the user is locked to the screen.
+
+----------
+2003/03/17 22:31:59 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+
+Added type casts to avoid warning.
+
+----------
+2003/03/16 17:40:57 crs
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CMSWindowsScreenSaver.h
+
+Fixed detection of screen saver shutdown on windows nt.
+
+----------
+2003/03/16 17:40:56 crs
+lib/common/Makefile.am
+lib/common/common.dsp
+lib/common/stdbitset.h
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+
+Made releaseKeys() only synthesize key releases for those keys
+that synergy synthesized a press for, not keys that the user
+is physically pressing.
+
+----------
+2003/03/16 17:40:47 crs
+lib/platform/CSynergyHook.cpp
+
+Minor hook fixes.
+
+----------
+2003/03/16 17:40:25 crs
+cmd/synergyc/synergyc.rc
+cmd/synergys/synergys.rc
+
+Added resources missing from previous checkin.
+
+----------
+2003/03/13 20:24:45 crs
+lib/platform/CXWindowsScreenSaver.cpp
+
+Moved comment to more relevant location.
+
+----------
+2003/03/13 19:20:55 crs
+lib/platform/CXWindowsScreen.cpp
+
+Fixed double locking of mutex.
+
+----------
+2003/03/12 22:34:07 crs
+cmd/launcher/CAdvancedOptions.cpp
+cmd/launcher/CAdvancedOptions.h
+cmd/launcher/CGlobalOptions.cpp
+cmd/launcher/CGlobalOptions.h
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/LaunchUtil.h
+cmd/launcher/Makefile.am
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/resource.h
+cmd/synergyc/CClientTaskBarReceiver.cpp
+cmd/synergyc/CClientTaskBarReceiver.h
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
+cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
+cmd/synergyc/CXWindowsClientTaskBarReceiver.h
+cmd/synergyc/Makefile.am
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.dsp
+cmd/synergyc/tb_error.ico
+cmd/synergyc/tb_idle.ico
+cmd/synergyc/tb_run.ico
+cmd/synergyc/tb_wait.ico
+cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CMSWindowsServerTaskBarReceiver.h
+cmd/synergys/CServerTaskBarReceiver.cpp
+cmd/synergys/CServerTaskBarReceiver.h
+cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
+cmd/synergys/CXWindowsServerTaskBarReceiver.h
+cmd/synergys/Makefile.am
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.dsp
+cmd/synergys/tb_error.ico
+cmd/synergys/tb_idle.ico
+cmd/synergys/tb_run.ico
+cmd/synergys/tb_wait.ico
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchConsoleWindows.cpp
+lib/arch/CArchConsoleWindows.h
+lib/arch/CArchImpl.cpp
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchMultithreadWindows.h
+lib/arch/CArchTaskBarWindows.cpp
+lib/arch/CArchTaskBarWindows.h
+lib/arch/CArchTaskBarXWindows.cpp
+lib/arch/CArchTaskBarXWindows.h
+lib/arch/IArchMultithread.h
+lib/arch/IArchTaskBar.h
+lib/arch/IArchTaskBarReceiver.h
+lib/arch/Makefile.am
+lib/arch/arch.dsp
+lib/base/CJobList.cpp
+lib/base/CJobList.h
+lib/base/LogOutputters.cpp
+lib/base/LogOutputters.h
+lib/base/Makefile.am
+lib/base/base.dsp
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CServerProxy.cpp
+lib/mt/CThread.cpp
+lib/mt/CThread.h
+lib/mt/CTimerThread.cpp
+lib/mt/CTimerThread.h
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/CSecondaryScreen.cpp
+lib/synergy/CSecondaryScreen.h
+
+Added switch delay and double-tap options to win32 and added a
+tray icon to the client and server that gives status feedback to
+the user and allows the user to kill the app.
+
+----------
+2003/02/23 19:29:08 crs
+lib/server/CConfig.cpp
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/OptionTypes.h
+lib/synergy/ProtocolTypes.h
+
+Added support for a user option to require hitting the edge of a
+screen twice within a specified amount of time in order to switch
+screens. This can help prevent unintended switching.
+
+----------
+2003/02/22 21:53:25 crs
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsPrimaryScreen.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/server/CConfig.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/CPrimaryScreen.h
+lib/synergy/IPrimaryScreenReceiver.h
+lib/synergy/IScreenEventHandler.h
+lib/synergy/OptionTypes.h
+
+Added support on X11 for a global option to delay switching screens
+when the mouse reaches a jump zone.
+
+----------
+2003/02/22 16:41:03 crs
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+
+Added global options to CConfig (needed for heartbeat option).
+
+----------
+2003/02/22 16:20:23 crs
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/server/CClientProxy.cpp
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CServer.cpp
+lib/synergy/OptionTypes.h
+lib/synergy/ProtocolTypes.h
+
+Added support for heartbeat global option.
+
+----------
+2003/02/22 15:04:09 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.0.5.
+
+----------
+2003/02/22 15:03:31 crs
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/synergy/KeyTypes.h
+lib/synergy/OptionTypes.h
+
+Changes to support remapping modifier keys on clients.
+
+----------
+2003/02/17 12:44:37 crs
+configure.in
+lib/common/Version.h
+
+Changed version to 1.0.3.
+
+----------
+2003/02/16 19:55:54 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+
+Changed win32 client side cursor warping to be all relative motion
+when not on the primary monitor. This should eliminate the flicker
+between virtual display 0,0 and the correct position. While this
+allows the user to confuse synergy by using the client's mouse,
+synergy recovers quickly and easily from any confusion.
+
+----------
+2003/02/16 19:53:56 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+
+Added hack to heuristically detect bogus mouse motion caused by
+a race condition where the synergy server updates the mouse
+position but the synergy hook later receives a mouse update from
+before the position change (i.e. out of order).
+
+----------
+2003/02/16 19:51:46 crs
+lib/platform/CSynergyHook.cpp
+
+Commented out an unnecessary hook and added a compile time
+switch to disable grabbing of keyboard on win32 to facilitate
+debugging.
+
+----------
+2003/02/16 19:50:36 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Changed heap to stack allocation in an oft-called function for
+data that's never used outside the function.
+
+----------
+2003/02/16 19:49:44 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/arch/CArchMultithreadWindows.cpp
+lib/base/CUnicode.cpp
+
+Fixed memory leaks.
+
+----------
+2003/02/12 20:59:25 crs
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Fixed incorrect mouse button swapping on client screens.
+
+----------
+2003/02/12 20:59:08 crs
+lib/arch/CArchDaemonWindows.cpp
+
+Fixed error in debug build on win32.
+
+----------
+2003/02/12 19:50:22 crs
+lib/arch/vsnprintf.cpp
+
+Added a simple implementation of vsnprintf for unix platforms
+without it using /dev/null, vfprintf(), and vsprintf().
+
+----------
+2003/02/12 19:38:39 crs
+lib/arch/CArchMiscWindows.h
+lib/arch/XArch.h
+lib/base/CLog.h
+lib/base/CString.h
+lib/base/ILogOutputter.h
+lib/mt/CCondVar.h
+lib/mt/CLock.h
+lib/mt/CThread.h
+lib/mt/CTimerThread.h
+
+Made sure every file includes common.h directly or indirectly.
+Also made sure common.h is included before any system headers.
+
+----------
+2003/02/01 18:10:43 crs
+FAQ
+INSTALL
+README
+TODO
+
+Added info about using SSH for authentication and encryption.
+
+----------
+2003/01/29 22:16:40 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+To support keymaps with only upper (or lower) case keysyms we now
+use Xlib to convert an unmatched keysym to upper and lower case and
+use whichever, if any, is not the same as the original keysym.
+This supports case conversion in any language that Xlib supports
+it in.
+
+----------
+2003/01/29 19:32:25 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Applied patch from grmcdorman at users dot sourceforge dot net to
+support keymaps that have only uppercase letters, which is the case
+by default on the Sun X server (for US keyboards anyway).
+
+----------
+2003/01/25 13:39:26 crs
+NEWS
+configure.in
+lib/common/Version.h
+
+Changed version number to 1.0.2.
+
+----------
+2003/01/25 13:34:51 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+
+Added ability to set screen options from the windows launch dialog.
+
+----------
+2003/01/25 13:34:17 crs
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkWinsock.cpp
+
+Added missing entry in a socket family table. This was a serious
+bug and should've failed on all platforms but just happened to
+work on linux and windows.
+
+----------
+2003/01/22 08:37:32 crs
+NEWS
+configure.in
+lib/common/Version.h
+
+Changed version number to 1.0.1.
+
+----------
+2003/01/22 08:36:43 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchDaemonWindows.h
+lib/arch/CArchLogWindows.cpp
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchMultithreadWindows.h
+
+Fixed running as a service on Windows NT family.
+
+----------
+2003/01/18 14:36:19 crs
+lib/arch/CArchSleepWindows.cpp
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CSynergyHook.cpp
+
+Fixed stupid errors introduced by last attempt to fix broken
+mouse behavior on multimonitor windows systems. Those errors
+broke synergy on all windows systems running as a server.
+Also added an attempt to reduce the occasional jump that can
+occur when switching screens when windows is the server.
+
+----------
+2003/01/18 14:31:54 crs
+lib/platform/CXWindowsSecondaryScreen.cpp
+
+Was forcing modifier keys that have no effect on the keysym
+lookup to be up when synthesizing key events. Now leaving
+those modifiers in their current state.
+
+----------
+2003/01/18 10:49:13 crs
+Makefile.am
+
+Added a dist-pkg target to put the binary distribution files into
+a tar gzip file. This is to ease distribution of the binaries on
+systems without a packaging system supported by synergy (which
+currently supports only RPM).
+
+----------
+2003/01/16 21:28:15 crs
+lib/server/CServer.cpp
+
+Fixed lookup of neighbor screens. The first problem was an old
+code in a conditional for moving left that blew an assert verifying
+that the mouse position was really on the screen if the neighbor
+screen wasn't connected.
+
+After that was fixed there was another problem when one screen
+linked to another which then linked (in the same direction) to
+itself. If the latter screen wasn't connected then it'd get into
+an infinite loop.
+
+----------
+2003/01/14 19:46:41 crs
+lib/server/CServer.cpp
+
+Moved log message into conditionals so it only appears when the
+conditions are true.
+
+----------
+2003/01/14 19:46:17 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CSynergyHook.cpp
+
+Another try at fixing broken mouse behavior when a windows system
+has multiple monitors with 0,0 of the virtual desktop not at the
+upper-left.
+
+----------
+2003/01/12 16:35:54 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Added test of using the client's own name as the server name
+with an appropriate error message.
+
+----------
+2003/01/12 16:08:45 crs
+lib/server/CServer.cpp
+
+Now catching and ignoring errors when writing to a socket in those
+cases where errors were not being caught, typically when responding
+to some other socket or protocol error.
+
+----------
+2003/01/11 21:06:21 crs
+acinclude.m4
+configure.in
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/arch/CArchSleepUnix.cpp
+lib/arch/CMultibyteEmu.cpp
+lib/common/Makefile.am
+
+Fixes to support FreeBSD and Darwin.
+
+----------
+2003/01/11 15:16:41 crs
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+
+Synergy no longer tries to suppress the screen saver once it starts.
+It was doing that already if started through synergy but not if
+started by something outside of synergy. In particular, if you
+use `xscreensaver-command --activate' synergy used to send fake
+mouse motion events every 5 seconds to deactivate it. That's
+unlikely to be what the user wanted, especially if the locking is
+enabled since it would force the password dialog to appear.
+
+As before, it's recommended that client screens not use locking
+because xscreensaver will not deactivate without getting a
+password even if we make the request through a programmatic
+interface. Presumably that's for security reasons but it makes
+life harder for synergy.
+
+----------
+2003/01/11 14:01:44 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.cpp
+
+Attempt to fix problems with multimon windows. The mouse position
+reported by the synergy hook dll is in a space with 0,0 in the
+upper-left which is not necessarily the same as the virtual desktop
+space. So the windows primary screen now accounts for that. On
+the secondary screen, mouse_event() doesn't seem to accept negative
+coordinates even on the windows NT family, making monitors with
+negative coordinates inaccessible via absolute moves. So if the
+move will be to negative coordinates, use the windows 95 family
+fallback of absolute moving to 0,0 then relative moving to the
+final position.
+
+----------
+2003/01/08 22:17:44 crs
+FAQ
+INSTALL
+
+Added bit about configuring on Solaris, which requires some
+options to find the X11 includes and libraries.
+
+----------
+2003/01/08 21:36:14 crs
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchNetworkBSD.cpp
+
+Portability fixes. Now builds on Linux 2.2 and 2.4 and solaris.
+Also builds on i386, alpha, G3/G4, and sparc.
+
+----------
+2003/01/08 21:36:13 crs
+lib/client/CClient.cpp
+lib/platform/CXWindowsUtil.cpp
+
+Changed log level of two messages. Now won't spew about reading
+window properties and will report connection failure at DEBUG
+instead of DEBUG1.
+
+----------
+2003/01/08 21:36:10 crs
+FAQ
+
+Added a FAQ entry for client being rejected. User probably didn't
+start the server or told the client the wrong server host name.
+
+----------
+2003/01/07 21:47:27 crs
+ChangeLog
+configure.in
+lib/common/Version.h
+
+Changed version number to 0.9.15. Added 0.9.15 log entries.
+
+----------
+2003/01/07 21:12:51 crs
+lib/platform/CMSWindowsPrimaryScreen.cpp
+
+Attempts to improve forcing synergy window to foreground. These
+changes don't seem to improve the situation but don't seem to
+hurt either.
+
+----------
+2003/01/07 21:11:54 crs
+lib/platform/CSynergyHook.cpp
+
+Added low-level mouse hook to support mouse wheel on NT (>=SP3).
+Thanks to karsten for the patch used as a starting point.
+
+----------
+2003/01/05 21:52:28 crs
+lib/base/LogOutputters.cpp
+lib/base/LogOutputters.h
+
+Added missing files.
+
+----------
+2003/01/05 21:48:54 crs
+PORTING
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+doc/doxygen.cfg.in
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchConsoleUnix.h
+lib/arch/CArchConsoleWindows.h
+lib/arch/CArchDaemonNone.h
+lib/arch/CArchDaemonUnix.h
+lib/arch/CArchDaemonWindows.h
+lib/arch/CArchFileUnix.h
+lib/arch/CArchFileWindows.h
+lib/arch/CArchLogUnix.h
+lib/arch/CArchLogWindows.h
+lib/arch/CArchMiscWindows.h
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchMultithreadWindows.h
+lib/arch/CArchNetworkBSD.h
+lib/arch/CArchNetworkWinsock.cpp
+lib/arch/CArchNetworkWinsock.h
+lib/arch/CArchSleepUnix.h
+lib/arch/CArchSleepWindows.h
+lib/arch/CArchStringUnix.cpp
+lib/arch/CArchStringUnix.h
+lib/arch/CArchStringWindows.cpp
+lib/arch/CArchStringWindows.h
+lib/arch/CArchTimeUnix.h
+lib/arch/CArchTimeWindows.h
+lib/arch/IArchConsole.h
+lib/arch/IArchFile.h
+lib/arch/IArchLog.h
+lib/arch/IArchMultithread.h
+lib/arch/IArchNetwork.h
+lib/arch/IArchSleep.h
+lib/arch/IArchString.h
+lib/arch/IArchTime.h
+lib/arch/Makefile.am
+lib/arch/XArchImpl.h
+lib/arch/arch.dsp
+lib/base/CLog.cpp
+lib/base/CUnicode.cpp
+lib/base/XBase.cpp
+lib/base/XBase.h
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CMSWindowsSecondaryScreen.h
+lib/client/CSecondaryScreen.cpp
+lib/client/CSecondaryScreen.h
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+lib/client/ISecondaryScreenFactory.h
+lib/client/Makefile.am
+lib/client/client.dsp
+lib/http/XHTTP.h
+lib/platform/CMSWindowsPrimaryScreen.cpp
+lib/platform/CMSWindowsPrimaryScreen.h
+lib/platform/CMSWindowsScreen.h
+lib/platform/CMSWindowsSecondaryScreen.cpp
+lib/platform/CMSWindowsSecondaryScreen.h
+lib/platform/CXWindowsPrimaryScreen.cpp
+lib/platform/CXWindowsPrimaryScreen.h
+lib/platform/CXWindowsScreen.h
+lib/platform/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsSecondaryScreen.h
+lib/platform/Makefile.am
+lib/platform/platform.dsp
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CMSWindowsPrimaryScreen.h
+lib/server/CPrimaryScreen.cpp
+lib/server/CPrimaryScreen.h
+lib/server/CXWindowsPrimaryScreen.cpp
+lib/server/CXWindowsPrimaryScreen.h
+lib/server/IPrimaryScreenFactory.h
+lib/server/Makefile.am
+lib/server/server.dsp
+lib/synergy/CPrimaryScreen.cpp
+lib/synergy/CPrimaryScreen.h
+lib/synergy/CSecondaryScreen.cpp
+lib/synergy/CSecondaryScreen.h
+lib/synergy/IPrimaryScreenFactory.h
+lib/synergy/ISecondaryScreenFactory.h
+lib/synergy/Makefile.am
+lib/synergy/libsynergy.dsp
+
+Moved CPrimaryScreen and CSecondaryScreen to the lib/synergy
+and the platform specific implementations to lib/platform.
+Added an lib/arch method to query the platform's native wide
+character encoding and changed CUnicode to use it. All
+platform dependent code is now in lib/arch, lib/platform,
+and the programs under cmd. Also added more documentation.
+
+----------
+2003/01/04 22:01:32 crs
+PORTING
+cmd/launcher/CAutoStart.cpp
+cmd/launcher/CAutoStart.h
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/synergyc/Makefile.am
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.dsp
+cmd/synergys/Makefile.am
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.dsp
+configure.in
+lib/Makefile.am
+lib/arch/CArch.cpp
+lib/arch/CArch.h
+lib/arch/CArchConsoleUnix.cpp
+lib/arch/CArchConsoleUnix.h
+lib/arch/CArchConsoleWindows.cpp
+lib/arch/CArchConsoleWindows.h
+lib/arch/CArchDaemonNone.cpp
+lib/arch/CArchDaemonNone.h
+lib/arch/CArchDaemonUnix.cpp
+lib/arch/CArchDaemonUnix.h
+lib/arch/CArchDaemonWindows.cpp
+lib/arch/CArchDaemonWindows.h
+lib/arch/CArchFileUnix.cpp
+lib/arch/CArchFileUnix.h
+lib/arch/CArchFileWindows.cpp
+lib/arch/CArchFileWindows.h
+lib/arch/CArchImpl.cpp
+lib/arch/CArchLogUnix.cpp
+lib/arch/CArchLogUnix.h
+lib/arch/CArchLogWindows.cpp
+lib/arch/CArchLogWindows.h
+lib/arch/CArchMiscWindows.cpp
+lib/arch/CArchMiscWindows.h
+lib/arch/CArchMultithreadPosix.cpp
+lib/arch/CArchMultithreadPosix.h
+lib/arch/CArchMultithreadWindows.cpp
+lib/arch/CArchMultithreadWindows.h
+lib/arch/CArchNetworkBSD.cpp
+lib/arch/CArchNetworkBSD.h
+lib/arch/CArchNetworkWinsock.cpp
+lib/arch/CArchNetworkWinsock.h
+lib/arch/CArchSleepUnix.cpp
+lib/arch/CArchSleepUnix.h
+lib/arch/CArchSleepWindows.cpp
+lib/arch/CArchSleepWindows.h
+lib/arch/CArchStringUnix.cpp
+lib/arch/CArchStringUnix.h
+lib/arch/CArchStringWindows.cpp
+lib/arch/CArchStringWindows.h
+lib/arch/CArchTimeUnix.cpp
+lib/arch/CArchTimeUnix.h
+lib/arch/CArchTimeWindows.cpp
+lib/arch/CArchTimeWindows.h
+lib/arch/CMultibyte.cpp
+lib/arch/CMultibyteEmu.cpp
+lib/arch/CMultibyteOS.cpp
+lib/arch/IArchConsole.h
+lib/arch/IArchDaemon.h
+lib/arch/IArchFile.h
+lib/arch/IArchLog.h
+lib/arch/IArchMultithread.h
+lib/arch/IArchNetwork.h
+lib/arch/IArchSleep.h
+lib/arch/IArchString.h
+lib/arch/IArchTime.h
+lib/arch/Makefile.am
+lib/arch/XArch.cpp
+lib/arch/XArch.h
+lib/arch/XArchImpl.h
+lib/arch/XArchUnix.cpp
+lib/arch/XArchUnix.h
+lib/arch/XArchWindows.cpp
+lib/arch/XArchWindows.h
+lib/arch/arch.dsp
+lib/arch/vsnprintf.cpp
+lib/base/BasicTypes.h
+lib/base/CLog.cpp
+lib/base/CLog.h
+lib/base/CStopwatch.cpp
+lib/base/CString.cpp
+lib/base/CString.h
+lib/base/CStringUtil.cpp
+lib/base/CStringUtil.h
+lib/base/CUnicode.cpp
+lib/base/CUnicode.h
+lib/base/IInterface.h
+lib/base/ILogOutputter.h
+lib/base/Makefile.am
+lib/base/Version.h
+lib/base/XBase.cpp
+lib/base/XBase.h
+lib/base/base.dsp
+lib/base/common.h
+lib/base/stdfstream.h
+lib/base/stdistream.h
+lib/base/stdlist.h
+lib/base/stdmap.h
+lib/base/stdostream.h
+lib/base/stdpost.h
+lib/base/stdpre.h
+lib/base/stdset.h
+lib/base/stdsstream.h
+lib/base/stdvector.h
+lib/client/CClient.cpp
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/Makefile.am
+lib/client/client.dsp
+lib/common/BasicTypes.h
+lib/common/IInterface.h
+lib/common/Makefile.am
+lib/common/Version.h
+lib/common/common.dsp
+lib/common/common.h
+lib/common/stdfstream.h
+lib/common/stdistream.h
+lib/common/stdlist.h
+lib/common/stdmap.h
+lib/common/stdostream.h
+lib/common/stdpost.h
+lib/common/stdpre.h
+lib/common/stdset.h
+lib/common/stdsstream.h
+lib/common/stdstring.h
+lib/common/stdvector.h
+lib/http/CHTTPProtocol.h
+lib/http/Makefile.am
+lib/http/XHTTP.cpp
+lib/http/http.dsp
+lib/io/CUnicode.cpp
+lib/io/CUnicode.h
+lib/io/Makefile.am
+lib/io/XIO.cpp
+lib/io/XIO.h
+lib/io/io.dsp
+lib/mt/CCondVar.cpp
+lib/mt/CCondVar.h
+lib/mt/CMutex.cpp
+lib/mt/CMutex.h
+lib/mt/CThread.cpp
+lib/mt/CThread.h
+lib/mt/CThreadRep.cpp
+lib/mt/CThreadRep.h
+lib/mt/CTimerThread.cpp
+lib/mt/Makefile.am
+lib/mt/XMT.cpp
+lib/mt/XMT.h
+lib/mt/XThread.h
+lib/mt/mt.dsp
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/net/CNetworkAddress.cpp
+lib/net/CNetworkAddress.h
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPListenSocket.h
+lib/net/CTCPSocket.cpp
+lib/net/CTCPSocket.h
+lib/net/Makefile.am
+lib/net/XNetwork.cpp
+lib/net/XNetwork.h
+lib/net/XSocket.cpp
+lib/net/XSocket.h
+lib/net/net.dsp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CPlatform.cpp
+lib/platform/CPlatform.h
+lib/platform/CUnixPlatform.cpp
+lib/platform/CUnixPlatform.h
+lib/platform/CWin32Platform.cpp
+lib/platform/CWin32Platform.h
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/IPlatform.h
+lib/platform/Makefile.am
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/CConfig.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CServer.cpp
+lib/server/CXWindowsPrimaryScreen.cpp
+lib/server/Makefile.am
+lib/server/server.dsp
+lib/synergy/Makefile.am
+lib/synergy/XScreen.cpp
+lib/synergy/XScreen.h
+lib/synergy/XSynergy.cpp
+lib/synergy/XSynergy.h
+lib/synergy/libsynergy.dsp
+synergy.dsw
+
+Refactored some platform dependent code into a new library,
+lib/arch. This should make porting easier. Will probably
+continue to refactor a little more, moving platform dependent
+event handling stuff into lib/platform.
+
+----------
+2002/12/26 18:40:22 crs
+FAQ
+
+More FAQs.
+
+----------
+2002/12/25 23:49:42 crs
+BUGS
+FAQ
+INSTALL
+README
+TODO
+
+Documentation update.
+
+----------
+2002/12/25 22:56:09 crs
+lib/server/CMSWindowsPrimaryScreen.cpp
+
+Made synrgyhk.dll error messages less cryptic.
+
+----------
+2002/12/25 19:21:17 crs
+NEWS
+configure.in
+lib/base/Version.h
+
+Changed version number to 0.9.14. Added NEWS item.
+
+----------
+2002/12/25 18:44:54 crs
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreenSaver.cpp
+
+Improved handling of screen saver handling when windows 2k is
+the client and the screen saver is password protected. It used
+to immediately turn off the screen saver (unintentionally) in
+that case.
+
+----------
+2002/12/25 10:35:59 crs
+acinclude.m4
+config/config.guess
+config/config.sub
+configure.in
+lib/base/common.h
+lib/mt/CThreadRep.cpp
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/platform/CUnixPlatform.cpp
+
+Changes to support building on solaris, irix, and darwin. Also
+removed test for working fork (AC_FORK).
+
+----------
+2002/12/23 14:47:44 crs
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+
+Added code to process set/reset options messages from server.
+
+----------
+2002/12/23 13:55:21 crs
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CMSWindowsSecondaryScreen.h
+lib/client/CSecondaryScreen.cpp
+lib/client/CSecondaryScreen.h
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CMSWindowsPrimaryScreen.h
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CPrimaryScreen.cpp
+lib/server/CPrimaryScreen.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/CXWindowsPrimaryScreen.cpp
+lib/server/CXWindowsPrimaryScreen.h
+lib/synergy/CProtocolUtil.cpp
+lib/synergy/CProtocolUtil.h
+lib/synergy/IClient.h
+lib/synergy/Makefile.am
+lib/synergy/OptionTypes.h
+lib/synergy/ProtocolTypes.h
+
+Added support for per-screen options in the configuration file
+and sending those options to the appropriate client screens.
+Currently, two options are supported: halfDuplexCapsLock and
+halfDuplexNumLock mark the caps lock and num lock keys,
+respectively, as being half-duplex.
+
+----------
+2002/12/22 14:51:41 crs
+configure.in
+doc/doxygen.cfg.in
+
+Doxygen config file now sets HAVE_DOT to YES only if dot is found
+by configure.
+
+----------
+2002/12/15 22:39:59 crs
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+
+Now handling any number of pointer buttons.
+
+----------
+2002/12/15 22:17:18 crs
+lib/server/CXWindowsPrimaryScreen.cpp
+
+Now ignoring half-duplex keys that are down when deciding if
+the mouse is locked to the screen. We can't tell if a half-
+duplex key is physically down and logically down just means
+it's active so there's no point in letting it lock the mouse
+to the screen.
+
+----------
+2002/12/15 22:14:49 crs
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CMSWindowsSecondaryScreen.h
+lib/client/CSecondaryScreen.cpp
+lib/client/CSecondaryScreen.h
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+
+Now restoring toggle key states on leaving a client screen to
+their state when the screen was entered. Previously when
+leaving a client screen the toggle keys kept their state so,
+say, caps lock, would remain on. This was inconvenient if
+you then used the client's keyboard directly.
+
+----------
+2002/12/15 20:00:52 crs
+lib/server/CMSWindowsPrimaryScreen.cpp
+
+Fixed loss of ctrl+alt when transmitted to non-windows platforms
+from a windows server. Was converting ctrl+alt on windows to
+mode switch on the server. No longer doing that; windows clients
+will interpret ctrl+alt as AltGr and other clients will just see
+ctrl+alt. Also made the right alt key mode switch on windows
+servers in case the user wants to force a mode switch, but that
+means the right alt key no longer acts as alt on clients.
+
+----------
+2002/12/15 19:58:41 crs
+lib/platform/CMSWindowsScreen.cpp
+
+Fixed client not reconnecting when server dies bug.
+
+----------
+2002/12/15 19:57:28 crs
+lib/client/CXWindowsSecondaryScreen.cpp
+
+Cleanup and changed some DEBUG1 messages to DEBUG2.
+
+----------
+2002/12/15 11:12:39 crs
+doc/doxygen.cfg.in
+
+Enabled using dot and class diagrams.
+
+----------
+2002/11/05 19:23:05 crs
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+
+Fixed bug in detecting screen saver activation. Was using || instead
+of && in conditional.
+
+----------
+2002/11/03 18:09:28 crs
+acinclude.m4
+configure.in
+lib/io/CUnicode.h
+lib/net/CNetwork.h
+lib/platform/CUnixPlatform.cpp
+
+Merged fixes for building on MacOS X. It dies on one file with
+an internal compiler error; building that file without
+optimization works around the compiler bug. Sadly, synergy can
+only interact with X windows, not native MacOS windows.
+
+----------
+2002/10/30 22:22:16 crs
+acinclude.m4
+
+Escaped quotes to satisfy older autoheader versions.
+
+----------
+2002/10/30 22:16:30 crs
+lib/net/CNetwork.h
+lib/net/CTCPSocket.cpp
+
+Fixed bugs in error handling in CTCPSocket; previously was not
+handling read errors at all and error handling for writes was
+never being used. Now the socket disconnects if a read or write
+fails on the socket for any reason except EINTR. Also added
+ to includes in CNetwork.h because it's needed on
+some platforms.
+
+----------
+2002/10/29 22:07:55 crs
+all.dsp
+lib/base/base.dsp
+lib/client/client.dsp
+lib/http/http.dsp
+lib/io/CUnicode.cpp
+lib/io/io.dsp
+lib/mt/mt.dsp
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/net/net.dsp
+lib/platform/makehook.dsp
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+
+Ported recent changes to win32 and fixed CRLF problems with project
+files (most had CRCRCRLF).
+
+----------
+2002/10/28 22:49:21 crs
+acinclude.m4
+configure.in
+lib/mt/CThreadRep.cpp
+
+solaris configure and build fixes. without having solaris i
+can only hope that these changes actually work.
+
+----------
+2002/10/22 22:35:13 crs
+configure.in
+lib/io/CUnicode.cpp
+
+Added workarounds for missing reentrant versions of wide char
+to/from multi-byte conversion functions.
+
+----------
+2002/10/22 21:30:48 crs
+lib/base/CUnicode.cpp
+lib/base/CUnicode.h
+lib/base/Makefile.am
+lib/io/CUnicode.cpp
+lib/io/CUnicode.h
+lib/io/Makefile.am
+lib/platform/Makefile.am
+
+Moved CUnicode to lib/io. That's a reasonable place for it
+that's after lib/mt. It needs to be after lib/mt in preparation
+for supporting platforms without the reentrant wide char and
+multi-byte functions.
+
+----------
+2002/10/20 22:39:54 crs
+lib/client/CMSWindowsSecondaryScreen.cpp
+
+Fixed conditional to test for multimon to do nasty win32 mouse
+positioning hack. Was doing hack if *not* a multiple monitor
+system but should've been doing it if is *is* a multimon system.
+
+----------
+2002/10/20 22:36:24 crs
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/net/CNetworkAddress.cpp
+
+Replaced inet_addr() with inet_aton(), which is a better function
+anyway but isn't implemented in winsock, removed use of INADDR_NONE
+which some platforms don't define except on winsock which does
+define it, and changed SOL_TCP to IPPROTO_TCP which should work on
+more platforms.
+
+----------
+2002/10/17 21:37:41 crs
+lib/platform/CXWindowsScreen.cpp
+
+Fixed CXWindowsScreen to force the event loop to wake up when
+exitMainLoop() is called.
+
+----------
+2002/10/17 21:37:37 crs
+lib/mt/CThreadRep.cpp
+
+Fixed CThreadRep to not raise a signal on the thread if it's
+already dead. Otherwise the signal could propagate to the
+parent thread (at least on linux threads) and cause havoc.
+
+----------
+2002/10/17 21:37:31 crs
+lib/server/CServer.cpp
+lib/server/CServer.h
+
+Changed server to fail with an error if in can't bind() the listen
+socket for any reason other than it's in use.
+
+----------
+2002/10/17 20:56:28 crs
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/net/CNetworkAddress.cpp
+
+Changed non-reentrant network functions to be reentrant and
+thread safe.
+
+----------
+2002/10/16 22:01:50 crs
+acinclude.m4
+configure.in
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/net/CTCPSocket.cpp
+lib/platform/CXWindowsScreen.cpp
+
+Added support for using select() instead of poll().
+
+----------
+2002/10/15 22:17:41 crs
+lib/server/CConfig.cpp
+
+CConfig now accepts and discards \r at the end of a line. This
+allows the unix server to read configuration files created on
+microsoft windows platforms.
+
+----------
+2002/10/15 22:08:10 crs
+cmd/synergys/synergys.cpp
+lib/server/CConfig.cpp
+
+Fixed use of %s instead of %{1} in format() call.
+
+----------
+2002/10/15 22:01:41 crs
+lib/client/CClient.cpp
+lib/mt/CThreadRep.cpp
+lib/mt/Makefile.am
+lib/mt/XMT.cpp
+lib/mt/XMT.h
+lib/mt/XThread.h
+lib/server/CServer.cpp
+
+Renamed XThreadUnavailable to XMTThreadUnavailable and derived it
+from XBase so it can be caught normally. Changed client and server
+to handle unavailable threads (in main loop, anyway).
+
+----------
+2002/10/15 21:35:12 crs
+lib/mt/CThreadRep.cpp
+
+Workaround for pthread bug on RedHat 7.2 on multiprocessor
+systems.
+
+----------
+2002/10/15 21:29:44 crs
+cmd/synergyc/synergyc.cpp
+cmd/synergys/synergys.cpp
+lib/base/CLog.h
+lib/client/CClient.cpp
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CSecondaryScreen.cpp
+lib/client/CServerProxy.cpp
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/http/CHTTPProtocol.cpp
+lib/mt/CMutex.cpp
+lib/mt/CThread.cpp
+lib/mt/CThreadRep.cpp
+lib/mt/CTimerThread.cpp
+lib/net/CNetwork.cpp
+lib/platform/CMSWindowsClipboard.cpp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CWin32Platform.cpp
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsUtil.cpp
+lib/server/CClientProxy1_0.cpp
+lib/server/CHTTPServer.cpp
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryScreen.cpp
+lib/server/CServer.cpp
+lib/server/CXWindowsPrimaryScreen.cpp
+lib/synergy/CProtocolUtil.cpp
+
+Changed log() and logc() macros to LOG() and LOGC(), respectively.
+This avoids a conflict with the standard math library log()
+function.
+
+----------
+2002/09/14 21:31:35 crs
+lib/base/XBase.cpp
+lib/base/XBase.h
+
+removed std::exception from base class list of XBase. this
+is a workaround for gcc 3.2 until everything necessary has
+throw() specifiers.
+
+----------
+2002/09/14 20:56:50 crs
+lib/server/CServer.cpp
+
+now logging bind failures as warnings.
+
+----------
+2002/09/14 20:56:28 crs
+lib/base/XBase.cpp
+lib/base/XBase.h
+lib/io/XIO.cpp
+lib/io/XIO.h
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPSocket.cpp
+lib/net/XSocket.cpp
+lib/net/XSocket.h
+
+added better network error message support.
+
+----------
+2002/09/14 12:07:02 crs
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CXWindowsPrimaryScreen.cpp
+lib/server/CXWindowsPrimaryScreen.h
+lib/synergy/KeyTypes.h
+
+Rewrote handling of key press on X11 client; it should be much
+more robust now. Also added handling of Super modifier key and
+changed windows keys to map to Super instead of Meta, which is
+the default on my keyboard.
+
+----------
+2002/09/14 12:05:06 crs
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+
+Added debug level combo box and version number to title bar of win32
+launcher.
+
+----------
+2002/09/14 12:03:43 crs
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.rc
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.rc
+
+Fixed backend mode. Now reports log messages and, if any are
+serious, shows a message box before exiting.
+
+----------
+2002/09/04 21:17:01 crs
+NEWS
+configure.in
+lib/base/Version.h
+
+Changed version number to 0.9.11. Added NEWS item.
+
+----------
+2002/09/04 21:14:18 crs
+lib/client/CMSWindowsSecondaryScreen.cpp
+
+now looking up SendEvent() using GetProcAddress() so win95
+systems can run the synergy client.
+
+----------
+2002/09/04 20:17:54 crs
+lib/client/CXWindowsSecondaryScreen.cpp
+
+fixed bug that caused the wrong keycode to be used for most,
+possibly all, keysyms. was reading past the end of an array
+of keysyms.
+
+----------
+2002/09/02 17:36:25 crs
+configure.in
+lib/base/Version.h
+
+Changed version number to 0.9.10.
+
+----------
+2002/09/02 17:30:04 crs
+BUGS
+INSTALL
+cmd/launcher/CAutoStart.cpp
+cmd/launcher/CAutoStart.h
+cmd/launcher/LaunchUtil.cpp
+cmd/launcher/LaunchUtil.h
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.rc
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+lib/client/CClient.cpp
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/platform/CUnixPlatform.cpp
+lib/platform/CUnixPlatform.h
+lib/platform/CWin32Platform.cpp
+lib/platform/CWin32Platform.h
+lib/platform/IPlatform.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+
+Fixed win32 config saving, keyboard mapping, and AltGr bugs.
+Made extensive changes to the launcher to provide more control
+over setting up auto-start and it now saves configuration to
+the user's documents directory if auto-starting at login and
+saves to the system directory if auto-starting at boot.
+Replaced MapVirtualKey() with table lookup to work around that
+function's lack of support for extended keyboard scan codes.
+Added first cut at support for AltGr.
+
+----------
+2002/09/01 15:30:00 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/KeyTypes.h
+
+Added support for mode switch key to X11 screens.
+
+----------
+2002/09/01 10:31:10 crs
+acinclude.m4
+configure.in
+lib/base/stdsstream.h
+
+added more tests to autoconf. also now handling missing sstream
+header in gcc 2.95 by including sstream header backported from v3.
+
+----------
+2002/09/01 09:28:54 crs
+lib/platform/CXWindowsUtil.cpp
+
+lowered severity of some debug messages.
+
+----------
+2002/08/18 17:45:59 crs
+configure.in
+lib/base/Version.h
+
+Changed version number to 0.9.9.
+
+----------
+2002/08/18 17:40:10 crs
+lib/server/CMSWindowsPrimaryScreen.cpp
+
+fixed win32 deadlock. when a client disconnects the server will
+warp the mouse to the primary screen. entering the primary
+screen causes the primary screen's window to be hidden. the
+deadlock occurs because hiding the window seems to post a
+message then wait for it to be handled (or possibly it won't
+send a message while a posted message is being handled).
+thread A locks the mutex, warps the mouse, the hides the window.
+thread B begins processing the mouse warp then tries to lock
+the mutex. thread A is waiting on the event loop owned by B
+while B is waiting on the mutex owned by A. this fix simply
+hides the window asynchronously. however, there may be other
+ways to cause a similar deadlock that have not been found.
+
+----------
+2002/08/18 17:35:10 crs
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CMSWindowsSecondaryScreen.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+
+fixed PrintScrn handling; it was being changed to keypad multiply.
+
+----------
+2002/08/18 17:31:48 crs
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+
+no longer sending fake events for unmapped logical buttons.
+
+----------
+2002/08/11 22:43:07 crs
+BUGS
+INSTALL
+NEWS
+PORTING
+README
+cmd/Makefile.am
+cmd/launcher/launcher.cpp
+cmd/synergy/Makefile.am
+cmd/synergy/resource.h
+cmd/synergy/synergy.cpp
+cmd/synergy/synergy.dsp
+cmd/synergy/synergy.ico
+cmd/synergy/synergy.rc
+cmd/synergyc/Makefile.am
+cmd/synergyc/resource.h
+cmd/synergyc/synergyc.cpp
+cmd/synergyc/synergyc.dsp
+cmd/synergyc/synergyc.ico
+cmd/synergyc/synergyc.rc
+cmd/synergyd/Makefile.am
+cmd/synergyd/resource.h
+cmd/synergyd/synergy.ico
+cmd/synergyd/synergyd.cpp
+cmd/synergyd/synergyd.dsp
+cmd/synergyd/synergyd.rc
+cmd/synergys/Makefile.am
+cmd/synergys/resource.h
+cmd/synergys/synergys.cpp
+cmd/synergys/synergys.dsp
+cmd/synergys/synergys.ico
+cmd/synergys/synergys.rc
+configure.in
+dist/rpm/synergy.spec.in
+synergy.dsw
+
+Moved synergy client to cmd/synergyc and renamed it synergyc.
+Moved synergy server to cmd/synergys and renamed it synergys.
+Updated documentation to reflect that and the win32 launcher.
+
+----------
+2002/08/11 11:50:49 crs
+Makefile.am
+TODO
+
+added TODO file and top-level rule to make zip file of distribution
+files.
+
+----------
+2002/08/03 11:50:07 crs
+lib/mt/CCondVar.h
+
+removed pre-instantiation of templates in header file.
+
+----------
+2002/08/03 11:49:36 crs
+all.dsp
+cmd/Makefile.am
+cmd/launcher/Makefile.am
+cmd/launcher/launcher.cpp
+cmd/launcher/launcher.dsp
+cmd/launcher/launcher.rc
+cmd/launcher/resource.h
+cmd/launcher/synergy.ico
+cmd/synergy/Makefile.am
+cmd/synergy/resource.h
+cmd/synergy/synergy.cpp
+cmd/synergy/synergy.dsp
+cmd/synergy/synergy.ico
+cmd/synergy/synergy.rc
+cmd/synergyd/Makefile.am
+cmd/synergyd/resource.h
+cmd/synergyd/synergy.ico
+cmd/synergyd/synergyd.cpp
+cmd/synergyd/synergyd.dsp
+cmd/synergyd/synergyd.rc
+configure.in
+lib/base/CString.cpp
+lib/base/Version.h
+lib/base/base.dsp
+lib/client/client.dsp
+lib/http/http.dsp
+lib/io/io.dsp
+lib/mt/mt.dsp
+lib/net/net.dsp
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/makehook.dsp
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+synergy.dsw
+
+added win32 launcher program. also changed VC++ dsp and dsw
+files to binary form so \r\n aren't converted. added icons
+to client and server apps on win32.
+
+----------
+2002/08/02 17:57:54 crs
+Makefile.am
+configure.in
+dist/Makefile.am
+dist/rpm/Makefile.am
+dist/rpm/synergy.spec.in
+
+added build rule to create RPMs.
+
+----------
+2002/08/02 17:53:23 crs
+AUTHORS
+BUGS
+FAQ
+HISTORY
+INSTALL
+NEWS
+PORTING
+README
+
+minor documentation updates. added HISTORY and PORTING.
+
+----------
+2002/08/01 18:07:32 crs
+AUTHORS
+BUGS
+COPYING
+ChangeLog
+FAQ
+INSTALL
+NEWS
+README
+
+added files for release.
+
+----------
+2002/08/01 11:45:21 crs
+configure.in
+lib/base/CStopwatch.cpp
+lib/mt/CCondVar.cpp
+lib/platform/CUnixPlatform.cpp
+
+minor automake fixes.
+
+----------
+2002/07/31 17:40:36 crs
+Makefile.am
+
+added simple rule to build doxygen.
+
+----------
+2002/07/31 17:40:21 crs
+lib/synergy/XSynergy.h
+
+fixed comment.
+
+----------
+2002/07/31 17:35:43 crs
+Makefile.am
+
+removed two programs from files to clean.
+
+----------
+2002/07/31 17:34:05 crs
+Makefile.am
+cmd/Makefile.am
+cmd/synergy/Makefile.am
+cmd/synergyd/Makefile.am
+lib/Makefile.am
+lib/base/Makefile.am
+lib/client/Makefile.am
+lib/http/Makefile.am
+lib/io/Makefile.am
+lib/mt/Makefile.am
+lib/net/Makefile.am
+lib/platform/Makefile.am
+lib/server/Makefile.am
+lib/synergy/Makefile.am
+
+fixes to get vpath builds working (necessary for `make distcheck').
+
+----------
+2002/07/31 16:57:26 crs
+Makefile.am
+cmd/Makefile.am
+cmd/synergy/Makefile.am
+cmd/synergy/synergy.cpp
+cmd/synergyd/Makefile.am
+cmd/synergyd/synergyd.cpp
+configure.in
+lib/Makefile.am
+lib/base/Makefile.am
+lib/base/Version.h
+lib/client/Makefile.am
+lib/http/Makefile.am
+lib/io/Makefile.am
+lib/mt/Makefile.am
+lib/net/Makefile.am
+lib/platform/Makefile.am
+lib/server/Makefile.am
+lib/synergy/Makefile.am
+lib/synergy/ProtocolTypes.h
+lib/synergy/Version.h
+
+Moved version header to base and it now uses VERSION macro
+from config.h if available (which means version is now a
+string, not three integers). Changed version to 1.0.0 and
+protocol version to 1.0. And added MAINTAINERCLEANFILES
+to makefiles to remove generated files.
+
+----------
+2002/07/31 16:27:06 crs
+Makefile.am
+cmd/synergy/Makefile.am
+cmd/synergyd/Makefile.am
+examples/synergy.linux.init
+examples/synergyd.linux.init
+lib/base/Makefile.am
+lib/client/Makefile.am
+lib/http/Makefile.am
+lib/io/Makefile.am
+lib/mt/Makefile.am
+lib/net/Makefile.am
+lib/platform/Makefile.am
+lib/server/Makefile.am
+lib/synergy/Makefile.am
+nodist/notes
+notes
+
+added EXTRA_* files to get `make dist' doing the right thing.
+
+----------
+2002/07/31 16:24:45 crs
+notes
+
+checkpoint notes.
+
+----------
+2002/07/31 13:56:59 crs
+lib/base/CLog.cpp
+
+removed now unnecssary #define.
+
+----------
+2002/07/31 13:41:58 crs
+lib/http/http.dsp
+lib/platform/CMSWindowsClipboardAnyTextConverter.cpp
+lib/platform/CMSWindowsClipboardAnyTextConverter.h
+lib/platform/CMSWindowsClipboardTextConverter.cpp
+lib/platform/CMSWindowsClipboardTextConverter.h
+lib/platform/CMSWindowsClipboardUTF16Converter.cpp
+lib/platform/CMSWindowsClipboardUTF16Converter.h
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CMSWindowsScreenSaver.h
+lib/platform/IMSWindowsScreenEventHandler.h
+
+okay, now the files should no longer be executable.
+
+----------
+2002/07/31 13:34:18 crs
+lib/http/http.dsp
+lib/platform/CMSWindowsClipboardAnyTextConverter.cpp
+lib/platform/CMSWindowsClipboardAnyTextConverter.h
+lib/platform/CMSWindowsClipboardTextConverter.cpp
+lib/platform/CMSWindowsClipboardTextConverter.h
+lib/platform/CMSWindowsClipboardUTF16Converter.cpp
+lib/platform/CMSWindowsClipboardUTF16Converter.h
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CMSWindowsScreenSaver.h
+lib/platform/IMSWindowsScreenEventHandler.h
+notes
+
+removed unintentional executable flag.
+
+----------
+2002/07/31 13:29:33 crs
+notes
+
+checkpoint notes.
+
+----------
+2002/07/31 13:18:27 crs
+README
+
+added comment about large motif clipboard items to README.
+
+----------
+2002/07/31 13:10:15 crs
+README
+
+updated README.
+
+----------
+2002/07/31 12:40:41 crs
+lib/platform/CSynergyHook.cpp
+lib/platform/synrgyhk.dsp
+
+now building hook dll for release without linking in standard
+C runtime. need C runtime for debug build for asserts.
+
+----------
+2002/07/31 12:39:34 crs
+cmd/synergy/synergy.cpp
+cmd/synergyd/synergyd.cpp
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/platform/CXWindowsScreen.cpp
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/synergy/IClient.h
+lib/synergy/IScreen.h
+lib/synergy/XScreen.cpp
+lib/synergy/XScreen.h
+
+fixed problem with opening client and server. in some cases it
+would fail to open in such a way that it could never succeed
+but it'd never stop retrying. now terminating when open fails
+such that it'll never succeed.
+
+----------
+2002/07/30 19:03:40 crs
+lib/client/client.dsp
+lib/io/io.dsp
+lib/net/net.dsp
+lib/server/server.dsp
+lib/synergy/libsynergy.dsp
+
+added new files to projects and added two project files that
+should've been adding in change 530.
+
+----------
+2002/07/30 18:49:31 crs
+lib/client/CServerProxy.cpp
+lib/server/CClientProxy1_0.cpp
+lib/synergy/ProtocolTypes.h
+
+made it so a negative kHeartRate disables heartbeats and set
+kHeartRate to -1.
+
+----------
+2002/07/30 18:31:21 crs
+lib/mt/CThreadRep.cpp
+lib/mt/XThread.h
+
+moved exception definition to header file.
+
+----------
+2002/07/30 18:31:00 crs
+cmd/synergy/synergy.cpp
+cmd/synergyd/synergyd.cpp
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/ISecondaryScreenFactory.h
+lib/client/Makefile.am
+lib/io/IStreamFilterFactory.h
+lib/io/Makefile.am
+lib/net/CTCPSocketFactory.cpp
+lib/net/CTCPSocketFactory.h
+lib/net/ISocketFactory.h
+lib/net/Makefile.am
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/IPrimaryScreenFactory.h
+lib/server/Makefile.am
+lib/synergy/CTCPSocketFactory.cpp
+lib/synergy/CTCPSocketFactory.h
+lib/synergy/ISocketFactory.h
+lib/synergy/Makefile.am
+lib/synergy/ProtocolTypes.h
+
+now using class factories to move some decisions from the libraries
+into the application.
+
+----------
+2002/07/30 16:52:46 crs
+Makefile.am
+base/BasicTypes.h
+base/CFunctionJob.cpp
+base/CFunctionJob.h
+base/CLog.cpp
+base/CLog.h
+base/CStopwatch.cpp
+base/CStopwatch.h
+base/CString.cpp
+base/CString.h
+base/CUnicode.cpp
+base/CUnicode.h
+base/IInterface.h
+base/IJob.h
+base/Makefile.am
+base/TMethodJob.h
+base/XBase.cpp
+base/XBase.h
+base/base.dsp
+base/common.h
+base/stdfstream.h
+base/stdistream.h
+base/stdlist.h
+base/stdmap.h
+base/stdostream.h
+base/stdpost.h
+base/stdpre.h
+base/stdset.h
+base/stdsstream.h
+base/stdvector.h
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CSecondaryScreen.cpp
+client/CSecondaryScreen.h
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/Makefile.am
+client/client.cpp
+client/client.dsp
+client/client.rc
+client/resource.h
+cmd/Makefile.am
+cmd/synergy/Makefile.am
+cmd/synergy/resource.h
+cmd/synergy/synergy.cpp
+cmd/synergy/synergy.dsp
+cmd/synergy/synergy.rc
+cmd/synergyd/Makefile.am
+cmd/synergyd/resource.h
+cmd/synergyd/synergyd.cpp
+cmd/synergyd/synergyd.dsp
+cmd/synergyd/synergyd.rc
+configure.in
+http/CHTTPProtocol.cpp
+http/CHTTPProtocol.h
+http/Makefile.am
+http/XHTTP.cpp
+http/XHTTP.h
+http/http.dsp
+io/CBufferedInputStream.cpp
+io/CBufferedInputStream.h
+io/CBufferedOutputStream.cpp
+io/CBufferedOutputStream.h
+io/CInputStreamFilter.cpp
+io/CInputStreamFilter.h
+io/COutputStreamFilter.cpp
+io/COutputStreamFilter.h
+io/CStreamBuffer.cpp
+io/CStreamBuffer.h
+io/IInputStream.h
+io/IOutputStream.h
+io/Makefile.am
+io/XIO.cpp
+io/XIO.h
+io/io.dsp
+lib/Makefile.am
+lib/base/BasicTypes.h
+lib/base/CFunctionJob.cpp
+lib/base/CFunctionJob.h
+lib/base/CLog.cpp
+lib/base/CLog.h
+lib/base/CStopwatch.cpp
+lib/base/CStopwatch.h
+lib/base/CString.cpp
+lib/base/CString.h
+lib/base/CUnicode.cpp
+lib/base/CUnicode.h
+lib/base/IInterface.h
+lib/base/IJob.h
+lib/base/Makefile.am
+lib/base/TMethodJob.h
+lib/base/XBase.cpp
+lib/base/XBase.h
+lib/base/base.dsp
+lib/base/common.h
+lib/base/stdfstream.h
+lib/base/stdistream.h
+lib/base/stdlist.h
+lib/base/stdmap.h
+lib/base/stdostream.h
+lib/base/stdpost.h
+lib/base/stdpre.h
+lib/base/stdset.h
+lib/base/stdsstream.h
+lib/base/stdvector.h
+lib/client/CClient.cpp
+lib/client/CClient.h
+lib/client/CMSWindowsSecondaryScreen.cpp
+lib/client/CMSWindowsSecondaryScreen.h
+lib/client/CSecondaryScreen.cpp
+lib/client/CSecondaryScreen.h
+lib/client/CServerProxy.cpp
+lib/client/CServerProxy.h
+lib/client/CXWindowsSecondaryScreen.cpp
+lib/client/CXWindowsSecondaryScreen.h
+lib/client/Makefile.am
+lib/http/CHTTPProtocol.cpp
+lib/http/CHTTPProtocol.h
+lib/http/Makefile.am
+lib/http/XHTTP.cpp
+lib/http/XHTTP.h
+lib/http/http.dsp
+lib/io/CBufferedInputStream.cpp
+lib/io/CBufferedInputStream.h
+lib/io/CBufferedOutputStream.cpp
+lib/io/CBufferedOutputStream.h
+lib/io/CInputStreamFilter.cpp
+lib/io/CInputStreamFilter.h
+lib/io/COutputStreamFilter.cpp
+lib/io/COutputStreamFilter.h
+lib/io/CStreamBuffer.cpp
+lib/io/CStreamBuffer.h
+lib/io/IInputStream.h
+lib/io/IOutputStream.h
+lib/io/Makefile.am
+lib/io/XIO.cpp
+lib/io/XIO.h
+lib/io/io.dsp
+lib/mt/CCondVar.cpp
+lib/mt/CCondVar.h
+lib/mt/CLock.cpp
+lib/mt/CLock.h
+lib/mt/CMutex.cpp
+lib/mt/CMutex.h
+lib/mt/CThread.cpp
+lib/mt/CThread.h
+lib/mt/CThreadRep.cpp
+lib/mt/CThreadRep.h
+lib/mt/CTimerThread.cpp
+lib/mt/CTimerThread.h
+lib/mt/Makefile.am
+lib/mt/XThread.h
+lib/mt/mt.dsp
+lib/net/CNetwork.cpp
+lib/net/CNetwork.h
+lib/net/CNetworkAddress.cpp
+lib/net/CNetworkAddress.h
+lib/net/CTCPListenSocket.cpp
+lib/net/CTCPListenSocket.h
+lib/net/CTCPSocket.cpp
+lib/net/CTCPSocket.h
+lib/net/IDataSocket.h
+lib/net/IListenSocket.h
+lib/net/ISocket.h
+lib/net/Makefile.am
+lib/net/XNetwork.cpp
+lib/net/XNetwork.h
+lib/net/XSocket.cpp
+lib/net/XSocket.h
+lib/net/net.dsp
+lib/platform/CMSWindowsClipboard.cpp
+lib/platform/CMSWindowsClipboard.h
+lib/platform/CMSWindowsClipboardAnyTextConverter.cpp
+lib/platform/CMSWindowsClipboardAnyTextConverter.h
+lib/platform/CMSWindowsClipboardTextConverter.cpp
+lib/platform/CMSWindowsClipboardTextConverter.h
+lib/platform/CMSWindowsClipboardUTF16Converter.cpp
+lib/platform/CMSWindowsClipboardUTF16Converter.h
+lib/platform/CMSWindowsScreen.cpp
+lib/platform/CMSWindowsScreen.h
+lib/platform/CMSWindowsScreenSaver.cpp
+lib/platform/CMSWindowsScreenSaver.h
+lib/platform/CPlatform.cpp
+lib/platform/CPlatform.h
+lib/platform/CSynergyHook.cpp
+lib/platform/CSynergyHook.h
+lib/platform/CUnixPlatform.cpp
+lib/platform/CUnixPlatform.h
+lib/platform/CWin32Platform.cpp
+lib/platform/CWin32Platform.h
+lib/platform/CXWindowsClipboard.cpp
+lib/platform/CXWindowsClipboard.h
+lib/platform/CXWindowsClipboardTextConverter.cpp
+lib/platform/CXWindowsClipboardTextConverter.h
+lib/platform/CXWindowsClipboardUCS2Converter.cpp
+lib/platform/CXWindowsClipboardUCS2Converter.h
+lib/platform/CXWindowsClipboardUTF8Converter.cpp
+lib/platform/CXWindowsClipboardUTF8Converter.h
+lib/platform/CXWindowsScreen.cpp
+lib/platform/CXWindowsScreen.h
+lib/platform/CXWindowsScreenSaver.cpp
+lib/platform/CXWindowsScreenSaver.h
+lib/platform/CXWindowsUtil.cpp
+lib/platform/CXWindowsUtil.h
+lib/platform/IMSWindowsScreenEventHandler.h
+lib/platform/IPlatform.h
+lib/platform/Makefile.am
+lib/platform/makehook.dsp
+lib/platform/platform.dsp
+lib/platform/synrgyhk.dsp
+lib/server/CClientProxy.cpp
+lib/server/CClientProxy.h
+lib/server/CClientProxy1_0.cpp
+lib/server/CClientProxy1_0.h
+lib/server/CConfig.cpp
+lib/server/CConfig.h
+lib/server/CHTTPServer.cpp
+lib/server/CHTTPServer.h
+lib/server/CMSWindowsPrimaryScreen.cpp
+lib/server/CMSWindowsPrimaryScreen.h
+lib/server/CPrimaryClient.cpp
+lib/server/CPrimaryClient.h
+lib/server/CPrimaryScreen.cpp
+lib/server/CPrimaryScreen.h
+lib/server/CServer.cpp
+lib/server/CServer.h
+lib/server/CXWindowsPrimaryScreen.cpp
+lib/server/CXWindowsPrimaryScreen.h
+lib/server/Makefile.am
+lib/synergy/CClipboard.cpp
+lib/synergy/CClipboard.h
+lib/synergy/CInputPacketStream.cpp
+lib/synergy/CInputPacketStream.h
+lib/synergy/COutputPacketStream.cpp
+lib/synergy/COutputPacketStream.h
+lib/synergy/CProtocolUtil.cpp
+lib/synergy/CProtocolUtil.h
+lib/synergy/CTCPSocketFactory.cpp
+lib/synergy/CTCPSocketFactory.h
+lib/synergy/ClipboardTypes.h
+lib/synergy/IClient.h
+lib/synergy/IClipboard.h
+lib/synergy/IPrimaryScreenReceiver.h
+lib/synergy/IScreen.h
+lib/synergy/IScreenEventHandler.h
+lib/synergy/IScreenReceiver.h
+lib/synergy/IScreenSaver.h
+lib/synergy/IServer.h
+lib/synergy/ISocketFactory.h
+lib/synergy/KeyTypes.h
+lib/synergy/Makefile.am
+lib/synergy/MouseTypes.h
+lib/synergy/ProtocolTypes.h
+lib/synergy/Version.h
+lib/synergy/XScreen.cpp
+lib/synergy/XScreen.h
+lib/synergy/XSynergy.cpp
+lib/synergy/XSynergy.h
+lib/synergy/libsynergy.dsp
+mt/CCondVar.cpp
+mt/CCondVar.h
+mt/CLock.cpp
+mt/CLock.h
+mt/CMutex.cpp
+mt/CMutex.h
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+mt/CTimerThread.cpp
+mt/CTimerThread.h
+mt/Makefile.am
+mt/XThread.h
+mt/mt.dsp
+net/CNetwork.cpp
+net/CNetwork.h
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/CTCPListenSocket.cpp
+net/CTCPListenSocket.h
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+net/IDataSocket.h
+net/IListenSocket.h
+net/ISocket.h
+net/Makefile.am
+net/XNetwork.cpp
+net/XNetwork.h
+net/XSocket.cpp
+net/XSocket.h
+net/net.dsp
+platform/CMSWindowsClipboard.cpp
+platform/CMSWindowsClipboard.h
+platform/CMSWindowsClipboardAnyTextConverter.cpp
+platform/CMSWindowsClipboardAnyTextConverter.h
+platform/CMSWindowsClipboardTextConverter.cpp
+platform/CMSWindowsClipboardTextConverter.h
+platform/CMSWindowsClipboardUTF16Converter.cpp
+platform/CMSWindowsClipboardUTF16Converter.h
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CMSWindowsScreenSaver.cpp
+platform/CMSWindowsScreenSaver.h
+platform/CPlatform.cpp
+platform/CPlatform.h
+platform/CSynergyHook.cpp
+platform/CSynergyHook.h
+platform/CUnixPlatform.cpp
+platform/CUnixPlatform.h
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+platform/CXWindowsClipboardTextConverter.cpp
+platform/CXWindowsClipboardTextConverter.h
+platform/CXWindowsClipboardUCS2Converter.cpp
+platform/CXWindowsClipboardUCS2Converter.h
+platform/CXWindowsClipboardUTF8Converter.cpp
+platform/CXWindowsClipboardUTF8Converter.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsScreenSaver.h
+platform/CXWindowsUtil.cpp
+platform/CXWindowsUtil.h
+platform/IMSWindowsScreenEventHandler.h
+platform/IPlatform.h
+platform/Makefile.am
+platform/makehook.dsp
+platform/platform.dsp
+platform/synrgyhk.dsp
+server/CClientProxy.cpp
+server/CClientProxy.h
+server/CClientProxy1_0.cpp
+server/CClientProxy1_0.h
+server/CConfig.cpp
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CPrimaryScreen.cpp
+server/CPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/Makefile.am
+server/resource.h
+server/server.cpp
+server/server.dsp
+server/server.rc
+synergy.dsw
+synergy/CClipboard.cpp
+synergy/CClipboard.h
+synergy/CInputPacketStream.cpp
+synergy/CInputPacketStream.h
+synergy/COutputPacketStream.cpp
+synergy/COutputPacketStream.h
+synergy/CProtocolUtil.cpp
+synergy/CProtocolUtil.h
+synergy/CTCPSocketFactory.cpp
+synergy/CTCPSocketFactory.h
+synergy/ClipboardTypes.h
+synergy/IClient.h
+synergy/IClipboard.h
+synergy/IPrimaryScreenReceiver.h
+synergy/IScreen.h
+synergy/IScreenEventHandler.h
+synergy/IScreenReceiver.h
+synergy/IScreenSaver.h
+synergy/IServer.h
+synergy/ISocketFactory.h
+synergy/KeyTypes.h
+synergy/Makefile.am
+synergy/MouseTypes.h
+synergy/ProtocolTypes.h
+synergy/Version.h
+synergy/XScreen.cpp
+synergy/XScreen.h
+synergy/XSynergy.cpp
+synergy/XSynergy.h
+synergy/synergy.dsp
+
+Reorganized source tree. Moved client.cpp into cmd/synergy as
+synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp.
+Moved and renamed related files. Moved remaining source files
+into lib/.... Modified and added makefiles as appropriate.
+Result is that library files are under lib with each library
+in its own directory and program files are under cmd with each
+command in its own directory.
+
+----------
+2002/07/30 15:17:44 crs
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CSecondaryScreen.cpp
+client/CSecondaryScreen.h
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/client.cpp
+server/CClientProxy.h
+server/CClientProxy1_0.cpp
+server/CClientProxy1_0.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CPrimaryScreen.cpp
+server/CPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/server.cpp
+synergy/IClient.h
+
+Replaced method name `run' with `mainLoop', and `stop' and `quit'
+with `exitMainLoop' in most places.
+
+----------
+2002/07/30 14:59:36 crs
+client/CClient.h
+client/CMSWindowsSecondaryScreen.h
+client/CSecondaryScreen.h
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/CXWindowsSecondaryScreen.h
+server/CClientProxy.h
+server/CClientProxy1_0.h
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryClient.h
+server/CPrimaryScreen.h
+server/CServer.h
+server/CXWindowsPrimaryScreen.h
+synergy/IClient.h
+synergy/IScreen.h
+synergy/IScreenReceiver.h
+synergy/IServer.h
+
+Added doxygen comments for all relevant headers in client and server.
+
+----------
+2002/07/29 17:03:55 crs
+platform/CMSWindowsClipboard.h
+platform/CMSWindowsClipboardAnyTextConverter.h
+platform/CMSWindowsClipboardTextConverter.h
+platform/CMSWindowsClipboardUTF16Converter.h
+platform/CMSWindowsScreen.h
+platform/CMSWindowsScreenSaver.h
+platform/CPlatform.h
+platform/CSynergyHook.h
+platform/CUnixPlatform.h
+platform/CWin32Platform.h
+platform/CXWindowsClipboard.h
+platform/CXWindowsClipboardTextConverter.h
+platform/CXWindowsClipboardUCS2Converter.h
+platform/CXWindowsClipboardUTF8Converter.h
+platform/CXWindowsScreen.h
+platform/CXWindowsScreenSaver.h
+platform/CXWindowsUtil.h
+platform/IMSWindowsScreenEventHandler.h
+platform/IPlatform.h
+
+Added doxygen comments for all relevant headers in platform.
+
+----------
+2002/07/29 16:07:26 crs
+synergy/CClipboard.h
+synergy/CInputPacketStream.h
+synergy/COutputPacketStream.h
+synergy/CProtocolUtil.h
+synergy/CTCPSocketFactory.h
+synergy/ClipboardTypes.h
+synergy/IClient.h
+synergy/IClipboard.h
+synergy/IPrimaryScreenReceiver.h
+synergy/IScreen.h
+synergy/IScreenEventHandler.h
+synergy/IScreenReceiver.h
+synergy/IScreenSaver.h
+synergy/IServer.h
+synergy/ISocketFactory.h
+synergy/KeyTypes.h
+synergy/MouseTypes.h
+synergy/ProtocolTypes.h
+synergy/Version.h
+synergy/XScreen.h
+synergy/XSynergy.h
+
+Added doxygen comments for all relevant headers in synergy.
+
+----------
+2002/07/29 16:06:52 crs
+platform/CMSWindowsScreen.cpp
+server/CPrimaryClient.cpp
+
+moved try/catch block from CMSWindowsScreen to CPrimaryClient.
+this means CMSWindowsScreen doesn't need to include XSynergy.h.
+
+----------
+2002/07/29 16:05:59 crs
+doc/doxygen.cfg
+
+changed doxygen configuration.
+
+----------
+2002/07/28 19:06:52 crs
+net/CNetwork.h
+net/CNetworkAddress.h
+net/CTCPListenSocket.h
+net/CTCPSocket.h
+net/IDataSocket.h
+net/IListenSocket.h
+net/ISocket.h
+net/XNetwork.h
+net/XSocket.cpp
+net/XSocket.h
+
+Added doxygen comments for all relevant headers in net.
+
+----------
+2002/07/28 17:55:59 crs
+http/CHTTPProtocol.h
+http/XHTTP.cpp
+http/XHTTP.h
+
+Added doxygen comments for all relevant headers in http.
+
+----------
+2002/07/28 17:25:13 crs
+io/CBufferedInputStream.cpp
+io/CBufferedInputStream.h
+io/CBufferedOutputStream.cpp
+io/CBufferedOutputStream.h
+io/CInputStreamFilter.h
+io/COutputStreamFilter.h
+io/CStreamBuffer.h
+io/IInputStream.h
+io/IOutputStream.h
+io/XIO.h
+
+Added doxygen comments for all relevant headers in io.
+
+----------
+2002/07/28 13:34:19 crs
+mt/CCondVar.h
+mt/CLock.h
+mt/CMutex.h
+mt/CThread.h
+mt/CThreadRep.h
+mt/CTimerThread.h
+mt/XThread.h
+
+Added doxygen comments for all relevant headers in mt.
+
+----------
+2002/07/26 18:28:18 crs
+base/CFunctionJob.h
+base/CLog.h
+base/CStopwatch.h
+base/CString.h
+base/CUnicode.h
+base/IInterface.h
+base/IJob.h
+base/TMethodJob.h
+base/XBase.h
+base/common.h
+
+added doxygen comments for all relevant headers in base.
+
+----------
+2002/07/26 18:27:31 crs
+platform/CXWindowsUtil.cpp
+
+fixed type mismatch (SInt32 vs int) in definition of
+getWindowProperty().
+
+----------
+2002/07/26 16:05:59 crs
+doc/doxygen.cfg
+
+added configuration file for building doxygen documentation.
+the code is not yet doxygen documented, though.
+
+----------
+2002/07/26 15:22:25 crs
+platform/CXWindowsUtil.cpp
+
+now deleting property when so requested even if read failed.
+
+----------
+2002/07/25 18:08:00 crs
+notes
+
+checkpoint.
+
+----------
+2002/07/25 17:58:01 crs
+client/client.cpp
+net/XSocket.cpp
+server/server.cpp
+
+improved error messages for bad addresses.
+
+----------
+2002/07/25 17:52:40 crs
+base/XBase.cpp
+http/XHTTP.cpp
+io/XIO.cpp
+net/XNetwork.cpp
+net/XSocket.cpp
+server/CConfig.cpp
+server/server.cpp
+synergy/CProtocolUtil.cpp
+synergy/XScreen.cpp
+synergy/XSynergy.cpp
+
+made all getWhat() methods on exceptions consistent. they now
+all use format() the same way. also changed format() to actually
+do formatting. however, it doesn't try looking up formatting
+strings by id, it just uses the fallback format string.
+
+----------
+2002/07/25 17:23:35 crs
+base/CLog.cpp
+base/CLog.h
+base/CString.cpp
+base/CString.h
+
+moved string formatting into CStringUtil from CLog and added
+methods for format positional string arguments.
+
+----------
+2002/07/25 09:55:01 crs
+platform/CXWindowsScreen.cpp
+
+added unix specific implementation of CXWindowsScreen::mainLoop()
+that uses poll() to process events more efficiently. it won't
+wake up nor sleep any more than necessary, unlike the platform
+independent implementation that polls and sleeps.
+
+----------
+2002/07/25 09:23:24 crs
+platform/CXWindowsClipboard.cpp
+
+finished INCR transfer changes. also made motifGetTime() return
+icccmGetTime() because it seems motif does TIMESTAMP like ICCCM.
+
+----------
+2002/07/25 08:57:46 crs
+platform/CXWindowsClipboard.cpp
+
+checkpoint. working on INCR transfers.
+
+----------
+2002/07/24 19:26:18 crs
+platform/CMSWindowsScreen.cpp
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+
+fixes for win32 due to changes in how s_restartable is handled.
+the main change is that WM_QUIT now causes the thread to be
+cancelled instead of mainLoop() just returning. this also
+requires runDaemon() to call the run function in a new thread
+each time it calls it because it could can cancelled.
+
+----------
+2002/07/24 19:24:21 crs
+platform/CMSWindowsClipboardTextConverter.cpp
+platform/CMSWindowsClipboardUTF16Converter.cpp
+
+fixes for win32 clipboard due to CUnicode nul terminator changes.
+
+----------
+2002/07/24 19:23:46 crs
+base/CUnicode.cpp
+
+fixed an off-by-one error in UTF8ToText().
+
+----------
+2002/07/24 17:39:52 crs
+base/CUnicode.cpp
+
+fixed an off-by-one error in textToUTF8().
+
+----------
+2002/07/24 17:30:32 crs
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+
+fixed type of TARGETS target.
+
+----------
+2002/07/24 17:22:01 crs
+base/CUnicode.cpp
+base/CUnicode.h
+platform/CMSWindowsClipboardTextConverter.cpp
+platform/CMSWindowsClipboardUTF16Converter.cpp
+
+made handling of nul terminators in CUnicode more sane.
+
+----------
+2002/07/24 17:07:52 crs
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+
+some fixes for motif clipboard. still not handling incremental
+transfer through root window property because not sure of the
+protocol.
+
+----------
+2002/07/24 13:01:18 crs
+client/CClient.cpp
+client/client.cpp
+net/CTCPSocket.cpp
+net/XSocket.h
+platform/CUnixPlatform.cpp
+platform/CUnixPlatform.h
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsUtil.cpp
+platform/IPlatform.h
+server/CPrimaryClient.cpp
+server/CServer.cpp
+server/server.cpp
+synergy/ProtocolTypes.h
+synergy/Version.h
+
+removed restart function from platform. no longer trying to
+restart if the X server connection was lost; since synergy
+is likely to be started by xdm or the user's xsession, it's
+better for synergy to simply terminate when the connection
+is lost. synergy will still restart due to other errors.
+also fixed numerous other minor bugs and cleaned some stuff
+up (like app error codes are now consistent and enumerated
+in Version.h, for lack of a better place). and boosted
+version and protocol numbers.
+
+----------
+2002/07/23 19:00:01 crs
+notes
+
+checkpoint.
+
+----------
+2002/07/23 18:59:44 crs
+platform/CMSWindowsClipboard.cpp
+
+fixed a bug in clipboard conversion (was using wrong converter or
+no converter when one was available).
+
+----------
+2002/07/23 18:59:15 crs
+client/CMSWindowsSecondaryScreen.cpp
+server/CMSWindowsPrimaryScreen.cpp
+synergy/KeyTypes.h
+
+converted win32 to use unicode based KeyID.
+
+----------
+2002/07/23 17:04:41 crs
+client/CXWindowsSecondaryScreen.cpp
+server/CXWindowsPrimaryScreen.cpp
+synergy/KeyTypes.h
+
+checkpoint. converting KeyID to use UTF-32 encoding instead of
+X11 keysyms.
+
+----------
+2002/07/23 15:34:05 crs
+synergy/CClipboard.cpp
+synergy/IClipboard.h
+
+no longer attempting to unmarshall clipboard formats that aren't
+known to the caller. if the client supports more formats than
+the server then the server could get a clipboard format greater
+than kNumFormats. with this change the server discards the
+extra formats instead of crashing.
+
+----------
+2002/07/23 15:26:40 crs
+base/CUnicode.cpp
+base/CUnicode.h
+base/base.dsp
+platform/CMSWindowsClipboard.cpp
+platform/CMSWindowsClipboard.h
+platform/CMSWindowsClipboardAnyTextConverter.cpp
+platform/CMSWindowsClipboardAnyTextConverter.h
+platform/CMSWindowsClipboardTextConverter.cpp
+platform/CMSWindowsClipboardTextConverter.h
+platform/CMSWindowsClipboardUTF16Converter.cpp
+platform/CMSWindowsClipboardUTF16Converter.h
+platform/platform.dsp
+
+unicode clipboard changes for win32 plus some bug fixes.
+
+----------
+2002/07/23 12:35:36 crs
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+
+removed unnecessary atoms from X clipboard object.
+
+----------
+2002/07/23 12:08:30 crs
+base/CUnicode.cpp
+
+checkpoint. more CUnicode fixes.
+
+----------
+2002/07/23 11:51:13 crs
+base/CUnicode.cpp
+
+checkpoint. fixed the other cases in the same function as the
+previous checkin. also prevented the errors flag from getting
+reset after the multibyte to wide character conversion.
+
+----------
+2002/07/23 11:42:54 crs
+base/CUnicode.cpp
+
+checkpoint. fixed cases for mbrtowc (was using 1 and 2 instead
+of -1 and -2).
+
+----------
+2002/07/23 11:36:18 crs
+base/CUnicode.cpp
+base/CUnicode.h
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboardTextConverter.cpp
+
+checkpoint. more UTF8 clipboard stuff.
+
+----------
+2002/07/23 09:33:50 crs
+base/CUnicode.cpp
+base/CUnicode.h
+platform/CXWindowsClipboard.cpp
+
+checkpoint. more UTF8 clipboard testing.
+
+----------
+2002/07/22 18:46:57 crs
+base/CUnicode.cpp
+platform/CXWindowsClipboard.cpp
+
+checkpoint. more UTF8 clipboard stuff.
+
+----------
+2002/07/22 18:17:21 crs
+platform/CXWindowsClipboard.cpp
+
+checkpoint. more UTF8 clipboard stuff.
+
+----------
+2002/07/22 18:03:44 crs
+platform/CXWindowsClipboard.cpp
+
+checkpoint. working on UTF8 clipboard transfer.
+
+----------
+2002/07/22 17:32:51 crs
+base/CUnicode.cpp
+base/CUnicode.h
+base/Makefile.am
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+platform/CXWindowsClipboardTextConverter.cpp
+platform/CXWindowsClipboardTextConverter.h
+platform/CXWindowsClipboardUCS2Converter.cpp
+platform/CXWindowsClipboardUCS2Converter.h
+platform/CXWindowsClipboardUTF8Converter.cpp
+platform/CXWindowsClipboardUTF8Converter.h
+platform/Makefile.am
+synergy/IClipboard.h
+
+checkpoint. adding support for unicode in clipboard.
+
+----------
+2002/07/19 21:27:59 crs
+README
+
+changed notes about how to startup configure synergy. it now
+discourages using boot scripts, which can't handle X servers
+requiring authorization, and suggests modifying xdm's Xsetup.
+
+----------
+2002/07/19 20:44:57 crs
+examples/synergy.linux.init
+examples/synergyd.linux.init
+
+updated init.d scripts to work with SuSE. however, it looks as
+if they cannot be used on an X server using authentication
+because the daemons they start are not authorized to connect to
+the X server. X users should modify Xsetup or Xsession.
+
+----------
+2002/07/19 18:12:41 crs
+server/CXWindowsPrimaryScreen.cpp
+
+formatting.
+
+----------
+2002/07/19 17:39:45 crs
+server/CPrimaryScreen.cpp
+
+removed from previous change.
+
+----------
+2002/07/19 17:38:34 crs
+server/CPrimaryScreen.cpp
+
+reordered operations to reduce cursor flashing when entering
+primary screen.
+
+----------
+2002/07/18 17:03:10 crs
+platform/CSynergyHook.cpp
+server/CMSWindowsPrimaryScreen.cpp
+
+fixed handling of calling init() when a previous process did not
+call cleanup(). if that process still appears to exist then the
+init() fails. otherwise some cleanup is performed and the init()
+proceeds. a synergy server started while another is running will
+now exit immediately without interfering the original server.
+
+----------
+2002/07/18 17:00:48 crs
+server/CServer.cpp
+server/CServer.h
+
+now cancelling and waiting for the accept client thread before
+cancelling any other threads. this prevents a race condition
+where we disconnect a client but it reconnects before we
+manage to shutdown. that might leave a thread running and
+the connection won't be closed down properly.
+
+----------
+2002/07/18 16:58:08 crs
+mt/CThreadRep.cpp
+platform/CMSWindowsScreen.cpp
+
+changed waitForEvent() to handle a peculiar feature of
+MsgWaitForMultipleObjects(): it will not return immediately
+if an event already in the queue when it's called was already
+in the queue during the last call to GetMessage()/PeekMessage().
+also now discarding screen saver events if there are any other
+screen saver events in the queue already. this prevents these
+events from piling up in the queue, which they'd do because we
+sleep for 250ms when handling each one.
+
+----------
+2002/07/18 08:54:17 crs
+synergy.dsw
+
+fixed incorrect paths to makehook and synrgyhk project files.
+
+----------
+2002/07/17 17:27:41 crs
+platform/CMSWindowsScreen.cpp
+platform/CSynergyHook.cpp
+platform/CSynergyHook.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryScreen.cpp
+server/CPrimaryScreen.h
+
+attempt to fix stuttering when leaving win32 screen. seems to
+work but will let testers make the final call. also fixed
+desktop synchronization by setting a variable that was
+mistakenly left unset. and tried to work around an apparent
+bug in MsgWaitForMultipleObjects() that prevented the service
+from closing down properly. start/pause/continue/stop
+sequence still doesn't shut down correctly. start/pause/stop
+and start/stop work fine.
+
+----------
+2002/07/17 17:24:44 crs
+client/CClient.cpp
+
+removed unnecessary local variable.
+
+----------
+2002/07/16 19:07:15 crs
+base/stdistream.h
+io/CStreamBuffer.cpp
+
+fixes to get it compiling on .NET.
+
+----------
+2002/07/16 16:52:26 crs
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CSecondaryScreen.cpp
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+platform/CXWindowsScreen.cpp
+platform/IMSWindowsScreenEventHandler.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CPrimaryScreen.cpp
+server/CPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreenReceiver.h
+synergy/IScreen.h
+synergy/IScreenEventHandler.h
+synergy/IScreenReceiver.h
+synergy/IServer.h
+
+moved onError() method to IScreenReceiver from IPrimaryScreenReceiver.
+also implemented onError in CClient which previously did not have
+any way to handle display disconnection.
+
+----------
+2002/07/15 15:03:04 crs
+platform/CSynergyHook.cpp
+platform/synrgyhk.dsp
+
+completing previous checkin.
+
+----------
+2002/07/15 15:01:36 crs
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CSecondaryScreen.cpp
+client/CSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/client.dsp
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CSynergyHook.cpp
+platform/CSynergyHook.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/IMSWindowsScreenEventHandler.h
+platform/makehook.dsp
+platform/platform.dsp
+platform/synrgyhk.dsp
+server/CConfig.cpp
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryScreen.cpp
+server/CPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/makehook.dsp
+server/server.dsp
+server/synrgyhk.dsp
+synergy/IScreen.h
+synergy/IScreenEventHandler.h
+synergy/ProtocolTypes.h
+synergy/synergy.dsp
+
+checkpoint. refactored win32 code. had to edit and rename some
+files so this is only a checkpoint.
+
+----------
+2002/07/13 22:00:38 crs
+client/CClient.cpp
+client/CClient.h
+client/CSecondaryScreen.cpp
+client/CSecondaryScreen.h
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/ISecondaryScreen.h
+client/Makefile.am
+client/client.cpp
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+server/CClientProxy.h
+server/CClientProxy1_0.cpp
+server/CClientProxy1_0.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CPrimaryScreen.cpp
+server/CPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/IPrimaryScreen.h
+server/Makefile.am
+server/server.cpp
+synergy/IClient.h
+synergy/IPrimaryScreenReceiver.h
+synergy/IScreen.h
+synergy/IScreenEventHandler.h
+synergy/IScreenReceiver.h
+synergy/IServer.h
+synergy/Makefile.am
+
+checkpoint. still refactoring. merged common code from primary
+screens into CPrimaryScreen and merged common code from secondary
+screens into CSecondaryScreen. changed is-a relationship to a
+has-a between the primary and secondary screen classes and the
+generic platform dependent screen class to avoid multiple
+inheritance of implementation. also standardized the interface
+for those generic screen classes. adding a platform now involves
+implementing simpler interfaces: IScreen for the generic screen,
+IScreenEventHandler and some methods of CPrimaryScreen for the
+primary screen, and IScreenEventHandler and some methods of
+CSecondaryScreen for the secondary screen. did X11 platform
+but not win32 platform.
+
+----------
+2002/07/12 20:41:23 crs
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsScreenSaver.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+refactoring. refactored stuff in client (with changes to server
+as necessary).
+
+----------
+2002/07/11 18:58:49 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+checkpoint. making win32 and X primary screen code more similar
+in order to share code later.
+
+----------
+2002/07/11 13:13:37 crs
+client/CClient.cpp
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CServerProxy.cpp
+client/client.dsp
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CServer.cpp
+server/CServer.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/IPrimaryScreen.h
+server/server.dsp
+synergy/synergy.dsp
+
+applied refactoring to win32 code.
+
+----------
+2002/07/10 21:22:28 crs
+client/CClient.cpp
+client/CClient.h
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/ISecondaryScreen.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreenReceiver.h
+synergy/IScreenReceiver.h
+synergy/IServer.h
+synergy/Makefile.am
+
+more refactoring.
+
+----------
+2002/07/10 20:18:32 crs
+client/CClient.cpp
+client/CClient.h
+client/CServerProxy.cpp
+client/CServerProxy.h
+client/ISecondaryScreen.h
+client/Makefile.am
+client/client.cpp
+server/CClientProxy.h
+server/CClientProxy1_0.cpp
+server/CClientProxy1_0.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CServer.cpp
+synergy/IClient.h
+synergy/ISecondaryScreen.h
+synergy/Makefile.am
+
+refactored client code. it now uses IClient and IServer and
+has a CServerProxy, making it's design similar to the server
+code.
+
+----------
+2002/07/10 14:29:50 crs
+synergy/IClient.h
+
+removed some obsolete comments.
+
+----------
+2002/07/10 14:15:17 crs
+server/CClientProxy1_0.cpp
+server/CClientProxy1_0.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/IPrimaryReceiver.h
+server/Makefile.am
+synergy/IServer.h
+synergy/ProtocolTypes.h
+
+removed IPrimaryReceiver in favor of IServer, which required a few
+minor changes to support IPrimaryReciever's functionality. this
+does mean that the IPrimaryScreen class will be calling some
+methods with dummy arguments. those are documented in
+CPrimaryClient.
+
+----------
+2002/07/09 21:22:31 crs
+acinclude.m4
+acsite.m4
+config/depcomp
+config/install-sh
+config/missing
+config/mkinstalldirs
+mt/CThread.cpp
+mt/CThread.h
+notes
+platform/CXWindowsClipboard.cpp
+server/CClientProxy.cpp
+server/CClientProxy.h
+server/CClientProxy1_0.cpp
+server/CClientProxy1_0.h
+server/CPrimaryClient.cpp
+server/CPrimaryClient.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.cpp
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/IPrimaryReceiver.h
+server/IPrimaryScreen.h
+server/IServerProtocol.h
+server/Makefile.am
+synergy/IClient.h
+synergy/IServer.h
+synergy/Makefile.am
+
+updated to new automake and refactored server stuff. the server
+now speaks to the primary screen and secondary screens almost
+everywhere the same way through an IClient interface; only
+special primary screen calls are accessed through a different
+interface, the CPrimaryClient interface. this simplifies the
+server since it no longer needs to test whether the active screen
+is the primary or a secondary in most cases.
+
+the server no longer speaks directly to the primary screen; all
+that goes through the CPrimaryClient, which often just forwards
+the call. the primary screen no longer speaks directly to the
+server either, again going through the CPrimaryClient via a
+IPrimaryReceiver interface.
+
+CServerProtocol classes have been replaced by CClientProxy
+classes which are very similar. the name makes more sense
+though.
+
+----------
+2002/07/09 17:31:45 crs
+server/IPrimaryScreen.h
+synergy/IPrimaryScreen.h
+synergy/Makefile.am
+
+checkpoint. moved IPrimaryScreen.h.
+
+----------
+2002/07/07 15:15:34 crs
+server/IServerProtocol.h
+synergy/IServerProtocol.h
+
+moved IServerProtocol to server from synergy directory.
+
+----------
+2002/07/03 16:25:36 crs
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+fixed spurious mouse motions when entering/leaving primary
+screen on X11.
+
+----------
+2002/07/01 15:05:49 crs
+server/CMSWindowsPrimaryScreen.cpp
+
+mistakenly removed mouse button checks when on secondary screens
+from isLockedToScreen() in earlier checkin.
+
+----------
+2002/07/01 14:01:23 crs
+README
+notes
+
+checkpoint.
+
+----------
+2002/07/01 13:03:16 crs
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+synergy/ISecondaryScreen.h
+
+now synthesizing key release events for each pressed key when
+the client screen is closed. this fixes the bug where the
+client's keyboard was left with some keys logically pressed
+when the client died (e.g. using ctrl+c on the client program
+from the server's keyboard would leave the ctrl key logically
+pressed).
+
+----------
+2002/07/01 13:01:16 crs
+server/CServerProtocol1_0.cpp
+
+disabled removing client if no heartbeat is received. we don't
+want that while testing because it might hide bugs.
+
+----------
+2002/07/01 13:00:12 crs
+server/CMSWindowsPrimaryScreen.cpp
+
+fixed locking to screen on win32. was using GetKeyboardState()
+to query keys but that doesn't give us up-to-date information.
+now using GetAsyncKeyState() if on primary and m_keys if on
+secondary.
+
+----------
+2002/07/01 12:58:52 crs
+platform/CMSWindowsScreenSaver.cpp
+platform/CMSWindowsScreenSaver.h
+
+added win32 screen saver class forgotten in previous checkins.
+
+----------
+2002/06/26 16:31:48 crs
+client/CClient.cpp
+http/CHTTPProtocol.cpp
+io/CBufferedInputStream.cpp
+io/CBufferedInputStream.h
+io/CInputStreamFilter.h
+io/IInputStream.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CServer.cpp
+server/CServerProtocol1_0.cpp
+server/CSynergyHook.cpp
+synergy/CInputPacketStream.cpp
+synergy/CInputPacketStream.h
+synergy/CProtocolUtil.cpp
+synergy/ProtocolTypes.h
+
+synergy hook DLL will now restart itself if a client tries to
+init() it while it's already running. fixed an uninitialized
+pointer bug in CServer and some cleanup-on-error code in
+CMSWindowsPrimaryScreen. also added timeout to read() on
+IInputStream and a heartbeat sent by clients so the server
+can disconnect clients that are dead but never reset the TCP
+connection. previously the server would keep these dead
+clients around forever and if the user was locked on the
+client screen for some reason then the server would have to
+be rebooted (or the server would have to be killed via a
+remote login).
+
+----------
+2002/06/26 13:48:08 crs
+client/CClient.cpp
+client/CClient.h
+
+client now compresses mouse motion events. this fixes slow
+dragging on grace, possibly on win32 too.
+
+----------
+2002/06/26 13:31:06 crs
+synergy/CInputPacketStream.cpp
+synergy/CInputPacketStream.h
+
+fixed getSize() to be non-blocking in CInputPacketStream.
+
+----------
+2002/06/26 12:44:52 crs
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreenSaver.h
+
+fixed re-entrant calls to X bug.
+
+----------
+2002/06/23 23:24:22 crs
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreen.h
+
+fixed handling of jumping to primary when screen saver starts
+and back to secondary when it stops. also now redirecting
+keyboard input to root window when screen saver starts; this
+allows the user to type in the lock dialog and also effectively
+discards any input used to deactivate the screen saver.
+
+----------
+2002/06/23 21:54:05 crs
+notes
+
+checkpoint.
+
+----------
+2002/06/23 21:53:31 crs
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/platform.dsp
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+
+win32 screen saver now handled.
+
+----------
+2002/06/23 21:48:33 crs
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsScreenSaver.h
+
+now disabling disable job timer when forcing screen saver
+activation. previously the timer would deactivate the screen
+saver shortly after activation. job timer is restored when
+the screen saver is deactivated.
+
+----------
+2002/06/23 15:43:40 crs
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsScreenSaver.h
+platform/CXWindowsUtil.cpp
+server/CServer.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/Makefile.am
+synergy/IPrimaryScreen.h
+
+checkpoint screensaver changes. now handling xscreensaver
+dying and restarting or starting after synergy does. also
+now disabling the screen saver on the client. next step:
+win32 support.
+
+----------
+2002/06/22 20:29:59 crs
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsScreenSaver.h
+
+fixes to get xscreensaver integration working.
+
+----------
+2002/06/22 19:47:27 crs
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsUtil.cpp
+platform/CXWindowsUtil.h
+server/CXWindowsPrimaryScreen.cpp
+
+CXWindowsUtil::CErrorLock wasn't XSync()'ing the display before
+installing and uninstalling the new error handler, causing
+errors before the lock to be caught and errors during the lock
+to not be caught. had to add Display* as argument to c'tor.
+
+----------
+2002/06/22 19:20:21 crs
+client/CClient.cpp
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/CXWindowsScreenSaver.cpp
+platform/CXWindowsScreenSaver.h
+platform/Makefile.am
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreen.h
+synergy/IScreenSaver.h
+synergy/ISecondaryScreen.h
+synergy/Makefile.am
+
+checkpoint. adding screen saver support. only on X so far
+and untested. also some known problems: not detecting an
+xscreensaver started after us and not detecting built-in
+screen saver activation (not sure if we can without using
+ugly extensions).
+
+----------
+2002/06/22 17:31:24 crs
+client/Makefile.am
+http/Makefile.am
+io/Makefile.am
+mt/Makefile.am
+net/Makefile.am
+platform/Makefile.am
+server/Makefile.am
+synergy/Makefile.am
+
+added header files to _SOURCES.
+
+----------
+2002/06/22 13:55:45 crs
+server/CXWindowsPrimaryScreen.cpp
+
+added comments.
+
+----------
+2002/06/22 12:09:49 crs
+client/CXWindowsSecondaryScreen.cpp
+
+cleanup.
+
+----------
+2002/06/21 17:55:47 crs
+client/CClient.cpp
+client/CClient.h
+client/CXWindowsSecondaryScreen.cpp
+client/client.cpp
+server/CServer.cpp
+server/CServer.h
+server/server.cpp
+
+cleaned up some minor bugs.
+
+----------
+2002/06/21 17:54:22 crs
+net/CNetwork.cpp
+net/CNetwork.h
+
+ported network changes to win32.
+
+----------
+2002/06/21 16:29:35 crs
+net/CNetworkAddress.cpp
+
+now trying to convert hostname as a dot notation address before
+trying name lookup. not all platforms will do this for us in
+gethostbyname().
+
+----------
+2002/06/21 16:19:08 crs
+net/CNetwork.cpp
+net/CNetwork.h
+net/CTCPListenSocket.cpp
+net/CTCPSocket.cpp
+
+fixed CTCPSocket::connect() to allow cancellation.
+
+----------
+2002/06/21 15:18:01 crs
+server/CServer.cpp
+server/CServer.h
+
+some cleanup. also fixed a race condition when adding threads
+to the thread list: the child thread would add itself to the
+list which means there could be a time interval in the parent
+where the child thread exists but isn't on the list. the
+parent now does the adding and removing.
+
+----------
+2002/06/21 15:15:34 crs
+platform/CUnixPlatform.cpp
+
+now blocking SIGINT and SIGTERM in restart function. the child
+should handle the signal and terminate. then the restart
+function will exit.
+
+----------
+2002/06/21 15:14:32 crs
+mt/CThreadRep.cpp
+
+signal handler thread now dies when SIGABRT is raised. ignoring
+SIGABRT in sigwait() seems to be a bug in the linux pthread
+library.
+
+----------
+2002/06/20 16:27:49 crs
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+
+fixed bug introduced by previous checkin. calling XCheckIfEvent()
+multiple times is *not* the same as calling XIfEvent() because the
+former will re-encounter events that it didn't process previously.
+to make things simple it now pulls events off the queue and saves
+them if not processed for selection transfer and puts them back
+afterwards.
+
+----------
+2002/06/20 14:01:44 crs
+platform/CXWindowsClipboard.cpp
+
+speeded up clipboard transfer by avoiding a selection request
+when it wasn't necessary. (in particular, we were getting the
+clipboard update time from the owner then emptying the clipboard,
+so we didn't need to get the time. worse, most owners don't
+support getting the time and we often timed out.)
+
+also fixed a multithread bug using the X display. we were using
+a CThread to send an event after a timeout while we were waiting
+in XIfEvent(). this necessarily involved two threads calling
+into Xlib at once, which is not allowed. now using polling to
+do the timeout because Xlib doesn't have a function to get
+events with a timeout.
+
+----------
+2002/06/20 13:35:28 crs
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+
+checkpoint. trying to fix a delay when sending clipboards on X.
+
+----------
+2002/06/20 11:13:37 crs
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+
+added workaround for bug windows 98 (Me?) and multiple displays:
+absolute mouse_event() moves don't work except for primary
+display.
+
+----------
+2002/06/20 09:19:55 crs
+server/CXWindowsPrimaryScreen.cpp
+
+work around for bug with mouse driver on lombard powerbook.
+
+----------
+2002/06/19 20:24:35 crs
+client/CMSWindowsSecondaryScreen.cpp
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+fixed bugs in mouse motion. wasn't taking care to capture all
+motion events relative to the previous mouse position. for
+example, if two mouse events arrive, the first at x+1,y and
+the second at x+2,y, we used to compute deltas of 1,0 and 2,0
+instead of 1,0 and 1,0. that's fixed. also worked around a
+bug (probably) in windows that caused a motion event after a
+SetCursorPos() to be lost or reported one pixel off from the
+correct position. now using mouse_event() which doesn't
+have that problem. also fixed calculation of normalized
+coordinates for mouse_event() when there are multiple
+displays.
+
+----------
+2002/06/19 17:03:29 crs
+client/CClient.cpp
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol1_0.cpp
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/ProtocolTypes.h
+
+checkpoint. initial support for multiple displays on win32.
+
+----------
+2002/06/19 14:45:22 crs
+client/Makefile.am
+configure.in
+server/Makefile.am
+
+fixed addition of X11 -L and -l options on link lines.
+
+----------
+2002/06/19 12:21:26 crs
+configure.in
+platform/CUnixPlatform.cpp
+
+checkpoint. automake changes for wait().
+
+----------
+2002/06/19 11:58:48 crs
+configure.in
+http/CHTTPProtocol.cpp
+platform/CUnixPlatform.cpp
+
+checkpoint. automake changes for reentrant functions.
+
+----------
+2002/06/19 11:23:49 crs
+base/BasicTypes.h
+base/CLog.cpp
+base/CLog.h
+base/CStopwatch.cpp
+base/XBase.cpp
+base/common.h
+base/stdistream.h
+base/stdostream.h
+client/CClient.cpp
+client/CXWindowsSecondaryScreen.cpp
+client/client.cpp
+configure.in
+mt/CCondVar.cpp
+mt/CCondVar.h
+mt/CMutex.cpp
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+net/CNetwork.cpp
+net/CNetwork.h
+platform/CPlatform.cpp
+platform/CPlatform.h
+platform/CXWindowsClipboard.h
+platform/CXWindowsScreen.h
+platform/CXWindowsUtil.h
+server/CServer.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/server.cpp
+synergy/CProtocolUtil.h
+
+checkpoint. more conversion to automake.
+
+----------
+2002/06/19 08:23:08 crs
+config/install-sh
+config/missing
+config/mkinstalldirs
+configure.in
+install-sh
+missing
+mkinstalldirs
+
+moved auxillary automake files into config directory.
+
+----------
+2002/06/18 19:47:52 crs
+install-sh
+missing
+mkinstalldirs
+
+added automake required tools.
+
+----------
+2002/06/18 19:44:34 crs
+Make-linux
+Make-solaris
+Makecommon
+Makefile
+Makefile.am
+acsite.m4
+base/Makefile
+base/Makefile.am
+client/Makefile
+client/Makefile.am
+configure.in
+http/Makefile
+http/Makefile.am
+io/Makefile
+io/Makefile.am
+mt/Makefile
+mt/Makefile.am
+net/Makefile
+net/Makefile.am
+platform/Makefile
+platform/Makefile.am
+server/Makefile
+server/Makefile.am
+synergy/Makefile
+synergy/Makefile.am
+tools/depconv
+
+started to convert to autoconf/automake.
+
+----------
+2002/06/18 18:34:55 crs
+base/CLog.cpp
+
+now checking vsnprintf result against < 0 instead of == -1
+for portability.
+
+----------
+2002/06/18 18:33:59 crs
+net/XSocket.cpp
+
+added FIXME to commented out code.
+
+----------
+2002/06/17 15:44:45 crs
+README
+client/client.cpp
+server/server.cpp
+
+made command line parsing a little more sane with respect to
+windows NT services.
+
+----------
+2002/06/17 14:10:25 crs
+README
+
+updates
+
+----------
+2002/06/17 13:31:21 crs
+base/CLog.cpp
+base/CString.cpp
+base/XBase.cpp
+client/CClient.cpp
+client/CMSWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.cpp
+client/client.cpp
+http/CHTTPProtocol.cpp
+http/XHTTP.cpp
+io/CBufferedInputStream.cpp
+io/CBufferedOutputStream.cpp
+io/CInputStreamFilter.cpp
+io/COutputStreamFilter.cpp
+io/CStreamBuffer.cpp
+mt/CCondVar.cpp
+mt/CMutex.cpp
+mt/CThread.cpp
+mt/CThreadRep.cpp
+mt/CTimerThread.cpp
+net/CNetwork.cpp
+net/CNetworkAddress.cpp
+net/CTCPListenSocket.cpp
+net/CTCPSocket.cpp
+net/XNetwork.cpp
+net/XSocket.cpp
+platform/CMSWindowsClipboard.cpp
+platform/CMSWindowsScreen.cpp
+platform/CUnixPlatform.cpp
+platform/CWin32Platform.cpp
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsScreen.cpp
+platform/CXWindowsUtil.cpp
+server/CConfig.cpp
+server/CHTTPServer.cpp
+server/CMSWindowsPrimaryScreen.cpp
+server/CServer.cpp
+server/CServerProtocol.cpp
+server/CServerProtocol1_0.cpp
+server/CSynergyHook.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/server.cpp
+synergy/CClipboard.cpp
+synergy/CInputPacketStream.cpp
+synergy/COutputPacketStream.cpp
+synergy/CProtocolUtil.cpp
+synergy/XSynergy.cpp
+
+formatting changes.
+
+----------
+2002/06/17 12:02:26 crs
+client/CClient.cpp
+net/CTCPListenSocket.cpp
+net/CTCPListenSocket.h
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+net/IDataSocket.h
+net/IListenSocket.h
+net/ISocket.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CServer.cpp
+synergy/CTCPSocketFactory.cpp
+synergy/CTCPSocketFactory.h
+synergy/ISocketFactory.h
+
+refactored ISocket into IDataSocket. the latter and IListenSocket
+now derive from ISocket.
+
+----------
+2002/06/14 18:08:20 crs
+base/CFunctionJob.cpp
+base/CFunctionJob.h
+base/CLog.cpp
+base/TMethodJob.h
+base/common.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/client.cpp
+io/CStreamBuffer.cpp
+io/CStreamBuffer.h
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+platform/CMSWindowsScreen.cpp
+platform/CUnixPlatform.cpp
+platform/CUnixPlatform.h
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+platform/IPlatform.h
+server/server.cpp
+
+performance fixes on win32 plus clean up of some warnings. also
+improved error messages when uninstalling service.
+
+----------
+2002/06/11 20:10:49 crs
+README
+
+added a blurb about synrgyhk.dll and that the service manager
+will look for the binary wherever it was when --install was
+used.
+
+----------
+2002/06/11 20:09:59 crs
+base/stdpre.h
+platform/CMSWindowsScreen.h
+
+windows fixes needed for formatting changes.
+
+----------
+2002/06/11 18:33:03 crs
+client/CXWindowsSecondaryScreen.cpp
+
+commented out half-duplex flags that should never have been
+uncommented.
+
+----------
+2002/06/11 18:31:06 crs
+server/CServer.cpp
+
+fixed bug with switching screens on primary when there's no
+link in that direction (it would assert). introduced bug
+when adding support for wrapping. now ignores attempts to
+move in a direction with no link.
+
+----------
+2002/06/11 18:30:08 crs
+platform/CUnixPlatform.cpp
+
+added missing #include .
+
+----------
+2002/06/10 22:06:45 crs
+base/BasicTypes.h
+base/CFunctionJob.cpp
+base/CLog.cpp
+base/CLog.h
+base/CString.cpp
+base/CString.h
+base/TMethodJob.h
+base/XBase.cpp
+base/XBase.h
+base/common.h
+base/stdistream.h
+base/stdostream.h
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/client.cpp
+http/CHTTPProtocol.cpp
+http/CHTTPProtocol.h
+http/XHTTP.cpp
+http/XHTTP.h
+io/CBufferedInputStream.cpp
+io/CBufferedInputStream.h
+io/CBufferedOutputStream.cpp
+io/CBufferedOutputStream.h
+io/CInputStreamFilter.cpp
+io/COutputStreamFilter.cpp
+io/CStreamBuffer.cpp
+io/IInputStream.h
+io/IOutputStream.h
+io/XIO.cpp
+io/XIO.h
+mt/CCondVar.cpp
+mt/CCondVar.h
+mt/CLock.cpp
+mt/CLock.h
+mt/CMutex.cpp
+mt/CMutex.h
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CTimerThread.cpp
+mt/CTimerThread.h
+mt/XThread.h
+net/CNetwork.cpp
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/CTCPListenSocket.cpp
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+net/IListenSocket.h
+net/ISocket.h
+net/Makefile
+net/XNetwork.cpp
+net/XNetwork.h
+net/XSocket.cpp
+net/XSocket.h
+platform/CMSWindowsClipboard.cpp
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CPlatform.cpp
+platform/CUnixPlatform.cpp
+platform/CUnixPlatform.h
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/CXWindowsUtil.cpp
+platform/CXWindowsUtil.h
+platform/IPlatform.h
+server/CConfig.cpp
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.cpp
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/server.cpp
+synergy/CClipboard.cpp
+synergy/CClipboard.h
+synergy/CInputPacketStream.cpp
+synergy/COutputPacketStream.cpp
+synergy/CProtocolUtil.cpp
+synergy/CProtocolUtil.h
+synergy/CTCPSocketFactory.cpp
+synergy/IClipboard.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/ISocketFactory.h
+synergy/XScreen.cpp
+synergy/XSynergy.cpp
+
+indentation and other formatting changes. also cleaned up
+#includes.
+
+----------
+2002/06/10 16:49:46 crs
+base/CLog.cpp
+base/CStopwatch.cpp
+mt/CCondVar.cpp
+mt/CMutex.cpp
+mt/CThreadRep.h
+net/CNetwork.cpp
+net/CNetwork.h
+platform/CMSWindowsClipboard.h
+platform/CMSWindowsScreen.h
+platform/CWin32Platform.h
+server/CSynergyHook.h
+server/synrgyhk.dsp
+
+win32 changes. now including windows.h with WIN32_LEAN_AND_MEAN
+to avoid including some stuff we don't want (like winsock).
+
+----------
+2002/06/10 11:09:02 crs
+README
+
+fixes.
+
+----------
+2002/06/10 11:08:02 crs
+README
+
+updates.
+
+----------
+2002/06/10 11:00:55 crs
+README
+examples/synergy.conf
+examples/synergy.linux.init
+examples/synergyd.linux.init
+
+added example files and a README.
+
+----------
+2002/06/10 10:08:36 crs
+server/CMSWindowsPrimaryScreen.cpp
+server/CServer.cpp
+server/CXWindowsPrimaryScreen.cpp
+
+now allowing a screen to be its own neighbor to allow wrapping.
+also no longer warping mouse to 0,0 when setting server screen
+info. that was causing the mouse to jump if the server screen
+had itself as its left or top neighbor (directly or indirectly)
+once a screen could be its own neighbor.
+
+----------
+2002/06/10 09:49:21 crs
+server/CConfig.cpp
+
+fixed stripping of comments from configuration streams.
+
+----------
+2002/06/10 09:49:03 crs
+client/client.cpp
+server/server.cpp
+
+changed "permitted" to "supported" in error messages.
+
+----------
+2002/06/09 23:08:18 crs
+client/CClient.cpp
+
+no longer camps if the server sends an error message.
+
+----------
+2002/06/09 22:20:28 crs
+client/CClient.cpp
+client/CClient.h
+client/client.cpp
+
+added support for camping, i.e. repeatly trying to connect to the
+server until we succeed.
+
+----------
+2002/06/09 22:20:01 crs
+mt/CTimerThread.cpp
+mt/CTimerThread.h
+
+CTimerThread now allows zero and negative timeouts. a negative
+timeout never times out and CTimerThread is a no-op.
+
+----------
+2002/06/09 18:03:32 crs
+platform/CXWindowsScreen.cpp
+
+now using ":0.0" as the display if DISPLAY isn't set.
+
+----------
+2002/06/09 18:00:03 crs
+notes
+
+checkpoint.
+
+----------
+2002/06/09 17:59:32 crs
+client/client.cpp
+server/CServer.cpp
+server/CServer.h
+server/server.cpp
+
+added command line option to choose the screen name. also now
+using the hostname as the default name. this is on both client
+and server.
+
+----------
+2002/06/09 17:35:28 crs
+mt/CThreadRep.cpp
+
+added FIXME comment.
+
+----------
+2002/06/09 17:21:33 crs
+server/CServer.cpp
+
+fixed problem with setConfig(). if the new config didn't
+include a screen that was already connected under an alias
+then that screen wouldn't be disconnected and removed from
+the screen list until the screen voluntarily disconnected.
+at that time removeConnection() would assert because the
+screen name would not be found. now using the canonical
+name in the protocol object as well as CServer. this
+allows setConfig() to always detect removed screens and
+disconnect them.
+
+----------
+2002/06/09 16:53:57 crs
+platform/CUnixPlatform.cpp
+
+now exits instead of restarting if child dies due to an
+unexpected signal.
+
+----------
+2002/06/09 16:53:25 crs
+client/client.cpp
+net/CNetwork.cpp
+net/CNetwork.h
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/XSocket.cpp
+net/XSocket.h
+server/CConfig.cpp
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CServer.cpp
+server/CServer.h
+server/server.cpp
+synergy/ProtocolTypes.h
+
+added command line and configuration file arguments to choose
+the address and port to listen on or connect to. changed the
+default port and put it in ProtocolTypes.h. the HTTP port is
+now no longer opened unless the --http argument is supplied
+or the config file includes it.
+
+----------
+2002/06/08 23:24:40 crs
+server/CConfig.cpp
+server/CConfig.h
+server/CServer.cpp
+server/server.cpp
+
+added aliases to configuration. an alias is another name for
+a screen. it's expected that the server will want to accept
+a given client under several names (e.g. the hostname and the
+FQDN).
+
+----------
+2002/06/08 21:48:16 crs
+notes
+
+checkpoint.
+
+----------
+2002/06/08 21:48:00 crs
+all.dsp
+base/CLog.cpp
+base/CLog.h
+base/base.dsp
+base/common.h
+base/stdpre.h
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/client.cpp
+client/client.dsp
+http/http.dsp
+io/io.dsp
+mt/CThreadRep.cpp
+mt/mt.dsp
+net/net.dsp
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CUnixPlatform.cpp
+platform/CUnixPlatform.h
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+platform/IPlatform.h
+platform/platform.dsp
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/makehook.dsp
+server/server.cpp
+server/server.dsp
+server/synrgyhk.dsp
+synergy/IPrimaryScreen.h
+synergy/synergy.dsp
+
+win32 changes. changed names of binaries. added support for
+running as (and installing/installing) a service. added
+support for multiple desktops (NT only, 95 doesn't support
+multiple desktops).
+
+----------
+2002/06/04 12:26:23 crs
+Makefile
+client/Makefile
+client/client.cpp
+client/client.dsp
+platform/CMSWindowsClipboard.cpp
+platform/CMSWindowsClipboard.h
+platform/CMSWindowsScreen.cpp
+platform/CMSWindowsScreen.h
+platform/CPlatform.cpp
+platform/CPlatform.h
+platform/CUnixPlatform.cpp
+platform/CUnixPlatform.h
+platform/CWin32Platform.cpp
+platform/CWin32Platform.h
+platform/CXWindowsClipboard.cpp
+platform/CXWindowsClipboard.h
+platform/CXWindowsScreen.cpp
+platform/CXWindowsScreen.h
+platform/CXWindowsUtil.cpp
+platform/CXWindowsUtil.h
+platform/IPlatform.h
+platform/Makefile
+server/Makefile
+server/server.cpp
+server/server.dsp
+synergy.dsw
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsClipboard.h
+synergy/CMSWindowsScreen.cpp
+synergy/CMSWindowsScreen.h
+synergy/CXWindowsClipboard.cpp
+synergy/CXWindowsClipboard.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/CXWindowsUtil.cpp
+synergy/CXWindowsUtil.h
+synergy/Makefile
+synergy/synergy.dsp
+test.cpp
+
+refactored some common platform dependent stuff into a new
+library: platform. also removed test.cpp.
+
+----------
+2002/06/04 11:06:26 crs
+client/CClient.cpp
+client/client.cpp
+server/CServer.cpp
+server/CServerProtocol.cpp
+server/server.cpp
+synergy/ProtocolTypes.h
+synergy/Version.h
+
+added command line parsing, restartability, and daemonizing to
+client. broke win32 stuff though. also moved version and
+copyright constants into a new file and renamed protocol
+version constants.
+
+----------
+2002/06/04 11:03:34 crs
+base/CLog.cpp
+
+fixed delete bug in printt -- when skipping file and line the
+deleted pointer was wrong.
+
+----------
+2002/06/04 11:02:33 crs
+synergy/CXWindowsClipboard.cpp
+
+fixed timeout when getting selection -- forgot to set flag to
+terminate event loop.
+
+----------
+2002/06/03 18:53:18 crs
+base/CLog.cpp
+base/CLog.h
+server/CConfig.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/server.cpp
+synergy/CXWindowsScreen.cpp
+synergy/IPrimaryScreen.h
+
+changes to add command line arguments. also added automatic
+restarting and daemonizing on unix. daemon sends log messages
+to syslog. unix now reads config file from file named on
+command line; if no command line arg then uses effective
+user's config file and if that's not there it finally tries
+/etc/synergy.conf. if there are no screens configured then
+one is added for the primary screen. broke some startup
+stuff on win32.
+
+also now timing out if X primary screen can't grab the mouse
+and keyboard. the server will just give up trying to switch
+screens. the grabs will fail is some other app has a grab
+and won't release it. note that kdm grabs the keyboard for
+the duration that the login window is displayed, effectively
+disabling synergy.
+
+----------
+2002/06/03 16:36:45 crs
+base/CLog.cpp
+base/CLog.h
+
+added a method to set the filter given a priority string (instead
+of a number). fixed a comment related to what those priority
+strings are. added a CLOG_PRINT priority which is never filtered
+and suppresses the trace info and the priority level message.
+it's intended as a way to output a message through the logger
+without getting extra output.
+
+----------
+2002/06/03 16:34:22 crs
+base/CString.cpp
+base/CString.h
+base/Makefile
+base/base.dsp
+http/CHTTPProtocol.cpp
+http/CHTTPProtocol.h
+
+moved case insensitive comparison utility functions into CString
+from CHTTPProtocol.
+
+----------
+2002/06/03 13:45:30 crs
+client/CClient.cpp
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/Makefile
+synergy/XScreen.cpp
+synergy/XScreen.h
+synergy/synergy.dsp
+
+added better handling of X server disconnecting unexpectedly.
+the apps still exit but they do it in a mostly controlled
+manner. in particular, the server threads except the one
+processing primary screen events will terminate gracefully.
+this will be important should the server ever allow HTTP
+clients to rewrite the configuration file.
+
+note that X makes it effectively impossible to continue once
+the X server disconnects. even if it didn't it would be
+difficult for synergy to recover. users will have to add
+synergy to the X display manager's startup script if they
+expect the server to be restarted. alternatively, we could
+add code to fork synergy at startup; the child would do
+the normal work while the parent would simply wait for the
+child to exit and restart it.
+
+----------
+2002/06/02 23:07:57 crs
+net/CTCPListenSocket.cpp
+
+shortened poll() timeout.
+
+----------
+2002/06/02 22:57:50 crs
+io/CBufferedOutputStream.cpp
+io/CBufferedOutputStream.h
+net/CTCPSocket.cpp
+
+changed buffered output stream to wait() when flush()ing instead
+of polling/sleeping. changed CTCPSocket to not use thread
+cancellation but to instead use m_connected to exit the thread.
+also shortened poll timeout.
+
+----------
+2002/06/02 21:35:20 crs
+synergy/CMSWindowsScreen.cpp
+synergy/CXWindowsScreen.cpp
+
+make sleep shorter in poll/sleep getEvent() loops.
+
+----------
+2002/06/02 21:03:38 crs
+synergy/CXWindowsClipboard.cpp
+synergy/CXWindowsClipboard.h
+synergy/CXWindowsUtil.cpp
+
+removed poll/sleep code to improve performance.
+
+----------
+2002/06/02 19:04:24 crs
+client/CXWindowsSecondaryScreen.cpp
+
+now ignores key if there's no key mapped for a required modifier.
+was asserting (on the wrong expression).
+
+----------
+2002/06/02 18:49:35 crs
+client/CClient.cpp
+client/client.cpp
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+server/CServer.cpp
+server/server.cpp
+
+added SIGINT and SIGTERM handling to unix client and server.
+either signal causes the main thread to be cancelled. added
+necessary code to make main thread cancellation clean up
+nicely.
+
+----------
+2002/06/02 13:34:35 crs
+http/CHTTPProtocol.cpp
+http/CHTTPProtocol.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+
+added a maximum request size to CHTTPProtocol so we can bail
+on clients that cause us to use too much memory. also put
+methods in CHTTPRequest to get/set headers and changed the
+data structure used to store them. fixed a couple of other
+miscellaneous bugs in CHTTPProtocol.cpp.
+
+----------
+2002/06/02 11:49:46 crs
+mt/CCondVar.h
+server/CServer.cpp
+server/CServer.h
+
+now limiting number of simultaneous HTTP requests being handled
+at once. this is to prevent denial of service.
+
+----------
+2002/06/01 19:26:11 crs
+base/CLog.cpp
+base/CLog.h
+base/CString.h
+base/XBase.h
+base/base.dsp
+base/common.h
+base/stdfstream.h
+base/stdistream.h
+base/stdlist.h
+base/stdmap.h
+base/stdostream.h
+base/stdpost.h
+base/stdpre.h
+base/stdset.h
+base/stdsstream.h
+base/stdvector.h
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.h
+client/client.cpp
+client/client.dsp
+http/CHTTPProtocol.cpp
+http/CHTTPProtocol.h
+http/XHTTP.cpp
+http/http.dsp
+io/CStreamBuffer.h
+io/io.dsp
+mt/mt.dsp
+net/net.dsp
+server/CConfig.cpp
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CSynergyHook.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/makehook.dsp
+server/server.cpp
+server/server.dsp
+server/synrgyhk.dsp
+synergy.dsw
+synergy/CXWindowsClipboard.h
+synergy/IPrimaryScreen.h
+synergy/synergy.dsp
+
+fixes, mainly for windows. first, had to add a notification from
+CServer to the primary screen when the configuration changes so it
+can make necessary adjustments (the win32 primary screen must tell
+the hook dll about the new jump zones).
+
+changed includes of some std c++ library files to go through
+our own include files. these wrap the include with stuff to
+keep vc++ quiet when compiling at warning level 4, which is
+what it does now. it also works around missing and
+ on g++2.96.
+
+added missing std:: where necessary. g++ doesn't really support
+namespaces so it lets references without the namespace slip
+through.
+
+added workaround or fix. not sure if istringstream::str(string)
+should reset eofbit. it does on g++ but does not on vc++.
+added clear() after str() so it works either way.
+
+added low-level keyboard hook to win32. if available (it's only
+available on NT SP3 and up) it allows us to catch and handle
+alt+tab, alt+esc, ctrl+esc, and windows key hot keys. i think
+that leaves only ctrl+alt+del and accessibility functions
+uncaught on those systems.
+
+----------
+2002/06/01 10:52:02 crs
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol1_0.cpp
+
+added mutex to all public methods that didn't already have it.
+fixed two blown assertions. first, if user tried to switch to
+a client that had connected but hadn't yet sent the first info
+message it would assert on the zero size screen. second, if
+the primary screen was handling a mouse motion on behalf of a
+secondary screen when that secondary screen disconnected then
+an assert would blow because the primary screen would call
+onMouseMoveSecondary() but m_protocol on the active screen is
+NULL because disconnecting the active secondary screen caused
+the mouse to jump to the primary screen.
+
+----------
+2002/05/31 18:35:53 crs
+server/CConfig.h
+
+changed iterator to use iterator_traits directly instead of
+std::iterator to support the old STL on grace.
+
+----------
+2002/05/31 18:18:29 crs
+client/CClient.cpp
+client/CClient.h
+server/CServer.cpp
+synergy/ProtocolTypes.h
+synergy/XSynergy.cpp
+synergy/XSynergy.h
+
+server now rejects clients that are not in the configuration.
+added a protocol message to indicate this.
+
+----------
+2002/05/31 18:09:43 crs
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol1_0.cpp
+
+fixed setConfig() to disconnect secondary screens that aren't
+in the new configuration.
+
+----------
+2002/05/31 18:08:08 crs
+server/CConfig.cpp
+server/CConfig.h
+
+made isScreen() a const method.
+
+----------
+2002/05/31 17:32:26 crs
+server/CConfig.cpp
+server/CConfig.h
+server/server.cpp
+
+added I/O for configuration files and changed the server to use
+an external file for its configuration (was hard coding a config
+for testing).
+
+----------
+2002/05/31 14:44:54 crs
+server/CConfig.cpp
+server/CScreenMap.cpp
+server/Makefile
+server/server.dsp
+
+finished renaming CScreenMap to CConfig.
+
+----------
+2002/05/31 14:43:23 crs
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CScreenMap.cpp
+server/CServer.cpp
+server/CServer.h
+server/CSynergyHook.cpp
+server/server.cpp
+
+checkpoint. changed CScreenMap to CConfig. must still change
+CScreenMap.cpp to CConfig.cpp.
+
+----------
+2002/05/31 14:34:16 crs
+server/CConfig.h
+server/CHTTPServer.cpp
+server/CScreenMap.cpp
+server/CScreenMap.h
+server/CServer.h
+server/CSynergyHook.cpp
+server/server.cpp
+
+checkpoint. renamed CScreenMap.h to CConfig.h. will be
+changing CScreenMap to CConfig everywhere.
+
+----------
+2002/05/31 14:25:26 crs
+base/CLog.cpp
+base/CLog.h
+client/client.cpp
+server/server.cpp
+
+added methods to CLog for getting the outputter, getting and
+setting the priority filter, and added code for thread safety.
+added code to apps to enable thread safety in CLog.
+
+----------
+2002/05/30 16:13:16 crs
+Makefile
+base/common.h
+http/CHTTPProtocol.cpp
+http/CHTTPProtocol.h
+http/Makefile
+http/XHTTP.cpp
+http/XHTTP.h
+server/CHTTPServer.cpp
+server/CHTTPServer.h
+server/CScreenMap.cpp
+server/CScreenMap.h
+server/CServer.cpp
+server/CServer.h
+server/Makefile
+
+added basic support for an embedded HTTP server. server
+currently supports editing the screen map but changing
+the map won't behave correctly if there are connected
+screens.
+
+----------
+2002/05/30 16:11:59 crs
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+
+fixed bug in closing down a socket.
+
+----------
+2002/05/27 18:55:51 crs
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsClipboard.h
+
+updated win32 clipboard to match new model.
+
+----------
+2002/05/27 18:35:14 crs
+notes
+
+checkpoint
+
+----------
+2002/05/27 18:30:13 crs
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/CXWindowsClipboard.cpp
+synergy/CXWindowsScreen.h
+synergy/CXWindowsUtil.cpp
+synergy/CXWindowsUtil.h
+
+removed getEventMask() from primary screen. added a class to
+CXWindowsUtil that installs/uninstalls an X error hander.
+using that in primary screen, clipboard, and util to ensure
+that certain errors don't kill the app.
+
+----------
+2002/05/27 18:28:06 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+
+removed getEventMask() and fixed some comments. also now using
+toggle key states in updateModifiers().
+
+----------
+2002/05/27 17:05:34 crs
+synergy/CXWindowsClipboard.cpp
+
+changed lesstif hack to only apply to the CLIPBOARD selection.
+apprently the PRIMARY selection must follow the ICCCM protocol
+correctly.
+
+----------
+2002/05/27 16:51:07 crs
+synergy/CXWindowsUtil.cpp
+synergy/CXWindowsUtil.h
+
+added missing files from previous submit.
+
+----------
+2002/05/27 16:22:59 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/CClipboard.cpp
+synergy/CClipboard.h
+synergy/CXWindowsClipboard.cpp
+synergy/CXWindowsClipboard.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/IClipboard.h
+synergy/Makefile
+
+checkpoint. changed clipboard model. the clipboard can only
+be accessed now between open()/close(). ownership of the
+clipboard is asserted via the empty() method. this parallels
+the win32 model (but the win32 code hasn't been updated yet).
+
+refactored X11 clipboard code. moved the bulk of it into
+CXWindowsClipboard and moved some comment event handling into
+CXWindowsScreen. changed how requests are processed into a
+hopefully easier to understand model. added support for getting
+clipboard from and sending clipboard to motif (or at least
+lesstif) clients. sending to lesstif required a hack to work
+around an apparent bug in lesstif.
+
+----------
+2002/05/24 17:54:34 crs
+notes
+
+checkpoint
+
+----------
+2002/05/24 17:54:28 crs
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CXWindowsPrimaryScreen.cpp
+synergy/CMSWindowsScreen.cpp
+synergy/CMSWindowsScreen.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/ProtocolTypes.h
+
+added screen locking support to win32. added support for
+resolution changing (only semi-supported on X because that
+has no means for resizing screen anyway). also fixed some
+clipboard problems on win32.
+
+----------
+2002/05/24 14:37:12 crs
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreen.h
+
+added support for locking to a screen when the sroll lock is
+toggled on or when any key or button is pressed. fully
+implemented on X but stubbed out for now on win32.
+
+----------
+2002/05/23 18:35:15 crs
+notes
+
+checkpoint
+
+----------
+2002/05/23 18:35:08 crs
+server/CMSWindowsPrimaryScreen.cpp
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+
+added support for mouse wheel on win32.
+
+----------
+2002/05/23 15:50:38 crs
+client/CXWindowsSecondaryScreen.cpp
+server/CXWindowsPrimaryScreen.cpp
+
+added support for mouse wheel on X.
+
+----------
+2002/05/23 15:00:39 crs
+server/server.cpp
+
+added a third screen to hard coded map for testing purposes.
+
+----------
+2002/05/23 15:00:13 crs
+server/CServer.cpp
+
+fixed log message.
+
+----------
+2002/05/23 14:56:03 crs
+client/CClient.cpp
+client/CClient.h
+server/CServer.cpp
+server/CServerProtocol.cpp
+server/CServerProtocol1_0.cpp
+synergy/ProtocolTypes.h
+synergy/XSynergy.cpp
+synergy/XSynergy.h
+
+server no longer asserts when a client connects with a name that's
+already in use by another client. also added reporting of errors
+from the server to clients so clients can report meaningful
+messages to users.
+
+----------
+2002/05/23 14:04:43 crs
+notes
+
+checkpoint
+
+----------
+2002/05/23 14:04:35 crs
+net/CNetwork.h
+synergy/CXWindowsScreen.h
+
+changed structs to classes. there should be no more structs now.
+
+----------
+2002/05/22 17:09:08 crs
+notes
+
+checkpoint.
+
+----------
+2002/05/22 17:08:37 crs
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsScreen.cpp
+synergy/CMSWindowsScreen.h
+synergy/CProtocolUtil.cpp
+
+removed unnecessary call in screen class, added logging calls
+in clipboard class, and added another cast in protocol util
+to avoid warning on win32.
+
+----------
+2002/05/22 17:05:26 crs
+server/CSynergyHook.cpp
+
+now letting some key events filter through. this allows the
+keyboard lights to track toggle changes. however, it also
+seems to let through keyboard events that shouldn't get
+through.
+
+----------
+2002/05/22 17:02:58 crs
+server/CScreenMap.cpp
+
+fixed incorrect for-loop over directions conditional.
+
+----------
+2002/05/22 17:01:17 crs
+base/CLog.cpp
+base/CLog.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+
+win32 changes. replaced log dialog hack with a windows console
+window. now attaching thread input queues as necessary. shifted
+code around so toggling toggle keys is immediately reflected by
+secondary screen's keyboard. now setting extended key flag for
+keys that need it. fixed handling of shift + caps-lock. added
+handling of keys that should distinguish between left and right
+but don't. fixed get/set of active window on leave/enter of
+primary screen. replaced 1x1 primary window with a full screen
+window to work around a problem with losing key events. changed
+calculation of mouse move deltas.
+
+----------
+2002/05/22 16:56:06 crs
+net/CTCPListenSocket.cpp
+
+fixed type of socket handle (from int to CNetwork::Socket).
+
+----------
+2002/05/22 16:55:19 crs
+mt/CTimerThread.cpp
+
+removed blank line.
+
+----------
+2002/05/22 16:55:05 crs
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+
+changed un-inlined code to avoid bogus VC++ level 4 warnings.
+added support for more win32 thread priorities.
+
+----------
+2002/05/22 16:51:59 crs
+client/client.cpp
+
+fixed parameter type for socket port.
+
+----------
+2002/05/22 16:43:14 crs
+base/common.h
+
+changed set of disabled win32 warnings.
+
+----------
+2002/05/22 16:42:48 crs
+client/CClient.cpp
+
+fixed NULL dereference.
+
+----------
+2002/05/22 16:41:24 crs
+base/common.h
+
+changed set of disabled win32 warnings.
+
+----------
+2002/05/22 16:40:51 crs
+base/CLog.cpp
+base/CLog.h
+
+replaced logging dialog hack with a windows console window.
+
+----------
+2002/05/22 16:40:38 crs
+client/CClient.cpp
+
+fixed NULL dereference.
+
+----------
+2002/05/05 23:37:12 crs
+net/CTCPSocket.cpp
+
+removed setting send buffer to zero size. it just reduced
+performance.
+
+----------
+2002/05/05 19:52:03 crs
+client/CXWindowsSecondaryScreen.cpp
+
+replaced True/False with true/false when assigning to m_repeat.
+also should now work if the first element of a modifier
+keymapping is 0. that won't normally be the case but xmodmap
+was doing weird things on grace. if the first element is 0
+it'll try the second element. if that's also zero then that
+modifier will be ignored.
+
+----------
+2002/05/05 19:38:09 crs
+client/CMSWindowsSecondaryScreen.cpp
+server/CMSWindowsPrimaryScreen.cpp
+
+fixes for win32 keyboard.
+
+----------
+2002/05/04 19:43:20 crs
+client/CXWindowsSecondaryScreen.cpp
+
+fixed caps-lock handling.
+
+----------
+2002/05/04 18:33:48 crs
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+checkpoint. added half duplex for num lock.
+
+----------
+2002/05/04 18:31:54 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+
+checkpoint. fixing up handling of half-duplex num-lock.
+
+----------
+2002/05/04 18:09:02 crs
+client/CXWindowsSecondaryScreen.cpp
+
+checkpoint. changed when toggle keys toggle (now always on
+release). must see if this works.
+
+----------
+2002/05/04 18:08:22 crs
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+net/CTCPSocket.cpp
+server/CMSWindowsPrimaryScreen.cpp
+
+Fixes for win32 key handling.
+
+----------
+2002/05/04 11:23:11 crs
+client/CXWindowsSecondaryScreen.cpp
+
+fixed handling of shift + caps-lock. those two modifiers should
+cancel out if the keysym is subject to case conversion, but not
+otherwise. also added logging of key lookup code.
+
+----------
+2002/05/03 12:23:48 crs
+client/CXWindowsSecondaryScreen.cpp
+
+fixed handling of shift+tab on a system that can map ISO_Left_Tab.
+now tries to map ISO_Left_Tab without shift first then falls back
+to Tab (note that if ISO_Left_Tab can be mapped but requires a
+modifier then the modifier will be added). also changed attempt
+to map ISO_Left_Tab as a backup to Tab to request the shift
+modifier whether or not the primary screen requested it.
+
+----------
+2002/05/03 12:14:55 crs
+client/CXWindowsSecondaryScreen.cpp
+
+fixed handling of ISO_Left_Tab when that is not mapped to a
+keycode by mapping it to tab with shift pressed.
+
+----------
+2002/05/03 11:49:30 crs
+client/CXWindowsSecondaryScreen.cpp
+
+removed attempt to make release/press of a repeating key use
+the same server time. was getting what appears to be deadlock
+but not sure why.
+
+----------
+2002/05/03 11:26:44 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+checkpoint. made changes to support key autorepeats on X.
+
+----------
+2002/05/02 11:44:21 crs
+synergy/COutputPacketStream.cpp
+
+Indentation change.
+
+----------
+2002/05/02 11:43:52 crs
+io/CStreamBuffer.cpp
+net/CTCPSocket.cpp
+
+Fixed bug in stream buffer that could cause data to be
+inserted out of order. Also removed unnecessary limit
+on writes to the TCP socket.
+
+----------
+2002/05/02 11:33:34 crs
+io/CStreamBuffer.cpp
+
+checkpoint debugging of stream buffer.
+
+----------
+2002/05/01 16:30:20 crs
+synergy/CXWindowsScreen.cpp
+
+Was trying to avoid sending clipboard if timestamp wasn't
+changed but clipboard owners may not update that timestamp
+when the selection is changed. Disabled the timestamp check.
+
+----------
+2002/05/01 16:17:57 crs
+server/CServer.cpp
+synergy/CXWindowsScreen.cpp
+
+Added more checks to avoid sending unchanged clipboard data.
+Still takes too long to query the clipboard owner for info
+(maybe 1/10th second) but not sure why or if that can be
+improved.
+
+----------
+2002/05/01 15:31:47 crs
+Make-linux
+net/CNetwork.h
+net/CTCPSocket.cpp
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+
+checkpoint. turned off nagle and send buffering. also
+added test to skip clipboard conversion if a previous
+conversion from that owner failed.
+
+----------
+2002/05/01 14:36:52 crs
+server/CServer.cpp
+server/CXWindowsPrimaryScreen.cpp
+
+Fixed uninitialized variable when computing toggle mask. Also
+reduced priority of some mouse motion log messages.
+
+----------
+2002/05/01 14:35:55 crs
+net/CSocketInputStream.cpp
+net/CSocketInputStream.h
+net/CSocketOutputStream.cpp
+net/CSocketOutputStream.h
+net/CSocketStreamBuffer.cpp
+net/CSocketStreamBuffer.h
+net/net.dsp
+
+removed obsolete files.
+
+----------
+2002/04/30 18:30:05 crs
+client/CXWindowsSecondaryScreen.cpp
+
+added fallback for missing numpad movement keys (if there's no
+mapping for those keys then the non-keypad versions are tried).
+
+----------
+2002/04/30 17:48:11 crs
+client/CClient.cpp
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/ProtocolTypes.h
+
+checkpoint. now sending toggle modifier state when entering
+a screen. this allows the secondary screen to set it's
+modifier state to match the primary screen's state. this is
+not strictly necessary since each keystroke should adjust the
+modifier state as needed to get the right result.
+
+----------
+2002/04/30 16:25:29 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+
+Added logging and handling of "half-duplex" caps-lock key.
+
+----------
+2002/04/30 16:23:30 crs
+Make-linux
+Make-solaris
+
+Changed name for auto-generated dependency files from
+Makedepend to .depend.
+
+----------
+2002/04/30 16:23:03 crs
+client/CClient.cpp
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServerProtocol1_0.cpp
+server/server.rc
+synergy/CClipboard.cpp
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsClipboard.h
+synergy/synergy.dsp
+
+Fixes to get win32 client and server up to date.
+
+----------
+2002/04/29 14:40:01 crs
+base/CFunctionJob.h
+base/CLog.h
+base/CStopwatch.cpp
+base/CStopwatch.h
+base/CString.h
+base/IInterface.h
+base/IJob.h
+base/TMethodJob.h
+base/XBase.h
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+io/CBufferedInputStream.h
+io/CBufferedOutputStream.h
+io/CInputStreamFilter.h
+io/COutputStreamFilter.h
+io/CStreamBuffer.h
+io/IInputStream.h
+io/IOutputStream.h
+io/XIO.h
+mt/CCondVar.cpp
+mt/CCondVar.h
+mt/CLock.h
+mt/CMutex.cpp
+mt/CMutex.h
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+mt/CTimerThread.h
+mt/XThread.h
+net/CNetwork.h
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/CSocketInputStream.h
+net/CSocketOutputStream.h
+net/CSocketStreamBuffer.h
+net/CTCPListenSocket.h
+net/CTCPSocket.h
+net/IListenSocket.h
+net/ISocket.h
+net/XNetwork.h
+net/XSocket.h
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CScreenMap.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.h
+server/CServerProtocol1_0.h
+server/CSynergyHook.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/CClipboard.h
+synergy/CInputPacketStream.cpp
+synergy/CInputPacketStream.h
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsClipboard.h
+synergy/CMSWindowsScreen.h
+synergy/COutputPacketStream.h
+synergy/CProtocolUtil.cpp
+synergy/CProtocolUtil.h
+synergy/CTCPSocketFactory.h
+synergy/CXWindowsClipboard.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/IClipboard.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/ISocketFactory.h
+synergy/XSynergy.h
+
+Indentation changes.
+
+----------
+2002/04/29 14:25:24 crs
+client/CClient.cpp
+server/CServer.cpp
+server/CServerProtocol1_0.cpp
+
+Added some validation of protocol message parameters.
+
+----------
+2002/04/29 14:12:48 crs
+synergy/CXWindowsScreen.cpp
+
+Shortened timeout on waiting for clipboard response.
+
+----------
+2002/04/29 14:08:48 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CServer.cpp
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+
+Made event selection a little more robust. Also fixed failure
+to marshall clipboard data when updating primary clipboards.
+
+----------
+2002/04/29 13:49:56 crs
+client/CXWindowsSecondaryScreen.cpp
+
+Added missing event mask.
+
+----------
+2002/04/29 13:31:44 crs
+client/CClient.cpp
+client/CClient.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+synergy/CClipboard.cpp
+synergy/CClipboard.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/IClipboard.h
+synergy/IPrimaryScreen.h
+synergy/IServerProtocol.h
+synergy/ProtocolTypes.h
+
+checkpoint. changed protocol to better handle clipboards. now
+sending a sequence number with enter messages. screens use that
+sequence number in clipboard grab and data messages. the server
+uses the sequence number to order messages across clients. also
+changed secondary screens to send clipboard updates on leaving
+(or when grab occurs when not active) instead of on a query from
+the server. primary effectively does the same. the query
+message has been removed.
+
+----------
+2002/04/29 11:58:17 crs
+client/CClient.cpp
+
+changed logging levels.
+
+----------
+2002/04/28 00:46:15 crs
+client/CXWindowsSecondaryScreen.cpp
+server/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+
+Clipboard improvements. Still not working right. Nedit
+doesn't work at all but at least now there's a timeout to
+prevent synergy from hanging waiting on a reply.
+
+----------
+2002/04/27 18:49:03 crs
+base/CLog.cpp
+base/CLog.h
+client/CClient.cpp
+mt/CThread.cpp
+mt/CThreadRep.cpp
+mt/CTimerThread.cpp
+net/CNetwork.cpp
+server/CServer.cpp
+server/CServerProtocol1_0.cpp
+server/CXWindowsPrimaryScreen.cpp
+synergy/CProtocolUtil.cpp
+synergy/CXWindowsScreen.cpp
+
+Added more debug levels and moved some annoying debug messages
+to those levels. Default log level is now DEBUG for debug
+builds and INFO for release builds.
+
+----------
+2002/04/27 18:06:40 crs
+client/CClient.cpp
+client/CXWindowsSecondaryScreen.cpp
+server/CServer.cpp
+server/CServerProtocol1_0.cpp
+server/CXWindowsPrimaryScreen.cpp
+synergy/CProtocolUtil.cpp
+synergy/CXWindowsScreen.cpp
+synergy/ProtocolTypes.h
+
+checkpoint. changed CProtocolUtil::readf() to store 1 and 2
+byte integers into pointers to 1 and 2 byte integers. was
+always assuming pointers to 4 byte integers.
+
+----------
+2002/04/27 14:19:53 crs
+client/CClient.cpp
+client/CClient.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/ClipboardTypes.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/ProtocolTypes.h
+
+Added support for multiple clipboards. This is mainly to
+support both PRIMARY and CLIPBOARD selections on X windows.
+
+----------
+2002/04/27 14:19:19 crs
+Makecommon
+
+set TARGETS macro to BIN and LIB targets.
+
+----------
+2002/04/26 20:15:59 crs
+notes
+
+updated
+
+----------
+2002/04/26 20:14:46 crs
+client/CXWindowsSecondaryScreen.cpp
+
+Fixed caps-lock and num-lock behavior. It seems to work okay
+now but did notice one problem: when powerbook is primary and
+num-lock is on the keypad works fine until shift is pressed
+(and released); after that the keypad only works while the
+shift key is down.
+
+----------
+2002/04/26 20:12:55 crs
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+
+Added hack to handle "half-duplex" caps-lock key on powerbook.
+That key only reports press when pressed and released when
+caps-lock is activated and only reports release when pressed
+and released when caps-lock is deactivated. I don't know of a
+way to detect this behavior so it may have to be configured by
+the user. The code assumes normal behavior; will have to add
+code to set the flag (perhaps from a user configuration).
+
+----------
+2002/04/26 17:38:01 crs
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+synergy/KeyTypes.h
+
+changed processing of key events in X. secondary screen now
+activates/deactivates modifiers as necessary to get a keycode
+interpreted as the expected keysym. still some work and
+testing to do on this.
+
+----------
+2002/04/25 10:44:01 crs
+notes
+
+Added notes on keyboard handling.
+
+----------
+2002/04/25 10:43:53 crs
+client/CXWindowsSecondaryScreen.cpp
+server/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+
+added handling for DestroyNotify of clipboard requestors.
+
+----------
+2001/11/26 22:36:51 crs
+synergy/CXWindowsScreen.cpp
+
+checkpoint. improvements to clipboard transfer on X windows.
+not detecting a change to clipboard when synergy window isn't
+the owner (since there's no event for this; we'll have to
+check when we leave the screen i guess). large transfers
+don't seem to work.
+
+----------
+2001/11/26 22:09:53 crs
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+
+checkpoint. testing clipboard transfer on X windows.
+
+----------
+2001/11/25 22:20:41 crs
+client/CXWindowsSecondaryScreen.cpp
+server/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+
+checkpoint. implementing clipboard owner in x windows.
+
+----------
+2001/11/25 18:44:13 crs
+synergy/CXWindowsClipboard.cpp
+synergy/CXWindowsClipboard.h
+
+fixed function signature.
+
+----------
+2001/11/25 18:42:13 crs
+Make-linux
+Make-solaris
+Makecommon
+client/Makefile
+server/Makefile
+
+executables are now built into a common area on unix (and they
+already were on win32).
+
+----------
+2001/11/25 18:32:41 crs
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/client.cpp
+client/client.dsp
+net/CNetwork.cpp
+notes
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/makehook.dsp
+server/server.cpp
+server/server.dsp
+server/synrgyhk.dsp
+synergy.dsw
+synergy/CClipboard.cpp
+synergy/CClipboard.h
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsClipboard.h
+synergy/CMSWindowsScreen.cpp
+synergy/CMSWindowsScreen.h
+synergy/CProtocolUtil.cpp
+synergy/CProtocolUtil.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/IClipboard.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/Makefile
+synergy/ProtocolTypes.h
+synergy/synergy.dsp
+
+added platform independent clipboard transfer stuff
+clipboard owner support (MS windows done, X windows partial)
+added key transfer on ms windows
+mutex fixes in CClient (had race conditions)
+faster debug output in ms windows
+changed temporary screen name to "secondary"
+network fixes on ms windows (poll returned wrong result)
+fixed transparent cursor on ms windows
+
+----------
+2001/11/19 00:33:36 crs
+Make-linux
+all.dsp
+base/BasicTypes.h
+base/CLog.cpp
+base/CLog.h
+base/XBase.cpp
+base/base.dsp
+base/common.h
+client/CClient.cpp
+client/CClient.h
+client/CMSWindowsSecondaryScreen.cpp
+client/CMSWindowsSecondaryScreen.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/Makefile
+client/client.cpp
+client/client.dsp
+client/client.rc
+client/resource.h
+io/io.dsp
+mt/CCondVar.cpp
+mt/CThread.cpp
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+mt/mt.dsp
+net/CNetwork.cpp
+net/CNetwork.h
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/CTCPListenSocket.cpp
+net/CTCPListenSocket.h
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+net/Makefile
+net/XNetwork.cpp
+net/XNetwork.h
+net/net.dsp
+notes
+server/CMSWindowsPrimaryScreen.cpp
+server/CMSWindowsPrimaryScreen.h
+server/CScreenMap.h
+server/CServer.cpp
+server/CServer.h
+server/CSynergyHook.cpp
+server/CSynergyHook.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/Makefile
+server/makehook.dsp
+server/resource.h
+server/server.cpp
+server/server.dsp
+server/server.rc
+server/synrgyhk.dsp
+synergy.dsw
+synergy/CMSWindowsClipboard.cpp
+synergy/CMSWindowsClipboard.h
+synergy/CMSWindowsScreen.cpp
+synergy/CMSWindowsScreen.h
+synergy/CXWindowsClipboard.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/IClipboard.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/synergy.dsp
+
+checkpoint. merging win32 code. server on X is currently broken
+and client probably is.
+
+----------
+2001/11/18 23:14:28 crs
+Makefile
+client/CClient.cpp
+client/CClient.h
+client/CXWindowsSecondaryScreen.cpp
+client/CXWindowsSecondaryScreen.h
+client/Makefile
+client/client.cpp
+server/CScreenMap.cpp
+server/CScreenMap.h
+server/CServer.cpp
+server/CServer.h
+server/CServerProtocol.cpp
+server/CServerProtocol.h
+server/CServerProtocol1_0.cpp
+server/CServerProtocol1_0.h
+server/CXWindowsPrimaryScreen.cpp
+server/CXWindowsPrimaryScreen.h
+server/Makefile
+server/server.cpp
+synergy/CClient.cpp
+synergy/CClient.h
+synergy/CScreenMap.cpp
+synergy/CScreenMap.h
+synergy/CServer.cpp
+synergy/CServer.h
+synergy/CServerProtocol.cpp
+synergy/CServerProtocol.h
+synergy/CServerProtocol1_0.cpp
+synergy/CServerProtocol1_0.h
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsPrimaryScreen.h
+synergy/CXWindowsSecondaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.h
+synergy/Makefile
+synergy/client.cpp
+synergy/server.cpp
+
+moved client and server files into their own respective
+directories.
+
+----------
+2001/11/13 23:34:12 crs
+synergy/CServer.cpp
+synergy/CXWindowsClipboard.cpp
+synergy/CXWindowsClipboard.h
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsPrimaryScreen.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/IClipboard.h
+synergy/IPrimaryScreen.h
+synergy/Makefile
+
+added preliminary support for getting the X selection.
+
+----------
+2001/11/11 21:27:36 crs
+synergy/CServer.cpp
+
+fixed clamping when mapping to a different screen when beyond
+bottom or right of source screen.
+
+----------
+2001/11/11 21:15:30 crs
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsPrimaryScreen.h
+synergy/CXWindowsScreen.cpp
+synergy/CXWindowsScreen.h
+synergy/CXWindowsSecondaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.h
+synergy/Makefile
+
+factored common X windows screen stuff into a common base class.
+
+----------
+2001/11/10 22:28:37 crs
+notes
+
+updated notes.
+
+----------
+2001/11/10 22:28:30 crs
+Makefile
+
+added main app directory to build.
+
+----------
+2001/10/25 22:17:17 crs
+io/CBufferedInputStream.cpp
+mt/CCondVar.cpp
+mt/CMutex.cpp
+mt/CThreadRep.cpp
+net/CNetworkAddress.cpp
+net/CSocketInputStream.cpp
+net/CTCPListenSocket.cpp
+net/CTCPSocket.cpp
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.cpp
+
+removed unnecessary global scoping operators.
+
+----------
+2001/10/25 22:09:27 crs
+synergy/CXWindowsSecondaryScreen.cpp
+
+changed hider window to move underneath mouse when leaving the
+screen. this makes it so if the mouse is moved locally, it'll
+reappear where it was last seen.
+
+----------
+2001/10/25 21:40:29 crs
+synergy/CClient.cpp
+synergy/CXWindowsSecondaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.h
+synergy/ISecondaryScreen.h
+
+changed some method names and removed warpCursor() from
+secondary screen interface.
+
+----------
+2001/10/24 23:29:29 crs
+synergy/CServer.cpp
+synergy/CServer.h
+
+now handling disconnect of secondary screen that has the cursor
+by jumping back to the primary screen (without trying to notify
+the now disconnected secondary screen). also fixed blown assert
+in mapPosition().
+
+----------
+2001/10/24 22:33:24 crs
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsPrimaryScreen.h
+synergy/CXWindowsSecondaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.h
+
+made calls to X thread safe.
+
+----------
+2001/10/23 22:45:59 crs
+notes
+
+more notes.
+
+----------
+2001/10/23 22:41:46 crs
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsPrimaryScreen.h
+synergy/CXWindowsSecondaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.h
+
+added cursor hiding.
+
+----------
+2001/10/23 21:23:29 crs
+base/CLog.cpp
+
+can now filter logging by level.
+
+----------
+2001/10/23 21:13:08 crs
+synergy/CServer.cpp
+
+fixed blown assert trying to find neighbor when there was none.
+
+----------
+2001/10/21 00:21:21 crs
+synergy/CClient.cpp
+
+fixed handling of stream ownership.
+
+----------
+2001/10/21 00:21:02 crs
+io/CBufferedInputStream.cpp
+io/CBufferedOutputStream.cpp
+mt/CThreadRep.cpp
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+synergy/CServer.cpp
+synergy/server.cpp
+
+fixed bugs in handling streams.
+
+----------
+2001/10/20 20:43:31 crs
+Make-linux
+mt/CThreadRep.cpp
+
+threading fixes. had sigmask set in wrong place. was setting
+m_exit flag potentially after the object had been destroyed.
+most importantly, RTTI must be enabled on PPC to avoid SIGILL.
+
+----------
+2001/10/14 19:16:54 crs
+mt/CThread.cpp
+mt/CThreadRep.cpp
+mt/CTimerThread.cpp
+
+some debugging code.
+
+----------
+2001/10/14 18:29:43 crs
+base/CLog.h
+mt/CMutex.cpp
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+mt/CTimerThread.cpp
+synergy/CClient.cpp
+synergy/CClient.h
+synergy/CProtocolUtil.cpp
+synergy/CServerProtocol1_0.cpp
+synergy/client.cpp
+synergy/server.cpp
+
+fixed timeout bug in CThreadRep::wait() (negative timeout wouldn't
+wait forever). also fixed early return from sleep due to signal.
+now forcing client to initialize CThread to ensure global mutex
+gets initialized before threads are used.
+
+----------
+2001/10/14 16:58:01 crs
+io/CBufferedInputStream.cpp
+io/CBufferedInputStream.h
+io/CBufferedOutputStream.cpp
+io/CBufferedOutputStream.h
+io/CInputStreamFilter.cpp
+io/CInputStreamFilter.h
+io/COutputStreamFilter.cpp
+io/COutputStreamFilter.h
+io/CStreamBuffer.cpp
+io/CStreamBuffer.h
+io/IInputStream.h
+io/IOutputStream.h
+mt/CCondVar.cpp
+mt/CCondVar.h
+mt/CLock.cpp
+mt/CLock.h
+mt/CMutex.cpp
+mt/CMutex.h
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/CSocketInputStream.cpp
+net/CSocketInputStream.h
+net/CSocketOutputStream.cpp
+net/CSocketOutputStream.h
+net/CSocketStreamBuffer.cpp
+net/CSocketStreamBuffer.h
+net/CTCPListenSocket.cpp
+net/CTCPListenSocket.h
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+net/IListenSocket.h
+net/ISocket.h
+synergy/CInputPacketStream.cpp
+synergy/CInputPacketStream.h
+synergy/COutputPacketStream.cpp
+synergy/COutputPacketStream.h
+synergy/CProtocolUtil.cpp
+synergy/CProtocolUtil.h
+synergy/CScreenMap.cpp
+synergy/CScreenMap.h
+synergy/CServer.cpp
+synergy/CServer.h
+synergy/CServerProtocol.cpp
+synergy/CServerProtocol.h
+synergy/CServerProtocol1_0.cpp
+synergy/CServerProtocol1_0.h
+synergy/CTCPSocketFactory.cpp
+synergy/CTCPSocketFactory.h
+synergy/IServerProtocol.h
+synergy/ISocketFactory.h
+
+removed exception specifications. thread exceptions weren't
+being listed and they'd have to be added to every one. just
+doesn't seem worth the trouble.
+
+----------
+2001/10/14 14:56:06 crs
+synergy/CProtocolUtil.cpp
+
+stupid bug fixes. writef() used the wrong variable as the number
+of bytes to write. readf() forgot to prepare the va_list.
+
+----------
+2001/10/14 14:38:45 crs
+base/CLog.cpp
+base/CLog.h
+
+forgot to add the logger files.
+
+----------
+2001/10/14 14:37:41 crs
+Make-linux
+base/Makefile
+synergy/CClient.cpp
+synergy/CScreenMap.cpp
+synergy/CScreenMap.h
+synergy/CServer.cpp
+synergy/CServerProtocol1_0.cpp
+synergy/CXWindowsPrimaryScreen.cpp
+
+added logging facility and added a bunch of log messages.
+
+----------
+2001/10/08 19:24:46 crs
+Makefile
+notes
+synergy/CClient.cpp
+synergy/CClient.h
+synergy/CServer.cpp
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.cpp
+synergy/CXWindowsSecondaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/Makefile
+synergy/client.cpp
+synergy/server.cpp
+
+checkpoint. first cut of client and server apps. not tested
+yet but they compile and *should* work as is.
+
+----------
+2001/10/06 14:18:01 crs
+Make-linux
+Makefile
+
+updated old files to new implementation
+
+----------
+2001/10/06 14:13:28 crs
+BasicTypes.h
+CClient.cpp
+CClient.h
+CEvent.h
+CEventQueue.cpp
+CEventQueue.h
+CMessageSocket.cpp
+CMessageSocket.h
+CProtocol.h
+CScreenProxy.cpp
+CScreenProxy.h
+CServer.cpp
+CServer.h
+CSocket.cpp
+CSocket.h
+CSocketFactory.cpp
+CSocketFactory.h
+CString.h
+CTrace.cpp
+CTrace.h
+CUnixEventQueue.cpp
+CUnixEventQueue.h
+CUnixTCPSocket.cpp
+CUnixTCPSocket.h
+CUnixXScreen.cpp
+CUnixXScreen.h
+CXScreen.cpp
+CXScreen.h
+IClient.h
+IClipboard.h
+IEventQueue.h
+IJob.h
+IScreen.h
+IServer.h
+ISocket.h
+KeyTypes.h
+Make-linux
+Make-solaris
+Makecommon
+Makefile
+MouseTypes.h
+TMethodJob.h
+XBase.cpp
+XBase.h
+XSocket.h
+base/BasicTypes.h
+base/CFunctionJob.cpp
+base/CFunctionJob.h
+base/CStopwatch.cpp
+base/CStopwatch.h
+base/CString.h
+base/IInterface.h
+base/IJob.h
+base/Makefile
+base/TMethodJob.h
+base/XBase.cpp
+base/XBase.h
+base/common.h
+io/CBufferedInputStream.cpp
+io/CBufferedInputStream.h
+io/CBufferedOutputStream.cpp
+io/CBufferedOutputStream.h
+io/CInputStreamFilter.cpp
+io/CInputStreamFilter.h
+io/COutputStreamFilter.cpp
+io/COutputStreamFilter.h
+io/CStreamBuffer.cpp
+io/CStreamBuffer.h
+io/IInputStream.h
+io/IOutputStream.h
+io/Makefile
+io/XIO.cpp
+io/XIO.h
+main.cpp
+mt/CCondVar.cpp
+mt/CCondVar.h
+mt/CLock.cpp
+mt/CLock.h
+mt/CMutex.cpp
+mt/CMutex.h
+mt/CThread.cpp
+mt/CThread.h
+mt/CThreadRep.cpp
+mt/CThreadRep.h
+mt/CTimerThread.cpp
+mt/CTimerThread.h
+mt/Makefile
+mt/XThread.h
+net/CNetworkAddress.cpp
+net/CNetworkAddress.h
+net/CSocketInputStream.cpp
+net/CSocketInputStream.h
+net/CSocketOutputStream.cpp
+net/CSocketOutputStream.h
+net/CSocketStreamBuffer.cpp
+net/CSocketStreamBuffer.h
+net/CTCPListenSocket.cpp
+net/CTCPListenSocket.h
+net/CTCPSocket.cpp
+net/CTCPSocket.h
+net/IListenSocket.h
+net/ISocket.h
+net/Makefile
+net/XSocket.cpp
+net/XSocket.h
+notes
+synergy/CClient.cpp
+synergy/CClient.h
+synergy/CInputPacketStream.cpp
+synergy/CInputPacketStream.h
+synergy/COutputPacketStream.cpp
+synergy/COutputPacketStream.h
+synergy/CProtocolUtil.cpp
+synergy/CProtocolUtil.h
+synergy/CScreenMap.cpp
+synergy/CScreenMap.h
+synergy/CServer.cpp
+synergy/CServer.h
+synergy/CServerProtocol.cpp
+synergy/CServerProtocol.h
+synergy/CServerProtocol1_0.cpp
+synergy/CServerProtocol1_0.h
+synergy/CTCPSocketFactory.cpp
+synergy/CTCPSocketFactory.h
+synergy/CXWindowsPrimaryScreen.cpp
+synergy/CXWindowsPrimaryScreen.h
+synergy/IPrimaryScreen.h
+synergy/ISecondaryScreen.h
+synergy/IServerProtocol.h
+synergy/ISocketFactory.h
+synergy/KeyTypes.h
+synergy/Makefile
+synergy/MouseTypes.h
+synergy/ProtocolTypes.h
+synergy/XSynergy.cpp
+synergy/XSynergy.h
+test.cpp
+
+Started over.
+
+----------
+2001/05/14 21:14:49 crs
+MouseTypes.h
+
+flipped order of buttons to match default X setup.
+
+----------
+2001/05/14 21:14:25 crs
+CClient.cpp
+CEvent.h
+CScreenProxy.cpp
+CScreenProxy.h
+CServer.cpp
+CXScreen.cpp
+CXScreen.h
+IScreen.h
+KeyTypes.h
+
+added other mouse and key event handling to CXScreen. key repeat
+isn't implemented and modifier masks are ignored. modifier masks
+are new; they indicate the modifier key (shift, ctrl, etc) state
+at the time of the key event.
+
+----------
+2001/05/13 12:43:16 crs
+CUnixTCPSocket.cpp
+CUnixTCPSocket.h
+
+more fixes to reduce latency. nagle agorithm doesn't seem to
+stay off on a socket on linux because a connection clearly
+doesn't send data as often as possible. will have to implement
+a UDP socket to reduce overhead and avoid these delays. wanted
+to do that anyway.
+
+----------
+2001/05/13 12:21:11 crs
+CUnixTCPSocket.cpp
+CXScreen.cpp
+
+fixes to avoid update delays.
+
+----------
+2001/05/13 12:07:32 crs
+CMessageSocket.cpp
+
+fixed bug in read() that miscalculated the message length.
+
+----------
+2001/05/13 11:40:29 crs
+BasicTypes.h
+CClient.cpp
+CClient.h
+CEvent.h
+CEventQueue.cpp
+CEventQueue.h
+CMessageSocket.cpp
+CMessageSocket.h
+CProtocol.h
+CScreenProxy.cpp
+CScreenProxy.h
+CServer.cpp
+CServer.h
+CSocket.cpp
+CSocket.h
+CSocketFactory.cpp
+CSocketFactory.h
+CString.h
+CTrace.cpp
+CTrace.h
+CUnixEventQueue.cpp
+CUnixEventQueue.h
+CUnixTCPSocket.cpp
+CUnixTCPSocket.h
+CUnixXScreen.cpp
+CUnixXScreen.h
+CXScreen.cpp
+CXScreen.h
+IClient.h
+IClipboard.h
+IEventQueue.h
+IJob.h
+IScreen.h
+IServer.h
+ISocket.h
+KeyTypes.h
+Make-linux
+Makefile
+MouseTypes.h
+TMethodJob.h
+XBase.cpp
+XBase.h
+XSocket.h
+main.cpp
+tools/depconv
+
+initial revision of synergy. currently semi-supports X windows
+on unix, but client screens don't simulate events other than
+mouse move. also not supporting clipboard at all yet and the
+main app is just a temporary framework to test with. must
+clean up protocol and communication.
+
+----------
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..7262d958
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1 @@
+See doc/compiling.html.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 00000000..26a5086f
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,97 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+SUBDIRS = \
+ lib \
+ cmd \
+ doc \
+ dist \
+ $(NULL)
+
+EXTRA_DIST = \
+ Makefile.win \
+ examples/synergy.conf \
+ win32util/autodep.cpp \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ aclocal.m4 \
+ config.h \
+ config.h.in \
+ config.log \
+ config.status \
+ configure \
+ stamp-h.in \
+ stamp-h1 \
+ $(NULL)
+
+PKG_FILES = \
+ ChangeLog \
+ README \
+ cmd/synergyc/synergyc \
+ cmd/synergys/synergys \
+ examples/synergy.conf \
+ $(NULL)
+PKG_DOC_FILES = \
+ doc/PORTING \
+ doc/*.html \
+ doc/*.css \
+ $(NULL)
+PKG_PROG_FILES = \
+ synergyc \
+ synergys \
+ $(NULL)
+
+# build doxygen documentation
+doxygen:
+ doxygen doc/doxygen.cfg
+
+# build RPMs
+RPMTOPDIR=/var/tmp/@PACKAGE@-@VERSION@
+dist-rpm: dist
+ rm -rf $(RPMTOPDIR)
+ mkdir $(RPMTOPDIR)
+ (cd $(RPMTOPDIR); mkdir BUILD SOURCES SPECS SRPMS RPMS)
+ cp @PACKAGE@-@VERSION@.tar.gz $(RPMTOPDIR)/SOURCES
+ rpm --define '_topdir $(RPMTOPDIR)' -ba dist/rpm/synergy.spec && \
+ mv -f $(RPMTOPDIR)/SRPMS/*.rpm . && \
+ mv -f $(RPMTOPDIR)/RPMS/*/*.rpm . && \
+ rm -rf $(RPMTOPDIR)
+
+# build zip
+# FIXME -- have automake generate this rule for us
+dist-zip: distdir
+ zip -r $(distdir).zip $(distdir)
+ -chmod -R a+w $(distdir) >/dev/null 2>&1; rm -rf $(distdir)
+
+# build binary package. owner/group of packaged files will be
+# owner/group of user running make.
+PKGTOPDIR=/var/tmp/@PACKAGE@-@VERSION@
+dist-pkg: all
+ rm -rf $(PKGTOPDIR)
+ mkdir $(PKGTOPDIR)
+ mkdir $(PKGTOPDIR)/@PACKAGE@-@VERSION@
+ mkdir $(PKGTOPDIR)/@PACKAGE@-@VERSION@/doc
+ cp $(PKG_FILES) $(PKGTOPDIR)/@PACKAGE@-@VERSION@
+ cp $(PKG_DOC_FILES) $(PKGTOPDIR)/@PACKAGE@-@VERSION@/doc
+ (cd $(PKGTOPDIR)/@PACKAGE@-@VERSION@; \
+ chmod 644 *; \
+ chmod 755 doc $(PKG_PROG_FILES); \
+ strip $(PKG_PROG_FILES) )
+ type=`uname -s -m | tr '[A-Z] ' '[a-z].'`; \
+ (cd $(PKGTOPDIR); tar cf - @PACKAGE@-@VERSION@ | \
+ gzip - ) > @PACKAGE@-@VERSION@-1.$${type}.tar.gz && \
+ rm -rf $(PKGTOPDIR)
diff --git a/Makefile.win b/Makefile.win
new file mode 100644
index 00000000..d232b58a
--- /dev/null
+++ b/Makefile.win
@@ -0,0 +1,145 @@
+# synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2007 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.
+
+# Name of this file for recursive make
+MAKEFILE = Makefile.win
+
+# Default build is release is NODEBUG is defined, debug otherwise.
+!if !DEFINED(DEBUG)
+NODEBUG = 1
+!else
+!undef NODEBUG
+!endif
+
+# Build all by default
+default: all
+
+# Redefine implicit rule suffixes
+.SUFFIXES:
+.SUFFIXES: .cpp .rc .obj
+
+# Shut up
+.SILENT:
+
+# Include system macros
+#APPVER = 5.0
+#TARGETOS = WINNT
+!include
+
+# Be explicit about C++ compiler
+cpp = $(cc)
+cppdebug = $(cdebug)
+cppflags = $(cflags)
+cppvarsmt = $(cvarsmt)
+
+# Library tool options
+ildebug =
+ilflags = /nologo
+
+# Handy macro for defining list macros
+NULL =
+
+# System commands
+ECHO = echo
+MKDIR = mkdir
+RM = del /f
+RMR = rmdir /q /s
+
+# Local build utilities
+UTIL_DIR = win32util
+AUTODEP = "$(UTIL_DIR)\autodep.exe"
+
+# Destination for intermediate build targets
+BUILD_DIR = build
+BUILD_DEBUG_DIR = $(BUILD_DIR)\Debug
+BUILD_RELEASE_DIR = $(BUILD_DIR)\Release
+!if DEFINED(NODEBUG)
+BUILD_DST = $(BUILD_RELEASE_DIR)
+!else
+BUILD_DST = $(BUILD_DEBUG_DIR)
+!endif
+
+# Compiler argument changes
+cflags = $(cflags:-W3=-W4) /WX
+cflags = $(cflags) -D_CRT_SECURE_NO_DEPRECATE
+cflags = $(cflags) /GR
+!if !DEFINED(OLDCOMPILER)
+cflags = $(cflags) /EHsc
+!else
+cflags = $(cflags) /GX
+!endif
+!if !DEFINED(NODEBUG)
+!if !DEFINED(OLDCOMPILER)
+cdebug = $(cdebug) /RTC1
+!else
+cdebug = $(cdebug) /GZ
+!endif
+!endif
+
+# Initialize variables for library and program makefiles
+C_FILES =
+CPP_FILES =
+OBJ_FILES =
+LIB_FILES =
+PROGRAMS =
+OPTPROGRAMS = $(AUTODEP)
+
+# Include subdirectory makefiles
+!include lib\common\$(MAKEFILE)
+!include lib\arch\$(MAKEFILE)
+!include lib\base\$(MAKEFILE)
+!include lib\mt\$(MAKEFILE)
+!include lib\io\$(MAKEFILE)
+!include lib\net\$(MAKEFILE)
+!include lib\synergy\$(MAKEFILE)
+!include lib\platform\$(MAKEFILE)
+!include lib\client\$(MAKEFILE)
+!include lib\server\$(MAKEFILE)
+!include cmd\synergyc\$(MAKEFILE)
+!include cmd\synergys\$(MAKEFILE)
+!include cmd\launcher\$(MAKEFILE)
+!include dist\nullsoft\$(MAKEFILE)
+
+# Collect library and program variables
+INTERMEDIATES = $(OBJ_FILES) $(AUTODEP:.exe=.obj)
+TARGETS = $(LIB_FILES) $(PROGRAMS)
+OPTTARGETS = $(OPTPROGRAMS)
+
+# Build release by reinvoking make with NODEBUG defined
+release:
+ @$(MAKE) /nologo /f $(MAKEFILE) NODEBUG=1
+
+# Build debug by reinvoking make with DEBUG defined
+debug:
+ @$(MAKE) /nologo /f $(MAKEFILE) DEBUG=1
+
+# Build all targets
+all: $(TARGETS)
+
+# Clean intermediate targets
+clean:
+ -$(RMR) $(BUILD_DEBUG_DIR)
+ -$(RMR) $(BUILD_RELEASE_DIR)
+
+# Clean all targets
+clobber: clean
+ -$(RMR) $(BUILD_DIR)
+
+# Utility command build rules
+$(AUTODEP): $(AUTODEP:.exe=.cpp)
+!if DEFINED(NODEBUG)
+ @$(ECHO) Build $(@F)
+ $(cpp) $(cppdebug) $(cppflags) $(cppvars) /Fo"$(**:.cpp=.obj)" $**
+ $(link) $(ldebug) $(conflags) -out:$@ $(**:.cpp=.obj) $(conlibs)
+!else
+ @$(MAKE) /nologo /f $(MAKEFILE) NODEBUG=1 $@
+!endif
diff --git a/NEWS b/NEWS
new file mode 100644
index 00000000..e9aa7916
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+See doc/news.html.
diff --git a/README b/README
new file mode 100644
index 00000000..aa6d7ea3
--- /dev/null
+++ b/README
@@ -0,0 +1,21 @@
+Synergy
+=======
+
+synergy: [noun] a mutually advantageous conjunction of distinct elements
+
+Synergy lets you easily share a single mouse and keyboard between
+multiple computers with different operating systems, each with its
+own display, without special hardware. It's intended for users
+with multiple computers on their desk since each system uses its
+own display.
+
+Redirecting the mouse and keyboard is as simple as moving the mouse
+off the edge of your screen. Synergy also merges the clipboards of
+all the systems into one, allowing cut-and-paste between systems.
+Furthermore, it synchronizes screen savers so they all start and stop
+together and, if screen locking is enabled, only one screen requires
+a password to unlock them all.
+
+Synergy is open source and released under the GNU Public License (GPL).
+
+Please see doc/index.html for more information.
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 00000000..29163d5a
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,571 @@
+dnl synergy -- mouse and keyboard sharing utility
+dnl Copyright (C) 2002 Chris Schoeneman
+dnl
+dnl This package is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU General Public License
+dnl found in the file COPYING that should have accompanied this file.
+dnl
+dnl This package is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+
+AC_DEFUN([ACX_CHECK_SOCKLEN_T], [
+ AC_MSG_CHECKING([for socklen_t])
+ AC_TRY_COMPILE([
+ #include
+ #include
+ ],
+ [socklen_t len;],[acx_socklen_t_ok=yes],[acx_socklen_t_ok=no])
+ AC_MSG_RESULT($acx_socklen_t_ok)
+ if test x"$acx_socklen_t_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_SOCKLEN_T,1,[Define if your compiler defines socklen_t.]),[$1])
+ :
+ else
+ acx_socklen_t_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_SOCKLEN_T
+
+# HP-UX defines socklen_t but doesn't use it in arg 3 for accept().
+AC_DEFUN([ACX_FUNC_ACCEPT], [
+ AC_MSG_CHECKING([for type of arg 3 for accept])
+ acx_accept_socklen_t_arg3=int
+ if test x"$acx_socklen_t_ok" = xyes; then
+ AC_TRY_COMPILE([
+ #include
+ #include
+ ],
+ [struct sockaddr addr; socklen_t len; accept(0, &addr, &len);],
+ [acx_accept_socklen_t_arg3=socklen_t],
+ [acx_accept_socklen_t_arg3=int])
+ fi
+ AC_MSG_RESULT($acx_accept_socklen_t_arg3)
+ AC_DEFINE_UNQUOTED(ACCEPT_TYPE_ARG3,$acx_accept_socklen_t_arg3,[Define to the base type of arg 3 for `accept'.])
+])dnl ACX_FUNC_ACCEPT
+
+AC_DEFUN([ACX_CHECK_CXX], [
+ AC_MSG_CHECKING([if g++ defines correct C++ macro])
+ AC_TRY_COMPILE(, [
+ #if defined(_LANGUAGE_C) && !defined(_LANGUAGE_C_PLUS_PLUS)
+ #error wrong macro
+ #endif],[acx_cxx_macro_ok=yes],[acx_cxx_macro_ok=no])
+ AC_MSG_RESULT($acx_cxx_macro_ok)
+ if test x"$acx_cxx_macro_ok" = xyes; then
+ SYNERGY_CXXFLAGS=""
+ else
+ SYNERGY_CXXFLAGS="-U_LANGUAGE_C -D_LANGUAGE_C_PLUS_PLUS"
+ fi
+])dnl ACX_CHECK_CXX
+
+AC_DEFUN([ACX_CHECK_CXX_BOOL], [
+ AC_MSG_CHECKING([for bool support])
+ AC_TRY_COMPILE(, [bool t = true, f = false;],
+ [acx_cxx_bool_ok=yes],[acx_cxx_bool_ok=no])
+ AC_MSG_RESULT($acx_cxx_bool_ok)
+ if test x"$acx_cxx_bool_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_CXX_BOOL,1,[Define if your compiler has bool support.]),[$1])
+ :
+ else
+ acx_cxx_bool_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_CXX_BOOL
+
+AC_DEFUN([ACX_CHECK_CXX_EXCEPTIONS], [
+ AC_MSG_CHECKING([for exception support])
+ AC_TRY_COMPILE(, [try{throw int(4);}catch(int){throw;}catch(...){}],
+ [acx_cxx_exception_ok=yes],[acx_cxx_exception_ok=no])
+ AC_MSG_RESULT($acx_cxx_exception_ok)
+ if test x"$acx_cxx_exception_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_CXX_EXCEPTIONS,1,[Define if your compiler has exceptions support.]),[$1])
+ :
+ else
+ acx_cxx_exception_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_CXX_EXCEPTIONS
+
+AC_DEFUN([ACX_CHECK_CXX_CASTS], [
+ AC_MSG_CHECKING([for C++ cast support])
+ AC_TRY_COMPILE(, [const char* f="a";const_cast(f);
+ reinterpret_cast(f);static_cast(4.5);],
+ [acx_cxx_cast_ok=yes],[acx_cxx_cast_ok=no])
+ AC_MSG_RESULT($acx_cxx_cast_ok)
+ if test x"$acx_cxx_cast_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_CXX_CASTS,1,[Define if your compiler has C++ cast support.]),[$1])
+ :
+ else
+ acx_cxx_cast_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_CXX_CASTS
+
+AC_DEFUN([ACX_CHECK_CXX_MUTABLE], [
+ AC_MSG_CHECKING([for mutable support])
+ AC_TRY_COMPILE(, [struct A{mutable int b;void f() const {b=0;}};
+ A a;a.f();],[acx_cxx_mutable_ok=yes],[acx_cxx_mutable_ok=no])
+ AC_MSG_RESULT($acx_cxx_mutable_ok)
+ if test x"$acx_cxx_mutable_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_CXX_MUTABLE,1,[Define if your compiler has mutable support.]),[$1])
+ :
+ else
+ acx_cxx_mutable_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_CXX_MUTABLE
+
+AC_DEFUN([ACX_CHECK_CXX_STDLIB], [
+ AC_MSG_CHECKING([for C++ standard library])
+ AC_TRY_LINK([#include ], [std::set a; a.insert(3);],
+ [acx_cxx_stdlib_ok=yes],[acx_cxx_stdlib_ok=no])
+ AC_MSG_RESULT($acx_cxx_stdlib_ok)
+ if test x"$acx_cxx_stdlib_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_CXX_STDLIB,1,[Define if your compiler has standard C++ library support.]),[$1])
+ :
+ else
+ acx_cxx_stdlib_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_CXX_STDLIB
+
+AC_DEFUN([ACX_CHECK_GETPWUID_R], [
+ AC_MSG_CHECKING([for working getpwuid_r])
+ AC_TRY_LINK([#include ],
+ [char buffer[4096]; struct passwd pwd, *pwdp;
+ getpwuid_r(0, &pwd, buffer, sizeof(buffer), &pwdp);],
+ acx_getpwuid_r_ok=yes, acx_getpwuid_r_ok=no)
+ AC_MSG_RESULT($acx_getpwuid_r_ok)
+ if test x"$acx_getpwuid_r_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_GETPWUID_R,1,[Define if you have a working \`getpwuid_r\' function.]),[$1])
+ :
+ else
+ acx_getpwuid_r_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_GETPWUID_R
+
+AC_DEFUN([ACX_CHECK_POLL], [
+ AC_MSG_CHECKING([for poll])
+ AC_TRY_LINK([#include ],
+ [#if defined(_POLL_EMUL_H_)
+ #error emulated poll
+ #endif
+ struct pollfd ufds[] = { 0, POLLIN, 0 }; poll(ufds, 1, 10);],
+ acx_poll_ok=yes, acx_poll_ok=no)
+ AC_MSG_RESULT($acx_poll_ok)
+ if test x"$acx_poll_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_POLL,1,[Define if you have the \`poll\' function.]),[$1])
+ :
+ else
+ acx_poll_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_POLL
+
+dnl See if we need extra libraries for nanosleep
+AC_DEFUN([ACX_CHECK_NANOSLEEP], [
+ acx_nanosleep_ok=no
+ acx_nanosleep_list=""
+
+ dnl check if user has set NANOSLEEP_LIBS
+ save_user_NANOSLEEP_LIBS="$NANOSLEEP_LIBS"
+ if test x"$NANOSLEEP_LIBS" != x; then
+ acx_nanosleep_list=user
+ fi
+
+ dnl check various libraries (including no extra libraries) for
+ dnl nanosleep. `none' should appear first.
+ acx_nanosleep_list="none $acx_nanosleep_list rt"
+ for flag in $acx_nanosleep_list; do
+ case $flag in
+ none)
+ AC_MSG_CHECKING([for nanosleep])
+ NANOSLEEP_LIBS=""
+ ;;
+
+ user)
+ AC_MSG_CHECKING([for nanosleep in $save_user_NANOSLEEP_LIBS])
+ NANOSLEEP_LIBS="$save_user_NANOSLEEP_LIBS"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for nanosleep in -l$flag])
+ NANOSLEEP_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ LIBS="$NANOSLEEP_LIBS $LIBS"
+ AC_TRY_LINK([#include ],
+ [struct timespec t = { 1, 1000 }; nanosleep(&t, NULL);],
+ acx_nanosleep_ok=yes, acx_nanosleep_ok=no)
+ LIBS="$save_LIBS"
+ AC_MSG_RESULT($acx_nanosleep_ok)
+ if test x"$acx_nanosleep_ok" = xyes; then
+ break;
+ fi
+ NANOSLEEP_LIBS=""
+ done
+
+ AC_SUBST(NANOSLEEP_LIBS)
+
+ # execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+ if test x"$acx_nanosleep_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_NANOSLEEP,1,[Define if you have the \`nanosleep\' function.]),[$1])
+ :
+ else
+ acx_nanosleep_ok=no
+ $2
+ fi
+])dnl ACX_CHECK_NANOSLEEP
+
+dnl See if we need extra libraries for inet_aton
+AC_DEFUN([ACX_CHECK_INET_ATON], [
+ acx_inet_aton_ok=no
+ acx_inet_aton_list=""
+
+ dnl check if user has set INET_ATON_LIBS
+ save_user_INET_ATON_LIBS="$INET_ATON_LIBS"
+ if test x"$INET_ATON_LIBS" != x; then
+ acx_inet_aton_list=user
+ fi
+
+ dnl check various libraries (including no extra libraries) for
+ dnl inet_aton. `none' should appear first.
+ acx_inet_aton_list="none $acx_inet_aton_list resolv"
+ for flag in $acx_inet_aton_list; do
+ case $flag in
+ none)
+ AC_MSG_CHECKING([for inet_aton])
+ INET_ATON_LIBS=""
+ ;;
+
+ user)
+ AC_MSG_CHECKING([for inet_aton in $save_user_INET_ATON_LIBS])
+ INET_ATON_LIBS="$save_user_INET_ATON_LIBS"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for inet_aton in -l$flag])
+ INET_ATON_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ LIBS="$INET_ATON_LIBS $LIBS"
+ AC_TRY_LINK([#include
+ #include
+ #include
+ #include ],
+ [struct in_addr addr; inet_aton("foo.bar", &addr);],
+ acx_inet_aton_ok=yes, acx_inet_aton_ok=no)
+ LIBS="$save_LIBS"
+ AC_MSG_RESULT($acx_inet_aton_ok)
+ if test x"$acx_inet_aton_ok" = xyes; then
+ AC_DEFINE(HAVE_INET_ATON,1,[Define if you have the \`inet_aton\' function.])
+ break;
+ fi
+ INET_ATON_LIBS=""
+ done
+
+ AC_SUBST(INET_ATON_LIBS)
+])dnl ACX_CHECK_INET_ATON
+
+dnl The following macros are from http://www.gnu.org/software/ac-archive/
+dnl which distributes them under the following license:
+dnl
+dnl Every Autoconf macro presented on this web site is free software; you can
+dnl redistribute it and/or modify it under the terms of the GNU General
+dnl Public License as published by the Free Software Foundation; either
+dnl version 2, or (at your option) any later version.
+dnl
+dnl They are distributed in the hope that they will be useful, but WITHOUT
+dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+dnl more details. (You should have received a copy of the GNU General Public
+dnl License along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place -- Suite 330, Boston, MA 02111-1307,
+dnl USA.)
+dnl
+dnl As a special exception, the Free Software Foundation gives unlimited
+dnl permission to copy, distribute and modify the configure scripts that are
+dnl the output of Autoconf. You need not follow the terms of the GNU General
+dnl Public License when using or distributing such scripts, even though
+dnl portions of the text of Autoconf appear in them. The GNU General Public
+dnl License (GPL) does govern all other use of the material that constitutes
+dnl the Autoconf program.
+dnl
+dnl Certain portions of the Autoconf source text are designed to be copied
+dnl (in certain cases, depending on the input) into the output of Autoconf.
+dnl We call these the "data" portions. The rest of the Autoconf source text
+dnl consists of comments plus executable code that decides which of the data
+dnl portions to output in any given case. We call these comments and
+dnl executable code the "non-data" portions. Autoconf never copies any of the
+dnl non-data portions into its output.
+dnl
+dnl This special exception to the GPL applies to versions of Autoconf
+dnl released by the Free Software Foundation. When you make and distribute a
+dnl modified version of Autoconf, you may extend this special exception to
+dnl the GPL to apply to your modified version as well, *unless* your modified
+dnl version has the potential to copy into its output some of the text that
+dnl was the non-data portion of the version that you started with. (In other
+dnl words, unless your change moves or copies text from the non-data portions
+dnl to the data portions.) If your modification has such potential, you must
+dnl delete any notice of this special exception to the GPL from your modified
+dnl version
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthread or
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include ],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include ], [int attr=$attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ # Detect POSIX sigwait()
+ AC_MSG_CHECKING([for POSIX sigwait])
+ AC_TRY_LINK([#include
+ #include ],
+ [sigset_t sigset; int signal; sigwait(&sigset, &signal);],
+ ok=yes, ok=unknown)
+ if test x"$ok" = xunknown; then
+ save_CFLAGS2="$CFLAGS"
+ CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS"
+ AC_TRY_LINK([#include
+ #include ],
+ [sigset_t sigset; int signal; sigwait(&sigset, &signal);],
+ ok=-D_POSIX_PTHREAD_SEMANTICS, ok=no)
+ CFLAGS="$save_CFLAGS2"
+ fi
+ AC_MSG_RESULT(${ok})
+ if test x"$ok" != xno; then
+ AC_DEFINE(HAVE_POSIX_SIGWAIT,1,[Define if you have a POSIX \`sigwait\' function.])
+ if test x"$ok" != xyes; then
+ PTHREAD_CFLAGS="$ok $PTHREAD_CFLAGS"
+ fi
+ fi
+
+ # Detect pthread signal functions
+ AC_MSG_CHECKING([for pthread signal functions])
+ AC_TRY_LINK([#include
+ #include ],
+ [pthread_kill(pthread_self(), SIGTERM);],
+ ok=yes, ok=no)
+ AC_MSG_RESULT(${ok})
+ if test x"$ok" = xyes; then
+ AC_DEFINE(HAVE_PTHREAD_SIGNAL,1,[Define if you have \`pthread_sigmask\' and \`pthread_kill\' functions.])
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with cc_r
+ AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
+
+dnl enable maximum compiler warnings. must ignore unknown pragmas to
+dnl build on solaris.
+dnl we only know how to do this for g++
+AC_DEFUN([ACX_CXX_WARNINGS], [
+ AC_MSG_CHECKING([for C++ compiler warning flags])
+ if test "$GXX" = "yes"; then
+ acx_cxx_warnings="-Wall -Wno-unknown-pragmas"
+ fi
+ if test -n "$acx_cxx_warnings"; then
+ CXXFLAGS="$CXXFLAGS $acx_cxx_warnings"
+ else
+ acx_cxx_warnings="unknown"
+ fi
+ AC_MSG_RESULT($acx_cxx_warnings)
+])dnl ACX_CXX_WARNINGS
+
+dnl enable compiler warnings are errors
+dnl we only know how to do this for g++
+AC_DEFUN([ACX_CXX_WARNINGS_ARE_ERRORS], [
+ AC_MSG_CHECKING([for C++ compiler warning are errors flags])
+ if test "$GXX" = "yes"; then
+ acx_cxx_warnings_are_errors="-Werror"
+ fi
+ if test -n "$acx_cxx_warnings_are_errors"; then
+ CXXFLAGS="$CXXFLAGS $acx_cxx_warnings_are_errors"
+ else
+ acx_cxx_warnings_are_errors="unknown"
+ fi
+ AC_MSG_RESULT($acx_cxx_warnings_are_errors)
+])dnl ACX_CXX_WARNINGS_ARE_ERRORS
diff --git a/cmd/Makefile.am b/cmd/Makefile.am
new file mode 100644
index 00000000..1e43b156
--- /dev/null
+++ b/cmd/Makefile.am
@@ -0,0 +1,27 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+SUBDIRS = \
+ launcher \
+ synergyc \
+ synergys \
+ $(NULL)
+
+EXTRA_DIST = \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
diff --git a/cmd/launcher/CAddScreen.cpp b/cmd/launcher/CAddScreen.cpp
new file mode 100644
index 00000000..5a876b77
--- /dev/null
+++ b/cmd/launcher/CAddScreen.cpp
@@ -0,0 +1,427 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CConfig.h"
+#include "KeyTypes.h"
+#include "OptionTypes.h"
+#include "ProtocolTypes.h"
+#include "CStringUtil.h"
+#include "CArch.h"
+#include "CAddScreen.h"
+#include "LaunchUtil.h"
+#include "resource.h"
+
+struct CModifierInfo {
+public:
+ int m_ctrlID;
+ const char* m_name;
+ KeyModifierID m_modifierID;
+ OptionID m_optionID;
+};
+
+static const CModifierInfo s_modifiers[] = {
+ { IDC_ADD_MOD_SHIFT, "Shift",
+ kKeyModifierIDShift, kOptionModifierMapForShift },
+ { IDC_ADD_MOD_CTRL, "Ctrl",
+ kKeyModifierIDControl, kOptionModifierMapForControl },
+ { IDC_ADD_MOD_ALT, "Alt",
+ kKeyModifierIDAlt, kOptionModifierMapForAlt },
+ { IDC_ADD_MOD_META, "Meta",
+ kKeyModifierIDMeta, kOptionModifierMapForMeta },
+ { IDC_ADD_MOD_SUPER, "Super",
+ kKeyModifierIDSuper, kOptionModifierMapForSuper }
+};
+
+static const KeyModifierID baseModifier = kKeyModifierIDShift;
+
+//
+// CAddScreen
+//
+
+CAddScreen* CAddScreen::s_singleton = NULL;
+
+CAddScreen::CAddScreen(HWND parent, CConfig* config, const CString& name) :
+ m_parent(parent),
+ m_config(config),
+ m_name(name)
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+}
+
+CAddScreen::~CAddScreen()
+{
+ s_singleton = NULL;
+}
+
+bool
+CAddScreen::doModal()
+{
+ // do dialog
+ return (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this) != 0);
+}
+
+CString
+CAddScreen::getName() const
+{
+ return m_name;
+}
+
+void
+CAddScreen::init(HWND hwnd)
+{
+ // set title
+ CString title;
+ if (m_name.empty()) {
+ title = getString(IDS_ADD_SCREEN);
+ }
+ else {
+ title = CStringUtil::format(
+ getString(IDS_EDIT_SCREEN).c_str(),
+ m_name.c_str());
+ }
+ SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)title.c_str());
+
+ // fill in screen name
+ HWND child = getItem(hwnd, IDC_ADD_SCREEN_NAME_EDIT);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)m_name.c_str());
+
+ // fill in aliases
+ CString aliases;
+ for (CConfig::all_const_iterator index = m_config->beginAll();
+ index != m_config->endAll(); ++index) {
+ if (CStringUtil::CaselessCmp::equal(index->second, m_name) &&
+ !CStringUtil::CaselessCmp::equal(index->second, index->first)) {
+ if (!aliases.empty()) {
+ aliases += "\r\n";
+ }
+ aliases += index->first;
+ }
+ }
+ child = getItem(hwnd, IDC_ADD_ALIASES_EDIT);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)aliases.c_str());
+
+ // set options
+ CConfig::CScreenOptions options;
+ getOptions(options);
+ CConfig::CScreenOptions::const_iterator index;
+ child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
+ index = options.find(kOptionHalfDuplexCapsLock);
+ setItemChecked(child, (index != options.end() && index->second != 0));
+ child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
+ index = options.find(kOptionHalfDuplexNumLock);
+ setItemChecked(child, (index != options.end() && index->second != 0));
+ child = getItem(hwnd, IDC_ADD_HD_SCROLL_CHECK);
+ index = options.find(kOptionHalfDuplexScrollLock);
+ setItemChecked(child, (index != options.end() && index->second != 0));
+
+ // modifier options
+ for (UInt32 i = 0; i < sizeof(s_modifiers) /
+ sizeof(s_modifiers[0]); ++i) {
+ child = getItem(hwnd, s_modifiers[i].m_ctrlID);
+
+ // fill in options
+ for (UInt32 j = 0; j < sizeof(s_modifiers) /
+ sizeof(s_modifiers[0]); ++j) {
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)s_modifiers[j].m_name);
+ }
+
+ // choose current value
+ index = options.find(s_modifiers[i].m_optionID);
+ KeyModifierID id = s_modifiers[i].m_modifierID;
+ if (index != options.end()) {
+ id = index->second;
+ }
+ SendMessage(child, CB_SETCURSEL, id - baseModifier, 0);
+ }
+
+ // dead corners
+ UInt32 corners = 0;
+ index = options.find(kOptionScreenSwitchCorners);
+ if (index != options.end()) {
+ corners = index->second;
+ }
+ child = getItem(hwnd, IDC_ADD_DC_TOP_LEFT);
+ setItemChecked(child, (corners & kTopLeftMask) != 0);
+ child = getItem(hwnd, IDC_ADD_DC_TOP_RIGHT);
+ setItemChecked(child, (corners & kTopRightMask) != 0);
+ child = getItem(hwnd, IDC_ADD_DC_BOTTOM_LEFT);
+ setItemChecked(child, (corners & kBottomLeftMask) != 0);
+ child = getItem(hwnd, IDC_ADD_DC_BOTTOM_RIGHT);
+ setItemChecked(child, (corners & kBottomRightMask) != 0);
+ index = options.find(kOptionScreenSwitchCornerSize);
+ SInt32 size = 0;
+ if (index != options.end()) {
+ size = index->second;
+ }
+ char buffer[20];
+ sprintf(buffer, "%d", size);
+ child = getItem(hwnd, IDC_ADD_DC_SIZE);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
+}
+
+bool
+CAddScreen::save(HWND hwnd)
+{
+ // get the old aliases and options
+ CStringList oldAliases;
+ getAliases(oldAliases);
+ CConfig::CScreenOptions options;
+ getOptions(options);
+
+ // extract name and aliases
+ CString newName;
+ HWND child = getItem(hwnd, IDC_ADD_SCREEN_NAME_EDIT);
+ newName = getWindowText(child);
+ CStringList newAliases;
+ child = getItem(hwnd, IDC_ADD_ALIASES_EDIT);
+ tokenize(newAliases, getWindowText(child));
+
+ // name must be valid
+ if (!m_config->isValidScreenName(newName)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_SCREEN_NAME).c_str(),
+ newName.c_str()));
+ return false;
+ }
+
+ // aliases must be valid
+ for (CStringList::const_iterator index = newAliases.begin();
+ index != newAliases.end(); ++index) {
+ if (!m_config->isValidScreenName(*index)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_SCREEN_NAME).c_str(),
+ index->c_str()));
+ return false;
+ }
+ }
+
+ // new name may not be in the new alias list
+ if (isNameInList(newAliases, newName)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_SCREEN_NAME_IS_ALIAS).c_str(),
+ newName.c_str()));
+ return false;
+ }
+
+ // name must not exist in config but allow same name. also
+ // allow name if it exists in the old alias list but not the
+ // new one.
+ if (m_config->isScreen(newName) &&
+ !CStringUtil::CaselessCmp::equal(newName, m_name) &&
+ !isNameInList(oldAliases, newName)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_DUPLICATE_SCREEN_NAME).c_str(),
+ newName.c_str()));
+ return false;
+ }
+
+ // aliases must not exist in config but allow same aliases and
+ // allow an alias to be the old name.
+ for (CStringList::const_iterator index = newAliases.begin();
+ index != newAliases.end(); ++index) {
+ if (m_config->isScreen(*index) &&
+ !CStringUtil::CaselessCmp::equal(*index, m_name) &&
+ !isNameInList(oldAliases, *index)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_DUPLICATE_SCREEN_NAME).c_str(),
+ index->c_str()));
+ return false;
+ }
+ }
+
+ // dead corner size must be non-negative
+ child = getItem(hwnd, IDC_ADD_DC_SIZE);
+ CString valueString = getWindowText(child);
+ int cornerSize = atoi(valueString.c_str());
+ if (cornerSize < 0) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_CORNER_SIZE).c_str(),
+ valueString.c_str()));
+ SetFocus(child);
+ return false;
+ }
+
+ // collect options
+ child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
+ if (isItemChecked(child)) {
+ options[kOptionHalfDuplexCapsLock] = 1;
+ }
+ else {
+ options.erase(kOptionHalfDuplexCapsLock);
+ }
+ child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
+ if (isItemChecked(child)) {
+ options[kOptionHalfDuplexNumLock] = 1;
+ }
+ else {
+ options.erase(kOptionHalfDuplexNumLock);
+ }
+ child = getItem(hwnd, IDC_ADD_HD_SCROLL_CHECK);
+ if (isItemChecked(child)) {
+ options[kOptionHalfDuplexScrollLock] = 1;
+ }
+ else {
+ options.erase(kOptionHalfDuplexScrollLock);
+ }
+
+ // save modifier options
+ for (UInt32 i = 0; i < sizeof(s_modifiers) /
+ sizeof(s_modifiers[0]); ++i) {
+ child = getItem(hwnd, s_modifiers[i].m_ctrlID);
+ KeyModifierID id = static_cast(
+ SendMessage(child, CB_GETCURSEL, 0, 0) +
+ baseModifier);
+ if (id != s_modifiers[i].m_modifierID) {
+ options[s_modifiers[i].m_optionID] = id;
+ }
+ else {
+ options.erase(s_modifiers[i].m_optionID);
+ }
+ }
+
+ // save dead corner options
+ UInt32 corners = 0;
+ if (isItemChecked(getItem(hwnd, IDC_ADD_DC_TOP_LEFT))) {
+ corners |= kTopLeftMask;
+ }
+ if (isItemChecked(getItem(hwnd, IDC_ADD_DC_TOP_RIGHT))) {
+ corners |= kTopRightMask;
+ }
+ if (isItemChecked(getItem(hwnd, IDC_ADD_DC_BOTTOM_LEFT))) {
+ corners |= kBottomLeftMask;
+ }
+ if (isItemChecked(getItem(hwnd, IDC_ADD_DC_BOTTOM_RIGHT))) {
+ corners |= kBottomRightMask;
+ }
+ options[kOptionScreenSwitchCorners] = corners;
+ options[kOptionScreenSwitchCornerSize] = cornerSize;
+
+ // save new data to config
+ if (m_name.empty()) {
+ // added screen
+ m_config->addScreen(newName);
+ }
+ else {
+ // edited screen
+ m_config->removeAliases(m_name);
+ m_config->removeOptions(m_name);
+ m_config->renameScreen(m_name, newName);
+ }
+ m_name = newName;
+ for (CStringList::const_iterator index = newAliases.begin();
+ index != newAliases.end(); ++index) {
+ m_config->addAlias(m_name, *index);
+ }
+ for (CConfig::CScreenOptions::const_iterator
+ index = options.begin();
+ index != options.end(); ++index) {
+ m_config->addOption(m_name, index->first, index->second);
+ }
+
+ return true;
+}
+
+BOOL
+CAddScreen::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ init(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (save(hwnd)) {
+ EndDialog(hwnd, 1);
+ }
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CAddScreen::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
+
+void
+CAddScreen::getAliases(CStringList& aliases) const
+{
+ for (CConfig::all_const_iterator index = m_config->beginAll();
+ index != m_config->endAll(); ++index) {
+ if (CStringUtil::CaselessCmp::equal(index->second, m_name) &&
+ !CStringUtil::CaselessCmp::equal(index->second, index->first)) {
+ aliases.push_back(index->first);
+ }
+ }
+}
+
+void
+CAddScreen::getOptions(CConfig::CScreenOptions& optionsOut) const
+{
+ const CConfig::CScreenOptions* options = m_config->getOptions(m_name);
+ if (options == NULL) {
+ optionsOut = CConfig::CScreenOptions();
+ }
+ else {
+ optionsOut = *options;
+ }
+}
+
+void
+CAddScreen::tokenize(CStringList& tokens, const CString& src)
+{
+ // find first non-whitespace
+ CString::size_type x = src.find_first_not_of(" \t\r\n");
+ if (x == CString::npos) {
+ return;
+ }
+
+ // find next whitespace
+ do {
+ CString::size_type y = src.find_first_of(" \t\r\n", x);
+ if (y == CString::npos) {
+ y = src.size();
+ }
+ tokens.push_back(src.substr(x, y - x));
+ x = src.find_first_not_of(" \t\r\n", y);
+ } while (x != CString::npos);
+}
+
+bool
+CAddScreen::isNameInList(const CStringList& names, const CString& name)
+{
+ for (CStringList::const_iterator index = names.begin();
+ index != names.end(); ++index) {
+ if (CStringUtil::CaselessCmp::equal(name, *index)) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/cmd/launcher/CAddScreen.h b/cmd/launcher/CAddScreen.h
new file mode 100644
index 00000000..e926c498
--- /dev/null
+++ b/cmd/launcher/CAddScreen.h
@@ -0,0 +1,74 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CADDSCREEN_H
+#define CADDSCREEN_H
+
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+class CConfig;
+
+//! Add screen dialog for Microsoft Windows launcher
+class CAddScreen {
+public:
+ CAddScreen(HWND parent, CConfig*, const CString& name);
+ ~CAddScreen();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user. Return
+ \c true if the user accepted the changes, false otherwise.
+ */
+ bool doModal();
+
+ //@}
+ //! @name accessors
+ //@{
+
+ CString getName() const;
+
+ //@}
+
+private:
+ typedef std::vector CStringList;
+
+ void getAliases(CStringList&) const;
+ void getOptions(CConfig::CScreenOptions&) const;
+
+ static void tokenize(CStringList& tokens, const CString& src);
+ static bool isNameInList(const CStringList& tokens,
+ const CString& src);
+
+ void init(HWND hwnd);
+ bool save(HWND hwnd);
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+private:
+ static CAddScreen* s_singleton;
+
+ HWND m_parent;
+ CConfig* m_config;
+ CString m_name;
+};
+
+#endif
diff --git a/cmd/launcher/CAdvancedOptions.cpp b/cmd/launcher/CAdvancedOptions.cpp
new file mode 100644
index 00000000..c1ea83ef
--- /dev/null
+++ b/cmd/launcher/CAdvancedOptions.cpp
@@ -0,0 +1,269 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CConfig.h"
+#include "ProtocolTypes.h"
+#include "CStringUtil.h"
+#include "CArch.h"
+#include "CArchMiscWindows.h"
+#include "CAdvancedOptions.h"
+#include "LaunchUtil.h"
+#include "XArch.h"
+#include "resource.h"
+
+//
+// CAdvancedOptions
+//
+
+CAdvancedOptions* CAdvancedOptions::s_singleton = NULL;
+
+CAdvancedOptions::CAdvancedOptions(HWND parent, CConfig* config) :
+ m_parent(parent),
+ m_config(config),
+ m_isClient(false),
+ m_screenName(ARCH->getHostName()),
+ m_port(kDefaultPort),
+ m_interface()
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+ init();
+}
+
+CAdvancedOptions::~CAdvancedOptions()
+{
+ s_singleton = NULL;
+}
+
+void
+CAdvancedOptions::doModal(bool isClient)
+{
+ // save state
+ m_isClient = isClient;
+
+ // do dialog
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADVANCED_OPTIONS),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this);
+}
+
+CString
+CAdvancedOptions::getScreenName() const
+{
+ return m_screenName;
+}
+
+int
+CAdvancedOptions::getPort() const
+{
+ return m_port;
+}
+
+CString
+CAdvancedOptions::getInterface() const
+{
+ return m_interface;
+}
+
+CString
+CAdvancedOptions::getCommandLine(bool isClient, const CString& serverName) const
+{
+ CString cmdLine;
+
+ // screen name
+ if (!m_screenName.empty()) {
+ cmdLine += " --name ";
+ cmdLine += m_screenName;
+ }
+
+ // port
+ char portString[20];
+ sprintf(portString, "%d", m_port);
+ if (isClient) {
+ cmdLine += " ";
+ cmdLine += serverName;
+ cmdLine += ":";
+ cmdLine += portString;
+ }
+ else {
+ cmdLine += " --address ";
+ if (!m_interface.empty()) {
+ cmdLine += m_interface;
+ }
+ cmdLine += ":";
+ cmdLine += portString;
+ }
+
+ return cmdLine;
+}
+
+void
+CAdvancedOptions::init()
+{
+ // get values from registry
+ HKEY key = CArchMiscWindows::openKey(HKEY_CURRENT_USER, getSettingsPath());
+ if (key != NULL) {
+ DWORD newPort = CArchMiscWindows::readValueInt(key, "port");
+ CString newName = CArchMiscWindows::readValueString(key, "name");
+ CString newInterface =
+ CArchMiscWindows::readValueString(key, "interface");
+ if (newPort != 0) {
+ m_port = static_cast(newPort);
+ }
+ if (!newName.empty()) {
+ m_screenName = newName;
+ }
+ if (!newInterface.empty()) {
+ m_interface = newInterface;
+ }
+ CArchMiscWindows::closeKey(key);
+ }
+}
+
+void
+CAdvancedOptions::doInit(HWND hwnd)
+{
+ // set values in GUI
+ HWND child;
+ char buffer[20];
+ sprintf(buffer, "%d", m_port);
+ child = getItem(hwnd, IDC_ADVANCED_PORT_EDIT);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
+
+ child = getItem(hwnd, IDC_ADVANCED_NAME_EDIT);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)m_screenName.c_str());
+
+ child = getItem(hwnd, IDC_ADVANCED_INTERFACE_EDIT);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)m_interface.c_str());
+}
+
+bool
+CAdvancedOptions::save(HWND hwnd)
+{
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+ HWND child = getItem(hwnd, IDC_ADVANCED_NAME_EDIT);
+ CString name = getWindowText(child);
+ if (!m_config->isValidScreenName(name)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_SCREEN_NAME).c_str(),
+ name.c_str()));
+ SetFocus(child);
+ return false;
+ }
+ if (!m_isClient && !m_config->isScreen(name)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
+ name.c_str()));
+ SetFocus(child);
+ return false;
+ }
+
+ child = getItem(hwnd, IDC_ADVANCED_INTERFACE_EDIT);
+ CString iface = getWindowText(child);
+ if (!m_isClient) {
+ try {
+ if (!iface.empty()) {
+ ARCH->nameToAddr(iface);
+ }
+ }
+ catch (XArchNetworkName& e) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_INTERFACE_NAME).c_str(),
+ iface.c_str(), e.what().c_str()));
+ SetFocus(child);
+ return false;
+ }
+ }
+
+ // get and verify port
+ child = getItem(hwnd, IDC_ADVANCED_PORT_EDIT);
+ CString portString = getWindowText(child);
+ int port = atoi(portString.c_str());
+ if (port < 1 || port > 65535) {
+ CString defaultPortString = CStringUtil::print("%d", kDefaultPort);
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_PORT).c_str(),
+ portString.c_str(),
+ defaultPortString.c_str()));
+ SetFocus(child);
+ return false;
+ }
+
+ // save state
+ m_screenName = name;
+ m_port = port;
+ m_interface = iface;
+
+ // save values to registry
+ HKEY key = CArchMiscWindows::addKey(HKEY_CURRENT_USER, getSettingsPath());
+ if (key != NULL) {
+ CArchMiscWindows::setValue(key, "port", m_port);
+ CArchMiscWindows::setValue(key, "name", m_screenName);
+ CArchMiscWindows::setValue(key, "interface", m_interface);
+ CArchMiscWindows::closeKey(key);
+ }
+
+ return true;
+}
+
+void
+CAdvancedOptions::setDefaults(HWND hwnd)
+{
+ // restore defaults
+ m_screenName = ARCH->getHostName();
+ m_port = kDefaultPort;
+ m_interface = "";
+
+ // update GUI
+ doInit(hwnd);
+}
+
+BOOL
+CAdvancedOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ doInit(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (save(hwnd)) {
+ EndDialog(hwnd, 0);
+ }
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDC_ADVANCED_DEFAULTS:
+ setDefaults(hwnd);
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CAdvancedOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
diff --git a/cmd/launcher/CAdvancedOptions.h b/cmd/launcher/CAdvancedOptions.h
new file mode 100644
index 00000000..1dd9dc44
--- /dev/null
+++ b/cmd/launcher/CAdvancedOptions.h
@@ -0,0 +1,80 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CADVANCEDOPTIONS_H
+#define CADVANCEDOPTIONS_H
+
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+class CConfig;
+
+//! Advanced options dialog for Microsoft Windows launcher
+class CAdvancedOptions {
+public:
+ CAdvancedOptions(HWND parent, CConfig*);
+ ~CAdvancedOptions();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user.
+ */
+ void doModal(bool isClient);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Get the screen name
+ CString getScreenName() const;
+
+ //! Get the port
+ int getPort() const;
+
+ //! Get the interface
+ CString getInterface() const;
+
+ //! Convert options to command line string
+ CString getCommandLine(bool isClient,
+ const CString& serverName) const;
+
+ //@}
+
+private:
+ void init();
+ void doInit(HWND hwnd);
+ bool save(HWND hwnd);
+ void setDefaults(HWND hwnd);
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+private:
+ static CAdvancedOptions* s_singleton;
+
+ HWND m_parent;
+ CConfig* m_config;
+ bool m_isClient;
+ CString m_screenName;
+ int m_port;
+ CString m_interface;
+};
+
+#endif
diff --git a/cmd/launcher/CAutoStart.cpp b/cmd/launcher/CAutoStart.cpp
new file mode 100644
index 00000000..eb18a6b0
--- /dev/null
+++ b/cmd/launcher/CAutoStart.cpp
@@ -0,0 +1,361 @@
+/*
+ * 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 "CLog.h"
+#include "ILogOutputter.h"
+#include "CArch.h"
+#include "CStringUtil.h"
+#include "XArch.h"
+#include "CAutoStart.h"
+#include "LaunchUtil.h"
+#include "resource.h"
+
+static const char* CLIENT_DAEMON_NAME = "Synergy Client";
+static const char* SERVER_DAEMON_NAME = "Synergy Server";
+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.";
+
+//
+// CAutoStartOutputter
+//
+// This class detects a message above a certain level and saves it
+//
+
+class CAutoStartOutputter : public ILogOutputter {
+public:
+ CAutoStartOutputter(CString* msg) : m_msg(msg) { }
+ virtual ~CAutoStartOutputter() { }
+
+ // 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 ""; }
+
+private:
+ CString* m_msg;
+};
+
+bool
+CAutoStartOutputter::write(ELevel level, const char* message)
+{
+ if (level <= CLog::kERROR) {
+ *m_msg = message;
+ }
+ return false;
+}
+
+
+//
+// CAutoStart
+//
+
+CAutoStart* CAutoStart::s_singleton = NULL;
+
+CAutoStart::CAutoStart(HWND parent, bool isServer, const CString& cmdLine) :
+ m_parent(parent),
+ m_isServer(isServer),
+ m_cmdLine(cmdLine),
+ m_name(isServer ? SERVER_DAEMON_NAME : CLIENT_DAEMON_NAME)
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+}
+
+CAutoStart::~CAutoStart()
+{
+ s_singleton = NULL;
+}
+
+void
+CAutoStart::doModal()
+{
+ // install our log outputter
+ CLOG->insert(new CAutoStartOutputter(&m_errorMessage));
+
+ // do dialog
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this);
+
+ // remove log outputter
+ CLOG->pop_front();
+}
+
+void
+CAutoStart::reinstallDaemon(bool isClient, const CString& cmdLine)
+{
+ // get installation state
+ const char* name = (isClient ? CLIENT_DAEMON_NAME : SERVER_DAEMON_NAME);
+ bool installedSystem = ARCH->isDaemonInstalled(name, true);
+ bool installedUser = ARCH->isDaemonInstalled(name, false);
+
+ // reinstall if anything is installed
+ if (installedSystem || installedUser) {
+ ARCH->installDaemon(name,
+ isClient ? CLIENT_DAEMON_INFO : SERVER_DAEMON_INFO,
+ getAppPath(isClient ? CLIENT_APP : SERVER_APP).c_str(),
+ cmdLine.c_str(),
+ NULL,
+ installedSystem);
+ }
+}
+
+void
+CAutoStart::uninstallDaemons(bool client)
+{
+ if (client) {
+ try {
+ ARCH->uninstallDaemon(CLIENT_DAEMON_NAME, true);
+ }
+ catch (...) {
+ }
+ try {
+ ARCH->uninstallDaemon(CLIENT_DAEMON_NAME, false);
+ }
+ catch (...) {
+ }
+ }
+ else {
+ try {
+ ARCH->uninstallDaemon(SERVER_DAEMON_NAME, true);
+ }
+ catch (...) {
+ }
+ try {
+ ARCH->uninstallDaemon(SERVER_DAEMON_NAME, false);
+ }
+ catch (...) {
+ }
+ }
+}
+
+bool
+CAutoStart::startDaemon()
+{
+ const char* name = NULL;
+ if (ARCH->isDaemonInstalled(CLIENT_DAEMON_NAME, true)) {
+ name = CLIENT_DAEMON_NAME;
+ }
+ else if (ARCH->isDaemonInstalled(SERVER_DAEMON_NAME, true)) {
+ name = SERVER_DAEMON_NAME;
+ }
+ if (name == NULL) {
+ return false;
+ }
+
+ // open service manager
+ SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
+ if (mgr == NULL) {
+ return false;
+ }
+
+ // open the service
+ SC_HANDLE service = OpenService(mgr, name, SERVICE_START);
+ if (service == NULL) {
+ CloseServiceHandle(mgr);
+ return false;
+ }
+
+ // start the service
+ BOOL okay = StartService(service, 0, NULL);
+
+ // clean up
+ CloseServiceHandle(service);
+ CloseServiceHandle(mgr);
+
+ return (okay != 0);
+}
+
+bool
+CAutoStart::isDaemonInstalled()
+{
+ return (ARCH->isDaemonInstalled(CLIENT_DAEMON_NAME, false) ||
+ ARCH->isDaemonInstalled(CLIENT_DAEMON_NAME, true) ||
+ ARCH->isDaemonInstalled(SERVER_DAEMON_NAME, false) ||
+ ARCH->isDaemonInstalled(SERVER_DAEMON_NAME, true));
+}
+
+void
+CAutoStart::update()
+{
+ // get installation state
+ const bool installedSystem = ARCH->isDaemonInstalled(
+ m_name.c_str(), true);
+ const bool installedUser = ARCH->isDaemonInstalled(
+ m_name.c_str(), false);
+
+ // get user's permissions
+ const bool canInstallSystem = ARCH->canInstallDaemon(
+ m_name.c_str(), true);
+ const bool canInstallUser = ARCH->canInstallDaemon(
+ m_name.c_str(), false);
+
+ // update messages
+ CString msg, label;
+ if (canInstallSystem) {
+ if (canInstallUser) {
+ msg = getString(IDS_AUTOSTART_PERMISSION_ALL);
+ }
+ else {
+ msg = getString(IDS_AUTOSTART_PERMISSION_SYSTEM);
+ }
+ }
+ else if (canInstallUser) {
+ msg = getString(IDS_AUTOSTART_PERMISSION_USER);
+ }
+ else {
+ msg = getString(IDS_AUTOSTART_PERMISSION_NONE);
+ }
+ setWindowText(getItem(m_hwnd, IDC_AUTOSTART_PERMISSION_MSG), msg);
+ if (installedSystem) {
+ msg = getString(IDS_AUTOSTART_INSTALLED_SYSTEM);
+ label = getString(IDS_UNINSTALL_LABEL);
+ }
+ else if (installedUser) {
+ msg = getString(IDS_AUTOSTART_INSTALLED_USER);
+ label = getString(IDS_UNINSTALL_LABEL);
+ }
+ else {
+ msg = getString(IDS_AUTOSTART_INSTALLED_NONE);
+ label = getString(IDS_INSTALL_LABEL);
+ }
+ setWindowText(getItem(m_hwnd, IDC_AUTOSTART_INSTALLED_MSG), msg);
+
+ // update buttons
+ setWindowText(getItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM), label);
+ setWindowText(getItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER), label);
+ if (installedSystem) {
+ enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM, canInstallSystem);
+ enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER, false);
+ m_install = false;
+ }
+ else if (installedUser) {
+ enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM, false);
+ enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER, canInstallUser);
+ m_install = false;
+ }
+ else {
+ enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM, canInstallSystem);
+ enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER, canInstallUser);
+ m_install = true;
+ }
+}
+
+bool
+CAutoStart::onInstall(bool allUsers)
+{
+ if (!m_install) {
+ return onUninstall(allUsers);
+ }
+
+ // get the app path
+ CString appPath = getAppPath(m_isServer ? SERVER_APP : CLIENT_APP);
+
+ // clear error message
+ m_errorMessage = "";
+
+ // install
+ try {
+ ARCH->installDaemon(m_name.c_str(),
+ m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO,
+ appPath.c_str(), m_cmdLine.c_str(),
+ NULL, allUsers);
+ askOkay(m_hwnd, getString(IDS_INSTALL_TITLE),
+ getString(allUsers ?
+ IDS_INSTALLED_SYSTEM :
+ IDS_INSTALLED_USER));
+ return true;
+ }
+ catch (XArchDaemon& e) {
+ if (m_errorMessage.empty()) {
+ m_errorMessage = CStringUtil::format(
+ getString(IDS_INSTALL_GENERIC_ERROR).c_str(),
+ e.what().c_str());
+ }
+ showError(m_hwnd, m_errorMessage);
+ return false;
+ }
+}
+
+bool
+CAutoStart::onUninstall(bool allUsers)
+{
+ // clear error message
+ m_errorMessage = "";
+
+ // uninstall
+ try {
+ ARCH->uninstallDaemon(m_name.c_str(), allUsers);
+ askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE),
+ getString(allUsers ?
+ IDS_UNINSTALLED_SYSTEM :
+ IDS_UNINSTALLED_USER));
+ return true;
+ }
+ catch (XArchDaemon& e) {
+ if (m_errorMessage.empty()) {
+ m_errorMessage = CStringUtil::format(
+ getString(IDS_UNINSTALL_GENERIC_ERROR).c_str(),
+ e.what().c_str());
+ }
+ showError(m_hwnd, m_errorMessage);
+ return false;
+ }
+}
+
+BOOL
+CAutoStart::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ // save our hwnd
+ m_hwnd = hwnd;
+
+ // update the controls
+ update();
+
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_AUTOSTART_INSTALL_SYSTEM:
+ onInstall(true);
+ update();
+ return TRUE;
+
+ case IDC_AUTOSTART_INSTALL_USER:
+ onInstall(false);
+ update();
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ m_hwnd = NULL;
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CAutoStart::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
diff --git a/cmd/launcher/CAutoStart.h b/cmd/launcher/CAutoStart.h
new file mode 100644
index 00000000..46aad100
--- /dev/null
+++ b/cmd/launcher/CAutoStart.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#ifndef CAUTOSTART_H
+#define CAUTOSTART_H
+
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+//! Auto start dialog for Microsoft Windows launcher
+class CAutoStart {
+public:
+ CAutoStart(HWND parent, bool isServer, const CString& cmdLine);
+ ~CAutoStart();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user.
+ */
+ void doModal();
+
+ //! Reinstall daemon
+ /*!
+ Reinstalls the currently installed daemon.
+ */
+ static void reinstallDaemon(bool isClient, const CString& cmdLine);
+
+ //! Uninstalls daemon
+ /*!
+ Uninstalls all installed client (\p client is \c true) or server daemons.
+ */
+ static void uninstallDaemons(bool client);
+
+ //! Starts an installed daemon
+ /*!
+ Returns \c true iff a daemon was started. This will only start daemons
+ installed for all users.
+ */
+ static bool startDaemon();
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Tests if any daemons are installed
+ /*!
+ Returns \c true if any daemons are installed.
+ */
+ static bool isDaemonInstalled();
+
+ //@}
+
+private:
+ void update();
+ bool onInstall(bool allUsers);
+ bool onUninstall(bool allUsers);
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+private:
+ static CAutoStart* s_singleton;
+
+ HWND m_parent;
+ bool m_isServer;
+ CString m_cmdLine;
+ CString m_name;
+ HWND m_hwnd;
+ bool m_install;
+ CString m_errorMessage;
+};
+
+#endif
diff --git a/cmd/launcher/CGlobalOptions.cpp b/cmd/launcher/CGlobalOptions.cpp
new file mode 100644
index 00000000..8237a07f
--- /dev/null
+++ b/cmd/launcher/CGlobalOptions.cpp
@@ -0,0 +1,281 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CConfig.h"
+#include "ProtocolTypes.h"
+#include "CStringUtil.h"
+#include "CArch.h"
+#include "CGlobalOptions.h"
+#include "LaunchUtil.h"
+#include "resource.h"
+
+static const int s_defaultDelay = 250;
+static const int s_defaultHeartbeat = 5000;
+
+//
+// CGlobalOptions
+//
+
+CGlobalOptions* CGlobalOptions::s_singleton = NULL;
+
+CGlobalOptions::CGlobalOptions(HWND parent, CConfig* config) :
+ m_parent(parent),
+ m_config(config),
+ m_delayTime(s_defaultDelay),
+ m_twoTapTime(s_defaultDelay),
+ m_heartbeatTime(s_defaultHeartbeat)
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+}
+
+CGlobalOptions::~CGlobalOptions()
+{
+ s_singleton = NULL;
+}
+
+void
+CGlobalOptions::doModal()
+{
+ // do dialog
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_GLOBAL_OPTIONS),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this);
+}
+
+void
+CGlobalOptions::init(HWND hwnd)
+{
+ HWND child;
+ char buffer[30];
+
+ // reset options
+ sprintf(buffer, "%d", m_delayTime);
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
+ setItemChecked(child, false);
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
+ setWindowText(child, buffer);
+ sprintf(buffer, "%d", m_twoTapTime);
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
+ setItemChecked(child, false);
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
+ setWindowText(child, buffer);
+ sprintf(buffer, "%d", m_heartbeatTime);
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_CHECK);
+ setItemChecked(child, false);
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_TIME);
+ setWindowText(child, buffer);
+ child = getItem(hwnd, IDC_GLOBAL_SCREENSAVER_SYNC);
+ setItemChecked(child, true);
+ child = getItem(hwnd, IDC_GLOBAL_RELATIVE_MOVES);
+ setItemChecked(child, false);
+ child = getItem(hwnd, IDC_GLOBAL_LEAVE_FOREGROUND);
+ setItemChecked(child, false);
+
+ // get the global options
+ const CConfig::CScreenOptions* options = m_config->getOptions("");
+ if (options != NULL) {
+ for (CConfig::CScreenOptions::const_iterator index = options->begin();
+ index != options->end(); ++index) {
+ const OptionID id = index->first;
+ const OptionValue value = index->second;
+ if (id == kOptionScreenSwitchDelay) {
+ if (value > 0) {
+ sprintf(buffer, "%d", value);
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
+ setItemChecked(child, true);
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
+ setWindowText(child, buffer);
+ }
+ }
+ else if (id == kOptionScreenSwitchTwoTap) {
+ if (value > 0) {
+ sprintf(buffer, "%d", value);
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
+ setItemChecked(child, true);
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
+ setWindowText(child, buffer);
+ }
+ }
+ else if (id == kOptionHeartbeat) {
+ if (value > 0) {
+ sprintf(buffer, "%d", value);
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_CHECK);
+ setItemChecked(child, true);
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_TIME);
+ setWindowText(child, buffer);
+ }
+ }
+ else if (id == kOptionScreenSaverSync) {
+ child = getItem(hwnd, IDC_GLOBAL_SCREENSAVER_SYNC);
+ setItemChecked(child, (value != 0));
+ }
+ else if (id == kOptionRelativeMouseMoves) {
+ child = getItem(hwnd, IDC_GLOBAL_RELATIVE_MOVES);
+ setItemChecked(child, (value != 0));
+ }
+ else if (id == kOptionWin32KeepForeground) {
+ child = getItem(hwnd, IDC_GLOBAL_LEAVE_FOREGROUND);
+ setItemChecked(child, (value != 0));
+ }
+ }
+ }
+}
+
+bool
+CGlobalOptions::save(HWND hwnd)
+{
+ HWND child;
+ int newDelayTime = 0;
+ int newTwoTapTime = 0;
+ int newHeartbeatTime = 0;
+
+ // get requested options
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
+ if (isItemChecked(child)) {
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
+ newDelayTime = getTime(hwnd, child, true);
+ if (newDelayTime == 0) {
+ return false;
+ }
+ }
+ else {
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
+ newDelayTime = getTime(hwnd, child, false);
+ if (newDelayTime == 0) {
+ newDelayTime = s_defaultDelay;
+ }
+ }
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
+ if (isItemChecked(child)) {
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
+ newTwoTapTime = getTime(hwnd, child, true);
+ if (newTwoTapTime == 0) {
+ return false;
+ }
+ }
+ else {
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
+ newTwoTapTime = getTime(hwnd, child, false);
+ if (newTwoTapTime == 0) {
+ newTwoTapTime = s_defaultDelay;
+ }
+ }
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_CHECK);
+ if (isItemChecked(child)) {
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_TIME);
+ newHeartbeatTime = getTime(hwnd, child, true);
+ if (newHeartbeatTime == 0) {
+ return false;
+ }
+ }
+ else {
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_TIME);
+ newHeartbeatTime = getTime(hwnd, child, false);
+ if (newHeartbeatTime == 0) {
+ newHeartbeatTime = s_defaultHeartbeat;
+ }
+ }
+
+ // remove existing config options
+ m_config->removeOption("", kOptionScreenSwitchDelay);
+ m_config->removeOption("", kOptionScreenSwitchTwoTap);
+ m_config->removeOption("", kOptionHeartbeat);
+ m_config->removeOption("", kOptionScreenSaverSync);
+ m_config->removeOption("", kOptionRelativeMouseMoves);
+ m_config->removeOption("", kOptionWin32KeepForeground);
+
+ // add requested options
+ child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
+ if (isItemChecked(child)) {
+ m_config->addOption("", kOptionScreenSwitchDelay, newDelayTime);
+ }
+ child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
+ if (isItemChecked(child)) {
+ m_config->addOption("", kOptionScreenSwitchTwoTap, newTwoTapTime);
+ }
+ child = getItem(hwnd, IDC_GLOBAL_HEARTBEAT_CHECK);
+ if (isItemChecked(child)) {
+ m_config->addOption("", kOptionHeartbeat, newHeartbeatTime);
+ }
+ child = getItem(hwnd, IDC_GLOBAL_SCREENSAVER_SYNC);
+ if (!isItemChecked(child)) {
+ m_config->addOption("", kOptionScreenSaverSync, 0);
+ }
+ child = getItem(hwnd, IDC_GLOBAL_RELATIVE_MOVES);
+ if (isItemChecked(child)) {
+ m_config->addOption("", kOptionRelativeMouseMoves, 1);
+ }
+ child = getItem(hwnd, IDC_GLOBAL_LEAVE_FOREGROUND);
+ if (isItemChecked(child)) {
+ m_config->addOption("", kOptionWin32KeepForeground, 1);
+ }
+
+ // save last values
+ m_delayTime = newDelayTime;
+ m_twoTapTime = newTwoTapTime;
+ m_heartbeatTime = newHeartbeatTime;
+ return true;
+}
+
+int
+CGlobalOptions::getTime(HWND hwnd, HWND child, bool reportError)
+{
+ CString valueString = getWindowText(child);
+ int value = atoi(valueString.c_str());
+ if (value < 1) {
+ if (reportError) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_TIME).c_str(),
+ valueString.c_str()));
+ SetFocus(child);
+ }
+ return 0;
+ }
+ return value;
+}
+
+BOOL
+CGlobalOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ init(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (save(hwnd)) {
+ EndDialog(hwnd, 0);
+ }
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CGlobalOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
diff --git a/cmd/launcher/CGlobalOptions.h b/cmd/launcher/CGlobalOptions.h
new file mode 100644
index 00000000..f04f1bae
--- /dev/null
+++ b/cmd/launcher/CGlobalOptions.h
@@ -0,0 +1,67 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CGLOBALOPTIONS_H
+#define CGLOBALOPTIONS_H
+
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+class CConfig;
+
+//! Global options dialog for Microsoft Windows launcher
+class CGlobalOptions {
+public:
+ CGlobalOptions(HWND parent, CConfig*);
+ ~CGlobalOptions();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user.
+ */
+ void doModal();
+
+ //@}
+ //! @name accessors
+ //@{
+
+
+ //@}
+
+private:
+ void init(HWND hwnd);
+ bool save(HWND hwnd);
+
+ int getTime(HWND hwnd, HWND child, bool reportError);
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+private:
+ static CGlobalOptions* s_singleton;
+
+ HWND m_parent;
+ CConfig* m_config;
+ int m_delayTime;
+ int m_twoTapTime;
+ int m_heartbeatTime;
+};
+
+#endif
diff --git a/cmd/launcher/CHotkeyOptions.cpp b/cmd/launcher/CHotkeyOptions.cpp
new file mode 100644
index 00000000..5aa981e0
--- /dev/null
+++ b/cmd/launcher/CHotkeyOptions.cpp
@@ -0,0 +1,1938 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2006 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 "CArchMiscWindows.h"
+#include "CMSWindowsKeyState.h"
+#include "CConfig.h"
+#include "CHotkeyOptions.h"
+#include "CStringUtil.h"
+#include "LaunchUtil.h"
+#include "resource.h"
+
+#if !defined(WM_XBUTTONDOWN)
+#define WM_XBUTTONDOWN 0x020B
+#define WM_XBUTTONUP 0x020C
+#define WM_XBUTTONDBLCLK 0x020D
+#define XBUTTON1 0x0001
+#define XBUTTON2 0x0002
+#endif
+
+//
+// CAdvancedOptions
+//
+
+CHotkeyOptions* CHotkeyOptions::s_singleton = NULL;
+
+CHotkeyOptions::CHotkeyOptions(HWND parent, CConfig* config) :
+ m_parent(parent),
+ m_config(config)
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+}
+
+CHotkeyOptions::~CHotkeyOptions()
+{
+ s_singleton = NULL;
+}
+
+void
+CHotkeyOptions::doModal()
+{
+ // do dialog
+ m_inputFilter = m_config->getInputFilter();
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_OPTIONS),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this);
+}
+
+void
+CHotkeyOptions::doInit(HWND hwnd)
+{
+ m_activeRuleIndex = (UInt32)-1;
+ fillHotkeys(hwnd);
+ openRule(hwnd);
+}
+
+void
+CHotkeyOptions::fillHotkeys(HWND hwnd, UInt32 select)
+{
+ HWND rules = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
+
+ SendMessage(rules, LB_RESETCONTENT, 0, 0);
+ for (UInt32 i = 0, n = m_inputFilter->getNumRules(); i < n; ++i) {
+ CInputFilter::CRule& rule = m_inputFilter->getRule(i);
+ SendMessage(rules, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)rule.getCondition()->format().c_str());
+ }
+
+ if (select < m_inputFilter->getNumRules()) {
+ SendMessage(rules, LB_SETCURSEL, select, 0);
+ }
+
+ updateHotkeysControls(hwnd);
+}
+
+void
+CHotkeyOptions::updateHotkeysControls(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
+ bool selected = (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR);
+
+ enableItem(hwnd, IDC_HOTKEY_ADD_HOTKEY, TRUE);
+ enableItem(hwnd, IDC_HOTKEY_EDIT_HOTKEY, selected);
+ enableItem(hwnd, IDC_HOTKEY_REMOVE_HOTKEY, selected);
+}
+
+void
+CHotkeyOptions::addHotkey(HWND hwnd)
+{
+ closeRule(hwnd);
+ CInputFilter::CCondition* condition = NULL;
+ if (editCondition(hwnd, condition)) {
+ m_inputFilter->addFilterRule(CInputFilter::CRule(condition));
+ fillHotkeys(hwnd, m_inputFilter->getNumRules() - 1);
+ }
+ else {
+ delete condition;
+ }
+ openRule(hwnd);
+}
+
+void
+CHotkeyOptions::removeHotkey(HWND hwnd)
+{
+ UInt32 ruleIndex = m_activeRuleIndex;
+ closeRule(hwnd);
+
+ m_inputFilter->removeFilterRule(ruleIndex);
+ UInt32 n = m_inputFilter->getNumRules();
+ if (n > 0 && ruleIndex >= n) {
+ ruleIndex = n - 1;
+ }
+ fillHotkeys(hwnd, ruleIndex);
+
+ openRule(hwnd);
+}
+
+void
+CHotkeyOptions::editHotkey(HWND hwnd)
+{
+ // save selected item in action list
+ HWND actions = getItem(hwnd, IDC_HOTKEY_ACTIONS);
+ LRESULT aIndex = SendMessage(actions, LB_GETCURSEL, 0, 0);
+
+ UInt32 index = m_activeRuleIndex;
+ closeRule(hwnd);
+
+ CInputFilter::CRule& rule = m_inputFilter->getRule(index);
+ CInputFilter::CCondition* condition = rule.getCondition()->clone();
+ if (editCondition(hwnd, condition)) {
+ rule.setCondition(condition);
+ fillHotkeys(hwnd, index);
+ }
+ else {
+ delete condition;
+ }
+
+ openRule(hwnd);
+
+ // restore selected item in action list
+ if (aIndex != LB_ERR) {
+ SendMessage(actions, LB_SETCURSEL, aIndex, 0);
+ }
+}
+
+void
+CHotkeyOptions::fillActions(HWND hwnd, UInt32 select)
+{
+ HWND actions = getItem(hwnd, IDC_HOTKEY_ACTIONS);
+ SendMessage(actions, LB_RESETCONTENT, 0, 0);
+ if (m_activeRuleIndex != (UInt32)-1) {
+ UInt32 n = m_activeRule.getNumActions(true);
+ UInt32 n2 = m_activeRule.getNumActions(false);
+ for (UInt32 i = 0; i < n; ++i) {
+ const CInputFilter::CAction& action =
+ m_activeRule.getAction(true, i);
+ CString line("A ");
+ line += action.format();
+ SendMessage(actions, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)line.c_str());
+ SendMessage(actions, LB_SETITEMDATA, (WPARAM)i, (LPARAM)i);
+ }
+ for (UInt32 i = 0; i < n2; ++i) {
+ const CInputFilter::CAction& action =
+ m_activeRule.getAction(false, i);
+ CString line("D ");
+ line += action.format();
+ SendMessage(actions, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)line.c_str());
+ SendMessage(actions, LB_SETITEMDATA, (WPARAM)i + n,
+ (LPARAM)(i | 0x80000000u));
+ }
+
+ if (select < n + n2) {
+ SendMessage(actions, LB_SETCURSEL, select, 0);
+ }
+ }
+
+ updateActionsControls(hwnd);
+}
+
+void
+CHotkeyOptions::updateActionsControls(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
+ bool active = (m_activeRuleIndex != (UInt32)-1);
+
+ child = getItem(hwnd, IDC_HOTKEY_ACTIONS);
+ bool selected =
+ (active && (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR));
+
+ enableItem(hwnd, IDC_HOTKEY_ADD_ACTION, active);
+ enableItem(hwnd, IDC_HOTKEY_EDIT_ACTION, selected);
+ enableItem(hwnd, IDC_HOTKEY_REMOVE_ACTION, selected);
+}
+
+void
+CHotkeyOptions::addAction(HWND hwnd)
+{
+ CInputFilter::CAction* action = NULL;
+ bool onActivate = true;
+ if (editAction(hwnd, action, onActivate)) {
+ m_activeRule.adoptAction(action, onActivate);
+
+ UInt32 actionIndex = m_activeRule.getNumActions(true) - 1;
+ if (!onActivate) {
+ actionIndex += m_activeRule.getNumActions(false);
+ }
+ fillActions(hwnd, actionIndex);
+ }
+ else {
+ delete action;
+ }
+}
+
+void
+CHotkeyOptions::removeAction(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTIONS);
+ LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
+ if (index != LB_ERR) {
+ UInt32 actionIndex =
+ (UInt32)SendMessage(child, LB_GETITEMDATA, index, 0);
+ bool onActivate = ((actionIndex & 0x80000000u) == 0);
+ actionIndex &= ~0x80000000u;
+
+ m_activeRule.removeAction(onActivate, actionIndex);
+
+ actionIndex = static_cast(index);
+ UInt32 n = m_activeRule.getNumActions(true) +
+ m_activeRule.getNumActions(false);
+ if (n > 0 && actionIndex >= n) {
+ actionIndex = n - 1;
+ }
+ fillActions(hwnd, actionIndex);
+ }
+}
+
+void
+CHotkeyOptions::editAction(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTIONS);
+ LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
+ if (index != LB_ERR) {
+ UInt32 actionIndex =
+ (UInt32)SendMessage(child, LB_GETITEMDATA, index, 0);
+ bool onActivate = ((actionIndex & 0x80000000u) == 0);
+ actionIndex &= ~0x80000000u;
+
+ CInputFilter::CAction* action =
+ m_activeRule.getAction(onActivate, actionIndex).clone();
+ bool newOnActivate = onActivate;
+ if (editAction(hwnd, action, newOnActivate)) {
+ if (onActivate == newOnActivate) {
+ m_activeRule.replaceAction(action, onActivate, actionIndex);
+ actionIndex = static_cast(index);
+ }
+ else {
+ m_activeRule.removeAction(onActivate, actionIndex);
+ m_activeRule.adoptAction(action, newOnActivate);
+ actionIndex = m_activeRule.getNumActions(true) - 1;
+ if (!newOnActivate) {
+ actionIndex += m_activeRule.getNumActions(false);
+ }
+ }
+ fillActions(hwnd, actionIndex);
+ }
+ else {
+ delete action;
+ }
+ }
+}
+
+bool
+CHotkeyOptions::editCondition(HWND hwnd, CInputFilter::CCondition*& condition)
+{
+ return CConditionDialog::doModal(hwnd, condition);
+}
+
+bool
+CHotkeyOptions::editAction(HWND hwnd, CInputFilter::CAction*& action,
+ bool& onActivate)
+{
+ return CActionDialog::doModal(hwnd, m_config, action, onActivate);
+}
+
+void
+CHotkeyOptions::openRule(HWND hwnd)
+{
+ // get the active rule and copy it, merging down/up pairs of keystroke
+ // and mouse button actions into single actions for the convenience of
+ // of the user.
+ HWND rules = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
+ LRESULT index = SendMessage(rules, LB_GETCURSEL, 0, 0);
+ if (index != LB_ERR) {
+ // copy the rule as is
+ m_activeRuleIndex = (SInt32)index;
+ m_activeRule = m_inputFilter->getRule(m_activeRuleIndex);
+
+ // look for actions to combine
+ for (UInt32 i = 0, n = m_activeRule.getNumActions(true); i < n; ++i) {
+ // get next activate action
+ const CInputFilter::CAction* action =
+ &m_activeRule.getAction(true, i);
+
+ // check if it's a key or mouse action
+ const CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(action);
+ const CInputFilter::CMouseButtonAction* mouseAction =
+ dynamic_cast(action);
+ if (keyAction == NULL && mouseAction == NULL) {
+ continue;
+ }
+
+ // check for matching deactivate action
+ UInt32 j = (UInt32)-1;
+ CInputFilter::CAction* newAction = NULL;
+ if (keyAction != NULL) {
+ j = findMatchingAction(keyAction);
+ if (j != (UInt32)-1) {
+ // found a match
+ const IPlatformScreen::CKeyInfo* oldInfo =
+ keyAction->getInfo();
+ IPlatformScreen::CKeyInfo* newInfo =
+ IKeyState::CKeyInfo::alloc(*oldInfo);
+ newAction = new CKeystrokeDownUpAction(newInfo);
+ }
+ }
+ else if (mouseAction != NULL) {
+ j = findMatchingAction(mouseAction);
+ if (j != (UInt32)-1) {
+ // found a match
+ const IPlatformScreen::CButtonInfo* oldInfo =
+ mouseAction->getInfo();
+ IPlatformScreen::CButtonInfo* newInfo =
+ IPrimaryScreen::CButtonInfo::alloc(*oldInfo);
+ newAction = new CMouseButtonDownUpAction(newInfo);
+ }
+ }
+
+ // perform merge
+ if (newAction != NULL) {
+ m_activeRule.replaceAction(newAction, true, i);
+ m_activeRule.removeAction(false, j);
+ }
+ }
+ }
+ else {
+ m_activeRuleIndex = (UInt32)-1;
+ }
+ fillActions(hwnd);
+}
+
+void
+CHotkeyOptions::closeRule(HWND)
+{
+ // copy rule back to input filter, expanding merged actions into the
+ // two component actions.
+ if (m_activeRuleIndex != (UInt32)-1) {
+ // expand merged rules
+ for (UInt32 i = 0, n = m_activeRule.getNumActions(true); i < n; ++i) {
+ // get action
+ const CInputFilter::CAction* action =
+ &m_activeRule.getAction(true, i);
+
+ // check if it's a merged key or mouse action
+ const CKeystrokeDownUpAction* keyAction =
+ dynamic_cast(action);
+ const CMouseButtonDownUpAction* mouseAction =
+ dynamic_cast(action);
+ if (keyAction == NULL && mouseAction == NULL) {
+ continue;
+ }
+
+ // expand
+ if (keyAction != NULL) {
+ const IPlatformScreen::CKeyInfo* oldInfo =
+ keyAction->getInfo();
+ IPlatformScreen::CKeyInfo* newInfo =
+ IKeyState::CKeyInfo::alloc(*oldInfo);
+ CInputFilter::CKeystrokeAction* downAction =
+ new CInputFilter::CKeystrokeAction(newInfo, true);
+ newInfo = IKeyState::CKeyInfo::alloc(*oldInfo);
+ CInputFilter::CKeystrokeAction* upAction =
+ new CInputFilter::CKeystrokeAction(newInfo, false);
+ m_activeRule.replaceAction(downAction, true, i);
+ m_activeRule.adoptAction(upAction, false);
+ }
+ else if (mouseAction != NULL) {
+ const IPlatformScreen::CButtonInfo* oldInfo =
+ mouseAction->getInfo();
+ IPlatformScreen::CButtonInfo* newInfo =
+ IPrimaryScreen::CButtonInfo::alloc(*oldInfo);
+ CInputFilter::CMouseButtonAction* downAction =
+ new CInputFilter::CMouseButtonAction(newInfo, true);
+ newInfo = IPrimaryScreen::CButtonInfo::alloc(*oldInfo);
+ CInputFilter::CMouseButtonAction* upAction =
+ new CInputFilter::CMouseButtonAction(newInfo, false);
+ m_activeRule.replaceAction(downAction, true, i);
+ m_activeRule.adoptAction(upAction, false);
+ }
+ }
+
+ // copy it back
+ m_inputFilter->getRule(m_activeRuleIndex) = m_activeRule;
+ }
+ m_activeRuleIndex = (UInt32)-1;
+}
+
+UInt32
+CHotkeyOptions::findMatchingAction(
+ const CInputFilter::CKeystrokeAction* src) const
+{
+ for (UInt32 i = 0, n = m_activeRule.getNumActions(false); i < n; ++i) {
+ const CInputFilter::CKeystrokeAction* dst =
+ dynamic_cast(
+ &m_activeRule.getAction(false, i));
+ if (dst != NULL &&
+ IKeyState::CKeyInfo::equal(src->getInfo(), dst->getInfo())) {
+ return i;
+ }
+ }
+ return (UInt32)-1;
+}
+
+UInt32
+CHotkeyOptions::findMatchingAction(
+ const CInputFilter::CMouseButtonAction* src) const
+{
+ for (UInt32 i = 0, n = m_activeRule.getNumActions(false); i < n; ++i) {
+ const CInputFilter::CMouseButtonAction* dst =
+ dynamic_cast(
+ &m_activeRule.getAction(false, i));
+ if (dst != NULL &&
+ IPrimaryScreen::CButtonInfo::equal(
+ src->getInfo(), dst->getInfo())) {
+ return i;
+ }
+ }
+ return (UInt32)-1;
+}
+
+BOOL
+CHotkeyOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ doInit(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ closeRule(hwnd);
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDC_HOTKEY_HOTKEYS:
+ switch (HIWORD(wParam)) {
+ case LBN_DBLCLK:
+ editHotkey(hwnd);
+ return TRUE;
+
+ case LBN_SELCHANGE: {
+ HWND rules = getItem(hwnd, IDC_HOTKEY_HOTKEYS);
+ LRESULT index = SendMessage(rules, LB_GETCURSEL, 0, 0);
+ if (m_activeRuleIndex != (UInt32)index) {
+ closeRule(hwnd);
+ updateHotkeysControls(hwnd);
+ openRule(hwnd);
+ }
+ return TRUE;
+ }
+ }
+ break;
+
+ case IDC_HOTKEY_ADD_HOTKEY:
+ addHotkey(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_REMOVE_HOTKEY:
+ removeHotkey(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_EDIT_HOTKEY:
+ editHotkey(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTIONS:
+ switch (HIWORD(wParam)) {
+ case LBN_DBLCLK:
+ editAction(hwnd);
+ return TRUE;
+
+ case LBN_SELCHANGE:
+ updateActionsControls(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_HOTKEY_ADD_ACTION:
+ addAction(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_REMOVE_ACTION:
+ removeAction(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_EDIT_ACTION:
+ editAction(hwnd);
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CHotkeyOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
+
+
+//
+// CHotkeyOptions::CConditionDialog
+//
+
+CInputFilter::CCondition*
+ CHotkeyOptions::CConditionDialog::s_condition = NULL;
+CInputFilter::CCondition*
+ CHotkeyOptions::CConditionDialog::s_lastGoodCondition = NULL;
+WNDPROC CHotkeyOptions::CConditionDialog::s_editWndProc = NULL;
+
+bool
+CHotkeyOptions::CConditionDialog::doModal(HWND parent,
+ CInputFilter::CCondition*& condition)
+{
+ s_condition = condition;
+ if (s_condition != NULL) {
+ s_lastGoodCondition = s_condition->clone();
+ }
+ else {
+ s_lastGoodCondition = NULL;
+ }
+ int n = DialogBox(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_CONDITION),
+ parent, dlgProc);
+
+ condition = s_condition;
+ delete s_lastGoodCondition;
+ s_condition = NULL;
+ s_lastGoodCondition = NULL;
+
+ // user effectively cancelled if the condition is NULL
+ if (condition == NULL) {
+ n = 0;
+ }
+
+ return (n == 1);
+}
+
+void
+CHotkeyOptions::CConditionDialog::doInit(HWND hwnd)
+{
+ // subclass edit control
+ HWND child = getItem(hwnd, IDC_HOTKEY_CONDITION_HOTKEY);
+ s_editWndProc = (WNDPROC)GetWindowLong(child, GWL_WNDPROC);
+ SetWindowLong(child, GWL_WNDPROC, (LONG)editProc);
+
+ // fill control
+ fillHotkey(hwnd);
+}
+
+void
+CHotkeyOptions::CConditionDialog::fillHotkey(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_CONDITION_HOTKEY);
+ if (s_condition != NULL) {
+ setWindowText(child, s_condition->format().c_str());
+ }
+ else {
+ setWindowText(child, "");
+ }
+}
+
+void
+CHotkeyOptions::CConditionDialog::onButton(HWND hwnd, ButtonID button)
+{
+ delete s_condition;
+ s_condition =
+ new CInputFilter::CMouseButtonCondition(button, getModifiers());
+
+ fillHotkey(GetParent(hwnd));
+}
+
+void
+CHotkeyOptions::CConditionDialog::onKey(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ // ignore key repeats
+ if ((lParam & 0xc0000000u) == 0x40000000u) {
+ return;
+ }
+
+ // ignore key releases if the condition is complete and for the tab
+ // key (in case we were just tabbed to)
+ if ((lParam & 0x80000000u) != 0) {
+ if (isGoodCondition() || wParam == VK_TAB) {
+ return;
+ }
+ }
+
+ KeyID key = kKeyNone;
+ KeyModifierMask mask = getModifiers();
+ switch (wParam) {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ case VK_CONTROL:
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ case VK_MENU:
+ case VK_LMENU:
+ case VK_RMENU:
+ case VK_LWIN:
+ case VK_RWIN:
+ break;
+
+ case VK_TAB:
+ // allow tabbing out of control
+ if ((mask & (KeyModifierControl |
+ KeyModifierAlt | KeyModifierSuper)) == 0) {
+ HWND next = hwnd;
+ if ((mask & KeyModifierShift) == 0) {
+ do {
+ next = GetWindow(next, GW_HWNDNEXT);
+ if (next == NULL) {
+ next = GetWindow(hwnd, GW_HWNDFIRST);
+ }
+ } while (next != hwnd &&
+ (!IsWindowVisible(next) ||
+ (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
+ }
+ else {
+ do {
+ next = GetWindow(next, GW_HWNDPREV);
+ if (next == NULL) {
+ next = GetWindow(hwnd, GW_HWNDLAST);
+ }
+ } while (next != hwnd &&
+ (!IsWindowVisible(next) ||
+ (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
+ }
+ SetFocus(next);
+ return;
+ }
+ // fall through
+
+ default:
+ key = CMSWindowsKeyState::getKeyID(wParam,
+ static_cast((lParam & 0x1ff0000u) >> 16));
+ switch (key) {
+ case kKeyNone:
+ // could be a character
+ key = getChar(wParam, lParam);
+ if (key == kKeyNone) {
+ return;
+ }
+ break;
+
+ case kKeyShift_L:
+ case kKeyShift_R:
+ case kKeyControl_L:
+ case kKeyControl_R:
+ case kKeyAlt_L:
+ case kKeyAlt_R:
+ case kKeyMeta_L:
+ case kKeyMeta_R:
+ case kKeySuper_L:
+ case kKeySuper_R:
+ case kKeyCapsLock:
+ case kKeyNumLock:
+ case kKeyScrollLock:
+ // bogus
+ return;
+ }
+ break;
+ }
+
+ delete s_condition;
+ s_condition = new CInputFilter::CKeystrokeCondition(key, mask);
+
+ fillHotkey(GetParent(hwnd));
+}
+
+KeyID
+CHotkeyOptions::CConditionDialog::getChar(WPARAM wParam, LPARAM lParam)
+{
+ BYTE keyState[256];
+ UINT virtualKey = (UINT)wParam;
+ UINT scanCode = (UINT)((lParam & 0x0ff0000u) >> 16);
+ GetKeyboardState(keyState);
+
+ // reset modifier state
+ keyState[VK_SHIFT] = 0;
+ keyState[VK_LSHIFT] = 0;
+ keyState[VK_RSHIFT] = 0;
+ keyState[VK_CONTROL] = 0;
+ keyState[VK_LCONTROL] = 0;
+ keyState[VK_RCONTROL] = 0;
+ keyState[VK_MENU] = 0;
+ keyState[VK_LMENU] = 0;
+ keyState[VK_RMENU] = 0;
+ keyState[VK_LWIN] = 0;
+ keyState[VK_RWIN] = 0;
+
+ // translate virtual key to character
+ int n;
+ KeyID id;
+ if (CArchMiscWindows::isWindows95Family()) {
+ // XXX -- how do we get characters not in Latin-1?
+ WORD ascii;
+ n = ToAscii(virtualKey, scanCode, keyState, &ascii, 0);
+ id = static_cast(ascii & 0xffu);
+ }
+ else {
+ typedef int (WINAPI *ToUnicode_t)(UINT wVirtKey,
+ UINT wScanCode,
+ PBYTE lpKeyState,
+ LPWSTR pwszBuff,
+ int cchBuff,
+ UINT wFlags);
+ ToUnicode_t s_ToUnicode = NULL;
+ if (s_ToUnicode == NULL) {
+ HMODULE userModule = GetModuleHandle("user32.dll");
+ s_ToUnicode =
+ (ToUnicode_t)GetProcAddress(userModule, "ToUnicode");
+ }
+
+ WCHAR unicode[2];
+ n = s_ToUnicode(virtualKey, scanCode, keyState,
+ unicode, sizeof(unicode) / sizeof(unicode[0]),
+ 0);
+ id = static_cast(unicode[0]);
+ }
+ switch (n) {
+ case -1:
+ // no hot keys on dead keys
+ return kKeyNone;
+
+ default:
+ case 0:
+ // unmapped
+ return kKeyNone;
+
+ case 1:
+ return id;
+ }
+}
+
+KeyModifierMask
+CHotkeyOptions::CConditionDialog::getModifiers()
+{
+ KeyModifierMask mask = 0;
+ if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) {
+ mask |= KeyModifierShift;
+ }
+ if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) {
+ mask |= KeyModifierControl;
+ }
+ if ((GetKeyState(VK_MENU) & 0x8000) != 0) {
+ mask |= KeyModifierAlt;
+ }
+ if ((GetKeyState(VK_LWIN) & 0x8000) != 0 ||
+ (GetKeyState(VK_RWIN) & 0x8000) != 0) {
+ mask |= KeyModifierSuper;
+ }
+ return mask;
+}
+
+bool
+CHotkeyOptions::CConditionDialog::isGoodCondition()
+{
+ CInputFilter::CKeystrokeCondition* keyCondition =
+ dynamic_cast(s_condition);
+ return (keyCondition == NULL || keyCondition->getKey() != kKeyNone);
+}
+
+BOOL CALLBACK
+CHotkeyOptions::CConditionDialog::dlgProc(HWND hwnd,
+ UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ doInit(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ EndDialog(hwnd, 1);
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+LRESULT CALLBACK
+CHotkeyOptions::CConditionDialog::editProc(HWND hwnd,
+ UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ onButton(hwnd, kButtonLeft);
+ }
+ else {
+ SetFocus(hwnd);
+ }
+ return 0;
+
+ case WM_MBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ onButton(hwnd, kButtonMiddle);
+ }
+ return 0;
+
+ case WM_RBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ onButton(hwnd, kButtonRight);
+ }
+ return 0;
+
+ case WM_XBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ switch (HIWORD(wParam)) {
+ case XBUTTON1:
+ onButton(hwnd, kButtonExtra0 + 0);
+ break;
+
+ case XBUTTON2:
+ onButton(hwnd, kButtonExtra0 + 1);
+ break;
+ }
+ }
+ return 0;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ onKey(hwnd, wParam, lParam);
+ return 0;
+
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_XBUTTONUP:
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ case WM_DEADCHAR:
+ case WM_SYSDEADCHAR:
+ return 0;
+
+ case WM_SETFOCUS:
+ if (s_condition != NULL) {
+ delete s_lastGoodCondition;
+ s_lastGoodCondition = s_condition->clone();
+ }
+ break;
+
+ case WM_KILLFOCUS:
+ if (!isGoodCondition()) {
+ delete s_condition;
+ if (s_lastGoodCondition != NULL) {
+ s_condition = s_lastGoodCondition->clone();
+ }
+ else {
+ s_condition = NULL;
+ }
+ }
+ fillHotkey(GetParent(hwnd));
+ break;
+
+ case WM_GETDLGCODE:
+ return DLGC_WANTALLKEYS;
+
+ default:
+ break;
+ }
+ return CallWindowProc(s_editWndProc, hwnd, message, wParam, lParam);
+}
+
+
+//
+// CHotkeyOptions::CActionDialog
+//
+
+CConfig* CHotkeyOptions::CActionDialog::s_config = NULL;
+bool CHotkeyOptions::CActionDialog::s_onActivate = false;
+CInputFilter::CAction*
+ CHotkeyOptions::CActionDialog::s_action = NULL;
+CInputFilter::CAction*
+ CHotkeyOptions::CActionDialog::s_lastGoodAction = NULL;
+std::set
+ CHotkeyOptions::CActionDialog::s_screens;
+WNDPROC CHotkeyOptions::CActionDialog::s_editWndProc = NULL;
+
+bool
+CHotkeyOptions::CActionDialog::doModal(HWND parent, CConfig* config,
+ CInputFilter::CAction*& action, bool& onActivate)
+{
+ s_config = config;
+ s_onActivate = onActivate;
+ s_action = action;
+ if (s_action != NULL) {
+ s_lastGoodAction = s_action->clone();
+ }
+ else {
+ s_lastGoodAction = NULL;
+ }
+
+ int n = DialogBox(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_ACTION),
+ parent, dlgProc);
+
+ onActivate = s_onActivate;
+ action = s_action;
+ delete s_lastGoodAction;
+ s_action = NULL;
+ s_lastGoodAction = NULL;
+
+ return (n == 1);
+}
+
+void
+CHotkeyOptions::CActionDialog::doInit(HWND hwnd)
+{
+ // subclass edit control
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY);
+ s_editWndProc = (WNDPROC)GetWindowLong(child, GWL_WNDPROC);
+ SetWindowLong(child, GWL_WNDPROC, (LONG)editProc);
+ setWindowText(getItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY), "");
+ fillHotkey(hwnd);
+
+ // fill screens
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST);
+ SendMessage(child, CB_RESETCONTENT, 0, 0);
+ for (CConfig::const_iterator index = s_config->begin();
+ index != s_config->end(); ) {
+ const CString& name = *index;
+ ++index;
+ if (index != s_config->end()) {
+ SendMessage(child, CB_INSERTSTRING,
+ (WPARAM)-1, (LPARAM)name.c_str());
+ }
+ else {
+ SendMessage(child, CB_ADDSTRING, 0, (LPARAM)name.c_str());
+ }
+ }
+ SendMessage(child, CB_SETCURSEL, 0, 0);
+
+ // fill directions
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST);
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_LEFT).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_RIGHT).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_TOP).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_BOTTOM).c_str());
+ SendMessage(child, CB_SETCURSEL, 0, 0);
+
+ // fill lock modes
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_MODE_OFF).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_MODE_ON).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_MODE_TOGGLE).c_str());
+ SendMessage(child, CB_SETCURSEL, 0, 0);
+
+ // fill keyboard broadcast modes
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_MODE_OFF).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_MODE_ON).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_MODE_TOGGLE).c_str());
+ SendMessage(child, CB_SETCURSEL, 0, 0);
+
+ // select when
+ if (s_onActivate) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_ON_ACTIVATE);
+ }
+ else {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_ON_DEACTIVATE);
+ }
+ setItemChecked(child, true);
+
+ // no screens by default
+ s_screens.clear();
+
+ // select mode
+ child = NULL;
+ CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(s_action);
+ CInputFilter::CMouseButtonAction* mouseAction =
+ dynamic_cast(s_action);
+ CInputFilter::CLockCursorToScreenAction* lockAction =
+ dynamic_cast(s_action);
+ CInputFilter::CSwitchToScreenAction* switchToAction =
+ dynamic_cast(s_action);
+ CInputFilter::CSwitchInDirectionAction* switchInAction =
+ dynamic_cast(s_action);
+ CInputFilter::CKeyboardBroadcastAction* keyboardBroadcastAction=
+ dynamic_cast(s_action);
+ if (keyAction != NULL) {
+ if (dynamic_cast(s_action) != NULL) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP);
+ }
+ else if (keyAction->isOnPress()) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWN);
+ }
+ else {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_UP);
+ }
+ }
+ else if (mouseAction != NULL) {
+ if (dynamic_cast(s_action) != NULL) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP);
+ }
+ else if (keyAction->isOnPress()) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_DOWN);
+ }
+ else {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_UP);
+ }
+ }
+ else if (lockAction != NULL) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
+ SendMessage(child, CB_SETCURSEL, lockAction->getMode(), 0);
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK);
+ }
+ else if (switchToAction != NULL) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST);
+ DWORD i = SendMessage(child, CB_FINDSTRINGEXACT, (WPARAM)-1,
+ (LPARAM)switchToAction->getScreen().c_str());
+ if (i == CB_ERR) {
+ i = 0;
+ }
+ SendMessage(child, CB_SETCURSEL, i, 0);
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO);
+ }
+ else if (switchInAction != NULL) {
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST);
+ SendMessage(child, CB_SETCURSEL,
+ switchInAction->getDirection() - kLeft, 0);
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN);
+ }
+ else if (keyboardBroadcastAction != NULL) {
+ // Save the screens we're broadcasting to
+ s_screens = keyboardBroadcastAction->getScreens();
+
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
+ SendMessage(child, CB_SETCURSEL, keyboardBroadcastAction->getMode(), 0);
+ child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST);
+ }
+ if (child != NULL) {
+ setItemChecked(child, true);
+ }
+
+ updateControls(hwnd);
+}
+
+void
+CHotkeyOptions::CActionDialog::fillHotkey(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY);
+ CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(s_action);
+ CInputFilter::CMouseButtonAction* mouseAction =
+ dynamic_cast(s_action);
+ if (keyAction != NULL || mouseAction != NULL) {
+ setWindowText(child, s_action->format().c_str());
+ }
+ else {
+ setWindowText(child, "");
+ }
+
+ // can only set screens in key actions
+ enableItem(hwnd, IDC_HOTKEY_ACTION_SCREENS, keyAction != NULL);
+}
+
+void
+CHotkeyOptions::CActionDialog::updateControls(HWND hwnd)
+{
+ // determine which mode we're in
+ UInt32 mode = 0;
+ if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP)) ||
+ isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWN)) ||
+ isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_UP))) {
+ mode = 1;
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO))) {
+ mode = 2;
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN))) {
+ mode = 3;
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_LOCK))) {
+ mode = 4;
+ }
+ else if (isItemChecked(getItem(hwnd,
+ IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST))) {
+ mode = 5;
+ }
+
+ // enable/disable all mode specific controls
+ enableItem(hwnd, IDC_HOTKEY_ACTION_HOTKEY, mode == 1);
+ enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST, mode == 2);
+ enableItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST, mode == 3);
+ enableItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST, mode == 4);
+ enableItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST, mode == 5);
+ enableItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS, mode == 5);
+
+ // can only set screens in key actions
+ CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(s_action);
+ enableItem(hwnd, IDC_HOTKEY_ACTION_SCREENS, keyAction != NULL);
+}
+
+void
+CHotkeyOptions::CActionDialog::onButton(HWND hwnd, ButtonID button)
+{
+ IPlatformScreen::CButtonInfo* info =
+ IPrimaryScreen::CButtonInfo::alloc(button, getModifiers());
+ delete s_action;
+ HWND parent = GetParent(hwnd);
+ if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWNUP))) {
+ s_action = new CMouseButtonDownUpAction(info);
+ }
+ else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWN))) {
+ s_action = new CInputFilter::CMouseButtonAction(info, true);
+ }
+ else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_UP))) {
+ s_action = new CInputFilter::CMouseButtonAction(info, false);
+ }
+ else {
+ s_action = NULL;
+ }
+
+ fillHotkey(parent);
+}
+
+void
+CHotkeyOptions::CActionDialog::onKey(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+ // ignore key repeats
+ if ((lParam & 0xc0000000u) == 0x40000000u) {
+ return;
+ }
+
+ // ignore key releases if the action is complete and for the tab
+ // key (in case we were just tabbed to)
+ if ((lParam & 0x80000000u) != 0) {
+ if (isGoodAction() || wParam == VK_TAB) {
+ return;
+ }
+ }
+
+ KeyID key = kKeyNone;
+ KeyModifierMask mask = getModifiers();
+ switch (wParam) {
+ case VK_SHIFT:
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ case VK_CONTROL:
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ case VK_MENU:
+ case VK_LMENU:
+ case VK_RMENU:
+ case VK_LWIN:
+ case VK_RWIN:
+ break;
+
+ case VK_TAB:
+ // allow tabbing out of control
+ if ((mask & (KeyModifierControl |
+ KeyModifierAlt | KeyModifierSuper)) == 0) {
+ HWND next = hwnd;
+ if ((mask & KeyModifierShift) == 0) {
+ do {
+ next = GetWindow(next, GW_HWNDNEXT);
+ if (next == NULL) {
+ next = GetWindow(hwnd, GW_HWNDFIRST);
+ }
+ } while (next != hwnd &&
+ (!IsWindowVisible(next) ||
+ (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
+ }
+ else {
+ do {
+ next = GetWindow(next, GW_HWNDPREV);
+ if (next == NULL) {
+ next = GetWindow(hwnd, GW_HWNDLAST);
+ }
+ } while (next != hwnd &&
+ (!IsWindowVisible(next) ||
+ (GetWindowLong(next, GWL_STYLE) & WS_TABSTOP) == 0));
+ }
+ SetFocus(next);
+ return;
+ }
+ // fall through
+
+ default:
+ key = CMSWindowsKeyState::getKeyID(wParam,
+ static_cast((lParam & 0x1ff0000u) >> 16));
+ switch (key) {
+ case kKeyNone:
+ // could be a character
+ key = getChar(wParam, lParam);
+ if (key == kKeyNone) {
+ return;
+ }
+ break;
+
+ case kKeyShift_L:
+ case kKeyShift_R:
+ case kKeyControl_L:
+ case kKeyControl_R:
+ case kKeyAlt_L:
+ case kKeyAlt_R:
+ case kKeyMeta_L:
+ case kKeyMeta_R:
+ case kKeySuper_L:
+ case kKeySuper_R:
+ case kKeyCapsLock:
+ case kKeyNumLock:
+ case kKeyScrollLock:
+ // bogus
+ return;
+ }
+ break;
+ }
+
+ // get old screen list
+ std::set screens;
+ CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(s_action);
+ if (keyAction == NULL) {
+ keyAction =
+ dynamic_cast(s_lastGoodAction);
+ }
+ if (keyAction != NULL) {
+ IKeyState::CKeyInfo::split(keyAction->getInfo()->m_screens, screens);
+ }
+
+ // create new action
+ IPlatformScreen::CKeyInfo* info =
+ IKeyState::CKeyInfo::alloc(key, mask, 0, 0, screens);
+ delete s_action;
+ HWND parent = GetParent(hwnd);
+ if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWNUP))) {
+ s_action = new CKeystrokeDownUpAction(info);
+ }
+ else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_DOWN))) {
+ s_action = new CInputFilter::CKeystrokeAction(info, true);
+ }
+ else if (isItemChecked(getItem(parent, IDC_HOTKEY_ACTION_UP))) {
+ s_action = new CInputFilter::CKeystrokeAction(info, false);
+ }
+ else {
+ s_action = NULL;
+ }
+
+ fillHotkey(parent);
+}
+
+void
+CHotkeyOptions::CActionDialog::onLockAction(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_LOCK_LIST);
+ LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
+ if (index != CB_ERR) {
+ delete s_action;
+ s_action = new CInputFilter::CLockCursorToScreenAction(
+ (CInputFilter::CLockCursorToScreenAction::Mode)index);
+ }
+}
+
+void
+CHotkeyOptions::CActionDialog::onSwitchToAction(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_TO_LIST);
+ CString screen = getWindowText(child);
+ delete s_action;
+ s_action = new CInputFilter::CSwitchToScreenAction(screen);
+}
+
+void
+CHotkeyOptions::CActionDialog::onSwitchInAction(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_SWITCH_IN_LIST);
+ LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
+ if (index != CB_ERR) {
+ delete s_action;
+ s_action = new CInputFilter::CSwitchInDirectionAction(
+ (EDirection)(index + kLeft));
+ }
+}
+
+void
+CHotkeyOptions::CActionDialog::onKeyboardBroadcastAction(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST);
+ LRESULT index = SendMessage(child, CB_GETCURSEL, 0, 0);
+ if (index != CB_ERR) {
+ delete s_action;
+ s_action = new CInputFilter::CKeyboardBroadcastAction(
+ (CInputFilter::CKeyboardBroadcastAction::Mode)index, s_screens);
+ }
+}
+
+KeyID
+CHotkeyOptions::CActionDialog::getChar(WPARAM wParam, LPARAM lParam)
+{
+ BYTE keyState[256];
+ UINT virtualKey = (UINT)wParam;
+ UINT scanCode = (UINT)((lParam & 0x0ff0000u) >> 16);
+ GetKeyboardState(keyState);
+
+ // reset modifier state
+ keyState[VK_SHIFT] = 0;
+ keyState[VK_LSHIFT] = 0;
+ keyState[VK_RSHIFT] = 0;
+ keyState[VK_CONTROL] = 0;
+ keyState[VK_LCONTROL] = 0;
+ keyState[VK_RCONTROL] = 0;
+ keyState[VK_MENU] = 0;
+ keyState[VK_LMENU] = 0;
+ keyState[VK_RMENU] = 0;
+ keyState[VK_LWIN] = 0;
+ keyState[VK_RWIN] = 0;
+
+ // translate virtual key to character
+ int n;
+ KeyID id;
+ if (CArchMiscWindows::isWindows95Family()) {
+ // XXX -- how do we get characters not in Latin-1?
+ WORD ascii;
+ n = ToAscii(virtualKey, scanCode, keyState, &ascii, 0);
+ id = static_cast(ascii & 0xffu);
+ }
+ else {
+ typedef int (WINAPI *ToUnicode_t)(UINT wVirtKey,
+ UINT wScanCode,
+ PBYTE lpKeyState,
+ LPWSTR pwszBuff,
+ int cchBuff,
+ UINT wFlags);
+ ToUnicode_t s_ToUnicode = NULL;
+ if (s_ToUnicode == NULL) {
+ HMODULE userModule = GetModuleHandle("user32.dll");
+ s_ToUnicode =
+ (ToUnicode_t)GetProcAddress(userModule, "ToUnicode");
+ }
+
+ WCHAR unicode[2];
+ n = s_ToUnicode(virtualKey, scanCode, keyState,
+ unicode, sizeof(unicode) / sizeof(unicode[0]),
+ 0);
+ id = static_cast(unicode[0]);
+ }
+ switch (n) {
+ case -1:
+ // no hot keys on dead keys
+ return kKeyNone;
+
+ default:
+ case 0:
+ // unmapped
+ return kKeyNone;
+
+ case 1:
+ return id;
+ }
+}
+
+KeyModifierMask
+CHotkeyOptions::CActionDialog::getModifiers()
+{
+ KeyModifierMask mask = 0;
+ if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) {
+ mask |= KeyModifierShift;
+ }
+ if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) {
+ mask |= KeyModifierControl;
+ }
+ if ((GetKeyState(VK_MENU) & 0x8000) != 0) {
+ mask |= KeyModifierAlt;
+ }
+ if ((GetKeyState(VK_LWIN) & 0x8000) != 0 ||
+ (GetKeyState(VK_RWIN) & 0x8000) != 0) {
+ mask |= KeyModifierSuper;
+ }
+ return mask;
+}
+
+bool
+CHotkeyOptions::CActionDialog::isGoodAction()
+{
+ CInputFilter::CMouseButtonAction* mouseAction =
+ dynamic_cast(s_action);
+ CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(s_action);
+ return (mouseAction == NULL || keyAction == NULL ||
+ keyAction->getInfo()->m_key != kKeyNone);
+}
+
+void
+CHotkeyOptions::CActionDialog::convertAction(HWND hwnd)
+{
+ if (s_lastGoodAction != NULL) {
+ CInputFilter::CMouseButtonAction* mouseAction =
+ dynamic_cast(s_lastGoodAction);
+ CInputFilter::CKeystrokeAction* keyAction =
+ dynamic_cast(s_lastGoodAction);
+ if (mouseAction != NULL) {
+ IPlatformScreen::CButtonInfo* info =
+ IPrimaryScreen::CButtonInfo::alloc(*mouseAction->getInfo());
+ delete s_action;
+ if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP))) {
+ s_action = new CMouseButtonDownUpAction(info);
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWN))) {
+ s_action = new CInputFilter::CMouseButtonAction(info, true);
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_UP))) {
+ s_action = new CInputFilter::CMouseButtonAction(info, false);
+ }
+ else {
+ free(info);
+ s_action = NULL;
+ }
+ }
+ else if (keyAction != NULL) {
+ IPlatformScreen::CKeyInfo* info =
+ IKeyState::CKeyInfo::alloc(*keyAction->getInfo());
+ delete s_action;
+ if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWNUP))) {
+ s_action = new CKeystrokeDownUpAction(info);
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_DOWN))) {
+ s_action = new CInputFilter::CKeystrokeAction(info, true);
+ }
+ else if (isItemChecked(getItem(hwnd, IDC_HOTKEY_ACTION_UP))) {
+ s_action = new CInputFilter::CKeystrokeAction(info, false);
+ }
+ else {
+ free(info);
+ s_action = NULL;
+ }
+ }
+ }
+}
+
+bool
+CHotkeyOptions::CActionDialog::isDownUpAction()
+{
+ return (dynamic_cast(s_action) != NULL ||
+ dynamic_cast(s_action) != NULL);
+}
+
+BOOL CALLBACK
+CHotkeyOptions::CActionDialog::dlgProc(HWND hwnd,
+ UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ doInit(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ if (isDownUpAction()) {
+ s_onActivate = true;
+ }
+ EndDialog(hwnd, 1);
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_ON_ACTIVATE:
+ s_onActivate = true;
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_ON_DEACTIVATE:
+ s_onActivate = false;
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_DOWNUP:
+ case IDC_HOTKEY_ACTION_DOWN:
+ case IDC_HOTKEY_ACTION_UP:
+ convertAction(hwnd);
+ fillHotkey(hwnd);
+ updateControls(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_LOCK:
+ onLockAction(hwnd);
+ updateControls(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_SWITCH_TO:
+ onSwitchToAction(hwnd);
+ updateControls(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_SWITCH_IN:
+ onSwitchInAction(hwnd);
+ updateControls(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST:
+ onKeyboardBroadcastAction(hwnd);
+ updateControls(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_LOCK_LIST:
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ onLockAction(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_HOTKEY_ACTION_SWITCH_TO_LIST:
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ onSwitchToAction(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_HOTKEY_ACTION_SWITCH_IN_LIST:
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ onSwitchInAction(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST:
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ onKeyboardBroadcastAction(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_HOTKEY_ACTION_SCREENS:
+ CScreensDialog::doModal(hwnd, s_config,
+ dynamic_cast(s_action));
+ fillHotkey(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS: {
+ // convert screens to form that CScreenDialog::doModal() wants
+ IPlatformScreen::CKeyInfo* tmpInfo =
+ IPlatformScreen::CKeyInfo::alloc(0, 0, 0, 1, s_screens);
+ CInputFilter::CKeystrokeAction tmpAction(tmpInfo, true);
+
+ // get the screens
+ CScreensDialog::doModal(hwnd, s_config, &tmpAction);
+
+ // convert screens back
+ IPlatformScreen::CKeyInfo::split(
+ tmpAction.getInfo()->m_screens, s_screens);
+
+ // update
+ onKeyboardBroadcastAction(hwnd);
+ return TRUE;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+LRESULT CALLBACK
+CHotkeyOptions::CActionDialog::editProc(HWND hwnd,
+ UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ onButton(hwnd, kButtonLeft);
+ }
+ else {
+ SetFocus(hwnd);
+ }
+ return 0;
+
+ case WM_MBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ onButton(hwnd, kButtonMiddle);
+ }
+ return 0;
+
+ case WM_RBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ onButton(hwnd, kButtonRight);
+ }
+ return 0;
+
+ case WM_XBUTTONDOWN:
+ if (GetFocus() == hwnd) {
+ switch (HIWORD(wParam)) {
+ case XBUTTON1:
+ onButton(hwnd, kButtonExtra0 + 0);
+ break;
+
+ case XBUTTON2:
+ onButton(hwnd, kButtonExtra0 + 1);
+ break;
+ }
+ }
+ return 0;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ onKey(hwnd, wParam, lParam);
+ return 0;
+
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_XBUTTONUP:
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ case WM_DEADCHAR:
+ case WM_SYSDEADCHAR:
+ return 0;
+
+ case WM_SETFOCUS:
+ if (s_action != NULL) {
+ delete s_lastGoodAction;
+ s_lastGoodAction = s_action->clone();
+ }
+ break;
+
+ case WM_KILLFOCUS:
+ if (!isGoodAction()) {
+ delete s_action;
+ if (s_lastGoodAction != NULL) {
+ s_action = s_lastGoodAction->clone();
+ }
+ else {
+ s_action = NULL;
+ }
+ }
+ else if (s_action != NULL) {
+ delete s_lastGoodAction;
+ s_lastGoodAction = s_action->clone();
+ }
+ fillHotkey(GetParent(hwnd));
+ break;
+
+ case WM_GETDLGCODE:
+ return DLGC_WANTALLKEYS;
+
+ default:
+ break;
+ }
+ return CallWindowProc(s_editWndProc, hwnd, message, wParam, lParam);
+}
+
+
+//
+// CHotkeyOptions::CScreensDialog
+//
+
+CConfig* CHotkeyOptions::CScreensDialog::s_config = NULL;
+CInputFilter::CKeystrokeAction*
+ CHotkeyOptions::CScreensDialog::s_action = NULL;
+CHotkeyOptions::CScreensDialog::CScreens
+ CHotkeyOptions::CScreensDialog::s_nonTargets;
+CHotkeyOptions::CScreensDialog::CScreens
+ CHotkeyOptions::CScreensDialog::s_targets;
+CString CHotkeyOptions::CScreensDialog::s_allScreens;
+
+void
+CHotkeyOptions::CScreensDialog::doModal(HWND parent, CConfig* config,
+ CInputFilter::CKeystrokeAction* action)
+{
+ s_allScreens = getString(IDS_ALL_SCREENS);
+ s_config = config;
+ s_action = action;
+ DialogBox(s_instance, MAKEINTRESOURCE(IDD_HOTKEY_SCREENS),
+ parent, dlgProc);
+ s_config = NULL;
+ s_action = NULL;
+}
+
+void
+CHotkeyOptions::CScreensDialog::doInit(HWND hwnd)
+{
+ s_nonTargets.clear();
+ s_targets.clear();
+
+ // get screens from config
+ s_nonTargets.insert("*");
+ for (CConfig::const_iterator i = s_config->begin();
+ i != s_config->end(); ++i) {
+ s_nonTargets.insert(*i);
+ }
+
+ // get screens in action
+ IKeyState::CKeyInfo::split(s_action->getInfo()->m_screens, s_targets);
+
+ // remove screens in action from screens in config
+ for (CScreens::const_iterator i = s_targets.begin();
+ i != s_targets.end(); ++i) {
+ s_nonTargets.erase(*i);
+ }
+
+ // fill dialog
+ fillScreens(hwnd);
+ updateControls(hwnd);
+}
+
+void
+CHotkeyOptions::CScreensDialog::doFini(HWND)
+{
+ // put screens into action
+ const IPlatformScreen::CKeyInfo* oldInfo = s_action->getInfo();
+ IPlatformScreen::CKeyInfo* newInfo =
+ IKeyState::CKeyInfo::alloc(oldInfo->m_key,
+ oldInfo->m_mask, 0, 0, s_targets);
+ s_action->adoptInfo(newInfo);
+}
+
+void
+CHotkeyOptions::CScreensDialog::fillScreens(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_SCREENS_SRC);
+ SendMessage(child, LB_RESETCONTENT, 0, 0);
+ for (CScreens::const_iterator i = s_nonTargets.begin();
+ i != s_nonTargets.end(); ++i) {
+ CString name = *i;
+ if (name == "*") {
+ name = s_allScreens;
+ }
+ SendMessage(child, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)name.c_str());
+ }
+
+ child = getItem(hwnd, IDC_HOTKEY_SCREENS_DST);
+ SendMessage(child, LB_RESETCONTENT, 0, 0);
+ for (CScreens::const_iterator i = s_targets.begin();
+ i != s_targets.end(); ++i) {
+ CString name = *i;
+ if (name == "*") {
+ name = s_allScreens;
+ }
+ SendMessage(child, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)name.c_str());
+ }
+ if (s_targets.empty()) {
+ // if no targets then add a special item so the user knows
+ // what'll happen
+ CString activeScreenLabel = getString(IDS_ACTIVE_SCREEN);
+ SendMessage(child, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)activeScreenLabel.c_str());
+ }
+}
+
+void
+CHotkeyOptions::CScreensDialog::updateControls(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_HOTKEY_SCREENS_SRC);
+ bool canAdd = (SendMessage(child, LB_GETSELCOUNT, 0, 0) != 0);
+ child = getItem(hwnd, IDC_HOTKEY_SCREENS_DST);
+ bool canRemove = (!s_targets.empty() &&
+ (SendMessage(child, LB_GETSELCOUNT, 0, 0) != 0));
+
+ enableItem(hwnd, IDC_HOTKEY_SCREENS_ADD, canAdd);
+ enableItem(hwnd, IDC_HOTKEY_SCREENS_REMOVE, canRemove);
+}
+
+void
+CHotkeyOptions::CScreensDialog::add(HWND hwnd)
+{
+ CScreens selected;
+ getSelected(hwnd, IDC_HOTKEY_SCREENS_SRC, s_nonTargets, selected);
+ for (CScreens::const_iterator i = selected.begin();
+ i != selected.end(); ++i) {
+ s_targets.insert(*i);
+ s_nonTargets.erase(*i);
+ }
+ fillScreens(hwnd);
+ updateControls(hwnd);
+}
+
+void
+CHotkeyOptions::CScreensDialog::remove(HWND hwnd)
+{
+ CScreens selected;
+ getSelected(hwnd, IDC_HOTKEY_SCREENS_DST, s_targets, selected);
+ for (CScreens::const_iterator i = selected.begin();
+ i != selected.end(); ++i) {
+ s_nonTargets.insert(*i);
+ s_targets.erase(*i);
+ }
+ fillScreens(hwnd);
+ updateControls(hwnd);
+}
+
+void
+CHotkeyOptions::CScreensDialog::getSelected(HWND hwnd, UINT id,
+ const CScreens& inScreens, CScreens& outScreens)
+{
+ // get the selected item indices
+ HWND child = getItem(hwnd, id);
+ UInt32 n = (UInt32)SendMessage(child, LB_GETSELCOUNT, 0, 0);
+ int* index = new int[n];
+ SendMessage(child, LB_GETSELITEMS, (WPARAM)n, (LPARAM)index);
+
+ // get the items in a vector
+ std::vector tmpList;
+ for (CScreens::const_iterator i = inScreens.begin();
+ i != inScreens.end(); ++i) {
+ tmpList.push_back(*i);
+ }
+
+ // get selected items into the output set
+ outScreens.clear();
+ for (UInt32 i = 0; i < n; ++i) {
+ outScreens.insert(tmpList[index[i]]);
+ }
+
+ // clean up
+ delete[] index;
+}
+
+BOOL CALLBACK
+CHotkeyOptions::CScreensDialog::dlgProc(HWND hwnd,
+ UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ doInit(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ doFini(hwnd);
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDC_HOTKEY_SCREENS_ADD:
+ add(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_SCREENS_REMOVE:
+ remove(hwnd);
+ return TRUE;
+
+ case IDC_HOTKEY_SCREENS_SRC:
+ case IDC_HOTKEY_SCREENS_DST:
+ switch (HIWORD(wParam)) {
+ case LBN_SELCANCEL:
+ case LBN_SELCHANGE:
+ updateControls(hwnd);
+ return TRUE;
+ }
+ break;
+ }
+ break;
+
+ case WM_CTLCOLORLISTBOX:
+ if (s_targets.empty() &&
+ (HWND)lParam == getItem(hwnd, IDC_HOTKEY_SCREENS_DST)) {
+ // override colors
+ HDC dc = (HDC)wParam;
+ SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
+ return (BOOL)GetSysColorBrush(COLOR_WINDOW);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/cmd/launcher/CHotkeyOptions.h b/cmd/launcher/CHotkeyOptions.h
new file mode 100644
index 00000000..dec5367a
--- /dev/null
+++ b/cmd/launcher/CHotkeyOptions.h
@@ -0,0 +1,227 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2006 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CHOTKEYOPTIONS_H
+#define CHOTKEYOPTIONS_H
+
+#include "CString.h"
+#include "KeyTypes.h"
+#include "MouseTypes.h"
+#include "CInputFilter.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+class CConfig;
+
+//! Hotkey options dialog for Microsoft Windows launcher
+class CHotkeyOptions {
+public:
+ CHotkeyOptions(HWND parent, CConfig*);
+ ~CHotkeyOptions();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user.
+ */
+ void doModal();
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //@}
+
+private:
+ void doInit(HWND hwnd);
+
+ void fillHotkeys(HWND hwnd, UInt32 select = (UInt32)-1);
+ void updateHotkeysControls(HWND hwnd);
+
+ void addHotkey(HWND hwnd);
+ void removeHotkey(HWND hwnd);
+ void editHotkey(HWND hwnd);
+
+ void fillActions(HWND hwnd, UInt32 select = (UInt32)-1);
+ void updateActionsControls(HWND hwnd);
+
+ void addAction(HWND hwnd);
+ void removeAction(HWND hwnd);
+ void editAction(HWND hwnd);
+
+ bool editCondition(HWND hwnd, CInputFilter::CCondition*&);
+ bool editAction(HWND hwnd, CInputFilter::CAction*&,
+ bool& onActivate);
+
+ void openRule(HWND hwnd);
+ void closeRule(HWND hwnd);
+ UInt32 findMatchingAction(
+ const CInputFilter::CKeystrokeAction*) const;
+ UInt32 findMatchingAction(
+ const CInputFilter::CMouseButtonAction*) const;
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+ // special actions we use to combine matching down/up actions into a
+ // single action for the convenience of the user.
+ class CKeystrokeDownUpAction : public CInputFilter::CKeystrokeAction {
+ public:
+ CKeystrokeDownUpAction(IPlatformScreen::CKeyInfo* adoptedInfo) :
+ CInputFilter::CKeystrokeAction(adoptedInfo, true) { }
+
+ // CAction overrides
+ virtual CInputFilter::CAction* clone() const
+ {
+ IKeyState::CKeyInfo* info = IKeyState::CKeyInfo::alloc(*getInfo());
+ return new CKeystrokeDownUpAction(info);
+ }
+
+ protected:
+ // CKeystrokeAction overrides
+ virtual const char* formatName() const { return "keystroke"; }
+ };
+ class CMouseButtonDownUpAction : public CInputFilter::CMouseButtonAction {
+ public:
+ CMouseButtonDownUpAction(IPrimaryScreen::CButtonInfo* adoptedInfo) :
+ CInputFilter::CMouseButtonAction(adoptedInfo, true) { }
+
+ // CAction overrides
+ virtual CInputFilter::CAction* clone() const
+ {
+ IPlatformScreen::CButtonInfo* info =
+ IPrimaryScreen::CButtonInfo::alloc(*getInfo());
+ return new CMouseButtonDownUpAction(info);
+ }
+
+ protected:
+ // CMouseButtonAction overrides
+ virtual const char* formatName() const { return "mousebutton"; }
+ };
+
+ class CConditionDialog {
+ public:
+ static bool doModal(HWND parent, CInputFilter::CCondition*&);
+
+ private:
+ static void doInit(HWND hwnd);
+ static void fillHotkey(HWND hwnd);
+
+ static void onButton(HWND hwnd, ButtonID button);
+ static void onKey(HWND hwnd, WPARAM wParam, LPARAM lParam);
+ static KeyID getChar(WPARAM wParam, LPARAM lParam);
+ static KeyModifierMask
+ getModifiers();
+
+ static bool isGoodCondition();
+
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+ static LRESULT CALLBACK editProc(HWND hwnd, UINT, WPARAM, LPARAM);
+
+ private:
+ static CInputFilter::CCondition*
+ s_condition;
+ static CInputFilter::CCondition*
+ s_lastGoodCondition;
+ static WNDPROC s_editWndProc;
+ };
+
+ class CActionDialog {
+ public:
+ static bool doModal(HWND parent, CConfig* config,
+ CInputFilter::CAction*&, bool& onActivate);
+
+ private:
+ static void doInit(HWND hwnd);
+ static void fillHotkey(HWND hwnd);
+ static void updateControls(HWND hwnd);
+
+ static void onButton(HWND hwnd, ButtonID button);
+ static void onKey(HWND hwnd, WPARAM wParam, LPARAM lParam);
+ static void onLockAction(HWND hwnd);
+ static void onSwitchToAction(HWND hwnd);
+ static void onSwitchInAction(HWND hwnd);
+ static void onKeyboardBroadcastAction(HWND hwnd);
+
+ static KeyID getChar(WPARAM wParam, LPARAM lParam);
+ static KeyModifierMask
+ getModifiers();
+
+ static bool isGoodAction();
+ static void convertAction(HWND hwnd);
+
+ static bool isDownUpAction();
+
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+ static LRESULT CALLBACK editProc(HWND hwnd, UINT, WPARAM, LPARAM);
+
+ private:
+ static CConfig* s_config;
+ static bool s_onActivate;
+ static CInputFilter::CAction*
+ s_action;
+ static CInputFilter::CAction*
+ s_lastGoodAction;
+ static std::set s_screens;
+ static WNDPROC s_editWndProc;
+ };
+
+// public to allow CActionDialog to use it
+public:
+ class CScreensDialog {
+ public:
+ static void doModal(HWND parent, CConfig* config,
+ CInputFilter::CKeystrokeAction*);
+
+ // public due to compiler brokenness
+ typedef std::set CScreens;
+
+ private:
+
+ static void doInit(HWND hwnd);
+ static void doFini(HWND hwnd);
+ static void fillScreens(HWND hwnd);
+ static void updateControls(HWND hwnd);
+
+ static void add(HWND hwnd);
+ static void remove(HWND hwnd);
+
+ static void getSelected(HWND hwnd, UINT id,
+ const CScreens& inScreens, CScreens& outScreens);
+
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+ private:
+ static CConfig* s_config;
+ static CInputFilter::CKeystrokeAction* s_action;
+ static CScreens s_nonTargets;
+ static CScreens s_targets;
+ static CString s_allScreens;
+ };
+
+private:
+ static CHotkeyOptions* s_singleton;
+
+ HWND m_parent;
+ CConfig* m_config;
+ CInputFilter* m_inputFilter;
+ CInputFilter::CRule m_activeRule;
+ UInt32 m_activeRuleIndex;
+};
+
+#endif
diff --git a/cmd/launcher/CInfo.cpp b/cmd/launcher/CInfo.cpp
new file mode 100644
index 00000000..669da0e2
--- /dev/null
+++ b/cmd/launcher/CInfo.cpp
@@ -0,0 +1,111 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2006 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 "ProtocolTypes.h"
+#include "CStringUtil.h"
+#include "Version.h"
+#include "CArch.h"
+#include "CInfo.h"
+#include "LaunchUtil.h"
+#include "resource.h"
+
+//
+// CInfo
+//
+
+CInfo* CInfo::s_singleton = NULL;
+
+CInfo::CInfo(HWND parent) :
+ m_parent(parent)
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+}
+
+CInfo::~CInfo()
+{
+ s_singleton = NULL;
+}
+
+void
+CInfo::doModal()
+{
+ // do dialog
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_INFO),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this);
+}
+
+void
+CInfo::init(HWND hwnd)
+{
+ // collect info
+ CString version =
+ CStringUtil::format(getString(IDS_TITLE).c_str(), VERSION);
+ CString hostname = ARCH->getHostName();
+ CString address = ARCH->addrToString(ARCH->nameToAddr(hostname));
+ CString userConfig = ARCH->getUserDirectory();
+ if (!userConfig.empty()) {
+ userConfig = ARCH->concatPath(userConfig, CONFIG_NAME);
+ }
+ CString sysConfig = ARCH->getSystemDirectory();
+ if (!sysConfig.empty()) {
+ sysConfig = ARCH->concatPath(sysConfig, CONFIG_NAME);
+ }
+
+ // set info
+ HWND child;
+ child = getItem(hwnd, IDC_INFO_VERSION);
+ setWindowText(child, version);
+ child = getItem(hwnd, IDC_INFO_HOSTNAME);
+ setWindowText(child, hostname);
+ child = getItem(hwnd, IDC_INFO_IP_ADDRESS);
+ setWindowText(child, address);
+ child = getItem(hwnd, IDC_INFO_USER_CONFIG);
+ setWindowText(child, userConfig);
+ child = getItem(hwnd, IDC_INFO_SYS_CONFIG);
+ setWindowText(child, sysConfig);
+
+ // focus on okay button
+ SetFocus(getItem(hwnd, IDOK));
+}
+
+BOOL
+CInfo::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ init(hwnd);
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CInfo::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
diff --git a/cmd/launcher/CInfo.h b/cmd/launcher/CInfo.h
new file mode 100644
index 00000000..2d85ec7d
--- /dev/null
+++ b/cmd/launcher/CInfo.h
@@ -0,0 +1,57 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2006 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CINFO_H
+#define CINFO_H
+
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+//! Info dialog for Microsoft Windows launcher
+class CInfo {
+public:
+ CInfo(HWND parent);
+ ~CInfo();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user.
+ */
+ void doModal();
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //@}
+
+private:
+ void init(HWND hwnd);
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+private:
+ static CInfo* s_singleton;
+
+ HWND m_parent;
+};
+
+#endif
diff --git a/cmd/launcher/CScreensLinks.cpp b/cmd/launcher/CScreensLinks.cpp
new file mode 100644
index 00000000..c7e58a04
--- /dev/null
+++ b/cmd/launcher/CScreensLinks.cpp
@@ -0,0 +1,855 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CConfig.h"
+#include "ProtocolTypes.h"
+#include "CStringUtil.h"
+#include "CArch.h"
+#include "CScreensLinks.h"
+#include "CAddScreen.h"
+#include "LaunchUtil.h"
+#include "resource.h"
+
+//
+// CScreensLinks
+//
+
+CScreensLinks* CScreensLinks::s_singleton = NULL;
+
+CScreensLinks::CScreensLinks(HWND parent, CConfig* config) :
+ m_parent(parent),
+ m_mainConfig(config),
+ m_config(&m_scratchConfig)
+{
+ assert(s_singleton == NULL);
+ s_singleton = this;
+
+ // get formatting strings
+ m_linkFormat = getString(IDS_LINK_FORMAT);
+ m_intervalFormat = getString(IDS_LINK_INTERVAL_FORMAT);
+ m_newLinkLabel = getString(IDS_NEW_LINK);
+ m_sideLabel[kLeft - kFirstDirection] = getString(IDS_SIDE_LEFT);
+ m_sideLabel[kRight - kFirstDirection] = getString(IDS_SIDE_RIGHT);
+ m_sideLabel[kTop - kFirstDirection] = getString(IDS_SIDE_TOP);
+ m_sideLabel[kBottom - kFirstDirection] = getString(IDS_SIDE_BOTTOM);
+
+ // GDI objects
+ m_redPen = CreatePen(PS_INSIDEFRAME, 1, RGB(255, 0, 0));
+}
+
+CScreensLinks::~CScreensLinks()
+{
+ DeleteObject(m_redPen);
+ s_singleton = NULL;
+}
+
+void
+CScreensLinks::doModal()
+{
+ // do dialog
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_SCREENS_LINKS),
+ m_parent, (DLGPROC)dlgProc, (LPARAM)this);
+}
+
+void
+CScreensLinks::init(HWND hwnd)
+{
+ // get initial config
+ m_scratchConfig = *m_mainConfig;
+
+ // fill side list box (in EDirection order)
+ HWND child = getItem(hwnd, IDC_SCREENS_SRC_SIDE);
+ SendMessage(child, CB_ADDSTRING, 0, (LPARAM)TEXT("---"));
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_LEFT).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_RIGHT).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_TOP).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_EDGE_BOTTOM).c_str());
+
+ // create error boxes
+ m_srcSideError = createErrorBox(hwnd);
+ m_srcScreenError = createErrorBox(hwnd);
+ m_dstScreenError = createErrorBox(hwnd);
+ resizeErrorBoxes();
+
+ m_selectedLink = -1;
+ m_editedLink = CEdgeLink();
+ m_edgeLinks.clear();
+ updateScreens(hwnd, "");
+ updateScreensControls(hwnd);
+ updateLinks(hwnd);
+ updateLinksControls(hwnd);
+}
+
+bool
+CScreensLinks::save(HWND /*hwnd*/)
+{
+ *m_mainConfig = m_scratchConfig;
+ return true;
+}
+
+BOOL
+CScreensLinks::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ init(hwnd);
+ return TRUE;
+
+ case WM_SIZE:
+ resizeErrorBoxes();
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ SetFocus(getItem(hwnd, IDOK));
+ if (save(hwnd)) {
+ EndDialog(hwnd, 0);
+ }
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDC_SCREENS_SCREENS:
+ switch (HIWORD(wParam)) {
+ case LBN_DBLCLK:
+ editScreen(hwnd);
+ return TRUE;
+
+ case LBN_SELCHANGE:
+ updateScreensControls(hwnd);
+ updateLinkView(hwnd);
+ return TRUE;
+
+ case LBN_SELCANCEL:
+ updateScreensControls(hwnd);
+ updateLinkView(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_SCREENS_ADD_SCREEN:
+ addScreen(hwnd);
+ return TRUE;
+
+ case IDC_SCREENS_REMOVE_SCREEN:
+ removeScreen(hwnd);
+ return TRUE;
+
+ case IDC_SCREENS_EDIT_SCREEN:
+ editScreen(hwnd);
+ return TRUE;
+
+ case IDC_SCREENS_LINKS:
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ editLink(hwnd);
+ return TRUE;
+
+ case LBN_SELCANCEL:
+ editLink(hwnd);
+ return TRUE;
+ }
+ break;
+
+ case IDC_SCREENS_ADD_LINK:
+ addLink(hwnd);
+ return TRUE;
+
+ case IDC_SCREENS_REMOVE_LINK:
+ removeLink(hwnd);
+ return TRUE;
+
+ case IDC_SCREENS_SRC_SIDE:
+ switch (HIWORD(wParam)) {
+ case CBN_SELCHANGE:
+ changeSrcSide(hwnd);
+ break;
+ }
+ break;
+
+ case IDC_SCREENS_SRC_SCREEN:
+ switch (HIWORD(wParam)) {
+ case CBN_SELCHANGE:
+ changeSrcScreen(hwnd);
+ break;
+ }
+ break;
+
+ case IDC_SCREENS_DST_SCREEN:
+ switch (HIWORD(wParam)) {
+ case CBN_SELCHANGE:
+ changeDstScreen(hwnd);
+ break;
+ }
+ break;
+
+ case IDC_SCREENS_SRC_START:
+ switch (HIWORD(wParam)) {
+ case EN_KILLFOCUS:
+ changeIntervalStart(hwnd, LOWORD(wParam),
+ m_editedLink.m_srcInterval);
+ break;
+ }
+ break;
+
+ case IDC_SCREENS_SRC_END:
+ switch (HIWORD(wParam)) {
+ case EN_KILLFOCUS:
+ changeIntervalEnd(hwnd, LOWORD(wParam),
+ m_editedLink.m_srcInterval);
+ break;
+ }
+ break;
+
+ case IDC_SCREENS_DST_START:
+ switch (HIWORD(wParam)) {
+ case EN_KILLFOCUS:
+ changeIntervalStart(hwnd, LOWORD(wParam),
+ m_editedLink.m_dstInterval);
+ break;
+ }
+ break;
+
+ case IDC_SCREENS_DST_END:
+ switch (HIWORD(wParam)) {
+ case EN_KILLFOCUS:
+ changeIntervalEnd(hwnd, LOWORD(wParam),
+ m_editedLink.m_dstInterval);
+ break;
+ }
+ break;
+ }
+
+ break;
+
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_SCREENS_OVERLAP_ERROR:
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE));
+ SetTextColor((HDC)wParam, RGB(255, 0, 0));
+ return (BOOL)GetSysColorBrush(COLOR_3DFACE);
+ }
+ break;
+
+ // error outlines
+ case WM_DRAWITEM: {
+ DRAWITEMSTRUCT* di = (DRAWITEMSTRUCT*)lParam;
+ if (di->CtlType == ODT_STATIC) {
+ HGDIOBJ oldPen = SelectObject(di->hDC, m_redPen);
+ HGDIOBJ oldBrush = SelectObject(di->hDC,
+ GetStockObject(NULL_BRUSH));
+ Rectangle(di->hDC, di->rcItem.left, di->rcItem.top,
+ di->rcItem.right, di->rcItem.bottom);
+ SelectObject(di->hDC, oldPen);
+ SelectObject(di->hDC, oldBrush);
+ return TRUE;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+BOOL CALLBACK
+CScreensLinks::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
+}
+
+CString
+CScreensLinks::getSelectedScreen(HWND hwnd) const
+{
+ HWND child = getItem(hwnd, IDC_SCREENS_SCREENS);
+ LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
+ if (index == LB_ERR) {
+ return CString();
+ }
+
+ LRESULT size = SendMessage(child, LB_GETTEXTLEN, index, 0);
+ char* buffer = new char[size + 1];
+ SendMessage(child, LB_GETTEXT, index, (LPARAM)buffer);
+ buffer[size] = '\0';
+ CString result(buffer);
+ delete[] buffer;
+ return result;
+}
+
+void
+CScreensLinks::addScreen(HWND hwnd)
+{
+ CAddScreen dialog(hwnd, m_config, "");
+ if (dialog.doModal()) {
+ updateScreens(hwnd, dialog.getName());
+ updateScreensControls(hwnd);
+ updateLinks(hwnd);
+ updateLinksControls(hwnd);
+ }
+}
+
+void
+CScreensLinks::editScreen(HWND hwnd)
+{
+ CString oldName = getSelectedScreen(hwnd);
+ CAddScreen dialog(hwnd, m_config, oldName);
+ if (dialog.doModal()) {
+ CString newName = dialog.getName();
+
+ // rename screens in the edge list
+ if (newName != oldName) {
+ for (size_t i = 0; i < m_edgeLinks.size(); ++i) {
+ m_edgeLinks[i].rename(oldName, newName);
+ }
+ m_editedLink.rename(oldName, newName);
+ }
+
+ updateScreens(hwnd, newName);
+ updateScreensControls(hwnd);
+ updateLinks(hwnd);
+ updateLinksControls(hwnd);
+ }
+}
+
+void
+CScreensLinks::removeScreen(HWND hwnd)
+{
+ // remove screen from config (this also removes aliases)
+ m_config->removeScreen(getSelectedScreen(hwnd));
+
+ // update dialog
+ updateScreens(hwnd, "");
+ updateScreensControls(hwnd);
+ updateLinks(hwnd);
+ updateLinksControls(hwnd);
+}
+
+void
+CScreensLinks::addLink(HWND hwnd)
+{
+ if (m_editedLink.connect(m_config)) {
+ m_editedLink = CEdgeLink();
+ updateLinks(hwnd);
+ updateLinksControls(hwnd);
+ }
+}
+
+void
+CScreensLinks::editLink(HWND hwnd)
+{
+ // get selection
+ HWND child = getItem(hwnd, IDC_SCREENS_LINKS);
+ DWORD i = SendMessage(child, LB_GETCURSEL, 0, 0);
+ if (i != LB_ERR && i != (DWORD)m_edgeLinks.size()) {
+ // existing link
+ m_selectedLink = (SInt32)SendMessage(child, LB_GETITEMDATA, i, 0);
+ m_editedLink = m_edgeLinks[m_selectedLink];
+ }
+ else {
+ // new link
+ m_selectedLink = -1;
+ m_editedLink = CEdgeLink();
+ }
+ updateLinksControls(hwnd);
+}
+
+void
+CScreensLinks::removeLink(HWND hwnd)
+{
+ if (m_editedLink.disconnect(m_config)) {
+ updateLinks(hwnd);
+ updateLinksControls(hwnd);
+ }
+}
+
+void
+CScreensLinks::updateScreens(HWND hwnd, const CString& selectName)
+{
+ HWND child;
+
+ // set screen list
+ child = getItem(hwnd, IDC_SCREENS_SCREENS);
+ SendMessage(child, LB_RESETCONTENT, 0, 0);
+ for (CConfig::const_iterator index = m_config->begin();
+ index != m_config->end(); ) {
+ const CString& name = *index;
+ ++index;
+ if (index != m_config->end()) {
+ SendMessage(child, LB_INSERTSTRING,
+ (WPARAM)-1, (LPARAM)name.c_str());
+ }
+ else {
+ SendMessage(child, LB_ADDSTRING, 0, (LPARAM)name.c_str());
+ }
+ }
+
+ // find the named screen
+ if (!selectName.empty()) {
+ DWORD i = SendMessage(child, LB_FINDSTRINGEXACT,
+ (UINT)-1, (LPARAM)selectName.c_str());
+ if (i != LB_ERR) {
+ SendMessage(child, LB_SETSEL, TRUE, i);
+ }
+ }
+}
+
+void
+CScreensLinks::updateScreensControls(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_SCREENS_SCREENS);
+ bool screenSelected = (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR);
+
+ enableItem(hwnd, IDC_SCREENS_ADD_SCREEN, TRUE);
+ enableItem(hwnd, IDC_SCREENS_EDIT_SCREEN, screenSelected);
+ enableItem(hwnd, IDC_SCREENS_REMOVE_SCREEN, screenSelected);
+}
+
+void
+CScreensLinks::updateLinks(HWND hwnd)
+{
+ HWND links = getItem(hwnd, IDC_SCREENS_LINKS);
+ HWND srcScreens = getItem(hwnd, IDC_SCREENS_SRC_SCREEN);
+ HWND dstScreens = getItem(hwnd, IDC_SCREENS_DST_SCREEN);
+
+ // get old selection
+ CEdgeLink oldLink;
+ if (m_selectedLink != -1) {
+ oldLink = m_edgeLinks[m_selectedLink];
+ }
+
+ // clear links and screens
+ SendMessage(links, LB_RESETCONTENT, 0, 0);
+ SendMessage(srcScreens, CB_RESETCONTENT, 0, 0);
+ SendMessage(dstScreens, CB_RESETCONTENT, 0, 0);
+ m_edgeLinks.clear();
+
+ // add "no screen" items
+ SendMessage(srcScreens, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)TEXT("----"));
+ SendMessage(dstScreens, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)TEXT("----"));
+
+ // add links and screens
+ for (CConfig::const_iterator i = m_config->begin();
+ i != m_config->end(); ++i) {
+ const CString& name = *i;
+
+ // add screen
+ SendMessage(srcScreens, CB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)name.c_str());
+ SendMessage(dstScreens, CB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)name.c_str());
+
+ // add links for screen
+ for (CConfig::link_const_iterator j = m_config->beginNeighbor(name),
+ n = m_config->endNeighbor(name);
+ j != n; ++j) {
+ DWORD k = m_edgeLinks.size();
+ m_edgeLinks.push_back(CEdgeLink(name, *j));
+ SendMessage(links, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)formatLink(m_edgeLinks.back()).c_str());
+ SendMessage(links, LB_SETITEMDATA, (WPARAM)k, (LPARAM)k);
+ }
+ }
+
+ // add "new link" item to sort
+ SendMessage(links, LB_ADDSTRING, 0, (LPARAM)m_newLinkLabel.c_str());
+
+ // remove the "new link" item then insert it on the end
+ DWORD i = SendMessage(links, LB_FINDSTRINGEXACT,
+ (UINT)-1, (LPARAM)m_newLinkLabel.c_str());
+ if (i != LB_ERR) {
+ SendMessage(links, LB_DELETESTRING, i, 0);
+ }
+ SendMessage(links, LB_INSERTSTRING, (WPARAM)-1,
+ (LPARAM)getString(IDS_NEW_LINK).c_str());
+ SendMessage(links, LB_SETITEMDATA, (WPARAM)m_edgeLinks.size(),
+ (LPARAM)-1);
+
+ // select the same link as before
+ SendMessage(links, LB_SETCURSEL, (WPARAM)m_edgeLinks.size(), 0);
+ if (m_selectedLink != -1) {
+ m_selectedLink = -1;
+ for (size_t j = 0; j < m_edgeLinks.size(); ++j) {
+ if (m_edgeLinks[j] == oldLink) {
+ // found matching link
+ m_selectedLink = j;
+ for (size_t k = 0; k < m_edgeLinks.size(); ++k) {
+ if (SendMessage(links, LB_GETITEMDATA, k, 0) == (int)j) {
+ SendMessage(links, LB_SETCURSEL, k, 0);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ // if we can't find the link anymore then reset edited link
+ if (m_selectedLink == -1) {
+ m_editedLink = CEdgeLink();
+ }
+ }
+}
+
+void
+CScreensLinks::updateLinksControls(HWND hwnd)
+{
+ // get selection. select "new link" if nothing is selected.
+ HWND child = getItem(hwnd, IDC_SCREENS_LINKS);
+ if (m_selectedLink == -1) {
+ SendMessage(child, LB_SETCURSEL, m_edgeLinks.size(), 0);
+ }
+
+ // enable/disable remove button
+ enableItem(hwnd, IDC_SCREENS_REMOVE_LINK, m_selectedLink != -1);
+
+ // fill link entry controls from m_editedLink
+ updateLinkEditControls(hwnd, m_editedLink);
+ updateLinkValid(hwnd, m_editedLink);
+ updateLinkView(hwnd);
+}
+
+void
+CScreensLinks::changeSrcSide(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_SCREENS_SRC_SIDE);
+ m_editedLink.m_srcSide = (EDirection)SendMessage(child, CB_GETCURSEL, 0, 0);
+ updateLink(hwnd);
+}
+
+void
+CScreensLinks::changeSrcScreen(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_SCREENS_SRC_SCREEN);
+ m_editedLink.m_srcName = getWindowText(child);
+ updateLink(hwnd);
+}
+
+void
+CScreensLinks::changeDstScreen(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_SCREENS_DST_SCREEN);
+ m_editedLink.m_dstName = getWindowText(child);
+ updateLink(hwnd);
+}
+
+void
+CScreensLinks::changeIntervalStart(HWND hwnd, int id, CConfig::CInterval& i)
+{
+ int x = (int)GetDlgItemInt(hwnd, id, NULL, FALSE);
+ if (x < 0) {
+ x = 0;
+ }
+ else if (x > 99) {
+ x = 99;
+ }
+
+ i.first = 0.01f * (float)x;
+ if (i.first >= i.second) {
+ i.second = 0.01f * (float)(x + 1);
+ }
+
+ updateLinkIntervalControls(hwnd, m_editedLink);
+ updateLink(hwnd);
+}
+
+void
+CScreensLinks::changeIntervalEnd(HWND hwnd, int id, CConfig::CInterval& i)
+{
+ int x = (int)GetDlgItemInt(hwnd, id, NULL, FALSE);
+ if (x < 1) {
+ x = 1;
+ }
+ else if (x > 100) {
+ x = 100;
+ }
+
+ i.second = 0.01f * (float)x;
+ if (i.first >= i.second) {
+ i.first = 0.01f * (float)(x - 1);
+ }
+
+ updateLinkIntervalControls(hwnd, m_editedLink);
+ updateLink(hwnd);
+}
+
+void
+CScreensLinks::selectScreen(HWND hwnd, int id, const CString& name)
+{
+ HWND child = getItem(hwnd, id);
+ DWORD i = SendMessage(child, CB_FINDSTRINGEXACT, (WPARAM)-1,
+ (LPARAM)name.c_str());
+ if (i == CB_ERR) {
+ // no match, select no screen
+ SendMessage(child, CB_SETCURSEL, 0, 0);
+ }
+ else {
+ SendMessage(child, CB_SETCURSEL, i, 0);
+ }
+}
+
+void
+CScreensLinks::updateLinkEditControls(HWND hwnd, const CEdgeLink& link)
+{
+ // fill link entry controls from link
+ HWND child = getItem(hwnd, IDC_SCREENS_SRC_SIDE);
+ SendMessage(child, CB_SETCURSEL, link.m_srcSide, 0);
+ selectScreen(hwnd, IDC_SCREENS_SRC_SCREEN, link.m_srcName);
+ selectScreen(hwnd, IDC_SCREENS_DST_SCREEN, link.m_dstName);
+ updateLinkIntervalControls(hwnd, link);
+}
+
+void
+CScreensLinks::updateLinkIntervalControls(HWND hwnd, const CEdgeLink& link)
+{
+ HWND child;
+
+ // src interval
+ child = getItem(hwnd, IDC_SCREENS_SRC_START);
+ setWindowText(child, formatIntervalValue(link.m_srcInterval.first));
+ child = getItem(hwnd, IDC_SCREENS_SRC_END);
+ setWindowText(child, formatIntervalValue(link.m_srcInterval.second));
+
+ // dst interval
+ child = getItem(hwnd, IDC_SCREENS_DST_START);
+ setWindowText(child, formatIntervalValue(link.m_dstInterval.first));
+ child = getItem(hwnd, IDC_SCREENS_DST_END);
+ setWindowText(child, formatIntervalValue(link.m_dstInterval.second));
+}
+
+void
+CScreensLinks::updateLink(HWND hwnd)
+{
+ updateLinkValid(hwnd, m_editedLink);
+
+ // update link in config
+ if (m_selectedLink != -1 && m_editedLinkIsValid) {
+ // editing an existing link and entry is valid
+ if (m_edgeLinks[m_selectedLink].disconnect(m_config)) {
+ // successfully removed old link
+ if (!m_editedLink.connect(m_config)) {
+ // couldn't set new link so restore old link
+ m_edgeLinks[m_selectedLink].connect(m_config);
+ }
+ else {
+ m_edgeLinks[m_selectedLink] = m_editedLink;
+ updateLinks(hwnd);
+ updateLinkEditControls(hwnd, m_editedLink);
+ }
+ }
+ }
+
+ updateLinkView(hwnd);
+}
+
+void
+CScreensLinks::updateLinkValid(HWND hwnd, const CEdgeLink& link)
+{
+ m_editedLinkIsValid = true;
+
+ // check source side and screen
+ if (link.m_srcSide == kNoDirection) {
+ m_editedLinkIsValid = false;
+ ShowWindow(m_srcSideError, SW_SHOWNA);
+ }
+ else {
+ ShowWindow(m_srcSideError, SW_HIDE);
+ }
+ if (!m_config->isCanonicalName(link.m_srcName)) {
+ m_editedLinkIsValid = false;
+ ShowWindow(m_srcScreenError, SW_SHOWNA);
+ }
+ else {
+ ShowWindow(m_srcScreenError, SW_HIDE);
+ }
+
+ // check for overlap. if editing a link we must remove it, then
+ // check for overlap and restore the old link.
+ bool overlap = false;
+ if (m_editedLinkIsValid) {
+ if (m_selectedLink == -1) {
+ if (link.overlaps(m_config)) {
+ m_editedLinkIsValid = false;
+ overlap = true;
+ }
+ }
+ else {
+ if (m_edgeLinks[m_selectedLink].disconnect(m_config)) {
+ overlap = link.overlaps(m_config);
+ m_edgeLinks[m_selectedLink].connect(m_config);
+ if (overlap) {
+ m_editedLinkIsValid = false;
+ }
+ }
+ }
+ }
+ ShowWindow(getItem(hwnd, IDC_SCREENS_OVERLAP_ERROR),
+ overlap ? SW_SHOWNA : SW_HIDE);
+
+ // check dst screen
+ if (!m_config->isCanonicalName(link.m_dstName)) {
+ m_editedLinkIsValid = false;
+ ShowWindow(m_dstScreenError, SW_SHOWNA);
+ }
+ else {
+ ShowWindow(m_dstScreenError, SW_HIDE);
+ }
+
+ // update add link button
+ enableItem(hwnd, IDC_SCREENS_ADD_LINK,
+ m_selectedLink == -1 && m_editedLinkIsValid);
+}
+
+void
+CScreensLinks::updateLinkView(HWND /*hwnd*/)
+{
+ // XXX -- draw visual of selected screen, highlighting selected link
+}
+
+HWND
+CScreensLinks::createErrorBox(HWND parent)
+{
+ return CreateWindow(TEXT("STATIC"), TEXT(""),
+ WS_CHILD | SS_OWNERDRAW,
+ 0, 0, 1, 1,
+ parent, (HMENU)-1,
+ s_instance, NULL);
+}
+
+void
+CScreensLinks::resizeErrorBoxes()
+{
+ HWND hwnd = GetParent(m_srcSideError);
+ resizeErrorBox(m_srcSideError, getItem(hwnd, IDC_SCREENS_SRC_SIDE));
+ resizeErrorBox(m_srcScreenError, getItem(hwnd, IDC_SCREENS_SRC_SCREEN));
+ resizeErrorBox(m_dstScreenError, getItem(hwnd, IDC_SCREENS_DST_SCREEN));
+}
+
+void
+CScreensLinks::resizeErrorBox(HWND box, HWND assoc)
+{
+ RECT rect;
+ GetWindowRect(assoc, &rect);
+ MapWindowPoints(NULL, GetParent(box), (POINT*)&rect, 2);
+ SetWindowPos(box, HWND_TOP, rect.left - 1, rect.top - 1,
+ rect.right - rect.left + 2,
+ rect.bottom - rect.top + 2, SWP_NOACTIVATE);
+}
+
+CString
+CScreensLinks::formatIntervalValue(float x) const
+{
+ return CStringUtil::print("%d", (int)(x * 100.0f + 0.5f));
+}
+
+CString
+CScreensLinks::formatInterval(const CConfig::CInterval& i) const
+{
+ if (i.first == 0.0f && i.second == 1.0f) {
+ return "";
+ }
+ else {
+ CString start = formatIntervalValue(i.first);
+ CString end = formatIntervalValue(i.second);
+ return CStringUtil::format(m_intervalFormat.c_str(),
+ start.c_str(), end.c_str());
+ }
+}
+
+CString
+CScreensLinks::formatLink(const CEdgeLink& link) const
+{
+ CString srcInterval = formatInterval(link.m_srcInterval);
+ CString dstInterval = formatInterval(link.m_dstInterval);
+ return CStringUtil::format(m_linkFormat.c_str(),
+ link.m_srcName.c_str(), srcInterval.c_str(),
+ m_sideLabel[link.m_srcSide - kFirstDirection].c_str(),
+ link.m_dstName.c_str(), dstInterval.c_str());
+}
+
+//
+// CScreensLinks::CEdgeLink
+//
+
+CScreensLinks::CEdgeLink::CEdgeLink() :
+ m_srcName(),
+ m_srcSide(kNoDirection),
+ m_srcInterval(0.0f, 1.0f),
+ m_dstName(),
+ m_dstInterval(0.0f, 1.0f)
+{
+ // do nothing
+}
+
+CScreensLinks::CEdgeLink::CEdgeLink(const CString& name,
+ const CConfigLink& link) :
+ m_srcName(name),
+ m_srcSide(link.first.getSide()),
+ m_srcInterval(link.first.getInterval()),
+ m_dstName(link.second.getName()),
+ m_dstInterval(link.second.getInterval())
+{
+ // do nothing
+}
+
+bool
+CScreensLinks::CEdgeLink::connect(CConfig* config)
+{
+ return config->connect(m_srcName, m_srcSide,
+ m_srcInterval.first, m_srcInterval.second,
+ m_dstName,
+ m_dstInterval.first, m_dstInterval.second);
+}
+
+bool
+CScreensLinks::CEdgeLink::disconnect(CConfig* config)
+{
+ return config->disconnect(m_srcName, m_srcSide, 0.5f *
+ (m_srcInterval.first + m_srcInterval.second));
+}
+
+void
+CScreensLinks::CEdgeLink::rename(const CString& oldName, const CString& newName)
+{
+ if (m_srcName == oldName) {
+ m_srcName = newName;
+ }
+ if (m_dstName == oldName) {
+ m_dstName = newName;
+ }
+}
+
+bool
+CScreensLinks::CEdgeLink::overlaps(const CConfig* config) const
+{
+ return config->hasNeighbor(m_srcName, m_srcSide,
+ m_srcInterval.first, m_srcInterval.second);
+}
+
+bool
+CScreensLinks::CEdgeLink::operator==(const CEdgeLink& x) const
+{
+ return (m_srcName == x.m_srcName &&
+ m_srcSide == x.m_srcSide &&
+ m_srcInterval == x.m_srcInterval &&
+ m_dstName == x.m_dstName &&
+ m_dstInterval == x.m_dstInterval);
+}
diff --git a/cmd/launcher/CScreensLinks.h b/cmd/launcher/CScreensLinks.h
new file mode 100644
index 00000000..8ffd0089
--- /dev/null
+++ b/cmd/launcher/CScreensLinks.h
@@ -0,0 +1,138 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CSCREENSLINKS_H
+#define CSCREENSLINKS_H
+
+#include "CConfig.h"
+#include "ProtocolTypes.h"
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+
+//! Screens and links dialog for Microsoft Windows launcher
+class CScreensLinks {
+public:
+ CScreensLinks(HWND parent, CConfig*);
+ ~CScreensLinks();
+
+ //! @name manipulators
+ //@{
+
+ //! Run dialog
+ /*!
+ Display and handle the dialog until closed by the user.
+ */
+ void doModal();
+
+ //@}
+ //! @name accessors
+ //@{
+
+
+ //@}
+
+private:
+ typedef std::pair CConfigLink;
+ struct CEdgeLink {
+ public:
+ CEdgeLink();
+ CEdgeLink(const CString& name, const CConfigLink&);
+
+ bool connect(CConfig*);
+ bool disconnect(CConfig*);
+ void rename(const CString& oldName, const CString& newName);
+
+ bool overlaps(const CConfig* config) const;
+ bool operator==(const CEdgeLink&) const;
+
+ public:
+ CString m_srcName;
+ EDirection m_srcSide;
+ CConfig::CInterval m_srcInterval;
+ CString m_dstName;
+ CConfig::CInterval m_dstInterval;
+ };
+ typedef std::vector CEdgeLinkList;
+
+ void init(HWND hwnd);
+ bool save(HWND hwnd);
+
+ CString getSelectedScreen(HWND hwnd) const;
+ void addScreen(HWND hwnd);
+ void editScreen(HWND hwnd);
+ void removeScreen(HWND hwnd);
+ void addLink(HWND hwnd);
+ void editLink(HWND hwnd);
+ void removeLink(HWND hwnd);
+
+ void updateScreens(HWND hwnd, const CString& name);
+ void updateScreensControls(HWND hwnd);
+ void updateLinks(HWND hwnd);
+ void updateLinksControls(HWND hwnd);
+
+ void changeSrcSide(HWND hwnd);
+ void changeSrcScreen(HWND hwnd);
+ void changeDstScreen(HWND hwnd);
+ void changeIntervalStart(HWND hwnd, int id,
+ CConfig::CInterval&);
+ void changeIntervalEnd(HWND hwnd, int id,
+ CConfig::CInterval&);
+
+ void selectScreen(HWND hwnd, int id, const CString& name);
+ void updateLinkEditControls(HWND hwnd,
+ const CEdgeLink& link);
+ void updateLinkIntervalControls(HWND hwnd,
+ const CEdgeLink& link);
+ void updateLink(HWND hwnd);
+ void updateLinkValid(HWND hwnd, const CEdgeLink& link);
+
+ void updateLinkView(HWND hwnd);
+
+ HWND createErrorBox(HWND parent);
+ void resizeErrorBoxes();
+ void resizeErrorBox(HWND box, HWND assoc);
+
+ CString formatIntervalValue(float) const;
+ CString formatInterval(const CConfig::CInterval&) const;
+ CString formatLink(const CEdgeLink&) const;
+
+ // message handling
+ BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
+ static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
+
+private:
+ static CScreensLinks* s_singleton;
+
+ HWND m_parent;
+ CConfig* m_mainConfig;
+ CConfig m_scratchConfig;
+ CConfig* m_config;
+
+ CString m_linkFormat;
+ CString m_intervalFormat;
+ CString m_newLinkLabel;
+ CString m_sideLabel[kNumDirections];
+ CEdgeLinkList m_edgeLinks;
+ SInt32 m_selectedLink;
+ CEdgeLink m_editedLink;
+ bool m_editedLinkIsValid;
+ HPEN m_redPen;
+ HWND m_srcSideError;
+ HWND m_srcScreenError;
+ HWND m_dstScreenError;
+};
+
+#endif
diff --git a/cmd/launcher/LaunchUtil.cpp b/cmd/launcher/LaunchUtil.cpp
new file mode 100644
index 00000000..05b517e7
--- /dev/null
+++ b/cmd/launcher/LaunchUtil.cpp
@@ -0,0 +1,261 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CConfig.h"
+#include "LaunchUtil.h"
+#include "CMSWindowsUtil.h"
+#include "CArch.h"
+#include "resource.h"
+#include "stdfstream.h"
+
+size_t s_showingDialog = 0;
+
+CString
+getString(DWORD id)
+{
+ return CMSWindowsUtil::getString(s_instance, id);
+}
+
+CString
+getErrorString(DWORD error)
+{
+ return CMSWindowsUtil::getErrorString(s_instance, error, IDS_ERROR);
+}
+
+void
+showError(HWND hwnd, const CString& msg)
+{
+ CString title = getString(IDS_ERROR);
+ ++s_showingDialog;
+ MessageBox(hwnd, msg.c_str(), title.c_str(), MB_OK | MB_APPLMODAL);
+ --s_showingDialog;
+}
+
+void
+askOkay(HWND hwnd, const CString& title, const CString& msg)
+{
+ ++s_showingDialog;
+ MessageBox(hwnd, msg.c_str(), title.c_str(), MB_OK | MB_APPLMODAL);
+ --s_showingDialog;
+}
+
+bool
+askVerify(HWND hwnd, const CString& msg)
+{
+ CString title = getString(IDS_VERIFY);
+ ++s_showingDialog;
+ int result = MessageBox(hwnd, msg.c_str(),
+ title.c_str(), MB_OKCANCEL | MB_APPLMODAL);
+ --s_showingDialog;
+ return (result == IDOK);
+}
+
+bool
+isShowingDialog()
+{
+ return (s_showingDialog != 0);
+}
+
+void
+setWindowText(HWND hwnd, const CString& msg)
+{
+ SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)msg.c_str());
+}
+
+CString
+getWindowText(HWND hwnd)
+{
+ LRESULT size = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
+ char* buffer = new char[size + 1];
+ SendMessage(hwnd, WM_GETTEXT, size + 1, (LPARAM)buffer);
+ buffer[size] = '\0';
+ CString result(buffer);
+ delete[] buffer;
+ return result;
+}
+
+HWND
+getItem(HWND hwnd, int id)
+{
+ return GetDlgItem(hwnd, id);
+}
+
+void
+enableItem(HWND hwnd, int id, bool enabled)
+{
+ EnableWindow(GetDlgItem(hwnd, id), enabled);
+}
+
+void
+setItemChecked(HWND hwnd, bool checked)
+{
+ SendMessage(hwnd, BM_SETCHECK, checked ? BST_CHECKED : BST_UNCHECKED, 0);
+}
+
+bool
+isItemChecked(HWND hwnd)
+{
+ return (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
+}
+
+CString
+getAppPath(const CString& appName)
+{
+ // prepare path to app
+ char myPathname[MAX_PATH];
+ GetModuleFileName(s_instance, myPathname, MAX_PATH);
+ const char* myBasename = ARCH->getBasename(myPathname);
+ CString appPath = CString(myPathname, myBasename - myPathname);
+ appPath += appName;
+ return appPath;
+}
+
+static
+void
+getFileTime(const CString& path, time_t& t)
+{
+ struct _stat s;
+ if (_stat(path.c_str(), &s) != -1) {
+ t = s.st_mtime;
+ }
+}
+
+bool
+isConfigNewer(time_t& oldTime, bool userConfig)
+{
+ time_t newTime = oldTime;
+ if (userConfig) {
+ CString path = ARCH->getUserDirectory();
+ if (!path.empty()) {
+ path = ARCH->concatPath(path, CONFIG_NAME);
+ getFileTime(path, newTime);
+ }
+ }
+ else {
+ CString path = ARCH->getSystemDirectory();
+ if (!path.empty()) {
+ path = ARCH->concatPath(path, CONFIG_NAME);
+ getFileTime(path, newTime);
+ }
+ }
+ bool result = (newTime > oldTime);
+ oldTime = newTime;
+ return result;
+}
+
+static
+bool
+loadConfig(const CString& pathname, CConfig& config)
+{
+ try {
+ std::ifstream stream(pathname.c_str());
+ if (stream) {
+ stream >> config;
+ return true;
+ }
+ }
+ catch (...) {
+ // ignore
+ }
+ return false;
+}
+
+bool
+loadConfig(CConfig& config, time_t& t, bool& userConfig)
+{
+ // load configuration
+ bool configLoaded = false;
+ CString path = ARCH->getUserDirectory();
+ if (!path.empty()) {
+ // try loading the user's configuration
+ path = ARCH->concatPath(path, CONFIG_NAME);
+ if (loadConfig(path, config)) {
+ configLoaded = true;
+ userConfig = true;
+ getFileTime(path, t);
+ }
+ else {
+ // try the system-wide config file
+ path = ARCH->getSystemDirectory();
+ if (!path.empty()) {
+ path = ARCH->concatPath(path, CONFIG_NAME);
+ if (loadConfig(path, config)) {
+ configLoaded = true;
+ userConfig = false;
+ getFileTime(path, t);
+ }
+ }
+ }
+ }
+ return configLoaded;
+}
+
+static
+bool
+saveConfig(const CString& pathname, const CConfig& config)
+{
+ try {
+ std::ofstream stream(pathname.c_str());
+ if (stream) {
+ stream << config;
+ return !!stream;
+ }
+ }
+ catch (...) {
+ // ignore
+ }
+ return false;
+}
+
+bool
+saveConfig(const CConfig& config, bool sysOnly, time_t& t)
+{
+ // try saving the user's configuration
+ if (!sysOnly) {
+ CString path = ARCH->getUserDirectory();
+ if (!path.empty()) {
+ path = ARCH->concatPath(path, CONFIG_NAME);
+ if (saveConfig(path, config)) {
+ getFileTime(path, t);
+ return true;
+ }
+ }
+ }
+
+ // try the system-wide config file
+ else {
+ CString path = ARCH->getSystemDirectory();
+ if (!path.empty()) {
+ path = ARCH->concatPath(path, CONFIG_NAME);
+ if (saveConfig(path, config)) {
+ getFileTime(path, t);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+const TCHAR* const*
+getSettingsPath()
+{
+ static const TCHAR* s_keyNames[] = {
+ TEXT("Software"),
+ TEXT("Synergy"),
+ TEXT("Synergy"),
+ NULL
+ };
+ return s_keyNames;
+}
diff --git a/cmd/launcher/LaunchUtil.h b/cmd/launcher/LaunchUtil.h
new file mode 100644
index 00000000..75954046
--- /dev/null
+++ b/cmd/launcher/LaunchUtil.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef LAUNCHUTIL_H
+#define LAUNCHUTIL_H
+
+#include "CString.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include
+#include
+#include
+
+#define CLIENT_APP "synergyc.exe"
+#define SERVER_APP "synergys.exe"
+#define CONFIG_NAME "synergy.sgc"
+
+class CConfig;
+
+// client must define this and set it before calling any function here
+extern HINSTANCE s_instance;
+
+CString getString(DWORD id);
+CString getErrorString(DWORD error);
+
+void showError(HWND hwnd, const CString& msg);
+void askOkay(HWND hwnd, const CString& title,
+ const CString& msg);
+bool askVerify(HWND hwnd, const CString& msg);
+bool isShowingDialog();
+
+void setWindowText(HWND hwnd, const CString& msg);
+CString getWindowText(HWND hwnd);
+
+HWND getItem(HWND hwnd, int id);
+void enableItem(HWND hwnd, int id, bool enabled);
+
+void setItemChecked(HWND, bool);
+bool isItemChecked(HWND);
+
+CString getAppPath(const CString& appName);
+
+bool isConfigNewer(time_t&, bool userConfig);
+bool loadConfig(CConfig& config, time_t&, bool& userConfig);
+bool saveConfig(const CConfig& config,
+ bool sysOnly, time_t&);
+
+const TCHAR* const* getSettingsPath();
+
+#endif
diff --git a/cmd/launcher/Makefile.am b/cmd/launcher/Makefile.am
new file mode 100644
index 00000000..6fc879e3
--- /dev/null
+++ b/cmd/launcher/Makefile.am
@@ -0,0 +1,75 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+MSWINDOWS_SOURCE_FILES = \
+ CAddScreen.cpp \
+ CAdvancedOptions.cpp \
+ CAutoStart.cpp \
+ CGlobalOptions.cpp \
+ CHotkeyOptions.cpp \
+ CInfo.cpp \
+ CScreensLinks.cpp \
+ LaunchUtil.cpp \
+ launcher.cpp \
+ CAddScreen.h \
+ CAdvancedOptions.h \
+ CAutoStart.h \
+ CGlobalOptions.h \
+ CHotkeyOptions.h \
+ CInfo.h \
+ CScreensLinks.h \
+ LaunchUtil.h \
+ resource.h \
+ launcher.rc \
+ $(NULL)
+
+EXTRA_DIST = \
+ Makefile.win \
+ synergy.ico \
+ $(MSWINDOWS_SOURCE_FILES) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
+
+if MSWINDOWS
+bin_PROGRAMS = synergy
+synergy_SOURCES = \
+ $(MSWINDOWS_SOURCE_FILES) \
+ $(NULL)
+endif
+synergy_LDADD = \
+ $(top_builddir)/lib/server/libserver.a \
+ $(top_builddir)/lib/platform/libplatform.a \
+ $(top_builddir)/lib/synergy/libsynergy.a \
+ $(top_builddir)/lib/net/libnet.a \
+ $(top_builddir)/lib/io/libio.a \
+ $(top_builddir)/lib/mt/libmt.a \
+ $(top_builddir)/lib/base/libbase.a \
+ $(top_builddir)/lib/common/libcommon.a \
+ $(top_builddir)/lib/arch/libarch.a \
+ $(NULL)
+INCLUDES = \
+ -I$(top_srcdir)/lib/common \
+ -I$(top_srcdir)/lib/arch \
+ -I$(top_srcdir)/lib/base \
+ -I$(top_srcdir)/lib/mt \
+ -I$(top_srcdir)/lib/io \
+ -I$(top_srcdir)/lib/net \
+ -I$(top_srcdir)/lib/synergy \
+ -I$(top_srcdir)/lib/platform \
+ -I$(top_srcdir)/lib/server \
+ $(NULL)
diff --git a/cmd/launcher/Makefile.win b/cmd/launcher/Makefile.win
new file mode 100644
index 00000000..3d4f277a
--- /dev/null
+++ b/cmd/launcher/Makefile.win
@@ -0,0 +1,101 @@
+# synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2007 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.
+
+BIN_LAUNCHER_SRC = cmd\launcher
+BIN_LAUNCHER_DST = $(BUILD_DST)\$(BIN_LAUNCHER_SRC)
+BIN_LAUNCHER_EXE = "$(BUILD_DST)\synergy.exe"
+BIN_LAUNCHER_CPP = \
+ "CAddScreen.cpp" \
+ "CAdvancedOptions.cpp" \
+ "CAutoStart.cpp" \
+ "CGlobalOptions.cpp" \
+ "CHotkeyOptions.cpp" \
+ "CInfo.cpp" \
+ "CScreensLinks.cpp" \
+ "LaunchUtil.cpp" \
+ "launcher.cpp" \
+ $(NULL)
+BIN_LAUNCHER_OBJ = \
+ "$(BIN_LAUNCHER_DST)\CAddScreen.obj" \
+ "$(BIN_LAUNCHER_DST)\CAdvancedOptions.obj" \
+ "$(BIN_LAUNCHER_DST)\CAutoStart.obj" \
+ "$(BIN_LAUNCHER_DST)\CGlobalOptions.obj" \
+ "$(BIN_LAUNCHER_DST)\CHotkeyOptions.obj" \
+ "$(BIN_LAUNCHER_DST)\CInfo.obj" \
+ "$(BIN_LAUNCHER_DST)\CScreensLinks.obj" \
+ "$(BIN_LAUNCHER_DST)\LaunchUtil.obj" \
+ "$(BIN_LAUNCHER_DST)\launcher.obj" \
+ $(NULL)
+BIN_LAUNCHER_RC = "$(BIN_LAUNCHER_SRC)\launcher.rc"
+BIN_LAUNCHER_RES = "$(BIN_LAUNCHER_DST)\launcher.res"
+BIN_LAUNCHER_INC = \
+ /I"lib\common" \
+ /I"lib\arch" \
+ /I"lib\base" \
+ /I"lib\mt" \
+ /I"lib\io" \
+ /I"lib\net" \
+ /I"lib\synergy" \
+ /I"lib\platform" \
+ /I"lib\server" \
+ $(NULL)
+BIN_LAUNCHER_LIB = \
+ $(LIB_SERVER_LIB) \
+ $(LIB_PLATFORM_LIB) \
+ $(LIB_SYNERGY_LIB) \
+ $(LIB_NET_LIB) \
+ $(LIB_IO_LIB) \
+ $(LIB_MT_LIB) \
+ $(LIB_BASE_LIB) \
+ $(LIB_ARCH_LIB) \
+ $(LIB_COMMON_LIB) \
+ $(NULL)
+
+CPP_FILES = $(CPP_FILES) $(BIN_LAUNCHER_CPP)
+OBJ_FILES = $(OBJ_FILES) $(BIN_LAUNCHER_OBJ)
+PROGRAMS = $(PROGRAMS) $(BIN_LAUNCHER_EXE)
+
+# Need shell functions.
+guilibs = $(guilibs) shell32.lib
+
+# Dependency rules
+$(BIN_LAUNCHER_OBJ): $(AUTODEP)
+!if EXIST($(BIN_LAUNCHER_DST)\deps.mak)
+!include $(BIN_LAUNCHER_DST)\deps.mak
+!endif
+
+# Build rules. Use batch-mode rules if possible.
+!if DEFINED(_NMAKE_VER)
+{$(BIN_LAUNCHER_SRC)\}.cpp{$(BIN_LAUNCHER_DST)\}.obj::
+!else
+{$(BIN_LAUNCHER_SRC)\}.cpp{$(BIN_LAUNCHER_DST)\}.obj:
+!endif
+ @$(ECHO) Compile in $(BIN_LAUNCHER_SRC)
+ -@$(MKDIR) $(BIN_LAUNCHER_DST) 2>NUL:
+ $(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
+ $(BIN_LAUNCHER_INC) \
+ /Fo$(BIN_LAUNCHER_DST)\ \
+ /Fd$(BIN_LAUNCHER_DST)\src.pdb \
+ $< | $(AUTODEP) $(BIN_LAUNCHER_SRC) $(BIN_LAUNCHER_DST)
+$(BIN_LAUNCHER_RES): $(BIN_LAUNCHER_RC)
+ @$(ECHO) Compile $(**F)
+ -@$(MKDIR) $(BIN_LAUNCHER_DST) 2>NUL:
+ $(rc) $(rcflags) $(rcvars) \
+ /fo$@ \
+ $**
+$(BIN_LAUNCHER_EXE): $(BIN_LAUNCHER_OBJ) $(BIN_LAUNCHER_RES) $(BIN_LAUNCHER_LIB)
+ @$(ECHO) Link $(@F)
+ $(link) $(ldebug) $(guilflags) $(guilibsmt) \
+ /out:$@ \
+ $**
+ $(AUTODEP) $(BIN_LAUNCHER_SRC) $(BIN_LAUNCHER_DST) \
+ $(BIN_LAUNCHER_OBJ:.obj=.d)
diff --git a/cmd/launcher/launcher.cpp b/cmd/launcher/launcher.cpp
new file mode 100644
index 00000000..938822da
--- /dev/null
+++ b/cmd/launcher/launcher.cpp
@@ -0,0 +1,755 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2002 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CConfig.h"
+#include "KeyTypes.h"
+#include "OptionTypes.h"
+#include "ProtocolTypes.h"
+#include "CLog.h"
+#include "CStringUtil.h"
+#include "CArch.h"
+#include "CArchMiscWindows.h"
+#include "XArch.h"
+#include "Version.h"
+#include "stdvector.h"
+#include "resource.h"
+
+// these must come after the above because it includes windows.h
+#include "LaunchUtil.h"
+#include "CAddScreen.h"
+#include "CAdvancedOptions.h"
+#include "CAutoStart.h"
+#include "CGlobalOptions.h"
+#include "CHotkeyOptions.h"
+#include "CInfo.h"
+#include "CScreensLinks.h"
+
+typedef std::vector CStringList;
+
+class CChildWaitInfo {
+public:
+ HWND m_dialog;
+ HANDLE m_child;
+ DWORD m_childID;
+ HANDLE m_ready;
+ HANDLE m_stop;
+};
+
+static const char* s_debugName[][2] = {
+ { TEXT("Error"), "ERROR" },
+ { TEXT("Warning"), "WARNING" },
+ { TEXT("Note"), "NOTE" },
+ { TEXT("Info"), "INFO" },
+ { TEXT("Debug"), "DEBUG" },
+ { TEXT("Debug1"), "DEBUG1" },
+ { TEXT("Debug2"), "DEBUG2" }
+};
+static const int s_defaultDebug = 1; // WARNING
+static const int s_minTestDebug = 3; // INFO
+
+HINSTANCE s_instance = NULL;
+
+static CGlobalOptions* s_globalOptions = NULL;
+static CAdvancedOptions* s_advancedOptions = NULL;
+static CHotkeyOptions* s_hotkeyOptions = NULL;
+static CScreensLinks* s_screensLinks = NULL;
+static CInfo* s_info = NULL;
+
+static bool s_userConfig = true;
+static time_t s_configTime = 0;
+static CConfig s_lastConfig;
+
+static const TCHAR* s_mainClass = TEXT("GoSynergy");
+static const TCHAR* s_layoutClass = TEXT("SynergyLayout");
+
+enum SaveMode {
+ SAVE_QUITING,
+ SAVE_NORMAL,
+ SAVE_QUIET
+};
+
+//
+// program arguments
+//
+
+#define ARG CArgs::s_instance
+
+class CArgs {
+public:
+ CArgs() { s_instance = this; }
+ ~CArgs() { s_instance = NULL; }
+
+public:
+ static CArgs* s_instance;
+ CConfig m_config;
+ CStringList m_screens;
+};
+
+CArgs* CArgs::s_instance = NULL;
+
+
+static
+BOOL CALLBACK
+addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+static
+bool
+isClientChecked(HWND hwnd)
+{
+ HWND child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
+ return isItemChecked(child);
+}
+
+static
+void
+enableMainWindowControls(HWND hwnd)
+{
+ bool client = isClientChecked(hwnd);
+ enableItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_LABEL, client);
+ enableItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT, client);
+ enableItem(hwnd, IDC_MAIN_SERVER_SCREENS_LABEL, !client);
+ enableItem(hwnd, IDC_MAIN_SCREENS, !client);
+ enableItem(hwnd, IDC_MAIN_OPTIONS, !client);
+ enableItem(hwnd, IDC_MAIN_HOTKEYS, !client);
+}
+
+static
+bool
+execApp(const char* app, const CString& cmdLine, PROCESS_INFORMATION* procInfo)
+{
+ // prepare startup info
+ STARTUPINFO startup;
+ startup.cb = sizeof(startup);
+ startup.lpReserved = NULL;
+ startup.lpDesktop = NULL;
+ startup.lpTitle = NULL;
+ startup.dwX = (DWORD)CW_USEDEFAULT;
+ startup.dwY = (DWORD)CW_USEDEFAULT;
+ startup.dwXSize = (DWORD)CW_USEDEFAULT;
+ startup.dwYSize = (DWORD)CW_USEDEFAULT;
+ startup.dwXCountChars = 0;
+ startup.dwYCountChars = 0;
+ startup.dwFillAttribute = 0;
+ startup.dwFlags = STARTF_FORCEONFEEDBACK;
+ startup.wShowWindow = SW_SHOWDEFAULT;
+ startup.cbReserved2 = 0;
+ startup.lpReserved2 = NULL;
+ startup.hStdInput = NULL;
+ startup.hStdOutput = NULL;
+ startup.hStdError = NULL;
+
+ // prepare path to app
+ CString appPath = getAppPath(app);
+
+ // put path to app in command line
+ CString commandLine = "\"";
+ commandLine += appPath;
+ commandLine += "\" ";
+ commandLine += cmdLine;
+
+ // start child
+ if (CreateProcess(NULL, (char*)commandLine.c_str(),
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_DEFAULT_ERROR_MODE |
+ CREATE_NEW_PROCESS_GROUP |
+ NORMAL_PRIORITY_CLASS,
+ NULL,
+ NULL,
+ &startup,
+ procInfo) == 0) {
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+static
+CString
+getCommandLine(HWND hwnd, bool testing, bool silent)
+{
+ CString cmdLine;
+
+ // add constant testing args
+ if (testing) {
+ cmdLine += " -z --no-restart --no-daemon";
+ }
+
+ // can't start as service on NT
+ else if (!CArchMiscWindows::isWindows95Family()) {
+ cmdLine += " --no-daemon";
+ }
+
+ // get the server name
+ CString server;
+ bool isClient = isClientChecked(hwnd);
+ if (isClient) {
+ // check server name
+ HWND child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
+ server = getWindowText(child);
+ if (!ARG->m_config.isValidScreenName(server)) {
+ if (!silent) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_INVALID_SERVER_NAME).c_str(),
+ server.c_str()));
+ }
+ SetFocus(child);
+ return CString();
+ }
+
+ // compare server name to local host. a common error
+ // is to provide the client's name for the server. we
+ // don't bother to check the addresses though that'd be
+ // more accurate.
+ if (CStringUtil::CaselessCmp::equal(ARCH->getHostName(), server)) {
+ if (!silent) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_SERVER_IS_CLIENT).c_str(),
+ server.c_str()));
+ }
+ SetFocus(child);
+ return CString();
+ }
+ }
+
+ // debug level. always include this.
+ if (true) {
+ HWND child = getItem(hwnd, IDC_MAIN_DEBUG);
+ int debug = (int)SendMessage(child, CB_GETCURSEL, 0, 0);
+
+ // if testing then we force the debug level to be no less than
+ // s_minTestDebug. what's the point of testing if you can't
+ // see the debugging info?
+ if (testing && debug < s_minTestDebug) {
+ debug = s_minTestDebug;
+ }
+
+ cmdLine += " --debug ";
+ cmdLine += s_debugName[debug][1];
+ }
+
+ // add advanced options
+ cmdLine += s_advancedOptions->getCommandLine(isClient, server);
+
+ return cmdLine;
+}
+
+static
+bool
+launchApp(HWND hwnd, bool testing, HANDLE* thread, DWORD* threadID)
+{
+ if (thread != NULL) {
+ *thread = NULL;
+ }
+ if (threadID != NULL) {
+ *threadID = 0;
+ }
+
+ // start daemon if it's installed and we're not testing
+ if (!testing && CAutoStart::startDaemon()) {
+ return true;
+ }
+
+ // decide if client or server
+ const bool isClient = isClientChecked(hwnd);
+ const char* app = isClient ? CLIENT_APP : SERVER_APP;
+
+ // prepare command line
+ CString cmdLine = getCommandLine(hwnd, testing, false);
+ if (cmdLine.empty()) {
+ return false;
+ }
+
+ // start child
+ PROCESS_INFORMATION procInfo;
+ if (!execApp(app, cmdLine, &procInfo)) {
+ showError(hwnd, CStringUtil::format(
+ getString(IDS_STARTUP_FAILED).c_str(),
+ getErrorString(GetLastError()).c_str()));
+ return false;
+ }
+
+ // don't need process handle
+ CloseHandle(procInfo.hProcess);
+
+ // save thread handle and thread ID if desired
+ if (thread != NULL) {
+ *thread = procInfo.hThread;
+ }
+ if (threadID != NULL) {
+ *threadID = procInfo.dwThreadId;
+ }
+
+ return true;
+}
+
+static
+BOOL CALLBACK
+waitDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // only one wait dialog at a time!
+ static CChildWaitInfo* info = NULL;
+
+ switch (message) {
+ case WM_INITDIALOG:
+ // save info pointer
+ info = reinterpret_cast(lParam);
+
+ // save hwnd
+ info->m_dialog = hwnd;
+
+ // signal ready
+ SetEvent(info->m_ready);
+
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ case IDOK:
+ // signal stop
+ SetEvent(info->m_stop);
+
+ // done
+ EndDialog(hwnd, 0);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static
+DWORD WINAPI
+waitForChildThread(LPVOID vinfo)
+{
+ CChildWaitInfo* info = reinterpret_cast(vinfo);
+
+ // wait for ready
+ WaitForSingleObject(info->m_ready, INFINITE);
+
+ // wait for thread to complete or stop event
+ HANDLE handles[2];
+ handles[0] = info->m_child;
+ handles[1] = info->m_stop;
+ DWORD n = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+
+ // if stop was raised then terminate child and wait for it
+ if (n == WAIT_OBJECT_0 + 1) {
+ PostThreadMessage(info->m_childID, WM_QUIT, 0, 0);
+ WaitForSingleObject(info->m_child, INFINITE);
+ }
+
+ // otherwise post IDOK to dialog box
+ else {
+ PostMessage(info->m_dialog, WM_COMMAND, MAKEWPARAM(IDOK, 0), 0);
+ }
+
+ return 0;
+}
+
+static
+void
+waitForChild(HWND hwnd, HANDLE thread, DWORD threadID)
+{
+ // prepare info for child wait dialog and thread
+ CChildWaitInfo info;
+ info.m_dialog = NULL;
+ info.m_child = thread;
+ info.m_childID = threadID;
+ info.m_ready = CreateEvent(NULL, TRUE, FALSE, NULL);
+ info.m_stop = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ // create a thread to wait on the child thread and event
+ DWORD id;
+ HANDLE waiter = CreateThread(NULL, 0, &waitForChildThread, &info,0, &id);
+
+ // do dialog that let's the user terminate the test
+ DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_WAIT), hwnd,
+ (DLGPROC)waitDlgProc, (LPARAM)&info);
+
+ // force the waiter thread to finish and wait for it
+ SetEvent(info.m_ready);
+ SetEvent(info.m_stop);
+ WaitForSingleObject(waiter, INFINITE);
+
+ // clean up
+ CloseHandle(waiter);
+ CloseHandle(info.m_ready);
+ CloseHandle(info.m_stop);
+}
+
+static
+void
+initMainWindow(HWND hwnd)
+{
+ // append version number to title
+ CString titleFormat = getString(IDS_TITLE);
+ setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION));
+
+ // load configuration
+ bool configLoaded =
+ loadConfig(ARG->m_config, s_configTime, s_userConfig);
+ if (configLoaded) {
+ s_lastConfig = ARG->m_config;
+ }
+
+ // get settings from registry
+ bool isServer = configLoaded;
+ int debugLevel = s_defaultDebug;
+ CString server;
+ HKEY key = CArchMiscWindows::openKey(HKEY_CURRENT_USER, getSettingsPath());
+ if (key != NULL) {
+ if (isServer && CArchMiscWindows::hasValue(key, "isServer")) {
+ isServer = (CArchMiscWindows::readValueInt(key, "isServer") != 0);
+ }
+ if (CArchMiscWindows::hasValue(key, "debug")) {
+ debugLevel = static_cast(
+ CArchMiscWindows::readValueInt(key, "debug"));
+ if (debugLevel < 0) {
+ debugLevel = 0;
+ }
+ else if (debugLevel > CLog::kDEBUG2) {
+ debugLevel = CLog::kDEBUG2;
+ }
+ }
+ server = CArchMiscWindows::readValueString(key, "server");
+ CArchMiscWindows::closeKey(key);
+ }
+
+ // choose client/server radio buttons
+ HWND child;
+ child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
+ setItemChecked(child, !isServer);
+ child = getItem(hwnd, IDC_MAIN_SERVER_RADIO);
+ setItemChecked(child, isServer);
+
+ // set server name
+ child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
+ setWindowText(child, server);
+
+ // debug level
+ child = getItem(hwnd, IDC_MAIN_DEBUG);
+ for (unsigned int i = 0; i < sizeof(s_debugName) /
+ sizeof(s_debugName[0]); ++i) {
+ SendMessage(child, CB_ADDSTRING, 0, (LPARAM)s_debugName[i][0]);
+ }
+ SendMessage(child, CB_SETCURSEL, debugLevel, 0);
+
+ // update controls
+ enableMainWindowControls(hwnd);
+}
+
+static
+bool
+saveMainWindow(HWND hwnd, SaveMode mode, CString* cmdLineOut = NULL)
+{
+ DWORD errorID = 0;
+ CString arg;
+ CString cmdLine;
+
+ // save dialog state
+ bool isClient = isClientChecked(hwnd);
+ HKEY key = CArchMiscWindows::addKey(HKEY_CURRENT_USER, getSettingsPath());
+ if (key != NULL) {
+ HWND child;
+ child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
+ CArchMiscWindows::setValue(key, "server", getWindowText(child));
+ child = getItem(hwnd, IDC_MAIN_DEBUG);
+ CArchMiscWindows::setValue(key, "debug",
+ SendMessage(child, CB_GETCURSEL, 0, 0));
+ CArchMiscWindows::setValue(key, "isServer", isClient ? 0 : 1);
+ CArchMiscWindows::closeKey(key);
+ }
+
+ // save user's configuration
+ if (!s_userConfig || ARG->m_config != s_lastConfig) {
+ time_t t;
+ if (!saveConfig(ARG->m_config, false, t)) {
+ errorID = IDS_SAVE_FAILED;
+ arg = getErrorString(GetLastError());
+ goto failed;
+ }
+ if (s_userConfig) {
+ s_configTime = t;
+ s_lastConfig = ARG->m_config;
+ }
+ }
+
+ // save autostart configuration
+ if (CAutoStart::isDaemonInstalled()) {
+ if (s_userConfig || ARG->m_config != s_lastConfig) {
+ time_t t;
+ if (!saveConfig(ARG->m_config, true, t)) {
+ errorID = IDS_AUTOSTART_SAVE_FAILED;
+ arg = getErrorString(GetLastError());
+ goto failed;
+ }
+ if (!s_userConfig) {
+ s_configTime = t;
+ s_lastConfig = ARG->m_config;
+ }
+ }
+ }
+
+ // get autostart command
+ cmdLine = getCommandLine(hwnd, false, mode == SAVE_QUITING);
+ if (cmdLineOut != NULL) {
+ *cmdLineOut = cmdLine;
+ }
+ if (cmdLine.empty()) {
+ return (mode == SAVE_QUITING);
+ }
+
+ // save autostart command
+ if (CAutoStart::isDaemonInstalled()) {
+ try {
+ CAutoStart::reinstallDaemon(isClient, cmdLine);
+ CAutoStart::uninstallDaemons(!isClient);
+ }
+ catch (XArchDaemon& e) {
+ errorID = IDS_INSTALL_GENERIC_ERROR;
+ arg = e.what();
+ goto failed;
+ }
+ }
+
+ return true;
+
+failed:
+ CString errorMessage =
+ CStringUtil::format(getString(errorID).c_str(), arg.c_str());
+ if (mode == SAVE_QUITING) {
+ errorMessage += "\n";
+ errorMessage += getString(IDS_UNSAVED_DATA_REALLY_QUIT);
+ if (askVerify(hwnd, errorMessage)) {
+ return true;
+ }
+ }
+ else if (mode == SAVE_NORMAL) {
+ showError(hwnd, errorMessage);
+ }
+ return false;
+}
+
+static
+LRESULT CALLBACK
+mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_ACTIVATE:
+ if (LOWORD(wParam) != WA_INACTIVE) {
+ // activated
+
+ // see if the configuration changed
+ if (isConfigNewer(s_configTime, s_userConfig)) {
+ CString message = getString(IDS_CONFIG_CHANGED);
+ if (askVerify(hwnd, message)) {
+ time_t configTime;
+ bool userConfig;
+ CConfig newConfig;
+ if (loadConfig(newConfig, configTime, userConfig) &&
+ userConfig == s_userConfig) {
+ ARG->m_config = newConfig;
+ s_lastConfig = ARG->m_config;
+ }
+ else {
+ message = getString(IDS_LOAD_FAILED);
+ showError(hwnd, message);
+ s_lastConfig = CConfig();
+ }
+ }
+ }
+ }
+ else {
+ // deactivated; write configuration
+ if (!isShowingDialog()) {
+ saveMainWindow(hwnd, SAVE_QUIET);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ // save data
+ if (saveMainWindow(hwnd, SAVE_QUITING)) {
+ // quit
+ PostQuitMessage(0);
+ }
+ return 0;
+
+ case IDOK:
+ case IDC_MAIN_TEST: {
+ // note if testing
+ const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
+
+ // save data
+ if (saveMainWindow(hwnd, SAVE_NORMAL)) {
+ // launch child app
+ DWORD threadID;
+ HANDLE thread;
+ if (!launchApp(hwnd, testing, &thread, &threadID)) {
+ return 0;
+ }
+
+ // handle child program
+ if (testing) {
+ // wait for process to stop, allowing the user to kill it
+ waitForChild(hwnd, thread, threadID);
+
+ // clean up
+ CloseHandle(thread);
+ }
+ else {
+ // don't need thread handle
+ if (thread != NULL) {
+ CloseHandle(thread);
+ }
+
+ // notify of success
+ askOkay(hwnd, getString(IDS_STARTED_TITLE),
+ getString(IDS_STARTED));
+
+ // quit
+ PostQuitMessage(0);
+ }
+ }
+ return 0;
+ }
+
+ case IDC_MAIN_AUTOSTART: {
+ CString cmdLine;
+ if (saveMainWindow(hwnd, SAVE_NORMAL, &cmdLine)) {
+ // run dialog
+ CAutoStart autoStart(hwnd, !isClientChecked(hwnd), cmdLine);
+ autoStart.doModal();
+ }
+ return 0;
+ }
+
+ case IDC_MAIN_CLIENT_RADIO:
+ case IDC_MAIN_SERVER_RADIO:
+ enableMainWindowControls(hwnd);
+ return 0;
+
+ case IDC_MAIN_SCREENS:
+ s_screensLinks->doModal();
+ break;
+
+ case IDC_MAIN_OPTIONS:
+ s_globalOptions->doModal();
+ break;
+
+ case IDC_MAIN_ADVANCED:
+ s_advancedOptions->doModal(isClientChecked(hwnd));
+ break;
+
+ case IDC_MAIN_HOTKEYS:
+ s_hotkeyOptions->doModal();
+ break;
+
+ case IDC_MAIN_INFO:
+ s_info->doModal();
+ break;
+ }
+
+ default:
+ break;
+ }
+ return DefDlgProc(hwnd, message, wParam, lParam);
+}
+
+int WINAPI
+WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmdLine, int nCmdShow)
+{
+ CArch arch(instance);
+ CLOG;
+ CArgs args;
+
+ s_instance = instance;
+
+ // if "/uninstall" is on the command line then just stop and
+ // uninstall the service and quit. this is the only option
+ // but we ignore any others.
+ if (CString(cmdLine).find("/uninstall") != CString::npos) {
+ CAutoStart::uninstallDaemons(false);
+ CAutoStart::uninstallDaemons(true);
+ return 0;
+ }
+
+ // register main window (dialog) class
+ WNDCLASSEX classInfo;
+ classInfo.cbSize = sizeof(classInfo);
+ classInfo.style = CS_HREDRAW | CS_VREDRAW;
+ classInfo.lpfnWndProc = &mainWndProc;
+ classInfo.cbClsExtra = 0;
+ classInfo.cbWndExtra = DLGWINDOWEXTRA;
+ classInfo.hInstance = instance;
+ classInfo.hIcon = (HICON)LoadImage(instance,
+ MAKEINTRESOURCE(IDI_SYNERGY),
+ IMAGE_ICON,
+ 32, 32, LR_SHARED);
+ classInfo.hCursor = LoadCursor(NULL, IDC_ARROW);
+ classInfo.hbrBackground = reinterpret_cast(COLOR_3DFACE + 1);
+ classInfo.lpszMenuName = NULL;
+ classInfo.lpszClassName = s_mainClass;
+ classInfo.hIconSm = (HICON)LoadImage(instance,
+ MAKEINTRESOURCE(IDI_SYNERGY),
+ IMAGE_ICON,
+ 16, 16, LR_SHARED);
+ RegisterClassEx(&classInfo);
+
+ // create main window
+ HWND mainWindow = CreateDialog(s_instance,
+ MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
+
+ // prep windows
+ initMainWindow(mainWindow);
+ s_globalOptions = new CGlobalOptions(mainWindow, &ARG->m_config);
+ s_advancedOptions = new CAdvancedOptions(mainWindow, &ARG->m_config);
+ s_hotkeyOptions = new CHotkeyOptions(mainWindow, &ARG->m_config);
+ s_screensLinks = new CScreensLinks(mainWindow, &ARG->m_config);
+ s_info = new CInfo(mainWindow);
+
+ // show window
+ ShowWindow(mainWindow, nCmdShow);
+
+ // main loop
+ MSG msg;
+ bool done = false;
+ do {
+ switch (GetMessage(&msg, NULL, 0, 0)) {
+ case -1:
+ // error
+ break;
+
+ case 0:
+ // quit
+ done = true;
+ break;
+
+ default:
+ if (!IsDialogMessage(mainWindow, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ break;
+ }
+ } while (!done);
+
+ return msg.wParam;
+}
diff --git a/cmd/launcher/launcher.rc b/cmd/launcher/launcher.rc
new file mode 100644
index 00000000..ff72d069
--- /dev/null
+++ b/cmd/launcher/launcher.rc
@@ -0,0 +1,617 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#if !defined(IDC_STATIC)
+#define IDC_STATIC (-1)
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAIN DIALOG DISCARDABLE 32768, 0, 300, 199
+STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU
+CAPTION "Synergy"
+CLASS "GoSynergy"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Choose to share or use a shared keyboard and mouse, provide the requested information, then click Test to check your settings or Start to save your settings and start Synergy.",
+ IDC_STATIC,7,7,286,19
+ GROUPBOX "",IDC_STATIC,7,29,286,36
+ GROUPBOX "",IDC_STATIC,7,72,286,36
+ GROUPBOX "Options",IDC_STATIC,7,115,286,56
+ CONTROL "&Use another computer's shared keyboard and mouse (client)",
+ IDC_MAIN_CLIENT_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP | WS_TABSTOP,11,29,205,10
+ CONTROL "Share this computer's keyboard and mouse (server)",
+ IDC_MAIN_SERVER_RADIO,"Button",BS_AUTORADIOBUTTON,11,72,
+ 177,10
+ LTEXT "Other Computer's &Host Name:",
+ IDC_MAIN_CLIENT_SERVER_NAME_LABEL,12,46,94,8
+ EDITTEXT IDC_MAIN_CLIENT_SERVER_NAME_EDIT,111,44,106,12,
+ ES_AUTOHSCROLL
+ LTEXT "&Screens && Links:",IDC_MAIN_SERVER_SCREENS_LABEL,12,89,
+ 54,8
+ PUSHBUTTON "Configure...",IDC_MAIN_SCREENS,71,86,50,14
+ PUSHBUTTON "&Options...",IDC_MAIN_OPTIONS,12,129,50,14
+ PUSHBUTTON "Hot &Keys...",IDC_MAIN_HOTKEYS,68,129,50,14
+ PUSHBUTTON "Adva&nced...",IDC_MAIN_ADVANCED,124,129,50,14
+ PUSHBUTTON "&AutoStart...",IDC_MAIN_AUTOSTART,180,129,50,14
+ LTEXT "&Logging Level:",IDC_STATIC,12,154,48,8
+ COMBOBOX IDC_MAIN_DEBUG,68,151,61,60,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Info",IDC_MAIN_INFO,7,178,50,14
+ DEFPUSHBUTTON "&Test",IDC_MAIN_TEST,131,179,50,14
+ PUSHBUTTON "Start",IDOK,187,179,50,14
+ PUSHBUTTON "Quit",IDCANCEL,243,179,50,14
+END
+
+IDD_ADD DIALOG DISCARDABLE 0, 0, 192, 254
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
+CAPTION "Add Screen"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Screen Name:",IDC_STATIC,7,9,46,8
+ EDITTEXT IDC_ADD_SCREEN_NAME_EDIT,79,7,106,12,ES_AUTOHSCROLL
+ LTEXT "&Aliases:",IDC_STATIC,7,25,25,8
+ EDITTEXT IDC_ADD_ALIASES_EDIT,79,26,106,24,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+ GROUPBOX "Options",IDC_STATIC,7,55,178,54
+ LTEXT "If your Caps, Num, or Scroll Lock keys behave strangely on this client screen then try turning the half-duplex options on and reconnect the client.",
+ IDC_STATIC,13,65,165,25
+ CONTROL "&Caps Lock",IDC_ADD_HD_CAPS_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,13,93,51,10
+ CONTROL "&Num Lock",IDC_ADD_HD_NUM_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,69,93,51,10
+ CONTROL "Sc&roll Lock",IDC_ADD_HD_SCROLL_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,125,93,51,10
+ GROUPBOX "Modifiers",IDC_STATIC,7,113,178,65
+ LTEXT "Shift",IDC_STATIC,13,129,15,8
+ COMBOBOX IDC_ADD_MOD_SHIFT,37,126,48,60,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Ctrl",IDC_STATIC,13,144,11,8
+ COMBOBOX IDC_ADD_MOD_CTRL,37,142,48,60,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Alt",IDC_STATIC,13,160,9,8
+ COMBOBOX IDC_ADD_MOD_ALT,37,158,48,60,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Meta",IDC_STATIC,101,128,17,8
+ COMBOBOX IDC_ADD_MOD_META,125,126,48,60,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Super",IDC_STATIC,101,144,20,8
+ COMBOBOX IDC_ADD_MOD_SUPER,125,142,48,60,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Dead Corners",IDC_STATIC,7,183,178,43
+ LTEXT "Don't switch in these corners:",IDC_STATIC,14,198,52,18
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,68,193,47,28
+ CONTROL "",IDC_ADD_DC_TOP_LEFT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,76,197,16,8
+ CONTROL "",IDC_ADD_DC_TOP_RIGHT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,98,197,16,8
+ CONTROL "",IDC_ADD_DC_BOTTOM_LEFT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,76,210,16,8
+ CONTROL "",IDC_ADD_DC_BOTTOM_RIGHT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,98,210,16,8
+ LTEXT "Size",IDC_STATIC,120,202,14,8
+ EDITTEXT IDC_ADD_DC_SIZE,139,200,40,12,ES_AUTOHSCROLL | ES_NUMBER
+ DEFPUSHBUTTON "OK",IDOK,79,233,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,135,233,50,14
+END
+
+IDD_WAIT DIALOG DISCARDABLE 0, 0, 186, 54
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
+CAPTION "Running Test..."
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Stop",IDOK,129,33,50,14
+ LTEXT "Running synergy. Press Stop to end the test.",
+ IDC_STATIC,7,7,172,15
+END
+
+IDD_AUTOSTART DIALOG DISCARDABLE 0, 0, 195, 189
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Auto Start"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Close",IDCANCEL,138,168,50,14
+ LTEXT "Synergy can be configured to start automatically when you log in. If you have sufficient access rights, you can instead configure synergy to start automatically when your computer starts.",
+ IDC_STATIC,7,7,181,33
+ LTEXT "You have sufficient access rights to install and uninstall Auto Start for all users or for just yourself.",
+ IDC_AUTOSTART_PERMISSION_MSG,7,69,181,17
+ LTEXT "Synergy is configured to start automatically when the system starts.",
+ IDC_AUTOSTART_INSTALLED_MSG,7,93,181,17
+ GROUPBOX "When &You Log In",IDC_STATIC,7,119,84,40
+ PUSHBUTTON "Install",IDC_AUTOSTART_INSTALL_USER,23,133,50,14
+ GROUPBOX "When &Computer Starts",IDC_STATIC,104,119,84,40
+ PUSHBUTTON "Install",IDC_AUTOSTART_INSTALL_SYSTEM,119,134,50,14
+ LTEXT "Synergy can be configured to start automatically when the computer starts or when you log in but not both.",
+ IDC_STATIC,7,43,181,17
+END
+
+IDD_GLOBAL_OPTIONS DIALOG DISCARDABLE 0, 0, 207, 290
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Options"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "It's easy to unintentionally switch screens when the pointer is near a screen's edge. Synergy can prevent switching until certain conditions are met to reduce unintentional switching.",
+ IDC_STATIC,7,7,191,26
+ LTEXT "Synergy can wait to switch until the cursor has been at a screen's edge for some amount of time.",
+ IDC_STATIC,7,37,193,16
+ CONTROL "Switch after waiting",IDC_GLOBAL_DELAY_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,59,77,10
+ EDITTEXT IDC_GLOBAL_DELAY_TIME,112,58,45,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "ms",IDC_STATIC,159,60,10,8
+ LTEXT "Synergy can switch only when the cursor hits a screen edge twice within some amount of time.",
+ IDC_STATIC,7,77,193,16
+ CONTROL "Switch on double tap within",IDC_GLOBAL_TWO_TAP_CHECK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,99,103,10
+ EDITTEXT IDC_GLOBAL_TWO_TAP_TIME,112,98,45,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "ms",IDC_STATIC,159,100,10,8
+ LTEXT "Synergy can periodically check that clients are still alive and connected. Use this only if synergy doesn't detect when clients disconnect.",
+ IDC_STATIC,7,122,193,24
+ CONTROL "Check clients every",IDC_GLOBAL_HEARTBEAT_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,153,78,10
+ EDITTEXT IDC_GLOBAL_HEARTBEAT_TIME,112,152,45,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "ms",IDC_STATIC,159,154,10,8
+ LTEXT "Synergy can synchronize screen savers across all screens.",
+ IDC_STATIC,7,176,193,8
+ CONTROL "Synchronize screen savers",IDC_GLOBAL_SCREENSAVER_SYNC,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,192,101,10
+ LTEXT "Relative mouse moves on secondary screens.",IDC_STATIC,
+ 7,213,193,8
+ CONTROL "Use relative mouse moves",IDC_GLOBAL_RELATIVE_MOVES,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,229,99,10
+ CONTROL "Don't take foreground window on Windows servers",
+ IDC_GLOBAL_LEAVE_FOREGROUND,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,7,250,177,10
+ DEFPUSHBUTTON "OK",IDOK,94,269,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,150,269,50,14
+END
+
+IDD_ADVANCED_OPTIONS DIALOG DISCARDABLE 0, 0, 230, 186
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Advanced Options"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Synergy normally uses this computer's name as its screen name. Enter another name here if you want to use a different screen name.",
+ IDC_STATIC,7,7,216,19
+ LTEXT "Screen &Name:",IDC_STATIC,7,34,46,8
+ EDITTEXT IDC_ADVANCED_NAME_EDIT,63,32,106,12,ES_AUTOHSCROLL
+ LTEXT "Synergy normally uses a particular network port number. Enter an alternative port here. (The server and all clients must use the same port number.)",
+ IDC_STATIC,7,56,216,26
+ LTEXT "&Port:",IDC_STATIC,7,90,16,8
+ EDITTEXT IDC_ADVANCED_PORT_EDIT,63,88,40,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "The server normally listens for client connections on all network interfaces. Enter the address of a particular interface to listen on just that interface.",
+ IDC_STATIC,7,110,216,26
+ LTEXT "&Interface:",IDC_STATIC,7,144,31,8
+ EDITTEXT IDC_ADVANCED_INTERFACE_EDIT,63,142,81,12,ES_AUTOHSCROLL
+ PUSHBUTTON "&Defaults",IDC_ADVANCED_DEFAULTS,7,165,50,14
+ DEFPUSHBUTTON "OK",IDOK,118,165,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,173,165,50,14
+END
+
+IDD_SCREENS_LINKS DIALOG DISCARDABLE 0, 0, 354, 213
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Screens & Links"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Screens:",IDC_STATIC,7,7,29,8
+ LISTBOX IDC_SCREENS_SCREENS,7,18,100,36,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_SCREENS_ADD_SCREEN,7,57,17,14
+ PUSHBUTTON "-",IDC_SCREENS_REMOVE_SCREEN,28,57,17,14
+ PUSHBUTTON "Edit",IDC_SCREENS_EDIT_SCREEN,49,57,24,14
+ LTEXT "&Links:",IDC_STATIC,7,83,20,8
+ LISTBOX IDC_SCREENS_LINKS,7,94,339,59,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_SCREENS_SRC_START,7,156,16,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "to",IDC_STATIC,25,158,8,8
+ EDITTEXT IDC_SCREENS_SRC_END,33,156,16,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "% of the",IDC_STATIC,52,158,27,8
+ COMBOBOX IDC_SCREENS_SRC_SIDE,80,156,48,69,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "of",IDC_STATIC,129,158,8,8
+ COMBOBOX IDC_SCREENS_SRC_SCREEN,139,156,59,53,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "goes to",IDC_STATIC,200,158,24,8
+ EDITTEXT IDC_SCREENS_DST_START,225,156,16,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "to",IDC_STATIC,243,158,8,8
+ EDITTEXT IDC_SCREENS_DST_END,251,156,16,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "% of",IDC_STATIC,270,158,15,8
+ COMBOBOX IDC_SCREENS_DST_SCREEN,287,156,59,53,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_SCREENS_ADD_LINK,7,172,17,14
+ PUSHBUTTON "-",IDC_SCREENS_REMOVE_LINK,28,172,17,14
+ DEFPUSHBUTTON "OK",IDOK,241,192,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,297,192,50,14
+ LTEXT "Source edge overlaps an existing edge.",
+ IDC_SCREENS_OVERLAP_ERROR,72,175,126,8,NOT WS_VISIBLE |
+ NOT WS_GROUP
+END
+
+IDD_INFO DIALOG DISCARDABLE 0, 0, 186, 95
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Version:",IDC_STATIC,7,7,26,8
+ EDITTEXT IDC_INFO_VERSION,52,7,127,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LTEXT "Hostname:",IDC_STATIC,7,19,35,8
+ EDITTEXT IDC_INFO_HOSTNAME,52,19,127,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LTEXT "IP Address:",IDC_STATIC,7,31,37,8
+ EDITTEXT IDC_INFO_IP_ADDRESS,52,31,127,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LTEXT "User Config:",IDC_STATIC,7,43,40,8
+ EDITTEXT IDC_INFO_USER_CONFIG,52,43,127,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LTEXT "Sys Config:",IDC_STATIC,7,55,36,8
+ EDITTEXT IDC_INFO_SYS_CONFIG,52,55,127,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ DEFPUSHBUTTON "OK",IDOK,129,74,50,14
+END
+
+IDD_HOTKEY_OPTIONS DIALOG DISCARDABLE 0, 0, 360, 151
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Hot Keys"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Hot Keys:",IDC_STATIC,7,7,32,8
+ LISTBOX IDC_HOTKEY_HOTKEYS,7,18,169,88,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_HOTKEY_ADD_HOTKEY,7,109,17,14
+ PUSHBUTTON "-",IDC_HOTKEY_REMOVE_HOTKEY,28,109,17,14
+ PUSHBUTTON "Edit",IDC_HOTKEY_EDIT_HOTKEY,49,109,24,14
+ LTEXT "&Actions:",IDC_STATIC,183,7,26,8
+ LISTBOX IDC_HOTKEY_ACTIONS,183,18,169,88,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_HOTKEY_ADD_ACTION,183,109,17,14
+ PUSHBUTTON "-",IDC_HOTKEY_REMOVE_ACTION,204,109,17,14
+ PUSHBUTTON "Edit",IDC_HOTKEY_EDIT_ACTION,225,109,24,14
+ DEFPUSHBUTTON "OK",IDOK,302,130,50,14
+END
+
+IDD_HOTKEY_CONDITION DIALOG DISCARDABLE 0, 0, 183, 58
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Hot Key"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Enter &new hot key or mouse button:",IDC_STATIC,7,7,113,
+ 8
+ EDITTEXT IDC_HOTKEY_CONDITION_HOTKEY,7,17,169,12,ES_WANTRETURN
+ DEFPUSHBUTTON "OK",IDOK,70,37,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,126,37,50,14
+END
+
+IDD_HOTKEY_ACTION DIALOG DISCARDABLE 0, 0, 183, 218
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Action"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Action:",IDC_STATIC,7,7,23,8
+ CONTROL "Press:",IDC_HOTKEY_ACTION_DOWN,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,7,19,35,10
+ CONTROL "Release:",IDC_HOTKEY_ACTION_UP,"Button",
+ BS_AUTORADIOBUTTON,7,31,44,10
+ CONTROL "Press && Release:",IDC_HOTKEY_ACTION_DOWNUP,"Button",
+ BS_AUTORADIOBUTTON,7,43,69,10
+ CONTROL "Switch To Screen:",IDC_HOTKEY_ACTION_SWITCH_TO,"Button",
+ BS_AUTORADIOBUTTON,7,85,75,10
+ CONTROL "Switch In Direction:",IDC_HOTKEY_ACTION_SWITCH_IN,
+ "Button",BS_AUTORADIOBUTTON,7,101,77,10
+ CONTROL "Lock Cursor to Screen:",IDC_HOTKEY_ACTION_LOCK,"Button",
+ BS_AUTORADIOBUTTON,7,117,89,10
+ CONTROL "Keyboard broadcasting:",
+ IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST,"Button",
+ BS_AUTORADIOBUTTON,7,133,89,10
+ LTEXT "&Hot key or mouse button:",IDC_STATIC,7,55,80,8
+ EDITTEXT IDC_HOTKEY_ACTION_HOTKEY,7,67,152,12,ES_WANTRETURN
+ PUSHBUTTON "...",IDC_HOTKEY_ACTION_SCREENS,162,67,14,12
+ COMBOBOX IDC_HOTKEY_ACTION_SWITCH_TO_LIST,87,83,89,62,
+ CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_HOTKEY_ACTION_SWITCH_IN_LIST,106,99,70,66,
+ CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_HOTKEY_ACTION_LOCK_LIST,106,115,70,58,
+ CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST,106,131,53,58,
+ CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS,
+ 162,131,14,12
+ LTEXT "Action takes place &when:",IDC_STATIC,7,153,81,8
+ CONTROL "Hot key is pressed",IDC_HOTKEY_ACTION_ON_ACTIVATE,
+ "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,165,74,10
+ CONTROL "Hot key is released",IDC_HOTKEY_ACTION_ON_DEACTIVATE,
+ "Button",BS_AUTORADIOBUTTON,7,177,76,10
+ DEFPUSHBUTTON "OK",IDOK,70,197,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,126,197,50,14
+END
+
+IDD_HOTKEY_SCREENS DIALOG DISCARDABLE 0, 0, 237, 79
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Target Screens"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Available screens:",IDC_STATIC,7,7,58,8
+ LISTBOX IDC_HOTKEY_SCREENS_SRC,7,17,100,36,LBS_NOINTEGRALHEIGHT |
+ LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP
+ LISTBOX IDC_HOTKEY_SCREENS_DST,130,17,100,36,
+ LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "-->",IDC_HOTKEY_SCREENS_ADD,109,21,17,14
+ PUSHBUTTON "<--",IDC_HOTKEY_SCREENS_REMOVE,109,38,17,14
+ DEFPUSHBUTTON "OK",IDOK,124,58,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,180,58,50,14
+ LTEXT "&Send action to screens:",IDC_STATIC,130,7,76,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_MAIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 293
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 192
+ END
+
+ IDD_ADD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 185
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 247
+ END
+
+ IDD_WAIT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 47
+ END
+
+ IDD_AUTOSTART, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 188
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 182
+ END
+
+ IDD_GLOBAL_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 200
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 283
+ END
+
+ IDD_ADVANCED_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 179
+ END
+
+ IDD_SCREENS_LINKS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 347
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 206
+ END
+
+ IDD_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 88
+ END
+
+ IDD_HOTKEY_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 353
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 144
+ END
+
+ IDD_HOTKEY_CONDITION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 176
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 51
+ END
+
+ IDD_HOTKEY_ACTION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 176
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 195
+ END
+
+ IDD_HOTKEY_SCREENS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 230
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 72
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SYNERGY ICON DISCARDABLE "synergy.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_ERROR "Error"
+ IDS_INVALID_SCREEN_NAME "Screen name `%{1}' is invalid."
+ IDS_DUPLICATE_SCREEN_NAME "The screen name `%{1}' is already being used."
+ IDS_SCREEN_NAME_IS_ALIAS "A name may not be an alias of itself."
+ IDS_VERIFY "Confirm"
+ IDS_UNSAVED_DATA_REALLY_QUIT "You have unsaved changes. Really quit?"
+ IDS_UNKNOWN_SCREEN_NAME "The screen name `%{1}' is not in the layout."
+ IDS_INVALID_PORT "The port `%{1}' is invalid. It must be between 1 and 65535 inclusive. %{2} is the standard port."
+ IDS_SAVE_FAILED "Failed to save configuration: %{1}"
+ IDS_STARTUP_FAILED "Failed to start synergy: %{1}"
+ IDS_STARTED_TITLE "Started"
+ IDS_STARTED "Synergy was successfully started. Use the task manager or tray icon to terminate it."
+ IDS_UNINSTALL_TITLE "Removed Auto-Start"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_AUTOSTART_PERMISSION_SYSTEM
+ "You have sufficient access rights to install and uninstall Auto Start for all users."
+ IDS_AUTOSTART_PERMISSION_USER
+ "You have sufficient access rights to install and uninstall Auto Start for just yourself."
+ IDS_AUTOSTART_PERMISSION_NONE
+ "You do not have sufficient access rights to install or uninstall Auto Start."
+ IDS_AUTOSTART_INSTALLED_SYSTEM
+ "Synergy is configured to start automatically when the system starts."
+ IDS_AUTOSTART_INSTALLED_USER
+ "Synergy is configured to start automatically when you log in."
+ IDS_AUTOSTART_INSTALLED_NONE
+ "Synergy is not configured to start automatically."
+ IDS_INSTALL_LABEL "Install"
+ IDS_UNINSTALL_LABEL "Uninstall"
+ IDS_INSTALL_GENERIC_ERROR "Install failed: %{1}"
+ IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed: %{1}"
+ IDS_INSTALL_TITLE "Installed Auto-Start"
+ IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will automatically start each time you start your computer."
+ IDS_INSTALLED_USER "Installed auto-start. Synergy will automatically start each time you log in."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_UNINSTALLED_SYSTEM "Removed auto-start. Synergy will not automatically start each time you start or reboot your computer."
+ IDS_UNINSTALLED_USER "Removed auto-start. Synergy will not automatically start each time you log in."
+ IDS_INVALID_SERVER_NAME "Server name `%{1}' is invalid."
+ IDS_TITLE "Synergy - Version %{1}"
+ IDS_SERVER_IS_CLIENT "Please enter the name of the computer sharing a\nkeyboard and mouse, not the name of this computer,\nin the Other Computer's Host Name field."
+ IDS_ADD_SCREEN "Add Screen"
+ IDS_EDIT_SCREEN "Edit Screen %{1}"
+ IDS_ERROR_CODE "Error code: %{1}"
+ IDS_AUTOSTART_PERMISSION_ALL
+ "You have sufficient access rights to install and uninstall Auto Start for all users or for just yourself."
+ IDS_INVALID_INTERFACE_NAME "The interface '%{1}' is invalid: %{2}"
+ IDS_INVALID_CORNER_SIZE "The dead corner size %{1} is invalid; it must be 0 or higher."
+ IDS_NEW_LINK "[New Link]"
+ IDS_SIDE_LEFT "left of"
+ IDS_SIDE_RIGHT "right of"
+ IDS_SIDE_TOP "above"
+ IDS_SIDE_BOTTOM "below"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_LINK_FORMAT "%{4}%{5} is %{3} %{1}%{2}"
+ IDS_LINK_INTERVAL_FORMAT "(%{1},%{2})"
+ IDS_EDGE_LEFT "left"
+ IDS_EDGE_RIGHT "right"
+ IDS_EDGE_TOP "top"
+ IDS_EDGE_BOTTOM "bottom"
+ IDS_AUTOSTART_SAVE_FAILED "Failed to save autostart configuration: %{1}"
+ IDS_LOAD_FAILED "Failed to load configuration."
+ IDS_CONFIG_CHANGED "Configuration changed on disk. Reload?"
+ IDS_MODE_OFF "off"
+ IDS_MODE_ON "on"
+ IDS_MODE_TOGGLE "toggle"
+ IDS_ALL_SCREENS "All Screens"
+ IDS_ACTIVE_SCREEN "Active Screen"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/cmd/launcher/resource.h b/cmd/launcher/resource.h
new file mode 100644
index 00000000..f284fd62
--- /dev/null
+++ b/cmd/launcher/resource.h
@@ -0,0 +1,186 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by launcher.rc
+//
+#define IDS_ERROR 1
+#define IDS_INVALID_SCREEN_NAME 2
+#define IDS_DUPLICATE_SCREEN_NAME 3
+#define IDS_SCREEN_NAME_IS_ALIAS 4
+#define IDS_VERIFY 5
+#define IDS_UNSAVED_DATA_REALLY_QUIT 6
+#define IDS_UNKNOWN_SCREEN_NAME 7
+#define IDS_INVALID_PORT 8
+#define IDS_SAVE_FAILED 9
+#define IDS_STARTUP_FAILED 10
+#define IDS_STARTED_TITLE 11
+#define IDS_STARTED 12
+#define IDS_INSTALL_FAILED 13
+#define IDS_UNINSTALL_TITLE 14
+#define IDS_UNINSTALLED 15
+#define IDS_UNINSTALL_FAILED 16
+#define IDS_CLIENT 17
+#define IDS_SERVER 18
+#define IDS_AUTOSTART_PERMISSION_SYSTEM 19
+#define IDS_AUTOSTART_PERMISSION_USER 20
+#define IDS_AUTOSTART_PERMISSION_NONE 21
+#define IDS_AUTOSTART_INSTALLED_SYSTEM 22
+#define IDS_AUTOSTART_INSTALLED_USER 23
+#define IDS_AUTOSTART_INSTALLED_NONE 24
+#define IDS_INSTALL_LABEL 25
+#define IDS_UNINSTALL_LABEL 26
+#define IDS_INSTALL_GENERIC_ERROR 27
+#define IDS_UNINSTALL_GENERIC_ERROR 28
+#define IDS_INSTALL_TITLE 29
+#define IDS_INSTALLED_SYSTEM 30
+#define IDS_INSTALLED_USER 31
+#define IDS_UNINSTALLED_SYSTEM 32
+#define IDS_UNINSTALLED_USER 33
+#define IDS_INVALID_SERVER_NAME 34
+#define IDS_TITLE 35
+#define IDS_SERVER_IS_CLIENT 36
+#define IDS_ADD_SCREEN 37
+#define IDS_EDIT_SCREEN 38
+#define IDS_INVALID_TIME 39
+#define IDS_ERROR_CODE 39
+#define IDS_AUTOSTART_PERMISSION_ALL 40
+#define IDS_INVALID_INTERFACE_NAME 41
+#define IDS_INVALID_CORNER_SIZE 42
+#define IDS_NEW_LINK 43
+#define IDS_SIDE_LEFT 44
+#define IDS_SIDE_RIGHT 45
+#define IDS_SIDE_TOP 46
+#define IDS_SIDE_BOTTOM 47
+#define IDS_LINK_FORMAT 48
+#define IDS_LINK_INTERVAL_FORMAT 49
+#define IDS_EDGE_LEFT 50
+#define IDS_EDGE_RIGHT 51
+#define IDS_EDGE_TOP 52
+#define IDS_EDGE_BOTTOM 53
+#define IDS_AUTOSTART_SAVE_FAILED 54
+#define IDS_LOAD_FAILED 55
+#define IDS_CONFIG_CHANGED 56
+#define IDS_MODE_OFF 57
+#define IDS_MODE_ON 58
+#define IDS_MODE_TOGGLE 59
+#define IDS_ALL_SCREENS 60
+#define IDS_ACTIVE_SCREEN 61
+#define IDD_MAIN 101
+#define IDD_ADD 102
+#define IDD_WAIT 103
+#define IDI_SYNERGY 104
+#define IDD_AUTOSTART 105
+#define IDD_ADVANCED_OPTIONS 106
+#define IDD_GLOBAL_OPTIONS 107
+#define IDD_SCREENS_LINKS 110
+#define IDD_INFO 111
+#define IDD_HOTKEY_OPTIONS 112
+#define IDD_HOTKEY_CONDITION 113
+#define IDD_HOTKEY_ACTION 114
+#define IDD_HOTKEY_SCREENS 115
+#define IDC_MAIN_CLIENT_RADIO 1000
+#define IDC_MAIN_SERVER_RADIO 1001
+#define IDC_MAIN_CLIENT_SERVER_NAME_LABEL 1002
+#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1003
+#define IDC_MAIN_SERVER_SCREENS_LABEL 1004
+#define IDC_MAIN_SCREENS 1005
+#define IDC_MAIN_OPTIONS 1006
+#define IDC_MAIN_ADVANCED 1007
+#define IDC_MAIN_AUTOSTART 1008
+#define IDC_MAIN_TEST 1009
+#define IDC_MAIN_SAVE 1010
+#define IDC_MAIN_HOTKEYS 1010
+#define IDC_MAIN_DEBUG 1011
+#define IDC_ADD_SCREEN_NAME_EDIT 1020
+#define IDC_ADD_ALIASES_EDIT 1021
+#define IDC_AUTOSTART_INSTALLED_MSG 1031
+#define IDC_AUTOSTART_PERMISSION_MSG 1032
+#define IDC_AUTOSTART_INSTALL_USER 1033
+#define IDC_AUTOSTART_INSTALL_SYSTEM 1034
+#define IDC_ADD_HD_CAPS_CHECK 1037
+#define IDC_ADD_HD_NUM_CHECK 1038
+#define IDC_ADVANCED_NAME_EDIT 1038
+#define IDC_ADVANCED_PORT_EDIT 1039
+#define IDC_ADD_HD_SCROLL_CHECK 1039
+#define IDC_ADVANCED_INTERFACE_EDIT 1040
+#define IDC_GLOBAL_DELAY_CHECK 1041
+#define IDC_GLOBAL_DELAY_TIME 1042
+#define IDC_GLOBAL_TWO_TAP_CHECK 1043
+#define IDC_ADD_MOD_SHIFT 1043
+#define IDC_GLOBAL_TWO_TAP_TIME 1044
+#define IDC_ADD_MOD_CTRL 1044
+#define IDC_ADD_MOD_ALT 1045
+#define IDC_GLOBAL_HEARTBEAT_CHECK 1045
+#define IDC_ADD_MOD_META 1046
+#define IDC_GLOBAL_HEARTBEAT_TIME 1046
+#define IDC_ADD_MOD_SUPER 1047
+#define IDC_GLOBAL_SCREENSAVER_SYNC 1047
+#define IDC_GLOBAL_RELATIVE_MOVES 1048
+#define IDC_ADVANCED_DEFAULTS 1049
+#define IDC_GLOBAL_LEAVE_FOREGROUND 1049
+#define IDC_ADD_DC_SIZE 1052
+#define IDC_ADD_DC_TOP_LEFT 1053
+#define IDC_ADD_DC_TOP_RIGHT 1054
+#define IDC_ADD_DC_BOTTOM_LEFT 1055
+#define IDC_ADD_DC_BOTTOM_RIGHT 1056
+#define IDC_SCREENS_SRC_SIDE 1057
+#define IDC_SCREENS_SRC_START 1058
+#define IDC_SCREENS_SRC_END 1059
+#define IDC_SCREENS_SRC_SCREEN 1060
+#define IDC_SCREENS_SCREENS 1061
+#define IDC_SCREENS_ADD_SCREEN 1062
+#define IDC_SCREENS_LINKS 1063
+#define IDC_SCREENS_DST_START 1064
+#define IDC_SCREENS_DST_END 1065
+#define IDC_SCREENS_DST_SCREEN 1066
+#define IDC_SCREENS_REMOVE_SCREEN 1067
+#define IDC_SCREENS_EDIT_SCREEN 1068
+#define IDC_SCREENS_ADD_LINK 1069
+#define IDC_SCREENS_REMOVE_LINK 1070
+#define IDC_SCREENS_OVERLAP_ERROR 1071
+#define IDC_INFO_VERSION 1073
+#define IDC_MAIN_INFO 1074
+#define IDC_INFO_HOSTNAME 1076
+#define IDC_HOTKEY_HOTKEYS 1076
+#define IDC_INFO_IP_ADDRESS 1077
+#define IDC_HOTKEY_ADD_HOTKEY 1077
+#define IDC_INFO_USER_CONFIG 1078
+#define IDC_HOTKEY_REMOVE_HOTKEY 1078
+#define IDC_INFO_SYS_CONFIG 1079
+#define IDC_HOTKEY_EDIT_HOTKEY 1079
+#define IDC_HOTKEY_ACTIONS 1080
+#define IDC_HOTKEY_CONDITION_HOTKEY 1080
+#define IDC_HOTKEY_ACTION_DOWNUP 1081
+#define IDC_HOTKEY_ADD_ACTION 1082
+#define IDC_HOTKEY_ACTION_DOWN 1082
+#define IDC_HOTKEY_REMOVE_ACTION 1083
+#define IDC_HOTKEY_ACTION_UP 1083
+#define IDC_HOTKEY_EDIT_ACTION 1084
+#define IDC_HOTKEY_ACTION_HOTKEY 1085
+#define IDC_HOTKEY_ACTION_SWITCH_TO_LIST 1086
+#define IDC_HOTKEY_ACTION_SWITCH_TO 1087
+#define IDC_HOTKEY_ACTION_SWITCH_IN 1088
+#define IDC_HOTKEY_ACTION_LOCK 1089
+#define IDC_HOTKEY_ACTION_SWITCH_IN_LIST 1090
+#define IDC_HOTKEY_ACTION_LOCK_LIST 1091
+#define IDC_HOTKEY_ACTION_ON_ACTIVATE 1092
+#define IDC_HOTKEY_ACTION_ON_DEACTIVATE 1093
+#define IDC_HOTKEY_ACTION_SCREENS 1094
+#define IDC_HOTKEY_SCREENS_SRC 1095
+#define IDC_HOTKEY_SCREENS_DST 1096
+#define IDC_HOTKEY_SCREENS_ADD 1097
+#define IDC_HOTKEY_SCREENS_REMOVE 1098
+#define IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST 1099
+#define IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_LIST 1100
+#define IDC_HOTKEY_ACTION_KEYBOARD_BROADCAST_SCREENS 1101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 116
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1102
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/cmd/launcher/synergy.ico b/cmd/launcher/synergy.ico
new file mode 100644
index 0000000000000000000000000000000000000000..89f965f4432c5f58054b9a1b0eae5bf6cbfd245d
GIT binary patch
literal 8478
zcmeI1KWH3B6vm(a*e8S|%Z-~Dq__}vXV}UrV&mT6#z|>aLkbt^+yrSM;8FwvhV6t%
zLQiZmzTr%%8baza{{iY$oC5(ZeHZtwQ9U1vh;!S!}zl^B0qm9a)se4
z$4!nI!GV?&yT9dtAbB1-&RoiHIHXs=+duJMuQ>Qqlb(9p`ug^E1I+I3?(XmJkD_Ir
zwoR+XpoZ`7n_*F5!?$xa7_9y@9UB~QjWDbDj>v-IqX1iNmO=`Jq0y9JcvU(jnEQ^w
z7Gb2>!%ze~pRL_3zyv-RkH?YkoZDF1+}w=gwY9a?KK%1QIIFneKdQ#~i{M`c0A3Tt
z1K}(%xF*;nf_mc~2;;GW3Worjn~JKt$bbM9zM*5w5O5oY2+>S!bo#xVIM#9I(&{w)eJBUN
zeJAtt^Rlq8Am`4VlM5Fv$i<5n<({SK{)Lx2
zcf5QpPsRUH%CArVl&9mdeD%YRB+58+ffXEO7-rZqY#FvpZQOaKIPAI@9d?J^VOO^T
zdx5=RP+%{x(@BZF#9m@AF_hRnW6#)^mO0~`5j-PMhEvA(o2BQJp&>&8GBjjp$k32^Z0N|)k*N+oJ*YAjjs+pbjlo20;DbJG3~oSXt2F(BaVG(BaTwr9y{8gF}NugO<*r!=b^Up|o%I
zGL(=!;g7MESF3|6au@Kd)Z{MERFJeFL4l@%+y!7k?t?N}3)s-$(csbG(csbG(O}C74J8^p8ax_G
zG!TXZJ{mk4JQ_S22+e^V4IT|14ITlW{3XFWjvkUDhGXo|;VrguoO~qT%DsE{eVYbJUo4A)*c53emtZek(@;r+A&?7`%alYMX$a
zY+S?5oN9)eBHqA@i;?Pjweae)tI(w2f&-E#+${e5S>63iAM`TagzjPcMcFJ$Y(hZaAL
zK9Rw|H_|&9)FI_tfX*qMLxQ;r%W>h`ir$IeFQ=8D75`u1H(R)5quI_B_inZY
z`w#h31SN9V5+-_1#7`aC(~P4ezM76pkkD<1n(})TrS!0)eWSx9y(K8_{d=_ISy@{N
zT9R7PBfXOV?+~X=Zo;=qR3)1r*J?T?JqdqOQS0|g$Q4UqeS6A`CiJxElT+yOJM;;M
z4u68)b!hW@=$O(;r2KxiS{sjsKb@U=ME;xEhFTKipMZQE#eS#RJDbrUyt}d2IpX6>
za(ySP_)ug{dwv(qXfHHQN7`?RK8(?u08Lb>z>#22Rc4!-|>%e>pWH7s3Yo%I-~CHeBwOgyeWaz
zp{~oYs#C06tRuuw-%(X(t$cW&zD$T!j`%zECiCoXIRyaW$EkIkxjg-ydip!{^nLpK
z@IIZrF`MQ1m2Nxb=7&PqIET$NlxiPcZLX`ax&{w}LnJfkI1B@$JJyFz#P!+JH%|8{
t;Zdj_)sxDeTJ=5vdoUQ9?87Q{NCkzlT_5sH8R_#vpACFJzU}{8{tX4i2$ui=
literal 0
HcmV?d00001
diff --git a/cmd/synergyc/CClientTaskBarReceiver.cpp b/cmd/synergyc/CClientTaskBarReceiver.cpp
new file mode 100644
index 00000000..025b43f6
--- /dev/null
+++ b/cmd/synergyc/CClientTaskBarReceiver.cpp
@@ -0,0 +1,136 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CClientTaskBarReceiver.h"
+#include "CClient.h"
+#include "CLock.h"
+#include "CStringUtil.h"
+#include "IEventQueue.h"
+#include "CArch.h"
+#include "Version.h"
+
+//
+// CClientTaskBarReceiver
+//
+
+CClientTaskBarReceiver::CClientTaskBarReceiver() :
+ m_state(kNotRunning)
+{
+ // do nothing
+}
+
+CClientTaskBarReceiver::~CClientTaskBarReceiver()
+{
+ // do nothing
+}
+
+void
+CClientTaskBarReceiver::updateStatus(CClient* client, const CString& errorMsg)
+{
+ {
+ // update our status
+ m_errorMessage = errorMsg;
+ if (client == NULL) {
+ if (m_errorMessage.empty()) {
+ m_state = kNotRunning;
+ }
+ else {
+ m_state = kNotWorking;
+ }
+ }
+ else {
+ m_server = client->getServerAddress().getHostname();
+
+ if (client->isConnected()) {
+ m_state = kConnected;
+ }
+ else if (client->isConnecting()) {
+ m_state = kConnecting;
+ }
+ else {
+ m_state = kNotConnected;
+ }
+ }
+
+ // let subclasses have a go
+ onStatusChanged(client);
+ }
+
+ // tell task bar
+ ARCH->updateReceiver(this);
+}
+
+CClientTaskBarReceiver::EState
+CClientTaskBarReceiver::getStatus() const
+{
+ return m_state;
+}
+
+const CString&
+CClientTaskBarReceiver::getErrorMessage() const
+{
+ return m_errorMessage;
+}
+
+void
+CClientTaskBarReceiver::quit()
+{
+ EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
+}
+
+void
+CClientTaskBarReceiver::onStatusChanged(CClient*)
+{
+ // do nothing
+}
+
+void
+CClientTaskBarReceiver::lock() const
+{
+ // do nothing
+}
+
+void
+CClientTaskBarReceiver::unlock() const
+{
+ // do nothing
+}
+
+std::string
+CClientTaskBarReceiver::getToolTip() const
+{
+ switch (m_state) {
+ case kNotRunning:
+ return CStringUtil::print("%s: Not running", kAppVersion);
+
+ case kNotWorking:
+ return CStringUtil::print("%s: %s",
+ kAppVersion, m_errorMessage.c_str());
+
+ case kNotConnected:
+ return CStringUtil::print("%s: Not connected: %s",
+ kAppVersion, m_errorMessage.c_str());
+
+ case kConnecting:
+ return CStringUtil::print("%s: Connecting to %s...",
+ kAppVersion, m_server.c_str());
+
+ case kConnected:
+ return CStringUtil::print("%s: Connected to %s",
+ kAppVersion, m_server.c_str());
+
+ default:
+ return "";
+ }
+}
diff --git a/cmd/synergyc/CClientTaskBarReceiver.h b/cmd/synergyc/CClientTaskBarReceiver.h
new file mode 100644
index 00000000..0e3440e1
--- /dev/null
+++ b/cmd/synergyc/CClientTaskBarReceiver.h
@@ -0,0 +1,83 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CCLIENTTASKBARRECEIVER_H
+#define CCLIENTTASKBARRECEIVER_H
+
+#include "CString.h"
+#include "IArchTaskBarReceiver.h"
+
+class CClient;
+
+//! Implementation of IArchTaskBarReceiver for the synergy server
+class CClientTaskBarReceiver : public IArchTaskBarReceiver {
+public:
+ CClientTaskBarReceiver();
+ virtual ~CClientTaskBarReceiver();
+
+ //! @name manipulators
+ //@{
+
+ //! Update status
+ /*!
+ Determine the status and query required information from the client.
+ */
+ void updateStatus(CClient*, const CString& errorMsg);
+
+ //@}
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus() = 0;
+ virtual void runMenu(int x, int y) = 0;
+ virtual void primaryAction() = 0;
+ virtual void lock() const;
+ virtual void unlock() const;
+ virtual const Icon getIcon() const = 0;
+ virtual std::string getToolTip() const;
+
+protected:
+ enum EState {
+ kNotRunning,
+ kNotWorking,
+ kNotConnected,
+ kConnecting,
+ kConnected,
+ kMaxState
+ };
+
+ //! Get status
+ EState getStatus() const;
+
+ //! Get error message
+ const CString& getErrorMessage() const;
+
+ //! Quit app
+ /*!
+ Causes the application to quit gracefully
+ */
+ void quit();
+
+ //! Status change notification
+ /*!
+ Called when status changes. The default implementation does nothing.
+ */
+ virtual void onStatusChanged(CClient* client);
+
+private:
+ EState m_state;
+ CString m_errorMessage;
+ CString m_server;
+};
+
+#endif
diff --git a/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp b/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
new file mode 100644
index 00000000..c002b9f1
--- /dev/null
+++ b/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
@@ -0,0 +1,346 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CMSWindowsClientTaskBarReceiver.h"
+#include "CClient.h"
+#include "CMSWindowsClipboard.h"
+#include "LogOutputters.h"
+#include "BasicTypes.h"
+#include "CArch.h"
+#include "CArchTaskBarWindows.h"
+#include "resource.h"
+
+//
+// CMSWindowsClientTaskBarReceiver
+//
+
+const UINT CMSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] =
+{
+ IDI_TASKBAR_NOT_RUNNING,
+ IDI_TASKBAR_NOT_WORKING,
+ IDI_TASKBAR_NOT_CONNECTED,
+ IDI_TASKBAR_NOT_CONNECTED,
+ IDI_TASKBAR_CONNECTED
+};
+
+CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
+ HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
+ CClientTaskBarReceiver(),
+ m_appInstance(appInstance),
+ m_window(NULL),
+ m_logBuffer(logBuffer)
+{
+ for (UInt32 i = 0; i < kMaxState; ++i) {
+ m_icon[i] = loadIcon(s_stateToIconID[i]);
+ }
+ m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
+
+ // don't create the window yet. we'll create it on demand. this
+ // has the side benefit of being created in the thread used for
+ // the task bar. that's good because it means the existence of
+ // the window won't prevent changing the main thread's desktop.
+
+ // add ourself to the task bar
+ ARCH->addReceiver(this);
+}
+
+CMSWindowsClientTaskBarReceiver::~CMSWindowsClientTaskBarReceiver()
+{
+ ARCH->removeReceiver(this);
+ for (UInt32 i = 0; i < kMaxState; ++i) {
+ deleteIcon(m_icon[i]);
+ }
+ DestroyMenu(m_menu);
+ destroyWindow();
+}
+
+void
+CMSWindowsClientTaskBarReceiver::showStatus()
+{
+ // create the window
+ createWindow();
+
+ // lock self while getting status
+ lock();
+
+ // get the current status
+ std::string status = getToolTip();
+
+ // done getting status
+ unlock();
+
+ // update dialog
+ HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
+
+ if (!IsWindowVisible(m_window)) {
+ // position it by the mouse
+ POINT cursorPos;
+ GetCursorPos(&cursorPos);
+ RECT windowRect;
+ GetWindowRect(m_window, &windowRect);
+ int x = cursorPos.x;
+ int y = cursorPos.y;
+ int fw = GetSystemMetrics(SM_CXDLGFRAME);
+ int fh = GetSystemMetrics(SM_CYDLGFRAME);
+ int ww = windowRect.right - windowRect.left;
+ int wh = windowRect.bottom - windowRect.top;
+ int sw = GetSystemMetrics(SM_CXFULLSCREEN);
+ int sh = GetSystemMetrics(SM_CYFULLSCREEN);
+ if (fw < 1) {
+ fw = 1;
+ }
+ if (fh < 1) {
+ fh = 1;
+ }
+ if (x + ww - fw > sw) {
+ x -= ww - fw;
+ }
+ else {
+ x -= fw;
+ }
+ if (x < 0) {
+ x = 0;
+ }
+ if (y + wh - fh > sh) {
+ y -= wh - fh;
+ }
+ else {
+ y -= fh;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+ SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
+ SWP_SHOWWINDOW);
+ }
+}
+
+void
+CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
+{
+ // do popup menu. we need a window to pass to TrackPopupMenu().
+ // the SetForegroundWindow() and SendMessage() calls around
+ // TrackPopupMenu() are to get the menu to be dismissed when
+ // another window gets activated and are just one of those
+ // win32 weirdnesses.
+ createWindow();
+ SetForegroundWindow(m_window);
+ HMENU menu = GetSubMenu(m_menu, 0);
+ SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
+ HMENU logLevelMenu = GetSubMenu(menu, 3);
+ CheckMenuRadioItem(logLevelMenu, 0, 6,
+ CLOG->getFilter() - CLog::kERROR, MF_BYPOSITION);
+ int n = TrackPopupMenu(menu,
+ TPM_NONOTIFY |
+ TPM_RETURNCMD |
+ TPM_LEFTBUTTON |
+ TPM_RIGHTBUTTON,
+ x, y, 0, m_window, NULL);
+ SendMessage(m_window, WM_NULL, 0, 0);
+
+ // perform the requested operation
+ switch (n) {
+ case IDC_TASKBAR_STATUS:
+ showStatus();
+ break;
+
+ case IDC_TASKBAR_LOG:
+ copyLog();
+ break;
+
+ case IDC_TASKBAR_SHOW_LOG:
+ ARCH->showConsole(true);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_ERROR:
+ CLOG->setFilter(CLog::kERROR);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_WARNING:
+ CLOG->setFilter(CLog::kWARNING);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_NOTE:
+ CLOG->setFilter(CLog::kNOTE);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_INFO:
+ CLOG->setFilter(CLog::kINFO);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_DEBUG:
+ CLOG->setFilter(CLog::kDEBUG);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_DEBUG1:
+ CLOG->setFilter(CLog::kDEBUG1);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_DEBUG2:
+ CLOG->setFilter(CLog::kDEBUG2);
+ break;
+
+ case IDC_TASKBAR_QUIT:
+ quit();
+ break;
+ }
+}
+
+void
+CMSWindowsClientTaskBarReceiver::primaryAction()
+{
+ showStatus();
+}
+
+const IArchTaskBarReceiver::Icon
+CMSWindowsClientTaskBarReceiver::getIcon() const
+{
+ return reinterpret_cast(m_icon[getStatus()]);
+}
+
+void
+CMSWindowsClientTaskBarReceiver::copyLog() const
+{
+ if (m_logBuffer != NULL) {
+ // collect log buffer
+ CString data;
+ for (CBufferedLogOutputter::const_iterator index = m_logBuffer->begin();
+ index != m_logBuffer->end(); ++index) {
+ data += *index;
+ data += "\n";
+ }
+
+ // copy log to clipboard
+ if (!data.empty()) {
+ CMSWindowsClipboard clipboard(m_window);
+ clipboard.open(0);
+ clipboard.emptyUnowned();
+ clipboard.add(IClipboard::kText, data);
+ clipboard.close();
+ }
+ }
+}
+
+void
+CMSWindowsClientTaskBarReceiver::onStatusChanged()
+{
+ if (IsWindowVisible(m_window)) {
+ showStatus();
+ }
+}
+
+HICON
+CMSWindowsClientTaskBarReceiver::loadIcon(UINT id)
+{
+ HANDLE icon = LoadImage(m_appInstance,
+ MAKEINTRESOURCE(id),
+ IMAGE_ICON,
+ 0, 0,
+ LR_DEFAULTCOLOR);
+ return reinterpret_cast(icon);
+}
+
+void
+CMSWindowsClientTaskBarReceiver::deleteIcon(HICON icon)
+{
+ if (icon != NULL) {
+ DestroyIcon(icon);
+ }
+}
+
+void
+CMSWindowsClientTaskBarReceiver::createWindow()
+{
+ // ignore if already created
+ if (m_window != NULL) {
+ return;
+ }
+
+ // get the status dialog
+ m_window = CreateDialogParam(m_appInstance,
+ MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
+ NULL,
+ (DLGPROC)&CMSWindowsClientTaskBarReceiver::staticDlgProc,
+ reinterpret_cast(
+ reinterpret_cast(this)));
+
+ // window should appear on top of everything, including (especially)
+ // the task bar.
+ LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE);
+ style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+ SetWindowLongPtr(m_window, GWL_EXSTYLE, style);
+
+ // tell the task bar about this dialog
+ CArchTaskBarWindows::addDialog(m_window);
+}
+
+void
+CMSWindowsClientTaskBarReceiver::destroyWindow()
+{
+ if (m_window != NULL) {
+ CArchTaskBarWindows::removeDialog(m_window);
+ DestroyWindow(m_window);
+ m_window = NULL;
+ }
+}
+
+BOOL
+CMSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ // use default focus
+ return TRUE;
+
+ case WM_ACTIVATE:
+ // hide when another window is activated
+ if (LOWORD(wParam) == WA_INACTIVE) {
+ ShowWindow(hwnd, SW_HIDE);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK
+CMSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ // if msg is WM_INITDIALOG, extract the CMSWindowsClientTaskBarReceiver*
+ // and put it in the extra window data then forward the call.
+ CMSWindowsClientTaskBarReceiver* self = NULL;
+ if (msg == WM_INITDIALOG) {
+ self = reinterpret_cast(
+ reinterpret_cast(lParam));
+ SetWindowLong(hwnd, GWL_USERDATA, lParam);
+ }
+ else {
+ // get the extra window data and forward the call
+ LONG data = GetWindowLong(hwnd, GWL_USERDATA);
+ if (data != 0) {
+ self = reinterpret_cast(
+ reinterpret_cast(data));
+ }
+ }
+
+ // forward the message
+ if (self != NULL) {
+ return self->dlgProc(hwnd, msg, wParam, lParam);
+ }
+ else {
+ return (msg == WM_INITDIALOG) ? TRUE : FALSE;
+ }
+}
diff --git a/cmd/synergyc/CMSWindowsClientTaskBarReceiver.h b/cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
new file mode 100644
index 00000000..72d33be5
--- /dev/null
+++ b/cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
@@ -0,0 +1,64 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CMSWINDOWSCLIENTTASKBARRECEIVER_H
+#define CMSWINDOWSCLIENTTASKBARRECEIVER_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "CClientTaskBarReceiver.h"
+#include
+
+class CBufferedLogOutputter;
+
+//! Implementation of CClientTaskBarReceiver for Microsoft Windows
+class CMSWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
+public:
+ CMSWindowsClientTaskBarReceiver(HINSTANCE, const CBufferedLogOutputter*);
+ virtual ~CMSWindowsClientTaskBarReceiver();
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus();
+ virtual void runMenu(int x, int y);
+ virtual void primaryAction();
+ virtual const Icon getIcon() const;
+
+protected:
+ void copyLog() const;
+
+ // CClientTaskBarReceiver overrides
+ virtual void onStatusChanged();
+
+private:
+ HICON loadIcon(UINT);
+ void deleteIcon(HICON);
+ void createWindow();
+ void destroyWindow();
+
+ BOOL dlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam);
+ static BOOL CALLBACK
+ staticDlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ HINSTANCE m_appInstance;
+ HWND m_window;
+ HMENU m_menu;
+ HICON m_icon[kMaxState];
+ const CBufferedLogOutputter* m_logBuffer;
+ static const UINT s_stateToIconID[];
+};
+
+#endif
diff --git a/cmd/synergyc/COSXClientTaskBarReceiver.cpp b/cmd/synergyc/COSXClientTaskBarReceiver.cpp
new file mode 100644
index 00000000..c380ac4d
--- /dev/null
+++ b/cmd/synergyc/COSXClientTaskBarReceiver.cpp
@@ -0,0 +1,56 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "COSXClientTaskBarReceiver.h"
+#include "CArch.h"
+
+//
+// COSXClientTaskBarReceiver
+//
+
+COSXClientTaskBarReceiver::COSXClientTaskBarReceiver(
+ const CBufferedLogOutputter*)
+{
+ // add ourself to the task bar
+ ARCH->addReceiver(this);
+}
+
+COSXClientTaskBarReceiver::~COSXClientTaskBarReceiver()
+{
+ ARCH->removeReceiver(this);
+}
+
+void
+COSXClientTaskBarReceiver::showStatus()
+{
+ // do nothing
+}
+
+void
+COSXClientTaskBarReceiver::runMenu(int, int)
+{
+ // do nothing
+}
+
+void
+COSXClientTaskBarReceiver::primaryAction()
+{
+ // do nothing
+}
+
+const IArchTaskBarReceiver::Icon
+COSXClientTaskBarReceiver::getIcon() const
+{
+ return NULL;
+}
diff --git a/cmd/synergyc/COSXClientTaskBarReceiver.h b/cmd/synergyc/COSXClientTaskBarReceiver.h
new file mode 100644
index 00000000..59bca97c
--- /dev/null
+++ b/cmd/synergyc/COSXClientTaskBarReceiver.h
@@ -0,0 +1,35 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef COSXCLIENTTASKBARRECEIVER_H
+#define COSXCLIENTTASKBARRECEIVER_H
+
+#include "CClientTaskBarReceiver.h"
+
+class CBufferedLogOutputter;
+
+//! Implementation of CClientTaskBarReceiver for OS X
+class COSXClientTaskBarReceiver : public CClientTaskBarReceiver {
+public:
+ COSXClientTaskBarReceiver(const CBufferedLogOutputter*);
+ virtual ~COSXClientTaskBarReceiver();
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus();
+ virtual void runMenu(int x, int y);
+ virtual void primaryAction();
+ virtual const Icon getIcon() const;
+};
+
+#endif
diff --git a/cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp b/cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
new file mode 100644
index 00000000..681f9be5
--- /dev/null
+++ b/cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
@@ -0,0 +1,56 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CXWindowsClientTaskBarReceiver.h"
+#include "CArch.h"
+
+//
+// CXWindowsClientTaskBarReceiver
+//
+
+CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(
+ const CBufferedLogOutputter*)
+{
+ // add ourself to the task bar
+ ARCH->addReceiver(this);
+}
+
+CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver()
+{
+ ARCH->removeReceiver(this);
+}
+
+void
+CXWindowsClientTaskBarReceiver::showStatus()
+{
+ // do nothing
+}
+
+void
+CXWindowsClientTaskBarReceiver::runMenu(int, int)
+{
+ // do nothing
+}
+
+void
+CXWindowsClientTaskBarReceiver::primaryAction()
+{
+ // do nothing
+}
+
+const IArchTaskBarReceiver::Icon
+CXWindowsClientTaskBarReceiver::getIcon() const
+{
+ return NULL;
+}
diff --git a/cmd/synergyc/CXWindowsClientTaskBarReceiver.h b/cmd/synergyc/CXWindowsClientTaskBarReceiver.h
new file mode 100644
index 00000000..fa9da471
--- /dev/null
+++ b/cmd/synergyc/CXWindowsClientTaskBarReceiver.h
@@ -0,0 +1,35 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CXWINDOWSCLIENTTASKBARRECEIVER_H
+#define CXWINDOWSCLIENTTASKBARRECEIVER_H
+
+#include "CClientTaskBarReceiver.h"
+
+class CBufferedLogOutputter;
+
+//! Implementation of CClientTaskBarReceiver for X Windows
+class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
+public:
+ CXWindowsClientTaskBarReceiver(const CBufferedLogOutputter*);
+ virtual ~CXWindowsClientTaskBarReceiver();
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus();
+ virtual void runMenu(int x, int y);
+ virtual void primaryAction();
+ virtual const Icon getIcon() const;
+};
+
+#endif
diff --git a/cmd/synergyc/Makefile.am b/cmd/synergyc/Makefile.am
new file mode 100644
index 00000000..b6e8c83d
--- /dev/null
+++ b/cmd/synergyc/Makefile.am
@@ -0,0 +1,98 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+COMMON_SOURCE_FILES = \
+ CClientTaskBarReceiver.cpp \
+ CClientTaskBarReceiver.h \
+ synergyc.cpp \
+ $(NULL)
+XWINDOWS_SOURCE_FILES = \
+ CXWindowsClientTaskBarReceiver.cpp \
+ CXWindowsClientTaskBarReceiver.h \
+ $(NULL)
+MSWINDOWS_SOURCE_FILES = \
+ CMSWindowsClientTaskBarReceiver.cpp \
+ CMSWindowsClientTaskBarReceiver.h \
+ resource.h \
+ synergyc.rc \
+ $(NULL)
+CARBON_SOURCE_FILES = \
+ COSXClientTaskBarReceiver.cpp \
+ COSXClientTaskBarReceiver.h \
+ $(NULL)
+
+EXTRA_DIST = \
+ Makefile.win \
+ synergyc.ico \
+ tb_error.ico \
+ tb_idle.ico \
+ tb_run.ico \
+ tb_wait.ico \
+ $(XWINDOWS_SOURCE_FILES) \
+ $(MSWINDOWS_SOURCE_FILES) \
+ $(CARBON_SOURCE_FILES) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
+
+bin_PROGRAMS = synergyc
+if XWINDOWS
+synergyc_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(XWINDOWS_SOURCE_FILES) \
+ $(NULL)
+endif
+if MSWINDOWS
+synergyc_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(MSWINDOWS_SOURCE_FILES) \
+ $(NULL)
+endif
+if CARBON
+synergyc_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(CARBON_SOURCE_FILES) \
+ $(NULL)
+synergyc_LDFLAGS = \
+ -framework ScreenSaver \
+ -framework IOKit \
+ -framework ApplicationServices \
+ -framework Foundation \
+ $(NULL)
+endif
+synergyc_LDADD = \
+ $(top_builddir)/lib/client/libclient.a \
+ $(top_builddir)/lib/platform/libplatform.a \
+ $(top_builddir)/lib/synergy/libsynergy.a \
+ $(top_builddir)/lib/net/libnet.a \
+ $(top_builddir)/lib/io/libio.a \
+ $(top_builddir)/lib/mt/libmt.a \
+ $(top_builddir)/lib/base/libbase.a \
+ $(top_builddir)/lib/common/libcommon.a \
+ $(top_builddir)/lib/arch/libarch.a \
+ $(NULL)
+INCLUDES = \
+ -I$(top_srcdir)/lib/common \
+ -I$(top_srcdir)/lib/arch \
+ -I$(top_srcdir)/lib/base \
+ -I$(top_srcdir)/lib/mt \
+ -I$(top_srcdir)/lib/io \
+ -I$(top_srcdir)/lib/net \
+ -I$(top_srcdir)/lib/synergy \
+ -I$(top_srcdir)/lib/platform \
+ -I$(top_srcdir)/lib/client \
+ $(NULL)
diff --git a/cmd/synergyc/Makefile.win b/cmd/synergyc/Makefile.win
new file mode 100644
index 00000000..29f2e516
--- /dev/null
+++ b/cmd/synergyc/Makefile.win
@@ -0,0 +1,89 @@
+# synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2007 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.
+
+BIN_SYNERGYC_SRC = cmd\synergyc
+BIN_SYNERGYC_DST = $(BUILD_DST)\$(BIN_SYNERGYC_SRC)
+BIN_SYNERGYC_EXE = "$(BUILD_DST)\synergyc.exe"
+BIN_SYNERGYC_CPP = \
+ "CClientTaskBarReceiver.cpp" \
+ "CMSWindowsClientTaskBarReceiver.cpp" \
+ "synergyc.cpp" \
+ $(NULL)
+BIN_SYNERGYC_OBJ = \
+ "$(BIN_SYNERGYC_DST)\CClientTaskBarReceiver.obj" \
+ "$(BIN_SYNERGYC_DST)\CMSWindowsClientTaskBarReceiver.obj" \
+ "$(BIN_SYNERGYC_DST)\synergyc.obj" \
+ $(NULL)
+BIN_SYNERGYC_RC = "$(BIN_SYNERGYC_SRC)\synergyc.rc"
+BIN_SYNERGYC_RES = "$(BIN_SYNERGYC_DST)\synergyc.res"
+BIN_SYNERGYC_INC = \
+ /I"lib\common" \
+ /I"lib\arch" \
+ /I"lib\base" \
+ /I"lib\mt" \
+ /I"lib\io" \
+ /I"lib\net" \
+ /I"lib\synergy" \
+ /I"lib\platform" \
+ /I"lib\client" \
+ $(NULL)
+BIN_SYNERGYC_LIB = \
+ $(LIB_CLIENT_LIB) \
+ $(LIB_PLATFORM_LIB) \
+ $(LIB_SYNERGY_LIB) \
+ $(LIB_NET_LIB) \
+ $(LIB_IO_LIB) \
+ $(LIB_MT_LIB) \
+ $(LIB_BASE_LIB) \
+ $(LIB_ARCH_LIB) \
+ $(LIB_COMMON_LIB) \
+ $(NULL)
+
+CPP_FILES = $(CPP_FILES) $(BIN_SYNERGYC_CPP)
+OBJ_FILES = $(OBJ_FILES) $(BIN_SYNERGYC_OBJ)
+PROGRAMS = $(PROGRAMS) $(BIN_SYNERGYC_EXE)
+
+# Need shell functions.
+guilibs = $(guilibs) shell32.lib
+
+# Dependency rules
+$(BIN_SYNERGYC_OBJ): $(AUTODEP)
+!if EXIST($(BIN_SYNERGYC_DST)\deps.mak)
+!include $(BIN_SYNERGYC_DST)\deps.mak
+!endif
+
+# Build rules. Use batch-mode rules if possible.
+!if DEFINED(_NMAKE_VER)
+{$(BIN_SYNERGYC_SRC)\}.cpp{$(BIN_SYNERGYC_DST)\}.obj::
+!else
+{$(BIN_SYNERGYC_SRC)\}.cpp{$(BIN_SYNERGYC_DST)\}.obj:
+!endif
+ @$(ECHO) Compile in $(BIN_SYNERGYC_SRC)
+ -@$(MKDIR) $(BIN_SYNERGYC_DST) 2>NUL:
+ $(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
+ $(BIN_SYNERGYC_INC) \
+ /Fo$(BIN_SYNERGYC_DST)\ \
+ /Fd$(BIN_SYNERGYC_DST)\src.pdb \
+ $< | $(AUTODEP) $(BIN_SYNERGYC_SRC) $(BIN_SYNERGYC_DST)
+$(BIN_SYNERGYC_RES): $(BIN_SYNERGYC_RC)
+ @$(ECHO) Compile $(**F)
+ -@$(MKDIR) $(BIN_SYNERGYC_DST) 2>NUL:
+ $(rc) $(rcflags) $(rcvars) \
+ /fo$@ \
+ $**
+$(BIN_SYNERGYC_EXE): $(BIN_SYNERGYC_OBJ) $(BIN_SYNERGYC_RES) $(BIN_SYNERGYC_LIB)
+ @$(ECHO) Link $(@F)
+ $(link) $(ldebug) $(guilflags) $(guilibsmt) \
+ /out:$@ \
+ $**
+ $(AUTODEP) $(BIN_SYNERGYC_SRC) $(BIN_SYNERGYC_DST) \
+ $(BIN_SYNERGYC_OBJ:.obj=.d)
diff --git a/cmd/synergyc/resource.h b/cmd/synergyc/resource.h
new file mode 100644
index 00000000..eeee6e1e
--- /dev/null
+++ b/cmd/synergyc/resource.h
@@ -0,0 +1,37 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by synergyc.rc
+//
+#define IDS_FAILED 1
+#define IDS_INIT_FAILED 2
+#define IDS_UNCAUGHT_EXCEPTION 3
+#define IDI_SYNERGY 101
+#define IDI_TASKBAR_NOT_RUNNING 102
+#define IDI_TASKBAR_NOT_WORKING 103
+#define IDI_TASKBAR_NOT_CONNECTED 104
+#define IDI_TASKBAR_CONNECTED 105
+#define IDR_TASKBAR 107
+#define IDD_TASKBAR_STATUS 108
+#define IDC_TASKBAR_STATUS_STATUS 1000
+#define IDC_TASKBAR_QUIT 40001
+#define IDC_TASKBAR_STATUS 40002
+#define IDC_TASKBAR_LOG 40003
+#define IDC_TASKBAR_SHOW_LOG 40004
+#define IDC_TASKBAR_LOG_LEVEL_ERROR 40009
+#define IDC_TASKBAR_LOG_LEVEL_WARNING 40010
+#define IDC_TASKBAR_LOG_LEVEL_NOTE 40011
+#define IDC_TASKBAR_LOG_LEVEL_INFO 40012
+#define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013
+#define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014
+#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 109
+#define _APS_NEXT_COMMAND_VALUE 40016
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/cmd/synergyc/synergyc.cpp b/cmd/synergyc/synergyc.cpp
new file mode 100644
index 00000000..1a230f0d
--- /dev/null
+++ b/cmd/synergyc/synergyc.cpp
@@ -0,0 +1,910 @@
+/*
+ * 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 "CClient.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
+
+#define DAEMON_RUNNING(running_)
+#if WINAPI_MSWINDOWS
+#include "CArchMiscWindows.h"
+#include "CMSWindowsScreen.h"
+#include "CMSWindowsUtil.h"
+#include "CMSWindowsClientTaskBarReceiver.h"
+#include "resource.h"
+#undef DAEMON_RUNNING
+#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
+#elif WINAPI_XWINDOWS
+#include "CXWindowsScreen.h"
+#include "CXWindowsClientTaskBarReceiver.h"
+#elif WINAPI_CARBON
+#include "COSXScreen.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_logFilter(NULL),
+ m_display(NULL),
+ m_serverAddress(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;
+ const char* m_logFilter;
+ const char* m_display;
+ CString m_name;
+ CNetworkAddress* m_serverAddress;
+};
+
+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));
+#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;
+
+static
+void
+updateStatus()
+{
+ s_taskBarReceiver->updateStatus(s_client, "");
+}
+
+static
+void
+updateStatus(const CString& msg)
+{
+ s_taskBarReceiver->updateStatus(s_client, msg);
+}
+
+static
+void
+resetRestartTimeout()
+{
+ s_retryTime = 0.0;
+}
+
+static
+double
+nextRestartTimeout()
+{
+ // 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 if (s_retryTime < 5.0) {
+ s_retryTime = 5.0;
+ }
+ else if (s_retryTime < 15.0) {
+ s_retryTime = 15.0;
+ }
+ else if (s_retryTime < 30.0) {
+ s_retryTime = 30.0;
+ }
+ else {
+ s_retryTime = 60.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(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(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()
+{
+ // 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"));
+
+ return kExitSuccess;
+}
+
+static
+int
+daemonMainLoop(int, const char**)
+{
+#if SYSAPI_WIN32
+ CSystemLogger sysLogger(DAEMON_NAME, false);
+#else
+ CSystemLogger sysLogger(DAEMON_NAME, true);
+#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 ]"
+# define USAGE_DISPLAY_INFO \
+" --display connect to the X server at \n"
+#else
+# define USAGE_DISPLAY_ARG
+# define USAGE_DISPLAY_INFO
+#endif
+
+ LOG((CLOG_PRINT
+"Usage: %s"
+" [--daemon|--no-daemon]"
+" [--debug ]"
+USAGE_DISPLAY_ARG
+" [--name ]"
+" [--restart|--no-restart]"
+" "
+"\n\n"
+"Start the synergy mouse/keyboard sharing server.\n"
+"\n"
+" -d, --debug 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 use screen-name instead the hostname to identify\n"
+" ourself to the server.\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"
+" -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: [][:]. 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);
+
+ // 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, "-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 "Synergy client %s on %s", kVersion, ARCH->getOSName().c_str()));
+}
+
+
+//
+// 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, "");
+ //throw;
+ }
+ return kExitFailed;
+}
+
+#elif SYSAPI_UNIX
+
+int
+main(int argc, char** argv)
+{
+ CArgs args;
+ try {
+ 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: \n"));
+ throw;
+ }
+}
+
+#else
+
+#error no main() for platform
+
+#endif
diff --git a/cmd/synergyc/synergyc.ico b/cmd/synergyc/synergyc.ico
new file mode 100644
index 0000000000000000000000000000000000000000..89f965f4432c5f58054b9a1b0eae5bf6cbfd245d
GIT binary patch
literal 8478
zcmeI1KWH3B6vm(a*e8S|%Z-~Dq__}vXV}UrV&mT6#z|>aLkbt^+yrSM;8FwvhV6t%
zLQiZmzTr%%8baza{{iY$oC5(ZeHZtwQ9U1vh;!S!}zl^B0qm9a)se4
z$4!nI!GV?&yT9dtAbB1-&RoiHIHXs=+duJMuQ>Qqlb(9p`ug^E1I+I3?(XmJkD_Ir
zwoR+XpoZ`7n_*F5!?$xa7_9y@9UB~QjWDbDj>v-IqX1iNmO=`Jq0y9JcvU(jnEQ^w
z7Gb2>!%ze~pRL_3zyv-RkH?YkoZDF1+}w=gwY9a?KK%1QIIFneKdQ#~i{M`c0A3Tt
z1K}(%xF*;nf_mc~2;;GW3Worjn~JKt$bbM9zM*5w5O5oY2+>S!bo#xVIM#9I(&{w)eJBUN
zeJAtt^Rlq8Am`4VlM5Fv$i<5n<({SK{)Lx2
zcf5QpPsRUH%CArVl&9mdeD%YRB+58+ffXEO7-rZqY#FvpZQOaKIPAI@9d?J^VOO^T
zdx5=RP+%{x(@BZF#9m@AF_hRnW6#)^mO0~`5j-PMhEvA(o2BQJp&>&8GBjjp$k32^Z0N|)k*N+oJ*YAjjs+pbjlo20;DbJG3~oSXt2F(BaVG(BaTwr9y{8gF}NugO<*r!=b^Up|o%I
zGL(=!;g7MESF3|6au@Kd)Z{MERFJeFL4l@%+y!7k?t?N}3)s-$(csbG(csbG(O}C74J8^p8ax_G
zG!TXZJ{mk4JQ_S22+e^V4IT|14ITlW{3XFWjvkUDhGXo|;VrguoO~qT%DsE{eVYbJUo4A)*c53emtZek(@;r+A&?7`%alYMX$a
zY+S?5oN9)eBHqA@i;?Pjweae)tI(w2f&-E#+${e5S>63iAM`TagzjPcMcFJ$Y(hZaAL
zK9Rw|H_|&9)FI_tfX*qMLxQ;r%W>h`ir$IeFQ=8D75`u1H(R)5quI_B_inZY
z`w#h31SN9V5+-_1#7`aC(~P4ezM76pkkD<1n(})TrS!0)eWSx9y(K8_{d=_ISy@{N
zT9R7PBfXOV?+~X=Zo;=qR3)1r*J?T?JqdqOQS0|g$Q4UqeS6A`CiJxElT+yOJM;;M
z4u68)b!hW@=$O(;r2KxiS{sjsKb@U=ME;xEhFTKipMZQE#eS#RJDbrUyt}d2IpX6>
za(ySP_)ug{dwv(qXfHHQN7`?RK8(?u08Lb>z>#22Rc4!-|>%e>pWH7s3Yo%I-~CHeBwOgyeWaz
zp{~oYs#C06tRuuw-%(X(t$cW&zD$T!j`%zECiCoXIRyaW$EkIkxjg-ydip!{^nLpK
z@IIZrF`MQ1m2Nxb=7&PqIET$NlxiPcZLX`ax&{w}LnJfkI1B@$JJyFz#P!+JH%|8{
t;Zdj_)sxDeTJ=5vdoUQ9?87Q{NCkzlT_5sH8R_#vpACFJzU}{8{tX4i2$ui=
literal 0
HcmV?d00001
diff --git a/cmd/synergyc/synergyc.rc b/cmd/synergyc/synergyc.rc
new file mode 100644
index 00000000..7f2a5dc1
--- /dev/null
+++ b/cmd/synergyc/synergyc.rc
@@ -0,0 +1,141 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#if !defined(IDC_STATIC)
+#define IDC_STATIC (-1)
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SYNERGY ICON DISCARDABLE "synergyc.ico"
+IDI_TASKBAR_NOT_RUNNING ICON DISCARDABLE "tb_idle.ico"
+IDI_TASKBAR_NOT_WORKING ICON DISCARDABLE "tb_error.ico"
+IDI_TASKBAR_NOT_CONNECTED ICON DISCARDABLE "tb_wait.ico"
+IDI_TASKBAR_CONNECTED ICON DISCARDABLE "tb_run.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_TASKBAR_STATUS DIALOG DISCARDABLE 0, 0, 145, 18
+STYLE DS_MODALFRAME | WS_POPUP
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TASKBAR MENU DISCARDABLE
+BEGIN
+ POPUP "Synergy"
+ BEGIN
+ MENUITEM "Show Status", IDC_TASKBAR_STATUS
+ MENUITEM "Show Log", IDC_TASKBAR_SHOW_LOG
+ MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG
+ POPUP "Set Log Level"
+ BEGIN
+ MENUITEM "Error", IDC_TASKBAR_LOG_LEVEL_ERROR
+
+ MENUITEM "Warning", IDC_TASKBAR_LOG_LEVEL_WARNING
+
+ MENUITEM "Note", IDC_TASKBAR_LOG_LEVEL_NOTE
+
+ MENUITEM "Info", IDC_TASKBAR_LOG_LEVEL_INFO
+
+ MENUITEM "Debug", IDC_TASKBAR_LOG_LEVEL_DEBUG
+
+ MENUITEM "Debug1", IDC_TASKBAR_LOG_LEVEL_DEBUG1
+
+ MENUITEM "Debug2", IDC_TASKBAR_LOG_LEVEL_DEBUG2
+
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Quit", IDC_TASKBAR_QUIT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
+ IDS_INIT_FAILED "Synergy failed to initialize: %{1}"
+ IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/cmd/synergyc/tb_error.ico b/cmd/synergyc/tb_error.ico
new file mode 100644
index 0000000000000000000000000000000000000000..746a87c9ec8ae70f24b4125afe9ca68defb2f6d1
GIT binary patch
literal 318
zcmZusyA6Xd5PgscB3VLIX+veDOwBY@u9?8{1k4aIf%|Jb3Y{4t9eD?$OZQF)q4|7v^Hl|=e!@IsjRK@B2u}b(FJQe=z?=V5liH
zWoPHjzBjX*nT1SN6a`+-89X}5txV(@w?b&ncnuP0lhP#!b);z;MJKxRrt5r?%Pbk_
z?N%_Tg0`uZoK7he#O%9wJeiXYR@<+l75<*=!?qP*0HwJ2|O6{7v9^DvFs
zu!_Y~)D!l8cMcLvA>Yqua2!LMtJfQ~uh~C-l}Rwt@WUxQyu;vMf6!iXu5qpJ`0fd8
C{!x(t
literal 0
HcmV?d00001
diff --git a/cmd/synergyc/tb_run.ico b/cmd/synergyc/tb_run.ico
new file mode 100644
index 0000000000000000000000000000000000000000..88e160cbfcd029978599f49605ba1a3c7695027e
GIT binary patch
literal 318
zcmZvXJ#K_B5QRT>QHT}^QKbzPO1ZU9vz2R3fRNJr5IzCD8;(L}A7MN84cny1jNhAi
z^COL+lJ|X&*-r&u76q#eLPafx?d1Px0X>%G9mGo6woTC*$N4x8%LKWVjJU*LBRA(t
z*&)UlLNF;^_DhTq!s6VW^|KVov_j`difNtFX&-H(O$k3SDILcq=N9iD-8@T;1372!
my*B6BBsAGS;Q0-Eqg$^!Uw{7
literal 0
HcmV?d00001
diff --git a/cmd/synergyc/tb_wait.ico b/cmd/synergyc/tb_wait.ico
new file mode 100644
index 0000000000000000000000000000000000000000..257be0a1d1bc613eec8cc1838a1dfd25d4644844
GIT binary patch
literal 318
zcmZvXF%H5o3`Ji7QN#e9SYe77nRA*>nK?mJi9LtNNy<&SB_ktS@h=k+vHidOZA%U`
zW?k2zcWvM#wvckMXxJFSxZpn+z?@1UcuF
zl1i)Vw8|M$8oa;3u2z*2ycgFRqu9Ap#396Zhplt1gb?~ejL|uFp_CFr025R~TS5=-
dGfb`By0-J}?~kW-COE!+Lz;S;(X4i~`vJXUO(y^V
literal 0
HcmV?d00001
diff --git a/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp b/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
new file mode 100644
index 00000000..e332ccea
--- /dev/null
+++ b/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
@@ -0,0 +1,374 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CMSWindowsServerTaskBarReceiver.h"
+#include "CServer.h"
+#include "CMSWindowsClipboard.h"
+#include "IEventQueue.h"
+#include "LogOutputters.h"
+#include "BasicTypes.h"
+#include "CArch.h"
+#include "CArchTaskBarWindows.h"
+#include "resource.h"
+
+extern CEvent::Type getReloadConfigEvent();
+extern CEvent::Type getForceReconnectEvent();
+
+//
+// CMSWindowsServerTaskBarReceiver
+//
+
+const UINT CMSWindowsServerTaskBarReceiver::s_stateToIconID[kMaxState] =
+{
+ IDI_TASKBAR_NOT_RUNNING,
+ IDI_TASKBAR_NOT_WORKING,
+ IDI_TASKBAR_NOT_CONNECTED,
+ IDI_TASKBAR_CONNECTED
+};
+
+CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
+ HINSTANCE appInstance, const CBufferedLogOutputter* logBuffer) :
+ CServerTaskBarReceiver(),
+ m_appInstance(appInstance),
+ m_window(NULL),
+ m_logBuffer(logBuffer)
+{
+ for (UInt32 i = 0; i < kMaxState; ++i) {
+ m_icon[i] = loadIcon(s_stateToIconID[i]);
+ }
+ m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
+
+ // don't create the window yet. we'll create it on demand. this
+ // has the side benefit of being created in the thread used for
+ // the task bar. that's good because it means the existence of
+ // the window won't prevent changing the main thread's desktop.
+
+ // add ourself to the task bar
+ ARCH->addReceiver(this);
+}
+
+CMSWindowsServerTaskBarReceiver::~CMSWindowsServerTaskBarReceiver()
+{
+ ARCH->removeReceiver(this);
+ for (UInt32 i = 0; i < kMaxState; ++i) {
+ deleteIcon(m_icon[i]);
+ }
+ DestroyMenu(m_menu);
+ destroyWindow();
+}
+
+void
+CMSWindowsServerTaskBarReceiver::showStatus()
+{
+ // create the window
+ createWindow();
+
+ // lock self while getting status
+ lock();
+
+ // get the current status
+ std::string status = getToolTip();
+
+ // get the connect clients, if any
+ const CClients& clients = getClients();
+
+ // done getting status
+ unlock();
+
+ // update dialog
+ HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
+ SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
+ child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS);
+ SendMessage(child, LB_RESETCONTENT, 0, 0);
+ for (CClients::const_iterator index = clients.begin();
+ index != clients.end(); ) {
+ const char* client = index->c_str();
+ if (++index == clients.end()) {
+ SendMessage(child, LB_ADDSTRING, 0, (LPARAM)client);
+ }
+ else {
+ SendMessage(child, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)client);
+ }
+ }
+
+ if (!IsWindowVisible(m_window)) {
+ // position it by the mouse
+ POINT cursorPos;
+ GetCursorPos(&cursorPos);
+ RECT windowRect;
+ GetWindowRect(m_window, &windowRect);
+ int x = cursorPos.x;
+ int y = cursorPos.y;
+ int fw = GetSystemMetrics(SM_CXDLGFRAME);
+ int fh = GetSystemMetrics(SM_CYDLGFRAME);
+ int ww = windowRect.right - windowRect.left;
+ int wh = windowRect.bottom - windowRect.top;
+ int sw = GetSystemMetrics(SM_CXFULLSCREEN);
+ int sh = GetSystemMetrics(SM_CYFULLSCREEN);
+ if (fw < 1) {
+ fw = 1;
+ }
+ if (fh < 1) {
+ fh = 1;
+ }
+ if (x + ww - fw > sw) {
+ x -= ww - fw;
+ }
+ else {
+ x -= fw;
+ }
+ if (x < 0) {
+ x = 0;
+ }
+ if (y + wh - fh > sh) {
+ y -= wh - fh;
+ }
+ else {
+ y -= fh;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+ SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
+ SWP_SHOWWINDOW);
+ }
+}
+
+void
+CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
+{
+ // do popup menu. we need a window to pass to TrackPopupMenu().
+ // the SetForegroundWindow() and SendMessage() calls around
+ // TrackPopupMenu() are to get the menu to be dismissed when
+ // another window gets activated and are just one of those
+ // win32 weirdnesses.
+ createWindow();
+ SetForegroundWindow(m_window);
+ HMENU menu = GetSubMenu(m_menu, 0);
+ SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
+ HMENU logLevelMenu = GetSubMenu(menu, 3);
+ CheckMenuRadioItem(logLevelMenu, 0, 6,
+ CLOG->getFilter() - CLog::kERROR, MF_BYPOSITION);
+ int n = TrackPopupMenu(menu,
+ TPM_NONOTIFY |
+ TPM_RETURNCMD |
+ TPM_LEFTBUTTON |
+ TPM_RIGHTBUTTON,
+ x, y, 0, m_window, NULL);
+ SendMessage(m_window, WM_NULL, 0, 0);
+
+ // perform the requested operation
+ switch (n) {
+ case IDC_TASKBAR_STATUS:
+ showStatus();
+ break;
+
+ case IDC_TASKBAR_LOG:
+ copyLog();
+ break;
+
+ case IDC_TASKBAR_SHOW_LOG:
+ ARCH->showConsole(true);
+ break;
+
+ case IDC_RELOAD_CONFIG:
+ EVENTQUEUE->addEvent(CEvent(getReloadConfigEvent(),
+ IEventQueue::getSystemTarget()));
+ break;
+
+ case IDC_FORCE_RECONNECT:
+ EVENTQUEUE->addEvent(CEvent(getForceReconnectEvent(),
+ IEventQueue::getSystemTarget()));
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_ERROR:
+ CLOG->setFilter(CLog::kERROR);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_WARNING:
+ CLOG->setFilter(CLog::kWARNING);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_NOTE:
+ CLOG->setFilter(CLog::kNOTE);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_INFO:
+ CLOG->setFilter(CLog::kINFO);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_DEBUG:
+ CLOG->setFilter(CLog::kDEBUG);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_DEBUG1:
+ CLOG->setFilter(CLog::kDEBUG1);
+ break;
+
+ case IDC_TASKBAR_LOG_LEVEL_DEBUG2:
+ CLOG->setFilter(CLog::kDEBUG2);
+ break;
+
+ case IDC_TASKBAR_QUIT:
+ quit();
+ break;
+ }
+}
+
+void
+CMSWindowsServerTaskBarReceiver::primaryAction()
+{
+ showStatus();
+}
+
+const IArchTaskBarReceiver::Icon
+CMSWindowsServerTaskBarReceiver::getIcon() const
+{
+ return reinterpret_cast(m_icon[getStatus()]);
+}
+
+void
+CMSWindowsServerTaskBarReceiver::copyLog() const
+{
+ if (m_logBuffer != NULL) {
+ // collect log buffer
+ CString data;
+ for (CBufferedLogOutputter::const_iterator index = m_logBuffer->begin();
+ index != m_logBuffer->end(); ++index) {
+ data += *index;
+ data += "\n";
+ }
+
+ // copy log to clipboard
+ if (!data.empty()) {
+ CMSWindowsClipboard clipboard(m_window);
+ clipboard.open(0);
+ clipboard.emptyUnowned();
+ clipboard.add(IClipboard::kText, data);
+ clipboard.close();
+ }
+ }
+}
+
+void
+CMSWindowsServerTaskBarReceiver::onStatusChanged()
+{
+ if (IsWindowVisible(m_window)) {
+ showStatus();
+ }
+}
+
+HICON
+CMSWindowsServerTaskBarReceiver::loadIcon(UINT id)
+{
+ HANDLE icon = LoadImage(m_appInstance,
+ MAKEINTRESOURCE(id),
+ IMAGE_ICON,
+ 0, 0,
+ LR_DEFAULTCOLOR);
+ return reinterpret_cast(icon);
+}
+
+void
+CMSWindowsServerTaskBarReceiver::deleteIcon(HICON icon)
+{
+ if (icon != NULL) {
+ DestroyIcon(icon);
+ }
+}
+
+void
+CMSWindowsServerTaskBarReceiver::createWindow()
+{
+ // ignore if already created
+ if (m_window != NULL) {
+ return;
+ }
+
+ // get the status dialog
+ m_window = CreateDialogParam(m_appInstance,
+ MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
+ NULL,
+ (DLGPROC)&CMSWindowsServerTaskBarReceiver::staticDlgProc,
+ reinterpret_cast(
+ reinterpret_cast(this)));
+
+ // window should appear on top of everything, including (especially)
+ // the task bar.
+ LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE);
+ style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+ SetWindowLongPtr(m_window, GWL_EXSTYLE, style);
+
+ // tell the task bar about this dialog
+ CArchTaskBarWindows::addDialog(m_window);
+}
+
+void
+CMSWindowsServerTaskBarReceiver::destroyWindow()
+{
+ if (m_window != NULL) {
+ CArchTaskBarWindows::removeDialog(m_window);
+ DestroyWindow(m_window);
+ m_window = NULL;
+ }
+}
+
+BOOL
+CMSWindowsServerTaskBarReceiver::dlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ // use default focus
+ return TRUE;
+
+ case WM_ACTIVATE:
+ // hide when another window is activated
+ if (LOWORD(wParam) == WA_INACTIVE) {
+ ShowWindow(hwnd, SW_HIDE);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK
+CMSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ // if msg is WM_INITDIALOG, extract the CMSWindowsServerTaskBarReceiver*
+ // and put it in the extra window data then forward the call.
+ CMSWindowsServerTaskBarReceiver* self = NULL;
+ if (msg == WM_INITDIALOG) {
+ self = reinterpret_cast(
+ reinterpret_cast(lParam));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ }
+ else {
+ // get the extra window data and forward the call
+ LONG data = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if (data != 0) {
+ self = reinterpret_cast(
+ reinterpret_cast(data));
+ }
+ }
+
+ // forward the message
+ if (self != NULL) {
+ return self->dlgProc(hwnd, msg, wParam, lParam);
+ }
+ else {
+ return (msg == WM_INITDIALOG) ? TRUE : FALSE;
+ }
+}
diff --git a/cmd/synergys/CMSWindowsServerTaskBarReceiver.h b/cmd/synergys/CMSWindowsServerTaskBarReceiver.h
new file mode 100644
index 00000000..ab679077
--- /dev/null
+++ b/cmd/synergys/CMSWindowsServerTaskBarReceiver.h
@@ -0,0 +1,64 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CMSWINDOWSSERVERTASKBARRECEIVER_H
+#define CMSWINDOWSSERVERTASKBARRECEIVER_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "CServerTaskBarReceiver.h"
+#include
+
+class CBufferedLogOutputter;
+
+//! Implementation of CServerTaskBarReceiver for Microsoft Windows
+class CMSWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
+public:
+ CMSWindowsServerTaskBarReceiver(HINSTANCE, const CBufferedLogOutputter*);
+ virtual ~CMSWindowsServerTaskBarReceiver();
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus();
+ virtual void runMenu(int x, int y);
+ virtual void primaryAction();
+ virtual const Icon getIcon() const;
+
+protected:
+ void copyLog() const;
+
+ // CServerTaskBarReceiver overrides
+ virtual void onStatusChanged();
+
+private:
+ HICON loadIcon(UINT);
+ void deleteIcon(HICON);
+ void createWindow();
+ void destroyWindow();
+
+ BOOL dlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam);
+ static BOOL CALLBACK
+ staticDlgProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ HINSTANCE m_appInstance;
+ HWND m_window;
+ HMENU m_menu;
+ HICON m_icon[kMaxState];
+ const CBufferedLogOutputter* m_logBuffer;
+ static const UINT s_stateToIconID[];
+};
+
+#endif
diff --git a/cmd/synergys/COSXServerTaskBarReceiver.cpp b/cmd/synergys/COSXServerTaskBarReceiver.cpp
new file mode 100644
index 00000000..8195b84f
--- /dev/null
+++ b/cmd/synergys/COSXServerTaskBarReceiver.cpp
@@ -0,0 +1,56 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "COSXServerTaskBarReceiver.h"
+#include "CArch.h"
+
+//
+// COSXServerTaskBarReceiver
+//
+
+COSXServerTaskBarReceiver::COSXServerTaskBarReceiver(
+ const CBufferedLogOutputter*)
+{
+ // add ourself to the task bar
+ ARCH->addReceiver(this);
+}
+
+COSXServerTaskBarReceiver::~COSXServerTaskBarReceiver()
+{
+ ARCH->removeReceiver(this);
+}
+
+void
+COSXServerTaskBarReceiver::showStatus()
+{
+ // do nothing
+}
+
+void
+COSXServerTaskBarReceiver::runMenu(int, int)
+{
+ // do nothing
+}
+
+void
+COSXServerTaskBarReceiver::primaryAction()
+{
+ // do nothing
+}
+
+const IArchTaskBarReceiver::Icon
+COSXServerTaskBarReceiver::getIcon() const
+{
+ return NULL;
+}
diff --git a/cmd/synergys/COSXServerTaskBarReceiver.h b/cmd/synergys/COSXServerTaskBarReceiver.h
new file mode 100644
index 00000000..7f6dc298
--- /dev/null
+++ b/cmd/synergys/COSXServerTaskBarReceiver.h
@@ -0,0 +1,35 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef COSXSERVERTASKBARRECEIVER_H
+#define COSXSERVERTASKBARRECEIVER_H
+
+#include "CServerTaskBarReceiver.h"
+
+class CBufferedLogOutputter;
+
+//! Implementation of CServerTaskBarReceiver for OS X
+class COSXServerTaskBarReceiver : public CServerTaskBarReceiver {
+public:
+ COSXServerTaskBarReceiver(const CBufferedLogOutputter*);
+ virtual ~COSXServerTaskBarReceiver();
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus();
+ virtual void runMenu(int x, int y);
+ virtual void primaryAction();
+ virtual const Icon getIcon() const;
+};
+
+#endif
diff --git a/cmd/synergys/CServerTaskBarReceiver.cpp b/cmd/synergys/CServerTaskBarReceiver.cpp
new file mode 100644
index 00000000..6555b214
--- /dev/null
+++ b/cmd/synergys/CServerTaskBarReceiver.cpp
@@ -0,0 +1,133 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CServerTaskBarReceiver.h"
+#include "CServer.h"
+#include "CLock.h"
+#include "CStringUtil.h"
+#include "IEventQueue.h"
+#include "CArch.h"
+#include "Version.h"
+
+//
+// CServerTaskBarReceiver
+//
+
+CServerTaskBarReceiver::CServerTaskBarReceiver() :
+ m_state(kNotRunning)
+{
+ // do nothing
+}
+
+CServerTaskBarReceiver::~CServerTaskBarReceiver()
+{
+ // do nothing
+}
+
+void
+CServerTaskBarReceiver::updateStatus(CServer* server, const CString& errorMsg)
+{
+ {
+ // update our status
+ m_errorMessage = errorMsg;
+ if (server == NULL) {
+ if (m_errorMessage.empty()) {
+ m_state = kNotRunning;
+ }
+ else {
+ m_state = kNotWorking;
+ }
+ }
+ else {
+ m_clients.clear();
+ server->getClients(m_clients);
+ if (m_clients.size() <= 1) {
+ m_state = kNotConnected;
+ }
+ else {
+ m_state = kConnected;
+ }
+ }
+
+ // let subclasses have a go
+ onStatusChanged(server);
+ }
+
+ // tell task bar
+ ARCH->updateReceiver(this);
+}
+
+CServerTaskBarReceiver::EState
+CServerTaskBarReceiver::getStatus() const
+{
+ return m_state;
+}
+
+const CString&
+CServerTaskBarReceiver::getErrorMessage() const
+{
+ return m_errorMessage;
+}
+
+const CServerTaskBarReceiver::CClients&
+CServerTaskBarReceiver::getClients() const
+{
+ return m_clients;
+}
+
+void
+CServerTaskBarReceiver::quit()
+{
+ EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
+}
+
+void
+CServerTaskBarReceiver::onStatusChanged(CServer*)
+{
+ // do nothing
+}
+
+void
+CServerTaskBarReceiver::lock() const
+{
+ // do nothing
+}
+
+void
+CServerTaskBarReceiver::unlock() const
+{
+ // do nothing
+}
+
+std::string
+CServerTaskBarReceiver::getToolTip() const
+{
+ switch (m_state) {
+ case kNotRunning:
+ return CStringUtil::print("%s: Not running", kAppVersion);
+
+ case kNotWorking:
+ return CStringUtil::print("%s: %s",
+ kAppVersion, m_errorMessage.c_str());
+
+ case kNotConnected:
+ return CStringUtil::print("%s: Waiting for clients", kAppVersion);
+
+ case kConnected:
+ return CStringUtil::print("%s: Connected", kAppVersion);
+
+ default:
+ return "";
+ }
+}
diff --git a/cmd/synergys/CServerTaskBarReceiver.h b/cmd/synergys/CServerTaskBarReceiver.h
new file mode 100644
index 00000000..d6ec8571
--- /dev/null
+++ b/cmd/synergys/CServerTaskBarReceiver.h
@@ -0,0 +1,88 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CSERVERTASKBARRECEIVER_H
+#define CSERVERTASKBARRECEIVER_H
+
+#include "CString.h"
+#include "IArchTaskBarReceiver.h"
+#include "stdvector.h"
+
+class CServer;
+
+//! Implementation of IArchTaskBarReceiver for the synergy server
+class CServerTaskBarReceiver : public IArchTaskBarReceiver {
+public:
+ CServerTaskBarReceiver();
+ virtual ~CServerTaskBarReceiver();
+
+ //! @name manipulators
+ //@{
+
+ //! Update status
+ /*!
+ Determine the status and query required information from the server.
+ */
+ void updateStatus(CServer*, const CString& errorMsg);
+
+ //@}
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus() = 0;
+ virtual void runMenu(int x, int y) = 0;
+ virtual void primaryAction() = 0;
+ virtual void lock() const;
+ virtual void unlock() const;
+ virtual const Icon getIcon() const = 0;
+ virtual std::string getToolTip() const;
+
+protected:
+ typedef std::vector CClients;
+ enum EState {
+ kNotRunning,
+ kNotWorking,
+ kNotConnected,
+ kConnected,
+ kMaxState
+ };
+
+ //! Get status
+ EState getStatus() const;
+
+ //! Get error message
+ const CString& getErrorMessage() const;
+
+ //! Get connected clients
+ const CClients& getClients() const;
+
+ //! Quit app
+ /*!
+ Causes the application to quit gracefully
+ */
+ void quit();
+
+ //! Status change notification
+ /*!
+ Called when status changes. The default implementation does
+ nothing.
+ */
+ virtual void onStatusChanged(CServer* server);
+
+private:
+ EState m_state;
+ CString m_errorMessage;
+ CClients m_clients;
+};
+
+#endif
diff --git a/cmd/synergys/CXWindowsServerTaskBarReceiver.cpp b/cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
new file mode 100644
index 00000000..861d2f8c
--- /dev/null
+++ b/cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
@@ -0,0 +1,56 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CXWindowsServerTaskBarReceiver.h"
+#include "CArch.h"
+
+//
+// CXWindowsServerTaskBarReceiver
+//
+
+CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver(
+ const CBufferedLogOutputter*)
+{
+ // add ourself to the task bar
+ ARCH->addReceiver(this);
+}
+
+CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver()
+{
+ ARCH->removeReceiver(this);
+}
+
+void
+CXWindowsServerTaskBarReceiver::showStatus()
+{
+ // do nothing
+}
+
+void
+CXWindowsServerTaskBarReceiver::runMenu(int, int)
+{
+ // do nothing
+}
+
+void
+CXWindowsServerTaskBarReceiver::primaryAction()
+{
+ // do nothing
+}
+
+const IArchTaskBarReceiver::Icon
+CXWindowsServerTaskBarReceiver::getIcon() const
+{
+ return NULL;
+}
diff --git a/cmd/synergys/CXWindowsServerTaskBarReceiver.h b/cmd/synergys/CXWindowsServerTaskBarReceiver.h
new file mode 100644
index 00000000..73234123
--- /dev/null
+++ b/cmd/synergys/CXWindowsServerTaskBarReceiver.h
@@ -0,0 +1,35 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CXWINDOWSSERVERTASKBARRECEIVER_H
+#define CXWINDOWSSERVERTASKBARRECEIVER_H
+
+#include "CServerTaskBarReceiver.h"
+
+class CBufferedLogOutputter;
+
+//! Implementation of CServerTaskBarReceiver for X Windows
+class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
+public:
+ CXWindowsServerTaskBarReceiver(const CBufferedLogOutputter*);
+ virtual ~CXWindowsServerTaskBarReceiver();
+
+ // IArchTaskBarReceiver overrides
+ virtual void showStatus();
+ virtual void runMenu(int x, int y);
+ virtual void primaryAction();
+ virtual const Icon getIcon() const;
+};
+
+#endif
diff --git a/cmd/synergys/Makefile.am b/cmd/synergys/Makefile.am
new file mode 100644
index 00000000..4ad48ce5
--- /dev/null
+++ b/cmd/synergys/Makefile.am
@@ -0,0 +1,98 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+COMMON_SOURCE_FILES = \
+ CServerTaskBarReceiver.cpp \
+ CServerTaskBarReceiver.h \
+ synergys.cpp \
+ $(NULL)
+XWINDOWS_SOURCE_FILES = \
+ CXWindowsServerTaskBarReceiver.cpp \
+ CXWindowsServerTaskBarReceiver.h \
+ $(NULL)
+MSWINDOWS_SOURCE_FILES = \
+ CMSWindowsServerTaskBarReceiver.cpp \
+ CMSWindowsServerTaskBarReceiver.h \
+ resource.h \
+ synergys.rc \
+ $(NULL)
+CARBON_SOURCE_FILES = \
+ COSXServerTaskBarReceiver.cpp \
+ COSXServerTaskBarReceiver.h \
+ $(NULL)
+
+EXTRA_DIST = \
+ Makefile.win \
+ synergys.ico \
+ tb_error.ico \
+ tb_idle.ico \
+ tb_run.ico \
+ tb_wait.ico \
+ $(XWINDOWS_SOURCE_FILES) \
+ $(MSWINDOWS_SOURCE_FILES) \
+ $(CARBON_SOURCE_FILES) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
+
+bin_PROGRAMS = synergys
+if XWINDOWS
+synergys_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(XWINDOWS_SOURCE_FILES) \
+ $(NULL)
+endif
+if MSWINDOWS
+synergys_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(MSWINDOWS_SOURCE_FILES) \
+ $(NULL)
+endif
+if CARBON
+synergys_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(CARBON_SOURCE_FILES) \
+ $(NULL)
+synergys_LDFLAGS = \
+ -framework ScreenSaver \
+ -framework IOKit \
+ -framework ApplicationServices \
+ -framework Foundation \
+ $(NULL)
+endif
+synergys_LDADD = \
+ $(top_builddir)/lib/server/libserver.a \
+ $(top_builddir)/lib/platform/libplatform.a \
+ $(top_builddir)/lib/synergy/libsynergy.a \
+ $(top_builddir)/lib/net/libnet.a \
+ $(top_builddir)/lib/io/libio.a \
+ $(top_builddir)/lib/mt/libmt.a \
+ $(top_builddir)/lib/base/libbase.a \
+ $(top_builddir)/lib/common/libcommon.a \
+ $(top_builddir)/lib/arch/libarch.a \
+ $(NULL)
+INCLUDES = \
+ -I$(top_srcdir)/lib/common \
+ -I$(top_srcdir)/lib/arch \
+ -I$(top_srcdir)/lib/base \
+ -I$(top_srcdir)/lib/mt \
+ -I$(top_srcdir)/lib/io \
+ -I$(top_srcdir)/lib/net \
+ -I$(top_srcdir)/lib/synergy \
+ -I$(top_srcdir)/lib/platform \
+ -I$(top_srcdir)/lib/server \
+ $(NULL)
diff --git a/cmd/synergys/Makefile.win b/cmd/synergys/Makefile.win
new file mode 100644
index 00000000..09d39958
--- /dev/null
+++ b/cmd/synergys/Makefile.win
@@ -0,0 +1,89 @@
+# synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2007 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.
+
+BIN_SYNERGYS_SRC = cmd\synergys
+BIN_SYNERGYS_DST = $(BUILD_DST)\$(BIN_SYNERGYS_SRC)
+BIN_SYNERGYS_EXE = "$(BUILD_DST)\synergys.exe"
+BIN_SYNERGYS_CPP = \
+ "CServerTaskBarReceiver.cpp" \
+ "CMSWindowsServerTaskBarReceiver.cpp" \
+ "synergys.cpp" \
+ $(NULL)
+BIN_SYNERGYS_OBJ = \
+ "$(BIN_SYNERGYS_DST)\CServerTaskBarReceiver.obj" \
+ "$(BIN_SYNERGYS_DST)\CMSWindowsServerTaskBarReceiver.obj" \
+ "$(BIN_SYNERGYS_DST)\synergys.obj" \
+ $(NULL)
+BIN_SYNERGYS_RC = "$(BIN_SYNERGYS_SRC)\synergys.rc"
+BIN_SYNERGYS_RES = "$(BIN_SYNERGYS_DST)\synergys.res"
+BIN_SYNERGYS_INC = \
+ /I"lib\common" \
+ /I"lib\arch" \
+ /I"lib\base" \
+ /I"lib\mt" \
+ /I"lib\io" \
+ /I"lib\net" \
+ /I"lib\synergy" \
+ /I"lib\platform" \
+ /I"lib\server" \
+ $(NULL)
+BIN_SYNERGYS_LIB = \
+ $(LIB_SERVER_LIB) \
+ $(LIB_PLATFORM_LIB) \
+ $(LIB_SYNERGY_LIB) \
+ $(LIB_NET_LIB) \
+ $(LIB_IO_LIB) \
+ $(LIB_MT_LIB) \
+ $(LIB_BASE_LIB) \
+ $(LIB_ARCH_LIB) \
+ $(LIB_COMMON_LIB) \
+ $(NULL)
+
+CPP_FILES = $(CPP_FILES) $(BIN_SYNERGYS_CPP)
+OBJ_FILES = $(OBJ_FILES) $(BIN_SYNERGYS_OBJ)
+PROGRAMS = $(PROGRAMS) $(BIN_SYNERGYS_EXE)
+
+# Need shell functions.
+guilibs = $(guilibs) shell32.lib
+
+# Dependency rules
+$(BIN_SYNERGYS_OBJ): $(AUTODEP)
+!if EXIST($(BIN_SYNERGYS_DST)\deps.mak)
+!include $(BIN_SYNERGYS_DST)\deps.mak
+!endif
+
+# Build rules. Use batch-mode rules if possible.
+!if DEFINED(_NMAKE_VER)
+{$(BIN_SYNERGYS_SRC)\}.cpp{$(BIN_SYNERGYS_DST)\}.obj::
+!else
+{$(BIN_SYNERGYS_SRC)\}.cpp{$(BIN_SYNERGYS_DST)\}.obj:
+!endif
+ @$(ECHO) Compile in $(BIN_SYNERGYS_SRC)
+ -@$(MKDIR) $(BIN_SYNERGYS_DST) 2>NUL:
+ $(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
+ $(BIN_SYNERGYS_INC) \
+ /Fo$(BIN_SYNERGYS_DST)\ \
+ /Fd$(BIN_SYNERGYS_DST)\src.pdb \
+ $< | $(AUTODEP) $(BIN_SYNERGYS_SRC) $(BIN_SYNERGYS_DST)
+$(BIN_SYNERGYS_RES): $(BIN_SYNERGYS_RC)
+ @$(ECHO) Compile $(**F)
+ -@$(MKDIR) $(BIN_SYNERGYS_DST) 2>NUL:
+ $(rc) $(rcflags) $(rcvars) \
+ /fo$@ \
+ $**
+$(BIN_SYNERGYS_EXE): $(BIN_SYNERGYS_OBJ) $(BIN_SYNERGYS_RES) $(BIN_SYNERGYS_LIB)
+ @$(ECHO) Link $(@F)
+ $(link) $(ldebug) $(guilflags) $(guilibsmt) \
+ /out:$@ \
+ $**
+ $(AUTODEP) $(BIN_SYNERGYS_SRC) $(BIN_SYNERGYS_DST) \
+ $(BIN_SYNERGYS_OBJ:.obj=.d)
diff --git a/cmd/synergys/resource.h b/cmd/synergys/resource.h
new file mode 100644
index 00000000..0ad5868a
--- /dev/null
+++ b/cmd/synergys/resource.h
@@ -0,0 +1,40 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by synergys.rc
+//
+#define IDS_FAILED 1
+#define IDS_INIT_FAILED 2
+#define IDS_UNCAUGHT_EXCEPTION 3
+#define IDI_SYNERGY 101
+#define IDI_TASKBAR_NOT_RUNNING 102
+#define IDI_TASKBAR_NOT_WORKING 103
+#define IDI_TASKBAR_NOT_CONNECTED 104
+#define IDI_TASKBAR_CONNECTED 105
+#define IDR_TASKBAR 107
+#define IDD_TASKBAR_STATUS 108
+#define IDC_TASKBAR_STATUS_STATUS 1000
+#define IDC_TASKBAR_STATUS_CLIENTS 1001
+#define IDC_TASKBAR_QUIT 40003
+#define IDC_TASKBAR_STATUS 40004
+#define IDC_TASKBAR_LOG 40005
+#define IDC_RELOAD_CONFIG 40006
+#define IDC_FORCE_RECONNECT 40007
+#define IDC_TASKBAR_SHOW_LOG 40008
+#define IDC_TASKBAR_LOG_LEVEL_ERROR 40009
+#define IDC_TASKBAR_LOG_LEVEL_WARNING 40010
+#define IDC_TASKBAR_LOG_LEVEL_NOTE 40011
+#define IDC_TASKBAR_LOG_LEVEL_INFO 40012
+#define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013
+#define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014
+#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 109
+#define _APS_NEXT_COMMAND_VALUE 40016
+#define _APS_NEXT_CONTROL_VALUE 1003
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/cmd/synergys/synergys.cpp b/cmd/synergys/synergys.cpp
new file mode 100644
index 00000000..4319af1e
--- /dev/null
+++ b/cmd/synergys/synergys.cpp
@@ -0,0 +1,1312 @@
+/*
+ * 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 "CClientListener.h"
+#include "CClientProxy.h"
+#include "CConfig.h"
+#include "CPrimaryClient.h"
+#include "CServer.h"
+#include "CScreen.h"
+#include "ProtocolTypes.h"
+#include "Version.h"
+#include "XScreen.h"
+#include "CSocketMultiplexer.h"
+#include "CTCPSocketFactory.h"
+#include "XSocket.h"
+#include "CThread.h"
+#include "CEventQueue.h"
+#include "CFunctionEventJob.h"
+#include "CLog.h"
+#include "CString.h"
+#include "CStringUtil.h"
+#include "LogOutputters.h"
+#include "CArch.h"
+#include "XArch.h"
+#include "stdfstream.h"
+#include
+
+#define DAEMON_RUNNING(running_)
+#if WINAPI_MSWINDOWS
+#include "CArchMiscWindows.h"
+#include "CMSWindowsScreen.h"
+#include "CMSWindowsUtil.h"
+#include "CMSWindowsServerTaskBarReceiver.h"
+#include "resource.h"
+#undef DAEMON_RUNNING
+#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
+#elif WINAPI_XWINDOWS
+#include "CXWindowsScreen.h"
+#include "CXWindowsServerTaskBarReceiver.h"
+#elif WINAPI_CARBON
+#include "COSXScreen.h"
+#include "COSXServerTaskBarReceiver.h"
+#endif
+
+// platform dependent name of a daemon
+#if SYSAPI_WIN32
+#define DAEMON_NAME "Synergy Server"
+#elif SYSAPI_UNIX
+#define DAEMON_NAME "synergys"
+#endif
+
+// 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
+
+typedef int (*StartupFunc)(int, char**);
+static void parse(int argc, const char* const* argv);
+static bool loadConfig(const CString& pathname);
+static void loadConfig();
+
+//
+// program arguments
+//
+
+#define ARG CArgs::s_instance
+
+class CArgs {
+public:
+ CArgs() :
+ m_pname(NULL),
+ m_backend(false),
+ m_restartable(true),
+ m_daemon(true),
+ m_configFile(),
+ m_logFilter(NULL),
+ m_display(NULL),
+ m_synergyAddress(NULL),
+ m_config(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;
+ CString m_configFile;
+ const char* m_logFilter;
+ const char* m_display;
+ CString m_name;
+ CNetworkAddress* m_synergyAddress;
+ CConfig* m_config;
+};
+
+CArgs* CArgs::s_instance = NULL;
+
+
+//
+// platform dependent factories
+//
+
+static
+CScreen*
+createScreen()
+{
+#if WINAPI_MSWINDOWS
+ return new CScreen(new CMSWindowsScreen(true));
+#elif WINAPI_XWINDOWS
+ return new CScreen(new CXWindowsScreen(ARG->m_display, true));
+#elif WINAPI_CARBON
+ return new CScreen(new COSXScreen(true));
+#endif
+}
+
+static
+CServerTaskBarReceiver*
+createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
+{
+#if WINAPI_MSWINDOWS
+ return new CMSWindowsServerTaskBarReceiver(
+ CMSWindowsScreen::getInstance(), logBuffer);
+#elif WINAPI_XWINDOWS
+ return new CXWindowsServerTaskBarReceiver(logBuffer);
+#elif WINAPI_CARBON
+ return new COSXServerTaskBarReceiver(logBuffer);
+#endif
+}
+
+
+//
+// platform independent main
+//
+
+enum EServerState {
+ kUninitialized,
+ kInitializing,
+ kInitializingToStart,
+ kInitialized,
+ kStarting,
+ kStarted
+};
+
+static EServerState s_serverState = kUninitialized;
+static CServer* s_server = NULL;
+static CScreen* s_serverScreen = NULL;
+static CPrimaryClient* s_primaryClient = NULL;
+static CClientListener* s_listener = NULL;
+static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
+static CEvent::Type s_reloadConfigEvent = CEvent::kUnknown;
+static CEvent::Type s_forceReconnectEvent = CEvent::kUnknown;
+static bool s_suspended = false;
+static CEventQueueTimer* s_timer = NULL;
+
+CEvent::Type
+getReloadConfigEvent()
+{
+ return CEvent::registerTypeOnce(s_reloadConfigEvent, "reloadConfig");
+}
+
+CEvent::Type
+getForceReconnectEvent()
+{
+ return CEvent::registerTypeOnce(s_forceReconnectEvent, "forceReconnect");
+}
+
+static
+void
+updateStatus()
+{
+ s_taskBarReceiver->updateStatus(s_server, "");
+}
+
+static
+void
+updateStatus(const CString& msg)
+{
+ s_taskBarReceiver->updateStatus(s_server, msg);
+}
+
+static
+void
+handleClientConnected(const CEvent&, void* vlistener)
+{
+ CClientListener* listener = reinterpret_cast(vlistener);
+ CClientProxy* client = listener->getNextClient();
+ if (client != NULL) {
+ s_server->adoptClient(client);
+ updateStatus();
+ }
+}
+
+static
+CClientListener*
+openClientListener(const CNetworkAddress& address)
+{
+ CClientListener* listen =
+ new CClientListener(address, new CTCPSocketFactory, NULL);
+ EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen,
+ new CFunctionEventJob(
+ &handleClientConnected, listen));
+ return listen;
+}
+
+static
+void
+closeClientListener(CClientListener* listen)
+{
+ if (listen != NULL) {
+ EVENTQUEUE->removeHandler(CClientListener::getConnectedEvent(), listen);
+ delete listen;
+ }
+}
+
+static
+void
+handleScreenError(const CEvent&, void*)
+{
+ LOG((CLOG_CRIT "error on screen"));
+ EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
+}
+
+
+static void handleSuspend(const CEvent& event, void*);
+static void handleResume(const CEvent& event, void*);
+
+static
+CScreen*
+openServerScreen()
+{
+ CScreen* screen = createScreen();
+ EVENTQUEUE->adoptHandler(IScreen::getErrorEvent(),
+ screen->getEventTarget(),
+ new CFunctionEventJob(
+ &handleScreenError));
+ EVENTQUEUE->adoptHandler(IScreen::getSuspendEvent(),
+ screen->getEventTarget(),
+ new CFunctionEventJob(
+ &handleSuspend));
+ EVENTQUEUE->adoptHandler(IScreen::getResumeEvent(),
+ screen->getEventTarget(),
+ new CFunctionEventJob(
+ &handleResume));
+ return screen;
+}
+
+static
+void
+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;
+ }
+}
+
+static
+CPrimaryClient*
+openPrimaryClient(const CString& name, CScreen* screen)
+{
+ LOG((CLOG_DEBUG1 "creating primary screen"));
+ return new CPrimaryClient(name, screen);
+}
+
+static
+void
+closePrimaryClient(CPrimaryClient* primaryClient)
+{
+ delete primaryClient;
+}
+
+static
+void
+handleNoClients(const CEvent&, void*)
+{
+ updateStatus();
+}
+
+static
+void
+handleClientsDisconnected(const CEvent&, void*)
+{
+ EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
+}
+
+static
+CServer*
+openServer(const CConfig& config, CPrimaryClient* primaryClient)
+{
+ CServer* server = new CServer(config, primaryClient);
+ EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
+ new CFunctionEventJob(handleNoClients));
+ return server;
+}
+
+static
+void
+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 CFunctionEventJob(handleClientsDisconnected));
+ EVENTQUEUE->adoptHandler(CServer::getDisconnectedEvent(), server,
+ new CFunctionEventJob(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;
+}
+
+static bool initServer();
+static bool startServer();
+
+static
+void
+stopRetryTimer()
+{
+ if (s_timer != NULL) {
+ EVENTQUEUE->deleteTimer(s_timer);
+ EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
+ s_timer = NULL;
+ }
+}
+
+static
+void
+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;
+ }
+}
+
+static
+bool
+initServer()
+{
+ // skip if already initialized or initializing
+ if (s_serverState != kUninitialized) {
+ return true;
+ }
+
+ double retryTime;
+ CScreen* serverScreen = NULL;
+ CPrimaryClient* primaryClient = NULL;
+ try {
+ CString name = ARG->m_config->getCanonicalName(ARG->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 (ARG->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 CFunctionEventJob(&retryHandler, NULL));
+ s_serverState = kInitializing;
+ return true;
+ }
+ else {
+ // don't try again
+ return false;
+ }
+}
+
+static
+bool
+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(ARG->m_config->getSynergyAddress());
+ s_server = openServer(*ARG->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 (ARG->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 CFunctionEventJob(&retryHandler, NULL));
+ s_serverState = kStarting;
+ return true;
+ }
+ else {
+ // don't try again
+ return false;
+ }
+}
+
+static
+void
+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);
+}
+
+static
+void
+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);
+}
+
+static
+void
+handleSuspend(const CEvent&, void*)
+{
+ if (!s_suspended) {
+ LOG((CLOG_INFO "suspend"));
+ stopServer();
+ s_suspended = true;
+ }
+}
+
+static
+void
+handleResume(const CEvent&, void*)
+{
+ if (s_suspended) {
+ LOG((CLOG_INFO "resume"));
+ startServer();
+ s_suspended = false;
+ }
+}
+
+static
+void
+reloadSignalHandler(CArch::ESignal, void*)
+{
+ EVENTQUEUE->addEvent(CEvent(getReloadConfigEvent(),
+ IEventQueue::getSystemTarget()));
+}
+
+static
+void
+reloadConfig(const CEvent&, void*)
+{
+ LOG((CLOG_DEBUG "reload configuration"));
+ if (loadConfig(ARG->m_configFile)) {
+ if (s_server != NULL) {
+ s_server->setConfig(*ARG->m_config);
+ }
+ LOG((CLOG_NOTE "reloaded configuration"));
+ }
+}
+
+static
+void
+forceReconnect(const CEvent&, void*)
+{
+ if (s_server != NULL) {
+ s_server->disconnect();
+ }
+}
+
+static
+int
+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;
+
+ // if configuration has no screens then add this system
+ // as the default
+ if (ARG->m_config->begin() == ARG->m_config->end()) {
+ ARG->m_config->addScreen(ARG->m_name);
+ }
+
+ // set the contact address, if provided, in the config.
+ // otherwise, if the config doesn't have an address, use
+ // the default.
+ if (ARG->m_synergyAddress->isValid()) {
+ ARG->m_config->setSynergyAddress(*ARG->m_synergyAddress);
+ }
+ else if (!ARG->m_config->getSynergyAddress().isValid()) {
+ ARG->m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
+ }
+
+ // canonicalize the primary screen name
+ CString primaryName = ARG->m_config->getCanonicalName(ARG->m_name);
+ if (primaryName.empty()) {
+ LOG((CLOG_CRIT "unknown screen name `%s'", ARG->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 CFunctionEventJob(&reloadConfig));
+
+ // handle force reconnect event by disconnecting clients. they'll
+ // reconnect automatically.
+ EVENTQUEUE->adoptHandler(getForceReconnectEvent(),
+ IEventQueue::getSystemTarget(),
+ new CFunctionEventJob(&forceReconnect));
+
+ // 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"));
+
+ return kExitSuccess;
+}
+
+static
+int
+daemonMainLoop(int, const char**)
+{
+#if SYSAPI_WIN32
+ CSystemLogger sysLogger(DAEMON_NAME, false);
+#else
+ CSystemLogger sysLogger(DAEMON_NAME, true);
+#endif
+ return mainLoop();
+}
+
+static
+int
+standardStartup(int argc, char** argv)
+{
+ if (!ARG->m_daemon) {
+ ARCH->showConsole(false);
+ }
+
+ // parse command line
+ parse(argc, argv);
+
+ // load configuration
+ loadConfig();
+
+ // daemonize if requested
+ if (ARG->m_daemon) {
+ return ARCH->daemonize(DAEMON_NAME, &daemonMainLoop);
+ }
+ else {
+ return mainLoop();
+ }
+}
+
+static
+int
+run(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
+{
+ // general initialization
+ ARG->m_synergyAddress = new CNetworkAddress;
+ ARG->m_config = new CConfig;
+ ARG->m_pname = ARCH->getBasename(argv[0]);
+
+ // install caller's output filter
+ if (outputter != NULL) {
+ CLOG->insert(outputter);
+ }
+
+ // save log messages
+ CBufferedLogOutputter logBuffer(1000);
+ CLOG->insert(&logBuffer, true);
+
+ // make the task bar receiver. the user can control this app
+ // through the task bar.
+ s_taskBarReceiver = createTaskBarReceiver(&logBuffer);
+
+ // run
+ int result = startup(argc, argv);
+
+ // done with task bar receiver
+ delete s_taskBarReceiver;
+
+ // done with log buffer
+ CLOG->remove(&logBuffer);
+
+ delete ARG->m_config;
+ delete ARG->m_synergyAddress;
+ return result;
+}
+
+
+//
+// command line parsing
+//
+
+#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 ]"
+# define USAGE_DISPLAY_INFO \
+" --display connect to the X server at \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
+
+ LOG((CLOG_PRINT
+"Usage: %s"
+" [--address ]"
+" [--config ]"
+" [--debug ]"
+USAGE_DISPLAY_ARG
+" [--name ]"
+" [--restart|--no-restart]"
+PLATFORM_ARGS
+"\n\n"
+"Start the synergy mouse/keyboard sharing server.\n"
+"\n"
+" -a, --address listen for clients on the given address.\n"
+" -c, --config use the named configuration file instead.\n"
+" -d, --debug 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 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"
+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: [][:]. 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.",
+ ARG->m_pname,
+ kDefaultPort,
+ ARCH->concatPath(
+ ARCH->getUserDirectory(),
+ USR_CONFIG_NAME).c_str(),
+ ARCH->concatPath(
+ ARCH->getSystemDirectory(),
+ SYS_CONFIG_NAME).c_str()));
+}
+
+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);
+
+ // set defaults
+ ARG->m_name = ARCH->getHostName();
+
+ // parse options
+ int i = 1;
+ for (; 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, "-a", "--address", 1)) {
+ // save listen address
+ try {
+ *ARG->m_synergyAddress = CNetworkAddress(argv[i + 1],
+ kDefaultPort);
+ ARG->m_synergyAddress->resolve();
+ }
+ catch (XSocketAddress& e) {
+ LOG((CLOG_PRINT "%s: %s" BYE,
+ ARG->m_pname, e.what(), ARG->m_pname));
+ bye(kExitArgs);
+ }
+ ++i;
+ }
+
+ else if (isArg(i, argc, argv, "-n", "--name", 1)) {
+ // save screen name
+ ARG->m_name = argv[++i];
+ }
+
+ else if (isArg(i, argc, argv, "-c", "--config", 1)) {
+ // save configuration file path
+ ARG->m_configFile = argv[++i];
+ }
+
+#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, "-f", "--no-daemon")) {
+ // not a daemon
+ ARG->m_daemon = false;
+ }
+
+ else if (isArg(i, argc, argv, NULL, "--daemon")) {
+ // daemonize
+ ARG->m_daemon = true;
+ }
+
+ 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;
+ }
+ }
+
+ // no non-option arguments are allowed
+ if (i != argc) {
+ LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
+ ARG->m_pname, argv[i], ARG->m_pname));
+ bye(kExitArgs);
+ }
+
+ // 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 "Synergy server %s on %s", kVersion, ARCH->getOSName().c_str()));
+}
+
+static
+bool
+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 >> *ARG->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;
+}
+
+static
+void
+loadConfig()
+{
+ bool loaded = false;
+
+ // load the config file, if specified
+ if (!ARG->m_configFile.empty()) {
+ loaded = loadConfig(ARG->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;
+ ARG->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;
+ ARG->m_configFile = path;
+ }
+ }
+ }
+ }
+
+ if (!loaded) {
+ LOG((CLOG_PRINT "%s: no configuration available", ARG->m_pname));
+ bye(kExitConfig);
+ }
+}
+
+
+//
+// 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;
+ loadConfig();
+ 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);
+
+ // load configuration
+ loadConfig();
+
+ // 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) + " " + "Server").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, "");
+ //throw;
+ }
+ return kExitFailed;
+}
+
+#elif SYSAPI_UNIX
+
+int
+main(int argc, char** argv)
+{
+ CArgs args;
+ try {
+ 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: \n"));
+ throw;
+ }
+}
+
+#else
+
+#error no main() for platform
+
+#endif
diff --git a/cmd/synergys/synergys.ico b/cmd/synergys/synergys.ico
new file mode 100644
index 0000000000000000000000000000000000000000..89f965f4432c5f58054b9a1b0eae5bf6cbfd245d
GIT binary patch
literal 8478
zcmeI1KWH3B6vm(a*e8S|%Z-~Dq__}vXV}UrV&mT6#z|>aLkbt^+yrSM;8FwvhV6t%
zLQiZmzTr%%8baza{{iY$oC5(ZeHZtwQ9U1vh;!S!}zl^B0qm9a)se4
z$4!nI!GV?&yT9dtAbB1-&RoiHIHXs=+duJMuQ>Qqlb(9p`ug^E1I+I3?(XmJkD_Ir
zwoR+XpoZ`7n_*F5!?$xa7_9y@9UB~QjWDbDj>v-IqX1iNmO=`Jq0y9JcvU(jnEQ^w
z7Gb2>!%ze~pRL_3zyv-RkH?YkoZDF1+}w=gwY9a?KK%1QIIFneKdQ#~i{M`c0A3Tt
z1K}(%xF*;nf_mc~2;;GW3Worjn~JKt$bbM9zM*5w5O5oY2+>S!bo#xVIM#9I(&{w)eJBUN
zeJAtt^Rlq8Am`4VlM5Fv$i<5n<({SK{)Lx2
zcf5QpPsRUH%CArVl&9mdeD%YRB+58+ffXEO7-rZqY#FvpZQOaKIPAI@9d?J^VOO^T
zdx5=RP+%{x(@BZF#9m@AF_hRnW6#)^mO0~`5j-PMhEvA(o2BQJp&>&8GBjjp$k32^Z0N|)k*N+oJ*YAjjs+pbjlo20;DbJG3~oSXt2F(BaVG(BaTwr9y{8gF}NugO<*r!=b^Up|o%I
zGL(=!;g7MESF3|6au@Kd)Z{MERFJeFL4l@%+y!7k?t?N}3)s-$(csbG(csbG(O}C74J8^p8ax_G
zG!TXZJ{mk4JQ_S22+e^V4IT|14ITlW{3XFWjvkUDhGXo|;VrguoO~qT%DsE{eVYbJUo4A)*c53emtZek(@;r+A&?7`%alYMX$a
zY+S?5oN9)eBHqA@i;?Pjweae)tI(w2f&-E#+${e5S>63iAM`TagzjPcMcFJ$Y(hZaAL
zK9Rw|H_|&9)FI_tfX*qMLxQ;r%W>h`ir$IeFQ=8D75`u1H(R)5quI_B_inZY
z`w#h31SN9V5+-_1#7`aC(~P4ezM76pkkD<1n(})TrS!0)eWSx9y(K8_{d=_ISy@{N
zT9R7PBfXOV?+~X=Zo;=qR3)1r*J?T?JqdqOQS0|g$Q4UqeS6A`CiJxElT+yOJM;;M
z4u68)b!hW@=$O(;r2KxiS{sjsKb@U=ME;xEhFTKipMZQE#eS#RJDbrUyt}d2IpX6>
za(ySP_)ug{dwv(qXfHHQN7`?RK8(?u08Lb>z>#22Rc4!-|>%e>pWH7s3Yo%I-~CHeBwOgyeWaz
zp{~oYs#C06tRuuw-%(X(t$cW&zD$T!j`%zECiCoXIRyaW$EkIkxjg-ydip!{^nLpK
z@IIZrF`MQ1m2Nxb=7&PqIET$NlxiPcZLX`ax&{w}LnJfkI1B@$JJyFz#P!+JH%|8{
t;Zdj_)sxDeTJ=5vdoUQ9?87Q{NCkzlT_5sH8R_#vpACFJzU}{8{tX4i2$ui=
literal 0
HcmV?d00001
diff --git a/cmd/synergys/synergys.rc b/cmd/synergys/synergys.rc
new file mode 100644
index 00000000..d56a4313
--- /dev/null
+++ b/cmd/synergys/synergys.rc
@@ -0,0 +1,146 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#if !defined(IDC_STATIC)
+#define IDC_STATIC (-1)
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SYNERGY ICON DISCARDABLE "synergys.ico"
+IDI_TASKBAR_NOT_RUNNING ICON DISCARDABLE "tb_idle.ico"
+IDI_TASKBAR_NOT_WORKING ICON DISCARDABLE "tb_error.ico"
+IDI_TASKBAR_NOT_CONNECTED ICON DISCARDABLE "tb_wait.ico"
+IDI_TASKBAR_CONNECTED ICON DISCARDABLE "tb_run.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TASKBAR MENU DISCARDABLE
+BEGIN
+ POPUP "Synergy"
+ BEGIN
+ MENUITEM "Show Status", IDC_TASKBAR_STATUS
+ MENUITEM "Show Log", IDC_TASKBAR_SHOW_LOG
+ MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG
+ POPUP "Set Log Level"
+ BEGIN
+ MENUITEM "Error", IDC_TASKBAR_LOG_LEVEL_ERROR
+
+ MENUITEM "Warning", IDC_TASKBAR_LOG_LEVEL_WARNING
+
+ MENUITEM "Note", IDC_TASKBAR_LOG_LEVEL_NOTE
+
+ MENUITEM "Info", IDC_TASKBAR_LOG_LEVEL_INFO
+
+ MENUITEM "Debug", IDC_TASKBAR_LOG_LEVEL_DEBUG
+
+ MENUITEM "Debug1", IDC_TASKBAR_LOG_LEVEL_DEBUG1
+
+ MENUITEM "Debug2", IDC_TASKBAR_LOG_LEVEL_DEBUG2
+
+ END
+ MENUITEM "Reload Configuration", IDC_RELOAD_CONFIG
+ MENUITEM "Force Reconnect", IDC_FORCE_RECONNECT
+ MENUITEM SEPARATOR
+ MENUITEM "Quit", IDC_TASKBAR_QUIT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_TASKBAR_STATUS DIALOG DISCARDABLE 0, 0, 145, 60
+STYLE DS_MODALFRAME | WS_POPUP
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL |
+ ES_READONLY | NOT WS_BORDER
+ LISTBOX IDC_TASKBAR_STATUS_CLIENTS,3,17,139,40,NOT LBS_NOTIFY |
+ LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
+ WS_TABSTOP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK."
+ IDS_INIT_FAILED "Synergy failed to initialize: %{1}"
+ IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/cmd/synergys/tb_error.ico b/cmd/synergys/tb_error.ico
new file mode 100644
index 0000000000000000000000000000000000000000..746a87c9ec8ae70f24b4125afe9ca68defb2f6d1
GIT binary patch
literal 318
zcmZusyA6Xd5PgscB3VLIX+veDOwBY@u9?8{1k4aIf%|Jb3Y{4t9eD?$OZQF)q4|7v^Hl|=e!@IsjRK@B2u}b(FJQe=z?=V5liH
zWoPHjzBjX*nT1SN6a`+-89X}5txV(@w?b&ncnuP0lhP#!b);z;MJKxRrt5r?%Pbk_
z?N%_Tg0`uZoK7he#O%9wJeiXYR@<+l75<*=!?qP*0HwJ2|O6{7v9^DvFs
zu!_Y~)D!l8cMcLvA>Yqua2!LMtJfQ~uh~C-l}Rwt@WUxQyu;vMf6!iXu5qpJ`0fd8
C{!x(t
literal 0
HcmV?d00001
diff --git a/cmd/synergys/tb_run.ico b/cmd/synergys/tb_run.ico
new file mode 100644
index 0000000000000000000000000000000000000000..88e160cbfcd029978599f49605ba1a3c7695027e
GIT binary patch
literal 318
zcmZvXJ#K_B5QRT>QHT}^QKbzPO1ZU9vz2R3fRNJr5IzCD8;(L}A7MN84cny1jNhAi
z^COL+lJ|X&*-r&u76q#eLPafx?d1Px0X>%G9mGo6woTC*$N4x8%LKWVjJU*LBRA(t
z*&)UlLNF;^_DhTq!s6VW^|KVov_j`difNtFX&-H(O$k3SDILcq=N9iD-8@T;1372!
my*B6BBsAGS;Q0-Eqg$^!Uw{7
literal 0
HcmV?d00001
diff --git a/cmd/synergys/tb_wait.ico b/cmd/synergys/tb_wait.ico
new file mode 100644
index 0000000000000000000000000000000000000000..257be0a1d1bc613eec8cc1838a1dfd25d4644844
GIT binary patch
literal 318
zcmZvXF%H5o3`Ji7QN#e9SYe77nRA*>nK?mJi9LtNNy<&SB_ktS@h=k+vHidOZA%U`
zW?k2zcWvM#wvckMXxJFSxZpn+z?@1UcuF
zl1i)Vw8|M$8oa;3u2z*2ycgFRqu9Ap#396Zhplt1gb?~ejL|uFp_CFr025R~TS5=-
dGfb`By0-J}?~kW-COE!+Lz;S;(X4i~`vJXUO(y^V
literal 0
HcmV?d00001
diff --git a/config/config.guess b/config/config.guess
new file mode 100644
index 00000000..6ead80a0
--- /dev/null
+++ b/config/config.guess
@@ -0,0 +1,1327 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+
+timestamp='2001-08-21'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner .
+# Please send patches to .
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int dummy(){}" > $dummy.c ;
+ for c in cc gcc c89 ; do
+ ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
+ if test $? = 0 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ rm -f $dummy.c $dummy.o $dummy.rel ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_MACHINE}" in
+ i?86)
+ test -z "$VENDOR" && VENDOR=pc
+ ;;
+ *)
+ test -z "$VENDOR" && VENDOR=unknown
+ ;;
+esac
+test -f /etc/SuSE-release && VENDOR=suse
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # Netbsd (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ # Determine the machine/vendor (is the vendor relevant).
+ case "${UNAME_MACHINE}" in
+ amiga) machine=m68k-unknown ;;
+ arm32) machine=arm-unknown ;;
+ atari*) machine=m68k-atari ;;
+ sun3*) machine=m68k-sun ;;
+ mac68k) machine=m68k-apple ;;
+ macppc) machine=powerpc-apple ;;
+ hp3[0-9][05]) machine=m68k-hp ;;
+ ibmrt|romp-ibm) machine=romp-ibm ;;
+ *) machine=${UNAME_MACHINE}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE}" in
+ i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <$dummy.s
+ .data
+\$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ 2-1307)
+ UNAME_MACHINE="alphaev68"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:NetBSD:*)
+ echo `uname -p`-unknown-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >$dummy.c
+ #include
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ case "${HPUX_REV}" in
+ 11.[0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ esac ;;
+ esac
+ fi ;;
+ esac
+ if [ "${HP_ARCH}" = "" ]; then
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include
+ #include
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ eval $set_cc_for_build
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+ if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+ rm -f $dummy.c $dummy
+ fi ;;
+ esac
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >$dummy.c
+ #include
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ hppa*:OpenBSD:*:*)
+ echo hppa-unknown-openbsd
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3D:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR}-linux
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR}-linux
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR}-linux
+ exit 0 ;;
+ mips:Linux:*:*)
+ case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in
+ big) echo mips-${VENDOR}-linux && exit 0 ;;
+ little) echo mipsel-${VENDOR}-linux && exit 0 ;;
+ esac
+ case `sed -n '/^system type/s/^.*: \([^ ]*\).*/\1/p' < /proc/cpuinfo` in
+ SGI|sgi) echo mips-${VENDOR}-linux-gnu && exit 0 ;;
+ esac
+ ;;
+ ppc:Linux:*:*|ppc64:Linux:*:*)
+ echo powerpc-${VENDOR}-linux
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-${VENDOR}-linux${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-${VENDOR}-linux ;;
+ PA8*) echo hppa2.0-${VENDOR}-linux ;;
+ *) echo hppa-${VENDOR}-linux ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-${VENDOR}-linux
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR}-linux
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-${VENDOR}-linux
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-${VENDOR}-linux
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_supported_targets=`cd /; ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-${VENDOR}-linux"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-${VENDOR}-linuxaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-${VENDOR}-linuxcoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linuxoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-${VENDOR}-linuxoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >$dummy.c <
+#ifdef __cplusplus
+#include /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linuxlibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linuxlibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linuxaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes .
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[KW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <
+# include
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+eval $set_cc_for_build
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 < in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config/config.sub b/config/config.sub
new file mode 100644
index 00000000..83f4b015
--- /dev/null
+++ b/config/config.sub
@@ -0,0 +1,1410 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+
+timestamp='2001-08-13'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to .
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit 0;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+ | c4x | clipper \
+ | d10v | d30v | dsp16xx \
+ | fr30 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | m32r | m68000 | m68k | m88k | mcore \
+ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el | mips64vr4300 \
+ | mips64vr4300el | mips64vr5000 | mips64vr5000el \
+ | mipsbe | mipsel | mipsle | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | ns16k | ns32k \
+ | openrisc \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | s390 | s390x \
+ | sh | sh[34] | sh[34]eb | shbe | shle \
+ | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \
+ | strongarm \
+ | tahoe | thumb | tic80 | tron \
+ | v850 \
+ | we32k \
+ | x86 | xscale \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alphapca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armv*-* \
+ | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c54x-* \
+ | clipper-* | cray2-* | cydra-* \
+ | d10v-* | d30v-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fr30-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | m32r-* \
+ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | mcore-* \
+ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \
+ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipsel-* \
+ | mipsle-* | mipstx39-* | mipstx39el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | s390-* | s390x-* \
+ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \
+ | sparc-* | sparc64-* | sparc86x-* | sparclite-* \
+ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* \
+ | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \
+ | v850-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [cjt]90)
+ basic_machine=${basic_machine}-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ mmix*)
+ basic_machine=mmix-knuth
+ os=-mmixware
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | k6 | nexgen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i686-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc64) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sparclite-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=t3e-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ windows32)
+ basic_machine=i386-pc
+ os=-windows32-msvcrt
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ mips)
+ case $os in
+ linux*)
+ basic_machine=mips-unknown
+ ;;
+ *)
+ basic_machine=mips-mips
+ ;;
+ esac
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh3 | sh4 | sh3eb | sh4eb)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv9 | sparcv9b)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ c4x*)
+ basic_machine=c4x-none
+ os=-coff
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux* | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto*)
+ os=-nto-qnx
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config/depcomp b/config/depcomp
new file mode 100644
index 00000000..65899658
--- /dev/null
+++ b/config/depcomp
@@ -0,0 +1,411 @@
+#! /bin/sh
+
+# depcomp - compile a program generating dependencies as side-effects
+# Copyright 1999, 2000 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva .
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+# `libtool' can also be set to `yes' or `no'.
+
+depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. This file always lives in the current directory.
+ # Also, the AIX compiler puts `$object:' at the start of each line;
+ # $object doesn't have directory information.
+ stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ outname="$stripped.o"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 AIX compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+
+ tmpdepfile1="$object.d"
+ tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'`
+ if test "$libtool" = yes; then
+ "$@" -Wc,-MD
+ else
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile1"; then
+ tmpdepfile="$tmpdepfile1"
+ else
+ tmpdepfile="$tmpdepfile2"
+ fi
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a space and a tab in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the proprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ test -z "$dashmflag" && dashmflag=-M
+ ( IFS=" "
+ case " $* " in
+ *" --mode=compile "*) # this is libtool, let us make it quiet
+ for arg
+ do # cycle over the arguments
+ case "$arg" in
+ "--mode=compile")
+ # insert --quiet before "--mode=compile"
+ set fnord "$@" --quiet
+ shift # fnord
+ ;;
+ esac
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # "$arg"
+ done
+ ;;
+ esac
+ "$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ ) &
+ proc=$!
+ "$@"
+ stat=$?
+ wait "$proc"
+ if test "$stat" != 0; then exit $stat; fi
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ # X makedepend
+ (
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in no)
+ set ""; shift
+ cleared=yes
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift;;
+ -*)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ ) &
+ proc=$!
+ "$@"
+ stat=$?
+ wait "$proc"
+ if test "$stat" != 0; then exit $stat; fi
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tail +3 "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the proprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ ( IFS=" "
+ case " $* " in
+ *" --mode=compile "*)
+ for arg
+ do # cycle over the arguments
+ case $arg in
+ "--mode=compile")
+ # insert --quiet before "--mode=compile"
+ set fnord "$@" --quiet
+ shift # fnord
+ ;;
+ esac
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # "$arg"
+ done
+ ;;
+ esac
+ "$@" -E |
+ sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ ) &
+ proc=$!
+ "$@"
+ stat=$?
+ wait "$proc"
+ if test "$stat" != 0; then exit $stat; fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the proprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ ( IFS=" "
+ case " $* " in
+ *" --mode=compile "*)
+ for arg
+ do # cycle over the arguments
+ case $arg in
+ "--mode=compile")
+ # insert --quiet before "--mode=compile"
+ set fnord "$@" --quiet
+ shift # fnord
+ ;;
+ esac
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # "$arg"
+ done
+ ;;
+ esac
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ ) &
+ proc=$!
+ "$@"
+ stat=$?
+ wait "$proc"
+ if test "$stat" != 0; then exit $stat; fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/config/install-sh b/config/install-sh
new file mode 100644
index 00000000..e9de2384
--- /dev/null
+++ b/config/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/config/missing b/config/missing
new file mode 100644
index 00000000..0a7fb5a2
--- /dev/null
+++ b/config/missing
@@ -0,0 +1,283 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard , 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program 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.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing 0.3 - GNU automake"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+ # We have makeinfo, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ fi
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar ${1+"$@"} && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar ${1+"$@"} && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" ${1+"$@"} && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" ${1+"$@"} && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/config/mkinstalldirs b/config/mkinstalldirs
new file mode 100644
index 00000000..6b3b5fc5
--- /dev/null
+++ b/config/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/configure.in b/configure.in
new file mode 100644
index 00000000..14367546
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,289 @@
+dnl synergy -- mouse and keyboard sharing utility
+dnl Copyright (C) 2002 Chris Schoeneman
+dnl
+dnl This package is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU General Public License
+dnl found in the file COPYING that should have accompanied this file.
+dnl
+dnl This package is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+
+dnl Process this file with autoconf to produce a configure script.
+
+dnl initialize
+AC_INIT(lib/common/common.h)
+AC_CONFIG_AUX_DIR(config)
+
+dnl current version, extracted from $srcdir/lib/common/Version.h
+MAJOR_VERSION=`grep '#.*define VERSION "' $srcdir/lib/common/Version.h | sed -e 's/.*"\([0-9]*\)\.[0-9]*\.[0-9]*".*/\1/'`
+MINOR_VERSION=`grep '#.*define VERSION "' $srcdir/lib/common/Version.h | sed -e 's/.*"[0-9]*\.\([0-9]*\)\.[0-9]*".*/\1/'`
+RELEASE_VERSION=`grep '#.*define VERSION "' $srcdir/lib/common/Version.h | sed -e 's/.*"[0-9]*\.[0-9]*\.\([0-9]*\)".*/\1/'`
+
+dnl initialize automake
+AM_INIT_AUTOMAKE(synergy, $MAJOR_VERSION.$MINOR_VERSION.$RELEASE_VERSION)
+AM_CONFIG_HEADER(config.h)
+
+dnl information on the package
+
+dnl decide on platform
+ARCH_LIBS=""
+ARCH_CFLAGS=""
+AC_CANONICAL_HOST
+case $host in
+*-*-mingw32* | *-*-windows*)
+ acx_host_arch="WIN32"
+ acx_host_winapi="MSWINDOWS"
+ ;;
+*-*-darwin*)
+ acx_host_arch="UNIX"
+ acx_host_winapi="CARBON"
+ ;;
+*)
+ acx_host_arch="UNIX"
+ acx_host_winapi="XWINDOWS"
+ ;;
+esac
+ARCH_CFLAGS="$ARCH_CFLAGS -DSYSAPI_$acx_host_arch=1 -DWINAPI_$acx_host_winapi=1"
+AM_CONDITIONAL(WIN32, test x$acx_host_arch = xWIN32)
+AM_CONDITIONAL(UNIX, test x$acx_host_arch = xUNIX)
+AM_CONDITIONAL(MSWINDOWS, test x$acx_host_winapi = xMSWINDOWS)
+AM_CONDITIONAL(CARBON, test x$acx_host_winapi = xCARBON)
+AM_CONDITIONAL(XWINDOWS, test x$acx_host_winapi = xXWINDOWS)
+
+dnl checks for programs
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_RANLIB
+AC_CHECK_PROG(HAVE_DOT, dot, YES, NO)
+
+dnl AC_PROG_OBJC doesn't exist. Borrow some ideas from KDE.
+dnl AC_MSG_CHECKING(for an Objective-C compiler)
+OBJC="${CC}"
+OBJCFLAGS="${CFLAGS}"
+AC_SUBST(OBJC)
+AC_SUBST(OBJCFLAGS)
+_AM_DEPENDENCIES(OBJC)
+
+dnl do checks using C++
+AC_LANG_CPLUSPLUS
+
+dnl our files end in .cpp not .C so tests should also end in .cpp
+ac_ext=cpp
+
+dnl enable debugging or disable asserts
+AC_ARG_ENABLE([debug], [ --enable-debug enable debugging])
+if test "x$enable_debug" != xno; then
+ CXXFLAGS="$CXXFLAGS -g"
+else
+ CXXFLAGS="$CXXFLAGS -DNDEBUG"
+fi
+
+dnl check compiler
+ACX_CHECK_CXX
+
+dnl checks for libraries
+if test x"$acx_host_arch" = xUNIX; then
+ ACX_PTHREAD(,AC_MSG_ERROR(You must have pthreads to compile synergy))
+ ARCH_LIBS="$PTHREAD_LIBS $ARCH_LIBS"
+ ARCH_CFLAGS="$ARCH_CFLAGS $PTHREAD_CFLAGS"
+fi
+if test x"$acx_host_winapi" = xCARBON; then
+ ARCH_LIBS="-framework Carbon $ARCH_LIBS"
+fi
+ACX_CHECK_NANOSLEEP
+ACX_CHECK_INET_ATON
+
+dnl checks for header files
+AC_HEADER_STDC
+AC_CHECK_HEADERS([unistd.h sys/time.h sys/types.h locale.h wchar.h])
+AC_CHECK_HEADERS([sys/socket.h sys/select.h])
+AC_CHECK_HEADERS([sys/utsname.h])
+AC_CHECK_HEADERS([istream ostream sstream])
+AC_HEADER_TIME
+if test x"$acx_host_winapi" = xXWINDOWS; then
+ AC_PATH_X
+ AC_PATH_XTRA
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+ XEXT_LDADD=
+
+ AC_CHECK_LIB(Xtst,
+ XTestQueryExtension,
+ [XEXT_LDADD="$XEXT_LDADD -lXtst"],
+ AC_MSG_ERROR(You must have the XTest library to build synergy),
+ [$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
+ AC_CHECK_HEADERS([X11/extensions/XTest.h],
+ ,
+ AC_MSG_ERROR(You must have the XTest headers to compile synergy))
+
+ acx_have_xkb=no
+ AC_CHECK_LIB(X11,
+ XkbQueryExtension,
+ [acx_have_xkb=yes],
+ [acx_have_xkb=no],
+ [$X_LIBS $X_EXTRA_LIBS])
+ if test x"$acx_have_xkb" = xyes; then
+ AC_CHECK_HEADERS([X11/XKBlib.h X11/extensions/XKBstr.h],
+ [acx_have_xkb=yes],
+ [acx_have_xkb=no],
+ [#include ])
+ if test x"$acx_have_xkb" = xyes; then
+ AC_TRY_COMPILE([
+ #include
+ #include
+ ],[
+ XkbQueryExtension(0, 0, 0, 0, 0, 0);
+ ],
+ [acx_have_xkb=yes],
+ [acx_have_xkb=no])
+ fi
+ fi
+ if test x"$acx_have_xkb" = xyes; then
+ AC_DEFINE(HAVE_XKB_EXTENSION, 1,
+ [Define this if the XKB extension is available.])
+ fi
+
+ acx_have_xinerama=yes
+ AC_CHECK_LIB(Xinerama,
+ XineramaQueryExtension,
+ [acx_have_xinerama=yes],
+ [acx_have_xinerama=no],
+ [$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
+ if test x"$acx_have_xinerama" = xyes; then
+ AC_CHECK_HEADERS([X11/extensions/Xinerama.h],
+ [acx_have_xinerama=yes],
+ [acx_have_xinerama=no],
+ [#include ])
+ fi
+ if test x"$acx_have_xinerama" = xyes; then
+ XEXT_LDADD="$XEXT_LDADD -lXinerama"
+ fi
+
+ X_DPMS_LDADD=
+ acx_have_dpms=no
+ AC_CHECK_LIB(Xext,
+ DPMSQueryExtension,
+ [acx_have_dpms=yes],
+ [acx_have_dpms=no],
+ [$X_LIBS -lX11 $X_EXTRA_LIBS])
+ if test x"$acx_have_dpms" != xyes; then
+ AC_CHECK_LIB(Xdpms,
+ DPMSQueryExtension,
+ [acx_have_dpms=yes; XDPMS_LDADD=-lXdpms],
+ [acx_have_dpms=no],
+ [$X_LIBS -lX11 $X_EXTRA_LIBS])
+ fi
+ if test x"$acx_have_dpms" = xyes; then
+ AC_CHECK_HEADERS([X11/extensions/dpms.h],
+ [acx_have_dpms_h=yes],
+ [acx_have_dpms_h=no],
+ [#include ])
+ if test x"$acx_have_dpms_h" = xyes; then
+ XEXT_LDADD="$XEXT_LDADD $XDPMS_LDADD"
+ AC_MSG_CHECKING(for prototypes in X11/extensions/dpms.h)
+ acx_have_dpms_protos=no
+ AC_TRY_COMPILE([
+ #include
+ extern "C" {
+ #include
+ }
+ ],[
+ int s = DPMSModeOn;
+ DPMSQueryExtension(0, 0, 0);
+ ],
+ [acx_have_dpms_protos=yes])
+ AC_MSG_RESULT($acx_have_dpms_protos)
+ if test x"$acx_have_dpms_protos" = xyes; then
+ AC_DEFINE(HAVE_DPMS_PROTOTYPES,1,[Define if the header file declares function prototypes.])
+ fi
+ fi
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ ARCH_LIBS="$X_LIBS $X_PRE_LIBS $XEXT_LDADD -lXext -lX11 $X_EXTRA_LIBS $ARCH_LIBS"
+ ARCH_CFLAGS="$ARCH_CFLAGS $X_CFLAGS"
+fi
+
+dnl checks for types
+AC_TYPE_SIZE_T
+ACX_CHECK_SOCKLEN_T
+
+dnl checks for structures
+AC_STRUCT_TM
+
+dnl checks for compiler characteristics
+AC_CHECK_SIZEOF(char, 1)
+AC_CHECK_SIZEOF(short, 2)
+AC_CHECK_SIZEOF(int, 2)
+AC_CHECK_SIZEOF(long, 4)
+ACX_CHECK_CXX_BOOL(,AC_MSG_ERROR(Your compiler must support bool to compile synergy))
+ACX_CHECK_CXX_EXCEPTIONS(,AC_MSG_ERROR(Your compiler must support exceptions to compile synergy))
+ACX_CHECK_CXX_CASTS(,AC_MSG_ERROR(Your compiler must support C++ casts to compile synergy))
+ACX_CHECK_CXX_MUTABLE(,AC_MSG_ERROR(Your compiler must support mutable to compile synergy))
+ACX_CHECK_CXX_STDLIB(,AC_MSG_ERROR(Your compiler must support the C++ standard library to compile synergy))
+
+dnl checks for library functions
+dnl AC_TYPE_SIGNAL
+AC_FUNC_MEMCMP
+AC_FUNC_STRFTIME
+AC_CHECK_FUNCS(gmtime_r)
+ACX_CHECK_GETPWUID_R
+AC_CHECK_FUNCS(vsnprintf)
+AC_FUNC_SELECT_ARGTYPES
+ACX_CHECK_POLL
+ACX_FUNC_ACCEPT
+dnl use AC_REPLACE_FUNCS() for stuff in string.h
+
+dnl checks for system services
+
+dnl enable maximum compiler warnings and warnings are errors.
+ACX_CXX_WARNINGS
+ACX_CXX_WARNINGS_ARE_ERRORS
+
+dnl adjust compiler and linker variables
+CXXFLAGS="$CXXFLAGS $SYNERGY_CXXFLAGS $ARCH_CFLAGS"
+OBJCXXFLAGS="$OBJCXXFLAGS $CXXFLAGS $ARCH_CFLAGS"
+LIBS="$NANOSLEEP_LIBS $INET_ATON_LIBS $ARCH_LIBS $LIBS"
+
+dnl we need to have an environment variable set when building on OS X.
+dnl i'm not sure of the right way to do that. writing 'export ...' to
+dnl the makefiles isn't portable. here we'll hijack XXXDEPMODE (where
+dnl XXX depends on the language) to insert setting the environment
+dnl variable when running the compiler. we'd like to put that in CC,
+dnl CXX and OBJC but that breaks depcomp. let's hope this works.
+if test x"$acx_host_winapi" = xCARBON; then
+ MACOSX_DEPLOYMENT_TARGET="10.2"
+ CCDEPMODE="MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET $CCDEPMODE"
+ CXXDEPMODE="MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET $CXXDEPMODE"
+ OBJCDEPMODE="MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET $OBJCDEPMODE"
+else
+ MACOSX_DEPLOYMENT_TARGET="5"
+ CXXDEPMODE="FOO=$MACOSX_DEPLOYMENT_TARGET $CXXDEPMODE"
+fi
+
+AC_OUTPUT([
+Makefile
+cmd/Makefile
+cmd/launcher/Makefile
+cmd/synergyc/Makefile
+cmd/synergys/Makefile
+dist/Makefile
+dist/nullsoft/Makefile
+dist/rpm/Makefile
+dist/rpm/synergy.spec
+doc/Makefile
+doc/doxygen.cfg
+lib/Makefile
+lib/arch/Makefile
+lib/base/Makefile
+lib/client/Makefile
+lib/common/Makefile
+lib/io/Makefile
+lib/mt/Makefile
+lib/net/Makefile
+lib/platform/Makefile
+lib/server/Makefile
+lib/synergy/Makefile
+])
diff --git a/dist/Makefile.am b/dist/Makefile.am
new file mode 100644
index 00000000..1af99c18
--- /dev/null
+++ b/dist/Makefile.am
@@ -0,0 +1,26 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+SUBDIRS = \
+ rpm \
+ nullsoft \
+ $(NULL)
+
+EXTRA_DIST = \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
diff --git a/dist/nullsoft/Makefile.am b/dist/nullsoft/Makefile.am
new file mode 100644
index 00000000..120cd016
--- /dev/null
+++ b/dist/nullsoft/Makefile.am
@@ -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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+EXTRA_DIST = \
+ Makefile.win \
+ synergy.nsi \
+ dosify.c \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
diff --git a/dist/nullsoft/Makefile.win b/dist/nullsoft/Makefile.win
new file mode 100644
index 00000000..91aa68bb
--- /dev/null
+++ b/dist/nullsoft/Makefile.win
@@ -0,0 +1,63 @@
+# synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2007 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.
+
+NSIS = "$(PROGRAMFILES)\NSIS\makensis.exe"
+NSIS_FLAGS = /NOCD /V1
+
+BIN_INSTALLER_SRC = dist\nullsoft
+BIN_INSTALLER_DST = $(BUILD_DST)\$(BIN_INSTALLER_SRC)
+BIN_DOSIFY_EXE = "$(BIN_INSTALLER_DST)\dosify.exe"
+BIN_DOSIFY_C = \
+ "$(BIN_INSTALLER_SRC)\dosify.c" \
+ $(NULL)
+BIN_DOSIFY_OBJ = \
+ "$(BIN_INSTALLER_DST)\dosify.obj" \
+ $(NULL)
+
+BIN_INSTALLER_NSI = "$(BIN_INSTALLER_SRC)\synergy.nsi"
+BIN_INSTALLER_EXE = "$(BUILD_DST)\SynergyInstaller.exe"
+BIN_INSTALLER_DOCS = \
+ COPYING \
+ ChangeLog \
+ $(NULL)
+BIN_INSTALLER_DOS_DOCS = \
+ $(BUILD_DST)\COPYING.txt \
+ $(BUILD_DST)\ChangeLog.txt \
+ $(NULL)
+
+C_FILES = $(C_FILES) $(BIN_DOSIFY_C)
+OBJ_FILES = $(OBJ_FILES) $(BIN_DOSIFY_OBJ)
+OPTPROGRAMS = $(OPTPROGRAMS) $(BIN_DOSIFY_EXE)
+
+# Build rules.
+$(BIN_DOSIFY_OBJ): $(BIN_DOSIFY_C)
+ @$(ECHO) Compile $(BIN_DOSIFY_C)
+ -@$(MKDIR) $(BIN_INSTALLER_DST) 2>NUL:
+ $(cc) $(cdebug) $(cflags) $(cvars) /Fo$@ /Fd$(@:.obj=.pdb) $**
+$(BIN_DOSIFY_EXE): $(BIN_DOSIFY_OBJ)
+ @$(ECHO) Link $(@F)
+ $(link) $(ldebug) $(conlflags) $(conlibsmt) /out:$@ $**
+
+# Convert text files from Unix to DOS format.
+$(BIN_INSTALLER_DOS_DOCS): $(BIN_DOSIFY_EXE) $(BIN_INSTALLER_DOCS)
+ @$(ECHO) Convert text files to DOS format
+ $(BIN_DOSIFY_EXE) "." "$(BUILD_DST)" $(BIN_INSTALLER_DOCS)
+
+# Allow installers for both debug and release.
+$(BIN_INSTALLER_EXE): $(BIN_INSTALLER_NSI) all $(BIN_INSTALLER_DOS_DOCS)
+ @$(ECHO) Build $(@F)
+ $(NSIS) $(NSIS_FLAGS) /DOUTPUTDIR=$(@D) /DOUTPUTFILE=$@ $(BIN_INSTALLER_NSI)
+installer: $(BIN_INSTALLER_EXE)
+debug-installer:
+ @$(MAKE) /nologo /f $(MAKEFILE) DEBUG=1 installer
+release-installer:
+ @$(MAKE) /nologo /f $(MAKEFILE) NODEBUG=1 installer
diff --git a/dist/nullsoft/dosify.c b/dist/nullsoft/dosify.c
new file mode 100644
index 00000000..95d0caee
--- /dev/null
+++ b/dist/nullsoft/dosify.c
@@ -0,0 +1,99 @@
+#include
+#include
+#include
+
+static
+char*
+concatPath(const char* dir, const char* name, const char* ext)
+{
+ size_t nDir = (dir != NULL) ? strlen(dir) : 0;
+ size_t nPath = nDir + 1 + strlen(name) + strlen(ext?ext:"") + 1;
+ char* path = malloc(nPath);
+
+ /* directory */
+ if (nDir > 0 && strcmp(dir, ".") != 0) {
+ strcpy(path, dir);
+ if (path[nDir - 1] != '\\' && path[nDir - 1] != '/') {
+ strcat(path, "\\");
+ }
+ }
+ else {
+ strcpy(path, "");
+ }
+
+
+ /* name */
+ strcat(path, name);
+
+ /* extension */
+ if (ext != NULL && strrchr(name, '.') == NULL) {
+ strcat(path, ext);
+ }
+
+ return path;
+}
+
+static
+int
+dosify(const char* srcdir, const char* dstdir, const char* name)
+{
+ FILE* dFile, *sFile;
+ char* dName, *sName;
+
+ sName = concatPath(srcdir, name, NULL);
+ dName = concatPath(dstdir, name, ".txt");
+
+ sFile = fopen(sName, "rb");
+ if (sFile == NULL) {
+ fprintf(stderr, "Can't open \"%s\" for reading\n", sName);
+ return 0;
+ }
+ else {
+ dFile = fopen(dName, "w");
+ if (dFile == NULL) {
+ fclose(sFile);
+ fprintf(stderr, "Can't open \"%s\" for writing\n", dName);
+ return 0;
+ }
+ else {
+ char buffer[1024];
+ while (!ferror(dFile) &&
+ fgets(buffer, sizeof(buffer), sFile) != NULL) {
+ fprintf(dFile, "%s", buffer);
+ }
+ if (ferror(sFile) || ferror(dFile)) {
+ fprintf(stderr,
+ "Error copying \"%s\" to \"%s\"\n", sName, dName);
+ fclose(dFile);
+ fclose(sFile);
+ _unlink(dName);
+ return 0;
+ }
+ }
+ }
+
+ fclose(dFile);
+ fclose(sFile);
+ free(dName);
+ free(sName);
+ return 1;
+}
+
+#include
+int
+main(int argc, char** argv)
+{
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s [files]\n", argv[0]);
+ return 1;
+ }
+
+ for (i = 3; i < argc; ++i) {
+ if (!dosify(argv[1], argv[2], argv[i]))
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/dist/nullsoft/synergy.nsi b/dist/nullsoft/synergy.nsi
new file mode 100644
index 00000000..3370d03a
--- /dev/null
+++ b/dist/nullsoft/synergy.nsi
@@ -0,0 +1,179 @@
+; Synergy.nsi
+;
+; This script is based on example1.nsi, but it remember the directory,
+; has uninstall support and (optionally) installs start menu shortcuts.
+;
+; It will install makensisw.exe into a directory that the user selects,
+
+;--------------------------------
+
+!ifndef OUTPUTDIR
+!define OUTPUTDIR "build\Release"
+!endif
+
+; The name of the installer
+Name "Synergy"
+
+; The file to write
+OutFile "${OUTPUTFILE}"
+
+; The default installation directory
+InstallDir $PROGRAMFILES\Synergy
+
+; Registry key to check for directory (so if you install again, it will
+; overwrite the old one automatically)
+InstallDirRegKey HKLM "Software\Synergy" "Install_Dir"
+
+;--------------------------------
+
+; Pages
+
+Page components
+Page license
+Page directory
+Page instfiles
+
+UninstPage uninstConfirm
+UninstPage instfiles
+
+;--------------------------------
+
+; Text
+ComponentText "This will install Synergy on your computer. Select the optional components you want to install."
+DirText "Choose a directory to install Synergy to:"
+UninstallText "This will uninstall Synergy from your computer."
+LicenseText "Synergy is distributed under the GNU GPL:"
+LicenseData ${OUTPUTDIR}\COPYING.txt
+
+;--------------------------------
+
+; The stuff to install
+Section "Synergy (required)"
+
+ SectionIn RO
+
+ ; Set output path to the installation directory.
+ SetOutPath $INSTDIR
+
+ ; Put files there
+ File "${OUTPUTDIR}\synergy.exe"
+ File "${OUTPUTDIR}\synergyc.exe"
+ File "${OUTPUTDIR}\synergys.exe"
+ File "${OUTPUTDIR}\*.dll"
+ File "${OUTPUTDIR}\COPYING.txt"
+ File "${OUTPUTDIR}\ChangeLog.txt"
+ File doc\PORTING
+ File doc\about.html
+ File doc\authors.html
+ File doc\autostart.html
+ File doc\banner.html
+ File doc\compiling.html
+ File doc\configuration.html
+ File doc\contact.html
+ File doc\developer.html
+ File doc\faq.html
+ File doc\history.html
+ File doc\home.html
+ File doc\index.html
+ File doc\license.html
+ File doc\news.html
+ File doc\roadmap.html
+ File doc\running.html
+ File doc\security.html
+ File doc\synergy.css
+ File doc\tips.html
+ File doc\toc.html
+ File doc\trouble.html
+
+ SetOutPath $INSTDIR\images
+ File doc\images\logo.gif
+ File doc\images\warp.gif
+
+ ; Write the installation path into the registry
+ WriteRegStr HKLM SOFTWARE\Synergy "Install_Dir" "$INSTDIR"
+
+ ; Write the uninstall keys for Windows
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Synergy" "DisplayName" "Synergy"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Synergy" "UninstallString" '"$INSTDIR\uninstall.exe"'
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Synergy" "NoModify" 1
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Synergy" "NoRepair" 1
+ WriteUninstaller "uninstall.exe"
+
+SectionEnd
+
+; Optional section (can be disabled by the user)
+Section "Start Menu Shortcuts"
+
+ CreateDirectory "$SMPROGRAMS\Synergy"
+ CreateShortCut "$SMPROGRAMS\Synergy\Synergy.lnk" "$INSTDIR\synergy.exe" "" "$INSTDIR\synergy.exe" 0
+ CreateShortCut "$SMPROGRAMS\Synergy\README.lnk" "$INSTDIR\index.html"
+ CreateShortCut "$SMPROGRAMS\Synergy\Synergy Folder.lnk" "$INSTDIR"
+ CreateShortCut "$SMPROGRAMS\Synergy\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
+
+SectionEnd
+
+; Optional section (can be disabled by the user)
+Section "Desktop Icon"
+
+ CreateShortCut "$DESKTOP\Synergy.lnk" "$INSTDIR\synergy.exe" "" "$INSTDIR\synergy.exe" 0
+
+SectionEnd
+
+;--------------------------------
+
+; Uninstaller
+
+Section "Uninstall"
+ ; Stop and uninstall the daemons
+ ExecWait '"$INSTDIR\synergy.exe" /uninstall'
+
+ ; Remove autorun registry keys for synergy
+ DeleteRegKey HKLM "SYSTEM\CurrentControlSet\Services\Synergy Server"
+ DeleteRegKey HKLM "SYSTEM\CurrentControlSet\Services\Synergy Client"
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\RunServices" "Synergy Server"
+ DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\RunServices" "Synergy Client"
+ DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "Synergy Server"
+ DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "Synergy Client"
+
+ ; not all keys will have existed, so errors WILL have happened
+ ClearErrors
+
+ ; Remove registry keys
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Synergy"
+ DeleteRegKey HKLM SOFTWARE\Synergy
+
+ ClearErrors
+
+ ; First try to remove files that might be locked (if synergy is running)
+ Delete /REBOOTOK $INSTDIR\synergy.exe
+ Delete /REBOOTOK $INSTDIR\synergyc.exe
+ Delete /REBOOTOK $INSTDIR\synergys.exe
+ Delete /REBOOTOK $INSTDIR\synrgyhk.dll
+
+ ; Remove files and directory
+ Delete $INSTDIR\*.*
+ RMDir $INSTDIR
+
+ ; Remove shortcuts, if any
+ Delete "$SMPROGRAMS\Synergy\*.*"
+ Delete "$DESKTOP\Synergy.lnk"
+
+ ; Remove directories used
+ RMDir "$SMPROGRAMS\Synergy"
+ RMDir "$INSTDIR"
+
+ IfRebootFlag 0 EndOfAll
+ MessageBox MB_OKCANCEL "Uninstaller needs to reboot to finish cleaning up. reboot now?" IDCANCEL NoReboot
+ ClearErrors
+ Reboot
+ IfErrors 0 EndOfAll
+ MessageBox MB_OK "Uninstaller could not reboot. Please reboot manually. Thank you."
+ Abort "Uninstaller could not reboot. Please reboot manually. Thank you."
+ NoReboot:
+ DetailPrint ""
+ DetailPrint "Uninstaller could not reboot. Please reboot manually. Thank you."
+ DetailPrint ""
+ SetDetailsView show
+ EndOfAll:
+
+SectionEnd
diff --git a/dist/rpm/Makefile.am b/dist/rpm/Makefile.am
new file mode 100644
index 00000000..0e86d9ba
--- /dev/null
+++ b/dist/rpm/Makefile.am
@@ -0,0 +1,22 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+EXTRA_DIST = \
+ synergy.spec.in \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
diff --git a/dist/rpm/synergy.spec.in b/dist/rpm/synergy.spec.in
new file mode 100644
index 00000000..0d2b6f48
--- /dev/null
+++ b/dist/rpm/synergy.spec.in
@@ -0,0 +1,66 @@
+Summary: Mouse and keyboard sharing utility
+Name: @PACKAGE@
+Version: @VERSION@
+Release: 1
+License: GPL
+Packager: Chris Schoeneman
+Group: System Environment/Daemons
+Prefixes: /usr/bin
+Source: @PACKAGE@-@VERSION@.tar.gz
+Buildroot: /var/tmp/@PACKAGE@-@VERSION@-root
+
+%description
+Synergy lets you easily share a single mouse and keyboard between
+multiple computers with different operating systems, each with its
+own display, without special hardware. It's intended for users
+with multiple computers on their desk since each system uses its
+own display.
+
+%prep
+%setup
+CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr
+
+%build
+make
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT
+strip $RPM_BUILD_ROOT/usr/bin/synergyc
+strip $RPM_BUILD_ROOT/usr/bin/synergys
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-, root, root)
+/usr/bin/synergyc
+/usr/bin/synergys
+%doc AUTHORS
+%doc COPYING
+%doc ChangeLog
+%doc INSTALL
+%doc NEWS
+%doc README
+%doc doc/about.html
+%doc doc/authors.html
+%doc doc/autostart.html
+%doc doc/banner.html
+%doc doc/border.html
+%doc doc/compiling.html
+%doc doc/configuration.html
+%doc doc/contact.html
+%doc doc/developer.html
+%doc doc/faq.html
+%doc doc/history.html
+%doc doc/home.html
+%doc doc/index.html
+%doc doc/license.html
+%doc doc/news.html
+%doc doc/roadmap.html
+%doc doc/running.html
+%doc doc/security.html
+%doc doc/tips.html
+%doc doc/toc.html
+%doc doc/trouble.html
+%doc doc/synergy.css
+%doc examples/synergy.conf
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 00000000..2efec24c
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,49 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+EXTRA_DIST = \
+ PORTING \
+ doxygen.cfg.in \
+ synergy.css \
+ about.html \
+ authors.html \
+ autostart.html \
+ banner.html \
+ border.html \
+ compiling.html \
+ configuration.html \
+ contact.html \
+ developer.html \
+ faq.html \
+ history.html \
+ home.html \
+ index.html \
+ license.html \
+ news.html \
+ roadmap.html \
+ running.html \
+ security.html \
+ tips.html \
+ toc.html \
+ trouble.html \
+ images/logo.gif \
+ images/warp.gif \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ doc/doxygen.cfg \
+ doc/doxygen/html/* \
+ $(NULL)
diff --git a/doc/PORTING b/doc/PORTING
new file mode 100644
index 00000000..4e2744df
--- /dev/null
+++ b/doc/PORTING
@@ -0,0 +1,419 @@
+Synergy Developer and Porting Guide
+===================================
+
+This document is under development.
+
+Code Organization
+-----------------
+
+The synergy source code organization is:
+
+. -- root makefiles, some standard documentation
+cmd -- program source code
+ launcher -- synergy launcher for Windows
+ synergyc -- synergy client
+ synergys -- synergy server
+config -- stuff for autoconf/automake
+dist -- files for creating distributions
+ nullsoft -- files for creating Nullsoft NSIS installer (Windows)
+ rpm -- files for creating RPMs
+doc -- placeholder for documentation
+examples -- example files
+lib -- library source code
+ arch -- platform dependent utility library
+ base -- simple utilities
+ client -- synergy client library
+ common -- commonly needed header files
+ io -- I/O
+ mt -- multithreading
+ net -- networking
+ platform -- platform dependent display/window/event stuff
+ server -- synergy server library
+ synergy -- synergy shared client/server code library
+
+Note how the utility code required by the programs is placed into
+separate library directories. This makes the makefiles a little
+more awkward but makes for a cleaner organization. The top level
+directory has only the standard documentation files and the files
+necessary to configure and build the rest of the project.
+
+
+Coding Style Guide
+------------------
+
+Synergy uses many coding conventions. Contributed code should
+following these guidelines.
+
+- Symbol Naming
+ Names always begin with a letter (never an underscore). The first
+ letter of interior names are always capitalized. Acronyms should
+ be all uppercase. For example: myTextAsASCII.
+
+ Names come it two flavors: leading capital and leading lowercase.
+ The former have the first character capitalized and the latter
+ don't. In the following table, leading capital names are indicated
+ by `Name' and leading lowercase names by `name'.
+
+ The naming convention for various things are:
+
+ * Exceptions -- X + Name XMyException
+ * Interfaces -- I + Name IMyInterface
+ * Template Classes -- T + Name TMyTemplate<>
+ * Other Classes -- C + Name CMyClass
+ * Enumerations -- E + Name EMyEnumeration
+ * Constants -- k + Name kMyConstant
+ * Data Members -- m_ + name m_myDataMember
+ * Methods -- name myMethod
+ * Functions -- name myFunction
+ * Variables -- name myVariable
+
+ Exceptions are types that get thrown and are generally derived
+ (possibly indirectly) from XBase. Interfaces are derived (possibly
+ indirectly) from IInterface and have only pure virtual functions.
+ Other classes are classes that aren't exceptions or interfaces.
+ Constants include global constants and enumerants.
+
+ Method names should usually have the form `verbObject'. For example:
+ * isGameOn()
+ * getBeer()
+ * pressPowerButton()
+ * setChannel()
+ In general, use `get' and `set' to read and write state but use `is'
+ to read boolean state. Note that classes that contain only `is',
+ `get', and `set' are probably plain old data; you might want to
+ consider using public data members only or, better, refactor your
+ design to have classes that actually do something more than just
+ hold data.
+
+- File Naming
+ Each class should have one source and one header file. If the
+ class is named `CMyClass' then the source file should be named
+ `CMyClass.cpp' and the header file `CMyClass.h'.
+
+ Headers files not containing a class should have some meaningful
+ name with a leading capital (e.g. `Version.h').
+
+ Source files without a header file have a leading lowercase name.
+ Only files containing the entry point for an application should
+ lack a header file.
+
+- Dependencies
+ * No circular library dependencies
+ Library dependencies form an acyclic graph. Conceptually
+ libraries can be arranged in layers where each library only
+ references libraries in layers below it, not in the same layer
+ or layers above it. The makefiles build the lowest layer
+ libraries first and work upwards.
+
+ * Avoid circular uses-a relationships
+ When possible, design classes with one-way uses-a relationships
+ and avoid cycles. This makes it easier to understand the code.
+ However, sometimes it's not always practical so it is permitted.
+
+ * Included files in headers
+ Headers should #include only the necessary headers. In
+ particular, if a class is referenced in a header file only as a
+ pointer or a reference then use `class COtherClass;' instead of
+ `#include "COtherClass.h".'
+
+ * #include syntax
+ Non-synergy header files must be included using angle brackets
+ while synergy header files must be included using double quotes.
+ #include "CSynergyHeader.h"
+ #include
+ The file name in a #include must not be a relative path unless
+ it's a system header file and it's customary to use a relative
+ path, e.g. `#include '. Use compiler options to
+ add necessary directories to the include search path.
+
+ * Included file ordering
+ Files should be included in the following order:
+ * Header for source file
+ The first include for CMyClass.cpp must be CMyClass.h.
+ * Other headers in directory, sorted alphabetically
+ * Headers for each library, sorted alphabetically per library
+ Include headers from the library closest in the dependency graph
+ first, then the next farthest, etc. Sort alphabetically within
+ each library.
+ * System headers
+
+- C++
+ * C++ features
+ Synergy uses the following more recent C++ features:
+ * bool
+ * templates
+ * exceptions
+ * mutable
+ * new scoping rules
+ * the standard C++ library
+
+ Do not use the following C++ features:
+ * dynamic_cast
+ * run time type information
+ * namespaces and using (use std:: where necessary)
+
+ The new scoping rules say that the scope of a variable declared
+ in a for statement is limited to the for loop. For example:
+
+ for (int i = 0; i < 10; ++i) {
+ // i is in scope here
+ }
+ // i is not in scope here
+
+ for (int i = -10; i < 0; ++i) {
+ // an entirely new i is in scope here
+ }
+ // i is not in scope here
+
+ This is used routinely in synergy, but only in for loops. There
+ is a macro for `for' in lib/base/common.h when building under
+ Microsoft Visual C++ that works around the fact that that compiler
+ doesn't follow the new scoping rules. Use the macro if your
+ compiler uses the old scoping rules.
+
+ * Standard C++ library
+ The standard C++ library containers should always be used in favor
+ of custom containers wherever reasonable. std::string is used
+ throughout synergy but only as the CString typedef; always use
+ CString, never std::string except in the arch library. Synergy
+ avoids using auto_ptr due to some portability problems. Synergy
+ makes limited use of standard algorithms and streams but they can
+ be freely used in new code.
+
+ * Limited multiple inheritance
+ Classes should inherit implementation from at most one superclass.
+ Inheriting implementation from multiple classes can have unpleasant
+ consequences in C++ due to it's limited capabilities. Classes can
+ inherit from any number of interface classes. An interface class
+ provides only pure virtual methods. Synergy breaks this rule in
+ IInterface which implements the virtual destructor for convenience.
+
+ * No globals
+ Avoid global variables. All global variables must be static, making
+ it visible only with its source file. Most uses of global variables
+ are better served by static data members of a class. Global
+ constants are permitted in some circumstances.
+
+ Also avoid global functions. Use public static member functions in
+ a class instead.
+
+ These rules are violated by the main source file for each program
+ (except that the globals are still static). They could easily be
+ rewritten to put all the variables and functions into a class but
+ there's little to be gained by that.
+
+ * Private data only
+ If a class is plain-old-data (i.e. it has no methods) all of its
+ data members should be public. Otherwise all of its data members
+ should be private, not public or protected. This makes it much
+ easier to track the use of a member when reading code. Protected
+ data is not allowed because `protected' is a synonym for `public
+ to my subclasses' and public data is a Bad Thing. While it might
+ seem okay in this limited situation, the situation is not at all
+ limited since an arbitrary number of classes can be derived,
+ directly or indirectly, from the class and any of those classes
+ have full access to the protected data.
+
+ * Plain old data
+ A class that merely contains data and doesn't perform operations
+ on that data (other than reads and writes) is plain old data (POD).
+ POD should have only public data members and non-copy constructors.
+ It must not have any methods other than constructors, not even a
+ destructor or assignment operators, nor protected or private data.
+ Note that this definition of POD is not the definition used in the
+ C++ standard, which limits the contained data types to types that
+ have no constructors, destructors, or methods.
+
+ * Avoid using friend
+ Avoid declaring friend functions or classes. They're sometimes
+ necessary for operator overloading. If you find it necessary to
+ add friends to some class C, consider creating a utility class U.
+ A utility class is declared as the only friend of C and provides
+ only static methods. Each method forwards to a private method on
+ an object of C type (passed as a parameter to the U's method).
+ This makes maintenance easier since only U has friend access to C
+ and finding any call to U is trivial (they're prefixed by U::).
+
+ * Don't test for NULL when using `delete' or `delete[]'
+ It's unnecessary since delete does it anyway.
+
+- Makefiles
+ Automake's makefiles (named Makefile.am) have a few requirements:
+ * Define the following macro at the top of the file:
+ NULL =
+ * Lists should have one item per line and end in $(NULL). For
+ example:
+ EXTRA_DIST = \
+ kiwi.txt \
+ mango.cpp \
+ papaya.h \
+ $(NULL)
+ Indentation must use tabs in a makefile. Line continuations
+ (backslashes) should be aligned using tabs.
+ * Lists of files should be sorted alphabetically in groups (e..g
+ source files, header files, then other files). Lists of
+ subdirectories must be in the desired build order.
+
+- Source Formatting
+ Every project has its own formatting style and no style satisfies
+ everyone. New code should be consistent with existing code:
+
+ * All files should include the copyright and license notice
+ * Use tabs to indent
+ * Tabs are 4 columns
+ * Lines should not extend past the 80th column
+ * Open braces ({) go on same line as introducing statement
+ `for (i = 0; i < 10; ++i) {' not
+ for (i = 0; i < 10; ++i)
+ {
+ * Close braces line up with introducing statement
+ * Open brace for function is on a line by itself in first column
+ * Close brace for function lines up with open brace
+ * Always use braces on: if, else, for, while, do, switch
+ * `else {' goes on its own line
+ * Always explicitly test pointers against NULL
+ e.g. `if (ptr == NULL)' not `if (ptr)'
+ * Always explicitly test integral values against 0
+ e.g. `if (i == 0)' not `if (i)'
+ * Put spaces around binary operators and after statements
+ e.g. `if (a == b) {' not `if(a==b){'
+ * C'tor initializers are one per line, indented one tab stop
+ * Other indentation should follow existing practice
+ * Use Qt style comments for extraction by doxygen (i.e. //! and /*!)
+ * Mark incomplete or buggy code with `FIXME'
+
+- Other
+ * calls to LOG() should always be all on one line (even past column 80)
+
+
+Class Relationships
+-------------------
+
+The doxygen documentation can help in understanding the relationships
+between objects. Use `make doxygen' in the top level directory to
+create the doxygen documentation into doc/doxygen/html. You must have
+doxygen installed, of course.
+
+FIXME -- high level overview of class relationships
+
+
+Portability
+-----------
+
+Synergy is mostly platform independent code but necessarily has
+platform dependent parts. The mundane platform dependent parts
+come from the usual suspects: networking, multithreading, file
+system, high resolution clocks, system logging, etc. Porting
+these parts is relatively straightforward.
+
+Synergy also has more esoteric platform dependent code. The
+functions for low-level event interception and insertion,
+warping the cursor position, character to keyboard event
+translation, clipboard manipulation, and screen saver control
+are often obscure and poorly documented. Unfortunately, these
+are exactly the functions synergy requires to do its magic.
+
+Porting synergy to a new platform requires the following steps:
+
+- Setting up the build
+- Adjusting lib/common/common.h
+- Implementing lib/arch
+- Implementing lib/platform
+- Tweaks
+
+Setting up the build:
+
+The first phase is simply to create the files necessary to build the
+other files. On Unix, synergy uses autoconf/automake which produces
+a `configure' script that generates makefiles. On Windows, synergy
+uses Visual C++ workspace and project files. If you're porting to
+another Unix variant, you may need to adjust `configure.in',
+`acinclude.m4', and Unix flavor dependent code in lib/arch. Note
+especially the SYSAPI_* and WINAPI_* macro definitions in
+ARCH_CFLAGS. Exactly one of each must be defined. It should also
+add AM_CONDITIONALs if a new SYSAPI_* or WINAPI_* was added.
+
+Adjusting lib/common/common.h:
+
+The lib/common/common.h header file is included directly or indirectly
+by every other file. Its primary job is to include config.h, which
+defines macros depending on what the 'configure' script discovered
+about the system. If the platform does not use the 'configure' script
+it must define the appropriate SYSAPI_* and WINAPI_* macro. It may
+also do other platform specific setup.
+
+Adjusting lib/common/BasicTypes.h:
+
+No changes should be necessary in BasicTypes.h. However, if the
+platform's system header files define SInt8, et al. you may need
+to adjust the typedefs to match the system's definitions.
+
+Implementing lib/arch:
+
+Much platform dependent code lives in lib/arch. There are several
+interface classes there and they must all be implemented for each
+platform. See the interface header files for more information.
+
+Platforms requiring special functions should create a class named
+CArchMiscXXX where XXX is the platform name. The class should have
+only static methods. Clients can include the appropriate header
+file and make calls directly, surrounded by a suitable #ifdef/#endif.
+
+If using automake, the Makefile.am should list the system specific
+files in a XXX_SOURCE_FILES macro where XXX matches the appropriate
+AM_CONDITIONAL symbol. XXX_SOURCE_FILES must be added to EXTRA_DIST
+and the following added above the INCLUDES macro:
+
+ if XXX
+ libarch_a_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(XXX_SOURCE_FILES) \
+ $(NULL)
+ endif
+
+Implementing lib/platform:
+
+Most of the remaining platform dependent code lives in lib/platform.
+The code there implements platform dependent window, clipboard, keyboard
+and screen saver handling. If a platform is named XXX then the following
+classes should be derived and implemented:
+
+ * CXXXClipboard : IClipboard
+ Provides clipboard operations. Typically, this class will
+ have helper classes for converting between various clipboard
+ data formats.
+
+ * CXXXEventQueueBuffer : IEventQueueBuffer
+ Provides operations for waiting for, posting and retrieving events.
+ Also provides operations for creating and deleting timers.
+
+ * CXXXKeyState : CKeyState
+ Provides operations for synthesizing key events and for mapping a
+ key ID to a sequence of events to generate that key.
+
+ * CXXXScreen : IScreen, IPrimaryScreen, ISecondaryScreen, IPlatformScreen
+ Provides screen operations.
+
+ * CXXXScreenSaver : IScreenSaver
+ Provides screen saver operations.
+
+If using automake, the Makefile.am should list the window system
+specific files in a XXX_SOURCE_FILES macro where XXX matches the
+appropriate AM_CONDITIONAL symbol. XXX_SOURCE_FILES must be added
+to EXTRA_DIST and the following added above the INCLUDES macro:
+
+ if XXX
+ libplatform_a_SOURCES = $(XXX_SOURCE_FILES)
+ endif
+
+Tweaks:
+
+Finally, each platform typically requires various adjustments here
+and there. In particular, synergyc.cpp and synergys.cpp usually
+require platform dependent code for the main entry point, parsing
+arguments, and reporting errors. Also, some platforms may benefit
+from a graphical user interface front end. These are generally
+not portable and synergy doesn't provide any infrastructure for
+the code common to any platform, though it may do so someday.
+There is, however, an implementation of a GUI front end for Windows
+that serves as an example.
diff --git a/doc/about.html b/doc/about.html
new file mode 100644
index 00000000..aadd5764
--- /dev/null
+++ b/doc/about.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+ About Synergy
+
+
+
+With synergy, all the computers on your desktop form a single virtual
+screen. You use the mouse and keyboard of only one of the computers
+while you use all of the monitors on all of the computers.
+You tell synergy how many screens you have and their positions relative
+to one another. Synergy then detects when the mouse moves off
+the edge of a screen and jumps it instantly to the neighboring screen.
+The keyboard works normally on each screen; input goes to whichever
+screen has the cursor.
+
+In this example, the user is moving the mouse from left to right.
+When the cursor reaches the right edge of the left screen it jumps
+instantly to the left edge of the right screen.
+
+
+
+You can arrange screens side-by-side, above and below one another,
+or any combination. You can even have a screen jump to the opposite
+edge of itself. Synergy also understands multiple screens attached
+to the same computer.
+
+Running a game and don't want synergy to jump screens? No problem.
+Just toggle Scroll Lock. Synergy keeps the cursor on the same screen
+when Scroll Lock is on. (This can be configured to another hot key.)
+
+Do you wish you could cut and paste between computers? Now you can!
+Just copy text, HTML, or an image as you normally would on one screen
+then switch to another screen and paste it. It's as if all your
+computers shared a single clipboard (and separate primary selection for
+you X11 users). It even converts newlines to each computer's native
+form so cut and paste between different operating systems works
+seamlessly. And it does it all in Unicode so any text can be copied.
+
+
+Do you use a screen saver? With synergy all your screen savers act in
+concert. When one starts they all start. When one stops they all
+stop. And, if you require a password to unlock the screen, you'll
+only have to enter a password on one screen.
+
+If you regularly use multiple computers on one desk, give synergy a
+try. You'll wonder how you ever lived without it.
+
+You can configure synergy to start automatically when the computer
+starts or when you log in. The steps to do that are different on
+each platform. Note that changing these configurations doesn't
+actually start or stop synergy. The changes take effect the next
+time you start your computer or log in.
+
+
Windows
+
+Start synergy and click the Configure... button
+by the text Automatic Startup. The
+Auto Start dialog will pop up.
+If an error occurs then correct the problem and click
+Configure again.
+
+On the Auto Start dialog you'll configure
+synergy to start or not start automatically when the computer starts
+or when you log in. You need Administrator access rights to start
+synergy automatically when the computer starts. The dialog will let
+you know if you have sufficient permission.
+
+If synergy is already configured to automatically start then there
+will be two Uninstall buttons, at most one
+of which is enabled. Click the enabled button, if any, to tell
+synergy to not start automatically.
+
+If synergy is not configured to start automatically then there will
+be two Install buttons. If you have
+sufficient permission to have synergy start automatically when the
+computer does then the Install button in the
+When Computer Starts box will be enabled.
+Click it to have synergy start for all users when the computer starts.
+In this case, synergy will be available during the login screen.
+Otherwise, click the Install button in the
+When You Log In box to have synergy
+automatically start when you log in.
+
+
Unix
+
+Synergy requires an X server. That means a server must be
+running and synergy must be authorized to connect to that server.
+It's best to have the display manager start synergy. You'll need
+the necessary (probably root) permission to modify the display
+manager configuration files. If you don't have that permission
+you can start synergy after logging in via the
+.xsession file.
+
+Typically, you need to edit three script files. The first file
+will start synergy before a user logs in, the second will kill
+that copy of synergy, and the third will start it again after
+the user logs in.
+
+The contents of the scripts varies greatly between systems so
+there's no one definite place where you should insert your edits.
+However, these scripts often exit before reaching the bottom so
+put the edits near the top of the script.
+
+The location and names of these files depend on the operating
+system and display manager you're using. A good guess for the
+location is /etc/X11. If you use kdm
+then try looking in /etc/kde3 or
+/usr/kde/version/share/config.
+Typical file names are:
+
+
+
+
xdm
kdm
gdm
+
1
xdm/Xsetup
kdm/Xsetup
gdm/Init/Default (*)
+
2
xdm/Xstartup
kdm/Xstartup
gdm/PostLogin/Default (*)
+
3
xdm/Xsession
kdm/Xsession
gdm/Sessions/Default (*, **)
+
+
+
+*) The Default file is used if no other
+suitable file is found. gdm will try
+displayname (e.g. :0)
+and hostname (e.g. somehost),
+in that order, before and instead of Default.
+
+**) gdm may use gdm/Xsession,
+xdm/Xsession or
+dm/Xsession if
+gdm/Sessions/Default doesn't exist.
+
+For a synergy client, add the following to the first file:
+
+ /usr/bin/killall synergyc
+ sleep 1
+ /usr/bin/synergyc [<options>] synergy-server-hostname
+
+Of course, the path to synergyc depends on where you installed it
+so adjust as necessary.
+
+Add to the second file:
+
+ /usr/bin/killall synergyc
+ sleep 1
+
+
+And to the third file:
+
+ /usr/bin/killall synergyc
+ sleep 1
+ /usr/bin/synergyc [<options>]synergy-server-hostname
+
+Note that <options>
+must not include
+-f or --no-daemon or
+the script will never exit and you won't be able to log in.
+
+The changes are the same for the synergy server except replace
+synergyc with synergys
+and use the appropriate synergys command
+line options. Note that the
+first script is run as root so synergys will look for the configuration
+file in root's home directory then in /etc.
+Make sure it exists in one of those places or use the
+--config config-pathname
+option to specify its location.
+
+Note that some display managers (xdm and kdm, but not gdm) grab
+the keyboard and do not release it until the user logs in for
+security reasons. This prevents a synergy server from sharing
+the mouse and keyboard until the user logs in. It doesn't
+prevent a synergy client from synthesizing mouse and keyboard
+input, though.
+
+If you're configuring synergy to start only after you log in then edit
+your .xsession file. Add just what you
+would add to the third file above.
+
+
Mac OS X
+
+[By Tor Slettnes]
+
+There are three different ways to automatically start Synergy
+(client or server) on Mac OS X:
+
+
+
+ The first method involves creating a StartupItem
+ at the system level, which is executed when the machine starts up
+ or shuts down. This script will run in the background, and
+ relaunch synergy as needed.
+
+
+
Pros:
+
+ Synergy is persistent, so this allows for a multi-user
+ setup and interactive logins.
+
+
Cons:
+
+ The synergy process does not have access to the clipboard
+ of the logged-in user.
+
+
+
+
+
+ The second method will launch Synergy from the
+ LoginWindow application, once a particular
+ user has logged in.
+
+
+
Pros:
+
+ The synergy process inherits the
+ $SECURITYSESSIONID environment variable,
+ and therefore copy/paste works.
+
+
Cons:
+
+ Once the user logs out, synergy dies, and no remote
+ control is possible.
+
+
+
+
+
+ The third method is to launch a startup script from the
+ "Startup Items" tab under System Preferences -> Accounts.
+
+
+
Pros:
+
+ Does not require root (Administrator) access
+
+
Cons:
+
+ Once the user logs out, synergy dies, and no remote
+ control is possible.
+
+
+
+
+
+The text below describes how to implement a Synergy client using
+the first two methods simultaneously. This way, Synergy is
+always running, and the clipboard is available when someone is
+logged in. A Mac OS X Synergy server setup will be quite similar.
+
+1. Create a System Level Startup Item
+
+
+
+ Open a Terminal window, and become root:
+
+ $ sudo su -
+
+
+
+ Create a folder for this item:
+
+ # mkdir -p /Library/StartupItems/Synergy
+
+
+
+ In this folder, create a new script file by the same name as
+ the directory itself, Synergy. This script
+ should contain the following text:
+
+ However, replace synergy-server with the actual
+ name or IP address of your Synergy server.
+
+ Note that this scripts takes care not to start
+ Synergy if another instance is currently running. This
+ allows it to run in the background even when synergy is also
+ started independently, e.g. from the LoginWindow
+ application as described below.
+
+
+ Make this script executable:
+
+ # chmod 755 /Library/StartupItems/Synergy/Synergy
+
+
+
+ In the same folder, create a file named
+ StartupParameters.plist containing:
+
+Any errors, as well as output from Synergy, will be shown in
+your terminal window.
+
+Next time you reboot, Synergy should start automatically.
+
+2. Run Synergy When a User Logs In
+
+Each time a user successfully logs in via the console, the
+LoginWindow application creates a unique session
+cookie and stores it in the environment variable
+$SECURITYSESSIONID. For copy and paste operations
+to work, Synergy needs access to this environment variable. In
+other words, Synergy needs to be launched (directly or
+indirectly) via the LoginWindow application.
+
+However, in order to kill any synergy processes started at the
+system level (as described above), we need root access. Thus,
+launching Synergy within the User's environment (e.g. via the
+Startup Items tab in System Preferences -> Accounts) is not an
+option that work in conjunction with the method above.
+
+Fortunately, the LoginWindow application provides
+a "hook" for running a custom program (as root, with the username provided as
+the first and only argument) once a user has authenticated, but
+before the user is logged in.
+
+Unfortunately, only one such hook is available. If you have
+already installed a Login Hook, you may need to add the text
+from below to your existing script, rather than creating a new
+one.
+
+
+
+ Launch a Terminal window, and become root:
+
+ $ sudo su -
+
+
+
+
+ Find out if a LoginHook already exists:
+
+ # defaults read com.apple.loginwindow LoginHook
+
+ This will either show the full path to a script or
+ executable file, or the text:
+
+ The domain/default pair of (com.apple.loginwindow, LoginHook) does not exist
+
+ In the former case, you need to modify your existing script,
+ and/or create a "superscript" which in turn calls your
+ existing script plus the one we will create here.
+
+ The rest of this text assumes that this item did not already
+ exist, and that we will create a new script.
+
+
+ Create a folder in which we will store our custom startup
+ script:
+
+ # mkdir -p /Library/LoginWindow
+
+
+
+ In this folder, create a new script file (let's name it
+ LoginHook.sh), containing the following text:
+
+
+#!/bin/sh
+prog=(/usr/local/bin/synergyc -n $(hostname -s) ip-address-of-server)
+
+### Stop any currently running Synergy client
+killall ${prog[0]##*/}
+
+### Start the new client
+exec "${prog[@]}"
+
+
+
+ Make this script executable:
+
+ # chmod 755 /Library/LoginWindow/LoginHook.sh
+
+
+
+ Create a login hook to call the script you just created:
+
+ # defaults write com.apple.loginwindow LoginHook /Library/LoginWindow/LoginHook.sh
+
+
+
+
+More information on setting up login hooks can be found at
+Apple.
+
+When running the Synergy client, you may need to use the IP
+address of the Synergy server rather than its host name.
+Specifically, unless you have listed the server in your
+local /etc/hosts file or in your local NetInfo
+database, name services (i.e. DNS) may not yet be available by the
+time you log in after power-up. synergyc will
+quit if it cannot resolve the server name.
+
+(This is not an issue with the previous method, because the
+StartupParameters.plist file specifies that this
+script should not be run until "network" is available).
+
+3. Good Luck!
+
+Remember to look in your system log on both your server and your
+client(s) for clues to any problems you may have
+(/var/log/system.log on your OS X box, typically
+/var/log/syslog on Linux boxes).
+
+so synergy can find the X11 includes and libraries.
+
+
Building
+
+
Windows
+
+ Open a command prompt window (cmd.exe or command.exe). If necessary
+ run vcvars.bat, created when VC++ or Visual Studio was installed. (Use
+ search to find it.) It's necessary to run the file if you didn't have
+ the installer set up environment variables for you. Then enter:
+
+ nmake /nologo /f Makefile.win
+
+ This will build the programs into build\Release.
+
+
Unix or Mac OS X
+
+ Simply enter:
+
+ make
+
+ This will build the client and server and leave them in their
+ respective source directories.
+
+
+
+
Installing
+
+
Windows
+
+ You'll need NSIS,
+ the Nullsoft Scriptable Install System. As in the building on Windows
+ description above, enter:
+
+ nmake /nologo /f Makefile.win installer
+
+ to build build\Release\SynergyInstaller.exe. Run
+ this to install synergy.
+
+ Alternatively, you can simply copy the following files from the
+ build\Release
+ directory to a directory you choose (perhaps under the
+ Program Files directory):
+
+
synergy.exe
+
synergyc.exe
+
synergys.exe
+
synrgyhk.dll
+
+
+
Unix or Mac OS X
+
+
+ make install
+
+ will install the client and server into
+ /usr/local/bin unless you
+ specified a different directory when you ran configure.
+
+
+
+
diff --git a/doc/configuration.html b/doc/configuration.html
new file mode 100644
index 00000000..6c1c8baa
--- /dev/null
+++ b/doc/configuration.html
@@ -0,0 +1,686 @@
+
+
+
+
+
+
+
+ Synergy Configuration Guide
+
+
+
+
Synergy Configuration File Format
+
+The synergy server requires configuration. It will try certain
+pathnames to load the configuration file if you don't specify a
+path using the --config command line
+option. synergys --help reports those
+pathnames.
+
+The configuration file is a plain text file. Use any text editor
+to create the configuration file. The file is broken into sections
+and each section has the form:
+
+ section: name
+ args
+ end
+
+Comments are introduced by # and continue to
+the end of the line. name must be one of the
+following:
+
+
screens
+
aliases
+
links
+
options
+
+See below for further explanation of each section type. The
+configuration file is case-sensitive so Section,
+SECTION, and section
+are all different and only the last is valid. Screen names are the
+exception; screen names are case-insensitive.
+
+The file is parsed top to bottom and names cannot be used before
+they've been defined in the screens or
+aliases sections. So the
+links and aliases
+must appear after the screens and links
+cannot refer to aliases unless the aliases
+appear before the links.
+
+
screens
+
+args is a list of screen names, one name per
+line, each followed by a colon. Names are arbitrary strings but they
+must be unique. The hostname of each computer is recommended. (This
+is the computer's network name on win32 and the name reported by the
+program hostname on Unix and OS X. Note
+that OS X may append .local to the name you
+gave your computer; e.g. somehost.local.)
+There must be a screen name for the server and each client. Each
+screen can specify a number of options. Options have the form
+name =
+value and are listed one per line
+after the screen name.
+
+Example:
+
+ section: screens
+ moe:
+ larry:
+ halfDuplexCapsLock = true
+ halfDuplexNumLock = true
+ curly:
+ meta = alt
+ end
+
+This declares three screens named moe,
+larry, and curly.
+Screen larry has half-duplex Caps Lock and
+Num Lock keys (see below) and screen curly
+converts the meta modifier key to the alt modifier key.
+
+A screen can have the following options:
+
+
halfDuplexCapsLock = {true|false}
+
+ This computer has a Caps Lock key that doesn't report a
+ press and a release event when the user presses it but
+ instead reports a press event when it's turned on and a
+ release event when it's turned off. If Caps Lock acts
+ strangely on all screens then you may need to set this
+ option to true
+ on the server screen. If it acts strangely on one
+ screen then that screen may need the option set to
+ true.
+
+
halfDuplexNumLock = {true|false}
+
+ This is identical to halfDuplexCapsLock
+ except it applies to the Num Lock key.
+
+
halfDuplexScrollLock = {true|false}
+
+ This is identical to halfDuplexCapsLock
+ except it applies to the Scroll Lock key. Note that, by default,
+ synergy uses Scroll Lock to keep the cursor on the current screen. That
+ is, when Scroll Lock is toggled on, the cursor is locked to the screen
+ that it's currently on. You can use that to prevent accidental switching.
+ You can also configure other hot keys to do that; see
+ lockCursorToScreen.
+
+ This option works around a bug in the XTest extension
+ when used in combination with Xinerama. It affects
+ X11 clients only. Not all versions of the XTest
+ extension are aware of the Xinerama extension. As a
+ result, they do not move the mouse correctly when
+ using multiple Xinerama screens. This option is
+ currently true by default. If
+ you know your XTest extension is Xinerama aware then set
+ this option to false.
+
+
shift = {shift|ctrl|alt|meta|super|none}
+ ctrl = {shift|ctrl|alt|meta|super|none}
+ alt = {shift|ctrl|alt|meta|super|none}
+ meta = {shift|ctrl|alt|meta|super|none}
+ super = {shift|ctrl|alt|meta|super|none}
+
+ Map a modifier key pressed on the server's keyboard to
+ a different modifier on this client. This option only
+ has an effect on a client screen; it's accepted and
+ ignored on the server screen.
+
+ You can map, say, the shift key to shift (the default),
+ ctrl, alt, meta, super or nothing. Normally, you
+ wouldn't remap shift or ctrl. You might, however, have
+ an X11 server with meta bound to the Alt keys. To use
+ this server effectively with a windows client, which
+ doesn't use meta but uses alt extensively, you'll want
+ the windows client to map meta to alt (using
+ meta = alt).
+
+
+
+
aliases
+
+ args is a list of screen names just like
+ in the screens section except each screen
+ is followed by a list of aliases, one per line, not followed
+ by a colon. An alias is a screen name and must be unique. During
+ screen name lookup each alias is equivalent to the screen name it
+ aliases. So a client can connect using its canonical screen name
+ or any of its aliases.
+
+ Example:
+
+ section: aliases
+ larry:
+ larry.stooges.com
+ curly:
+ shemp
+ end
+
+ Screen larry is also known as
+ larry.stooges.com and can connect as
+ either name. Screen curly is also
+ known as shemp (hey, it's just an example).
+
+
links
+
+ args is a list of screen names just like
+ in the screens section except each screen
+ is followed by a list of links, one per line. Each link has the
+ form {left|right|up|down}[<range>] =
+ name[<range>]. A link indicates which
+ screen is adjacent in the given direction.
+
+ Each side of a link can specify a range which defines a portion
+ of an edge. A range on the direction is the portion of edge you can
+ leave from while a range on the screen is the portion of edge you'll
+ enter into. Ranges are optional and default to the entire edge. All
+ ranges on a particular direction of a particular screen must not
+ overlap.
+
+ A <range> is written as (<start>,<end>).
+ Both start and end
+ are percentages in the range 0 to 100, inclusive. The start must be
+ less than the end. 0 is the left or top of an edge and 100 is the
+ right or bottom.
+
+ Example:
+
+ section: links
+ moe:
+ right = larry
+ up(50,100) = curly(0,50)
+ larry:
+ left = moe
+ up(0,50) = curly(50,100)
+ curly:
+ down(0,50) = moe
+ down(50,100) = larry(0,50)
+ end
+
+ This indicates that screen larry is to
+ the right of screen moe (so moving the
+ cursor off the right edge of moe would
+ make it appear at the left edge of larry),
+ the left half of
+ curly is above the right half of
+ moe,
+ moe is to the left of
+ larry (edges are not necessarily symmetric
+ so you have to provide both directions), the right half of
+ curly is above the left half of
+ larry, all of moe
+ is below the left half of curly, and the
+ left half of larry is below the right half of
+ curly.
+
+ Note that links do not have to be
+ symmetrical; for instance, here the edge between
+ moe and curly
+ maps to different ranges depending on if you're going up or down.
+ In fact links don't have to be bidirectional. You can configure
+ the right of moe to go to
+ larry without a link from the left of
+ larry to moe.
+ It's possible to configure a screen with no outgoing links; the
+ cursor will get stuck on that screen unless you have a hot key
+ configured to switch off of that screen.
+
+
options
+
+ args is a list of lines of the form
+ name = value. These set the global
+ options.
+
+ The server will expect each client to send a message no
+ less than every N milliseconds.
+ If no message arrives from a client within
+ 3N seconds the server forces that
+ client to disconnect.
+
+ If synergy fails to detect clients disconnecting while
+ the server is sleeping or vice versa, try using this
+ option.
+
+
switchCorners = <corners>
+
+ Synergy won't switch screens when the mouse reaches the edge of
+ the screen if it's in a listed corner. The size of all corners
+ is given by the switchCornerSize
+ option.
+
+ Corners are specified by a list using the following names:
+
+
none -- no corners
+
top-left -- the top left corner
+
top-right -- the top right corner
+
bottom-left -- the bottom left corner
+
bottom-right -- the bottom right corner
+
left -- top and bottom left corners
+
right -- top and bottom right corners
+
top -- left and right top corners
+
bottom -- left and right bottom corners
+
all -- all corners
+
+
+ The first name in the list is one of the above names and defines
+ the initial set of corners. Subsequent names are prefixed with
+ + or - to add the corner to or remove the corner from the set,
+ respectively. For example:
+
+
+ all -left +top-left
+
+
+ starts will all corners, removes the left corners (top and bottom)
+ then adds the top-left back in, resulting in the top-left,
+ bottom-left and bottom-right corners.
+
+
switchCornerSize = N
+
+ Sets the size of all corners in pixels. The cursor must be within
+ N pixels of the corner to be considered
+ to be in the corner.
+
+
switchDelay = N
+
+ Synergy won't switch screens when the mouse reaches the
+ edge of a screen unless it stays on the edge for
+ N
+ milliseconds. This helps prevent unintentional
+ switching when working near the edge of a screen.
+
+
switchDoubleTap = N
+
+ Synergy won't switch screens when the mouse reaches the
+ edge of a screen unless it's moved away from the edge
+ and then back to the edge within N
+ milliseconds. With
+ the option you have to quickly tap the edge twice to
+ switch. This helps prevent unintentional switching
+ when working near the edge of a screen.
+
+
screenSaverSync = {true|false}
+
+ If set to false then synergy
+ won't synchronize screen savers. Client screen savers
+ will start according to their individual configurations.
+ The server screen saver won't start if there is input,
+ even if that input is directed toward a client screen.
+
+
relativeMouseMoves = {true|false}
+
+ If set to true then secondary
+ screens move the mouse using relative rather than absolute
+ mouse moves when and only when the cursor is locked to the
+ screen (by Scroll Lock or a configured
+ hot key).
+ This is intended to make synergy work better with certain
+ games. If set to false or not
+ set then all mouse moves are absolute.
+
+
keystroke(key) = actions
+
+ Binds the key combination key to the
+ given actions. key
+ is an optional list of modifiers (shift,
+ control, alt,
+ meta or super)
+ optionally followed by a character or a key name, all separated by
+ + (plus signs). You must have either
+ modifiers or a character/key name or both. See below for
+ valid key names.
+
+ Keyboard hot keys are handled while the cursor is on the primary
+ screen and secondary screens. Separate actions can be assigned
+ to press and release.
+
+
mousebutton(button) = actions
+
+ Binds the modifier and mouse button combination
+ button to the given
+ actions. button
+ is an optional list of modifiers (shift,
+ control, alt,
+ meta or super)
+ followed by a button number. The primary button (the
+ left button for right handed users) is button 1, the middle button
+ is 2, etc.
+
+ Mouse button actions are not handled while the cursor is on the
+ primary screen. You cannot use these to perform an action while
+ on the primary screen. Separate actions can be assigned to press
+ and release.
+
+
+ You can use both the switchDelay and
+ switchDoubleTap options at the same
+ time. Synergy will switch when either requirement is satisfied.
+
+Actions are two lists of individual actions separated
+by commas. The two lists are separated by a semicolon. Either list can be
+empty and if the second list is empty then the semicolon is optional. The
+first list lists actions to take when the condition becomes true (e.g. the
+hot key or mouse button is pressed) and the second lists actions to take
+when the condition becomes false (e.g. the hot key or button is released).
+The condition becoming true is called activation and becoming false is
+called deactivation.
+Allowed individual actions are:
+
+
keystroke(key[,screens])
+
keyDown(key[,screens])
+
keyUp(key[,screens])
+
+ Synthesizes the modifiers and key given in key
+ which has the same form as described in the
+ keystroke option. If given,
+ screens lists the screen or screens to
+ direct the event to, regardless of the active screen. If not
+ given then the event is directed to the active screen only.
+ (Due to a bug, keys cannot be directed to the server while on a
+ client screen.)
+
+ keyDown synthesizes a key press and
+ keyUp synthesizes a key release.
+ keystroke synthesizes a key press on
+ activation and a release on deactivation and is equivalent to
+ a keyDown on activation and
+ keyUp on deactivation.
+
+ screens is either *
+ to indicate all screens or a colon (:) separated list of screen
+ names. (Note that the screen name must have already been encountered
+ in the configuration file so you'll probably want to put actions at
+ the bottom of the file.)
+
+
mousebutton(button)
+
mouseDown(button)
+
mouseUp(button)
+
+ Synthesizes the modifiers and mouse button given in
+ button
+ which has the same form as described in the
+ mousebutton option.
+
+ mouseDown synthesizes a mouse press and
+ mouseUp synthesizes a mouse release.
+ mousebutton synthesizes a mouse press on
+ activation and a release on deactivation and is equivalent to
+ a mouseDown on activation and
+ mouseUp on deactivation.
+
+
lockCursorToScreen(mode)
+
+ Locks the cursor to or unlocks the cursor from the active screen.
+ mode can be off
+ to unlock the cursor, on to lock the
+ cursor, or toggle to toggle the current
+ state. The default is toggle. If the
+ configuration has no lockCursorToScreen
+ action and Scroll Lock is not used as a hot key then Scroll Lock
+ toggles cursor locking.
+
+
switchToScreen(screen)
+
+ Jump to screen with name or alias screen.
+
+
switchInDirection(dir)
+
+ Switch to the screen in the direction dir,
+ which may be one of left,
+ right, up or
+ down.
+
+
keyboardBroadcast(mode[,screens])
+
+ Turns broadcasting of keystrokes to multiple screens on and off. When
+ turned on all key presses and releases are sent to all of the screens
+ listed in screens. If not given, empty or
+ * then keystrokes are broadcast to all screens.
+ (However, due to a bug, keys cannot be sent to the server while on a
+ client screen.)
+
+ mode can be off
+ to turn broadcasting off, on to turn it
+ on, or toggle to toggle the current
+ state. The default is toggle.
+
+ screens is either *
+ to indicate all screens or a colon (:) separated list of screen
+ names. (Note that the screen name must have already been encountered
+ in the configuration file so you'll probably want to put actions at
+ the bottom of the file.)
+
+ Multiple keyboardBroadcast actions may be
+ configured with different screens. The most
+ recently performed action defines the screens to broadcast to.
+
+
+
+Examples:
+
+
keystroke(alt+left) = switchInDirection(left)
+
+ Switches to the screen to left when the left arrow key is pressed
+ in combination with the Alt key.
+
+Additionally, a name of the form \uXXXX where
+XXXX is a hexadecimal number is interpreted as
+a unicode character code.
+Key and modifier names are case-insensitive. Keys that don't exist on
+the keyboard or in the default keyboard layout will not work.
+
+To avoid spam bots, the above email addresses have ".no_spam"
+hidden near the end. If you copy and paste the text be sure to
+remove it.
+
+Please check the
+
+bug list before reporting a bug. You may also find answers at the
+synergy forums.
+Emails for help asking questions answered on this site will go unanswered.
+
+Synergy is reasonably well commented so reading the source code
+should be enough to understand particular pieces. See the
+doc/PORTING
+file in the synergy source code for more high-level information.
+
+
How it works
+
+The theory behind synergy is simple: the server captures mouse,
+keyboard, clipboard, and screen saver events and forwards them to
+one or more clients. If input is directed to the server itself
+then the input is delivered normally. In practice, however, many
+complications arise.
+
+First, different keyboard mappings can produce different characters.
+Synergy attempts to generate the same character on the client as
+would've been generated on the server, including appropriate modifier
+keys (like Control and Alt). Non-character keys like Shift are also
+synthesized if possible. Sometimes the client simply cannot create
+the character or doesn't have a corresponding non-character key and
+synergy must discard the event. Note that synergy won't necessarily
+synthesize an event for the corresponding key on the client's
+keyboard. For example, if the client or server can't distinguish
+between the left and right shift keys then synergy can't be certain
+to synthesize the shift on the same side of the keyboard as the user
+pressed.
+
+Second, different systems have different clipboards and clipboard
+formats. The X window system has a system-wide selection and
+clipboard (and yet other buffers) while Microsoft Windows has only
+a system-wide clipboard. Synergy has to choose which of these
+buffers correspond to one another. Furthermore, different systems
+use different text encodings and line breaks. Synergy mediates and
+converts between them.
+
+Finally, there are no standards across operating systems for some
+operations that synergy requires. Among these are: intercepting
+and synthesizing events; enabling, disabling, starting and stopping
+the screen saver; detecting when the screen saver starts; reading
+and writing the clipboard(s).
+
+All this means that synergy must be customized to each operating
+system (or windowing system in the case of X windows). Synergy
+breaks platform differences into two groups. The first includes
+the mundane platform dependent things: file system stuff,
+multithreading, network I/O, multi-byte and wide character
+conversion, time and sleeping, message display and logging, and
+running a process detached from a terminal. This code lives in
+lib/arch.
+
+The second includes screen and window management handling, user
+event handling, event synthesis, the clipboards, and the screen
+saver. This code lives in lib/platform.
+
+For both groups, there are particular classes or interfaces that
+must be inherited and implemented for each platform. See the
+doc/PORTING file in the synergy source
+code for more information.
+
+
Auto-generated Documentation
+
+Synergy can automatically generate documentation from the comments
+in the code using doxygen.
+Use make doxygen to build it yourself
+from the source code into the doc/doxygen/html
+directory.
+
+
+
+
+
diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
new file mode 100644
index 00000000..4abf52f9
--- /dev/null
+++ b/doc/doxygen.cfg.in
@@ -0,0 +1,898 @@
+# Doxyfile 1.2.13.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = @PACKAGE@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc/doxygen
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French,
+# German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish,
+# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT =
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = .
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl
+
+FILE_PATTERNS = *.cpp *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command , where
+# is the value of the INPUT_FILTER tag, and is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse.
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 3
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT =
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT =
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT =
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT =
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION =
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line and do not end with a semicolon. Such function macros are typically
+# used for boiler-plate code, and will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = @HAVE_DOT@
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+CGI_NAME =
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+BIN_ABSPATH =
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS =
diff --git a/doc/faq.html b/doc/faq.html
new file mode 100644
index 00000000..b9696391
--- /dev/null
+++ b/doc/faq.html
@@ -0,0 +1,266 @@
+
+
+
+
+
+
+
+ Synergy Frequently Asked Questions
+
+
+
+
Why doesn't ctrl+alt+del work on secondary screens?
+
+ Synergy isn't able to capture ctrl+alt+del on PC compatible
+ primary screens because it's handled completely differently than
+ other keystrokes. However, when the mouse is on a client
+ screen, pressing ctrl+alt+pause will simulate ctrl+alt+del
+ on the client. (A client running on Windows NT, 2000, or XP
+ must be configured to autostart when the computer starts for
+ this to work.)
+
+ On a primary screen running on an OS X system, you can use
+ ctrl+command+del. Using the pause key isn't necessary since OS X
+ doesn't treat ctrl+command+del differently. And using the pause
+ key isn't usually possible because there isn't one on most OS X
+ systems. Use command instead of option/alt because
+ the command key, not the option/alt key, maps to alt on windows.
+ The reason is because the command key is in the same physical
+ location and performs the same general function (menu shortcuts)
+ as alt on a windows system. This mapping can be modified in
+ the configuration.
+
+ On mac laptops, the key labeled "delete" is actually backspace
+ and ctrl+command+delete won't work. However fn+delete really
+ is delete so fn+ctrl+command+delete will act as ctrl+alt+del
+ on a windows secondary screen.
+
+
Can the server and client be using different operating systems?
+
+ Yes. The synergy network protocol is platform neutral so
+ synergy doesn't care what operating systems are running on
+ the server and clients.
+
+
What's the difference between synergy and
+x2x, x2vnc, etc?
+
+ Unlike x2x, synergy supports any number of computers and
+ it doesn't require X on Microsoft Windows platforms. It
+ also has more advanced clipboard support and synchronizes
+ screensavers. x2vnc is also limited to two computers,
+ requires the separate vnc package, and is really only
+ appropriate for using an X system to control a non-X system.
+ However, the right tool for the job is whatever tool works
+ best for you.
+
+
What does "Cannot initialize hook library" mean?
+
+ This error can occur on a synergy server running on a
+ Microsoft Windows operating system. It means that synergy
+ is already running or possibly was not shut down properly.
+ If it's running then first end the synergy task. If it's
+ not then try logging off and back on or rebooting then
+ starting synergy again.
+
+
What security/encryption does synergy provide?
+
+ Synergy provides no built-in encryption or authentication.
+ Given that, synergy should not be used on or over any untrusted
+ network, especially the Internet. It's generally fine for home
+ networks. Future versions may provide built-in encryption and
+ authentication.
+
+ Strong encryption and authentication is available through SSH
+ (secure shell). Run the SSH daemon (i.e. server) on the same
+ computer that you run the synergy server. It requires no
+ special configuration to support synergy. On each synergy
+ client system, run SSH with port forwarding:
+
+ where server-hostname is the name of the
+ SSH/synergy server.
+ Once ssh authenticates itself, start the synergy client
+ normally except use localhost or
+ 127.0.0.1 as the server's
+ address. SSH will then encrypt all communication on behalf of
+ synergy. Authentication is handled by the SSH authentication.
+
+ A free implementation of SSH for Linux and many Unix systems is
+ OpenSSH. For
+ Windows there's a port of OpenSSH using
+ Cygwin.
+
+
What should I call my screens in the configuration?
+
+ You can use any unique name in the configuration file for each
+ screen but it's easiest to use the hostname of the computer.
+ That's the computer name not including the domain. For example,
+ a computer with the fully qualified domain name xyz.foo.com has
+ the hostname xyz. There should also be an alias for xyz to
+ xyz.foo.com. If you don't use the computer's hostname, you
+ have to tell synergy the name of the screen using a command line
+ option, or the startup dialog on Windows.
+
+ Some systems are configured to report the fully qualified domain
+ name as the hostname. For those systems it will be easier to use
+ the FQDN as the screen name. Also note that a Mac OS X system
+ named xyz may report its hostname as
+ xyz.local. If that's the case for you
+ then use xyz.local as the screen name.
+
+
Why do my Caps-Lock, Num-Lock, Scroll-Lock keys act funny?
+
+ Some systems treat the Caps-Lock, Num-Lock, and Scroll-Lock keys
+ differently than all the others. Whereas most keys report going down
+ when physically pressed and going up when physically released, on
+ these systems the Caps-Lock and Num-Lock keys report going down
+ when being activated and going up when being deactivated. That
+ is, when you press and release, say, Caps-Lock to activate it, it
+ only reports going down, and when you press and release to
+ deactivate it, it only reports going up. This confuses synergy.
+
+ You can solve the problem by changing your configuration file.
+ In the screens section, following each screen that has the
+ problem, any or all of these lines as appropriate:
+
+ Then restart synergy on the server or reload the configuration.
+
+
Can synergy share the display in addition to the mouse and keyboard?
+
+ No. Synergy is a KM solution not a KVM (keyboard, video, mouse)
+ solution. However, future versions will probably support KVM.
+ Hopefully, this will make synergy suitable for managing large
+ numbers of headless servers.
+
+
Can synergy do drag and drop between computers?
+
+ No. That's a very cool idea and it'll be explored. However, it's
+ also clearly difficult and may take a long time to implement.
+
+
Does AltGr/Mode-Switch/ISO_Level3_Shift work?
+
+ Yes, as of 1.0.12 synergy has full support for AltGr/Mode-switch.
+ That includes support for most (all?) European keyboard layouts.
+ All systems should be using the same keyboard layout, though, for
+ all characters to work. (Any character missing from a client's
+ layout cannot be generated by synergy.) There is experimental
+ support for ISO_Level3_Shift in 1.1.3.
+
+
Why isn't synergy ported to platform XYZ?
+
+ Probably because the developers don't have access to platform XYZ
+ and/or are unfamiliar with development on XYZ. Also, synergy has
+ inherently non-portable aspects so there's a not insignificant
+ effort involved in porting.
+
+
My client can't connect. What's wrong?
+
+ A common mistake when starting the client is to give the wrong
+ server host name. The last synergyc command line option (Unix)
+ or the "Server Host Name" edit field (Windows) should be the
+ host name (or IP address) of the server not the client's host
+ name. If you get the error connection failed: cannot connect
+ socket followed by the attempt to connect was forcefully
+ rejected or connection refused then the server isn't started,
+ can't bind the address, or the client is connecting to the wrong
+ host name/address or port. See the
+ troublshooting page for more help.
+
+ to the configure command line? Solaris puts
+ the X11 includes and libraries in an unusual place and the above lets
+ synergy find them.
+
+
The screen saver never starts. Why not?
+
+ If the synergy server is on X Windows then the screen saver will
+ not start while the mouse is on a client screen. This is a
+ consequence of how X Windows, synergy and xscreensaver work.
+
+
I can't switch screens anymore for no apparent reason. Why?
+
+ This should not happen with 1.1.3 and up. Earlier versions of
+ synergy would not allow switching screens when a key was down and
+ sometimes it would believe a key was down when it was not.
+
+
I get the error 'Xlib: No protocol specified'. Why?
+
+ You're running synergy without authorization to connect to the
+ X display. Typically the reason is running synergy as root when
+ logged in as non-root. Just run synergy as the same user that's
+ logged in.
+
+
The cursor goes to secondary screen but won't come back. Why?
+
+ Your configuration is incorrect. You must indicate the neighbors
+ of every screen. Just because you've configured 'Apple' to be to
+ the left of 'Orange' does not mean that 'Orange' is to the right
+ of 'Apple'. You must provide both in the configuration.
+
+
The cursor wraps from one edge of the screen to the opposite. Why?
+
+ Because you told it to. If you list 'Orange' to be to the left of
+ 'Orange' then moving the mouse off the left edge of 'Orange' will
+ make it jump to the right edge. Remove the offending line from the
+ configuration if you don't want that behavior.
+
+
How do I stop my game from minimizing when I leave the screen?
+
+ Many full screen applications, particularly games, automatically
+ minimize when they're no longer the active (foreground) application
+ on Microsoft Windows. The synergy server normally becomes the foreground
+ when you switch to another screen in order to more reliably capture all
+ user input causing those full screen applications to minimize. To
+ prevent synergy from stealing the foreground just click "Options..."
+ and check "Don't take foreground window on Windows servers." If you
+ turn this on then be aware that synergy may not function correctly when
+ certain programs, particularly the command prompt, are the foreground
+ when you switch to other screens. Simply make a different program the
+ foreground before switching to work around that.
+
+The first incarnation of synergy was CosmoSynergy, created by
+Richard Lee and Adam Feder then at Cosmo Software, Inc., a
+subsidiary of SGI (nee Silicon Graphics, Inc.), at the end of
+1996. They wrote it, and Chris Schoeneman contributed, to
+solve a problem: most of the engineers in Cosmo Software had
+both an Irix and a Windows box on their desks and switchboxes
+were expensive and annoying. CosmoSynergy was a great success
+but Cosmo Software declined to productize it and the company
+was later closed.
+
+Synergy is a from-scratch reimplementation of CosmoSynergy.
+It provides most of the features of the original and adds a
+few improvements.
+
+synergy: [noun] a mutually advantageous conjunction of distinct elements
+
+Synergy lets you easily share a single mouse and keyboard between
+multiple computers with different operating systems, each with its
+own display, without special hardware. It's intended for users
+with multiple computers on their desk since each system uses its
+own monitor(s).
+
+Redirecting the mouse and keyboard is as simple as moving the mouse
+off the edge of your screen. Synergy also merges the clipboards of
+all the systems into one, allowing cut-and-paste between systems.
+Furthermore, it synchronizes screen savers so they all start and stop
+together and, if screen locking is enabled, only one screen requires
+a password to unlock them all. Learn more
+about how it works.
+
Microsoft Windows 95, Windows 98, Windows Me (the Windows 95 family)
+
Microsoft Windows NT, Windows 2000, Windows XP (the Windows NT family)
+
Mac OS X 10.2 or higher
+
Unix
+
+
X Windows version 11 revision 4 or up
+
XTEST extension
+ (use "xdpyinfo | grep XTEST" to check for XTEST)
+
+
+All systems must support TCP/IP networking.
+
+"Unix" includes Linux, Solaris, Irix and other variants. Synergy has
+only been extensively tested on Linux and may not work completely or
+at all on other versions of Unix. Patches are welcome (including
+patches that package binaries) at the
+patches page.
+
+The Mac OS X port is incomplete. It does not synchronize the screen saver,
+only text clipboard data works (i.e. HTML and bitmap data do not work),
+the cursor won't hide when not on the screen, and there may be problems
+with mouse wheel acceleration. Other problems should be
+filed as bugs.
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+
Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+
GNU GENERAL PUBLIC LICENSE
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+
+
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+
+
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE
+IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE
+COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
+"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR
+IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED
+TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY
+WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED
+ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT
+LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
+HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
Hot key screen switching now restores last cursor position
+
Fixed loss of hot keys when reloading configuration
+
Fixed autorepeating on win32 (no longer sending repeating key releases)
+
Fixed autorepeating on X11 (non-repeating keys were repeating)
+
Fixed AltGr issues on X11
+
Fixed modifier mapping bug on OS X client (caused wrong characters)
+
Fixed one way for modifiers to get stuck active on all platforms
+
Fixed bugs in win32 GUI
+
Removed alloca() from unix code (should fix FreeBSD build)
+
Added more debugging output for network problems
+
Fixed failure to detect some errors on X11
+
+
+Mar-22-2006 - Synergy 1.3.0 released
+
+Made following additions:
+
+
Console window on win32 can now be closed (reopened from tray menu)
+
Can now change logging level on the fly from win32 tray menu
+
Added client keep alive (lost connections are now detected reliably)
+
Added support for linking portions of screen edges
+
Added version number to UI in win32
+
Added GUI for hot key configuration on win32
+
Hot keys can now perform actions on press and/or release
+
Added key down, key up, mouse down, and mouse up hot key actions
+
Key actions can be directed to particular screens
+
Hot keys can each perform multiple actions
+
+
+Made following fixes:
+
+
Fixed AltGr key mappings (again)
+
Fixed assertion when pasting on X11
+
Fixed modifier keys in VMware on X11
+
OS X server now treats sends option/alt as AltGr or super depending on key
+
Improved handling of AltGr on win32
+
Fixed not removing client when connection is lost
+
Clients now detect loss of connection to server and reconnect
+
Fixed mouse jumping on OS X multimonitor systems
+
Closing console on win32 no longer quits synergy
+
Fixed Num Lock breaking certain keys
+
Fixed Scroll Lock not locking cursor to screen
+
Fixed mapping of delete key on X11
+
Fixed loss of clipboard after a particular copy/paste sequence
+
Fixed compatibility with windows 95/98/Me (ToUnicodeEx)
+
Fixed bad argument to function on OS X
+
Fixed error parsing comments in configuration
+
Fixed autorepeat on win32 servers
+
Fixed X11 keyboard focus bug when reentering screen
+
Fixed (suppressed) hot key autorepeating
+
Fixed mousebutton action when Caps/Num/Scroll Lock were on
+
Added documentation on firewalls
+
Fixed documentation formatting on IE6
+
+
+Hot keys support has one known major bug: key actions cannot be directed
+to the server (primary) screen. The configuration file syntax has changed
+from earlier versions; users will have to modify the configurations by
+hand.
+
+Dec-18-2005 - Synergy 1.2.7 released
+
+Made following changes:
+
+
Added preliminary support for configurable hot keys (Lorenz Schori)
+
Major rewrite of keyboard handling code
+
Fixed non-US keyboard handling (AltGr and ISO_Level3_Shift)
+
Now supporting all installed keyboard layouts simultaneously
+
Fixed bug in handling remapped caps-lock on X11
+
Fixed control and alt keys getting stuck on on X11
+
Fixed desktop focus problems requiring extra clicks on win32
+
Fixed alt key event getting passed to server when on client on win32
+
Synergy would prevent alt+numpad character entry; this is fixed
+
Fixed suppression of xscreensaver 2.21 on X11
+
Fixed middle mouse button dragging on OSX server (Brian Kendall)
+
Fixed caps/num/scroll lock toggles getting out of sync
+
Enhanced support for converting clipboard text to the Latin-1 encoding
+
Added autostart documentation for KDE users
+
Added more details about using Terminal for OSX users
+
Fixed crash when using --help on certain platforms
+
+
+The hot key support is known to have bugs. The configuration file
+syntax for hot keys is likely to change and the documentation for it
+is minimal. The graphical UI on windows does not provide any support
+for editing hot keys.
+
+Nov-12-2005 - Synergy 1.2.6 released
+
+Made following changes:
+
+
Fixed permission problem saving autostart configuration in win32 launcher
+
Disabled buggy fix for loss of clipboard change detection
+
Restored pthread signal autoconf code
+
+
+Oct-17-2005 - Synergy 1.2.5 released
+
+Made following changes:
+
+
Win32 launcher now saves configuration automatically
+
Fixed failure to save autostart configuration on win32
+
Fixed output bottom-right configuration flag
+
Now properly releasing keys when leaving a client screen
+
Fixed stuck-Alt on win32
+
Fixed 64-bit problem with clipboard on X11
+
Fixed BadAtom bug on X11
+
Fixed loss of detection of clipboard changes on win32
+
Added support for the MightyMouse
+
Added support for buttons 4 and 5 on OSX
+
Now shutting down win32 services when uninstalling
+
+
+Aug-07-2005 - Synergy 1.2.4 released
+
+Made following changes:
+
+
Fixed gcc 4.0 warnings
+
Fixed autoconf/automake problems
+
Fixed scroll-lock on X windows
+
Added option to suppress foreground window grabbing on win32
+
Fixed --daemon option on win32 client
+
Fixed --no-restart on client
+
Updated OS X autostart documentation
+
+
+Jul-27-2005 - Synergy 1.2.3 released
+
+Made following changes:
+
+
Added OS X screensaver synchronization support (Lorenz Schori)
+
Added OS X sleep support (Lorenz Schori)
+
Added OS X fast user switching support (Lorenz Schori)
+
Fixed international keyboard support on OS X (Lorenz Schori)
+
Now capturing global hotkeys (e.g. cmd+tab, etc) on OS X (Lorenz Schori)
+
Added support for SO_REUSEADDR (Don Eisele)
+
Added "dead" corners feature
+
Fixed "resource temporarily unavailable" warning when quiting on OS X
+
Win32 now defaults to WARNING log level to avoid console window
+
Now disabling foreground window on win32 when leaving server (Brent Priddy)
+
+
+Jan-26-2005 - Synergy 1.2.2 released
+
+Made following changes:
+
+
Fixed major OS X modifier key handling bug
+
Fixed handling of ISO_Level3_Shift on X11
+
+
+Jan-04-2005 - Synergy 1.2.1 released
+
+Made following changes:
+
+
Fixed major OS X keyboard handling bug
+
Fixed some minor documentation bugs
+
+
+Dec-30-2004 - Synergy 1.2.0 released
+
+Made following changes:
+
+
Improved support for moving laptops between networks (Brent Priddy)
+
Added ISO_Level3_Shift support on X windows
+
Now doing PageUp/PageDown if no mouse wheel on X windows (Tom Chadwick)
+
Fixed handling of number pad number keys on Windows 95/98/Me
+
Fixed handling of non-existant 4th and 5th mouse buttons on Windows
+
Added support for Unicode keyboard layouts on OS X
+
Fixed memory leak on OS X
+
Added OS X autostart documentation (Tor Slettnes)
+
+
+Nov-12-2004 - Synergy 1.1.10 released
+
+Made following changes:
+
+
Fixed race in condition variable wrapper; caused synergy to hang randomly
+
Fixed modifier key and caps-lock handling on OSX
+
System info log message now filtered like all other messages
+
+
+Nov-07-2004 - Synergy 1.1.9 released
+
+Made following changes:
+
+
Fixed compiler error on gcc 3.4 and later
+
Worked around minor gcc -O3 compiler bug
+
Now logging system info at startup
+
Config file errors now logged as errors rather than debug warnings
+
Added half-duplex scroll lock option
+
Fixed tracking of half-duplex toggle key state
+
Now accepting screen names ending in dot (.) for OS X convenience
+
OS X key mapping now loaded from system resources rather than hard coded
+
Fixed multimonitor OS X pimary screen bug; multimon OS X should now work
+
Added experimental workaround for laggy mouse when running linux -> OS X
+
Fixed bug in win32 installer packaging
+
Fixed unrequested continuous mouse wheel scrolling on win32
+
Added win32 GUI to set server address to listen on
+
Fixed resource leak on win32
+
Fixed screensaver detection on windows 2000 and XP
+
Fixed flickering mouse on multimon windows NT/2000/XP
+
Fixed quiting when powerdvd stops playing (may fix other situations, too)
+
Added tray icon menu item to force clients to reconnect
+
Fixed handling of number pad keys with num-lock off on win32
+
Fixed shift key not working when a console windows has focus on win32 server
+
Improved configure of Xinerama and DPMS
+
Improved portability (removed recursive mutexes and _*_SOURCE defines)
+
Now handling DPMS headers without prototypes
+
Fixed dead key and AltGr+shift handling on X11
+
Fixed use of freed memory on unix
+
Fixed AltGr mapping to Ctrl and not Ctrl+Alt on X11 without Alt_R mapped
+
Worked around win32 command prompt stealing shift key events
+
Fixed handling of pause key on win32
+
Fixed handling of backslash on win32 internation keyboard mapping
+
Fixed handling of ctrl and alt keys on NT/2k/XP
+
Fixed XCode project (removed cross-compile)
+
Worked around select() bug in OS X
+
Worked around bug in ifstream on OS X
+
Fixed handling of modifier keys on OS X synergy server
+
Fixed handling of space key on OS X synergy server
+
Fixed handling of key autorepeat on OS X server
+
Fixed mouse wheel drift on OS X client
+
Reorganized documentation and converted to HTML
+
+
+Jun-13-2004 - Synergy 1.1.7 released
+
+Made following changes:
+
+
Added OS X precompiled header file forgotten in last build
+
Fixed bug in fix for 'unexpected async reply' on X11
+
Removed dependency on "browser" service on win32
+
Fixed assertion failure when connection fails immediately
+
Fixed failure to connect on AIX
+
Fixed error in conversion from multibyte to wide characters
+
Maybe fixed win32 screen saver detection
+
+
+May-26-2004 - Synergy 1.1.6 released
+
+Made following changes:
+
+
Added preliminary Mac OS X support (client and server)
+
Fixed ctrl+alt+del emulation on win32
+
Fixed ctrl+alt+del on win32 server acting on both client and server
+
Fixed handling of screen resolution changes on win32
+
Fixed 'unexpected async reply' on X11
+
Added dependency to win32 service to avoid startup race condition
+
Fixed reference count bug
+
Keyboard input focus now restored on X11 (fixes loss of input in some games)
+
+
+The OS X port does not yet support:
+
+
HTML and bitmap clipboard data
+
Screen saver synchronization
+
Non-US English keyboards
+
+
+May-05-2004 - Synergy 1.1.5 released
+
+Made following changes:
+
+
No longer switching screens when a mouse button is down
+
Worked around win32 mouse hook bug, fixing switch on double tap
+
Added support for HTML and bitmap (image/bmp) clipboard data
+
Physical mouse no longer necessary on win32 secondary screens to see cursor
+
Added experimental relative mouse moves on secondary screen option
+
Fixed win32 lock up when closing server with clients still connected
+
Fixed bug in handling duplicate connections
+
Fixed pthread mutex initialization
+
Made synergy dependent on NetBT on win32 (for service startup order)
+
Automake fixes; now mostly works on darwin and MinGW
+
Fixed builds on Solaris 9, FreeBSD, and OpenBSD
+
Partial support for MSYS/MinGW builds (NOT COMPLETE)
+
Partial merge of OS X port (NOT COMPLETE)
+
+
+Mar-31-2004 - Synergy 1.1.4 released
+
+Made following changes:
+
+
Fixed lookup of hosts by name of win32
+
Reverted tray icon code to 1.0.15 version; seems to fix the bugs
+
Fixed crash when caps, num, or scroll lock not in key map on X11
+
Fixed double tap and wait to switch features
+
+
+Mar-28-2004 - Synergy 1.1.3 released
+
+Made following changes:
+
+
Major code refactoring; reduced use of threads, added event queue
+
Removed unused HTTP support code
+
No longer interfering with mouse when scroll lock is toggled on
+
Fixed minor mispositioning of mouse on win32
+
Unix portability fixes
+
Added support for power management
+
Improved keyboard handling and bug fixes
+
Fixed dead key handling
+
+
+Note: the tray icon on windows is known to not work correctly when
+running the synergy server on Windows 95/95/Me.
+
+Aug-24-2003 - Synergy 1.0.14 released
+
+Made following changes:
+
+
Fixed bugs in setting win32 process/thread priority
+
Fixed resource leak in opening win32 system log
+
Fixed win32 launcher not getting non-default advanced options
+
Synergy log copied to clipboard now transferred to other screens
+
Hack to work around lesstif clipboard removed (fixes pasting on X)
+
+
+Jul-20-2003 - Synergy 1.0.12 released
+
+Made following changes:
+
+This release finally completes support for non-ASCII characters,
+fully supporting most (all?) European keyboard layouts including
+dead key composition. This release includes changes from several
+experimental versions (1.0.9, 1.0.11, 1.1.0, 1.1.1, 1.1.2, and
+1.1.3).
+
+Made following changes:
+
+
Added non-ASCII support to win32 and X11
+
Added dead key support to win32 and X11
+
Fixed AltGr handling
+
Added ctrl+alt+del simulation using ctrl+alt+pause
+
Fixed loss of key event when user releases ctrl+alt+del
+
Fixed incorrect synthesis of pointer-keys event on X11
+
Fixed Xinerama support
+
Made some clipboard fixes on win32 and X11
+
Add tray icon menu item to copy log to clipboard
+
Fixed mouse warping on unconnected client
+
Stopped unconnected client from filling up event logs
+
+
+May-10-2003 - Synergy 1.0.8 released
+
+Made following changes:
+
+
+
Fixed hook forwarding (fixing interaction with objectbar)
+
Fixed "Windows" key handling and added support Win+E, Win+F, etc
+
Added win 95/98/me support for Alt+Tab, Alt+Esc, Ctrl+Esc
+
Fixed scroll lock locking to server screen
+
Fixed screen flashing on X11 and Windows
+
Fixed compile problem on 64 bit systems
+
Fixed Xinerama support
+
Now allowing screen names that include underscores
+
Improved non-ASCII key handling on Windows
+
Fixed lagginess
+
Fixed failure to capture all mouse input on Windows
+
Fixed auto-repeat bugs on X11
+
Added option to disable screen saver synchronization
+
Added support for 4th and 5th mouse buttons on Windows
+
Added support for "Internet" and "Multimedia" keys
+
Fixed jumping from client to itself (mouse wrapping)
+
+
+Apr-26-2003 - Added roadmap
+
+There's now a roadmap for Synergy
+describing the plans for further development.
+
+Apr-26-2003 - Added Paypal donation page
+
+There's now a donate button for those
+who'd like to make a monetary contribution to the further
+development of Synergy.
+
+Apr-26-2003 - Development update
+
+Synergy 1.0.8 will include fixes for the following problems.
+These are already fixed and some are in development version 1.0.7.
+
+
+
Mouse events at edge of screen are stolen
+
Windows key doesn't work on clients
+
Alt+[Shift+]Tab, Alt+[Shift+]Esc, Ctrl+Esc don't work on Win 95/98/Me
+
Scroll lock doesn't lock to Windows server screen
+
Screen flashes every 5 seconds on some X11 systems
+
Synergy doesn't work properly with Xinerama
+
Screen names with underscores are not allowed
+
+
+Synergy 1.0.8 will probably include fixes for these problems:
+
+
+
AltGr/Mode_switch doesn't work
+
Non-ASCII keys aren't supported
+
Synergy performs badly on a busy Windows system
+
Unexpected key repeats on X11 clients
+
+
+Synergy 1.0.8 should be available in the first half of May.
+
+Mar-27-2003 - Synergy 1.0.6 released
+
+Made following changes:
+
+
+
Added tray icon on win32
+
Fixed multi-monitor support on win32
+
Fixed win32 screen saver detection on NT/2k/XP
+
Added per-screen options to remap modifier keys
+
Added global options for restricting screen jumping
+
Added global option for detecting unresponsive clients
+
Added more logging for why screen jump won't happen
+
Fixed problem sending the CLIPBOARD to motif/lesstif apps
+
Win32 launcher now remembers non-config-file state
+
+
+In addition, the version number scheme has been changed. Given a
+version number X.Y.Z, release versions will always have Y and Z
+even while development versions will have Y and Z odd.
+
+Mar-27-2003 - Synergy featured in Linux Journal.
+
+The April 2003 issue of Linux Journal includes an article on Synergy.
+Written by Chris Schoeneman, it describes configuring synergy between
+two linux systems.
+
+Mar-27-2003 - Contributions to Synergy.
+
+Many thanks to Girard Thibaut for providing a version of the win32
+launch dialog translated into French. I hope to integrate these
+changes into future releases.
+
+Thanks also to "wrhodes" who provided source files for
+building an InstallShield installer for Synergy. They'll be
+integrated into an upcoming release.
+
+Feb-18-2003 - Synergy 1.0.3 released
+
+Made following changes:
+
+
+
Added support for X11 keymaps with only uppercase letters
+
Reduced frequency of large cursor jumps when leaving win32 server
+
Changed cursor motion on win32 multimon to relative moves only
+
+
+Jan-25-2003 - Synergy 1.0.2 released
+
+Made following changes:
+
+
+
Fixed out-of-bounds array lookup in the BSD and Windows network code
+
Added ability to set screen options from Windows launch dialog
+
+
+Jan-22-2003 - Synergy 1.0.1 released
+
+Made following changes:
+
+
+
Fixed running as a service on Windows NT family
+
+
+Jan-20-2003 - Synergy 1.0.0 released
+
+Made following changes:
+
+
+
Refactored to centralize platform dependent code
+
Added support for mouse wheel on Windows NT (SP3 and up)
+
Portability improvements
+
Added more documentation
+
Fixes for working with xscreensaver
+
Fixes for circular screen links
+
+
+This release has been tested on Linux and Windows. It builds and
+is believed to run on Solaris and FreeBSD. It is believed to
+build and run on Irix and AIX. It builds but does not work on
+MacOS X.
+
+Dec-25-2002 - Synergy 0.9.14 released
+
+Made following changes:
+
+
+
Fixed solaris compile problems (untested)
+
Fixed irix compile problems (untested)
+
Fixed windows client not reconnecting when server dies bug
+
Fixed loss of ctrl+alt from windows server to non-windows clients
+
Fixed handling of password protected windows client screen saver
+
Now handling any number of pointer buttons on X11
+
Toggle key states now restored when leaving clients
+
Added support for per-screen config options
+
Added config options for half-duplex toggle keys on X11
+
Enabled class diagrams in doxygen documentation
+
+
+Nov-05-2002 - Synergy 0.9.13 released
+
+Made following changes:
+
+
+
Fixed solaris compile problems (untested)
+
Fixed MacOS X compile problems (semi-functional)
+
Fixed gcc-3.2 compile problems
+
Fixed some thread startup and shutdown bugs
+
Server now quits if bind() fails with an error other than in use
+
Fixed bug in moving mouse on Win98 without multiple monitors
+
Fixed bug in handling TCP socket errors on read and write
+
Fixed spurious screen saver activation on X11
+
Unix platforms can now read Win32 configuration files
+
Minor error reporting fixes
+
+
+Sep-14-2002 - Synergy 0.9.12 released
+
+Made following changes:
+
+
+
Win32 was not reporting log messages properly when run from synergy.exe
+
Network error messages weren't reporting useful information
+
Synergy won't build on gcc 3.2; added workaround for known problem
+
X11 wasn't handling some keys/key combinations correctly
+
Added option to change logging level when testing from synergy.exe
+
+
+Sep-04-2002 - Synergy 0.9.11 released
+
+Fixed following bugs:
+
+
+
Worked around missing SendInput() on windows 95/NT 4 prior to SP3
+
Fixed keyboard mapping on X11 synergy client
+
+
+Sep-02-2002 - Synergy 0.9.10 released
+
+Fixed following bugs:
+
+
+
The Pause/Break and keypad Enter buttons were not working correctly on windows
+
Configuration options were being lost on windows after a reboot
+
Added support for AltGr/ModeSwitch keys
+
Added support for auto-start on windows when not administrator
+
Improved autoconf
+
Added workaround for lack of sstream header on g++ 2.95.
+
+
+Aug-18-2002 - Synergy 0.9.9 released
+
+Fixed three bugs:
+
+
+
The PrintScrn button was not working correctly on windows
+
The Win32 server could hang when a client disconnected
+
Using the mouse wheel could hang the X server
+
+
+Aug-11-2002 - Synergy 0.9.8 released
+
+Supports any number of clients under Linux or Windows 95 or NT4
+or later. Includes mouse and keyboard sharing, clipboard
+synchronization and screen saver synchronization. Supports ASCII
+keystrokes, 5 button mouse with wheel, and Unicode text clipboard
+format.
+
+This page describes the planned development of Synergy. There are
+no dates or deadlines. Instead, you'll find the features to come
+and the rough order they'll arrive.
+
+
Short term
+
+Synergy should work seamlessly. When it works correctly, it works
+transparently so you don't even think about it. When it breaks,
+you're forced out of the illusion of a unified desktop. The first
+priority is fixing those bugs that break the illusion.
+
+Some of these bugs are pretty minor and some people would rather
+have new features first. But I'd rather fix the current
+foundation before building on it. That's not to say features
+won't get added until after bug fixes; sometimes it's just too
+tempting to code up a feature.
+
+The highest priority feature is currently splitting synergy into
+front-ends and a back-end. The back-end does the real work. The
+front-ends are console, GUI, or background applications that
+communicate with the back-end, either controlling it or receiving
+notifications from it.
+
+On win32, there'd be a front-end for the tray icon and a dialog to
+start, stop, and control the back-end. OS X and X11 would have
+similar front-ends. Splitting out the front-end has the added
+benefit on X11 of keeping the back-end totally independent of
+choice of GUI toolkit (KDE, Gnome, etc.)
+
+One can also imagine a front-end that does nothing but put monitors
+into power-saving mode when the cursor is not on them. If you have
+one monitor auto-senses two inputs, this would automatically switch
+the display when you move the cursor to one screen or another.
+
+
Medium term
+
+Some features fit well into Synergy's current design and may simply
+enhance it's current capabilities.
+
+
+
Configurable hot key to pop up a screen switch menu
+
Configure screen saver synchronization on or off
+
Graphical interface configuration and control on all platforms
+
Graphical status feedback on all platforms
+
More supported clipboard formats (particularly rich text)
+
+
+A popup menu would be new for Synergy, which currently doesn't have
+to do any drawing. That opens up many possibilities. Ideally,
+front-ends request hot keys from the back-end and then tell the back
+end what to do when they're invoked. This keeps the back-end
+independent of the user interface.
+
+
Long term
+
+Two features stand out as long term goals:
+
+
+
Support N computers on
+M monitors
+
Drag and drop across computers
+
+
+The first feature means sharing a monitor or monitors the way the
+keyboard and mouse are shared. With this, Synergy would be a full
+KVM solution. Not only would it support a few computers sharing
+one screen (still using the mouse to roll from one screen to
+another), but it should also support dozens of computers to provide
+a solution for server farm administrators. In this capacity, it
+may need to support text (as opposed to bitmap graphics) screens.
+
+The second feature would enhance the unified desktop illusion. It
+would make it possible to drag a file and possibly other objects
+to another screen. The object would be copied (or moved). I expect
+this to be a very tricky feature.
+
+Synergy lets you use one keyboard and mouse across multiple computers.
+To do so it requires that all the computers are connected to each other
+via TCP/IP networking. Most systems come with this installed.
+
+
Step 1 - Choose a server
+
+The first step is to pick which keyboard and mouse you want to share.
+The computer with that keyboard and mouse is called the "primary
+screen" and it runs the synergy server. All of the other computers
+are "secondary screens" and run the synergy client.
+
+
Step 2 - Install the software
+
+Second, you install the software. Choose the appropriate package
+and install it. For example, on Windows you would run
+SynergyInstaller. You must install the
+software on all the computers that will share the mouse and keyboard
+(clients and server). On OS X you'll just have a folder with some
+documentation and two programs. You can put this folder anywhere.
+
+
Step 3 - Configure and start the server
+
+Next you configure the server. You'll tell synergy the name of
+the primary and secondary screens, which screens are next to which,
+and choose desired options. On Windows there's a dialog box for
+setting the configuration. On other systems you'll create a simple
+text file.
+
+
+Note that when you tell synergy that screen A
+is to the left of screen B this does not
+imply that B is to the right of
+A. You must explicitly indicate both
+relations. If you don't do both then when you're running synergy you'll
+find you're unable to leave one of the screens.
+
+Windows
+On Windows run synergy by double clicking on the
+synergy file. This brings up a dialog.
+Configure the server:
+
+
Click the Share this computer's keyboard and mouse (server) radio button
+
Click the Screens & Links Configure... button
+
Click the + button to add the server to the
+ Screens list
+
+
Enter the name of server (the computer's name is the recommended name)
+
Optionally enter other names the server is known by
+
Click OK
+
+
Use the + button to add your other computers
+
+
Using a computer's name as its screen name is recommended
+
Choose desired screen options on the Add Screen dialog
+
+
Use the controls under Links to link screens together
+
+
Click (once) on the server's name in the Screens list
+
Choose the screen to the left of the server; use ---
+ if there is no screen to the left of the server
+
Choose the screens to the right, above and below the server
+
Repeat the above steps for all the other screens
+
+
Click OK to close the Screens & Links dialog
+
Use Options... to set desired options
+
If the server's screen name is not the server's computer name:
+
+
Click Advanced...
+
Enter the server's screen name next to
+ Screen Name
+
Click OK
+
+
+
+Now click Test. The server will start and
+you'll see a console window with log messages telling you about synergy's
+progress. If an error occurs you'll get one or more dialog boxes telling
+you what the errors are; read the errors to determine the problem then
+correct them and try Test again. See Step 5
+for typical errors.
+
+Unix or Mac OS X
+Create a text file named synergy.conf with the
+following:
+
+ section: screens
+ screen1:
+ screen2:
+ end
+ section: links
+ screen1:
+ right = screen2
+ screen2:
+ left = screen1
+ end
+
+Replace each occurrence of screen1 with the host name
+of the primary screen computer (as reported by the
+hostname program) and screen2
+with the host name of a secondary screen computer. In the above example,
+screen2 is to the right of
+screen1 and screen1 is to the
+left of screen2. If necessary you should replace
+right and left with
+left, right,
+up, or down. If you
+have more than two computers you can add those too: add each computer's host
+name in the screens section and add the
+appropriate links. See the configuration
+guide for more configuration possibilities.
+
+Now start the server. Normally synergy wants to run "in the background."
+It detaches from the terminal and doesn't have a visible window, effectively
+disappearing from view. Until you're sure your configuration works, you
+should start synergy "in the foreground" using the -f
+command line option.
+
+On unix type the command below in a shell. If synergys is not in your
+PATH then use the full pathname.
+
+ synergys -f --config synergy.conf
+
+On OS X open Terminal in the Utilities folder in the Applications folder.
+Drag the synergys program from the synergy folder onto the Terminal window.
+The path to the synergys program will appear. Add the following to the
+same line, type a space at the end of the line but don't press enter:
+
+ -f --config
+
+Now drag the synergy.conf file onto the Terminal window and press enter.
+Check the reported messages for errors. Use ctrl+c to stop synergy if
+it didn't stop automatically, correct any problems, and start it again.
+
+
Step 4 - Start the clients
+
+Next you start the client on each computer that will share the server's
+keyboard and mouse.
+
+Windows
+On Windows run synergy by double clicking on the
+synergy file. This brings up a dialog.
+Configure the client:
+
+
Click the Use another computer's shared keyboard and mouse (client) radio button
+
Enter the server's computer name next to Other Computer's Host Name
+
+
This is not the server's screen name, unless you made that the
+ server's host name as recommended
+
+
If the client's screen name is not the client's computer name:
+
+
Click Advanced...
+
Enter the client's screen name next to Screen Name
+
Click OK
+
+
+
+Now click Test.
+
+Unix or Mac OS X
+To start a client on unix, enter the following:
+
+ synergyc -f server-host-name
+
+where server-host-name is replaced by the host
+name of the computer running the synergy server. If synergyc is not in
+your PATH then use the full pathname.
+
+On OS X open Terminal in the Utilities folder in the Applications folder.
+Drag the synergyc program from the synergy folder onto the Terminal window.
+The path to the synergys program will appear. Add the following to the
+same line and press enter:
+
+ -f server-host-name
+
+
+When you added the client to the server's configuration you chose a
+name for the client. If that name was not client's host name then
+you must tell the client the name you used. Instead of the above
+command use this instead:
+
+ synergyc -f --name nameserver-host-name
+
+where name is the name for the client in
+the server's configuration. (On OS X drag the synergyc program to the
+Terminal window rather than typing synergyc.)
+
+
Step 5 - Test
+
+Clients should immediately report a successful connection or one or
+more error messages. Some typical problems and possible solutions are
+below. See the troubleshooting and the
+FAQ pages for more help.
+
+
failed to open screen (X11 only)
+
+ Check permission to open the X display;
+ check that the DISPLAY environment variable is set
+ use the --display command line option.
+
+
address already in use
+
+ Another program (maybe another copy of synergy) is using the synergy port;
+ stop the other program or choose a different port in the
+ Advanced... dialog. If you change the port
+ you must make the same change on all of the clients, too.
+
+
connection forcefully rejected
+
+ The synergy client successfully contacted the server but synergy wasn't
+ running or it's running on a different port. You may also see this if
+ there's a firewall blocking the host or port. Make sure synergy is
+ running on the server and check for a firewall.
+
+
already connected
+
+ Check that the synergy client isn't already running.
+
+
refused client
+
+ Add the client to the server's configuration file.
+
+
connection timed out
+
+ Check that server-host-name is correct.
+ Check that you don't have a firewall blocking the server or synergy port.
+
+
connection failed
+
+ Check that server-host-name is correct.
+
+
+If you get the error "Xlib: No protocol specified"
+you're probably running synergy as root while logged in as another user.
+X11 may prevent this for security reasons. Either run synergy as the same
+user that's logged in or (not recommended) use
+"xhost +" to allow anyone to connect
+to the display.
+
+When successful you should be able to move the mouse off the appropriate
+edges of your server's screen and have it appear on a client screen.
+Try to move the mouse to each screen and check all the configured links.
+Check the mouse buttons and wheel and try the keyboard on each client.
+You can also cut-and-paste text, HTML, and images across computers (HTML
+and images are not supported on OS X yet).
+
+
Step 6 - Run
+
+Once everything works correctly, stop all the clients then the server.
+Then start the server with the Start button
+on Windows and without the -f option on Unix
+and Mac OS X. Finally start the clients similarly. On Windows before
+clicking Start you may want to set the
+Logging Level to
+Warning so the logging window doesn't pop
+up (because you currently can't close it, just minimize it).
+
+You can also configure synergy to start automatically when your computer
+starts or when you log in. See the autostart
+guide for more information.
+
+
Command Line Options Guide
+
+Common Command Line Options
+The following options are supported by synergys
+and synergyc.
+
+
+
-d,
+
--debug level
+
use debugging level level
+
+
+
+
--daemon
+
run as a daemon (Unix) or background (Windows)
+
+
+
-f,
+
--no-daemon
+
run in the foreground
+
+
+
+
--display display
+
connect to X server at display (X11 only)
+
+
+
-n,
+
--name name
+
use name instead of the hostname
+
+
+
+
--restart
+
automatically restart on failures
+
+
+
-1,
+
--no-restart
+
do not restart on failure
+
+
+
-h,
+
--help
+
print help and exit
+
+
+
+
--version
+
print version information and exit
+
+
+
+Debug levels are from highest to lowest: FATAL,
+ERROR, WARNING,
+NOTE, INFO,
+DEBUG, DEBUG1, and
+DEBUG2. Only messages at or above the given
+level are logged. Messages are logged to a terminal window when
+running in the foreground. Unix logs messages to syslog when running
+as a daemon. The Windows NT family logs messages to the event log
+when running as a service. The Windows 95 family shows FATAL log
+messages in a message box and others in a terminal window when running
+as a service.
+
+The --name option lets the client or server
+use a name other than its hostname for its screen. This name is used
+when checking the configuration.
+
+Neither the client nor server will automatically restart if an error
+occurs that is sure to happen every time. For example, the server
+will exit immediately if it can't find itself in the configuration.
+On X11 both the client and server will also terminate if the
+connection to the X server is lost (usually because it died).
+
+hostname is a hostname or IP address of a network
+interface on the server system (e.g. somehost
+or 192.168.1.100). port
+is a port number from 1 to 65535. hostname defaults to
+the system's hostname and port defaults to 24800.
+
+Client Command Line Options
+
+
+ synergyc [options] address[:port]
+
+address is the hostname or IP address of
+the server and port is the optional network
+port on the server to connect to. The client accepts the
+common options.
+
+
+
+
diff --git a/doc/security.html b/doc/security.html
new file mode 100644
index 00000000..c8013c27
--- /dev/null
+++ b/doc/security.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+ Synergy Network Security Guide
+
+
+
+
Authentication and Encryption
+Synergy does not do any authentication or encryption. Any computer
+can connect to the synergy server if it provides a screen name known
+to the server, and all data is transferred between the server and the
+clients unencrypted which means that anyone can, say, extract the
+key presses used to type a password. Therefore, synergy should not
+be used on untrusted networks.
+
+However, there are tools that can add authentication and encryption
+to synergy without modifying either those tools or synergy. One
+such tool is SSH (which stands for secure shell). A free implementation
+of SSH is called OpenSSH and runs
+on Linux, many Unixes, and Windows (in combination with
+Cygwin).
+
+
Configuring the Server
+Install the OpenSSH server on the same computer as the synergy server.
+Configure the OpenSSH server as usual (synergy doesn't demand any
+special options in OpenSSH) and start it. Start the synergy server as
+usual; the synergy server requires no special options to work with
+OpenSSH.
+
+
Configuring the Clients
+Install the OpenSSH client on each synergy client computer. Then, on
+each client, start the OpenSSH client using port forwarding:
+
+The server-hostname is the name or address
+of the computer with the OpenSSH and synergy servers.
+The 24800 is the default network port used by synergy; if you use
+a different port then replace both instances of 24800 with the port
+number that you use. Finally, start the synergy client normally
+except use localhost as the server host
+name. For example:
+
+ Be aware that not all keystrokes can be handled by synergy. In
+ particular, ctrl+alt+del is not handled. However, synergy can
+ convert ctrl+alt+pause into ctrl+alt+del on the client side.
+ (Synergy must be configured to autostart when the computer starts
+ on the client for this to work on the Windows NT family.) Some
+ non-standard keys may not work, especially "multimedia" buttons,
+ though several are correctly handled.
+
+
+ A screen can be its own neighbor. That allows a screen to "wrap".
+ For example, if a configuration linked the left and right sides of
+ a screen to itself then moving off the left of the screen would put
+ the mouse at the right of the screen and vice versa.
+
+
+ You cannot switch screens when the Scroll Lock is toggled on. Use
+ this to prevent unintentional switching. You can configure other
+ hot keys to do this instead; see
+ lockCursorToScreen.
+
+
+ Turn off mouse driven virtual desktop switching on X windows. It
+ will interfere with synergy. Use keyboard shortcuts instead.
+
+
+ Synergy's screen saver synchronization works best with xscreensaver
+ under X windows. Synergy works better with xscreensaver if it is
+ using one of the screen saver extensions. Prior to xscreensaver 4.0
+ you can use -mit-extension,
+ -sgi-extension, or
+ -xidle-extension
+ command line options to enable an extension (assuming your server has
+ the extension). Starting with 4.0 you must enable the corresponding
+ option in your .xscreensaver file.
+
+
+ Synergy automatically converts newlines in clipboard text (Unix
+ expects \n to end each line while Windows
+ expects \r\n).
+
+
+ Clients can be started and stopped at any time. When a screen is
+ not connected, the mouse will jump over that screen as if the mouse
+ had moved all the way across it and jumped to the next screen.
+
+
+ A client's keyboard and mouse are fully functional while synergy is
+ running. You can use them in case synergy locks up.
+
+
+ Strong authentication and encryption is available by using SSH. See
+ the security guide for more information.
+ Synergy does not otherwise provide secure communications and it should
+ not be used on or over untrusted networks.
+
+
+ Synergy doesn't work if a 16-bit Windows application has the focus
+ on Windows 95/98/Me. This is due to limitations of Windows. One
+ commonly used 16-bit application is the command prompt
+ (command.exe)
+ and this includes synergy's log window when running in test mode.
+
+
diff --git a/doc/todo.html b/doc/todo.html
new file mode 100644
index 00000000..02a12a07
--- /dev/null
+++ b/doc/todo.html
@@ -0,0 +1,70 @@
+
+
+
+
+ Synergy To Do List
+
+
+
Synergy To Do List
+
+This page describes the planned development of Synergy. There are
+no dates or deadlines. Instead, you'll find the features to come
+and the rough order they can be expected to arrive.
+
+
+
Short term
+
+Synergy should work seamlessly. When it works correctly, it works
+transparently so you don't even think about it. When it breaks,
+you're forced out of the illusion of a unified desktop. The first
+priority is fixing those bugs that break the illusion.
+
+
+Some of these bugs are pretty minor and some people would rather
+have new features first. But I'd rather fix the current
+foundation before building on it. That's not to say features
+won't get added until after bug fixes; sometimes it's just too
+tempting to code up a feature.
+
+
+
Medium term
+
+Some features fit well into Synergy's current design and may simply
+enhance it's current capabilities.
+
+
Configurable hot key screen switching
+
Configurable hot key to lock to a screen
+
Configurable hot key to pop up a screen switch menu
+
Configure screen saver synchronization on or off
+
Graphical interface configuration and control on all platforms
+
Graphical status feedback on all platforms
+
More supported clipboard formats (particularly rich text)
+
+
+
+
Long term
+
+Two features stand out as long term goals:
+
+
Support N computers on
+M monitors
+
Drag and drop across computers
+
+
+
+The first feature means sharing a monitor or monitors the way the
+keyboard and mouse are shared. With this, Synergy would be a full
+KVM solution. Not only would it support a few computers sharing
+one screen (still using the mouse to roll from one screen to
+another), but it should also support dozens of computers to provide
+a solution for server farm administrators. In this capacity, it
+may need to support text (as opposed to bitmap graphics) screens.
+
+
+The second feature would enhance the unified desktop illusion. It
+would make it possible to drag a file and possibly other objects
+to another screen. The object would be copied (or moved). I expect
+this to be a very tricky feature.
+
+There's an error in the configuration file. This error is always
+accompanied by another message describing the problem. Use that
+message and the configuration documentation
+to determine the fix.
+
+
Connection forcefully rejected
+
+The client was able to contact the server computer but the server was
+not listening for clients. Possible reasons are:
+
+
+
The client is using the wrong server
+
+Make sure the client is using the hostname or IP address of the computer
+running the synergy server.
+
+
Synergy isn't running on the server
+
+Make sure the synergy server is running on the server computer. Make
+sure the server is ready to accept connections. If another program is
+using synergy's port (24800 by default) then synergy can't start unless
+you specify a different port.
+
+
The client is using the wrong port
+
+Synergy uses port 24800 by default but you can specify a different port.
+If you do use a different port you must use that port on the server and
+all clients.
+
+
+
Connection timed out
+
+The most likely reasons for this are:
+
+
+
A firewall
+
+A firewall is a program or device that deliberately blocks network
+connections for security reasons. Typically, they'll silently drop
+packets they don't want rather than sending a rejection to the sender.
+This makes it more difficult for intruders to break in.
+
+When synergy traffic hits a firewall and gets dropped, eventually the
+synergy client will give up waiting for a response and time out. To
+allow synergy traffic through first find all the firewalls on the
+network between and on the synergy client and server computers.
+
+A firewall on the server or any network device between the server and
+any client should allow packets to TCP port 24800. (Port 24800 is the
+default; use whichever port you've selected.) You'll have to consult
+the manual for your operating system, device, or firewall software to
+find out how to do this.
+
+Usually you'll won't need to adjust a firewall on client machines.
+That's because firewalls normally allow incoming traffic on any port
+they've initiated a connection on. The reasoning is, of course, if
+you started a conversation you probably want to hear the reply.
+
+
The network is down or busy
+
+Correct the network problem and try again. You might try
+ping to see if the two computers can see
+each other on the network.
+
+
The server is frozen
+
+If the synergy server is running but locked up or very busy then the
+client may get this message. If the server is locked up then you'll
+probably have to restart it. If it's just very busy then the client
+should successfully connect automatically once the server settles down.
+
+
+
Cannot listen for clients
+
+Synergy tried to start listening for clients but the network port is
+unavailable for some reason. Typical reasons are:
+
+
+
No network devices
+
+You must have a TCP/IP network device installed and enabled to use
+synergy.
+
+
A synergy server is already running
+
+Check that a synergy server isn't already running.
+
+
Another program is using synergy's port
+
+Only one program at a time can listen for connections on a given port.
+If the specific error is that the address is already in use and you've
+ruled out the other causes, then it's likely another program is already
+using synergy's port. By default synergy uses port 24800. Try having
+synergy use a different port number, like 24801 or 24900. Note that
+the server and all clients must use the same port number. Alternatively,
+find the other program and stop it or have it use another port.
+
+
+
Unknown screen name "XXX"
+
+This error can be reported when reading the configuration; see
+cannot read configuration. If the configuration
+was read successfully and you get this error then it means that the
+server's screen is not in the configuration. All screens must be listed
+in the configuration.
+
+A common reason for this is when you haven't used the system's hostname
+as its screen name. By default, synergy uses the hostname as the screen
+name. If you used a different screen name in the configuration then you
+must tell synergy what that name is. Let's say the hostname is
+frederick but the configuration defines a screen
+named fred. Then you must tell the server
+that its screen name is fred by using the
+--name fred command line option or setting
+the screen name in the advanced options dialog to
+fred.
+
+Alternatively, you can specify one name as an alias of another. See
+the configuration documentation
+for details.
+
+Another common reason for this is a mismatch between what you think the
+hostname is and what synergy thinks it is. Typically this is a problem
+with fully qualified domain names (FQDN). Perhaps you think your system
+is named fred but synergy thinks it's
+fred.nowhere.com or
+fred.local. You can use either solution above
+to fix this.
+
+
Server refused client with name "XXX"
+ A client with name "XXX" is not in the map
+
+The client is using a screen name not in the server's configuration.
+This is essentially the same problem as Unknown
+screen name "XXX" and has the same solutions: specify another
+screen name or add an alias.
+
+
Server already has a connected client with name "XXX"
+ A client with name "XXX" is already connected
+
+This happens when:
+
+
+
Two clients try use the same screen name
+
+Each client must have a unique screen name. Configure at least one
+client to use a different screen name.
+
+
One client reconnects without cleanly disconnecting
+
+It's possible for a client to disconnect without the server knowing,
+usually by being disconnected from the network or possibly by going
+to sleep or even crashing. The server is left thinking the client is
+still connected so when the client reconnects the server will think
+this is a different client using the same name. Synergy will usually
+detect and correct this problem within a few seconds. If it doesn't
+then restart the server.
+
+
+
Server has incompatible version
+
+You're using different versions of synergy on the client and server.
+You should use the same version on all systems.
+
+
The cursor goes to secondary screen but won't come back
+
+
+
+
diff --git a/examples/synergy.conf b/examples/synergy.conf
new file mode 100644
index 00000000..2586dfaf
--- /dev/null
+++ b/examples/synergy.conf
@@ -0,0 +1,37 @@
+# sample synergy configuration file
+#
+# comments begin with the # character and continue to the end of
+# line. comments may appear anywhere the syntax permits.
+
+section: screens
+ # three hosts named: moe, larry, and curly
+ moe:
+ larry:
+ curly:
+end
+
+section: links
+ # larry is to the right of moe and curly is above moe
+ moe:
+ right = larry
+ up = curly
+
+ # moe is to the left of larry and curly is above larry.
+ # note that curly is above both moe and larry and moe
+ # and larry have a symmetric connection (they're in
+ # opposite directions of each other).
+ larry:
+ left = moe
+ up = curly
+
+ # larry is below curly. if you move up from moe and then
+ # down, you'll end up on larry.
+ curly:
+ down = larry
+end
+
+section: aliases
+ # curly is also known as shemp
+ curly:
+ shemp
+end
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 00000000..2a57133c
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,34 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+SUBDIRS = \
+ common \
+ arch \
+ base \
+ mt \
+ io \
+ net \
+ synergy \
+ platform \
+ client \
+ server \
+ $(NULL)
+
+EXTRA_DIST = \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
diff --git a/lib/arch/CArch.cpp b/lib/arch/CArch.cpp
new file mode 100644
index 00000000..80c613ab
--- /dev/null
+++ b/lib/arch/CArch.cpp
@@ -0,0 +1,639 @@
+/*
+ * 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 "common.h"
+#include "CArch.h"
+
+#undef ARCH_CONSOLE
+#undef ARCH_DAEMON
+#undef ARCH_FILE
+#undef ARCH_LOG
+#undef ARCH_MULTITHREAD
+#undef ARCH_NETWORK
+#undef ARCH_SLEEP
+#undef ARCH_STRING
+#undef ARCH_SYSTEM
+#undef ARCH_TASKBAR
+#undef ARCH_TIME
+
+// include appropriate architecture implementation
+#if SYSAPI_WIN32
+# include "CArchConsoleWindows.h"
+# include "CArchDaemonWindows.h"
+# include "CArchFileWindows.h"
+# include "CArchLogWindows.h"
+# include "CArchMiscWindows.h"
+# include "CArchMultithreadWindows.h"
+# include "CArchNetworkWinsock.h"
+# include "CArchSleepWindows.h"
+# include "CArchStringWindows.h"
+# include "CArchSystemWindows.h"
+# include "CArchTaskBarWindows.h"
+# include "CArchTimeWindows.h"
+#elif SYSAPI_UNIX
+# include "CArchConsoleUnix.h"
+# include "CArchDaemonUnix.h"
+# include "CArchFileUnix.h"
+# include "CArchLogUnix.h"
+# if HAVE_PTHREAD
+# include "CArchMultithreadPosix.h"
+# endif
+# include "CArchNetworkBSD.h"
+# include "CArchSleepUnix.h"
+# include "CArchStringUnix.h"
+# include "CArchSystemUnix.h"
+# include "CArchTaskBarXWindows.h"
+# include "CArchTimeUnix.h"
+#endif
+
+#if !defined(ARCH_CONSOLE)
+# error unsupported platform for console
+#endif
+
+#if !defined(ARCH_DAEMON)
+# error unsupported platform for daemon
+#endif
+
+#if !defined(ARCH_FILE)
+# error unsupported platform for file
+#endif
+
+#if !defined(ARCH_LOG)
+# error unsupported platform for logging
+#endif
+
+#if !defined(ARCH_MULTITHREAD)
+# error unsupported platform for multithreading
+#endif
+
+#if !defined(ARCH_NETWORK)
+# error unsupported platform for network
+#endif
+
+#if !defined(ARCH_SLEEP)
+# error unsupported platform for sleep
+#endif
+
+#if !defined(ARCH_STRING)
+# error unsupported platform for string
+#endif
+
+#if !defined(ARCH_SYSTEM)
+# error unsupported platform for system
+#endif
+
+#if !defined(ARCH_TASKBAR)
+# error unsupported platform for taskbar
+#endif
+
+#if !defined(ARCH_TIME)
+# error unsupported platform for time
+#endif
+
+//
+// CArch
+//
+
+CArch* CArch::s_instance = NULL;
+
+CArch::CArch(ARCH_ARGS* args)
+{
+ // only once instance of CArch
+ assert(s_instance == NULL);
+ s_instance = this;
+
+ // create architecture implementation objects
+ m_mt = new ARCH_MULTITHREAD;
+ m_system = new ARCH_SYSTEM;
+ m_file = new ARCH_FILE;
+ m_log = new ARCH_LOG;
+ m_net = new ARCH_NETWORK;
+ m_sleep = new ARCH_SLEEP;
+ m_string = new ARCH_STRING;
+ m_time = new ARCH_TIME;
+ m_console = new ARCH_CONSOLE(args);
+ m_daemon = new ARCH_DAEMON;
+ m_taskbar = new ARCH_TASKBAR(args);
+
+#if SYSAPI_WIN32
+ CArchMiscWindows::init();
+#endif
+}
+
+CArch::~CArch()
+{
+ // clean up
+ delete m_taskbar;
+ delete m_daemon;
+ delete m_console;
+ delete m_time;
+ delete m_string;
+ delete m_sleep;
+ delete m_net;
+ delete m_log;
+ delete m_file;
+ delete m_system;
+ delete m_mt;
+
+ // no instance
+ s_instance = NULL;
+}
+
+CArch*
+CArch::getInstance()
+{
+ assert(s_instance != NULL);
+
+ return s_instance;
+}
+
+void
+CArch::openConsole(const char* title)
+{
+ m_console->openConsole(title);
+}
+
+void
+CArch::closeConsole()
+{
+ m_console->closeConsole();
+}
+
+void
+CArch::showConsole(bool showIfEmpty)
+{
+ m_console->showConsole(showIfEmpty);
+}
+
+void
+CArch::writeConsole(const char* str)
+{
+ m_console->writeConsole(str);
+}
+
+const char*
+CArch::getNewlineForConsole()
+{
+ return m_console->getNewlineForConsole();
+}
+
+void
+CArch::installDaemon(const char* name,
+ const char* description,
+ const char* pathname,
+ const char* commandLine,
+ const char* dependencies,
+ bool allUsers)
+{
+ m_daemon->installDaemon(name, description, pathname,
+ commandLine, dependencies, allUsers);
+}
+
+void
+CArch::uninstallDaemon(const char* name, bool allUsers)
+{
+ m_daemon->uninstallDaemon(name, allUsers);
+}
+
+int
+CArch::daemonize(const char* name, DaemonFunc func)
+{
+ return m_daemon->daemonize(name, func);
+}
+
+bool
+CArch::canInstallDaemon(const char* name, bool allUsers)
+{
+ return m_daemon->canInstallDaemon(name, allUsers);
+}
+
+bool
+CArch::isDaemonInstalled(const char* name, bool allUsers)
+{
+ return m_daemon->isDaemonInstalled(name, allUsers);
+}
+
+const char*
+CArch::getBasename(const char* pathname)
+{
+ return m_file->getBasename(pathname);
+}
+
+std::string
+CArch::getUserDirectory()
+{
+ return m_file->getUserDirectory();
+}
+
+std::string
+CArch::getSystemDirectory()
+{
+ return m_file->getSystemDirectory();
+}
+
+std::string
+CArch::concatPath(const std::string& prefix, const std::string& suffix)
+{
+ return m_file->concatPath(prefix, suffix);
+}
+
+void
+CArch::openLog(const char* name)
+{
+ m_log->openLog(name);
+}
+
+void
+CArch::closeLog()
+{
+ m_log->closeLog();
+}
+
+void
+CArch::showLog(bool showIfEmpty)
+{
+ m_log->showLog(showIfEmpty);
+}
+
+void
+CArch::writeLog(ELevel level, const char* msg)
+{
+ m_log->writeLog(level, msg);
+}
+
+CArchCond
+CArch::newCondVar()
+{
+ return m_mt->newCondVar();
+}
+
+void
+CArch::closeCondVar(CArchCond cond)
+{
+ m_mt->closeCondVar(cond);
+}
+
+void
+CArch::signalCondVar(CArchCond cond)
+{
+ m_mt->signalCondVar(cond);
+}
+
+void
+CArch::broadcastCondVar(CArchCond cond)
+{
+ m_mt->broadcastCondVar(cond);
+}
+
+bool
+CArch::waitCondVar(CArchCond cond, CArchMutex mutex, double timeout)
+{
+ return m_mt->waitCondVar(cond, mutex, timeout);
+}
+
+CArchMutex
+CArch::newMutex()
+{
+ return m_mt->newMutex();
+}
+
+void
+CArch::closeMutex(CArchMutex mutex)
+{
+ m_mt->closeMutex(mutex);
+}
+
+void
+CArch::lockMutex(CArchMutex mutex)
+{
+ m_mt->lockMutex(mutex);
+}
+
+void
+CArch::unlockMutex(CArchMutex mutex)
+{
+ m_mt->unlockMutex(mutex);
+}
+
+CArchThread
+CArch::newThread(ThreadFunc func, void* data)
+{
+ return m_mt->newThread(func, data);
+}
+
+CArchThread
+CArch::newCurrentThread()
+{
+ return m_mt->newCurrentThread();
+}
+
+CArchThread
+CArch::copyThread(CArchThread thread)
+{
+ return m_mt->copyThread(thread);
+}
+
+void
+CArch::closeThread(CArchThread thread)
+{
+ m_mt->closeThread(thread);
+}
+
+void
+CArch::cancelThread(CArchThread thread)
+{
+ m_mt->cancelThread(thread);
+}
+
+void
+CArch::setPriorityOfThread(CArchThread thread, int n)
+{
+ m_mt->setPriorityOfThread(thread, n);
+}
+
+void
+CArch::testCancelThread()
+{
+ m_mt->testCancelThread();
+}
+
+bool
+CArch::wait(CArchThread thread, double timeout)
+{
+ return m_mt->wait(thread, timeout);
+}
+
+bool
+CArch::isSameThread(CArchThread thread1, CArchThread thread2)
+{
+ return m_mt->isSameThread(thread1, thread2);
+}
+
+bool
+CArch::isExitedThread(CArchThread thread)
+{
+ return m_mt->isExitedThread(thread);
+}
+
+void*
+CArch::getResultOfThread(CArchThread thread)
+{
+ return m_mt->getResultOfThread(thread);
+}
+
+IArchMultithread::ThreadID
+CArch::getIDOfThread(CArchThread thread)
+{
+ return m_mt->getIDOfThread(thread);
+}
+
+void
+CArch::setSignalHandler(ESignal signal, SignalFunc func, void* userData)
+{
+ m_mt->setSignalHandler(signal, func, userData);
+}
+
+void
+CArch::raiseSignal(ESignal signal)
+{
+ m_mt->raiseSignal(signal);
+}
+
+CArchSocket
+CArch::newSocket(EAddressFamily family, ESocketType type)
+{
+ return m_net->newSocket(family, type);
+}
+
+CArchSocket
+CArch::copySocket(CArchSocket s)
+{
+ return m_net->copySocket(s);
+}
+
+void
+CArch::closeSocket(CArchSocket s)
+{
+ m_net->closeSocket(s);
+}
+
+void
+CArch::closeSocketForRead(CArchSocket s)
+{
+ m_net->closeSocketForRead(s);
+}
+
+void
+CArch::closeSocketForWrite(CArchSocket s)
+{
+ m_net->closeSocketForWrite(s);
+}
+
+void
+CArch::bindSocket(CArchSocket s, CArchNetAddress addr)
+{
+ m_net->bindSocket(s, addr);
+}
+
+void
+CArch::listenOnSocket(CArchSocket s)
+{
+ m_net->listenOnSocket(s);
+}
+
+CArchSocket
+CArch::acceptSocket(CArchSocket s, CArchNetAddress* addr)
+{
+ return m_net->acceptSocket(s, addr);
+}
+
+bool
+CArch::connectSocket(CArchSocket s, CArchNetAddress name)
+{
+ return m_net->connectSocket(s, name);
+}
+
+int
+CArch::pollSocket(CPollEntry pe[], int num, double timeout)
+{
+ return m_net->pollSocket(pe, num, timeout);
+}
+
+void
+CArch::unblockPollSocket(CArchThread thread)
+{
+ m_net->unblockPollSocket(thread);
+}
+
+size_t
+CArch::readSocket(CArchSocket s, void* buf, size_t len)
+{
+ return m_net->readSocket(s, buf, len);
+}
+
+size_t
+CArch::writeSocket(CArchSocket s, const void* buf, size_t len)
+{
+ return m_net->writeSocket(s, buf, len);
+}
+
+void
+CArch::throwErrorOnSocket(CArchSocket s)
+{
+ m_net->throwErrorOnSocket(s);
+}
+
+bool
+CArch::setNoDelayOnSocket(CArchSocket s, bool noDelay)
+{
+ return m_net->setNoDelayOnSocket(s, noDelay);
+}
+
+bool
+CArch::setReuseAddrOnSocket(CArchSocket s, bool reuse)
+{
+ return m_net->setReuseAddrOnSocket(s, reuse);
+}
+
+std::string
+CArch::getHostName()
+{
+ return m_net->getHostName();
+}
+
+CArchNetAddress
+CArch::newAnyAddr(EAddressFamily family)
+{
+ return m_net->newAnyAddr(family);
+}
+
+CArchNetAddress
+CArch::copyAddr(CArchNetAddress addr)
+{
+ return m_net->copyAddr(addr);
+}
+
+CArchNetAddress
+CArch::nameToAddr(const std::string& name)
+{
+ return m_net->nameToAddr(name);
+}
+
+void
+CArch::closeAddr(CArchNetAddress addr)
+{
+ m_net->closeAddr(addr);
+}
+
+std::string
+CArch::addrToName(CArchNetAddress addr)
+{
+ return m_net->addrToName(addr);
+}
+
+std::string
+CArch::addrToString(CArchNetAddress addr)
+{
+ return m_net->addrToString(addr);
+}
+
+IArchNetwork::EAddressFamily
+CArch::getAddrFamily(CArchNetAddress addr)
+{
+ return m_net->getAddrFamily(addr);
+}
+
+void
+CArch::setAddrPort(CArchNetAddress addr, int port)
+{
+ m_net->setAddrPort(addr, port);
+}
+
+int
+CArch::getAddrPort(CArchNetAddress addr)
+{
+ return m_net->getAddrPort(addr);
+}
+
+bool
+CArch::isAnyAddr(CArchNetAddress addr)
+{
+ return m_net->isAnyAddr(addr);
+}
+
+bool
+CArch::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
+{
+ return m_net->isEqualAddr(a, b);
+}
+
+void
+CArch::sleep(double timeout)
+{
+ m_sleep->sleep(timeout);
+}
+
+int
+CArch::vsnprintf(char* str, int size, const char* fmt, va_list ap)
+{
+ return m_string->vsnprintf(str, size, fmt, ap);
+}
+
+int
+CArch::convStringMBToWC(wchar_t* dst, const char* src, UInt32 n, bool* errors)
+{
+ return m_string->convStringMBToWC(dst, src, n, errors);
+}
+
+int
+CArch::convStringWCToMB(char* dst, const wchar_t* src, UInt32 n, bool* errors)
+{
+ return m_string->convStringWCToMB(dst, src, n, errors);
+}
+
+IArchString::EWideCharEncoding
+CArch::getWideCharEncoding()
+{
+ return m_string->getWideCharEncoding();
+}
+
+std::string
+CArch::getOSName() const
+{
+ return m_system->getOSName();
+}
+
+void
+CArch::addReceiver(IArchTaskBarReceiver* receiver)
+{
+ m_taskbar->addReceiver(receiver);
+}
+
+void
+CArch::removeReceiver(IArchTaskBarReceiver* receiver)
+{
+ m_taskbar->removeReceiver(receiver);
+}
+
+void
+CArch::updateReceiver(IArchTaskBarReceiver* receiver)
+{
+ m_taskbar->updateReceiver(receiver);
+}
+
+double
+CArch::time()
+{
+ return m_time->time();
+}
diff --git a/lib/arch/CArch.h b/lib/arch/CArch.h
new file mode 100644
index 00000000..644f015c
--- /dev/null
+++ b/lib/arch/CArch.h
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCH_H
+#define CARCH_H
+
+#include "IArchConsole.h"
+#include "IArchDaemon.h"
+#include "IArchFile.h"
+#include "IArchLog.h"
+#include "IArchMultithread.h"
+#include "IArchNetwork.h"
+#include "IArchSleep.h"
+#include "IArchString.h"
+#include "IArchSystem.h"
+#include "IArchTaskBar.h"
+#include "IArchTime.h"
+
+/*!
+\def ARCH
+This macro evaluates to the singleton CArch object.
+*/
+#define ARCH (CArch::getInstance())
+
+#define ARCH_ARGS void
+
+//! Delegating mplementation of architecture dependent interfaces
+/*!
+This class is a centralized interface to all architecture dependent
+interface implementations (except miscellaneous functions). It
+instantiates an implementation of each interface and delegates calls
+to each method to those implementations. Clients should use the
+\c ARCH macro to access this object. Clients must also instantiate
+exactly one of these objects before attempting to call any method,
+typically at the beginning of \c main().
+*/
+class CArch : public IArchConsole,
+ public IArchDaemon,
+ public IArchFile,
+ public IArchLog,
+ public IArchMultithread,
+ public IArchNetwork,
+ public IArchSleep,
+ public IArchString,
+ public IArchSystem,
+ public IArchTaskBar,
+ public IArchTime {
+public:
+ CArch(ARCH_ARGS* args = NULL);
+ ~CArch();
+
+ //
+ // accessors
+ //
+
+ //! Return the singleton instance
+ /*!
+ The client must have instantiated exactly once CArch object before
+ calling this function.
+ */
+ static CArch* getInstance();
+
+ // IArchConsole overrides
+ virtual void openConsole(const char*);
+ virtual void closeConsole();
+ virtual void showConsole(bool showIfEmpty);
+ virtual void writeConsole(const char*);
+ virtual const char* getNewlineForConsole();
+
+ // IArchDaemon overrides
+ virtual void installDaemon(const char* name,
+ const char* description,
+ const char* pathname,
+ const char* commandLine,
+ const char* dependencies,
+ bool allUsers);
+ virtual void uninstallDaemon(const char* name, bool allUsers);
+ virtual int daemonize(const char* name, DaemonFunc func);
+ virtual bool canInstallDaemon(const char* name, bool allUsers);
+ virtual bool isDaemonInstalled(const char* name, bool allUsers);
+
+ // IArchFile overrides
+ virtual const char* getBasename(const char* pathname);
+ virtual std::string getUserDirectory();
+ virtual std::string getSystemDirectory();
+ virtual std::string concatPath(const std::string& prefix,
+ const std::string& suffix);
+
+ // IArchLog overrides
+ virtual void openLog(const char*);
+ virtual void closeLog();
+ virtual void showLog(bool showIfEmpty);
+ virtual void writeLog(ELevel, const char*);
+
+ // IArchMultithread overrides
+ virtual CArchCond newCondVar();
+ virtual void closeCondVar(CArchCond);
+ virtual void signalCondVar(CArchCond);
+ virtual void broadcastCondVar(CArchCond);
+ virtual bool waitCondVar(CArchCond, CArchMutex, double timeout);
+ virtual CArchMutex newMutex();
+ virtual void closeMutex(CArchMutex);
+ virtual void lockMutex(CArchMutex);
+ virtual void unlockMutex(CArchMutex);
+ virtual CArchThread newThread(ThreadFunc, void*);
+ virtual CArchThread newCurrentThread();
+ virtual CArchThread copyThread(CArchThread);
+ virtual void closeThread(CArchThread);
+ virtual void cancelThread(CArchThread);
+ virtual void setPriorityOfThread(CArchThread, int n);
+ virtual void testCancelThread();
+ virtual bool wait(CArchThread, double timeout);
+ virtual bool isSameThread(CArchThread, CArchThread);
+ virtual bool isExitedThread(CArchThread);
+ virtual void* getResultOfThread(CArchThread);
+ virtual ThreadID getIDOfThread(CArchThread);
+ virtual void setSignalHandler(ESignal, SignalFunc, void*);
+ virtual void raiseSignal(ESignal);
+
+ // IArchNetwork overrides
+ virtual CArchSocket newSocket(EAddressFamily, ESocketType);
+ virtual CArchSocket copySocket(CArchSocket s);
+ virtual void closeSocket(CArchSocket s);
+ virtual void closeSocketForRead(CArchSocket s);
+ virtual void closeSocketForWrite(CArchSocket s);
+ virtual void bindSocket(CArchSocket s, CArchNetAddress addr);
+ virtual void listenOnSocket(CArchSocket s);
+ virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
+ virtual bool connectSocket(CArchSocket s, CArchNetAddress name);
+ virtual int pollSocket(CPollEntry[], int num, double timeout);
+ virtual void unblockPollSocket(CArchThread thread);
+ virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
+ virtual size_t writeSocket(CArchSocket s,
+ const void* buf, size_t len);
+ virtual void throwErrorOnSocket(CArchSocket);
+ virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay);
+ virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse);
+ virtual std::string getHostName();
+ virtual CArchNetAddress newAnyAddr(EAddressFamily);
+ virtual CArchNetAddress copyAddr(CArchNetAddress);
+ virtual CArchNetAddress nameToAddr(const std::string&);
+ virtual void closeAddr(CArchNetAddress);
+ virtual std::string addrToName(CArchNetAddress);
+ virtual std::string addrToString(CArchNetAddress);
+ virtual EAddressFamily getAddrFamily(CArchNetAddress);
+ virtual void setAddrPort(CArchNetAddress, int port);
+ virtual int getAddrPort(CArchNetAddress);
+ virtual bool isAnyAddr(CArchNetAddress);
+ virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
+
+ // IArchSleep overrides
+ virtual void sleep(double timeout);
+
+ // IArchString overrides
+ virtual int vsnprintf(char* str,
+ int size, const char* fmt, va_list ap);
+ virtual int convStringMBToWC(wchar_t*,
+ const char*, UInt32 n, bool* errors);
+ virtual int convStringWCToMB(char*,
+ const wchar_t*, UInt32 n, bool* errors);
+ virtual EWideCharEncoding
+ getWideCharEncoding();
+
+ // IArchSystem overrides
+ virtual std::string getOSName() const;
+
+ // IArchTaskBar
+ virtual void addReceiver(IArchTaskBarReceiver*);
+ virtual void removeReceiver(IArchTaskBarReceiver*);
+ virtual void updateReceiver(IArchTaskBarReceiver*);
+
+ // IArchTime overrides
+ virtual double time();
+
+private:
+ static CArch* s_instance;
+
+ IArchConsole* m_console;
+ IArchDaemon* m_daemon;
+ IArchFile* m_file;
+ IArchLog* m_log;
+ IArchMultithread* m_mt;
+ IArchNetwork* m_net;
+ IArchSleep* m_sleep;
+ IArchString* m_string;
+ IArchSystem* m_system;
+ IArchTaskBar* m_taskbar;
+ IArchTime* m_time;
+};
+
+//! Convenience object to lock/unlock an arch mutex
+class CArchMutexLock {
+public:
+ CArchMutexLock(CArchMutex mutex) : m_mutex(mutex)
+ {
+ ARCH->lockMutex(m_mutex);
+ }
+ ~CArchMutexLock()
+ {
+ ARCH->unlockMutex(m_mutex);
+ }
+
+private:
+ CArchMutex m_mutex;
+};
+
+#endif
diff --git a/lib/arch/CArchConsoleUnix.cpp b/lib/arch/CArchConsoleUnix.cpp
new file mode 100644
index 00000000..dcb6e961
--- /dev/null
+++ b/lib/arch/CArchConsoleUnix.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "CArchConsoleUnix.h"
+#include
+
+//
+// CArchConsoleUnix
+//
+
+CArchConsoleUnix::CArchConsoleUnix(void*)
+{
+ // 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";
+}
diff --git a/lib/arch/CArchConsoleUnix.h b/lib/arch/CArchConsoleUnix.h
new file mode 100644
index 00000000..f93630bd
--- /dev/null
+++ b/lib/arch/CArchConsoleUnix.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHCONSOLEUNIX_H
+#define CARCHCONSOLEUNIX_H
+
+#include "IArchConsole.h"
+
+#define ARCH_CONSOLE CArchConsoleUnix
+
+//! Unix implementation of IArchConsole
+class CArchConsoleUnix : public IArchConsole {
+public:
+ CArchConsoleUnix(void*);
+ 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
diff --git a/lib/arch/CArchConsoleWindows.cpp b/lib/arch/CArchConsoleWindows.cpp
new file mode 100644
index 00000000..14d418ac
--- /dev/null
+++ b/lib/arch/CArchConsoleWindows.cpp
@@ -0,0 +1,438 @@
+/*
+ * 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 "CArchConsoleWindows.h"
+#include "IArchMultithread.h"
+#include "CArch.h"
+#include "CArchMiscWindows.h"
+#include
+
+#define SYNERGY_MSG_CONSOLE_OPEN WM_APP + 0x0021
+#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
+
+//
+// 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(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(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(&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(removedCharacters);
+ SendMessage(m_hwnd, EM_EXSETSEL, 0, reinterpret_cast(&range));
+ SendMessage(m_hwnd, EM_REPLACESEL, FALSE, reinterpret_cast(""));
+
+ // adjust selection
+ if (selection.cpMin < static_cast(removedCharacters) ||
+ selection.cpMax < static_cast(removedCharacters)) {
+ selection.cpMin = 0;
+ selection.cpMax = 0;
+ }
+ else {
+ selection.cpMin -= static_cast(removedCharacters);
+ selection.cpMax -= static_cast(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 = m_numCharacters;
+ range.cpMax = m_numCharacters;
+ SendMessage(m_hwnd, EM_EXSETSEL, 0, reinterpret_cast(&range));
+ SendMessage(m_hwnd, EM_REPLACESEL, FALSE,
+ reinterpret_cast(m_buffer.back().c_str()));
+
+ // adjust selection
+ bool atEnd = false;
+ if (selection.cpMax == static_cast(m_numCharacters)) {
+ selection.cpMin = static_cast(newNumCharacters);
+ selection.cpMax = static_cast(newNumCharacters);
+ atEnd = true;
+ }
+
+ // restore the selection
+ SendMessage(m_hwnd, EM_EXSETSEL, 0, reinterpret_cast(&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(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(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;
+ 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(&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(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(windowClass), s_appInstance);
+}
+
+void*
+CArchConsoleWindows::threadEntry(void* self)
+{
+ reinterpret_cast(self)->threadMainLoop();
+ return NULL;
+}
diff --git a/lib/arch/CArchConsoleWindows.h b/lib/arch/CArchConsoleWindows.h
new file mode 100644
index 00000000..0d59e6ef
--- /dev/null
+++ b/lib/arch/CArchConsoleWindows.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHCONSOLEWINDOWS_H
+#define CARCHCONSOLEWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "IArchConsole.h"
+#include "IArchMultithread.h"
+#include "stddeque.h"
+#include
+
+#define ARCH_CONSOLE CArchConsoleWindows
+
+//! Win32 implementation of IArchConsole
+class CArchConsoleWindows : public IArchConsole {
+public:
+ CArchConsoleWindows(void*);
+ 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 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
diff --git a/lib/arch/CArchDaemonNone.cpp b/lib/arch/CArchDaemonNone.cpp
new file mode 100644
index 00000000..0281f365
--- /dev/null
+++ b/lib/arch/CArchDaemonNone.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "CArchDaemonNone.h"
+
+//
+// CArchDaemonNone
+//
+
+CArchDaemonNone::CArchDaemonNone()
+{
+ // do nothing
+}
+
+CArchDaemonNone::~CArchDaemonNone()
+{
+ // do nothing
+}
+
+void
+CArchDaemonNone::installDaemon(const char*,
+ const char*,
+ const char*,
+ const char*,
+ const char*,
+ bool)
+{
+ // do nothing
+}
+
+void
+CArchDaemonNone::uninstallDaemon(const char*, bool)
+{
+ // do nothing
+}
+
+int
+CArchDaemonNone::daemonize(const char* name, DaemonFunc func)
+{
+ // simply forward the call to func. obviously, this doesn't
+ // do any daemonizing.
+ return func(1, &name);
+}
+
+bool
+CArchDaemonNone::canInstallDaemon(const char*, bool)
+{
+ return false;
+}
+
+bool
+CArchDaemonNone::isDaemonInstalled(const char*, bool)
+{
+ return false;
+}
diff --git a/lib/arch/CArchDaemonNone.h b/lib/arch/CArchDaemonNone.h
new file mode 100644
index 00000000..1c196c5d
--- /dev/null
+++ b/lib/arch/CArchDaemonNone.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHDAEMONNONE_H
+#define CARCHDAEMONNONE_H
+
+#include "IArchDaemon.h"
+
+#define ARCH_DAEMON CArchDaemonNone
+
+//! Dummy implementation of IArchDaemon
+/*!
+This class implements IArchDaemon for a platform that does not have
+daemons. The install and uninstall functions do nothing, the query
+functions return false, and \c daemonize() simply calls the passed
+function and returns its result.
+*/
+class CArchDaemonNone : public IArchDaemon {
+public:
+ CArchDaemonNone();
+ virtual ~CArchDaemonNone();
+
+ // IArchDaemon overrides
+ virtual void installDaemon(const char* name,
+ const char* description,
+ const char* pathname,
+ const char* commandLine,
+ const char* dependencies,
+ bool allUsers);
+ virtual void uninstallDaemon(const char* name, bool allUsers);
+ virtual int daemonize(const char* name, DaemonFunc func);
+ virtual bool canInstallDaemon(const char* name, bool allUsers);
+ virtual bool isDaemonInstalled(const char* name, bool allUsers);
+};
+
+#endif
diff --git a/lib/arch/CArchDaemonUnix.cpp b/lib/arch/CArchDaemonUnix.cpp
new file mode 100644
index 00000000..93d50d4d
--- /dev/null
+++ b/lib/arch/CArchDaemonUnix.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "CArchDaemonUnix.h"
+#include "XArchUnix.h"
+#include
+#include
+#include
+#include
+#include
+
+//
+// CArchDaemonUnix
+//
+
+CArchDaemonUnix::CArchDaemonUnix()
+{
+ // do nothing
+}
+
+CArchDaemonUnix::~CArchDaemonUnix()
+{
+ // do nothing
+}
+
+int
+CArchDaemonUnix::daemonize(const char* name, DaemonFunc func)
+{
+ // fork so shell thinks we're done and so we're not a process
+ // group leader
+ switch (fork()) {
+ case -1:
+ // failed
+ throw XArchDaemonFailed(new XArchEvalUnix(errno));
+
+ case 0:
+ // child
+ break;
+
+ default:
+ // parent exits
+ exit(0);
+ }
+
+ // become leader of a new session
+ setsid();
+
+ // chdir to root so we don't keep mounted filesystems points busy
+ chdir("/");
+
+ // mask off permissions for any but owner
+ umask(077);
+
+ // close open files. we only expect stdin, stdout, stderr to be open.
+ close(0);
+ close(1);
+ close(2);
+
+ // attach file descriptors 0, 1, 2 to /dev/null so inadvertent use
+ // of standard I/O safely goes in the bit bucket.
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_RDWR);
+ dup(1);
+
+ // invoke function
+ return func(1, &name);
+}
diff --git a/lib/arch/CArchDaemonUnix.h b/lib/arch/CArchDaemonUnix.h
new file mode 100644
index 00000000..923004e1
--- /dev/null
+++ b/lib/arch/CArchDaemonUnix.h
@@ -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.
+ */
+
+#ifndef CARCHDAEMONUNIX_H
+#define CARCHDAEMONUNIX_H
+
+#include "CArchDaemonNone.h"
+
+#undef ARCH_DAEMON
+#define ARCH_DAEMON CArchDaemonUnix
+
+//! Unix implementation of IArchDaemon
+class CArchDaemonUnix : public CArchDaemonNone {
+public:
+ CArchDaemonUnix();
+ virtual ~CArchDaemonUnix();
+
+ // IArchDaemon overrides
+ virtual int daemonize(const char* name, DaemonFunc func);
+};
+
+#endif
diff --git a/lib/arch/CArchDaemonWindows.cpp b/lib/arch/CArchDaemonWindows.cpp
new file mode 100644
index 00000000..ab42ceab
--- /dev/null
+++ b/lib/arch/CArchDaemonWindows.cpp
@@ -0,0 +1,770 @@
+/*
+ * 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 "CArchDaemonWindows.h"
+#include "CArch.h"
+#include "CArchMiscWindows.h"
+#include "XArchWindows.h"
+#include "stdvector.h"
+
+//
+// CArchDaemonWindows
+//
+
+CArchDaemonWindows* CArchDaemonWindows::s_daemon = NULL;
+
+CArchDaemonWindows::CArchDaemonWindows()
+{
+ m_quitMessage = RegisterWindowMessage("SynergyDaemonExit");
+}
+
+CArchDaemonWindows::~CArchDaemonWindows()
+{
+ // do nothing
+}
+
+int
+CArchDaemonWindows::runDaemon(RunFunc runFunc)
+{
+ assert(s_daemon != NULL);
+
+ return s_daemon->doRunDaemon(runFunc);
+}
+
+void
+CArchDaemonWindows::daemonRunning(bool running)
+{
+ // if s_daemon is NULL we assume we're running on the windows
+ // 95 family and we just ignore this call so the caller doesn't
+ // have to go through the trouble of not calling it on the
+ // windows 95 family.
+ if (s_daemon != NULL) {
+ s_daemon->doDaemonRunning(running);
+ }
+}
+
+UINT
+CArchDaemonWindows::getDaemonQuitMessage()
+{
+ if (s_daemon != NULL) {
+ return s_daemon->doGetDaemonQuitMessage();
+ }
+ else {
+ return 0;
+ }
+}
+
+void
+CArchDaemonWindows::daemonFailed(int result)
+{
+ // if s_daemon is NULL we assume we're running on the windows
+ // 95 family and we just ignore this call so the caller doesn't
+ // have to go through the trouble of not calling it on the
+ // windows 95 family.
+ if (s_daemon != NULL) {
+ throw XArchDaemonRunFailed(result);
+ }
+}
+
+void
+CArchDaemonWindows::installDaemon(const char* name,
+ const char* description,
+ const char* pathname,
+ const char* commandLine,
+ const char* dependencies,
+ bool allUsers)
+{
+ // if not for all users then use the user's autostart registry.
+ // key. if windows 95 family then use windows 95 services key.
+ if (!allUsers || CArchMiscWindows::isWindows95Family()) {
+ // open registry
+ HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
+ open95ServicesKey() : openUserStartupKey();
+ if (key == NULL) {
+ // can't open key
+ throw XArchDaemonInstallFailed(new XArchEvalWindows);
+ }
+
+ // construct entry
+ std::string value;
+ value += "\"";
+ value += pathname;
+ value += "\" ";
+ value += commandLine;
+
+ // install entry
+ CArchMiscWindows::setValue(key, name, value);
+
+ // clean up
+ CArchMiscWindows::closeKey(key);
+ }
+
+ // windows NT family services
+ else {
+ // open service manager
+ SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
+ if (mgr == NULL) {
+ // can't open service manager
+ throw XArchDaemonInstallFailed(new XArchEvalWindows);
+ }
+
+ // create the service
+ SC_HANDLE service = CreateService(mgr,
+ name,
+ name,
+ 0,
+ SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS,
+ SERVICE_AUTO_START,
+ SERVICE_ERROR_NORMAL,
+ pathname,
+ NULL,
+ NULL,
+ dependencies,
+ NULL,
+ NULL);
+ if (service == NULL) {
+ // can't create service
+ DWORD err = GetLastError();
+ if (err != ERROR_SERVICE_EXISTS) {
+ CloseServiceHandle(mgr);
+ throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
+ }
+ }
+
+ // done with service and manager
+ CloseServiceHandle(service);
+ CloseServiceHandle(mgr);
+
+ // open the registry key for this service
+ HKEY key = openNTServicesKey();
+ key = CArchMiscWindows::addKey(key, name);
+ if (key == NULL) {
+ // can't open key
+ DWORD err = GetLastError();
+ try {
+ uninstallDaemon(name, allUsers);
+ }
+ catch (...) {
+ // ignore
+ }
+ throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
+ }
+
+ // set the description
+ CArchMiscWindows::setValue(key, _T("Description"), description);
+
+ // set command line
+ key = CArchMiscWindows::addKey(key, _T("Parameters"));
+ if (key == NULL) {
+ // can't open key
+ DWORD err = GetLastError();
+ CArchMiscWindows::closeKey(key);
+ try {
+ uninstallDaemon(name, allUsers);
+ }
+ catch (...) {
+ // ignore
+ }
+ throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
+ }
+ CArchMiscWindows::setValue(key, _T("CommandLine"), commandLine);
+
+ // done with registry
+ CArchMiscWindows::closeKey(key);
+ }
+}
+
+void
+CArchDaemonWindows::uninstallDaemon(const char* name, bool allUsers)
+{
+ // if not for all users then use the user's autostart registry.
+ // key. if windows 95 family then use windows 95 services key.
+ if (!allUsers || CArchMiscWindows::isWindows95Family()) {
+ // open registry
+ HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
+ open95ServicesKey() : openUserStartupKey();
+ if (key == NULL) {
+ // can't open key. daemon is probably not installed.
+ throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows);
+ }
+
+ // remove entry
+ CArchMiscWindows::deleteValue(key, name);
+
+ // clean up
+ CArchMiscWindows::closeKey(key);
+ }
+
+ // windows NT family services
+ else {
+ // remove parameters for this service. ignore failures.
+ HKEY key = openNTServicesKey();
+ key = CArchMiscWindows::openKey(key, name);
+ if (key != NULL) {
+ CArchMiscWindows::deleteKey(key, _T("Parameters"));
+ CArchMiscWindows::closeKey(key);
+ }
+
+ // open service manager
+ SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
+ if (mgr == NULL) {
+ // can't open service manager
+ throw XArchDaemonUninstallFailed(new XArchEvalWindows);
+ }
+
+ // open the service. oddly, you must open a service to delete it.
+ SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP);
+ if (service == NULL) {
+ DWORD err = GetLastError();
+ CloseServiceHandle(mgr);
+ if (err != ERROR_SERVICE_DOES_NOT_EXIST) {
+ throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
+ }
+ throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
+ }
+
+ // stop the service. we don't care if we fail.
+ SERVICE_STATUS status;
+ ControlService(service, SERVICE_CONTROL_STOP, &status);
+
+ // delete the service
+ const bool okay = (DeleteService(service) == 0);
+ const DWORD err = GetLastError();
+
+ // clean up
+ CloseServiceHandle(service);
+ CloseServiceHandle(mgr);
+
+ // handle failure. ignore error if service isn't installed anymore.
+ if (!okay && isDaemonInstalled(name, allUsers)) {
+ if (err == ERROR_IO_PENDING) {
+ // this seems to be a spurious error
+ return;
+ }
+ if (err != ERROR_SERVICE_MARKED_FOR_DELETE) {
+ throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
+ }
+ throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
+ }
+ }
+}
+
+int
+CArchDaemonWindows::daemonize(const char* name, DaemonFunc func)
+{
+ assert(name != NULL);
+ assert(func != NULL);
+
+ // windows 95 family services
+ if (CArchMiscWindows::isWindows95Family()) {
+ typedef DWORD (WINAPI *RegisterServiceProcessT)(DWORD, DWORD);
+
+ // mark this process as a service so it's not killed when the
+ // user logs off.
+ HINSTANCE kernel = LoadLibrary("kernel32.dll");
+ if (kernel == NULL) {
+ throw XArchDaemonFailed(new XArchEvalWindows);
+ }
+ RegisterServiceProcessT RegisterServiceProcess =
+ reinterpret_cast(
+ GetProcAddress(kernel,
+ "RegisterServiceProcess"));
+ if (RegisterServiceProcess == NULL) {
+ // missing RegisterServiceProcess function
+ DWORD err = GetLastError();
+ FreeLibrary(kernel);
+ throw XArchDaemonFailed(new XArchEvalWindows(err));
+ }
+ if (RegisterServiceProcess(0, 1) == 0) {
+ // RegisterServiceProcess failed
+ DWORD err = GetLastError();
+ FreeLibrary(kernel);
+ throw XArchDaemonFailed(new XArchEvalWindows(err));
+ }
+ FreeLibrary(kernel);
+
+ // now simply call the daemon function
+ return func(1, &name);
+ }
+
+ // windows NT family services
+ else {
+ // save daemon function
+ m_daemonFunc = func;
+
+ // construct the service entry
+ SERVICE_TABLE_ENTRY entry[2];
+ entry[0].lpServiceName = const_cast(name);
+ entry[0].lpServiceProc = &CArchDaemonWindows::serviceMainEntry;
+ entry[1].lpServiceName = NULL;
+ entry[1].lpServiceProc = NULL;
+
+ // hook us up to the service control manager. this won't return
+ // (if successful) until the processes have terminated.
+ s_daemon = this;
+ if (StartServiceCtrlDispatcher(entry) == 0) {
+ // StartServiceCtrlDispatcher failed
+ s_daemon = NULL;
+ throw XArchDaemonFailed(new XArchEvalWindows);
+ }
+
+ s_daemon = NULL;
+ return m_daemonResult;
+ }
+}
+
+bool
+CArchDaemonWindows::canInstallDaemon(const char* /*name*/, bool allUsers)
+{
+ // if not for all users then use the user's autostart registry.
+ // key. if windows 95 family then use windows 95 services key.
+ if (!allUsers || CArchMiscWindows::isWindows95Family()) {
+ // check if we can open the registry key
+ HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
+ open95ServicesKey() : openUserStartupKey();
+ CArchMiscWindows::closeKey(key);
+ return (key != NULL);
+ }
+
+ // windows NT family services
+ else {
+ // check if we can open service manager for write
+ SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
+ if (mgr == NULL) {
+ return false;
+ }
+ CloseServiceHandle(mgr);
+
+ // check if we can open the registry key
+ HKEY key = openNTServicesKey();
+// key = CArchMiscWindows::addKey(key, name);
+// key = CArchMiscWindows::addKey(key, _T("Parameters"));
+ CArchMiscWindows::closeKey(key);
+
+ return (key != NULL);
+ }
+}
+
+bool
+CArchDaemonWindows::isDaemonInstalled(const char* name, bool allUsers)
+{
+ // if not for all users then use the user's autostart registry.
+ // key. if windows 95 family then use windows 95 services key.
+ if (!allUsers || CArchMiscWindows::isWindows95Family()) {
+ // check if we can open the registry key
+ HKEY key = (allUsers && CArchMiscWindows::isWindows95Family()) ?
+ open95ServicesKey() : openUserStartupKey();
+ if (key == NULL) {
+ return false;
+ }
+
+ // check for entry
+ const bool installed = !CArchMiscWindows::readValueString(key,
+ name).empty();
+
+ // clean up
+ CArchMiscWindows::closeKey(key);
+
+ return installed;
+ }
+
+ // windows NT family services
+ else {
+ // check parameters for this service
+ HKEY key = openNTServicesKey();
+ key = CArchMiscWindows::openKey(key, name);
+ key = CArchMiscWindows::openKey(key, _T("Parameters"));
+ if (key != NULL) {
+ const bool installed = !CArchMiscWindows::readValueString(key,
+ _T("CommandLine")).empty();
+ CArchMiscWindows::closeKey(key);
+ if (!installed) {
+ return false;
+ }
+ }
+
+ // open service manager
+ SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
+ if (mgr == NULL) {
+ return false;
+ }
+
+ // open the service
+ SC_HANDLE service = OpenService(mgr, name, GENERIC_READ);
+
+ // clean up
+ if (service != NULL) {
+ CloseServiceHandle(service);
+ }
+ CloseServiceHandle(mgr);
+
+ return (service != NULL);
+ }
+}
+
+HKEY
+CArchDaemonWindows::openNTServicesKey()
+{
+ static const char* s_keyNames[] = {
+ _T("SYSTEM"),
+ _T("CurrentControlSet"),
+ _T("Services"),
+ NULL
+ };
+
+ return CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
+}
+
+HKEY
+CArchDaemonWindows::open95ServicesKey()
+{
+ static const char* s_keyNames[] = {
+ _T("Software"),
+ _T("Microsoft"),
+ _T("Windows"),
+ _T("CurrentVersion"),
+ _T("RunServices"),
+ NULL
+ };
+
+ return CArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
+}
+
+HKEY
+CArchDaemonWindows::openUserStartupKey()
+{
+ static const char* s_keyNames[] = {
+ _T("Software"),
+ _T("Microsoft"),
+ _T("Windows"),
+ _T("CurrentVersion"),
+ _T("Run"),
+ NULL
+ };
+
+ return CArchMiscWindows::addKey(HKEY_CURRENT_USER, s_keyNames);
+}
+
+bool
+CArchDaemonWindows::isRunState(DWORD state)
+{
+ switch (state) {
+ case SERVICE_START_PENDING:
+ case SERVICE_CONTINUE_PENDING:
+ case SERVICE_RUNNING:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+int
+CArchDaemonWindows::doRunDaemon(RunFunc run)
+{
+ // should only be called from DaemonFunc
+ assert(m_serviceMutex != NULL);
+ assert(run != NULL);
+
+ // create message queue for this thread
+ MSG dummy;
+ PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE);
+
+ int result = 0;
+ ARCH->lockMutex(m_serviceMutex);
+ m_daemonThreadID = GetCurrentThreadId();
+ while (m_serviceState != SERVICE_STOPPED) {
+ // wait until we're told to start
+ while (!isRunState(m_serviceState) &&
+ m_serviceState != SERVICE_STOP_PENDING) {
+ ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
+ }
+
+ // run unless told to stop
+ if (m_serviceState != SERVICE_STOP_PENDING) {
+ ARCH->unlockMutex(m_serviceMutex);
+ try {
+ result = run();
+ }
+ catch (...) {
+ ARCH->lockMutex(m_serviceMutex);
+ setStatusError(0);
+ m_serviceState = SERVICE_STOPPED;
+ setStatus(m_serviceState);
+ ARCH->broadcastCondVar(m_serviceCondVar);
+ ARCH->unlockMutex(m_serviceMutex);
+ throw;
+ }
+ ARCH->lockMutex(m_serviceMutex);
+ }
+
+ // notify of new state
+ if (m_serviceState == SERVICE_PAUSE_PENDING) {
+ m_serviceState = SERVICE_PAUSED;
+ }
+ else {
+ m_serviceState = SERVICE_STOPPED;
+ }
+ setStatus(m_serviceState);
+ ARCH->broadcastCondVar(m_serviceCondVar);
+ }
+ ARCH->unlockMutex(m_serviceMutex);
+ return result;
+}
+
+void
+CArchDaemonWindows::doDaemonRunning(bool running)
+{
+ ARCH->lockMutex(m_serviceMutex);
+ if (running) {
+ m_serviceState = SERVICE_RUNNING;
+ setStatus(m_serviceState);
+ ARCH->broadcastCondVar(m_serviceCondVar);
+ }
+ ARCH->unlockMutex(m_serviceMutex);
+}
+
+UINT
+CArchDaemonWindows::doGetDaemonQuitMessage()
+{
+ return m_quitMessage;
+}
+
+void
+CArchDaemonWindows::setStatus(DWORD state)
+{
+ setStatus(state, 0, 0);
+}
+
+void
+CArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
+{
+ assert(s_daemon != NULL);
+
+ SERVICE_STATUS status;
+ status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS;
+ status.dwCurrentState = state;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_PAUSE_CONTINUE |
+ SERVICE_ACCEPT_SHUTDOWN;
+ status.dwWin32ExitCode = NO_ERROR;
+ status.dwServiceSpecificExitCode = 0;
+ status.dwCheckPoint = step;
+ status.dwWaitHint = waitHint;
+ SetServiceStatus(s_daemon->m_statusHandle, &status);
+}
+
+void
+CArchDaemonWindows::setStatusError(DWORD error)
+{
+ assert(s_daemon != NULL);
+
+ SERVICE_STATUS status;
+ status.dwServiceType = SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS;
+ status.dwCurrentState = SERVICE_STOPPED;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_PAUSE_CONTINUE |
+ SERVICE_ACCEPT_SHUTDOWN;
+ status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ status.dwServiceSpecificExitCode = error;
+ status.dwCheckPoint = 0;
+ status.dwWaitHint = 0;
+ SetServiceStatus(s_daemon->m_statusHandle, &status);
+}
+
+void
+CArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn)
+{
+ typedef std::vector ArgList;
+ typedef std::vector Arguments;
+ const char** argv = const_cast(argvIn);
+
+ // create synchronization objects
+ m_serviceMutex = ARCH->newMutex();
+ m_serviceCondVar = ARCH->newCondVar();
+
+ // register our service handler function
+ m_statusHandle = RegisterServiceCtrlHandler(argv[0],
+ &CArchDaemonWindows::serviceHandlerEntry);
+ if (m_statusHandle == 0) {
+ // cannot start as service
+ m_daemonResult = -1;
+ ARCH->closeCondVar(m_serviceCondVar);
+ ARCH->closeMutex(m_serviceMutex);
+ return;
+ }
+
+ // tell service control manager that we're starting
+ m_serviceState = SERVICE_START_PENDING;
+ setStatus(m_serviceState, 0, 10000);
+
+ // if no arguments supplied then try getting them from the registry.
+ // the first argument doesn't count because it's the service name.
+ Arguments args;
+ ArgList myArgv;
+ if (argc <= 1) {
+ // read command line
+ std::string commandLine;
+ HKEY key = openNTServicesKey();
+ key = CArchMiscWindows::openKey(key, argvIn[0]);
+ key = CArchMiscWindows::openKey(key, _T("Parameters"));
+ if (key != NULL) {
+ commandLine = CArchMiscWindows::readValueString(key,
+ _T("CommandLine"));
+ }
+
+ // if the command line isn't empty then parse and use it
+ if (!commandLine.empty()) {
+ // parse, honoring double quoted substrings
+ std::string::size_type i = commandLine.find_first_not_of(" \t");
+ while (i != std::string::npos && i != commandLine.size()) {
+ // find end of string
+ std::string::size_type e;
+ if (commandLine[i] == '\"') {
+ // quoted. find closing quote.
+ ++i;
+ e = commandLine.find("\"", i);
+
+ // whitespace must follow closing quote
+ if (e == std::string::npos ||
+ (e + 1 != commandLine.size() &&
+ commandLine[e + 1] != ' ' &&
+ commandLine[e + 1] != '\t')) {
+ args.clear();
+ break;
+ }
+
+ // extract
+ args.push_back(commandLine.substr(i, e - i));
+ i = e + 1;
+ }
+ else {
+ // unquoted. find next whitespace.
+ e = commandLine.find_first_of(" \t", i);
+ if (e == std::string::npos) {
+ e = commandLine.size();
+ }
+
+ // extract
+ args.push_back(commandLine.substr(i, e - i));
+ i = e + 1;
+ }
+
+ // next argument
+ i = commandLine.find_first_not_of(" \t", i);
+ }
+
+ // service name goes first
+ myArgv.push_back(argv[0]);
+
+ // get pointers
+ for (size_t i = 0; i < args.size(); ++i) {
+ myArgv.push_back(args[i].c_str());
+ }
+
+ // adjust argc/argv
+ argc = myArgv.size();
+ argv = &myArgv[0];
+ }
+ }
+
+ try {
+ // invoke daemon function
+ m_daemonResult = m_daemonFunc(static_cast(argc), argv);
+ }
+ catch (XArchDaemonRunFailed& e) {
+ setStatusError(e.m_result);
+ m_daemonResult = -1;
+ }
+ catch (...) {
+ setStatusError(1);
+ m_daemonResult = -1;
+ }
+
+ // clean up
+ ARCH->closeCondVar(m_serviceCondVar);
+ ARCH->closeMutex(m_serviceMutex);
+}
+
+void WINAPI
+CArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR* argv)
+{
+ s_daemon->serviceMain(argc, argv);
+}
+
+void
+CArchDaemonWindows::serviceHandler(DWORD ctrl)
+{
+ assert(m_serviceMutex != NULL);
+ assert(m_serviceCondVar != NULL);
+
+ ARCH->lockMutex(m_serviceMutex);
+
+ // ignore request if service is already stopped
+ if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) {
+ if (s_daemon != NULL) {
+ setStatus(m_serviceState);
+ }
+ ARCH->unlockMutex(m_serviceMutex);
+ return;
+ }
+
+ switch (ctrl) {
+ case SERVICE_CONTROL_PAUSE:
+ m_serviceState = SERVICE_PAUSE_PENDING;
+ setStatus(m_serviceState, 0, 5000);
+ PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
+ while (isRunState(m_serviceState)) {
+ ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
+ }
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ // FIXME -- maybe should flush quit messages from queue
+ m_serviceState = SERVICE_CONTINUE_PENDING;
+ setStatus(m_serviceState, 0, 5000);
+ ARCH->broadcastCondVar(m_serviceCondVar);
+ break;
+
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ m_serviceState = SERVICE_STOP_PENDING;
+ setStatus(m_serviceState, 0, 5000);
+ PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0);
+ ARCH->broadcastCondVar(m_serviceCondVar);
+ while (isRunState(m_serviceState)) {
+ ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0);
+ }
+ break;
+
+ default:
+ // unknown service command
+ // fall through
+
+ case SERVICE_CONTROL_INTERROGATE:
+ setStatus(m_serviceState);
+ break;
+ }
+
+ ARCH->unlockMutex(m_serviceMutex);
+}
+
+void WINAPI
+CArchDaemonWindows::serviceHandlerEntry(DWORD ctrl)
+{
+ s_daemon->serviceHandler(ctrl);
+}
diff --git a/lib/arch/CArchDaemonWindows.h b/lib/arch/CArchDaemonWindows.h
new file mode 100644
index 00000000..ed09fab9
--- /dev/null
+++ b/lib/arch/CArchDaemonWindows.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHDAEMONWINDOWS_H
+#define CARCHDAEMONWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "IArchDaemon.h"
+#include "IArchMultithread.h"
+#include "stdstring.h"
+#include
+#include
+
+#define ARCH_DAEMON CArchDaemonWindows
+
+//! Win32 implementation of IArchDaemon
+class CArchDaemonWindows : public IArchDaemon {
+public:
+ typedef int (*RunFunc)(void);
+
+ CArchDaemonWindows();
+ virtual ~CArchDaemonWindows();
+
+ //! Run the daemon
+ /*!
+ When the client calls \c daemonize(), the \c DaemonFunc should call this
+ function after initialization and argument parsing to perform the
+ daemon processing. The \c runFunc should perform the daemon's
+ main loop, calling \c daemonRunning(true) when it enters the main loop
+ (i.e. after initialization) and \c daemonRunning(false) when it leaves
+ the main loop. The \c runFunc is called in a new thread and when the
+ daemon must exit the main loop due to some external control the
+ getDaemonQuitMessage() is posted to the thread. This function returns
+ what \c runFunc returns. \c runFunc should call \c daemonFailed() if
+ the daemon fails.
+ */
+ static int runDaemon(RunFunc runFunc);
+
+ //! Indicate daemon is in main loop
+ /*!
+ The \c runFunc passed to \c runDaemon() should call this function
+ to indicate when it has entered (\c running is \c true) or exited
+ (\c running is \c false) the main loop.
+ */
+ static void daemonRunning(bool running);
+
+ //! Indicate failure of running daemon
+ /*!
+ The \c runFunc passed to \c runDaemon() should call this function
+ to indicate failure. \c result is returned by \c daemonize().
+ */
+ static void daemonFailed(int result);
+
+ //! Get daemon quit message
+ /*!
+ The windows NT daemon tells daemon thread to exit by posting this
+ message to it. The thread must, of course, have a message queue
+ for this to work.
+ */
+ static UINT getDaemonQuitMessage();
+
+ // IArchDaemon overrides
+ virtual void installDaemon(const char* name,
+ const char* description,
+ const char* pathname,
+ const char* commandLine,
+ const char* dependencies,
+ bool allUsers);
+ virtual void uninstallDaemon(const char* name, bool allUsers);
+ virtual int daemonize(const char* name, DaemonFunc func);
+ virtual bool canInstallDaemon(const char* name, bool allUsers);
+ virtual bool isDaemonInstalled(const char* name, bool allUsers);
+
+private:
+ static HKEY openNTServicesKey();
+ static HKEY open95ServicesKey();
+ static HKEY openUserStartupKey();
+
+ int doRunDaemon(RunFunc runFunc);
+ void doDaemonRunning(bool running);
+ UINT doGetDaemonQuitMessage();
+
+ static void setStatus(DWORD state);
+ static void setStatus(DWORD state, DWORD step, DWORD waitHint);
+ static void setStatusError(DWORD error);
+
+ static bool isRunState(DWORD state);
+
+ void serviceMain(DWORD, LPTSTR*);
+ static void WINAPI serviceMainEntry(DWORD, LPTSTR*);
+
+ void serviceHandler(DWORD ctrl);
+ static void WINAPI serviceHandlerEntry(DWORD ctrl);
+
+private:
+ class XArchDaemonRunFailed {
+ public:
+ XArchDaemonRunFailed(int result) : m_result(result) { }
+
+ public:
+ int m_result;
+ };
+
+private:
+ static CArchDaemonWindows* s_daemon;
+
+ CArchMutex m_serviceMutex;
+ CArchCond m_serviceCondVar;
+ DWORD m_serviceState;
+ bool m_serviceHandlerWaiting;
+ bool m_serviceRunning;
+
+ DWORD m_daemonThreadID;
+ DaemonFunc m_daemonFunc;
+ int m_daemonResult;
+
+ SERVICE_STATUS_HANDLE m_statusHandle;
+
+ UINT m_quitMessage;
+};
+
+#endif
diff --git a/lib/arch/CArchFileUnix.cpp b/lib/arch/CArchFileUnix.cpp
new file mode 100644
index 00000000..89bb51dc
--- /dev/null
+++ b/lib/arch/CArchFileUnix.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "CArchFileUnix.h"
+#include
+#include
+#include
+#include
+#include
+
+//
+// CArchFileUnix
+//
+
+CArchFileUnix::CArchFileUnix()
+{
+ // do nothing
+}
+
+CArchFileUnix::~CArchFileUnix()
+{
+ // do nothing
+}
+
+const char*
+CArchFileUnix::getBasename(const char* pathname)
+{
+ if (pathname == NULL) {
+ return NULL;
+ }
+
+ const char* basename = strrchr(pathname, '/');
+ if (basename != NULL) {
+ return basename + 1;
+ }
+ else {
+ return pathname;
+ }
+}
+
+std::string
+CArchFileUnix::getUserDirectory()
+{
+ char* buffer = NULL;
+ std::string dir;
+#if HAVE_GETPWUID_R
+ struct passwd pwent;
+ struct passwd* pwentp;
+#if defined(_SC_GETPW_R_SIZE_MAX)
+ long size = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (size == -1) {
+ size = BUFSIZ;
+ }
+#else
+ long size = BUFSIZ;
+#endif
+ buffer = new char[size];
+ getpwuid_r(getuid(), &pwent, buffer, size, &pwentp);
+#else
+ struct passwd* pwentp = getpwuid(getuid());
+#endif
+ if (pwentp != NULL && pwentp->pw_dir != NULL) {
+ dir = pwentp->pw_dir;
+ }
+ delete[] buffer;
+ return dir;
+}
+
+std::string
+CArchFileUnix::getSystemDirectory()
+{
+ return "/etc";
+}
+
+std::string
+CArchFileUnix::concatPath(const std::string& prefix,
+ const std::string& suffix)
+{
+ std::string path;
+ path.reserve(prefix.size() + 1 + suffix.size());
+ path += prefix;
+ if (path.size() == 0 || path[path.size() - 1] != '/') {
+ path += '/';
+ }
+ path += suffix;
+ return path;
+}
diff --git a/lib/arch/CArchFileUnix.h b/lib/arch/CArchFileUnix.h
new file mode 100644
index 00000000..41d00e90
--- /dev/null
+++ b/lib/arch/CArchFileUnix.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHFILEUNIX_H
+#define CARCHFILEUNIX_H
+
+#include "IArchFile.h"
+
+#define ARCH_FILE CArchFileUnix
+
+//! Unix implementation of IArchFile
+class CArchFileUnix : public IArchFile {
+public:
+ CArchFileUnix();
+ virtual ~CArchFileUnix();
+
+ // IArchFile overrides
+ virtual const char* getBasename(const char* pathname);
+ virtual std::string getUserDirectory();
+ virtual std::string getSystemDirectory();
+ virtual std::string concatPath(const std::string& prefix,
+ const std::string& suffix);
+};
+
+#endif
diff --git a/lib/arch/CArchFileWindows.cpp b/lib/arch/CArchFileWindows.cpp
new file mode 100644
index 00000000..5debb17b
--- /dev/null
+++ b/lib/arch/CArchFileWindows.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "CArchFileWindows.h"
+#include
+#include
+#include
+#include
+
+//
+// CArchFileWindows
+//
+
+CArchFileWindows::CArchFileWindows()
+{
+ // do nothing
+}
+
+CArchFileWindows::~CArchFileWindows()
+{
+ // do nothing
+}
+
+const char*
+CArchFileWindows::getBasename(const char* pathname)
+{
+ if (pathname == NULL) {
+ return NULL;
+ }
+
+ // check for last slash
+ const char* basename = strrchr(pathname, '/');
+ if (basename != NULL) {
+ ++basename;
+ }
+ else {
+ basename = pathname;
+ }
+
+ // check for last backslash
+ const char* basename2 = strrchr(pathname, '\\');
+ if (basename2 != NULL && basename2 > basename) {
+ basename = basename2 + 1;
+ }
+
+ return basename;
+}
+
+std::string
+CArchFileWindows::getUserDirectory()
+{
+ // try %HOMEPATH%
+ TCHAR dir[MAX_PATH];
+ DWORD size = sizeof(dir) / sizeof(TCHAR);
+ DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size);
+ if (result != 0 && result <= size) {
+ // sanity check -- if dir doesn't appear to start with a
+ // drive letter and isn't a UNC name then don't use it
+ // FIXME -- allow UNC names
+ if (dir[0] != '\0' && (dir[1] == ':' ||
+ ((dir[0] == '\\' || dir[0] == '/') &&
+ (dir[1] == '\\' || dir[1] == '/')))) {
+ return dir;
+ }
+ }
+
+ // get the location of the personal files. that's as close to
+ // a home directory as we're likely to find.
+ ITEMIDLIST* idl;
+ if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) {
+ TCHAR* path = NULL;
+ if (SHGetPathFromIDList(idl, dir)) {
+ DWORD attr = GetFileAttributes(dir);
+ if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ path = dir;
+ }
+
+ IMalloc* shalloc;
+ if (SUCCEEDED(SHGetMalloc(&shalloc))) {
+ shalloc->Free(idl);
+ shalloc->Release();
+ }
+
+ if (path != NULL) {
+ return path;
+ }
+ }
+
+ // use root of C drive as a default
+ return "C:";
+}
+
+std::string
+CArchFileWindows::getSystemDirectory()
+{
+ // get windows directory
+ char dir[MAX_PATH];
+ if (GetWindowsDirectory(dir, sizeof(dir)) != 0) {
+ return dir;
+ }
+ else {
+ // can't get it. use C:\ as a default.
+ return "C:";
+ }
+}
+
+std::string
+CArchFileWindows::concatPath(const std::string& prefix,
+ const std::string& suffix)
+{
+ std::string path;
+ path.reserve(prefix.size() + 1 + suffix.size());
+ path += prefix;
+ if (path.size() == 0 ||
+ (path[path.size() - 1] != '\\' &&
+ path[path.size() - 1] != '/')) {
+ path += '\\';
+ }
+ path += suffix;
+ return path;
+}
diff --git a/lib/arch/CArchFileWindows.h b/lib/arch/CArchFileWindows.h
new file mode 100644
index 00000000..617b1c40
--- /dev/null
+++ b/lib/arch/CArchFileWindows.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHFILEWINDOWS_H
+#define CARCHFILEWINDOWS_H
+
+#include "IArchFile.h"
+
+#define ARCH_FILE CArchFileWindows
+
+//! Win32 implementation of IArchFile
+class CArchFileWindows : public IArchFile {
+public:
+ CArchFileWindows();
+ virtual ~CArchFileWindows();
+
+ // IArchFile overrides
+ virtual const char* getBasename(const char* pathname);
+ virtual std::string getUserDirectory();
+ virtual std::string getSystemDirectory();
+ virtual std::string concatPath(const std::string& prefix,
+ const std::string& suffix);
+};
+
+#endif
diff --git a/lib/arch/CArchLogUnix.cpp b/lib/arch/CArchLogUnix.cpp
new file mode 100644
index 00000000..093d89f9
--- /dev/null
+++ b/lib/arch/CArchLogUnix.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "CArchLogUnix.h"
+#include
+
+//
+// CArchLogUnix
+//
+
+CArchLogUnix::CArchLogUnix()
+{
+ // do nothing
+}
+
+CArchLogUnix::~CArchLogUnix()
+{
+ // do nothing
+}
+
+void
+CArchLogUnix::openLog(const char* name)
+{
+ openlog(name, 0, LOG_DAEMON);
+}
+
+void
+CArchLogUnix::closeLog()
+{
+ closelog();
+}
+
+void
+CArchLogUnix::showLog(bool)
+{
+ // do nothing
+}
+
+void
+CArchLogUnix::writeLog(ELevel level, const char* msg)
+{
+ // convert level
+ int priority;
+ switch (level) {
+ case kERROR:
+ priority = LOG_ERR;
+ break;
+
+ case kWARNING:
+ priority = LOG_WARNING;
+ break;
+
+ case kNOTE:
+ priority = LOG_NOTICE;
+ break;
+
+ case kINFO:
+ priority = LOG_INFO;
+ break;
+
+ default:
+ priority = LOG_DEBUG;
+ break;
+ }
+
+ // log it
+ syslog(priority, "%s", msg);
+}
diff --git a/lib/arch/CArchLogUnix.h b/lib/arch/CArchLogUnix.h
new file mode 100644
index 00000000..91070b45
--- /dev/null
+++ b/lib/arch/CArchLogUnix.h
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHLOGUNIX_H
+#define CARCHLOGUNIX_H
+
+#include "IArchLog.h"
+
+#define ARCH_LOG CArchLogUnix
+
+//! Unix implementation of IArchLog
+class CArchLogUnix : public IArchLog {
+public:
+ CArchLogUnix();
+ virtual ~CArchLogUnix();
+
+ // IArchLog overrides
+ virtual void openLog(const char* name);
+ virtual void closeLog();
+ virtual void showLog(bool);
+ virtual void writeLog(ELevel, const char*);
+};
+
+#endif
diff --git a/lib/arch/CArchLogWindows.cpp b/lib/arch/CArchLogWindows.cpp
new file mode 100644
index 00000000..0ac89131
--- /dev/null
+++ b/lib/arch/CArchLogWindows.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "CArchLogWindows.h"
+#include "CArchMiscWindows.h"
+#include
+
+//
+// CArchLogWindows
+//
+
+CArchLogWindows::CArchLogWindows() : m_eventLog(NULL)
+{
+ // do nothing
+}
+
+CArchLogWindows::~CArchLogWindows()
+{
+ // do nothing
+}
+
+void
+CArchLogWindows::openLog(const char* name)
+{
+ if (m_eventLog == NULL && !CArchMiscWindows::isWindows95Family()) {
+ m_eventLog = RegisterEventSource(NULL, name);
+ }
+}
+
+void
+CArchLogWindows::closeLog()
+{
+ if (m_eventLog != NULL) {
+ DeregisterEventSource(m_eventLog);
+ m_eventLog = NULL;
+ }
+}
+
+void
+CArchLogWindows::showLog(bool)
+{
+ // do nothing
+}
+
+void
+CArchLogWindows::writeLog(ELevel level, const char* msg)
+{
+ if (m_eventLog != NULL) {
+ // convert priority
+ WORD type;
+ switch (level) {
+ case kERROR:
+ type = EVENTLOG_ERROR_TYPE;
+ break;
+
+ case kWARNING:
+ type = EVENTLOG_WARNING_TYPE;
+ break;
+
+ default:
+ type = EVENTLOG_INFORMATION_TYPE;
+ break;
+ }
+
+ // log it
+ // FIXME -- win32 wants to use a message table to look up event
+ // strings. log messages aren't organized that way so we'll
+ // just dump our string into the raw data section of the event
+ // so users can at least see the message. note that we use our
+ // level as the event category.
+ ReportEvent(m_eventLog, type, static_cast(level),
+ 0, // event ID
+ NULL,
+ 0,
+ strlen(msg) + 1, // raw data size
+ NULL,
+ const_cast(msg));// raw data
+ }
+}
diff --git a/lib/arch/CArchLogWindows.h b/lib/arch/CArchLogWindows.h
new file mode 100644
index 00000000..e8812536
--- /dev/null
+++ b/lib/arch/CArchLogWindows.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHLOGWINDOWS_H
+#define CARCHLOGWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "IArchLog.h"
+#include
+
+#define ARCH_LOG CArchLogWindows
+
+//! Win32 implementation of IArchLog
+class CArchLogWindows : public IArchLog {
+public:
+ CArchLogWindows();
+ virtual ~CArchLogWindows();
+
+ // IArchLog overrides
+ virtual void openLog(const char* name);
+ virtual void closeLog();
+ virtual void showLog(bool showIfEmpty);
+ virtual void writeLog(ELevel, const char*);
+
+private:
+ HANDLE m_eventLog;
+};
+
+#endif
diff --git a/lib/arch/CArchMiscWindows.cpp b/lib/arch/CArchMiscWindows.cpp
new file mode 100644
index 00000000..e2fb2dce
--- /dev/null
+++ b/lib/arch/CArchMiscWindows.cpp
@@ -0,0 +1,416 @@
+/*
+ * 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 "CArchMiscWindows.h"
+#include "CArchDaemonWindows.h"
+
+#ifndef ES_SYSTEM_REQUIRED
+#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001)
+#endif
+#ifndef ES_DISPLAY_REQUIRED
+#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002)
+#endif
+#ifndef ES_CONTINUOUS
+#define ES_CONTINUOUS ((DWORD)0x80000000)
+#endif
+typedef DWORD EXECUTION_STATE;
+
+//
+// CArchMiscWindows
+//
+
+CArchMiscWindows::CDialogs* CArchMiscWindows::s_dialogs = NULL;
+DWORD CArchMiscWindows::s_busyState = 0;
+CArchMiscWindows::STES_t CArchMiscWindows::s_stes = NULL;
+HICON CArchMiscWindows::s_largeIcon = NULL;
+HICON CArchMiscWindows::s_smallIcon = NULL;
+
+void
+CArchMiscWindows::init()
+{
+ s_dialogs = new CDialogs;
+ isWindows95Family();
+}
+
+bool
+CArchMiscWindows::isWindows95Family()
+{
+ static bool init = false;
+ static bool result = false;
+
+ if (!init) {
+ OSVERSIONINFO version;
+ version.dwOSVersionInfoSize = sizeof(version);
+ if (GetVersionEx(&version) == 0) {
+ // cannot determine OS; assume windows 95 family
+ result = true;
+ }
+ else {
+ result = (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
+ }
+ init = true;
+ }
+ return result;
+}
+
+bool
+CArchMiscWindows::isWindowsModern()
+{
+ static bool init = false;
+ static bool result = false;
+
+ if (!init) {
+ OSVERSIONINFO version;
+ version.dwOSVersionInfoSize = sizeof(version);
+ if (GetVersionEx(&version) == 0) {
+ // cannot determine OS; assume not modern
+ result = false;
+ }
+ else {
+ result = ((version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
+ version.dwMajorVersion == 4 &&
+ version.dwMinorVersion > 0) ||
+ (version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+ version.dwMajorVersion > 4));
+ }
+ init = true;
+ }
+ return result;
+}
+
+void
+CArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon)
+{
+ s_largeIcon = largeIcon;
+ s_smallIcon = smallIcon;
+}
+
+void
+CArchMiscWindows::getIcons(HICON& largeIcon, HICON& smallIcon)
+{
+ largeIcon = s_largeIcon;
+ smallIcon = s_smallIcon;
+}
+
+int
+CArchMiscWindows::runDaemon(RunFunc runFunc)
+{
+ return CArchDaemonWindows::runDaemon(runFunc);
+}
+
+void
+CArchMiscWindows::daemonRunning(bool running)
+{
+ CArchDaemonWindows::daemonRunning(running);
+}
+
+void
+CArchMiscWindows::daemonFailed(int result)
+{
+ CArchDaemonWindows::daemonFailed(result);
+}
+
+UINT
+CArchMiscWindows::getDaemonQuitMessage()
+{
+ return CArchDaemonWindows::getDaemonQuitMessage();
+}
+
+HKEY
+CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName)
+{
+ return openKey(key, keyName, false);
+}
+
+HKEY
+CArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames)
+{
+ return openKey(key, keyNames, false);
+}
+
+HKEY
+CArchMiscWindows::addKey(HKEY key, const TCHAR* keyName)
+{
+ return openKey(key, keyName, true);
+}
+
+HKEY
+CArchMiscWindows::addKey(HKEY key, const TCHAR* const* keyNames)
+{
+ return openKey(key, keyNames, true);
+}
+
+HKEY
+CArchMiscWindows::openKey(HKEY key, const TCHAR* keyName, bool create)
+{
+ // ignore if parent is NULL
+ if (key == NULL) {
+ return NULL;
+ }
+
+ // open next key
+ HKEY newKey;
+ LONG result = RegOpenKeyEx(key, keyName, 0,
+ KEY_WRITE | KEY_QUERY_VALUE, &newKey);
+ if (result != ERROR_SUCCESS && create) {
+ DWORD disp;
+ result = RegCreateKeyEx(key, keyName, 0, TEXT(""),
+ 0, KEY_WRITE | KEY_QUERY_VALUE,
+ NULL, &newKey, &disp);
+ }
+ if (result != ERROR_SUCCESS) {
+ RegCloseKey(key);
+ return NULL;
+ }
+
+ // switch to new key
+ RegCloseKey(key);
+ return newKey;
+}
+
+HKEY
+CArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames, bool create)
+{
+ for (size_t i = 0; key != NULL && keyNames[i] != NULL; ++i) {
+ // open next key
+ key = openKey(key, keyNames[i], create);
+ }
+ return key;
+}
+
+void
+CArchMiscWindows::closeKey(HKEY key)
+{
+ assert(key != NULL);
+ RegCloseKey(key);
+}
+
+void
+CArchMiscWindows::deleteKey(HKEY key, const TCHAR* name)
+{
+ assert(key != NULL);
+ assert(name != NULL);
+ RegDeleteKey(key, name);
+}
+
+void
+CArchMiscWindows::deleteValue(HKEY key, const TCHAR* name)
+{
+ assert(key != NULL);
+ assert(name != NULL);
+ RegDeleteValue(key, name);
+}
+
+bool
+CArchMiscWindows::hasValue(HKEY key, const TCHAR* name)
+{
+ DWORD type;
+ LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
+ return (result == ERROR_SUCCESS &&
+ (type == REG_DWORD || type == REG_SZ));
+}
+
+CArchMiscWindows::EValueType
+CArchMiscWindows::typeOfValue(HKEY key, const TCHAR* name)
+{
+ DWORD type;
+ LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
+ if (result != ERROR_SUCCESS) {
+ return kNO_VALUE;
+ }
+ switch (type) {
+ case REG_DWORD:
+ return kUINT;
+
+ case REG_SZ:
+ return kSTRING;
+
+ case REG_BINARY:
+ return kBINARY;
+
+ default:
+ return kUNKNOWN;
+ }
+}
+
+void
+CArchMiscWindows::setValue(HKEY key,
+ const TCHAR* name, const std::string& value)
+{
+ assert(key != NULL);
+ assert(name != NULL);
+ RegSetValueEx(key, name, 0, REG_SZ,
+ reinterpret_cast(value.c_str()),
+ value.size() + 1);
+}
+
+void
+CArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value)
+{
+ assert(key != NULL);
+ assert(name != NULL);
+ RegSetValueEx(key, name, 0, REG_DWORD,
+ reinterpret_cast(&value),
+ sizeof(DWORD));
+}
+
+void
+CArchMiscWindows::setValueBinary(HKEY key,
+ const TCHAR* name, const std::string& value)
+{
+ assert(key != NULL);
+ assert(name != NULL);
+ RegSetValueEx(key, name, 0, REG_BINARY,
+ reinterpret_cast(value.data()),
+ value.size());
+}
+
+std::string
+CArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR* name, DWORD type)
+{
+ // get the size of the string
+ DWORD actualType;
+ DWORD size = 0;
+ LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size);
+ if (result != ERROR_SUCCESS || actualType != type) {
+ return std::string();
+ }
+
+ // if zero size then return empty string
+ if (size == 0) {
+ return std::string();
+ }
+
+ // allocate space
+ char* buffer = new char[size];
+
+ // read it
+ result = RegQueryValueEx(key, name, 0, &actualType,
+ reinterpret_cast(buffer), &size);
+ if (result != ERROR_SUCCESS || actualType != type) {
+ delete[] buffer;
+ return std::string();
+ }
+
+ // clean up and return value
+ if (type == REG_SZ && buffer[size - 1] == '\0') {
+ // don't include terminating nul; std::string will add one.
+ --size;
+ }
+ std::string value(buffer, size);
+ delete[] buffer;
+ return value;
+}
+
+std::string
+CArchMiscWindows::readValueString(HKEY key, const TCHAR* name)
+{
+ return readBinaryOrString(key, name, REG_SZ);
+}
+
+std::string
+CArchMiscWindows::readValueBinary(HKEY key, const TCHAR* name)
+{
+ return readBinaryOrString(key, name, REG_BINARY);
+}
+
+DWORD
+CArchMiscWindows::readValueInt(HKEY key, const TCHAR* name)
+{
+ DWORD type;
+ DWORD value;
+ DWORD size = sizeof(value);
+ LONG result = RegQueryValueEx(key, name, 0, &type,
+ reinterpret_cast(&value), &size);
+ if (result != ERROR_SUCCESS || type != REG_DWORD) {
+ return 0;
+ }
+ return value;
+}
+
+void
+CArchMiscWindows::addDialog(HWND hwnd)
+{
+ s_dialogs->insert(hwnd);
+}
+
+void
+CArchMiscWindows::removeDialog(HWND hwnd)
+{
+ s_dialogs->erase(hwnd);
+}
+
+bool
+CArchMiscWindows::processDialog(MSG* msg)
+{
+ for (CDialogs::const_iterator index = s_dialogs->begin();
+ index != s_dialogs->end(); ++index) {
+ if (IsDialogMessage(*index, msg)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+CArchMiscWindows::addBusyState(DWORD busyModes)
+{
+ s_busyState |= busyModes;
+ setThreadExecutionState(s_busyState);
+}
+
+void
+CArchMiscWindows::removeBusyState(DWORD busyModes)
+{
+ s_busyState &= ~busyModes;
+ setThreadExecutionState(s_busyState);
+}
+
+void
+CArchMiscWindows::setThreadExecutionState(DWORD busyModes)
+{
+ // look up function dynamically so we work on older systems
+ if (s_stes == NULL) {
+ HINSTANCE kernel = LoadLibrary("kernel32.dll");
+ if (kernel != NULL) {
+ s_stes = reinterpret_cast(GetProcAddress(kernel,
+ "SetThreadExecutionState"));
+ }
+ if (s_stes == NULL) {
+ s_stes = &CArchMiscWindows::dummySetThreadExecutionState;
+ }
+ }
+
+ // convert to STES form
+ EXECUTION_STATE state = 0;
+ if ((busyModes & kSYSTEM) != 0) {
+ state |= ES_SYSTEM_REQUIRED;
+ }
+ if ((busyModes & kDISPLAY) != 0) {
+ state |= ES_DISPLAY_REQUIRED;
+ }
+ if (state != 0) {
+ state |= ES_CONTINUOUS;
+ }
+
+ // do it
+ s_stes(state);
+}
+
+DWORD
+CArchMiscWindows::dummySetThreadExecutionState(DWORD)
+{
+ // do nothing
+ return 0;
+}
diff --git a/lib/arch/CArchMiscWindows.h b/lib/arch/CArchMiscWindows.h
new file mode 100644
index 00000000..95a1d136
--- /dev/null
+++ b/lib/arch/CArchMiscWindows.h
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHMISCWINDOWS_H
+#define CARCHMISCWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "common.h"
+#include "stdstring.h"
+#include "stdset.h"
+#include
+
+//! Miscellaneous win32 functions.
+class CArchMiscWindows {
+public:
+ enum EValueType {
+ kUNKNOWN,
+ kNO_VALUE,
+ kUINT,
+ kSTRING,
+ kBINARY
+ };
+ enum EBusyModes {
+ kIDLE = 0x0000,
+ kSYSTEM = 0x0001,
+ kDISPLAY = 0x0002
+ };
+
+ typedef int (*RunFunc)(void);
+
+ //! Initialize
+ static void init();
+
+ //! Test if windows 95, et al.
+ /*!
+ Returns true iff the platform is win95/98/me.
+ */
+ static bool isWindows95Family();
+
+ //! Test if windows 95, et al.
+ /*!
+ Returns true iff the platform is win98 or win2k or higher (i.e.
+ not windows 95 or windows NT).
+ */
+ static bool isWindowsModern();
+
+ //! Set the application icons
+ /*!
+ Set the application icons.
+ */
+ static void setIcons(HICON largeIcon, HICON smallIcon);
+
+ //! Get the application icons
+ /*!
+ Get the application icons.
+ */
+ static void getIcons(HICON& largeIcon, HICON& smallIcon);
+
+ //! Run the daemon
+ /*!
+ Delegates to CArchDaemonWindows.
+ */
+ static int runDaemon(RunFunc runFunc);
+
+ //! Indicate daemon is in main loop
+ /*!
+ Delegates to CArchDaemonWindows.
+ */
+ static void daemonRunning(bool running);
+
+ //! Indicate failure of running daemon
+ /*!
+ Delegates to CArchDaemonWindows.
+ */
+ static void daemonFailed(int result);
+
+ //! Get daemon quit message
+ /*!
+ Delegates to CArchDaemonWindows.
+ */
+ static UINT getDaemonQuitMessage();
+
+ //! Open and return a registry key, closing the parent key
+ static HKEY openKey(HKEY parent, const TCHAR* child);
+
+ //! Open and return a registry key, closing the parent key
+ static HKEY openKey(HKEY parent, const TCHAR* const* keyPath);
+
+ //! Open/create and return a registry key, closing the parent key
+ static HKEY addKey(HKEY parent, const TCHAR* child);
+
+ //! Open/create and return a registry key, closing the parent key
+ static HKEY addKey(HKEY parent, const TCHAR* const* keyPath);
+
+ //! Close a key
+ static void closeKey(HKEY);
+
+ //! Delete a key (which should have no subkeys)
+ static void deleteKey(HKEY parent, const TCHAR* name);
+
+ //! Delete a value
+ static void deleteValue(HKEY parent, const TCHAR* name);
+
+ //! Test if a value exists
+ static bool hasValue(HKEY key, const TCHAR* name);
+
+ //! Get type of value
+ static EValueType typeOfValue(HKEY key, const TCHAR* name);
+
+ //! Set a string value in the registry
+ static void setValue(HKEY key, const TCHAR* name,
+ const std::string& value);
+
+ //! Set a DWORD value in the registry
+ static void setValue(HKEY key, const TCHAR* name, DWORD value);
+
+ //! Set a BINARY value in the registry
+ /*!
+ Sets the \p name value of \p key to \p value.data().
+ */
+ static void setValueBinary(HKEY key, const TCHAR* name,
+ const std::string& value);
+
+ //! Read a string value from the registry
+ static std::string readValueString(HKEY, const TCHAR* name);
+
+ //! Read a DWORD value from the registry
+ static DWORD readValueInt(HKEY, const TCHAR* name);
+
+ //! Read a BINARY value from the registry
+ static std::string readValueBinary(HKEY, const TCHAR* name);
+
+ //! Add a dialog
+ static void addDialog(HWND);
+
+ //! Remove a dialog
+ static void removeDialog(HWND);
+
+ //! Process dialog message
+ /*!
+ Checks if the message is destined for a dialog. If so the message
+ is passed to the dialog and returns true, otherwise returns false.
+ */
+ static bool processDialog(MSG*);
+
+ //! Disable power saving
+ static void addBusyState(DWORD busyModes);
+
+ //! Enable power saving
+ static void removeBusyState(DWORD busyModes);
+
+private:
+ //! Open and return a registry key, closing the parent key
+ static HKEY openKey(HKEY parent, const TCHAR* child, bool create);
+
+ //! Open and return a registry key, closing the parent key
+ static HKEY openKey(HKEY parent, const TCHAR* const* keyPath,
+ bool create);
+
+ //! Read a string value from the registry
+ static std::string readBinaryOrString(HKEY, const TCHAR* name, DWORD type);
+
+ //! Set thread busy state
+ static void setThreadExecutionState(DWORD);
+
+ static DWORD WINAPI dummySetThreadExecutionState(DWORD);
+
+private:
+ typedef std::set CDialogs;
+ typedef DWORD (WINAPI *STES_t)(DWORD);
+
+ static CDialogs* s_dialogs;
+ static DWORD s_busyState;
+ static STES_t s_stes;
+ static HICON s_largeIcon;
+ static HICON s_smallIcon;
+};
+
+#endif
diff --git a/lib/arch/CArchMultithreadPosix.cpp b/lib/arch/CArchMultithreadPosix.cpp
new file mode 100644
index 00000000..ec11fc50
--- /dev/null
+++ b/lib/arch/CArchMultithreadPosix.cpp
@@ -0,0 +1,806 @@
+/*
+ * 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 "CArchMultithreadPosix.h"
+#include "CArch.h"
+#include "XArch.h"
+#include
+#if TIME_WITH_SYS_TIME
+# include
+# include
+#else
+# if HAVE_SYS_TIME_H
+# include
+# else
+# include
+# endif
+#endif
+#include
+
+#define SIGWAKEUP SIGUSR1
+
+#if !HAVE_PTHREAD_SIGNAL
+ // boy, is this platform broken. forget about pthread signal
+ // handling and let signals through to every process. synergy
+ // will not terminate cleanly when it gets SIGTERM or SIGINT.
+# define pthread_sigmask sigprocmask
+# define pthread_kill(tid_, sig_) kill(0, (sig_))
+# define sigwait(set_, sig_)
+# undef HAVE_POSIX_SIGWAIT
+# define HAVE_POSIX_SIGWAIT 1
+#endif
+
+static
+void
+setSignalSet(sigset_t* sigset)
+{
+ sigemptyset(sigset);
+ sigaddset(sigset, SIGHUP);
+ sigaddset(sigset, SIGINT);
+ sigaddset(sigset, SIGTERM);
+ sigaddset(sigset, SIGUSR2);
+}
+
+//
+// CArchThreadImpl
+//
+
+class CArchThreadImpl {
+public:
+ CArchThreadImpl();
+
+public:
+ int m_refCount;
+ IArchMultithread::ThreadID m_id;
+ pthread_t m_thread;
+ IArchMultithread::ThreadFunc m_func;
+ void* m_userData;
+ bool m_cancel;
+ bool m_cancelling;
+ bool m_exited;
+ void* m_result;
+ void* m_networkData;
+};
+
+CArchThreadImpl::CArchThreadImpl() :
+ m_refCount(1),
+ m_id(0),
+ m_func(NULL),
+ m_userData(NULL),
+ m_cancel(false),
+ m_cancelling(false),
+ m_exited(false),
+ m_result(NULL),
+ m_networkData(NULL)
+{
+ // do nothing
+}
+
+
+//
+// CArchMultithreadPosix
+//
+
+CArchMultithreadPosix* CArchMultithreadPosix::s_instance = NULL;
+
+CArchMultithreadPosix::CArchMultithreadPosix() :
+ m_newThreadCalled(false),
+ m_nextID(0)
+{
+ assert(s_instance == NULL);
+
+ s_instance = this;
+
+ // no signal handlers
+ for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
+ m_signalFunc[i] = NULL;
+ m_signalUserData[i] = NULL;
+ }
+
+ // create mutex for thread list
+ m_threadMutex = newMutex();
+
+ // create thread for calling (main) thread and add it to our
+ // list. no need to lock the mutex since we're the only thread.
+ m_mainThread = new CArchThreadImpl;
+ m_mainThread->m_thread = pthread_self();
+ insert(m_mainThread);
+
+ // install SIGWAKEUP handler. this causes SIGWAKEUP to interrupt
+ // system calls. we use that when cancelling a thread to force it
+ // to wake up immediately if it's blocked in a system call. we
+ // won't need this until another thread is created but it's fine
+ // to install it now.
+ struct sigaction act;
+ sigemptyset(&act.sa_mask);
+# if defined(SA_INTERRUPT)
+ act.sa_flags = SA_INTERRUPT;
+# else
+ act.sa_flags = 0;
+# endif
+ act.sa_handler = &threadCancel;
+ sigaction(SIGWAKEUP, &act, NULL);
+
+ // set desired signal dispositions. let SIGWAKEUP through but
+ // ignore SIGPIPE (we'll handle EPIPE).
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGWAKEUP);
+ pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGPIPE);
+ pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+}
+
+CArchMultithreadPosix::~CArchMultithreadPosix()
+{
+ assert(s_instance != NULL);
+
+ closeMutex(m_threadMutex);
+ s_instance = NULL;
+}
+
+void
+CArchMultithreadPosix::setNetworkDataForCurrentThread(void* data)
+{
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = find(pthread_self());
+ thread->m_networkData = data;
+ unlockMutex(m_threadMutex);
+}
+
+void*
+CArchMultithreadPosix::getNetworkDataForThread(CArchThread thread)
+{
+ lockMutex(m_threadMutex);
+ void* data = thread->m_networkData;
+ unlockMutex(m_threadMutex);
+ return data;
+}
+
+CArchMultithreadPosix*
+CArchMultithreadPosix::getInstance()
+{
+ return s_instance;
+}
+
+CArchCond
+CArchMultithreadPosix::newCondVar()
+{
+ CArchCondImpl* cond = new CArchCondImpl;
+ int status = pthread_cond_init(&cond->m_cond, NULL);
+ (void)status;
+ assert(status == 0);
+ return cond;
+}
+
+void
+CArchMultithreadPosix::closeCondVar(CArchCond cond)
+{
+ int status = pthread_cond_destroy(&cond->m_cond);
+ (void)status;
+ assert(status == 0);
+ delete cond;
+}
+
+void
+CArchMultithreadPosix::signalCondVar(CArchCond cond)
+{
+ int status = pthread_cond_signal(&cond->m_cond);
+ (void)status;
+ assert(status == 0);
+}
+
+void
+CArchMultithreadPosix::broadcastCondVar(CArchCond cond)
+{
+ int status = pthread_cond_broadcast(&cond->m_cond);
+ (void)status;
+ assert(status == 0);
+}
+
+bool
+CArchMultithreadPosix::waitCondVar(CArchCond cond,
+ CArchMutex mutex, double timeout)
+{
+ // we can't wait on a condition variable and also wake it up for
+ // cancellation since we don't use posix cancellation. so we
+ // must wake up periodically to check for cancellation. we
+ // can't simply go back to waiting after the check since the
+ // condition may have changed and we'll have lost the signal.
+ // so we have to return to the caller. since the caller will
+ // always check for spurious wakeups the only drawback here is
+ // performance: we're waking up a lot more than desired.
+ static const double maxCancellationLatency = 0.1;
+ if (timeout < 0.0 || timeout > maxCancellationLatency) {
+ timeout = maxCancellationLatency;
+ }
+
+ // see if we should cancel this thread
+ testCancelThread();
+
+ // get final time
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ struct timespec finalTime;
+ finalTime.tv_sec = now.tv_sec;
+ finalTime.tv_nsec = now.tv_usec * 1000;
+ long timeout_sec = (long)timeout;
+ long timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec));
+ finalTime.tv_sec += timeout_sec;
+ finalTime.tv_nsec += timeout_nsec;
+ if (finalTime.tv_nsec >= 1000000000) {
+ finalTime.tv_nsec -= 1000000000;
+ finalTime.tv_sec += 1;
+ }
+
+ // wait
+ int status = pthread_cond_timedwait(&cond->m_cond,
+ &mutex->m_mutex, &finalTime);
+
+ // check for cancel again
+ testCancelThread();
+
+ switch (status) {
+ case 0:
+ // success
+ return true;
+
+ case ETIMEDOUT:
+ return false;
+
+ default:
+ assert(0 && "condition variable wait error");
+ return false;
+ }
+}
+
+CArchMutex
+CArchMultithreadPosix::newMutex()
+{
+ pthread_mutexattr_t attr;
+ int status = pthread_mutexattr_init(&attr);
+ assert(status == 0);
+ CArchMutexImpl* mutex = new CArchMutexImpl;
+ status = pthread_mutex_init(&mutex->m_mutex, &attr);
+ assert(status == 0);
+ return mutex;
+}
+
+void
+CArchMultithreadPosix::closeMutex(CArchMutex mutex)
+{
+ int status = pthread_mutex_destroy(&mutex->m_mutex);
+ (void)status;
+ assert(status == 0);
+ delete mutex;
+}
+
+void
+CArchMultithreadPosix::lockMutex(CArchMutex mutex)
+{
+ int status = pthread_mutex_lock(&mutex->m_mutex);
+
+ switch (status) {
+ case 0:
+ // success
+ return;
+
+ case EDEADLK:
+ assert(0 && "lock already owned");
+ break;
+
+ case EAGAIN:
+ assert(0 && "too many recursive locks");
+ break;
+
+ default:
+ assert(0 && "unexpected error");
+ break;
+ }
+}
+
+void
+CArchMultithreadPosix::unlockMutex(CArchMutex mutex)
+{
+ int status = pthread_mutex_unlock(&mutex->m_mutex);
+
+ switch (status) {
+ case 0:
+ // success
+ return;
+
+ case EPERM:
+ assert(0 && "thread doesn't own a lock");
+ break;
+
+ default:
+ assert(0 && "unexpected error");
+ break;
+ }
+}
+
+CArchThread
+CArchMultithreadPosix::newThread(ThreadFunc func, void* data)
+{
+ assert(func != NULL);
+
+ // initialize signal handler. we do this here instead of the
+ // constructor so we can avoid daemonizing (using fork())
+ // when there are multiple threads. clients can safely
+ // use condition variables and mutexes before creating a
+ // new thread and they can safely use the only thread
+ // they have access to, the main thread, so they really
+ // can't tell the difference.
+ if (!m_newThreadCalled) {
+ m_newThreadCalled = true;
+#if HAVE_PTHREAD_SIGNAL
+ startSignalHandler();
+#endif
+ }
+
+ lockMutex(m_threadMutex);
+
+ // create thread impl for new thread
+ CArchThreadImpl* thread = new CArchThreadImpl;
+ thread->m_func = func;
+ thread->m_userData = data;
+
+ // create the thread. pthread_create() on RedHat 7.2 smp fails
+ // if passed a NULL attr so use a default attr.
+ pthread_attr_t attr;
+ int status = pthread_attr_init(&attr);
+ if (status == 0) {
+ status = pthread_create(&thread->m_thread, &attr,
+ &CArchMultithreadPosix::threadFunc, thread);
+ pthread_attr_destroy(&attr);
+ }
+
+ // check if thread was started
+ if (status != 0) {
+ // failed to start thread so clean up
+ delete thread;
+ thread = NULL;
+ }
+ else {
+ // add thread to list
+ insert(thread);
+
+ // increment ref count to account for the thread itself
+ refThread(thread);
+ }
+
+ // note that the child thread will wait until we release this mutex
+ unlockMutex(m_threadMutex);
+
+ return thread;
+}
+
+CArchThread
+CArchMultithreadPosix::newCurrentThread()
+{
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = find(pthread_self());
+ unlockMutex(m_threadMutex);
+ assert(thread != NULL);
+ return thread;
+}
+
+void
+CArchMultithreadPosix::closeThread(CArchThread thread)
+{
+ assert(thread != NULL);
+
+ // decrement ref count and clean up thread if no more references
+ if (--thread->m_refCount == 0) {
+ // detach from thread (unless it's the main thread)
+ if (thread->m_func != NULL) {
+ pthread_detach(thread->m_thread);
+ }
+
+ // remove thread from list
+ lockMutex(m_threadMutex);
+ assert(findNoRef(thread->m_thread) == thread);
+ erase(thread);
+ unlockMutex(m_threadMutex);
+
+ // done with thread
+ delete thread;
+ }
+}
+
+CArchThread
+CArchMultithreadPosix::copyThread(CArchThread thread)
+{
+ refThread(thread);
+ return thread;
+}
+
+void
+CArchMultithreadPosix::cancelThread(CArchThread thread)
+{
+ assert(thread != NULL);
+
+ // set cancel and wakeup flags if thread can be cancelled
+ bool wakeup = false;
+ lockMutex(m_threadMutex);
+ if (!thread->m_exited && !thread->m_cancelling) {
+ thread->m_cancel = true;
+ wakeup = true;
+ }
+ unlockMutex(m_threadMutex);
+
+ // force thread to exit system calls if wakeup is true
+ if (wakeup) {
+ pthread_kill(thread->m_thread, SIGWAKEUP);
+ }
+}
+
+void
+CArchMultithreadPosix::setPriorityOfThread(CArchThread thread, int /*n*/)
+{
+ assert(thread != NULL);
+
+ // FIXME
+}
+
+void
+CArchMultithreadPosix::testCancelThread()
+{
+ // find current thread
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = findNoRef(pthread_self());
+ unlockMutex(m_threadMutex);
+
+ // test cancel on thread
+ testCancelThreadImpl(thread);
+}
+
+bool
+CArchMultithreadPosix::wait(CArchThread target, double timeout)
+{
+ assert(target != NULL);
+
+ lockMutex(m_threadMutex);
+
+ // find current thread
+ CArchThreadImpl* self = findNoRef(pthread_self());
+
+ // ignore wait if trying to wait on ourself
+ if (target == self) {
+ unlockMutex(m_threadMutex);
+ return false;
+ }
+
+ // ref the target so it can't go away while we're watching it
+ refThread(target);
+
+ unlockMutex(m_threadMutex);
+
+ try {
+ // do first test regardless of timeout
+ testCancelThreadImpl(self);
+ if (isExitedThread(target)) {
+ closeThread(target);
+ return true;
+ }
+
+ // wait and repeat test if there's a timeout
+ if (timeout != 0.0) {
+ const double start = ARCH->time();
+ do {
+ // wait a little
+ ARCH->sleep(0.05);
+
+ // repeat test
+ testCancelThreadImpl(self);
+ if (isExitedThread(target)) {
+ closeThread(target);
+ return true;
+ }
+
+ // repeat wait and test until timed out
+ } while (timeout < 0.0 || (ARCH->time() - start) <= timeout);
+ }
+
+ closeThread(target);
+ return false;
+ }
+ catch (...) {
+ closeThread(target);
+ throw;
+ }
+}
+
+bool
+CArchMultithreadPosix::isSameThread(CArchThread thread1, CArchThread thread2)
+{
+ return (thread1 == thread2);
+}
+
+bool
+CArchMultithreadPosix::isExitedThread(CArchThread thread)
+{
+ lockMutex(m_threadMutex);
+ bool exited = thread->m_exited;
+ unlockMutex(m_threadMutex);
+ return exited;
+}
+
+void*
+CArchMultithreadPosix::getResultOfThread(CArchThread thread)
+{
+ lockMutex(m_threadMutex);
+ void* result = thread->m_result;
+ unlockMutex(m_threadMutex);
+ return result;
+}
+
+IArchMultithread::ThreadID
+CArchMultithreadPosix::getIDOfThread(CArchThread thread)
+{
+ return thread->m_id;
+}
+
+void
+CArchMultithreadPosix::setSignalHandler(
+ ESignal signal, SignalFunc func, void* userData)
+{
+ lockMutex(m_threadMutex);
+ m_signalFunc[signal] = func;
+ m_signalUserData[signal] = userData;
+ unlockMutex(m_threadMutex);
+}
+
+void
+CArchMultithreadPosix::raiseSignal(ESignal signal)
+{
+ lockMutex(m_threadMutex);
+ if (m_signalFunc[signal] != NULL) {
+ m_signalFunc[signal](signal, m_signalUserData[signal]);
+ pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
+ }
+ else if (signal == kINTERRUPT || signal == kTERMINATE) {
+ ARCH->cancelThread(m_mainThread);
+ }
+ unlockMutex(m_threadMutex);
+}
+
+void
+CArchMultithreadPosix::startSignalHandler()
+{
+ // set signal mask. the main thread blocks these signals and
+ // the signal handler thread will listen for them.
+ sigset_t sigset, oldsigset;
+ setSignalSet(&sigset);
+ pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset);
+
+ // fire up the INT and TERM signal handler thread. we could
+ // instead arrange to catch and handle these signals but
+ // we'd be unable to cancel the main thread since no pthread
+ // calls are allowed in a signal handler.
+ pthread_attr_t attr;
+ int status = pthread_attr_init(&attr);
+ if (status == 0) {
+ status = pthread_create(&m_signalThread, &attr,
+ &CArchMultithreadPosix::threadSignalHandler,
+ NULL);
+ pthread_attr_destroy(&attr);
+ }
+ if (status != 0) {
+ // can't create thread to wait for signal so don't block
+ // the signals.
+ pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL);
+ }
+}
+
+CArchThreadImpl*
+CArchMultithreadPosix::find(pthread_t thread)
+{
+ CArchThreadImpl* impl = findNoRef(thread);
+ if (impl != NULL) {
+ refThread(impl);
+ }
+ return impl;
+}
+
+CArchThreadImpl*
+CArchMultithreadPosix::findNoRef(pthread_t thread)
+{
+ // linear search
+ for (CThreadList::const_iterator index = m_threadList.begin();
+ index != m_threadList.end(); ++index) {
+ if ((*index)->m_thread == thread) {
+ return *index;
+ }
+ }
+ return NULL;
+}
+
+void
+CArchMultithreadPosix::insert(CArchThreadImpl* thread)
+{
+ assert(thread != NULL);
+
+ // thread shouldn't already be on the list
+ assert(findNoRef(thread->m_thread) == NULL);
+
+ // set thread id. note that we don't worry about m_nextID
+ // wrapping back to 0 and duplicating thread ID's since the
+ // likelihood of synergy running that long is vanishingly
+ // small.
+ thread->m_id = ++m_nextID;
+
+ // append to list
+ m_threadList.push_back(thread);
+}
+
+void
+CArchMultithreadPosix::erase(CArchThreadImpl* thread)
+{
+ for (CThreadList::iterator index = m_threadList.begin();
+ index != m_threadList.end(); ++index) {
+ if (*index == thread) {
+ m_threadList.erase(index);
+ break;
+ }
+ }
+}
+
+void
+CArchMultithreadPosix::refThread(CArchThreadImpl* thread)
+{
+ assert(thread != NULL);
+ assert(findNoRef(thread->m_thread) != NULL);
+ ++thread->m_refCount;
+}
+
+void
+CArchMultithreadPosix::testCancelThreadImpl(CArchThreadImpl* thread)
+{
+ assert(thread != NULL);
+
+ // update cancel state
+ lockMutex(m_threadMutex);
+ bool cancel = false;
+ if (thread->m_cancel && !thread->m_cancelling) {
+ thread->m_cancelling = true;
+ thread->m_cancel = false;
+ cancel = true;
+ }
+ unlockMutex(m_threadMutex);
+
+ // unwind thread's stack if cancelling
+ if (cancel) {
+ throw XThreadCancel();
+ }
+}
+
+void*
+CArchMultithreadPosix::threadFunc(void* vrep)
+{
+ // get the thread
+ CArchThreadImpl* thread = reinterpret_cast(vrep);
+
+ // setup pthreads
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+
+ // run thread
+ s_instance->doThreadFunc(thread);
+
+ // terminate the thread
+ return NULL;
+}
+
+void
+CArchMultithreadPosix::doThreadFunc(CArchThread thread)
+{
+ // default priority is slightly below normal
+ setPriorityOfThread(thread, 1);
+
+ // wait for parent to initialize this object
+ lockMutex(m_threadMutex);
+ unlockMutex(m_threadMutex);
+
+ void* result = NULL;
+ try {
+ // go
+ result = (*thread->m_func)(thread->m_userData);
+ }
+
+ catch (XThreadCancel&) {
+ // client called cancel()
+ }
+ catch (...) {
+ // note -- don't catch (...) to avoid masking bugs
+ lockMutex(m_threadMutex);
+ thread->m_exited = true;
+ unlockMutex(m_threadMutex);
+ closeThread(thread);
+ throw;
+ }
+
+ // thread has exited
+ lockMutex(m_threadMutex);
+ thread->m_result = result;
+ thread->m_exited = true;
+ unlockMutex(m_threadMutex);
+
+ // done with thread
+ closeThread(thread);
+}
+
+void
+CArchMultithreadPosix::threadCancel(int)
+{
+ // do nothing
+}
+
+void*
+CArchMultithreadPosix::threadSignalHandler(void*)
+{
+ // detach
+ pthread_detach(pthread_self());
+
+ // add signal to mask
+ sigset_t sigset;
+ setSignalSet(&sigset);
+
+ // also wait on SIGABRT. on linux (others?) this thread (process)
+ // will persist after all the other threads evaporate due to an
+ // assert unless we wait on SIGABRT. that means our resources (like
+ // the socket we're listening on) are not released and never will be
+ // until the lingering thread is killed. i don't know why sigwait()
+ // should protect the thread from being killed. note that sigwait()
+ // doesn't actually return if we receive SIGABRT and, for some
+ // reason, we don't have to block SIGABRT.
+ sigaddset(&sigset, SIGABRT);
+
+ // we exit the loop via thread cancellation in sigwait()
+ for (;;) {
+ // wait
+#if HAVE_POSIX_SIGWAIT
+ int signal = 0;
+ sigwait(&sigset, &signal);
+#else
+ sigwait(&sigset);
+#endif
+
+ // if we get here then the signal was raised
+ switch (signal) {
+ case SIGINT:
+ ARCH->raiseSignal(kINTERRUPT);
+ break;
+
+ case SIGTERM:
+ ARCH->raiseSignal(kTERMINATE);
+ break;
+
+ case SIGHUP:
+ ARCH->raiseSignal(kHANGUP);
+ break;
+
+ case SIGUSR2:
+ ARCH->raiseSignal(kUSER);
+ break;
+
+ default:
+ // ignore
+ break;
+ }
+ }
+
+ return NULL;
+}
diff --git a/lib/arch/CArchMultithreadPosix.h b/lib/arch/CArchMultithreadPosix.h
new file mode 100644
index 00000000..4e587cfc
--- /dev/null
+++ b/lib/arch/CArchMultithreadPosix.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHMULTITHREADPOSIX_H
+#define CARCHMULTITHREADPOSIX_H
+
+#include "IArchMultithread.h"
+#include "stdlist.h"
+#include
+
+#define ARCH_MULTITHREAD CArchMultithreadPosix
+
+class CArchCondImpl {
+public:
+ pthread_cond_t m_cond;
+};
+
+class CArchMutexImpl {
+public:
+ pthread_mutex_t m_mutex;
+};
+
+//! Posix implementation of IArchMultithread
+class CArchMultithreadPosix : public IArchMultithread {
+public:
+ CArchMultithreadPosix();
+ virtual ~CArchMultithreadPosix();
+
+ //! @name manipulators
+ //@{
+
+ void setNetworkDataForCurrentThread(void*);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ void* getNetworkDataForThread(CArchThread);
+
+ static CArchMultithreadPosix* getInstance();
+
+ //@}
+
+ // IArchMultithread overrides
+ virtual CArchCond newCondVar();
+ virtual void closeCondVar(CArchCond);
+ virtual void signalCondVar(CArchCond);
+ virtual void broadcastCondVar(CArchCond);
+ virtual bool waitCondVar(CArchCond, CArchMutex, double timeout);
+ virtual CArchMutex newMutex();
+ virtual void closeMutex(CArchMutex);
+ virtual void lockMutex(CArchMutex);
+ virtual void unlockMutex(CArchMutex);
+ virtual CArchThread newThread(ThreadFunc, void*);
+ virtual CArchThread newCurrentThread();
+ virtual CArchThread copyThread(CArchThread);
+ virtual void closeThread(CArchThread);
+ virtual void cancelThread(CArchThread);
+ virtual void setPriorityOfThread(CArchThread, int n);
+ virtual void testCancelThread();
+ virtual bool wait(CArchThread, double timeout);
+ virtual bool isSameThread(CArchThread, CArchThread);
+ virtual bool isExitedThread(CArchThread);
+ virtual void* getResultOfThread(CArchThread);
+ virtual ThreadID getIDOfThread(CArchThread);
+ virtual void setSignalHandler(ESignal, SignalFunc, void*);
+ virtual void raiseSignal(ESignal);
+
+private:
+ void startSignalHandler();
+
+ CArchThreadImpl* find(pthread_t thread);
+ CArchThreadImpl* findNoRef(pthread_t thread);
+ void insert(CArchThreadImpl* thread);
+ void erase(CArchThreadImpl* thread);
+
+ void refThread(CArchThreadImpl* rep);
+ void testCancelThreadImpl(CArchThreadImpl* rep);
+
+ void doThreadFunc(CArchThread thread);
+ static void* threadFunc(void* vrep);
+ static void threadCancel(int);
+ static void* threadSignalHandler(void* vrep);
+
+private:
+ typedef std::list CThreadList;
+
+ static CArchMultithreadPosix* s_instance;
+
+ bool m_newThreadCalled;
+
+ CArchMutex m_threadMutex;
+ CArchThread m_mainThread;
+ CThreadList m_threadList;
+ ThreadID m_nextID;
+
+ pthread_t m_signalThread;
+ SignalFunc m_signalFunc[kNUM_SIGNALS];
+ void* m_signalUserData[kNUM_SIGNALS];
+};
+
+#endif
diff --git a/lib/arch/CArchMultithreadWindows.cpp b/lib/arch/CArchMultithreadWindows.cpp
new file mode 100644
index 00000000..3adcd46a
--- /dev/null
+++ b/lib/arch/CArchMultithreadWindows.cpp
@@ -0,0 +1,699 @@
+/*
+ * 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.
+ */
+
+#if defined(_MSC_VER) && !defined(_MT)
+# error multithreading compile option is required
+#endif
+
+#include "CArchMultithreadWindows.h"
+#include "CArch.h"
+#include "XArch.h"
+#include
+
+//
+// note -- implementation of condition variable taken from:
+// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+// titled "Strategies for Implementing POSIX Condition Variables
+// on Win32." it also provides an implementation that doesn't
+// suffer from the incorrectness problem described in our
+// corresponding header but it is slower, still unfair, and
+// can cause busy waiting.
+//
+
+//
+// CArchThreadImpl
+//
+
+class CArchThreadImpl {
+public:
+ CArchThreadImpl();
+ ~CArchThreadImpl();
+
+public:
+ int m_refCount;
+ HANDLE m_thread;
+ DWORD m_id;
+ IArchMultithread::ThreadFunc m_func;
+ void* m_userData;
+ HANDLE m_cancel;
+ bool m_cancelling;
+ HANDLE m_exit;
+ void* m_result;
+ void* m_networkData;
+};
+
+CArchThreadImpl::CArchThreadImpl() :
+ m_refCount(1),
+ m_thread(NULL),
+ m_id(0),
+ m_func(NULL),
+ m_userData(NULL),
+ m_cancelling(false),
+ m_result(NULL),
+ m_networkData(NULL)
+{
+ m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
+}
+
+CArchThreadImpl::~CArchThreadImpl()
+{
+ CloseHandle(m_exit);
+ CloseHandle(m_cancel);
+}
+
+
+//
+// CArchMultithreadWindows
+//
+
+CArchMultithreadWindows* CArchMultithreadWindows::s_instance = NULL;
+
+CArchMultithreadWindows::CArchMultithreadWindows()
+{
+ assert(s_instance == NULL);
+ s_instance = this;
+
+ // no signal handlers
+ for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
+ m_signalFunc[i] = NULL;
+ m_signalUserData[i] = NULL;
+ }
+
+ // create mutex for thread list
+ m_threadMutex = newMutex();
+
+ // create thread for calling (main) thread and add it to our
+ // list. no need to lock the mutex since we're the only thread.
+ m_mainThread = new CArchThreadImpl;
+ m_mainThread->m_thread = NULL;
+ m_mainThread->m_id = GetCurrentThreadId();
+ insert(m_mainThread);
+}
+
+CArchMultithreadWindows::~CArchMultithreadWindows()
+{
+ s_instance = NULL;
+
+ // clean up thread list
+ for (CThreadList::iterator index = m_threadList.begin();
+ index != m_threadList.end(); ++index) {
+ delete *index;
+ }
+
+ // done with mutex
+ delete m_threadMutex;
+}
+
+void
+CArchMultithreadWindows::setNetworkDataForCurrentThread(void* data)
+{
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
+ thread->m_networkData = data;
+ unlockMutex(m_threadMutex);
+}
+
+void*
+CArchMultithreadWindows::getNetworkDataForThread(CArchThread thread)
+{
+ lockMutex(m_threadMutex);
+ void* data = thread->m_networkData;
+ unlockMutex(m_threadMutex);
+ return data;
+}
+
+HANDLE
+CArchMultithreadWindows::getCancelEventForCurrentThread()
+{
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
+ unlockMutex(m_threadMutex);
+ return thread->m_cancel;
+}
+
+CArchMultithreadWindows*
+CArchMultithreadWindows::getInstance()
+{
+ return s_instance;
+}
+
+CArchCond
+CArchMultithreadWindows::newCondVar()
+{
+ CArchCondImpl* cond = new CArchCondImpl;
+ cond->m_events[CArchCondImpl::kSignal] = CreateEvent(NULL,
+ FALSE, FALSE, NULL);
+ cond->m_events[CArchCondImpl::kBroadcast] = CreateEvent(NULL,
+ TRUE, FALSE, NULL);
+ cond->m_waitCountMutex = newMutex();
+ cond->m_waitCount = 0;
+ return cond;
+}
+
+void
+CArchMultithreadWindows::closeCondVar(CArchCond cond)
+{
+ CloseHandle(cond->m_events[CArchCondImpl::kSignal]);
+ CloseHandle(cond->m_events[CArchCondImpl::kBroadcast]);
+ closeMutex(cond->m_waitCountMutex);
+ delete cond;
+}
+
+void
+CArchMultithreadWindows::signalCondVar(CArchCond cond)
+{
+ // is anybody waiting?
+ lockMutex(cond->m_waitCountMutex);
+ const bool hasWaiter = (cond->m_waitCount > 0);
+ unlockMutex(cond->m_waitCountMutex);
+
+ // wake one thread if anybody is waiting
+ if (hasWaiter) {
+ SetEvent(cond->m_events[CArchCondImpl::kSignal]);
+ }
+}
+
+void
+CArchMultithreadWindows::broadcastCondVar(CArchCond cond)
+{
+ // is anybody waiting?
+ lockMutex(cond->m_waitCountMutex);
+ const bool hasWaiter = (cond->m_waitCount > 0);
+ unlockMutex(cond->m_waitCountMutex);
+
+ // wake all threads if anybody is waiting
+ if (hasWaiter) {
+ SetEvent(cond->m_events[CArchCondImpl::kBroadcast]);
+ }
+}
+
+bool
+CArchMultithreadWindows::waitCondVar(CArchCond cond,
+ CArchMutex mutex, double timeout)
+{
+ // prepare to wait
+ const DWORD winTimeout = (timeout < 0.0) ? INFINITE :
+ static_cast(1000.0 * timeout);
+
+ // make a list of the condition variable events and the cancel event
+ // for the current thread.
+ HANDLE handles[4];
+ handles[0] = cond->m_events[CArchCondImpl::kSignal];
+ handles[1] = cond->m_events[CArchCondImpl::kBroadcast];
+ handles[2] = getCancelEventForCurrentThread();
+
+ // update waiter count
+ lockMutex(cond->m_waitCountMutex);
+ ++cond->m_waitCount;
+ unlockMutex(cond->m_waitCountMutex);
+
+ // release mutex. this should be atomic with the wait so that it's
+ // impossible for another thread to signal us between the unlock and
+ // the wait, which would lead to a lost signal on broadcasts.
+ // however, we're using a manual reset event for broadcasts which
+ // stays set until we reset it, so we don't lose the broadcast.
+ unlockMutex(mutex);
+
+ // wait for a signal or broadcast
+ DWORD result = WaitForMultipleObjects(3, handles, FALSE, winTimeout);
+
+ // cancel takes priority
+ if (result != WAIT_OBJECT_0 + 2 &&
+ WaitForSingleObject(handles[2], 0) == WAIT_OBJECT_0) {
+ result = WAIT_OBJECT_0 + 2;
+ }
+
+ // update the waiter count and check if we're the last waiter
+ lockMutex(cond->m_waitCountMutex);
+ --cond->m_waitCount;
+ const bool last = (result == WAIT_OBJECT_0 + 1 && cond->m_waitCount == 0);
+ unlockMutex(cond->m_waitCountMutex);
+
+ // reset the broadcast event if we're the last waiter
+ if (last) {
+ ResetEvent(cond->m_events[CArchCondImpl::kBroadcast]);
+ }
+
+ // reacquire the mutex
+ lockMutex(mutex);
+
+ // cancel thread if necessary
+ if (result == WAIT_OBJECT_0 + 2) {
+ ARCH->testCancelThread();
+ }
+
+ // return success or failure
+ return (result == WAIT_OBJECT_0 + 0 ||
+ result == WAIT_OBJECT_0 + 1);
+}
+
+CArchMutex
+CArchMultithreadWindows::newMutex()
+{
+ CArchMutexImpl* mutex = new CArchMutexImpl;
+ InitializeCriticalSection(&mutex->m_mutex);
+ return mutex;
+}
+
+void
+CArchMultithreadWindows::closeMutex(CArchMutex mutex)
+{
+ DeleteCriticalSection(&mutex->m_mutex);
+ delete mutex;
+}
+
+void
+CArchMultithreadWindows::lockMutex(CArchMutex mutex)
+{
+ EnterCriticalSection(&mutex->m_mutex);
+}
+
+void
+CArchMultithreadWindows::unlockMutex(CArchMutex mutex)
+{
+ LeaveCriticalSection(&mutex->m_mutex);
+}
+
+CArchThread
+CArchMultithreadWindows::newThread(ThreadFunc func, void* data)
+{
+ lockMutex(m_threadMutex);
+
+ // create thread impl for new thread
+ CArchThreadImpl* thread = new CArchThreadImpl;
+ thread->m_func = func;
+ thread->m_userData = data;
+
+ // create thread
+ unsigned int id;
+ thread->m_thread = reinterpret_cast(_beginthreadex(NULL, 0,
+ threadFunc, (void*)thread, 0, &id));
+ thread->m_id = static_cast(id);
+
+ // check if thread was started
+ if (thread->m_thread == 0) {
+ // failed to start thread so clean up
+ delete thread;
+ thread = NULL;
+ }
+ else {
+ // add thread to list
+ insert(thread);
+
+ // increment ref count to account for the thread itself
+ refThread(thread);
+ }
+
+ // note that the child thread will wait until we release this mutex
+ unlockMutex(m_threadMutex);
+
+ return thread;
+}
+
+CArchThread
+CArchMultithreadWindows::newCurrentThread()
+{
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = find(GetCurrentThreadId());
+ unlockMutex(m_threadMutex);
+ assert(thread != NULL);
+ return thread;
+}
+
+void
+CArchMultithreadWindows::closeThread(CArchThread thread)
+{
+ assert(thread != NULL);
+
+ // decrement ref count and clean up thread if no more references
+ if (--thread->m_refCount == 0) {
+ // close the handle (main thread has a NULL handle)
+ if (thread->m_thread != NULL) {
+ CloseHandle(thread->m_thread);
+ }
+
+ // remove thread from list
+ lockMutex(m_threadMutex);
+ assert(findNoRefOrCreate(thread->m_id) == thread);
+ erase(thread);
+ unlockMutex(m_threadMutex);
+
+ // done with thread
+ delete thread;
+ }
+}
+
+CArchThread
+CArchMultithreadWindows::copyThread(CArchThread thread)
+{
+ refThread(thread);
+ return thread;
+}
+
+void
+CArchMultithreadWindows::cancelThread(CArchThread thread)
+{
+ assert(thread != NULL);
+
+ // set cancel flag
+ SetEvent(thread->m_cancel);
+}
+
+void
+CArchMultithreadWindows::setPriorityOfThread(CArchThread thread, int n)
+{
+ struct CPriorityInfo {
+ public:
+ DWORD m_class;
+ int m_level;
+ };
+ static const CPriorityInfo s_pClass[] = {
+ { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_IDLE },
+ { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
+ { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
+ { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
+ { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
+ { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
+ { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
+ { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
+ { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
+ { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
+ { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
+ { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
+ { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
+ { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
+ { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
+ { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_IDLE },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST },
+ { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL}
+ };
+#if defined(_DEBUG)
+ // don't use really high priorities when debugging
+ static const size_t s_pMax = 13;
+#else
+ static const size_t s_pMax = sizeof(s_pClass) / sizeof(s_pClass[0]) - 1;
+#endif
+ static const size_t s_pBase = 8; // index of normal priority
+
+ assert(thread != NULL);
+
+ size_t index;
+ if (n > 0 && s_pBase < (size_t)n) {
+ // lowest priority
+ index = 0;
+ }
+ else {
+ index = (size_t)((int)s_pBase - n);
+ if (index > s_pMax) {
+ // highest priority
+ index = s_pMax;
+ }
+ }
+ SetPriorityClass(GetCurrentProcess(), s_pClass[index].m_class);
+ SetThreadPriority(thread->m_thread, s_pClass[index].m_level);
+}
+
+void
+CArchMultithreadWindows::testCancelThread()
+{
+ // find current thread
+ lockMutex(m_threadMutex);
+ CArchThreadImpl* thread = findNoRef(GetCurrentThreadId());
+ unlockMutex(m_threadMutex);
+
+ // test cancel on thread
+ testCancelThreadImpl(thread);
+}
+
+bool
+CArchMultithreadWindows::wait(CArchThread target, double timeout)
+{
+ assert(target != NULL);
+
+ lockMutex(m_threadMutex);
+
+ // find current thread
+ CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
+
+ // ignore wait if trying to wait on ourself
+ if (target == self) {
+ unlockMutex(m_threadMutex);
+ return false;
+ }
+
+ // ref the target so it can't go away while we're watching it
+ refThread(target);
+
+ unlockMutex(m_threadMutex);
+
+ // convert timeout
+ DWORD t;
+ if (timeout < 0.0) {
+ t = INFINITE;
+ }
+ else {
+ t = (DWORD)(1000.0 * timeout);
+ }
+
+ // wait for this thread to be cancelled or woken up or for the
+ // target thread to terminate.
+ HANDLE handles[2];
+ handles[0] = target->m_exit;
+ handles[1] = self->m_cancel;
+ DWORD result = WaitForMultipleObjects(2, handles, FALSE, t);
+
+ // cancel takes priority
+ if (result != WAIT_OBJECT_0 + 1 &&
+ WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) {
+ result = WAIT_OBJECT_0 + 1;
+ }
+
+ // release target
+ closeThread(target);
+
+ // handle result
+ switch (result) {
+ case WAIT_OBJECT_0 + 0:
+ // target thread terminated
+ return true;
+
+ case WAIT_OBJECT_0 + 1:
+ // this thread was cancelled. does not return.
+ testCancelThreadImpl(self);
+
+ default:
+ // timeout or error
+ return false;
+ }
+}
+
+bool
+CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
+{
+ return (thread1 == thread2);
+}
+
+bool
+CArchMultithreadWindows::isExitedThread(CArchThread thread)
+{
+ // poll exit event
+ return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0);
+}
+
+void*
+CArchMultithreadWindows::getResultOfThread(CArchThread thread)
+{
+ lockMutex(m_threadMutex);
+ void* result = thread->m_result;
+ unlockMutex(m_threadMutex);
+ return result;
+}
+
+IArchMultithread::ThreadID
+CArchMultithreadWindows::getIDOfThread(CArchThread thread)
+{
+ return static_cast(thread->m_id);
+}
+
+void
+CArchMultithreadWindows::setSignalHandler(
+ ESignal signal, SignalFunc func, void* userData)
+{
+ lockMutex(m_threadMutex);
+ m_signalFunc[signal] = func;
+ m_signalUserData[signal] = userData;
+ unlockMutex(m_threadMutex);
+}
+
+void
+CArchMultithreadWindows::raiseSignal(ESignal signal)
+{
+ lockMutex(m_threadMutex);
+ if (m_signalFunc[signal] != NULL) {
+ m_signalFunc[signal](signal, m_signalUserData[signal]);
+ ARCH->unblockPollSocket(m_mainThread);
+ }
+ else if (signal == kINTERRUPT || signal == kTERMINATE) {
+ ARCH->cancelThread(m_mainThread);
+ }
+ unlockMutex(m_threadMutex);
+}
+
+CArchThreadImpl*
+CArchMultithreadWindows::find(DWORD id)
+{
+ CArchThreadImpl* impl = findNoRef(id);
+ if (impl != NULL) {
+ refThread(impl);
+ }
+ return impl;
+}
+
+CArchThreadImpl*
+CArchMultithreadWindows::findNoRef(DWORD id)
+{
+ CArchThreadImpl* impl = findNoRefOrCreate(id);
+ if (impl == NULL) {
+ // create thread for calling thread which isn't in our list and
+ // add it to the list. this won't normally happen but it can if
+ // the system calls us under a new thread, like it does when we
+ // run as a service.
+ impl = new CArchThreadImpl;
+ impl->m_thread = NULL;
+ impl->m_id = GetCurrentThreadId();
+ insert(impl);
+ }
+ return impl;
+}
+
+CArchThreadImpl*
+CArchMultithreadWindows::findNoRefOrCreate(DWORD id)
+{
+ // linear search
+ for (CThreadList::const_iterator index = m_threadList.begin();
+ index != m_threadList.end(); ++index) {
+ if ((*index)->m_id == id) {
+ return *index;
+ }
+ }
+ return NULL;
+}
+
+void
+CArchMultithreadWindows::insert(CArchThreadImpl* thread)
+{
+ assert(thread != NULL);
+
+ // thread shouldn't already be on the list
+ assert(findNoRefOrCreate(thread->m_id) == NULL);
+
+ // append to list
+ m_threadList.push_back(thread);
+}
+
+void
+CArchMultithreadWindows::erase(CArchThreadImpl* thread)
+{
+ for (CThreadList::iterator index = m_threadList.begin();
+ index != m_threadList.end(); ++index) {
+ if (*index == thread) {
+ m_threadList.erase(index);
+ break;
+ }
+ }
+}
+
+void
+CArchMultithreadWindows::refThread(CArchThreadImpl* thread)
+{
+ assert(thread != NULL);
+ assert(findNoRefOrCreate(thread->m_id) != NULL);
+ ++thread->m_refCount;
+}
+
+void
+CArchMultithreadWindows::testCancelThreadImpl(CArchThreadImpl* thread)
+{
+ assert(thread != NULL);
+
+ // poll cancel event. return if not set.
+ const DWORD result = WaitForSingleObject(thread->m_cancel, 0);
+ if (result != WAIT_OBJECT_0) {
+ return;
+ }
+
+ // update cancel state
+ lockMutex(m_threadMutex);
+ bool cancel = !thread->m_cancelling;
+ thread->m_cancelling = true;
+ ResetEvent(thread->m_cancel);
+ unlockMutex(m_threadMutex);
+
+ // unwind thread's stack if cancelling
+ if (cancel) {
+ throw XThreadCancel();
+ }
+}
+
+unsigned int __stdcall
+CArchMultithreadWindows::threadFunc(void* vrep)
+{
+ // get the thread
+ CArchThreadImpl* thread = reinterpret_cast(vrep);
+
+ // run thread
+ s_instance->doThreadFunc(thread);
+
+ // terminate the thread
+ return 0;
+}
+
+void
+CArchMultithreadWindows::doThreadFunc(CArchThread thread)
+{
+ // wait for parent to initialize this object
+ lockMutex(m_threadMutex);
+ unlockMutex(m_threadMutex);
+
+ void* result = NULL;
+ try {
+ // go
+ result = (*thread->m_func)(thread->m_userData);
+ }
+
+ catch (XThreadCancel&) {
+ // client called cancel()
+ }
+ catch (...) {
+ // note -- don't catch (...) to avoid masking bugs
+ SetEvent(thread->m_exit);
+ closeThread(thread);
+ throw;
+ }
+
+ // thread has exited
+ lockMutex(m_threadMutex);
+ thread->m_result = result;
+ unlockMutex(m_threadMutex);
+ SetEvent(thread->m_exit);
+
+ // done with thread
+ closeThread(thread);
+}
diff --git a/lib/arch/CArchMultithreadWindows.h b/lib/arch/CArchMultithreadWindows.h
new file mode 100644
index 00000000..d009c842
--- /dev/null
+++ b/lib/arch/CArchMultithreadWindows.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHMULTITHREADWINDOWS_H
+#define CARCHMULTITHREADWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "IArchMultithread.h"
+#include "stdlist.h"
+#include
+
+#define ARCH_MULTITHREAD CArchMultithreadWindows
+
+class CArchCondImpl {
+public:
+ enum { kSignal = 0, kBroadcast };
+
+ HANDLE m_events[2];
+ mutable int m_waitCount;
+ CArchMutex m_waitCountMutex;
+};
+
+class CArchMutexImpl {
+public:
+ CRITICAL_SECTION m_mutex;
+};
+
+//! Win32 implementation of IArchMultithread
+class CArchMultithreadWindows : public IArchMultithread {
+public:
+ CArchMultithreadWindows();
+ virtual ~CArchMultithreadWindows();
+
+ //! @name manipulators
+ //@{
+
+ void setNetworkDataForCurrentThread(void*);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ HANDLE getCancelEventForCurrentThread();
+
+ void* getNetworkDataForThread(CArchThread);
+
+ static CArchMultithreadWindows* getInstance();
+
+ //@}
+
+ // IArchMultithread overrides
+ virtual CArchCond newCondVar();
+ virtual void closeCondVar(CArchCond);
+ virtual void signalCondVar(CArchCond);
+ virtual void broadcastCondVar(CArchCond);
+ virtual bool waitCondVar(CArchCond, CArchMutex, double timeout);
+ virtual CArchMutex newMutex();
+ virtual void closeMutex(CArchMutex);
+ virtual void lockMutex(CArchMutex);
+ virtual void unlockMutex(CArchMutex);
+ virtual CArchThread newThread(ThreadFunc, void*);
+ virtual CArchThread newCurrentThread();
+ virtual CArchThread copyThread(CArchThread);
+ virtual void closeThread(CArchThread);
+ virtual void cancelThread(CArchThread);
+ virtual void setPriorityOfThread(CArchThread, int n);
+ virtual void testCancelThread();
+ virtual bool wait(CArchThread, double timeout);
+ virtual bool isSameThread(CArchThread, CArchThread);
+ virtual bool isExitedThread(CArchThread);
+ virtual void* getResultOfThread(CArchThread);
+ virtual ThreadID getIDOfThread(CArchThread);
+ virtual void setSignalHandler(ESignal, SignalFunc, void*);
+ virtual void raiseSignal(ESignal);
+
+private:
+ CArchThreadImpl* find(DWORD id);
+ CArchThreadImpl* findNoRef(DWORD id);
+ CArchThreadImpl* findNoRefOrCreate(DWORD id);
+ void insert(CArchThreadImpl* thread);
+ void erase(CArchThreadImpl* thread);
+
+ void refThread(CArchThreadImpl* rep);
+ void testCancelThreadImpl(CArchThreadImpl* rep);
+
+ void doThreadFunc(CArchThread thread);
+ static unsigned int __stdcall threadFunc(void* vrep);
+
+private:
+ typedef std::list CThreadList;
+
+ static CArchMultithreadWindows* s_instance;
+
+ CArchMutex m_threadMutex;
+
+ CThreadList m_threadList;
+ CArchThread m_mainThread;
+
+ SignalFunc m_signalFunc[kNUM_SIGNALS];
+ void* m_signalUserData[kNUM_SIGNALS];
+};
+
+#endif
diff --git a/lib/arch/CArchNetworkBSD.cpp b/lib/arch/CArchNetworkBSD.cpp
new file mode 100644
index 00000000..af474e86
--- /dev/null
+++ b/lib/arch/CArchNetworkBSD.cpp
@@ -0,0 +1,974 @@
+/*
+ * 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 "CArchNetworkBSD.h"
+#include "CArch.h"
+#include "CArchMultithreadPosix.h"
+#include "XArchUnix.h"
+#if HAVE_UNISTD_H
+# include
+#endif
+#include
+#include
+#if !defined(TCP_NODELAY)
+# include
+#endif
+#include
+#include
+#include
+#include
+
+#if HAVE_POLL
+# include
+#else
+# if HAVE_SYS_SELECT_H
+# include
+# endif
+# if HAVE_SYS_TIME_H
+# include
+# endif
+#endif
+
+#if !HAVE_INET_ATON
+# include
+#endif
+
+static const int s_family[] = {
+ PF_UNSPEC,
+ PF_INET
+};
+static const int s_type[] = {
+ SOCK_DGRAM,
+ SOCK_STREAM
+};
+
+#if !HAVE_INET_ATON
+// parse dotted quad addresses. we don't bother with the weird BSD'ism
+// of handling octal and hex and partial forms.
+static
+in_addr_t
+inet_aton(const char* cp, struct in_addr* inp)
+{
+ unsigned int a, b, c, d;
+ if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
+ return 0;
+ }
+ if (a >= 256 || b >= 256 || c >= 256 || d >= 256) {
+ return 0;
+ }
+ unsigned char* incp = (unsigned char*)inp;
+ incp[0] = (unsigned char)(a & 0xffu);
+ incp[1] = (unsigned char)(b & 0xffu);
+ incp[2] = (unsigned char)(c & 0xffu);
+ incp[3] = (unsigned char)(d & 0xffu);
+ return inp->s_addr;
+}
+#endif
+
+//
+// CArchNetworkBSD
+//
+
+CArchNetworkBSD::CArchNetworkBSD()
+{
+ // create mutex to make some calls thread safe
+ m_mutex = ARCH->newMutex();
+}
+
+CArchNetworkBSD::~CArchNetworkBSD()
+{
+ ARCH->closeMutex(m_mutex);
+}
+
+CArchSocket
+CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
+{
+ // create socket
+ int fd = socket(s_family[family], s_type[type], 0);
+ if (fd == -1) {
+ throwError(errno);
+ }
+ try {
+ setBlockingOnSocket(fd, false);
+ }
+ catch (...) {
+ close(fd);
+ throw;
+ }
+
+ // allocate socket object
+ CArchSocketImpl* newSocket = new CArchSocketImpl;
+ newSocket->m_fd = fd;
+ newSocket->m_refCount = 1;
+ return newSocket;
+}
+
+CArchSocket
+CArchNetworkBSD::copySocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // ref the socket and return it
+ ARCH->lockMutex(m_mutex);
+ ++s->m_refCount;
+ ARCH->unlockMutex(m_mutex);
+ return s;
+}
+
+void
+CArchNetworkBSD::closeSocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // unref the socket and note if it should be released
+ ARCH->lockMutex(m_mutex);
+ const bool doClose = (--s->m_refCount == 0);
+ ARCH->unlockMutex(m_mutex);
+
+ // close the socket if necessary
+ if (doClose) {
+ if (close(s->m_fd) == -1) {
+ // close failed. restore the last ref and throw.
+ int err = errno;
+ ARCH->lockMutex(m_mutex);
+ ++s->m_refCount;
+ ARCH->unlockMutex(m_mutex);
+ throwError(err);
+ }
+ delete s;
+ }
+}
+
+void
+CArchNetworkBSD::closeSocketForRead(CArchSocket s)
+{
+ assert(s != NULL);
+
+ if (shutdown(s->m_fd, 0) == -1) {
+ if (errno != ENOTCONN) {
+ throwError(errno);
+ }
+ }
+}
+
+void
+CArchNetworkBSD::closeSocketForWrite(CArchSocket s)
+{
+ assert(s != NULL);
+
+ if (shutdown(s->m_fd, 1) == -1) {
+ if (errno != ENOTCONN) {
+ throwError(errno);
+ }
+ }
+}
+
+void
+CArchNetworkBSD::bindSocket(CArchSocket s, CArchNetAddress addr)
+{
+ assert(s != NULL);
+ assert(addr != NULL);
+
+ if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
+ throwError(errno);
+ }
+}
+
+void
+CArchNetworkBSD::listenOnSocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // hardcoding backlog
+ if (listen(s->m_fd, 3) == -1) {
+ throwError(errno);
+ }
+}
+
+CArchSocket
+CArchNetworkBSD::acceptSocket(CArchSocket s, CArchNetAddress* addr)
+{
+ assert(s != NULL);
+
+ // if user passed NULL in addr then use scratch space
+ CArchNetAddress dummy;
+ if (addr == NULL) {
+ addr = &dummy;
+ }
+
+ // create new socket and address
+ CArchSocketImpl* newSocket = new CArchSocketImpl;
+ *addr = new CArchNetAddressImpl;
+
+ // accept on socket
+ ACCEPT_TYPE_ARG3 len = (ACCEPT_TYPE_ARG3)((*addr)->m_len);
+ int fd = accept(s->m_fd, &(*addr)->m_addr, &len);
+ (*addr)->m_len = (socklen_t)len;
+ if (fd == -1) {
+ int err = errno;
+ delete newSocket;
+ delete *addr;
+ *addr = NULL;
+ if (err == EAGAIN) {
+ return NULL;
+ }
+ throwError(err);
+ }
+
+ try {
+ setBlockingOnSocket(fd, false);
+ }
+ catch (...) {
+ close(fd);
+ delete newSocket;
+ delete *addr;
+ *addr = NULL;
+ throw;
+ }
+
+ // initialize socket
+ newSocket->m_fd = fd;
+ newSocket->m_refCount = 1;
+
+ // discard address if not requested
+ if (addr == &dummy) {
+ ARCH->closeAddr(dummy);
+ }
+
+ return newSocket;
+}
+
+bool
+CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
+{
+ assert(s != NULL);
+ assert(addr != NULL);
+
+ if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
+ if (errno == EISCONN) {
+ return true;
+ }
+ if (errno == EINPROGRESS) {
+ return false;
+ }
+ throwError(errno);
+ }
+ return true;
+}
+
+#if HAVE_POLL
+
+int
+CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
+{
+ assert(pe != NULL || num == 0);
+
+ // return if nothing to do
+ if (num == 0) {
+ if (timeout > 0.0) {
+ ARCH->sleep(timeout);
+ }
+ return 0;
+ }
+
+ // allocate space for translated query
+ struct pollfd* pfd = new struct pollfd[1 + num];
+
+ // translate query
+ for (int i = 0; i < num; ++i) {
+ pfd[i].fd = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd;
+ pfd[i].events = 0;
+ if ((pe[i].m_events & kPOLLIN) != 0) {
+ pfd[i].events |= POLLIN;
+ }
+ if ((pe[i].m_events & kPOLLOUT) != 0) {
+ pfd[i].events |= POLLOUT;
+ }
+ }
+ int n = num;
+
+ // add the unblock pipe
+ const int* unblockPipe = getUnblockPipe();
+ if (unblockPipe != NULL) {
+ pfd[n].fd = unblockPipe[0];
+ pfd[n].events = POLLIN;
+ ++n;
+ }
+
+ // prepare timeout
+ int t = (timeout < 0.0) ? -1 : static_cast(1000.0 * timeout);
+
+ // do the poll
+ n = poll(pfd, n, t);
+
+ // reset the unblock pipe
+ if (n > 0 && unblockPipe != NULL && (pfd[num].revents & POLLIN) != 0) {
+ // the unblock event was signalled. flush the pipe.
+ char dummy[100];
+ do {
+ read(unblockPipe[0], dummy, sizeof(dummy));
+ } while (errno != EAGAIN);
+
+ // don't count this unblock pipe in return value
+ --n;
+ }
+
+ // handle results
+ if (n == -1) {
+ if (errno == EINTR) {
+ // interrupted system call
+ ARCH->testCancelThread();
+ delete[] pfd;
+ return 0;
+ }
+ delete[] pfd;
+ throwError(errno);
+ }
+
+ // translate back
+ for (int i = 0; i < num; ++i) {
+ pe[i].m_revents = 0;
+ if ((pfd[i].revents & POLLIN) != 0) {
+ pe[i].m_revents |= kPOLLIN;
+ }
+ if ((pfd[i].revents & POLLOUT) != 0) {
+ pe[i].m_revents |= kPOLLOUT;
+ }
+ if ((pfd[i].revents & POLLERR) != 0) {
+ pe[i].m_revents |= kPOLLERR;
+ }
+ if ((pfd[i].revents & POLLNVAL) != 0) {
+ pe[i].m_revents |= kPOLLNVAL;
+ }
+ }
+
+ delete[] pfd;
+ return n;
+}
+
+#else
+
+int
+CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
+{
+ int i, n;
+
+ // prepare sets for select
+ n = 0;
+ fd_set readSet, writeSet, errSet;
+ fd_set* readSetP = NULL;
+ fd_set* writeSetP = NULL;
+ fd_set* errSetP = NULL;
+ FD_ZERO(&readSet);
+ FD_ZERO(&writeSet);
+ FD_ZERO(&errSet);
+ for (i = 0; i < num; ++i) {
+ // reset return flags
+ pe[i].m_revents = 0;
+
+ // set invalid flag if socket is bogus then go to next socket
+ if (pe[i].m_socket == NULL) {
+ pe[i].m_revents |= kPOLLNVAL;
+ continue;
+ }
+
+ int fdi = pe[i].m_socket->m_fd;
+ if (pe[i].m_events & kPOLLIN) {
+ FD_SET(pe[i].m_socket->m_fd, &readSet);
+ readSetP = &readSet;
+ if (fdi > n) {
+ n = fdi;
+ }
+ }
+ if (pe[i].m_events & kPOLLOUT) {
+ FD_SET(pe[i].m_socket->m_fd, &writeSet);
+ writeSetP = &writeSet;
+ if (fdi > n) {
+ n = fdi;
+ }
+ }
+ if (true) {
+ FD_SET(pe[i].m_socket->m_fd, &errSet);
+ errSetP = &errSet;
+ if (fdi > n) {
+ n = fdi;
+ }
+ }
+ }
+
+ // add the unblock pipe
+ const int* unblockPipe = getUnblockPipe();
+ if (unblockPipe != NULL) {
+ FD_SET(unblockPipe[0], &readSet);
+ readSetP = &readSet;
+ if (unblockPipe[0] > n) {
+ n = unblockPipe[0];
+ }
+ }
+
+ // if there are no sockets then don't block forever
+ if (n == 0 && timeout < 0.0) {
+ timeout = 0.0;
+ }
+
+ // prepare timeout for select
+ struct timeval timeout2;
+ struct timeval* timeout2P;
+ if (timeout < 0.0) {
+ timeout2P = NULL;
+ }
+ else {
+ timeout2P = &timeout2;
+ timeout2.tv_sec = static_cast(timeout);
+ timeout2.tv_usec = static_cast(1.0e+6 *
+ (timeout - timeout2.tv_sec));
+ }
+
+ // do the select
+ n = select((SELECT_TYPE_ARG1) n + 1,
+ SELECT_TYPE_ARG234 readSetP,
+ SELECT_TYPE_ARG234 writeSetP,
+ SELECT_TYPE_ARG234 errSetP,
+ SELECT_TYPE_ARG5 timeout2P);
+
+ // reset the unblock pipe
+ if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) {
+ // the unblock event was signalled. flush the pipe.
+ char dummy[100];
+ do {
+ read(unblockPipe[0], dummy, sizeof(dummy));
+ } while (errno != EAGAIN);
+ }
+
+ // handle results
+ if (n == -1) {
+ if (errno == EINTR) {
+ // interrupted system call
+ ARCH->testCancelThread();
+ return 0;
+ }
+ throwError(errno);
+ }
+ n = 0;
+ for (i = 0; i < num; ++i) {
+ if (pe[i].m_socket != NULL) {
+ if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
+ pe[i].m_revents |= kPOLLIN;
+ }
+ if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
+ pe[i].m_revents |= kPOLLOUT;
+ }
+ if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
+ pe[i].m_revents |= kPOLLERR;
+ }
+ }
+ if (pe[i].m_revents != 0) {
+ ++n;
+ }
+ }
+
+ return n;
+}
+
+#endif
+
+void
+CArchNetworkBSD::unblockPollSocket(CArchThread thread)
+{
+ const int* unblockPipe = getUnblockPipeForThread(thread);
+ if (unblockPipe != NULL) {
+ char dummy = 0;
+ write(unblockPipe[1], &dummy, 1);
+ }
+}
+
+size_t
+CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
+{
+ assert(s != NULL);
+
+ ssize_t n = read(s->m_fd, buf, len);
+ if (n == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ return 0;
+ }
+ throwError(errno);
+ }
+ return n;
+}
+
+size_t
+CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
+{
+ assert(s != NULL);
+
+ ssize_t n = write(s->m_fd, buf, len);
+ if (n == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ return 0;
+ }
+ throwError(errno);
+ }
+ return n;
+}
+
+void
+CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // get the error from the socket layer
+ int err = 0;
+ socklen_t size = (socklen_t)sizeof(err);
+ if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR,
+ (optval_t*)&err, &size) == -1) {
+ err = errno;
+ }
+
+ // throw if there's an error
+ if (err != 0) {
+ throwError(err);
+ }
+}
+
+void
+CArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking)
+{
+ assert(fd != -1);
+
+ int mode = fcntl(fd, F_GETFL, 0);
+ if (mode == -1) {
+ throwError(errno);
+ }
+ if (blocking) {
+ mode &= ~O_NONBLOCK;
+ }
+ else {
+ mode |= O_NONBLOCK;
+ }
+ if (fcntl(fd, F_SETFL, mode) == -1) {
+ throwError(errno);
+ }
+}
+
+bool
+CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
+{
+ assert(s != NULL);
+
+ // get old state
+ int oflag;
+ socklen_t size = (socklen_t)sizeof(oflag);
+ if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
+ (optval_t*)&oflag, &size) == -1) {
+ throwError(errno);
+ }
+
+ int flag = noDelay ? 1 : 0;
+ size = (socklen_t)sizeof(flag);
+ if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
+ (optval_t*)&flag, size) == -1) {
+ throwError(errno);
+ }
+
+ return (oflag != 0);
+}
+
+bool
+CArchNetworkBSD::setReuseAddrOnSocket(CArchSocket s, bool reuse)
+{
+ assert(s != NULL);
+
+ // get old state
+ int oflag;
+ socklen_t size = (socklen_t)sizeof(oflag);
+ if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
+ (optval_t*)&oflag, &size) == -1) {
+ throwError(errno);
+ }
+
+ int flag = reuse ? 1 : 0;
+ size = (socklen_t)sizeof(flag);
+ if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
+ (optval_t*)&flag, size) == -1) {
+ throwError(errno);
+ }
+
+ return (oflag != 0);
+}
+
+std::string
+CArchNetworkBSD::getHostName()
+{
+ char name[256];
+ if (gethostname(name, sizeof(name)) == -1) {
+ name[0] = '\0';
+ }
+ else {
+ name[sizeof(name) - 1] = '\0';
+ }
+ return name;
+}
+
+CArchNetAddress
+CArchNetworkBSD::newAnyAddr(EAddressFamily family)
+{
+ // allocate address
+ CArchNetAddressImpl* addr = new CArchNetAddressImpl;
+
+ // fill it in
+ switch (family) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ ipAddr->sin_family = AF_INET;
+ ipAddr->sin_port = 0;
+ ipAddr->sin_addr.s_addr = INADDR_ANY;
+ addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
+ break;
+ }
+
+ default:
+ delete addr;
+ assert(0 && "invalid family");
+ }
+
+ return addr;
+}
+
+CArchNetAddress
+CArchNetworkBSD::copyAddr(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ // allocate and copy address
+ return new CArchNetAddressImpl(*addr);
+}
+
+CArchNetAddress
+CArchNetworkBSD::nameToAddr(const std::string& name)
+{
+ // allocate address
+ CArchNetAddressImpl* addr = new CArchNetAddressImpl;
+
+ // try to convert assuming an IPv4 dot notation address
+ struct sockaddr_in inaddr;
+ memset(&inaddr, 0, sizeof(inaddr));
+ if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) {
+ // it's a dot notation address
+ addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
+ inaddr.sin_family = AF_INET;
+ inaddr.sin_port = 0;
+ memcpy(&addr->m_addr, &inaddr, addr->m_len);
+ }
+
+ else {
+ // mutexed address lookup (ugh)
+ ARCH->lockMutex(m_mutex);
+ struct hostent* info = gethostbyname(name.c_str());
+ if (info == NULL) {
+ ARCH->unlockMutex(m_mutex);
+ delete addr;
+ throwNameError(h_errno);
+ }
+
+ // copy over address (only IPv4 currently supported)
+ if (info->h_addrtype == AF_INET) {
+ addr->m_len = (socklen_t)sizeof(struct sockaddr_in);
+ inaddr.sin_family = info->h_addrtype;
+ inaddr.sin_port = 0;
+ memcpy(&inaddr.sin_addr, info->h_addr_list[0],
+ sizeof(inaddr.sin_addr));
+ memcpy(&addr->m_addr, &inaddr, addr->m_len);
+ }
+ else {
+ ARCH->unlockMutex(m_mutex);
+ delete addr;
+ throw XArchNetworkNameUnsupported(
+ "The requested name is valid but "
+ "does not have a supported address family");
+ }
+
+ // done with static buffer
+ ARCH->unlockMutex(m_mutex);
+ }
+
+ return addr;
+}
+
+void
+CArchNetworkBSD::closeAddr(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ delete addr;
+}
+
+std::string
+CArchNetworkBSD::addrToName(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ // mutexed name lookup (ugh)
+ ARCH->lockMutex(m_mutex);
+ struct hostent* info = gethostbyaddr(
+ reinterpret_cast(&addr->m_addr),
+ addr->m_len, addr->m_addr.sa_family);
+ if (info == NULL) {
+ ARCH->unlockMutex(m_mutex);
+ throwNameError(h_errno);
+ }
+
+ // save (primary) name
+ std::string name = info->h_name;
+
+ // done with static buffer
+ ARCH->unlockMutex(m_mutex);
+
+ return name;
+}
+
+std::string
+CArchNetworkBSD::addrToString(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ ARCH->lockMutex(m_mutex);
+ std::string s = inet_ntoa(ipAddr->sin_addr);
+ ARCH->unlockMutex(m_mutex);
+ return s;
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ return "";
+ }
+}
+
+IArchNetwork::EAddressFamily
+CArchNetworkBSD::getAddrFamily(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (addr->m_addr.sa_family) {
+ case AF_INET:
+ return kINET;
+
+ default:
+ return kUNKNOWN;
+ }
+}
+
+void
+CArchNetworkBSD::setAddrPort(CArchNetAddress addr, int port)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ ipAddr->sin_port = htons(port);
+ break;
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ break;
+ }
+}
+
+int
+CArchNetworkBSD::getAddrPort(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ return ntohs(ipAddr->sin_port);
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ return 0;
+ }
+}
+
+bool
+CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
+ addr->m_len == (socklen_t)sizeof(struct sockaddr_in));
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ return true;
+ }
+}
+
+bool
+CArchNetworkBSD::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
+{
+ return (a->m_len == b->m_len &&
+ memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
+}
+
+const int*
+CArchNetworkBSD::getUnblockPipe()
+{
+ CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
+ CArchThread thread = mt->newCurrentThread();
+ const int* p = getUnblockPipeForThread(thread);
+ ARCH->closeThread(thread);
+ return p;
+}
+
+const int*
+CArchNetworkBSD::getUnblockPipeForThread(CArchThread thread)
+{
+ CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
+ int* unblockPipe = (int*)mt->getNetworkDataForThread(thread);
+ if (unblockPipe == NULL) {
+ unblockPipe = new int[2];
+ if (pipe(unblockPipe) != -1) {
+ try {
+ setBlockingOnSocket(unblockPipe[0], false);
+ mt->setNetworkDataForCurrentThread(unblockPipe);
+ }
+ catch (...) {
+ delete[] unblockPipe;
+ unblockPipe = NULL;
+ }
+ }
+ else {
+ delete[] unblockPipe;
+ unblockPipe = NULL;
+ }
+ }
+ return unblockPipe;
+}
+
+void
+CArchNetworkBSD::throwError(int err)
+{
+ switch (err) {
+ case EINTR:
+ ARCH->testCancelThread();
+ throw XArchNetworkInterrupted(new XArchEvalUnix(err));
+
+ case EACCES:
+ case EPERM:
+ throw XArchNetworkAccess(new XArchEvalUnix(err));
+
+ case ENFILE:
+ case EMFILE:
+ case ENODEV:
+ case ENOBUFS:
+ case ENOMEM:
+ case ENETDOWN:
+#if defined(ENOSR)
+ case ENOSR:
+#endif
+ throw XArchNetworkResource(new XArchEvalUnix(err));
+
+ case EPROTOTYPE:
+ case EPROTONOSUPPORT:
+ case EAFNOSUPPORT:
+ case EPFNOSUPPORT:
+ case ESOCKTNOSUPPORT:
+ case EINVAL:
+ case ENOPROTOOPT:
+ case EOPNOTSUPP:
+ case ESHUTDOWN:
+#if defined(ENOPKG)
+ case ENOPKG:
+#endif
+ throw XArchNetworkSupport(new XArchEvalUnix(err));
+
+ case EIO:
+ throw XArchNetworkIO(new XArchEvalUnix(err));
+
+ case EADDRNOTAVAIL:
+ throw XArchNetworkNoAddress(new XArchEvalUnix(err));
+
+ case EADDRINUSE:
+ throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
+
+ case EHOSTUNREACH:
+ case ENETUNREACH:
+ throw XArchNetworkNoRoute(new XArchEvalUnix(err));
+
+ case ENOTCONN:
+ throw XArchNetworkNotConnected(new XArchEvalUnix(err));
+
+ case EPIPE:
+ throw XArchNetworkShutdown(new XArchEvalUnix(err));
+
+ case ECONNABORTED:
+ case ECONNRESET:
+ throw XArchNetworkDisconnected(new XArchEvalUnix(err));
+
+ case ECONNREFUSED:
+ throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
+
+ case EHOSTDOWN:
+ case ETIMEDOUT:
+ throw XArchNetworkTimedOut(new XArchEvalUnix(err));
+
+ default:
+ throw XArchNetwork(new XArchEvalUnix(err));
+ }
+}
+
+void
+CArchNetworkBSD::throwNameError(int err)
+{
+ static const char* s_msg[] = {
+ "The specified host is unknown",
+ "The requested name is valid but does not have an IP address",
+ "A non-recoverable name server error occurred",
+ "A temporary error occurred on an authoritative name server",
+ "An unknown name server error occurred"
+ };
+
+ switch (err) {
+ case HOST_NOT_FOUND:
+ throw XArchNetworkNameUnknown(s_msg[0]);
+
+ case NO_DATA:
+ throw XArchNetworkNameNoAddress(s_msg[1]);
+
+ case NO_RECOVERY:
+ throw XArchNetworkNameFailure(s_msg[2]);
+
+ case TRY_AGAIN:
+ throw XArchNetworkNameUnavailable(s_msg[3]);
+
+ default:
+ throw XArchNetworkName(s_msg[4]);
+ }
+}
diff --git a/lib/arch/CArchNetworkBSD.h b/lib/arch/CArchNetworkBSD.h
new file mode 100644
index 00000000..bba60272
--- /dev/null
+++ b/lib/arch/CArchNetworkBSD.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHNETWORKBSD_H
+#define CARCHNETWORKBSD_H
+
+#include "IArchNetwork.h"
+#include "IArchMultithread.h"
+#if HAVE_SYS_TYPES_H
+# include
+#endif
+#if HAVE_SYS_SOCKET_H
+# include
+#endif
+
+#if !HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+// old systems may use char* for [gs]etsockopt()'s optval argument.
+// this should be void on modern systems but char is forwards
+// compatible so we always use it.
+typedef char optval_t;
+
+#define ARCH_NETWORK CArchNetworkBSD
+
+class CArchSocketImpl {
+public:
+ int m_fd;
+ int m_refCount;
+};
+
+class CArchNetAddressImpl {
+public:
+ CArchNetAddressImpl() : m_len(sizeof(m_addr)) { }
+
+public:
+ struct sockaddr m_addr;
+ socklen_t m_len;
+};
+
+//! Berkeley (BSD) sockets implementation of IArchNetwork
+class CArchNetworkBSD : public IArchNetwork {
+public:
+ CArchNetworkBSD();
+ virtual ~CArchNetworkBSD();
+
+ // IArchNetwork overrides
+ virtual CArchSocket newSocket(EAddressFamily, ESocketType);
+ virtual CArchSocket copySocket(CArchSocket s);
+ virtual void closeSocket(CArchSocket s);
+ virtual void closeSocketForRead(CArchSocket s);
+ virtual void closeSocketForWrite(CArchSocket s);
+ virtual void bindSocket(CArchSocket s, CArchNetAddress addr);
+ virtual void listenOnSocket(CArchSocket s);
+ virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
+ virtual bool connectSocket(CArchSocket s, CArchNetAddress name);
+ virtual int pollSocket(CPollEntry[], int num, double timeout);
+ virtual void unblockPollSocket(CArchThread thread);
+ virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
+ virtual size_t writeSocket(CArchSocket s,
+ const void* buf, size_t len);
+ virtual void throwErrorOnSocket(CArchSocket);
+ virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay);
+ virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse);
+ virtual std::string getHostName();
+ virtual CArchNetAddress newAnyAddr(EAddressFamily);
+ virtual CArchNetAddress copyAddr(CArchNetAddress);
+ virtual CArchNetAddress nameToAddr(const std::string&);
+ virtual void closeAddr(CArchNetAddress);
+ virtual std::string addrToName(CArchNetAddress);
+ virtual std::string addrToString(CArchNetAddress);
+ virtual EAddressFamily getAddrFamily(CArchNetAddress);
+ virtual void setAddrPort(CArchNetAddress, int port);
+ virtual int getAddrPort(CArchNetAddress);
+ virtual bool isAnyAddr(CArchNetAddress);
+ virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
+
+private:
+ const int* getUnblockPipe();
+ const int* getUnblockPipeForThread(CArchThread);
+ void setBlockingOnSocket(int fd, bool blocking);
+ void throwError(int);
+ void throwNameError(int);
+
+private:
+ CArchMutex m_mutex;
+};
+
+#endif
diff --git a/lib/arch/CArchNetworkWinsock.cpp b/lib/arch/CArchNetworkWinsock.cpp
new file mode 100644
index 00000000..ac40596a
--- /dev/null
+++ b/lib/arch/CArchNetworkWinsock.cpp
@@ -0,0 +1,934 @@
+/*
+ * 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 "CArchNetworkWinsock.h"
+#include "CArch.h"
+#include "CArchMultithreadWindows.h"
+#include "IArchMultithread.h"
+#include "XArchWindows.h"
+#include
+
+static const int s_family[] = {
+ PF_UNSPEC,
+ PF_INET
+};
+static const int s_type[] = {
+ SOCK_DGRAM,
+ SOCK_STREAM
+};
+
+static SOCKET (PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);
+static int (PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, int namelen);
+static int (PASCAL FAR *close_winsock)(SOCKET s);
+static int (PASCAL FAR *connect_winsock)(SOCKET s, const struct sockaddr FAR *name, int namelen);
+static int (PASCAL FAR *gethostname_winsock)(char FAR * name, int namelen);
+static int (PASCAL FAR *getsockerror_winsock)(void);
+static int (PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen);
+static u_short (PASCAL FAR *htons_winsock)(u_short v);
+static char FAR * (PASCAL FAR *inet_ntoa_winsock)(struct in_addr in);
+static unsigned long (PASCAL FAR *inet_addr_winsock)(const char FAR * cp);
+static int (PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR * data);
+static int (PASCAL FAR *listen_winsock)(SOCKET s, int backlog);
+static u_short (PASCAL FAR *ntohs_winsock)(u_short v);
+static int (PASCAL FAR *recv_winsock)(SOCKET s, void FAR * buf, int len, int flags);
+static int (PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
+static int (PASCAL FAR *send_winsock)(SOCKET s, const void FAR * buf, int len, int flags);
+static int (PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, const void FAR * optval, int optlen);
+static int (PASCAL FAR *shutdown_winsock)(SOCKET s, int how);
+static SOCKET (PASCAL FAR *socket_winsock)(int af, int type, int protocol);
+static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR * addr, int len, int type);
+static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name);
+static int (PASCAL FAR *WSACleanup_winsock)(void);
+static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset);
+static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void);
+static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT);
+static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT);
+static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT);
+static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long);
+static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL);
+static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS);
+
+#undef FD_ISSET
+#define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set))
+
+#define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
+
+static HMODULE s_networkModule = NULL;
+
+static
+FARPROC
+netGetProcAddress(HMODULE module, LPCSTR name)
+{
+ FARPROC func = ::GetProcAddress(module, name);
+ if (!func) {
+ throw XArchNetworkSupport("");
+ }
+ return func;
+}
+
+CArchNetAddressImpl*
+CArchNetAddressImpl::alloc(size_t size)
+{
+ size_t totalSize = size + ADDR_HDR_SIZE;
+ CArchNetAddressImpl* addr = (CArchNetAddressImpl*)malloc(totalSize);
+ addr->m_len = size;
+ return addr;
+}
+
+
+//
+// CArchNetworkWinsock
+//
+
+CArchNetworkWinsock::CArchNetworkWinsock()
+{
+ static const char* s_library[] = { "ws2_32.dll" };
+
+ assert(WSACleanup_winsock == NULL);
+ assert(s_networkModule == NULL);
+
+ // try each winsock library
+ for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) {
+ try {
+ init((HMODULE)::LoadLibrary(s_library[i]));
+ m_mutex = ARCH->newMutex();
+ return;
+ }
+ catch (XArchNetwork&) {
+ // ignore
+ }
+ }
+
+ // can't initialize any library
+ throw XArchNetworkSupport("Cannot load winsock library");
+}
+
+CArchNetworkWinsock::~CArchNetworkWinsock()
+{
+ if (s_networkModule != NULL) {
+ WSACleanup_winsock();
+ ::FreeLibrary(s_networkModule);
+
+ WSACleanup_winsock = NULL;
+ s_networkModule = NULL;
+ }
+ ARCH->closeMutex(m_mutex);
+}
+
+void
+CArchNetworkWinsock::init(HMODULE module)
+{
+ if (module == NULL) {
+ throw XArchNetworkSupport("");
+ }
+
+ // get startup function address
+ int (PASCAL FAR *startup)(WORD, LPWSADATA);
+ setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA));
+
+ // startup network library
+ WORD version = MAKEWORD(2 /*major*/, 0 /*minor*/);
+ WSADATA data;
+ int err = startup(version, &data);
+ if (data.wVersion != version) {
+ throw XArchNetworkSupport(new XArchEvalWinsock(err));
+ }
+ if (err != 0) {
+ // some other initialization error
+ throwError(err);
+ }
+
+ // get function addresses
+ setfunc(accept_winsock, accept, SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen));
+ setfunc(bind_winsock, bind, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen));
+ setfunc(close_winsock, closesocket, int (PASCAL FAR *)(SOCKET s));
+ setfunc(connect_winsock, connect, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen));
+ setfunc(gethostname_winsock, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen));
+ setfunc(getsockerror_winsock, WSAGetLastError, int (PASCAL FAR *)(void));
+ setfunc(getsockopt_winsock, getsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen));
+ setfunc(htons_winsock, htons, u_short (PASCAL FAR *)(u_short v));
+ setfunc(inet_ntoa_winsock, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in));
+ setfunc(inet_addr_winsock, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp));
+ setfunc(ioctl_winsock, ioctlsocket, int (PASCAL FAR *)(SOCKET s, int cmd, void FAR *));
+ setfunc(listen_winsock, listen, int (PASCAL FAR *)(SOCKET s, int backlog));
+ setfunc(ntohs_winsock, ntohs, u_short (PASCAL FAR *)(u_short v));
+ setfunc(recv_winsock, recv, int (PASCAL FAR *)(SOCKET s, void FAR * buf, int len, int flags));
+ setfunc(select_winsock, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout));
+ setfunc(send_winsock, send, int (PASCAL FAR *)(SOCKET s, const void FAR * buf, int len, int flags));
+ setfunc(setsockopt_winsock, setsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, const void FAR * optval, int optlen));
+ setfunc(shutdown_winsock, shutdown, int (PASCAL FAR *)(SOCKET s, int how));
+ setfunc(socket_winsock, socket, SOCKET (PASCAL FAR *)(int af, int type, int protocol));
+ setfunc(gethostbyaddr_winsock, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type));
+ setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name));
+ setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void));
+ setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *));
+ setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void));
+ setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT));
+ setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
+ setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT));
+ setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long));
+ setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL));
+ setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS));
+
+ s_networkModule = module;
+}
+
+CArchSocket
+CArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type)
+{
+ // create socket
+ SOCKET fd = socket_winsock(s_family[family], s_type[type], 0);
+ if (fd == INVALID_SOCKET) {
+ throwError(getsockerror_winsock());
+ }
+ try {
+ setBlockingOnSocket(fd, false);
+ }
+ catch (...) {
+ close_winsock(fd);
+ throw;
+ }
+
+ // allocate socket object
+ CArchSocketImpl* socket = new CArchSocketImpl;
+ socket->m_socket = fd;
+ socket->m_refCount = 1;
+ socket->m_event = WSACreateEvent_winsock();
+ socket->m_pollWrite = true;
+ return socket;
+}
+
+CArchSocket
+CArchNetworkWinsock::copySocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // ref the socket and return it
+ ARCH->lockMutex(m_mutex);
+ ++s->m_refCount;
+ ARCH->unlockMutex(m_mutex);
+ return s;
+}
+
+void
+CArchNetworkWinsock::closeSocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // unref the socket and note if it should be released
+ ARCH->lockMutex(m_mutex);
+ const bool doClose = (--s->m_refCount == 0);
+ ARCH->unlockMutex(m_mutex);
+
+ // close the socket if necessary
+ if (doClose) {
+ if (close_winsock(s->m_socket) == SOCKET_ERROR) {
+ // close failed. restore the last ref and throw.
+ int err = getsockerror_winsock();
+ ARCH->lockMutex(m_mutex);
+ ++s->m_refCount;
+ ARCH->unlockMutex(m_mutex);
+ throwError(err);
+ }
+ WSACloseEvent_winsock(s->m_event);
+ delete s;
+ }
+}
+
+void
+CArchNetworkWinsock::closeSocketForRead(CArchSocket s)
+{
+ assert(s != NULL);
+
+ if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) {
+ if (getsockerror_winsock() != WSAENOTCONN) {
+ throwError(getsockerror_winsock());
+ }
+ }
+}
+
+void
+CArchNetworkWinsock::closeSocketForWrite(CArchSocket s)
+{
+ assert(s != NULL);
+
+ if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) {
+ if (getsockerror_winsock() != WSAENOTCONN) {
+ throwError(getsockerror_winsock());
+ }
+ }
+}
+
+void
+CArchNetworkWinsock::bindSocket(CArchSocket s, CArchNetAddress addr)
+{
+ assert(s != NULL);
+ assert(addr != NULL);
+
+ if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+}
+
+void
+CArchNetworkWinsock::listenOnSocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // hardcoding backlog
+ if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+}
+
+CArchSocket
+CArchNetworkWinsock::acceptSocket(CArchSocket s, CArchNetAddress* addr)
+{
+ assert(s != NULL);
+
+ // create new socket and temporary address
+ CArchSocketImpl* socket = new CArchSocketImpl;
+ CArchNetAddress tmp = CArchNetAddressImpl::alloc(sizeof(struct sockaddr));
+
+ // accept on socket
+ SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len);
+ if (fd == INVALID_SOCKET) {
+ int err = getsockerror_winsock();
+ delete socket;
+ free(tmp);
+ *addr = NULL;
+ if (err == WSAEWOULDBLOCK) {
+ return NULL;
+ }
+ throwError(err);
+ }
+
+ try {
+ setBlockingOnSocket(fd, false);
+ }
+ catch (...) {
+ close_winsock(fd);
+ delete socket;
+ free(tmp);
+ *addr = NULL;
+ throw;
+ }
+
+ // initialize socket
+ socket->m_socket = fd;
+ socket->m_refCount = 1;
+ socket->m_event = WSACreateEvent_winsock();
+ socket->m_pollWrite = true;
+
+ // copy address if requested
+ if (addr != NULL) {
+ *addr = ARCH->copyAddr(tmp);
+ }
+
+ free(tmp);
+ return socket;
+}
+
+bool
+CArchNetworkWinsock::connectSocket(CArchSocket s, CArchNetAddress addr)
+{
+ assert(s != NULL);
+ assert(addr != NULL);
+
+ if (connect_winsock(s->m_socket, &addr->m_addr,
+ addr->m_len) == SOCKET_ERROR) {
+ if (getsockerror_winsock() == WSAEISCONN) {
+ return true;
+ }
+ if (getsockerror_winsock() == WSAEWOULDBLOCK) {
+ return false;
+ }
+ throwError(getsockerror_winsock());
+ }
+ return true;
+}
+
+int
+CArchNetworkWinsock::pollSocket(CPollEntry pe[], int num, double timeout)
+{
+ int i;
+ DWORD n;
+
+ // prepare sockets and wait list
+ bool canWrite = false;
+ WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT));
+ for (i = 0, n = 0; i < num; ++i) {
+ // reset return flags
+ pe[i].m_revents = 0;
+
+ // set invalid flag if socket is bogus then go to next socket
+ if (pe[i].m_socket == NULL) {
+ pe[i].m_revents |= kPOLLNVAL;
+ continue;
+ }
+
+ // select desired events
+ long socketEvents = 0;
+ if ((pe[i].m_events & kPOLLIN) != 0) {
+ socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE;
+ }
+ if ((pe[i].m_events & kPOLLOUT) != 0) {
+ socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE;
+
+ // if m_pollWrite is false then we assume the socket is
+ // writable. winsock doesn't signal writability except
+ // when the state changes from unwritable.
+ if (!pe[i].m_socket->m_pollWrite) {
+ canWrite = true;
+ pe[i].m_revents |= kPOLLOUT;
+ }
+ }
+
+ // if no events then ignore socket
+ if (socketEvents == 0) {
+ continue;
+ }
+
+ // select socket for desired events
+ WSAEventSelect_winsock(pe[i].m_socket->m_socket,
+ pe[i].m_socket->m_event, socketEvents);
+
+ // add socket event to wait list
+ events[n++] = pe[i].m_socket->m_event;
+ }
+
+ // if no sockets then return immediately
+ if (n == 0) {
+ return 0;
+ }
+
+ // add the unblock event
+ CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
+ CArchThread thread = mt->newCurrentThread();
+ WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
+ ARCH->closeThread(thread);
+ if (unblockEvent == NULL) {
+ unblockEvent = new WSAEVENT;
+ *unblockEvent = WSACreateEvent_winsock();
+ mt->setNetworkDataForCurrentThread(unblockEvent);
+ }
+ events[n++] = *unblockEvent;
+
+ // prepare timeout
+ DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout);
+ if (canWrite) {
+ // if we know we can write then don't block
+ t = 0;
+ }
+
+ // wait
+ DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE);
+
+ // reset the unblock event
+ WSAResetEvent_winsock(*unblockEvent);
+
+ // handle results
+ if (result == WSA_WAIT_FAILED) {
+ if (getsockerror_winsock() == WSAEINTR) {
+ // interrupted system call
+ ARCH->testCancelThread();
+ return 0;
+ }
+ throwError(getsockerror_winsock());
+ }
+ if (result == WSA_WAIT_TIMEOUT && !canWrite) {
+ return 0;
+ }
+ if (result == WSA_WAIT_EVENT_0 + n - 1) {
+ // the unblock event was signalled
+ return 0;
+ }
+ for (i = 0, n = 0; i < num; ++i) {
+ // skip events we didn't check
+ if (pe[i].m_socket == NULL ||
+ (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
+ continue;
+ }
+
+ // get events
+ WSANETWORKEVENTS info;
+ if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket,
+ pe[i].m_socket->m_event, &info) == SOCKET_ERROR) {
+ continue;
+ }
+ if ((info.lNetworkEvents & FD_READ) != 0) {
+ pe[i].m_revents |= kPOLLIN;
+ }
+ if ((info.lNetworkEvents & FD_ACCEPT) != 0) {
+ pe[i].m_revents |= kPOLLIN;
+ }
+ if ((info.lNetworkEvents & FD_WRITE) != 0) {
+ pe[i].m_revents |= kPOLLOUT;
+
+ // socket is now writable so don't bothing polling for
+ // writable until it becomes unwritable.
+ pe[i].m_socket->m_pollWrite = false;
+ }
+ if ((info.lNetworkEvents & FD_CONNECT) != 0) {
+ if (info.iErrorCode[FD_CONNECT_BIT] != 0) {
+ pe[i].m_revents |= kPOLLERR;
+ }
+ else {
+ pe[i].m_revents |= kPOLLOUT;
+ pe[i].m_socket->m_pollWrite = false;
+ }
+ }
+ if ((info.lNetworkEvents & FD_CLOSE) != 0) {
+ if (info.iErrorCode[FD_CLOSE_BIT] != 0) {
+ pe[i].m_revents |= kPOLLERR;
+ }
+ else {
+ if ((pe[i].m_events & kPOLLIN) != 0) {
+ pe[i].m_revents |= kPOLLIN;
+ }
+ if ((pe[i].m_events & kPOLLOUT) != 0) {
+ pe[i].m_revents |= kPOLLOUT;
+ }
+ }
+ }
+ if (pe[i].m_revents != 0) {
+ ++n;
+ }
+ }
+
+ return (int)n;
+}
+
+void
+CArchNetworkWinsock::unblockPollSocket(CArchThread thread)
+{
+ // set the unblock event
+ CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
+ WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread);
+ if (unblockEvent != NULL) {
+ WSASetEvent_winsock(*unblockEvent);
+ }
+}
+
+size_t
+CArchNetworkWinsock::readSocket(CArchSocket s, void* buf, size_t len)
+{
+ assert(s != NULL);
+
+ int n = recv_winsock(s->m_socket, buf, len, 0);
+ if (n == SOCKET_ERROR) {
+ int err = getsockerror_winsock();
+ if (err == WSAEINTR || err == WSAEWOULDBLOCK) {
+ return 0;
+ }
+ throwError(err);
+ }
+ return static_cast(n);
+}
+
+size_t
+CArchNetworkWinsock::writeSocket(CArchSocket s, const void* buf, size_t len)
+{
+ assert(s != NULL);
+
+ int n = send_winsock(s->m_socket, buf, len, 0);
+ if (n == SOCKET_ERROR) {
+ int err = getsockerror_winsock();
+ if (err == WSAEINTR) {
+ return 0;
+ }
+ if (err == WSAEWOULDBLOCK) {
+ s->m_pollWrite = true;
+ return 0;
+ }
+ throwError(err);
+ }
+ return static_cast(n);
+}
+
+void
+CArchNetworkWinsock::throwErrorOnSocket(CArchSocket s)
+{
+ assert(s != NULL);
+
+ // get the error from the socket layer
+ int err = 0;
+ int size = sizeof(err);
+ if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
+ SO_ERROR, &err, &size) == SOCKET_ERROR) {
+ err = getsockerror_winsock();
+ }
+
+ // throw if there's an error
+ if (err != 0) {
+ throwError(err);
+ }
+}
+
+void
+CArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking)
+{
+ assert(s != 0);
+
+ int flag = blocking ? 0 : 1;
+ if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+}
+
+bool
+CArchNetworkWinsock::setNoDelayOnSocket(CArchSocket s, bool noDelay)
+{
+ assert(s != NULL);
+
+ // get old state
+ BOOL oflag;
+ int size = sizeof(oflag);
+ if (getsockopt_winsock(s->m_socket, IPPROTO_TCP,
+ TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+
+ // set new state
+ BOOL flag = noDelay ? 1 : 0;
+ size = sizeof(flag);
+ if (setsockopt_winsock(s->m_socket, IPPROTO_TCP,
+ TCP_NODELAY, &flag, size) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+
+ return (oflag != 0);
+}
+
+bool
+CArchNetworkWinsock::setReuseAddrOnSocket(CArchSocket s, bool reuse)
+{
+ assert(s != NULL);
+
+ // get old state
+ BOOL oflag;
+ int size = sizeof(oflag);
+ if (getsockopt_winsock(s->m_socket, SOL_SOCKET,
+ SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+
+ // set new state
+ BOOL flag = reuse ? 1 : 0;
+ size = sizeof(flag);
+ if (setsockopt_winsock(s->m_socket, SOL_SOCKET,
+ SO_REUSEADDR, &flag, size) == SOCKET_ERROR) {
+ throwError(getsockerror_winsock());
+ }
+
+ return (oflag != 0);
+}
+
+std::string
+CArchNetworkWinsock::getHostName()
+{
+ char name[256];
+ if (gethostname_winsock(name, sizeof(name)) == -1) {
+ name[0] = '\0';
+ }
+ else {
+ name[sizeof(name) - 1] = '\0';
+ }
+ return name;
+}
+
+CArchNetAddress
+CArchNetworkWinsock::newAnyAddr(EAddressFamily family)
+{
+ CArchNetAddressImpl* addr = NULL;
+ switch (family) {
+ case kINET: {
+ addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
+ struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
+ ipAddr->sin_family = AF_INET;
+ ipAddr->sin_port = 0;
+ ipAddr->sin_addr.s_addr = INADDR_ANY;
+ break;
+ }
+
+ default:
+ assert(0 && "invalid family");
+ }
+ return addr;
+}
+
+CArchNetAddress
+CArchNetworkWinsock::copyAddr(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ CArchNetAddressImpl* copy = CArchNetAddressImpl::alloc(addr->m_len);
+ memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
+ return copy;
+}
+
+CArchNetAddress
+CArchNetworkWinsock::nameToAddr(const std::string& name)
+{
+ // allocate address
+ CArchNetAddressImpl* addr = NULL;
+
+ // try to convert assuming an IPv4 dot notation address
+ struct sockaddr_in inaddr;
+ memset(&inaddr, 0, sizeof(inaddr));
+ inaddr.sin_family = AF_INET;
+ inaddr.sin_port = 0;
+ inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str());
+ if (inaddr.sin_addr.s_addr != INADDR_NONE) {
+ // it's a dot notation address
+ addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
+ memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
+ }
+
+ else {
+ // address lookup
+ struct hostent* info = gethostbyname_winsock(name.c_str());
+ if (info == NULL) {
+ throwNameError(getsockerror_winsock());
+ }
+
+ // copy over address (only IPv4 currently supported)
+ if (info->h_addrtype == AF_INET) {
+ addr = CArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
+ memcpy(&inaddr.sin_addr, info->h_addr_list[0],
+ sizeof(inaddr.sin_addr));
+ memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len);
+ }
+ else {
+ throw XArchNetworkNameUnsupported(
+ "The requested name is valid but "
+ "does not have a supported address family");
+ }
+ }
+
+ return addr;
+}
+
+void
+CArchNetworkWinsock::closeAddr(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ free(addr);
+}
+
+std::string
+CArchNetworkWinsock::addrToName(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ // name lookup
+ struct hostent* info = gethostbyaddr_winsock(
+ reinterpret_cast(&addr->m_addr),
+ addr->m_len, addr->m_addr.sa_family);
+ if (info == NULL) {
+ throwNameError(getsockerror_winsock());
+ }
+
+ // return (primary) name
+ return info->h_name;
+}
+
+std::string
+CArchNetworkWinsock::addrToString(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ return inet_ntoa_winsock(ipAddr->sin_addr);
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ return "";
+ }
+}
+
+IArchNetwork::EAddressFamily
+CArchNetworkWinsock::getAddrFamily(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (addr->m_addr.sa_family) {
+ case AF_INET:
+ return kINET;
+
+ default:
+ return kUNKNOWN;
+ }
+}
+
+void
+CArchNetworkWinsock::setAddrPort(CArchNetAddress addr, int port)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ ipAddr->sin_port = htons_winsock(static_cast(port));
+ break;
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ break;
+ }
+}
+
+int
+CArchNetworkWinsock::getAddrPort(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ return ntohs_winsock(ipAddr->sin_port);
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ return 0;
+ }
+}
+
+bool
+CArchNetworkWinsock::isAnyAddr(CArchNetAddress addr)
+{
+ assert(addr != NULL);
+
+ switch (getAddrFamily(addr)) {
+ case kINET: {
+ struct sockaddr_in* ipAddr =
+ reinterpret_cast(&addr->m_addr);
+ return (addr->m_len == sizeof(struct sockaddr_in) &&
+ ipAddr->sin_addr.s_addr == INADDR_ANY);
+ }
+
+ default:
+ assert(0 && "unknown address family");
+ return true;
+ }
+}
+
+bool
+CArchNetworkWinsock::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
+{
+ return (a == b || (a->m_len == b->m_len &&
+ memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0));
+}
+
+void
+CArchNetworkWinsock::throwError(int err)
+{
+ switch (err) {
+ case WSAEACCES:
+ throw XArchNetworkAccess(new XArchEvalWinsock(err));
+
+ case WSAEMFILE:
+ case WSAENOBUFS:
+ case WSAENETDOWN:
+ throw XArchNetworkResource(new XArchEvalWinsock(err));
+
+ case WSAEPROTOTYPE:
+ case WSAEPROTONOSUPPORT:
+ case WSAEAFNOSUPPORT:
+ case WSAEPFNOSUPPORT:
+ case WSAESOCKTNOSUPPORT:
+ case WSAEINVAL:
+ case WSAENOPROTOOPT:
+ case WSAEOPNOTSUPP:
+ case WSAESHUTDOWN:
+ case WSANOTINITIALISED:
+ case WSAVERNOTSUPPORTED:
+ case WSASYSNOTREADY:
+ throw XArchNetworkSupport(new XArchEvalWinsock(err));
+
+ case WSAEADDRNOTAVAIL:
+ throw XArchNetworkNoAddress(new XArchEvalWinsock(err));
+
+ case WSAEADDRINUSE:
+ throw XArchNetworkAddressInUse(new XArchEvalWinsock(err));
+
+ case WSAEHOSTUNREACH:
+ case WSAENETUNREACH:
+ throw XArchNetworkNoRoute(new XArchEvalWinsock(err));
+
+ case WSAENOTCONN:
+ throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
+
+ case WSAEDISCON:
+ throw XArchNetworkShutdown(new XArchEvalWinsock(err));
+
+ case WSAENETRESET:
+ case WSAECONNABORTED:
+ case WSAECONNRESET:
+ throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
+
+ case WSAECONNREFUSED:
+ throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err));
+
+ case WSAEHOSTDOWN:
+ case WSAETIMEDOUT:
+ throw XArchNetworkTimedOut(new XArchEvalWinsock(err));
+
+ case WSAHOST_NOT_FOUND:
+ throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
+
+ case WSANO_DATA:
+ throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
+
+ case WSANO_RECOVERY:
+ throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
+
+ case WSATRY_AGAIN:
+ throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
+
+ default:
+ throw XArchNetwork(new XArchEvalWinsock(err));
+ }
+}
+
+void
+CArchNetworkWinsock::throwNameError(int err)
+{
+ switch (err) {
+ case WSAHOST_NOT_FOUND:
+ throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
+
+ case WSANO_DATA:
+ throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
+
+ case WSANO_RECOVERY:
+ throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
+
+ case WSATRY_AGAIN:
+ throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
+
+ default:
+ throw XArchNetworkName(new XArchEvalWinsock(err));
+ }
+}
diff --git a/lib/arch/CArchNetworkWinsock.h b/lib/arch/CArchNetworkWinsock.h
new file mode 100644
index 00000000..3912ba5b
--- /dev/null
+++ b/lib/arch/CArchNetworkWinsock.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHNETWORKWINSOCK_H
+#define CARCHNETWORKWINSOCK_H
+
+#define WIN32_LEAN_AND_MEAN
+
+// declare no functions in winsock2
+#define INCL_WINSOCK_API_PROTOTYPES 0
+#define INCL_WINSOCK_API_TYPEDEFS 0
+
+#include "IArchNetwork.h"
+#include "IArchMultithread.h"
+#include
+#include
+
+#define ARCH_NETWORK CArchNetworkWinsock
+
+class CArchSocketImpl {
+public:
+ SOCKET m_socket;
+ int m_refCount;
+ WSAEVENT m_event;
+ bool m_pollWrite;
+};
+
+class CArchNetAddressImpl {
+public:
+ static CArchNetAddressImpl* alloc(size_t);
+
+public:
+ int m_len;
+ struct sockaddr m_addr;
+};
+#define ADDR_HDR_SIZE offsetof(CArchNetAddressImpl, m_addr)
+#define TYPED_ADDR(type_, addr_) (reinterpret_cast(&addr_->m_addr))
+
+//! Win32 implementation of IArchNetwork
+class CArchNetworkWinsock : public IArchNetwork {
+public:
+ CArchNetworkWinsock();
+ virtual ~CArchNetworkWinsock();
+
+ // IArchNetwork overrides
+ virtual CArchSocket newSocket(EAddressFamily, ESocketType);
+ virtual CArchSocket copySocket(CArchSocket s);
+ virtual void closeSocket(CArchSocket s);
+ virtual void closeSocketForRead(CArchSocket s);
+ virtual void closeSocketForWrite(CArchSocket s);
+ virtual void bindSocket(CArchSocket s, CArchNetAddress addr);
+ virtual void listenOnSocket(CArchSocket s);
+ virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr);
+ virtual bool connectSocket(CArchSocket s, CArchNetAddress name);
+ virtual int pollSocket(CPollEntry[], int num, double timeout);
+ virtual void unblockPollSocket(CArchThread thread);
+ virtual size_t readSocket(CArchSocket s, void* buf, size_t len);
+ virtual size_t writeSocket(CArchSocket s,
+ const void* buf, size_t len);
+ virtual void throwErrorOnSocket(CArchSocket);
+ virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay);
+ virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse);
+ virtual std::string getHostName();
+ virtual CArchNetAddress newAnyAddr(EAddressFamily);
+ virtual CArchNetAddress copyAddr(CArchNetAddress);
+ virtual CArchNetAddress nameToAddr(const std::string&);
+ virtual void closeAddr(CArchNetAddress);
+ virtual std::string addrToName(CArchNetAddress);
+ virtual std::string addrToString(CArchNetAddress);
+ virtual EAddressFamily getAddrFamily(CArchNetAddress);
+ virtual void setAddrPort(CArchNetAddress, int port);
+ virtual int getAddrPort(CArchNetAddress);
+ virtual bool isAnyAddr(CArchNetAddress);
+ virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress);
+
+private:
+ void init(HMODULE);
+
+ void setBlockingOnSocket(SOCKET, bool blocking);
+
+ void throwError(int);
+ void throwNameError(int);
+
+private:
+ CArchMutex m_mutex;
+};
+
+#endif
diff --git a/lib/arch/CArchSleepUnix.cpp b/lib/arch/CArchSleepUnix.cpp
new file mode 100644
index 00000000..35010721
--- /dev/null
+++ b/lib/arch/CArchSleepUnix.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "CArchSleepUnix.h"
+#include "CArch.h"
+#if TIME_WITH_SYS_TIME
+# include
+# include
+#else
+# if HAVE_SYS_TIME_H
+# include
+# else
+# include
+# endif
+#endif
+#if !HAVE_NANOSLEEP
+# if HAVE_SYS_SELECT_H
+# include
+# endif
+# if HAVE_SYS_TYPES_H
+# include
+# endif
+# if HAVE_UNISTD_H
+# include
+# endif
+#endif
+
+//
+// CArchSleepUnix
+//
+
+CArchSleepUnix::CArchSleepUnix()
+{
+ // do nothing
+}
+
+CArchSleepUnix::~CArchSleepUnix()
+{
+ // do nothing
+}
+
+void
+CArchSleepUnix::sleep(double timeout)
+{
+ ARCH->testCancelThread();
+ if (timeout < 0.0) {
+ return;
+ }
+
+#if HAVE_NANOSLEEP
+ // prep timeout
+ struct timespec t;
+ t.tv_sec = (long)timeout;
+ t.tv_nsec = (long)(1.0e+9 * (timeout - (double)t.tv_sec));
+
+ // wait
+ while (nanosleep(&t, &t) < 0)
+ ARCH->testCancelThread();
+#else
+ /* emulate nanosleep() with select() */
+ double startTime = ARCH->time();
+ double timeLeft = timeout;
+ while (timeLeft > 0.0) {
+ struct timeval timeout2;
+ timeout2.tv_sec = static_cast(timeLeft);
+ timeout2.tv_usec = static_cast(1.0e+6 * (timeLeft -
+ timeout2.tv_sec));
+ select((SELECT_TYPE_ARG1) 0,
+ SELECT_TYPE_ARG234 NULL,
+ SELECT_TYPE_ARG234 NULL,
+ SELECT_TYPE_ARG234 NULL,
+ SELECT_TYPE_ARG5 &timeout2);
+ ARCH->testCancelThread();
+ timeLeft = timeout - (ARCH->time() - startTime);
+ }
+#endif
+}
diff --git a/lib/arch/CArchSleepUnix.h b/lib/arch/CArchSleepUnix.h
new file mode 100644
index 00000000..939ca401
--- /dev/null
+++ b/lib/arch/CArchSleepUnix.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHSLEEPUNIX_H
+#define CARCHSLEEPUNIX_H
+
+#include "IArchSleep.h"
+
+#define ARCH_SLEEP CArchSleepUnix
+
+//! Unix implementation of IArchSleep
+class CArchSleepUnix : public IArchSleep {
+public:
+ CArchSleepUnix();
+ virtual ~CArchSleepUnix();
+
+ // IArchSleep overrides
+ virtual void sleep(double timeout);
+};
+
+#endif
diff --git a/lib/arch/CArchSleepWindows.cpp b/lib/arch/CArchSleepWindows.cpp
new file mode 100644
index 00000000..f6c8bed8
--- /dev/null
+++ b/lib/arch/CArchSleepWindows.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "CArchSleepWindows.h"
+#include "CArch.h"
+#include "CArchMultithreadWindows.h"
+
+//
+// CArchSleepWindows
+//
+
+CArchSleepWindows::CArchSleepWindows()
+{
+ // do nothing
+}
+
+CArchSleepWindows::~CArchSleepWindows()
+{
+ // do nothing
+}
+
+void
+CArchSleepWindows::sleep(double timeout)
+{
+ ARCH->testCancelThread();
+ if (timeout < 0.0) {
+ return;
+ }
+
+ // get the cancel event from the current thread. this only
+ // works if we're using the windows multithread object but
+ // this is windows so that's pretty certain; we'll get a
+ // link error if we're not, though.
+ CArchMultithreadWindows* mt = CArchMultithreadWindows::getInstance();
+ if (mt != NULL) {
+ HANDLE cancelEvent = mt->getCancelEventForCurrentThread();
+ WaitForSingleObject(cancelEvent, (DWORD)(1000.0 * timeout));
+ if (timeout == 0.0) {
+ Sleep(0);
+ }
+ }
+ else {
+ Sleep((DWORD)(1000.0 * timeout));
+ }
+ ARCH->testCancelThread();
+}
diff --git a/lib/arch/CArchSleepWindows.h b/lib/arch/CArchSleepWindows.h
new file mode 100644
index 00000000..a5a5fa90
--- /dev/null
+++ b/lib/arch/CArchSleepWindows.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHSLEEPWINDOWS_H
+#define CARCHSLEEPWINDOWS_H
+
+#include "IArchSleep.h"
+
+#define ARCH_SLEEP CArchSleepWindows
+
+//! Win32 implementation of IArchSleep
+class CArchSleepWindows : public IArchSleep {
+public:
+ CArchSleepWindows();
+ virtual ~CArchSleepWindows();
+
+ // IArchSleep overrides
+ virtual void sleep(double timeout);
+};
+
+#endif
diff --git a/lib/arch/CArchStringUnix.cpp b/lib/arch/CArchStringUnix.cpp
new file mode 100644
index 00000000..e0ad3457
--- /dev/null
+++ b/lib/arch/CArchStringUnix.cpp
@@ -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.
+ */
+
+#include "CArchStringUnix.h"
+#include
+
+//
+// CArchStringUnix
+//
+
+#include "CMultibyte.cpp"
+#include "vsnprintf.cpp"
+
+IArchString::EWideCharEncoding
+CArchStringUnix::getWideCharEncoding()
+{
+ return kUCS4;
+}
diff --git a/lib/arch/CArchStringUnix.h b/lib/arch/CArchStringUnix.h
new file mode 100644
index 00000000..20e5486b
--- /dev/null
+++ b/lib/arch/CArchStringUnix.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHSTRINGUNIX_H
+#define CARCHSTRINGUNIX_H
+
+#include "IArchString.h"
+
+#define ARCH_STRING CArchStringUnix
+
+//! Unix implementation of IArchString
+class CArchStringUnix : public IArchString {
+public:
+ CArchStringUnix();
+ virtual ~CArchStringUnix();
+
+ // IArchString overrides
+ virtual int vsnprintf(char* str,
+ int size, const char* fmt, va_list ap);
+ virtual int convStringMBToWC(wchar_t*,
+ const char*, UInt32 n, bool* errors);
+ virtual int convStringWCToMB(char*,
+ const wchar_t*, UInt32 n, bool* errors);
+ virtual EWideCharEncoding
+ getWideCharEncoding();
+};
+
+#endif
diff --git a/lib/arch/CArchStringWindows.cpp b/lib/arch/CArchStringWindows.cpp
new file mode 100644
index 00000000..a3b90765
--- /dev/null
+++ b/lib/arch/CArchStringWindows.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "CArchStringWindows.h"
+#include
+#include
+
+//
+// CArchStringWindows
+//
+
+#include "CMultibyte.cpp"
+#define HAVE_VSNPRINTF 1
+#define ARCH_VSNPRINTF _vsnprintf
+#include "vsnprintf.cpp"
+
+IArchString::EWideCharEncoding
+CArchStringWindows::getWideCharEncoding()
+{
+ return kUTF16;
+}
diff --git a/lib/arch/CArchStringWindows.h b/lib/arch/CArchStringWindows.h
new file mode 100644
index 00000000..a67d8431
--- /dev/null
+++ b/lib/arch/CArchStringWindows.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHSTRINGWINDOWS_H
+#define CARCHSTRINGWINDOWS_H
+
+#include "IArchString.h"
+
+#define ARCH_STRING CArchStringWindows
+
+//! Win32 implementation of IArchString
+class CArchStringWindows : public IArchString {
+public:
+ CArchStringWindows();
+ virtual ~CArchStringWindows();
+
+ // IArchString overrides
+ virtual int vsnprintf(char* str,
+ int size, const char* fmt, va_list ap);
+ virtual int convStringMBToWC(wchar_t*,
+ const char*, UInt32 n, bool* errors);
+ virtual int convStringWCToMB(char*,
+ const wchar_t*, UInt32 n, bool* errors);
+ virtual EWideCharEncoding
+ getWideCharEncoding();
+};
+
+#endif
diff --git a/lib/arch/CArchSystemUnix.cpp b/lib/arch/CArchSystemUnix.cpp
new file mode 100644
index 00000000..541038db
--- /dev/null
+++ b/lib/arch/CArchSystemUnix.cpp
@@ -0,0 +1,50 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CArchSystemUnix.h"
+#include
+
+//
+// CArchSystemUnix
+//
+
+CArchSystemUnix::CArchSystemUnix()
+{
+ // do nothing
+}
+
+CArchSystemUnix::~CArchSystemUnix()
+{
+ // do nothing
+}
+
+std::string
+CArchSystemUnix::getOSName() const
+{
+#if defined(HAVE_SYS_UTSNAME_H)
+ struct utsname info;
+ if (uname(&info) == 0) {
+ std::string msg;
+ msg += info.sysname;
+ msg += " ";
+ msg += info.release;
+ msg += " ";
+ msg += info.version;
+ msg += " ";
+ msg += info.machine;
+ return msg;
+ }
+#endif
+ return "Unix ";
+}
diff --git a/lib/arch/CArchSystemUnix.h b/lib/arch/CArchSystemUnix.h
new file mode 100644
index 00000000..525aed1c
--- /dev/null
+++ b/lib/arch/CArchSystemUnix.h
@@ -0,0 +1,32 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CARCHSYSTEMUNIX_H
+#define CARCHSYSTEMUNIX_H
+
+#include "IArchSystem.h"
+
+#define ARCH_SYSTEM CArchSystemUnix
+
+//! Unix implementation of IArchString
+class CArchSystemUnix : public IArchSystem {
+public:
+ CArchSystemUnix();
+ virtual ~CArchSystemUnix();
+
+ // IArchSystem overrides
+ virtual std::string getOSName() const;
+};
+
+#endif
diff --git a/lib/arch/CArchSystemWindows.cpp b/lib/arch/CArchSystemWindows.cpp
new file mode 100644
index 00000000..b634b4bc
--- /dev/null
+++ b/lib/arch/CArchSystemWindows.cpp
@@ -0,0 +1,86 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "CArchSystemWindows.h"
+#include
+
+//
+// CArchSystemWindows
+//
+
+CArchSystemWindows::CArchSystemWindows()
+{
+ // do nothing
+}
+
+CArchSystemWindows::~CArchSystemWindows()
+{
+ // do nothing
+}
+
+std::string
+CArchSystemWindows::getOSName() const
+{
+ OSVERSIONINFO info;
+ info.dwOSVersionInfoSize = sizeof(info);
+ if (GetVersionEx(&info)) {
+ switch (info.dwPlatformId) {
+ case VER_PLATFORM_WIN32_NT:
+ if (info.dwMajorVersion == 5 && info.dwMinorVersion == 2) {
+ return "Microsoft Windows Server 2003";
+ }
+ if (info.dwMajorVersion == 5 && info.dwMinorVersion == 1) {
+ return "Microsoft Windows Server XP";
+ }
+ if (info.dwMajorVersion == 5 && info.dwMinorVersion == 0) {
+ return "Microsoft Windows Server 2000";
+ }
+ if (info.dwMajorVersion <= 4) {
+ return "Microsoft Windows NT";
+ }
+ char buffer[100];
+ sprintf(buffer, "Microsoft Windows %d.%d",
+ info.dwMajorVersion, info.dwMinorVersion);
+ return buffer;
+
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
+ if (info.szCSDVersion[1] == 'C' ||
+ info.szCSDVersion[1] == 'B') {
+ return "Microsoft Windows 95 OSR2";
+ }
+ return "Microsoft Windows 95";
+ }
+ if (info.dwMajorVersion == 4 && info.dwMinorVersion == 10) {
+ if (info.szCSDVersion[1] == 'A') {
+ return "Microsoft Windows 98 SE";
+ }
+ return "Microsoft Windows 98";
+ }
+ if (info.dwMajorVersion == 4 && info.dwMinorVersion == 90) {
+ return "Microsoft Windows ME";
+ }
+ if (info.dwMajorVersion == 4) {
+ return "Microsoft Windows unknown 95 family";
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return "Microsoft Windows ";
+}
diff --git a/lib/arch/CArchSystemWindows.h b/lib/arch/CArchSystemWindows.h
new file mode 100644
index 00000000..e23913d0
--- /dev/null
+++ b/lib/arch/CArchSystemWindows.h
@@ -0,0 +1,32 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CARCHSYSTEMWINDOWS_H
+#define CARCHSYSTEMWINDOWS_H
+
+#include "IArchSystem.h"
+
+#define ARCH_SYSTEM CArchSystemWindows
+
+//! Win32 implementation of IArchString
+class CArchSystemWindows : public IArchSystem {
+public:
+ CArchSystemWindows();
+ virtual ~CArchSystemWindows();
+
+ // IArchSystem overrides
+ virtual std::string getOSName() const;
+};
+
+#endif
diff --git a/lib/arch/CArchTaskBarWindows.cpp b/lib/arch/CArchTaskBarWindows.cpp
new file mode 100644
index 00000000..29c57b66
--- /dev/null
+++ b/lib/arch/CArchTaskBarWindows.cpp
@@ -0,0 +1,492 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CArchTaskBarWindows.h"
+#include "CArchMiscWindows.h"
+#include "IArchTaskBarReceiver.h"
+#include "CArch.h"
+#include "XArch.h"
+#include
+#include
+
+static const UINT kAddReceiver = WM_USER + 10;
+static const UINT kRemoveReceiver = WM_USER + 11;
+static const UINT kUpdateReceiver = WM_USER + 12;
+static const UINT kNotifyReceiver = WM_USER + 13;
+static const UINT kFirstReceiverID = WM_USER + 14;
+
+//
+// CArchTaskBarWindows
+//
+
+CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
+HINSTANCE CArchTaskBarWindows::s_appInstance = NULL;
+
+CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) :
+ m_nextID(kFirstReceiverID)
+{
+ // save the singleton instance
+ s_instance = this;
+
+ // save app instance
+ s_appInstance = reinterpret_cast(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(&CArchTaskBarWindows::threadEntry, this);
+
+ // wait for child thread
+ while (!m_ready) {
+ ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
+ }
+
+ // ready
+ ARCH->unlockMutex(m_mutex);
+}
+
+CArchTaskBarWindows::~CArchTaskBarWindows()
+{
+ 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
+CArchTaskBarWindows::addDialog(HWND hwnd)
+{
+ CArchMiscWindows::addDialog(hwnd);
+}
+
+void
+CArchTaskBarWindows::removeDialog(HWND hwnd)
+{
+ CArchMiscWindows::removeDialog(hwnd);
+}
+
+void
+CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
+{
+ // ignore bogus receiver
+ if (receiver == NULL) {
+ return;
+ }
+
+ // add receiver if necessary
+ CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
+ if (index == m_receivers.end()) {
+ // add it, creating a new message ID for it
+ CReceiverInfo info;
+ info.m_id = getNextID();
+ index = m_receivers.insert(std::make_pair(receiver, info)).first;
+
+ // add ID to receiver mapping
+ m_idTable.insert(std::make_pair(info.m_id, index));
+ }
+
+ // add receiver
+ PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0);
+}
+
+void
+CArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver)
+{
+ // find receiver
+ CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
+ if (index == m_receivers.end()) {
+ return;
+ }
+
+ // remove icon. wait for this to finish before returning.
+ SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0);
+
+ // recycle the ID
+ recycleID(index->second.m_id);
+
+ // discard
+ m_idTable.erase(index->second.m_id);
+ m_receivers.erase(index);
+}
+
+void
+CArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver)
+{
+ // find receiver
+ CReceiverToInfoMap::const_iterator index = m_receivers.find(receiver);
+ if (index == m_receivers.end()) {
+ return;
+ }
+
+ // update icon and tool tip
+ PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0);
+}
+
+UINT
+CArchTaskBarWindows::getNextID()
+{
+ if (m_oldIDs.empty()) {
+ return m_nextID++;
+ }
+ UINT id = m_oldIDs.back();
+ m_oldIDs.pop_back();
+ return id;
+}
+
+void
+CArchTaskBarWindows::recycleID(UINT id)
+{
+ m_oldIDs.push_back(id);
+}
+
+void
+CArchTaskBarWindows::addIcon(UINT id)
+{
+ ARCH->lockMutex(m_mutex);
+ CIDToReceiverMap::const_iterator index = m_idTable.find(id);
+ if (index != m_idTable.end()) {
+ modifyIconNoLock(index->second, NIM_ADD);
+ }
+ ARCH->unlockMutex(m_mutex);
+}
+
+void
+CArchTaskBarWindows::removeIcon(UINT id)
+{
+ ARCH->lockMutex(m_mutex);
+ removeIconNoLock(id);
+ ARCH->unlockMutex(m_mutex);
+}
+
+void
+CArchTaskBarWindows::updateIcon(UINT id)
+{
+ ARCH->lockMutex(m_mutex);
+ CIDToReceiverMap::const_iterator index = m_idTable.find(id);
+ if (index != m_idTable.end()) {
+ modifyIconNoLock(index->second, NIM_MODIFY);
+ }
+ ARCH->unlockMutex(m_mutex);
+}
+
+void
+CArchTaskBarWindows::addAllIcons()
+{
+ ARCH->lockMutex(m_mutex);
+ for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
+ index != m_receivers.end(); ++index) {
+ modifyIconNoLock(index, NIM_ADD);
+ }
+ ARCH->unlockMutex(m_mutex);
+}
+
+void
+CArchTaskBarWindows::removeAllIcons()
+{
+ ARCH->lockMutex(m_mutex);
+ for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
+ index != m_receivers.end(); ++index) {
+ removeIconNoLock(index->second.m_id);
+ }
+ ARCH->unlockMutex(m_mutex);
+}
+
+void
+CArchTaskBarWindows::modifyIconNoLock(
+ CReceiverToInfoMap::const_iterator index, DWORD taskBarMessage)
+{
+ // get receiver
+ UINT id = index->second.m_id;
+ IArchTaskBarReceiver* receiver = index->first;
+
+ // lock receiver so icon and tool tip are guaranteed to be consistent
+ receiver->lock();
+
+ // get icon data
+ HICON icon = reinterpret_cast(
+ const_cast(receiver->getIcon()));
+
+ // get tool tip
+ std::string toolTip = receiver->getToolTip();
+
+ // done querying
+ receiver->unlock();
+
+ // prepare to add icon
+ NOTIFYICONDATA data;
+ data.cbSize = sizeof(NOTIFYICONDATA);
+ data.hWnd = m_hwnd;
+ data.uID = id;
+ data.uFlags = NIF_MESSAGE;
+ data.uCallbackMessage = kNotifyReceiver;
+ data.hIcon = icon;
+ if (icon != NULL) {
+ data.uFlags |= NIF_ICON;
+ }
+ if (!toolTip.empty()) {
+ strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip));
+ data.szTip[sizeof(data.szTip) - 1] = '\0';
+ data.uFlags |= NIF_TIP;
+ }
+ else {
+ data.szTip[0] = '\0';
+ }
+
+ // add icon
+ if (Shell_NotifyIcon(taskBarMessage, &data) == 0) {
+ // failed
+ }
+}
+
+void
+CArchTaskBarWindows::removeIconNoLock(UINT id)
+{
+ NOTIFYICONDATA data;
+ data.cbSize = sizeof(NOTIFYICONDATA);
+ data.hWnd = m_hwnd;
+ data.uID = id;
+ if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) {
+ // failed
+ }
+}
+
+void
+CArchTaskBarWindows::handleIconMessage(
+ IArchTaskBarReceiver* receiver, LPARAM lParam)
+{
+ // process message
+ switch (lParam) {
+ case WM_LBUTTONDOWN:
+ receiver->showStatus();
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ receiver->primaryAction();
+ break;
+
+ case WM_RBUTTONUP: {
+ POINT p;
+ GetCursorPos(&p);
+ receiver->runMenu(p.x, p.y);
+ break;
+ }
+
+ case WM_MOUSEMOVE:
+ // currently unused
+ break;
+
+ default:
+ // unused
+ break;
+ }
+}
+
+bool
+CArchTaskBarWindows::processDialogs(MSG* msg)
+{
+ // only one thread can be in this method on any particular object
+ // at any given time. that's not a problem since only our event
+ // loop calls this method and there's just one of those.
+
+ ARCH->lockMutex(m_mutex);
+
+ // remove removed dialogs
+ m_dialogs.erase(false);
+
+ // merge added dialogs into the dialog list
+ for (CDialogs::const_iterator index = m_addedDialogs.begin();
+ index != m_addedDialogs.end(); ++index) {
+ m_dialogs.insert(std::make_pair(index->first, index->second));
+ }
+ m_addedDialogs.clear();
+
+ ARCH->unlockMutex(m_mutex);
+
+ // check message against all dialogs until one handles it.
+ // note that we don't hold a lock while checking because
+ // the message is processed and may make calls to this
+ // object. that's okay because addDialog() and
+ // removeDialog() don't change the map itself (just the
+ // values of some elements).
+ ARCH->lockMutex(m_mutex);
+ for (CDialogs::const_iterator index = m_dialogs.begin();
+ index != m_dialogs.end(); ++index) {
+ if (index->second) {
+ ARCH->unlockMutex(m_mutex);
+ if (IsDialogMessage(index->first, msg)) {
+ return true;
+ }
+ ARCH->lockMutex(m_mutex);
+ }
+ }
+ ARCH->unlockMutex(m_mutex);
+
+ return false;
+}
+
+LRESULT
+CArchTaskBarWindows::wndProc(HWND hwnd,
+ UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case kNotifyReceiver: {
+ // lookup receiver
+ CIDToReceiverMap::const_iterator index = m_idTable.find(wParam);
+ if (index != m_idTable.end()) {
+ IArchTaskBarReceiver* receiver = index->second->first;
+ handleIconMessage(receiver, lParam);
+ return 0;
+ }
+ break;
+ }
+
+ case kAddReceiver:
+ addIcon(wParam);
+ break;
+
+ case kRemoveReceiver:
+ removeIcon(wParam);
+ break;
+
+ case kUpdateReceiver:
+ updateIcon(wParam);
+ break;
+
+ default:
+ if (msg == m_taskBarRestart) {
+ // task bar was recreated so re-add our icons
+ addAllIcons();
+ }
+ break;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+LRESULT CALLBACK
+CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ // if msg is WM_NCCREATE, extract the CArchTaskBarWindows* and put
+ // it in the extra window data then forward the call.
+ CArchTaskBarWindows* self = NULL;
+ if (msg == WM_NCCREATE) {
+ CREATESTRUCT* createInfo;
+ createInfo = reinterpret_cast(lParam);
+ self = reinterpret_cast(
+ createInfo->lpCreateParams);
+ SetWindowLong(hwnd, 0, reinterpret_cast(self));
+ }
+ else {
+ // get the extra window data and forward the call
+ LONG data = GetWindowLong(hwnd, 0);
+ if (data != 0) {
+ self = reinterpret_cast(
+ reinterpret_cast(data));
+ }
+ }
+
+ // forward the message
+ if (self != NULL) {
+ return self->wndProc(hwnd, msg, wParam, lParam);
+ }
+ else {
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+}
+
+void
+CArchTaskBarWindows::threadMainLoop()
+{
+ // register the task bar restart message
+ m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
+
+ // register a window class
+ WNDCLASSEX classInfo;
+ classInfo.cbSize = sizeof(classInfo);
+ classInfo.style = CS_NOCLOSE;
+ classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
+ classInfo.cbClsExtra = 0;
+ classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
+ classInfo.hInstance = s_appInstance;
+ classInfo.hIcon = NULL;
+ classInfo.hCursor = NULL;
+ classInfo.hbrBackground = NULL;
+ classInfo.lpszMenuName = NULL;
+ classInfo.lpszClassName = TEXT("SynergyTaskBar");
+ classInfo.hIconSm = NULL;
+ ATOM windowClass = RegisterClassEx(&classInfo);
+
+ // create window
+ m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
+ reinterpret_cast(windowClass),
+ TEXT("Synergy Task Bar"),
+ WS_POPUP,
+ 0, 0, 1, 1,
+ NULL,
+ NULL,
+ s_appInstance,
+ reinterpret_cast(this));
+
+ // signal ready
+ ARCH->lockMutex(m_mutex);
+ m_ready = true;
+ ARCH->broadcastCondVar(m_condVar);
+ ARCH->unlockMutex(m_mutex);
+
+ // handle failure
+ if (m_hwnd == NULL) {
+ UnregisterClass(reinterpret_cast(windowClass), s_appInstance);
+ return;
+ }
+
+ // main loop
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ if (!processDialogs(&msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ // clean up
+ removeAllIcons();
+ DestroyWindow(m_hwnd);
+ UnregisterClass(reinterpret_cast(windowClass), s_appInstance);
+}
+
+void*
+CArchTaskBarWindows::threadEntry(void* self)
+{
+ reinterpret_cast(self)->threadMainLoop();
+ return NULL;
+}
diff --git a/lib/arch/CArchTaskBarWindows.h b/lib/arch/CArchTaskBarWindows.h
new file mode 100644
index 00000000..67e9af17
--- /dev/null
+++ b/lib/arch/CArchTaskBarWindows.h
@@ -0,0 +1,110 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CARCHTASKBARWINDOWS_H
+#define CARCHTASKBARWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "IArchTaskBar.h"
+#include "IArchMultithread.h"
+#include "stdmap.h"
+#include "stdvector.h"
+#include
+
+#define ARCH_TASKBAR CArchTaskBarWindows
+
+//! Win32 implementation of IArchTaskBar
+class CArchTaskBarWindows : public IArchTaskBar {
+public:
+ CArchTaskBarWindows(void*);
+ virtual ~CArchTaskBarWindows();
+
+ //! Add a dialog window
+ /*!
+ Tell the task bar event loop about a dialog. Win32 annoyingly
+ requires messages destined for modeless dialog boxes to be
+ dispatched differently than other messages.
+ */
+ static void addDialog(HWND);
+
+ //! Remove a dialog window
+ /*!
+ Remove a dialog window added via \c addDialog().
+ */
+ static void removeDialog(HWND);
+
+ // IArchTaskBar overrides
+ virtual void addReceiver(IArchTaskBarReceiver*);
+ virtual void removeReceiver(IArchTaskBarReceiver*);
+ virtual void updateReceiver(IArchTaskBarReceiver*);
+
+private:
+ class CReceiverInfo {
+ public:
+ UINT m_id;
+ };
+
+ typedef std::map CReceiverToInfoMap;
+ typedef std::map CIDToReceiverMap;
+ typedef std::vector CIDStack;
+ typedef std::map CDialogs;
+
+ UINT getNextID();
+ void recycleID(UINT);
+
+ void addIcon(UINT);
+ void removeIcon(UINT);
+ void updateIcon(UINT);
+ void addAllIcons();
+ void removeAllIcons();
+ void modifyIconNoLock(CReceiverToInfoMap::const_iterator,
+ DWORD taskBarMessage);
+ void removeIconNoLock(UINT id);
+ void handleIconMessage(IArchTaskBarReceiver*, LPARAM);
+
+ bool processDialogs(MSG*);
+ LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
+ static LRESULT CALLBACK
+ staticWndProc(HWND, UINT, WPARAM, LPARAM);
+ void threadMainLoop();
+ static void* threadEntry(void*);
+
+private:
+ static CArchTaskBarWindows* s_instance;
+ static HINSTANCE s_appInstance;
+
+ // multithread data
+ CArchMutex m_mutex;
+ CArchCond m_condVar;
+ bool m_ready;
+ int m_result;
+ CArchThread m_thread;
+
+ // child thread data
+ HWND m_hwnd;
+ UINT m_taskBarRestart;
+
+ // shared data
+ CReceiverToInfoMap m_receivers;
+ CIDToReceiverMap m_idTable;
+ CIDStack m_oldIDs;
+ UINT m_nextID;
+
+ // dialogs
+ CDialogs m_dialogs;
+ CDialogs m_addedDialogs;
+};
+
+#endif
diff --git a/lib/arch/CArchTaskBarXWindows.cpp b/lib/arch/CArchTaskBarXWindows.cpp
new file mode 100644
index 00000000..6934f271
--- /dev/null
+++ b/lib/arch/CArchTaskBarXWindows.cpp
@@ -0,0 +1,47 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CArchTaskBarXWindows.h"
+
+//
+// CArchTaskBarXWindows
+//
+
+CArchTaskBarXWindows::CArchTaskBarXWindows(void*)
+{
+ // do nothing
+}
+
+CArchTaskBarXWindows::~CArchTaskBarXWindows()
+{
+ // do nothing
+}
+
+void
+CArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver* /*receiver*/)
+{
+ // do nothing
+}
+
+void
+CArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver* /*receiver*/)
+{
+ // do nothing
+}
+
+void
+CArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver* /*receiver*/)
+{
+ // do nothing
+}
diff --git a/lib/arch/CArchTaskBarXWindows.h b/lib/arch/CArchTaskBarXWindows.h
new file mode 100644
index 00000000..abf28012
--- /dev/null
+++ b/lib/arch/CArchTaskBarXWindows.h
@@ -0,0 +1,34 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CARCHTASKBARXWINDOWS_H
+#define CARCHTASKBARXWINDOWS_H
+
+#include "IArchTaskBar.h"
+
+#define ARCH_TASKBAR CArchTaskBarXWindows
+
+//! X11 implementation of IArchTaskBar
+class CArchTaskBarXWindows : public IArchTaskBar {
+public:
+ CArchTaskBarXWindows(void*);
+ virtual ~CArchTaskBarXWindows();
+
+ // IArchTaskBar overrides
+ virtual void addReceiver(IArchTaskBarReceiver*);
+ virtual void removeReceiver(IArchTaskBarReceiver*);
+ virtual void updateReceiver(IArchTaskBarReceiver*);
+};
+
+#endif
diff --git a/lib/arch/CArchTimeUnix.cpp b/lib/arch/CArchTimeUnix.cpp
new file mode 100644
index 00000000..49506bad
--- /dev/null
+++ b/lib/arch/CArchTimeUnix.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "CArchTimeUnix.h"
+#if TIME_WITH_SYS_TIME
+# include
+# include
+#else
+# if HAVE_SYS_TIME_H
+# include
+# else
+# include
+# endif
+#endif
+
+//
+// CArchTimeUnix
+//
+
+CArchTimeUnix::CArchTimeUnix()
+{
+ // do nothing
+}
+
+CArchTimeUnix::~CArchTimeUnix()
+{
+ // do nothing
+}
+
+double
+CArchTimeUnix::time()
+{
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
+}
diff --git a/lib/arch/CArchTimeUnix.h b/lib/arch/CArchTimeUnix.h
new file mode 100644
index 00000000..78c6ff6f
--- /dev/null
+++ b/lib/arch/CArchTimeUnix.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHTIMEUNIX_H
+#define CARCHTIMEUNIX_H
+
+#include "IArchTime.h"
+
+#define ARCH_TIME CArchTimeUnix
+
+//! Generic Unix implementation of IArchTime
+class CArchTimeUnix : public IArchTime {
+public:
+ CArchTimeUnix();
+ virtual ~CArchTimeUnix();
+
+ // IArchTime overrides
+ virtual double time();
+};
+
+#endif
diff --git a/lib/arch/CArchTimeWindows.cpp b/lib/arch/CArchTimeWindows.cpp
new file mode 100644
index 00000000..57aee290
--- /dev/null
+++ b/lib/arch/CArchTimeWindows.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+// avoid getting a lot a crap from mmsystem.h that we don't need
+#define MMNODRV // Installable driver support
+#define MMNOSOUND // Sound support
+#define MMNOWAVE // Waveform support
+#define MMNOMIDI // MIDI support
+#define MMNOAUX // Auxiliary audio support
+#define MMNOMIXER // Mixer support
+#define MMNOJOY // Joystick support
+#define MMNOMCI // MCI support
+#define MMNOMMIO // Multimedia file I/O support
+#define MMNOMMSYSTEM // General MMSYSTEM functions
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "CArchTimeWindows.h"
+#include
+#include
+
+typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void);
+
+static double s_freq = 0.0;
+static HINSTANCE s_mmInstance = NULL;
+static PTimeGetTime s_tgt = NULL;
+
+
+//
+// CArchTimeWindows
+//
+
+CArchTimeWindows::CArchTimeWindows()
+{
+ assert(s_freq == 0.0 || s_mmInstance == NULL);
+
+ LARGE_INTEGER freq;
+ if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) {
+ s_freq = 1.0 / static_cast(freq.QuadPart);
+ }
+ else {
+ // load winmm.dll and get timeGetTime
+ s_mmInstance = LoadLibrary("winmm");
+ if (s_mmInstance != NULL) {
+ s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime");
+ }
+ }
+}
+
+CArchTimeWindows::~CArchTimeWindows()
+{
+ s_freq = 0.0;
+ if (s_mmInstance == NULL) {
+ FreeLibrary(reinterpret_cast(s_mmInstance));
+ s_tgt = NULL;
+ s_mmInstance = NULL;
+ }
+}
+
+double
+CArchTimeWindows::time()
+{
+ // get time. we try three ways, in order of descending precision
+ if (s_freq != 0.0) {
+ LARGE_INTEGER c;
+ QueryPerformanceCounter(&c);
+ return s_freq * static_cast(c.QuadPart);
+ }
+ else if (s_tgt != NULL) {
+ return 0.001 * static_cast(s_tgt());
+ }
+ else {
+ return 0.001 * static_cast(GetTickCount());
+ }
+}
diff --git a/lib/arch/CArchTimeWindows.h b/lib/arch/CArchTimeWindows.h
new file mode 100644
index 00000000..fb9b1e9f
--- /dev/null
+++ b/lib/arch/CArchTimeWindows.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef CARCHTIMEWINDOWS_H
+#define CARCHTIMEWINDOWS_H
+
+#include "IArchTime.h"
+
+#define ARCH_TIME CArchTimeWindows
+
+//! Win32 implementation of IArchTime
+class CArchTimeWindows : public IArchTime {
+public:
+ CArchTimeWindows();
+ virtual ~CArchTimeWindows();
+
+ // IArchTime overrides
+ virtual double time();
+};
+
+#endif
diff --git a/lib/arch/CMultibyte.cpp b/lib/arch/CMultibyte.cpp
new file mode 100644
index 00000000..517d72d6
--- /dev/null
+++ b/lib/arch/CMultibyte.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+#ifndef CMULTIBYTE_H
+#define CMULTIBYTE_H
+
+#include "common.h"
+#include "CArch.h"
+#include
+#include
+#if HAVE_LOCALE_H
+# include
+#endif
+#if HAVE_WCHAR_H || defined(_MSC_VER)
+# include
+#elif __APPLE__
+ // wtf? Darwin puts mbtowc() et al. in stdlib
+# include
+#else
+ // platform apparently has no wchar_t support. provide dummy
+ // implementations. hopefully at least the C++ compiler has
+ // a built-in wchar_t type.
+
+static inline
+int
+mbtowc(wchar_t* dst, const char* src, int n)
+{
+ *dst = static_cast(*src);
+ return 1;
+}
+
+static inline
+int
+wctomb(char* dst, wchar_t src)
+{
+ *dst = static_cast(src);
+ return 1;
+}
+
+#endif
+
+//
+// use C library non-reentrant multibyte conversion with mutex
+//
+
+static CArchMutex s_mutex = NULL;
+
+ARCH_STRING::ARCH_STRING()
+{
+ s_mutex = ARCH->newMutex();
+
+#if HAVE_LOCALE_H
+ // see if we can convert a Latin-1 character
+ char mb[MB_LEN_MAX];
+ if (wctomb(mb, 0xe3) == -1) {
+ // can't convert. try another locale so we can convert latin-1.
+ setlocale(LC_CTYPE, "en_US");
+ }
+#endif
+}
+
+ARCH_STRING::~ARCH_STRING()
+{
+ ARCH->closeMutex(s_mutex);
+ s_mutex = NULL;
+}
+
+int
+ARCH_STRING::convStringWCToMB(char* dst,
+ const wchar_t* src, UInt32 n, bool* errors)
+{
+ int len = 0;
+
+ bool dummyErrors;
+ if (errors == NULL) {
+ errors = &dummyErrors;
+ }
+
+ ARCH->lockMutex(s_mutex);
+ if (dst == NULL) {
+ char dummy[MB_LEN_MAX];
+ for (const wchar_t* scan = src; n > 0; ++scan, --n) {
+ int mblen = wctomb(dummy, *scan);
+ if (mblen == -1) {
+ *errors = true;
+ mblen = 1;
+ }
+ len += mblen;
+ }
+ int mblen = wctomb(dummy, L'\0');
+ if (mblen != -1) {
+ len += mblen - 1;
+ }
+ }
+ else {
+ char* dst0 = dst;
+ for (const wchar_t* scan = src; n > 0; ++scan, --n) {
+ int mblen = wctomb(dst, *scan);
+ if (mblen == -1) {
+ *errors = true;
+ *dst++ = '?';
+ }
+ else {
+ dst += mblen;
+ }
+ }
+ int mblen = wctomb(dst, L'\0');
+ if (mblen != -1) {
+ // don't include nul terminator
+ dst += mblen - 1;
+ }
+ len = (int)(dst - dst0);
+ }
+ ARCH->unlockMutex(s_mutex);
+
+ return len;
+}
+
+int
+ARCH_STRING::convStringMBToWC(wchar_t* dst,
+ const char* src, UInt32 n, bool* errors)
+{
+ int len = 0;
+ wchar_t dummy;
+
+ bool dummyErrors;
+ if (errors == NULL) {
+ errors = &dummyErrors;
+ }
+
+ ARCH->lockMutex(s_mutex);
+ if (dst == NULL) {
+ for (const char* scan = src; n > 0; ) {
+ int mblen = mbtowc(&dummy, scan, n);
+ switch (mblen) {
+ case -2:
+ // incomplete last character. convert to unknown character.
+ *errors = true;
+ len += 1;
+ n = 0;
+ break;
+
+ case -1:
+ // invalid character. count one unknown character and
+ // start at the next byte.
+ *errors = true;
+ len += 1;
+ scan += 1;
+ n -= 1;
+ break;
+
+ case 0:
+ len += 1;
+ scan += 1;
+ n -= 1;
+ break;
+
+ default:
+ // normal character
+ len += 1;
+ scan += mblen;
+ n -= mblen;
+ break;
+ }
+ }
+ }
+ else {
+ wchar_t* dst0 = dst;
+ for (const char* scan = src; n > 0; ++dst) {
+ int mblen = mbtowc(dst, scan, n);
+ switch (mblen) {
+ case -2:
+ // incomplete character. convert to unknown character.
+ *errors = true;
+ *dst = (wchar_t)0xfffd;
+ n = 0;
+ break;
+
+ case -1:
+ // invalid character. count one unknown character and
+ // start at the next byte.
+ *errors = true;
+ *dst = (wchar_t)0xfffd;
+ scan += 1;
+ n -= 1;
+ break;
+
+ case 0:
+ *dst = (wchar_t)0x0000;
+ scan += 1;
+ n -= 1;
+ break;
+
+ default:
+ // normal character
+ scan += mblen;
+ n -= mblen;
+ break;
+ }
+ }
+ len = (int)(dst - dst0);
+ }
+ ARCH->unlockMutex(s_mutex);
+
+ return len;
+}
+
+#endif
diff --git a/lib/arch/IArchConsole.h b/lib/arch/IArchConsole.h
new file mode 100644
index 00000000..2befb196
--- /dev/null
+++ b/lib/arch/IArchConsole.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHCONSOLE_H
+#define IARCHCONSOLE_H
+
+#include "IInterface.h"
+
+//! Interface for architecture dependent console output
+/*!
+This interface defines the console operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchConsole : public IInterface {
+public:
+ //! @name manipulators
+ //@{
+
+ //! Open the console
+ /*!
+ Opens the console for writing. The console is opened automatically
+ on the first write so calling this method is optional. Uses \c title
+ for the console's title if appropriate for the architecture. Calling
+ this method on an already open console must have no effect.
+ */
+ virtual void openConsole(const char* title) = 0;
+
+ //! Close the console
+ /*!
+ Close the console. Calling this method on an already closed console
+ must have no effect.
+ */
+ virtual void closeConsole() = 0;
+
+ //! Show the console
+ /*!
+ Causes the console to become visible. This generally only makes sense
+ for a console in a graphical user interface. Other implementations
+ will do nothing. Iff \p showIfEmpty is \c false then the implementation
+ may optionally only show the console if it's not empty.
+ */
+ virtual void showConsole(bool showIfEmpty) = 0;
+
+ //! Write to the console
+ /*!
+ Writes the given string to the console, opening it if necessary.
+ */
+ 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;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchDaemon.h b/lib/arch/IArchDaemon.h
new file mode 100644
index 00000000..ba6b049b
--- /dev/null
+++ b/lib/arch/IArchDaemon.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHDAEMON_H
+#define IARCHDAEMON_H
+
+#include "IInterface.h"
+
+//! Interface for architecture dependent daemonizing
+/*!
+This interface defines the operations required by synergy for installing
+uninstalling daeamons and daemonizing a process. Each architecture must
+implement this interface.
+*/
+class IArchDaemon : public IInterface {
+public:
+ typedef int (*DaemonFunc)(int argc, const char** argv);
+
+ //! @name manipulators
+ //@{
+
+ //! Install daemon
+ /*!
+ Install a daemon. \c name is the name of the daemon passed to the
+ system and \c description is a short human readable description of
+ the daemon. \c pathname is the path to the daemon executable.
+ \c commandLine should \b not include the name of program as the
+ first argument. If \c allUsers is true then the daemon will be
+ installed to start at boot time, otherwise it will be installed to
+ start when the current user logs in. If \p dependencies is not NULL
+ then it's a concatenation of NUL terminated other daemon names
+ followed by a NUL; the daemon will be configured to startup after
+ the listed daemons. Throws an \c XArchDaemon exception on failure.
+ */
+ virtual void installDaemon(const char* name,
+ const char* description,
+ const char* pathname,
+ const char* commandLine,
+ const char* dependencies,
+ bool allUsers) = 0;
+
+ //! Uninstall daemon
+ /*!
+ Uninstall a daemon. Throws an \c XArchDaemon on failure.
+ */
+ virtual void uninstallDaemon(const char* name, bool allUsers) = 0;
+
+ //! Daemonize the process
+ /*!
+ Daemonize. Throw XArchDaemonFailed on error. \c name is the name
+ of the daemon. Once daemonized, \c func is invoked and daemonize
+ returns when and what it does.
+
+ Exactly what happens when daemonizing depends on the platform.
+
+
unix:
+ Detaches from terminal. \c func gets passed one argument, the
+ name passed to daemonize().
+
win32:
+ Becomes a service. Argument 0 is the name of the service
+ and the rest are the arguments passed to StartService().
+ \c func is only called when the service is actually started.
+ \c func must call \c CArchMiscWindows::runDaemon() to finally
+ becoming a service. The \c runFunc function passed to \c runDaemon()
+ must call \c CArchMiscWindows::daemonRunning(true) when it
+ enters the main loop (i.e. after initialization) and
+ \c CArchMiscWindows::daemonRunning(false) when it leaves
+ the main loop. The \c stopFunc function passed to \c runDaemon()
+ is called when the daemon must exit the main loop and it must cause
+ \c runFunc to return. \c func should return what \c runDaemon()
+ returns. \c func or \c runFunc can call
+ \c CArchMiscWindows::daemonFailed() to indicate startup failure.
+
+ */
+ virtual int daemonize(const char* name, DaemonFunc func) = 0;
+
+ //! Check if user has permission to install the daemon
+ /*!
+ Returns true iff the caller has permission to install or
+ uninstall the daemon. Note that even if this method returns
+ true it's possible that installing/uninstalling the service
+ may still fail. This method ignores whether or not the
+ service is already installed.
+ */
+ virtual bool canInstallDaemon(const char* name, bool allUsers) = 0;
+
+ //! Check if the daemon is installed
+ /*!
+ Returns true iff the daemon is installed.
+ */
+ virtual bool isDaemonInstalled(const char* name, bool allUsers) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchFile.h b/lib/arch/IArchFile.h
new file mode 100644
index 00000000..8594053d
--- /dev/null
+++ b/lib/arch/IArchFile.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHFILE_H
+#define IARCHFILE_H
+
+#include "IInterface.h"
+#include "stdstring.h"
+
+//! Interface for architecture dependent file system operations
+/*!
+This interface defines the file system operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchFile : public IInterface {
+public:
+ //! @name manipulators
+ //@{
+
+ //! Extract base name
+ /*!
+ Find the base name in the given \c pathname.
+ */
+ virtual const char* getBasename(const char* pathname) = 0;
+
+ //! Get user's home directory
+ /*!
+ Returns the user's home directory. Returns the empty string if
+ this cannot be determined.
+ */
+ virtual std::string getUserDirectory() = 0;
+
+ //! Get system directory
+ /*!
+ Returns the ussystem configuration file directory.
+ */
+ virtual std::string getSystemDirectory() = 0;
+
+ //! Concatenate path components
+ /*!
+ Concatenate pathname components with a directory separator
+ between them. This should not check if the resulting path
+ is longer than allowed by the system; we'll rely on the
+ system calls to tell us that.
+ */
+ virtual std::string concatPath(
+ const std::string& prefix,
+ const std::string& suffix) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchLog.h b/lib/arch/IArchLog.h
new file mode 100644
index 00000000..7655ff95
--- /dev/null
+++ b/lib/arch/IArchLog.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHLOG_H
+#define IARCHLOG_H
+
+#include "IInterface.h"
+
+//! Interface for architecture dependent logging
+/*!
+This interface defines the logging operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchLog : public IInterface {
+public:
+ //! Log levels
+ /*!
+ The logging priority levels in order of highest to lowest priority.
+ */
+ enum ELevel {
+ kERROR, //!< For serious or fatal errors
+ kWARNING, //!< For minor errors and warnings
+ kNOTE, //!< For messages about notable events
+ kINFO, //!< For informational messages
+ kDEBUG //!< For debugging messages
+ };
+
+ //! @name manipulators
+ //@{
+
+ //! Open the log
+ /*!
+ Opens the log for writing. The log must be opened before being
+ written to.
+ */
+ virtual void openLog(const char* name) = 0;
+
+ //! Close the log
+ /*!
+ Close the log.
+ */
+ virtual void closeLog() = 0;
+
+ //! Show the log
+ /*!
+ Causes the log to become visible. This generally only makes sense
+ for a log in a graphical user interface. Other implementations
+ will do nothing. Iff \p showIfEmpty is \c false then the implementation
+ may optionally only show the log if it's not empty.
+ */
+ virtual void showLog(bool showIfEmpty) = 0;
+
+ //! Write to the log
+ /*!
+ Writes the given string to the log with the given level.
+ */
+ virtual void writeLog(ELevel, const char*) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchMultithread.h b/lib/arch/IArchMultithread.h
new file mode 100644
index 00000000..b7b72293
--- /dev/null
+++ b/lib/arch/IArchMultithread.h
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHMULTITHREAD_H
+#define IARCHMULTITHREAD_H
+
+#include "IInterface.h"
+
+/*!
+\class CArchCondImpl
+\brief Internal condition variable data.
+An architecture dependent type holding the necessary data for a
+condition variable.
+*/
+class CArchCondImpl;
+
+/*!
+\var CArchCond
+\brief Opaque condition variable type.
+An opaque type representing a condition variable.
+*/
+typedef CArchCondImpl* CArchCond;
+
+/*!
+\class CArchMutexImpl
+\brief Internal mutex data.
+An architecture dependent type holding the necessary data for a mutex.
+*/
+class CArchMutexImpl;
+
+/*!
+\var CArchMutex
+\brief Opaque mutex type.
+An opaque type representing a mutex.
+*/
+typedef CArchMutexImpl* CArchMutex;
+
+/*!
+\class CArchThreadImpl
+\brief Internal thread data.
+An architecture dependent type holding the necessary data for a thread.
+*/
+class CArchThreadImpl;
+
+/*!
+\var CArchThread
+\brief Opaque thread type.
+An opaque type representing a thread.
+*/
+typedef CArchThreadImpl* CArchThread;
+
+//! Interface for architecture dependent multithreading
+/*!
+This interface defines the multithreading operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchMultithread : public IInterface {
+public:
+ //! Type of thread entry point
+ typedef void* (*ThreadFunc)(void*);
+ //! Type of thread identifier
+ typedef unsigned int ThreadID;
+ //! Types of signals
+ /*!
+ Not all platforms support all signals. Unsupported signals are
+ ignored.
+ */
+ enum ESignal {
+ kINTERRUPT, //!< Interrupt (e.g. Ctrl+C)
+ kTERMINATE, //!< Terminate (e.g. Ctrl+Break)
+ kHANGUP, //!< Hangup (SIGHUP)
+ kUSER, //!< User (SIGUSR2)
+ kNUM_SIGNALS
+ };
+ //! Type of signal handler function
+ typedef void (*SignalFunc)(ESignal, void* userData);
+
+ //! @name manipulators
+ //@{
+
+ //
+ // condition variable methods
+ //
+
+ //! Create a condition variable
+ /*!
+ The condition variable is an opaque data type.
+ */
+ virtual CArchCond newCondVar() = 0;
+
+ //! Destroy a condition variable
+ virtual void closeCondVar(CArchCond) = 0;
+
+ //! Signal a condition variable
+ /*!
+ Signalling a condition variable releases one waiting thread.
+ */
+ virtual void signalCondVar(CArchCond) = 0;
+
+ //! Broadcast a condition variable
+ /*!
+ Broadcasting a condition variable releases all waiting threads.
+ */
+ virtual void broadcastCondVar(CArchCond) = 0;
+
+ //! Wait on a condition variable
+ /*!
+ Wait on a conditation variable for up to \c timeout seconds.
+ If \c timeout is < 0 then there is no timeout. The mutex must
+ be locked when this method is called. The mutex is unlocked
+ during the wait and locked again before returning. Returns
+ true if the condition variable was signalled and false on
+ timeout.
+
+ (Cancellation point)
+ */
+ virtual bool waitCondVar(CArchCond, CArchMutex, double timeout) = 0;
+
+ //
+ // mutex methods
+ //
+
+ //! Create a recursive mutex
+ /*!
+ Creates a recursive mutex. A thread may lock a recursive mutex
+ when it already holds a lock on that mutex. The mutex is an
+ opaque data type.
+ */
+ virtual CArchMutex newMutex() = 0;
+
+ //! Destroy a mutex
+ virtual void closeMutex(CArchMutex) = 0;
+
+ //! Lock a mutex
+ virtual void lockMutex(CArchMutex) = 0;
+
+ //! Unlock a mutex
+ virtual void unlockMutex(CArchMutex) = 0;
+
+ //
+ // thread methods
+ //
+
+ //! Start a new thread
+ /*!
+ Creates and starts a new thread, using \c func as the entry point
+ and passing it \c userData. The thread is an opaque data type.
+ */
+ virtual CArchThread newThread(ThreadFunc func, void* userData) = 0;
+
+ //! Get a reference to the calling thread
+ /*!
+ Returns a thread representing the current (i.e. calling) thread.
+ */
+ virtual CArchThread newCurrentThread() = 0;
+
+ //! Copy a thread object
+ /*!
+ Returns a reference to to thread referred to by \c thread.
+ */
+ virtual CArchThread copyThread(CArchThread thread) = 0;
+
+ //! Release a thread reference
+ /*!
+ Deletes the given thread object. This does not destroy the thread
+ the object referred to, even if there are no remaining references.
+ Use cancelThread() and waitThread() to stop a thread and wait for
+ it to exit.
+ */
+ virtual void closeThread(CArchThread) = 0;
+
+ //! Force a thread to exit
+ /*!
+ Causes \c thread to exit when it next calls a cancellation point.
+ A thread avoids cancellation as long as it nevers calls a
+ cancellation point. Once it begins the cancellation process it
+ must always let cancellation go to completion but may take as
+ long as necessary to clean up.
+ */
+ virtual void cancelThread(CArchThread thread) = 0;
+
+ //! Change thread priority
+ /*!
+ Changes the priority of \c thread by \c n. If \c n is positive
+ the thread has a lower priority and if negative a higher priority.
+ Some architectures may not support either or both directions.
+ */
+ virtual void setPriorityOfThread(CArchThread, int n) = 0;
+
+ //! Cancellation point
+ /*!
+ This method does nothing but is a cancellation point. Clients
+ can make their own functions cancellation points by calling this
+ method at appropriate times.
+
+ (Cancellation point)
+ */
+ virtual void testCancelThread() = 0;
+
+ //! Wait for a thread to exit
+ /*!
+ Waits for up to \c timeout seconds for \c thread to exit (normally
+ or by cancellation). Waits forever if \c timeout < 0. Returns
+ true if the thread exited, false otherwise. Waiting on the current
+ thread returns immediately with false.
+
+ (Cancellation point)
+ */
+ virtual bool wait(CArchThread thread, double timeout) = 0;
+
+ //! Compare threads
+ /*!
+ Returns true iff two thread objects refer to the same thread.
+ Note that comparing thread objects directly is meaningless.
+ */
+ virtual bool isSameThread(CArchThread, CArchThread) = 0;
+
+ //! Test if thread exited
+ /*!
+ Returns true iff \c thread has exited.
+ */
+ virtual bool isExitedThread(CArchThread thread) = 0;
+
+ //! Returns the exit code of a thread
+ /*!
+ Waits indefinitely for \c thread to exit (if it hasn't yet) then
+ returns the thread's exit code.
+
+ (Cancellation point)
+ */
+ virtual void* getResultOfThread(CArchThread thread) = 0;
+
+ //! Returns an ID for a thread
+ /*!
+ Returns some ID number for \c thread. This is for logging purposes.
+ All thread objects referring to the same thread return the same ID.
+ However, clients should us isSameThread() to compare thread objects
+ instead of comparing IDs.
+ */
+ virtual ThreadID getIDOfThread(CArchThread thread) = 0;
+
+ //! Set the interrupt handler
+ /*!
+ Sets the function to call on receipt of an external interrupt.
+ By default and when \p func is NULL, the main thread is cancelled.
+ */
+ virtual void setSignalHandler(ESignal, SignalFunc func,
+ void* userData) = 0;
+
+ //! Invoke the signal handler
+ /*!
+ Invokes the signal handler for \p signal, if any. If no handler
+ cancels the main thread for \c kINTERRUPT and \c kTERMINATE and
+ ignores the call otherwise.
+ */
+ virtual void raiseSignal(ESignal signal) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchNetwork.h b/lib/arch/IArchNetwork.h
new file mode 100644
index 00000000..007fb442
--- /dev/null
+++ b/lib/arch/IArchNetwork.h
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHNETWORK_H
+#define IARCHNETWORK_H
+
+#include "IInterface.h"
+#include "stdstring.h"
+
+class CArchThreadImpl;
+typedef CArchThreadImpl* CArchThread;
+
+/*!
+\class CArchSocketImpl
+\brief Internal socket data.
+An architecture dependent type holding the necessary data for a socket.
+*/
+class CArchSocketImpl;
+
+/*!
+\var CArchSocket
+\brief Opaque socket type.
+An opaque type representing a socket.
+*/
+typedef CArchSocketImpl* CArchSocket;
+
+/*!
+\class CArchNetAddressImpl
+\brief Internal network address data.
+An architecture dependent type holding the necessary data for a network
+address.
+*/
+class CArchNetAddressImpl;
+
+/*!
+\var CArchNetAddress
+\brief Opaque network address type.
+An opaque type representing a network address.
+*/
+typedef CArchNetAddressImpl* CArchNetAddress;
+
+//! Interface for architecture dependent networking
+/*!
+This interface defines the networking operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchNetwork : public IInterface {
+public:
+ //! Supported address families
+ enum EAddressFamily {
+ kUNKNOWN,
+ kINET,
+ };
+
+ //! Supported socket types
+ enum ESocketType {
+ kDGRAM,
+ kSTREAM
+ };
+
+ //! Events for \c poll()
+ /*!
+ Events for \c poll() are bitmasks and can be combined using the
+ bitwise operators.
+ */
+ enum {
+ kPOLLIN = 1, //!< Socket is readable
+ kPOLLOUT = 2, //!< Socket is writable
+ kPOLLERR = 4, //!< The socket is in an error state
+ kPOLLNVAL = 8 //!< The socket is invalid
+ };
+
+ //! A socket query for \c poll()
+ class CPollEntry {
+ public:
+ //! The socket to query
+ CArchSocket m_socket;
+
+ //! The events to query for
+ /*!
+ The events to query for can be any combination of kPOLLIN and
+ kPOLLOUT.
+ */
+ unsigned short m_events;
+
+ //! The result events
+ unsigned short m_revents;
+ };
+
+ //! @name manipulators
+ //@{
+
+ //! Create a new socket
+ /*!
+ The socket is an opaque data type.
+ */
+ virtual CArchSocket newSocket(EAddressFamily, ESocketType) = 0;
+
+ //! Copy a socket object
+ /*!
+ Returns a reference to to socket referred to by \c s.
+ */
+ virtual CArchSocket copySocket(CArchSocket s) = 0;
+
+ //! Release a socket reference
+ /*!
+ Deletes the given socket object. This does not destroy the socket
+ the object referred to until there are no remaining references for
+ the socket.
+ */
+ virtual void closeSocket(CArchSocket s) = 0;
+
+ //! Close socket for further reads
+ /*!
+ Calling this disallows future reads on socket \c s.
+ */
+ virtual void closeSocketForRead(CArchSocket s) = 0;
+
+ //! Close socket for further writes
+ /*!
+ Calling this disallows future writes on socket \c s.
+ */
+ virtual void closeSocketForWrite(CArchSocket s) = 0;
+
+ //! Bind socket to address
+ /*!
+ Binds socket \c s to the address \c addr.
+ */
+ virtual void bindSocket(CArchSocket s, CArchNetAddress addr) = 0;
+
+ //! Listen for connections on socket
+ /*!
+ Causes the socket \c s to begin listening for incoming connections.
+ */
+ virtual void listenOnSocket(CArchSocket s) = 0;
+
+ //! Accept connection on socket
+ /*!
+ Accepts a connection on socket \c s, returning a new socket for the
+ connection and filling in \c addr with the address of the remote
+ end. \c addr may be NULL if the remote address isn't required.
+ The original socket \c s is unaffected and remains in the listening
+ state. The new socket shares most of the properties of \c s except
+ it's not in the listening state and it's connected. Returns NULL
+ if there are no pending connection requests.
+ */
+ virtual CArchSocket acceptSocket(CArchSocket s, CArchNetAddress* addr) = 0;
+
+ //! Connect socket
+ /*!
+ Connects the socket \c s to the remote address \c addr. Returns
+ true if the connection succeed immediately, false if the connection
+ is in progress, and throws if the connection failed immediately.
+ If it returns false, \c pollSocket() can be used to wait on the
+ socket for writing to detect when the connection finally succeeds
+ or fails.
+ */
+ virtual bool connectSocket(CArchSocket s, CArchNetAddress addr) = 0;
+
+ //! Check socket state
+ /*!
+ Tests the state of \c num sockets for readability and/or writability.
+ Waits up to \c timeout seconds for some socket to become readable
+ and/or writable (or indefinitely if \c timeout < 0). Returns the
+ number of sockets that were readable (if readability was being
+ queried) or writable (if writablility was being queried) and sets
+ the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL
+ are set in \c m_revents as appropriate. If a socket indicates
+ \c kPOLLERR then \c throwErrorOnSocket() can be used to determine
+ the type of error. Returns 0 immediately regardless of the \c timeout
+ if no valid sockets are selected for testing.
+
+ (Cancellation point)
+ */
+ virtual int pollSocket(CPollEntry[], int num, double timeout) = 0;
+
+ //! Unblock thread in pollSocket()
+ /*!
+ Cause a thread that's in a pollSocket() call to return. This
+ call may return before the thread is unblocked. If the thread is
+ not in a pollSocket() call this call has no effect.
+ */
+ virtual void unblockPollSocket(CArchThread thread) = 0;
+
+ //! Read data from socket
+ /*!
+ Read up to \c len bytes from socket \c s in \c buf and return the
+ number of bytes read. The number of bytes can be less than \c len
+ if not enough data is available. Returns 0 if the remote end has
+ disconnected and/or there is no more queued received data.
+ */
+ virtual size_t readSocket(CArchSocket s, void* buf, size_t len) = 0;
+
+ //! Write data from socket
+ /*!
+ Write up to \c len bytes to socket \c s from \c buf and return the
+ number of bytes written. The number of bytes can be less than
+ \c len if the remote end disconnected or the internal buffers fill
+ up.
+ */
+ virtual size_t writeSocket(CArchSocket s,
+ const void* buf, size_t len) = 0;
+
+ //! Check error on socket
+ /*!
+ If the socket \c s is in an error state then throws an appropriate
+ XArchNetwork exception.
+ */
+ virtual void throwErrorOnSocket(CArchSocket s) = 0;
+
+ //! Turn Nagle algorithm on or off on socket
+ /*!
+ Set socket to send messages immediately (true) or to collect small
+ messages into one packet (false). Returns the previous state.
+ */
+ virtual bool setNoDelayOnSocket(CArchSocket, bool noDelay) = 0;
+
+ //! Turn address reuse on or off on socket
+ /*!
+ Allows the address this socket is bound to to be reused while in the
+ TIME_WAIT state. Returns the previous state.
+ */
+ virtual bool setReuseAddrOnSocket(CArchSocket, bool reuse) = 0;
+
+ //! Return local host's name
+ virtual std::string getHostName() = 0;
+
+ //! Create an "any" network address
+ virtual CArchNetAddress newAnyAddr(EAddressFamily) = 0;
+
+ //! Copy a network address
+ virtual CArchNetAddress copyAddr(CArchNetAddress) = 0;
+
+ //! Convert a name to a network address
+ virtual CArchNetAddress nameToAddr(const std::string&) = 0;
+
+ //! Destroy a network address
+ virtual void closeAddr(CArchNetAddress) = 0;
+
+ //! Convert an address to a host name
+ virtual std::string addrToName(CArchNetAddress) = 0;
+
+ //! Convert an address to a string
+ virtual std::string addrToString(CArchNetAddress) = 0;
+
+ //! Get an address's family
+ virtual EAddressFamily getAddrFamily(CArchNetAddress) = 0;
+
+ //! Set the port of an address
+ virtual void setAddrPort(CArchNetAddress, int port) = 0;
+
+ //! Get the port of an address
+ virtual int getAddrPort(CArchNetAddress) = 0;
+
+ //! Test addresses for equality
+ virtual bool isEqualAddr(CArchNetAddress, CArchNetAddress) = 0;
+
+ //! Test for the "any" address
+ /*!
+ Returns true if \c addr is the "any" address. \c newAnyAddr()
+ returns an "any" address.
+ */
+ virtual bool isAnyAddr(CArchNetAddress addr) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchSleep.h b/lib/arch/IArchSleep.h
new file mode 100644
index 00000000..95a2852c
--- /dev/null
+++ b/lib/arch/IArchSleep.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHSLEEP_H
+#define IARCHSLEEP_H
+
+#include "IInterface.h"
+
+//! Interface for architecture dependent sleeping
+/*!
+This interface defines the sleep operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchSleep : public IInterface {
+public:
+ //! @name manipulators
+ //@{
+
+ //! Sleep
+ /*!
+ Blocks the calling thread for \c timeout seconds. If
+ \c timeout < 0.0 then the call returns immediately. If \c timeout
+ == 0.0 then the calling thread yields the CPU.
+
+ (cancellation point)
+ */
+ virtual void sleep(double timeout) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchString.h b/lib/arch/IArchString.h
new file mode 100644
index 00000000..703d64b1
--- /dev/null
+++ b/lib/arch/IArchString.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHSTRING_H
+#define IARCHSTRING_H
+
+#include "IInterface.h"
+#include "BasicTypes.h"
+#include
+
+//! Interface for architecture dependent string operations
+/*!
+This interface defines the string operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchString : public IInterface {
+public:
+ //! Wide character encodings
+ /*!
+ The known wide character encodings
+ */
+ enum EWideCharEncoding {
+ kUCS2, //!< The UCS-2 encoding
+ kUCS4, //!< The UCS-4 encoding
+ kUTF16, //!< The UTF-16 encoding
+ kUTF32 //!< The UTF-32 encoding
+ };
+
+ //! @name manipulators
+ //@{
+
+ //! printf() to limited size buffer with va_list
+ /*!
+ This method is equivalent to vsprintf() except it will not write
+ more than \c n bytes to the buffer, returning -1 if the output
+ was truncated and the number of bytes written not including the
+ trailing NUL otherwise.
+ */
+ virtual int vsnprintf(char* str,
+ int size, const char* fmt, va_list ap) = 0;
+
+ //! Convert multibyte string to wide character string
+ virtual int convStringMBToWC(wchar_t*,
+ const char*, UInt32 n, bool* errors) = 0;
+
+ //! Convert wide character string to multibyte string
+ virtual int convStringWCToMB(char*,
+ const wchar_t*, UInt32 n, bool* errors) = 0;
+
+ //! Return the architecture's native wide character encoding
+ virtual EWideCharEncoding
+ getWideCharEncoding() = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchSystem.h b/lib/arch/IArchSystem.h
new file mode 100644
index 00000000..7a6c941b
--- /dev/null
+++ b/lib/arch/IArchSystem.h
@@ -0,0 +1,39 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef IARCHSYSTEM_H
+#define IARCHSYSTEM_H
+
+#include "IInterface.h"
+#include "stdstring.h"
+
+//! Interface for architecture dependent system queries
+/*!
+This interface defines operations for querying system info.
+*/
+class IArchSystem : public IInterface {
+public:
+ //! @name accessors
+ //@{
+
+ //! Identify the OS
+ /*!
+ Returns a string identifying the operating system.
+ */
+ virtual std::string getOSName() const = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchTaskBar.h b/lib/arch/IArchTaskBar.h
new file mode 100644
index 00000000..e9471566
--- /dev/null
+++ b/lib/arch/IArchTaskBar.h
@@ -0,0 +1,60 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef IARCHTASKBAR_H
+#define IARCHTASKBAR_H
+
+#include "IInterface.h"
+
+class IArchTaskBarReceiver;
+
+//! Interface for architecture dependent task bar control
+/*!
+This interface defines the task bar icon operations required
+by synergy. Each architecture must implement this interface
+though each operation can be a no-op.
+*/
+class IArchTaskBar : public IInterface {
+public:
+ //! @name manipulators
+ //@{
+
+ //! Add a receiver
+ /*!
+ Add a receiver object to be notified of user and application
+ events. This should be called before other methods. When
+ the receiver is added to the task bar, its icon appears on
+ the task bar.
+ */
+ virtual void addReceiver(IArchTaskBarReceiver*) = 0;
+
+ //! Remove a receiver
+ /*!
+ Remove a receiver object from the task bar. This removes the
+ icon from the task bar.
+ */
+ virtual void removeReceiver(IArchTaskBarReceiver*) = 0;
+
+ //! Update a receiver
+ /*!
+ Updates the display of the receiver on the task bar. This
+ should be called when the receiver appearance may have changed
+ (e.g. it's icon or tool tip has changed).
+ */
+ virtual void updateReceiver(IArchTaskBarReceiver*) = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchTaskBarReceiver.h b/lib/arch/IArchTaskBarReceiver.h
new file mode 100644
index 00000000..917f2fbf
--- /dev/null
+++ b/lib/arch/IArchTaskBarReceiver.h
@@ -0,0 +1,90 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef IARCHTASKBARRECEIVER_H
+#define IARCHTASKBARRECEIVER_H
+
+#include "IInterface.h"
+#include "stdstring.h"
+
+//! Interface for architecture dependent task bar event handling
+/*!
+This interface defines the task bar icon event handlers required
+by synergy. Each architecture must implement this interface
+though each operation can be a no-op.
+*/
+class IArchTaskBarReceiver : public IInterface {
+public:
+ // Icon data is architecture dependent
+ typedef void* Icon;
+
+ //! @name manipulators
+ //@{
+
+ //! Show status window
+ /*!
+ Open a window displaying current status. This should return
+ immediately without waiting for the window to be closed.
+ */
+ virtual void showStatus() = 0;
+
+ //! Popup menu
+ /*!
+ Popup a menu of operations at or around \c x,y and perform the
+ chosen operation.
+ */
+ virtual void runMenu(int x, int y) = 0;
+
+ //! Perform primary action
+ /*!
+ Perform the primary (default) action.
+ */
+ virtual void primaryAction() = 0;
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Lock receiver
+ /*!
+ Locks the receiver from changing state. The receiver should be
+ locked when querying it's state to ensure consistent results.
+ Each call to \c lock() must have a matching \c unlock() and
+ locks cannot be nested.
+ */
+ virtual void lock() const = 0;
+
+ //! Unlock receiver
+ virtual void unlock() const = 0;
+
+ //! Get icon
+ /*!
+ Returns the icon to display in the task bar. The interface
+ to set the icon is left to subclasses. Getting and setting
+ the icon must be thread safe.
+ */
+ virtual const Icon getIcon() const = 0;
+
+ //! Get tooltip
+ /*!
+ Returns the tool tip to display in the task bar. The interface
+ to set the tooltip is left to sublclasses. Getting and setting
+ the icon must be thread safe.
+ */
+ virtual std::string getToolTip() const = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/IArchTime.h b/lib/arch/IArchTime.h
new file mode 100644
index 00000000..dade64bb
--- /dev/null
+++ b/lib/arch/IArchTime.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#ifndef IARCHTIME_H
+#define IARCHTIME_H
+
+#include "IInterface.h"
+
+//! Interface for architecture dependent time operations
+/*!
+This interface defines the time operations required by
+synergy. Each architecture must implement this interface.
+*/
+class IArchTime : public IInterface {
+public:
+ //! @name manipulators
+ //@{
+
+ //! Get the current time
+ /*!
+ Returns the number of seconds since some arbitrary starting time.
+ This should return as high a precision as reasonable.
+ */
+ virtual double time() = 0;
+
+ //@}
+};
+
+#endif
diff --git a/lib/arch/Makefile.am b/lib/arch/Makefile.am
new file mode 100644
index 00000000..8a1749ab
--- /dev/null
+++ b/lib/arch/Makefile.am
@@ -0,0 +1,118 @@
+# 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.
+
+## Process this file with automake to produce Makefile.in
+NULL =
+
+COMMON_SOURCE_FILES = \
+ CArch.cpp \
+ CArchDaemonNone.cpp \
+ CArchDaemonNone.h \
+ XArch.cpp \
+ CArch.h \
+ IArchConsole.h \
+ IArchDaemon.h \
+ IArchFile.h \
+ IArchLog.h \
+ IArchMultithread.h \
+ IArchNetwork.h \
+ IArchSleep.h \
+ IArchString.h \
+ IArchSystem.h \
+ IArchTaskBar.h \
+ IArchTaskBarReceiver.h \
+ IArchTime.h \
+ XArch.h \
+ $(NULL)
+UNIX_SOURCE_FILES = \
+ CArchConsoleUnix.cpp \
+ CArchDaemonUnix.cpp \
+ CArchFileUnix.cpp \
+ CArchLogUnix.cpp \
+ CArchMultithreadPosix.cpp \
+ CArchNetworkBSD.cpp \
+ CArchSleepUnix.cpp \
+ CArchStringUnix.cpp \
+ CArchSystemUnix.cpp \
+ CArchTaskBarXWindows.cpp \
+ CArchTimeUnix.cpp \
+ XArchUnix.cpp \
+ CArchConsoleUnix.h \
+ CArchDaemonUnix.h \
+ CArchFileUnix.h \
+ CArchLogUnix.h \
+ CArchMultithreadPosix.h \
+ CArchNetworkBSD.h \
+ CArchSleepUnix.h \
+ CArchStringUnix.h \
+ CArchSystemUnix.h \
+ CArchTaskBarXWindows.h \
+ CArchTimeUnix.h \
+ XArchUnix.h \
+ $(NULL)
+WIN32_SOURCE_FILES = \
+ CArchConsoleWindows.cpp \
+ CArchDaemonWindows.cpp \
+ CArchFileWindows.cpp \
+ CArchLogWindows.cpp \
+ CArchMiscWindows.cpp \
+ CArchMultithreadWindows.cpp \
+ CArchNetworkWinsock.cpp \
+ CArchSleepWindows.cpp \
+ CArchStringWindows.cpp \
+ CArchSystemWindows.cpp \
+ CArchTaskBarWindows.cpp \
+ CArchTimeWindows.cpp \
+ XArchWindows.cpp \
+ CArchConsoleWindows.h \
+ CArchDaemonWindows.h \
+ CArchFileWindows.h \
+ CArchLogWindows.h \
+ CArchMiscWindows.h \
+ CArchMultithreadWindows.h \
+ CArchNetworkWinsock.h \
+ CArchSleepWindows.h \
+ CArchStringWindows.h \
+ CArchSystemWindows.h \
+ CArchTaskBarWindows.h \
+ CArchTimeWindows.h \
+ XArchWindows.h \
+ $(NULL)
+
+EXTRA_DIST = \
+ CMultibyte.cpp \
+ Makefile.win \
+ vsnprintf.cpp \
+ $(UNIX_SOURCE_FILES) \
+ $(WIN32_SOURCE_FILES) \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ $(NULL)
+
+noinst_LIBRARIES = libarch.a
+if UNIX
+libarch_a_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(UNIX_SOURCE_FILES) \
+ $(NULL)
+endif
+if WIN32
+libarch_a_SOURCES = \
+ $(COMMON_SOURCE_FILES) \
+ $(WIN32_SOURCE_FILES) \
+ $(NULL)
+endif
+INCLUDES = \
+ -I$(top_srcdir)/lib/common \
+ $(NULL)
diff --git a/lib/arch/Makefile.win b/lib/arch/Makefile.win
new file mode 100644
index 00000000..4e151976
--- /dev/null
+++ b/lib/arch/Makefile.win
@@ -0,0 +1,84 @@
+# synergy -- mouse and keyboard sharing utility
+# Copyright (C) 2007 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.
+
+LIB_ARCH_SRC = lib\arch
+LIB_ARCH_DST = $(BUILD_DST)\$(LIB_ARCH_SRC)
+LIB_ARCH_LIB = "$(LIB_ARCH_DST)\arch.lib"
+LIB_ARCH_CPP = \
+ "CArch.cpp" \
+ "CArchDaemonNone.cpp" \
+ "XArch.cpp" \
+ "CArchConsoleWindows.cpp" \
+ "CArchDaemonWindows.cpp" \
+ "CArchFileWindows.cpp" \
+ "CArchLogWindows.cpp" \
+ "CArchMiscWindows.cpp" \
+ "CArchMultithreadWindows.cpp" \
+ "CArchNetworkWinsock.cpp" \
+ "CArchSleepWindows.cpp" \
+ "CArchStringWindows.cpp" \
+ "CArchSystemWindows.cpp" \
+ "CArchTaskBarWindows.cpp" \
+ "CArchTimeWindows.cpp" \
+ "XArchWindows.cpp" \
+ $(NULL)
+LIB_ARCH_OBJ = \
+ "$(LIB_ARCH_DST)\CArch.obj" \
+ "$(LIB_ARCH_DST)\CArchDaemonNone.obj" \
+ "$(LIB_ARCH_DST)\XArch.obj" \
+ "$(LIB_ARCH_DST)\CArchConsoleWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchDaemonWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchFileWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchLogWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchMiscWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchMultithreadWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchNetworkWinsock.obj" \
+ "$(LIB_ARCH_DST)\CArchSleepWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchStringWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchSystemWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchTaskBarWindows.obj" \
+ "$(LIB_ARCH_DST)\CArchTimeWindows.obj" \
+ "$(LIB_ARCH_DST)\XArchWindows.obj" \
+ $(NULL)
+LIB_ARCH_INC = \
+ /I"lib\common" \
+ $(NULL)
+
+CPP_FILES = $(CPP_FILES) $(LIB_ARCH_CPP)
+OBJ_FILES = $(OBJ_FILES) $(LIB_ARCH_OBJ)
+LIB_FILES = $(LIB_FILES) $(LIB_ARCH_LIB)
+
+# Dependency rules
+$(LIB_ARCH_OBJ): $(AUTODEP)
+!if EXIST($(LIB_ARCH_DST)\deps.mak)
+!include $(LIB_ARCH_DST)\deps.mak
+!endif
+
+# Build rules. Use batch-mode rules if possible.
+!if DEFINED(_NMAKE_VER)
+{$(LIB_ARCH_SRC)\}.cpp{$(LIB_ARCH_DST)\}.obj::
+!else
+{$(LIB_ARCH_SRC)\}.cpp{$(LIB_ARCH_DST)\}.obj:
+!endif
+ @$(ECHO) Compile in $(LIB_ARCH_SRC)
+ -@$(MKDIR) $(LIB_ARCH_DST) 2>NUL:
+ $(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
+ $(LIB_ARCH_INC) \
+ /Fo$(LIB_ARCH_DST)\ \
+ /Fd$(LIB_ARCH_LIB:.lib=.pdb) \
+ $< | $(AUTODEP) $(LIB_ARCH_SRC) $(LIB_ARCH_DST)
+$(LIB_ARCH_LIB): $(LIB_ARCH_OBJ)
+ @$(ECHO) Link $(@F)
+ $(implib) $(ildebug) $(ilflags) \
+ /out:$@ \
+ $**
+ $(AUTODEP) $(LIB_ARCH_SRC) $(LIB_ARCH_DST) $(**:.obj=.d)
diff --git a/lib/arch/XArch.cpp b/lib/arch/XArch.cpp
new file mode 100644
index 00000000..9dce5283
--- /dev/null
+++ b/lib/arch/XArch.cpp
@@ -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.
+ */
+
+#include "XArch.h"
+
+//
+// XArch
+//
+
+std::string
+XArch::what() const throw()
+{
+ try {
+ if (m_what.empty() && m_eval != NULL) {
+ m_what = m_eval->eval();
+ }
+ }
+ catch (...) {
+ // ignore
+ }
+ return m_what;
+}
diff --git a/lib/arch/XArch.h b/lib/arch/XArch.h
new file mode 100644
index 00000000..75083649
--- /dev/null
+++ b/lib/arch/XArch.h
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#ifndef XARCH_H
+#define XARCH_H
+
+#include "common.h"
+#include "stdstring.h"
+
+//! Generic thread exception
+/*!
+Exceptions derived from this class are used by the multithreading
+library to perform stack unwinding when a thread terminates. These
+exceptions must always be rethrown by clients when caught.
+*/
+class XThread { };
+
+//! Thread exception to cancel
+/*!
+Thrown to cancel a thread. Clients must not throw this type, but
+must rethrow it if caught (by XThreadCancel, XThread, or ...).
+*/
+class XThreadCancel : public XThread { };
+
+/*!
+\def RETHROW_XTHREAD
+Convenience macro to rethrow an XThread exception but ignore other
+exceptions. Put this in your catch (...) handler after necessary
+cleanup but before leaving or returning from the handler.
+*/
+#define RETHROW_XTHREAD \
+ try { throw; } catch (XThread&) { throw; } catch (...) { }
+
+//! Lazy error message string evaluation
+/*!
+This class encapsulates platform dependent error string lookup.
+Platforms subclass this type, taking an appropriate error code
+type in the c'tor and overriding eval() to return the error
+string for that error code.
+*/
+class XArchEval {
+public:
+ XArchEval() { }
+ virtual ~XArchEval() { }
+
+ virtual XArchEval* clone() const throw() = 0;
+
+ virtual std::string eval() const throw() = 0;
+};
+
+//! Generic exception architecture dependent library
+class XArch {
+public:
+ XArch(XArchEval* adoptedEvaluator) : m_eval(adoptedEvaluator) { }
+ XArch(const std::string& msg) : m_eval(NULL), m_what(msg) { }
+ XArch(const XArch& e) : m_eval(e.m_eval != NULL ? e.m_eval->clone() : NULL),
+ m_what(e.m_what) { }
+ ~XArch() { delete m_eval; }
+
+ std::string what() const throw();
+
+private:
+ XArchEval* m_eval;
+ mutable std::string m_what;
+};
+
+// Macro to declare XArch derived types
+#define XARCH_SUBCLASS(name_, super_) \
+class name_ : public super_ { \
+public: \
+ name_(XArchEval* adoptedEvaluator) : super_(adoptedEvaluator) { } \
+ name_(const std::string& msg) : super_(msg) { } \
+}
+
+//! Generic network exception
+/*!
+Exceptions derived from this class are used by the networking
+library to indicate various errors.
+*/
+XARCH_SUBCLASS(XArchNetwork, XArch);
+
+//! Operation was interrupted
+XARCH_SUBCLASS(XArchNetworkInterrupted, XArchNetwork);
+
+//! Network insufficient permission
+XARCH_SUBCLASS(XArchNetworkAccess, XArchNetwork);
+
+//! Network insufficient resources
+XARCH_SUBCLASS(XArchNetworkResource, XArchNetwork);
+
+//! No support for requested network resource/service
+XARCH_SUBCLASS(XArchNetworkSupport, XArchNetwork);
+
+//! Network I/O error
+XARCH_SUBCLASS(XArchNetworkIO, XArchNetwork);
+
+//! Network address is unavailable or not local
+XARCH_SUBCLASS(XArchNetworkNoAddress, XArchNetwork);
+
+//! Network address in use
+XARCH_SUBCLASS(XArchNetworkAddressInUse, XArchNetwork);
+
+//! No route to address
+XARCH_SUBCLASS(XArchNetworkNoRoute, XArchNetwork);
+
+//! Socket not connected
+XARCH_SUBCLASS(XArchNetworkNotConnected, XArchNetwork);
+
+//! Remote read end of socket has closed
+XARCH_SUBCLASS(XArchNetworkShutdown, XArchNetwork);
+
+//! Remote end of socket has disconnected
+XARCH_SUBCLASS(XArchNetworkDisconnected, XArchNetwork);
+
+//! Remote end of socket refused connection
+XARCH_SUBCLASS(XArchNetworkConnectionRefused, XArchNetwork);
+
+//! Remote end of socket is not responding
+XARCH_SUBCLASS(XArchNetworkTimedOut, XArchNetwork);
+
+//! Generic network name lookup erros
+XARCH_SUBCLASS(XArchNetworkName, XArchNetwork);
+
+//! The named host is unknown
+XARCH_SUBCLASS(XArchNetworkNameUnknown, XArchNetworkName);
+
+//! The named host is known but has no address
+XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName);
+
+//! Non-recoverable name server error
+XARCH_SUBCLASS(XArchNetworkNameFailure, XArchNetworkName);
+
+//! Temporary name server error
+XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName);
+
+//! The named host is known but no supported address
+XARCH_SUBCLASS(XArchNetworkNameUnsupported, XArchNetworkName);
+
+//! Generic daemon exception
+/*!
+Exceptions derived from this class are used by the daemon
+library to indicate various errors.
+*/
+XARCH_SUBCLASS(XArchDaemon, XArch);
+
+//! Could not daemonize
+XARCH_SUBCLASS(XArchDaemonFailed, XArchDaemon);
+
+//! Could not install daemon
+XARCH_SUBCLASS(XArchDaemonInstallFailed, XArchDaemon);
+
+//! Could not uninstall daemon
+XARCH_SUBCLASS(XArchDaemonUninstallFailed, XArchDaemon);
+
+//! Attempted to uninstall a daemon that was not installed
+XARCH_SUBCLASS(XArchDaemonUninstallNotInstalled, XArchDaemonUninstallFailed);
+
+
+#endif
diff --git a/lib/arch/XArchUnix.cpp b/lib/arch/XArchUnix.cpp
new file mode 100644
index 00000000..6f4047d5
--- /dev/null
+++ b/lib/arch/XArchUnix.cpp
@@ -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.
+ */
+
+#include "XArchUnix.h"
+#include
+
+//
+// XArchEvalUnix
+//
+
+XArchEval*
+XArchEvalUnix::clone() const throw()
+{
+ return new XArchEvalUnix(m_errno);
+}
+
+std::string
+XArchEvalUnix::eval() const throw()
+{
+ // FIXME -- not thread safe
+ return strerror(m_errno);
+}
diff --git a/lib/arch/XArchUnix.h b/lib/arch/XArchUnix.h
new file mode 100644
index 00000000..19e0df4c
--- /dev/null
+++ b/lib/arch/XArchUnix.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef XARCHUNIX_H
+#define XARCHUNIX_H
+
+#include "XArch.h"
+
+//! Lazy error message string evaluation for unix
+class XArchEvalUnix : public XArchEval {
+public:
+ XArchEvalUnix(int err) : m_errno(err) { }
+ virtual ~XArchEvalUnix() { }
+
+ // XArchEval overrides
+ virtual XArchEval* clone() const throw();
+ virtual std::string eval() const throw();
+
+private:
+ int m_errno;
+};
+
+#endif
diff --git a/lib/arch/XArchWindows.cpp b/lib/arch/XArchWindows.cpp
new file mode 100644
index 00000000..eebd6449
--- /dev/null
+++ b/lib/arch/XArchWindows.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "XArchWindows.h"
+#include "CArchNetworkWinsock.h"
+
+//
+// XArchEvalWindows
+//
+
+XArchEval*
+XArchEvalWindows::clone() const throw()
+{
+ return new XArchEvalWindows(m_errno);
+}
+
+std::string
+XArchEvalWindows::eval() const throw()
+{
+ char* cmsg;
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ 0,
+ m_errno,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&cmsg,
+ 0,
+ NULL) == 0) {
+ cmsg = NULL;
+ return "Unknown error";
+ }
+ std::string smsg(cmsg);
+ LocalFree(cmsg);
+ return smsg;
+}
+
+
+//
+// XArchEvalWinsock
+//
+
+XArchEval*
+XArchEvalWinsock::clone() const throw()
+{
+ return new XArchEvalWinsock(m_errno);
+}
+
+std::string
+XArchEvalWinsock::eval() const throw()
+{
+ // built-in windows function for looking up error message strings
+ // may not look up network error messages correctly. we'll have
+ // to do it ourself.
+ static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = {
+ /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
+ /* 10009 */{WSAEBADF, "Bad file handle"},
+ /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"},
+ /* 10014 */{WSAEFAULT, "WSAEFAULT"},
+ /* 10022 */{WSAEINVAL, "WSAEINVAL"},
+ /* 10024 */{WSAEMFILE, "No more file descriptors available"},
+ /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"},
+ /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"},
+ /* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"},
+ /* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"},
+ /* 10039 */{WSAEDESTADDRREQ, "A destination address is required"},
+ /* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"},
+ /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"},
+ /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"},
+ /* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"},
+ /* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"},
+ /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"},
+ /* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"},
+ /* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"},
+ /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"},
+ /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"},
+ /* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"},
+ /* 10051 */{WSAENETUNREACH, "The network can't be reached from this hos at this time"},
+ /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"},
+ /* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"},
+ /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"},
+ /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"},
+ /* 10056 */{WSAEISCONN, "The socket is already connected"},
+ /* 10057 */{WSAENOTCONN, "The socket is not connected"},
+ /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"},
+ /* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"},
+ /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"},
+ /* 10061 */{WSAECONNREFUSED, "The attempt to connect was forcefully rejected"},
+ /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"},
+ /* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"},
+ /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
+ /* 10065 */{WSAEHOSTUNREACH, "No route to host"},
+ /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"},
+ /* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"},
+ /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"},
+ /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"},
+ /* 10070 */{WSAESTALE, "Undocumented WinSock error code"},
+ /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"},
+ /* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"},
+ /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"},
+ /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"},
+ /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"},
+ /* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"},
+ /* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"},
+ /* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"},
+ /* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"},
+ /* end */{0, NULL}
+ };
+
+ for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) {
+ if (s_netErrorCodes[i].m_code == m_errno) {
+ return s_netErrorCodes[i].m_msg;
+ }
+ }
+ return "Unknown error";
+}
diff --git a/lib/arch/XArchWindows.h b/lib/arch/XArchWindows.h
new file mode 100644
index 00000000..56c24007
--- /dev/null
+++ b/lib/arch/XArchWindows.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef XARCHWINDOWS_H
+#define XARCHWINDOWS_H
+
+#define WIN32_LEAN_AND_MEAN
+
+#include "XArch.h"
+#include
+
+//! Lazy error message string evaluation for windows
+class XArchEvalWindows : public XArchEval {
+public:
+ XArchEvalWindows() : m_errno(GetLastError()) { }
+ XArchEvalWindows(DWORD err) : m_errno(err) { }
+ virtual ~XArchEvalWindows() { }
+
+ // XArchEval overrides
+ virtual XArchEval* clone() const throw();
+ virtual std::string eval() const throw();
+
+private:
+ DWORD m_errno;
+};
+
+//! Lazy error message string evaluation for winsock
+class XArchEvalWinsock : public XArchEval {
+public:
+ XArchEvalWinsock(int err) : m_errno(err) { }
+ virtual ~XArchEvalWinsock() { }
+
+ // XArchEval overrides
+ virtual XArchEval* clone() const throw();
+ virtual std::string eval() const throw();
+
+private:
+ int m_errno;
+};
+
+#endif
diff --git a/lib/arch/vsnprintf.cpp b/lib/arch/vsnprintf.cpp
new file mode 100644
index 00000000..10800ec7
--- /dev/null
+++ b/lib/arch/vsnprintf.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#if HAVE_VSNPRINTF
+
+#if !defined(ARCH_VSNPRINTF)
+# define ARCH_VSNPRINTF vsnprintf
+#endif
+
+int
+ARCH_STRING::vsnprintf(char* str, int size, const char* fmt, va_list ap)
+{
+ int n = ::ARCH_VSNPRINTF(str, size, fmt, ap);
+ if (n > size) {
+ n = -1;
+ }
+ return n;
+}
+
+#elif SYSAPI_UNIX // !HAVE_VSNPRINTF
+
+#include
+
+int
+ARCH_STRING::vsnprintf(char* str, int size, const char* fmt, va_list ap)
+{
+ static FILE* bitbucket = fopen("/dev/null", "w");
+ if (bitbucket == NULL) {
+ // uh oh
+ if (size > 0) {
+ str[0] = '\0';
+ }
+ return 0;
+ }
+ else {
+ // count the characters using the bitbucket
+ int n = vfprintf(bitbucket, fmt, ap);
+ if (n + 1 <= size) {
+ // it'll fit so print it into str
+ vsprintf(str, fmt, ap);
+ }
+ return n;
+ }
+}
+
+#else // !HAVE_VSNPRINTF && !SYSAPI_UNIX
+
+#error vsnprintf not implemented
+
+#endif // !HAVE_VSNPRINTF
diff --git a/lib/base/CEvent.cpp b/lib/base/CEvent.cpp
new file mode 100644
index 00000000..bfdf88ed
--- /dev/null
+++ b/lib/base/CEvent.cpp
@@ -0,0 +1,98 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CEvent.h"
+#include "CEventQueue.h"
+
+//
+// CEvent
+//
+
+CEvent::CEvent() :
+ m_type(kUnknown),
+ m_target(NULL),
+ m_data(NULL),
+ m_flags(0)
+{
+ // do nothing
+}
+
+CEvent::CEvent(Type type, void* target, void* data, Flags flags) :
+ m_type(type),
+ m_target(target),
+ m_data(data),
+ m_flags(flags)
+{
+ // do nothing
+}
+
+CEvent::Type
+CEvent::getType() const
+{
+ return m_type;
+}
+
+void*
+CEvent::getTarget() const
+{
+ return m_target;
+}
+
+void*
+CEvent::getData() const
+{
+ return m_data;
+}
+
+CEvent::Flags
+CEvent::getFlags() const
+{
+ return m_flags;
+}
+
+CEvent::Type
+CEvent::registerType(const char* name)
+{
+ return EVENTQUEUE->registerType(name);
+}
+
+CEvent::Type
+CEvent::registerTypeOnce(Type& type, const char* name)
+{
+ return EVENTQUEUE->registerTypeOnce(type, name);
+}
+
+const char*
+CEvent::getTypeName(Type type)
+{
+ return EVENTQUEUE->getTypeName(type);
+}
+
+void
+CEvent::deleteData(const CEvent& event)
+{
+ switch (event.getType()) {
+ case kUnknown:
+ case kQuit:
+ case kSystem:
+ case kTimer:
+ break;
+
+ default:
+ if ((event.getFlags() & kDontFreeData) == 0) {
+ free(event.getData());
+ }
+ break;
+ }
+}
diff --git a/lib/base/CEvent.h b/lib/base/CEvent.h
new file mode 100644
index 00000000..8b637cef
--- /dev/null
+++ b/lib/base/CEvent.h
@@ -0,0 +1,123 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CEVENT_H
+#define CEVENT_H
+
+#include "BasicTypes.h"
+#include "stdmap.h"
+
+//! Event
+/*!
+A \c CEvent holds an event type and a pointer to event data.
+*/
+class CEvent {
+public:
+ typedef UInt32 Type;
+ enum {
+ kUnknown, //!< The event type is unknown
+ kQuit, //!< The quit event
+ kSystem, //!< The data points to a system event type
+ kTimer, //!< The data points to timer info
+ kLast //!< Must be last
+ };
+
+ typedef UInt32 Flags;
+ enum {
+ kNone = 0x00, //!< No flags
+ kDeliverImmediately = 0x01, //!< Dispatch and free event immediately
+ kDontFreeData = 0x02 //!< Don't free data in deleteData
+ };
+
+ CEvent();
+
+ //! Create \c CEvent with data
+ /*!
+ The \p type must have been registered using \c registerType().
+ The \p data must be POD (plain old data) allocated by malloc(),
+ which means it cannot have a constructor, destructor or be
+ composed of any types that do. \p target is the intended
+ recipient of the event. \p flags is any combination of \c Flags.
+ */
+ CEvent(Type type, void* target = NULL, void* data = NULL,
+ UInt32 flags = kNone);
+
+ //! @name manipulators
+ //@{
+
+ //! Creates a new event type
+ /*!
+ Returns a unique event type id.
+ */
+ static Type registerType(const char* name);
+
+ //! Creates a new event type
+ /*!
+ If \p type contains \c kUnknown then it is set to a unique event
+ type id otherwise it is left alone. The final value of \p type
+ is returned.
+ */
+ static Type registerTypeOnce(Type& type, const char* name);
+
+ //! Get name for event
+ /*!
+ Returns the name for the event \p type. This is primarily for
+ debugging.
+ */
+ static const char* getTypeName(Type type);
+
+ //! Release event data
+ /*!
+ Deletes event data for the given event (using free()).
+ */
+ static void deleteData(const CEvent&);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Get event type
+ /*!
+ Returns the event type.
+ */
+ Type getType() const;
+
+ //! Get the event target
+ /*!
+ Returns the event target.
+ */
+ void* getTarget() const;
+
+ //! Get the event data
+ /*!
+ Returns the event data.
+ */
+ void* getData() const;
+
+ //! Get event flags
+ /*!
+ Returns the event flags.
+ */
+ Flags getFlags() const;
+
+ //@}
+
+private:
+ Type m_type;
+ void* m_target;
+ void* m_data;
+ Flags m_flags;
+};
+
+#endif
diff --git a/lib/base/CEventQueue.cpp b/lib/base/CEventQueue.cpp
new file mode 100644
index 00000000..d0a93391
--- /dev/null
+++ b/lib/base/CEventQueue.cpp
@@ -0,0 +1,526 @@
+;/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CEventQueue.h"
+#include "CLog.h"
+#include "CSimpleEventQueueBuffer.h"
+#include "CStopwatch.h"
+#include "IEventJob.h"
+#include "CArch.h"
+
+// interrupt handler. this just adds a quit event to the queue.
+static
+void
+interrupt(CArch::ESignal, void*)
+{
+ EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
+}
+
+
+//
+// CEventQueue
+//
+
+CEventQueue::CEventQueue() :
+ m_nextType(CEvent::kLast)
+{
+ setInstance(this);
+ m_mutex = ARCH->newMutex();
+ ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
+ ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
+ m_buffer = new CSimpleEventQueueBuffer;
+}
+
+CEventQueue::~CEventQueue()
+{
+ delete m_buffer;
+ ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
+ ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
+ ARCH->closeMutex(m_mutex);
+ setInstance(NULL);
+}
+
+CEvent::Type
+CEventQueue::registerType(const char* name)
+{
+ CArchMutexLock lock(m_mutex);
+ m_typeMap.insert(std::make_pair(m_nextType, name));
+ LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
+ return m_nextType++;
+}
+
+CEvent::Type
+CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
+{
+ CArchMutexLock lock(m_mutex);
+ if (type == CEvent::kUnknown) {
+ m_typeMap.insert(std::make_pair(m_nextType, name));
+ LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
+ type = m_nextType++;
+ }
+ return type;
+}
+
+const char*
+CEventQueue::getTypeName(CEvent::Type type)
+{
+ switch (type) {
+ case CEvent::kUnknown:
+ return "nil";
+
+ case CEvent::kQuit:
+ return "quit";
+
+ case CEvent::kSystem:
+ return "system";
+
+ case CEvent::kTimer:
+ return "timer";
+
+ default:
+ CTypeMap::const_iterator i = m_typeMap.find(type);
+ if (i == m_typeMap.end()) {
+ return "";
+ }
+ else {
+ return i->second;
+ }
+ }
+}
+
+void
+CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
+{
+ CArchMutexLock lock(m_mutex);
+
+ // discard old buffer and old events
+ delete m_buffer;
+ for (CEventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
+ CEvent::deleteData(i->second);
+ }
+ m_events.clear();
+ m_oldEventIDs.clear();
+
+ // use new buffer
+ m_buffer = buffer;
+ if (m_buffer == NULL) {
+ m_buffer = new CSimpleEventQueueBuffer;
+ }
+}
+
+bool
+CEventQueue::getEvent(CEvent& event, double timeout)
+{
+ CStopwatch timer(true);
+retry:
+ // if no events are waiting then handle timers and then wait
+ while (m_buffer->isEmpty()) {
+ // handle timers first
+ if (hasTimerExpired(event)) {
+ return true;
+ }
+
+ // get time remaining in timeout
+ double timeLeft = timeout - timer.getTime();
+ if (timeout >= 0.0 && timeLeft <= 0.0) {
+ return false;
+ }
+
+ // get time until next timer expires. if there is a timer
+ // and it'll expire before the client's timeout then use
+ // that duration for our timeout instead.
+ double timerTimeout = getNextTimerTimeout();
+ if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
+ timeLeft = timerTimeout;
+ }
+
+ // wait for an event
+ m_buffer->waitForEvent(timeLeft);
+ }
+
+ // get the event
+ UInt32 dataID;
+ IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
+ switch (type) {
+ case IEventQueueBuffer::kNone:
+ if (timeout < 0.0 || timeout <= timer.getTime()) {
+ // don't want to fail if client isn't expecting that
+ // so if getEvent() fails with an infinite timeout
+ // then just try getting another event.
+ goto retry;
+ }
+ return false;
+
+ case IEventQueueBuffer::kSystem:
+ return true;
+
+ case IEventQueueBuffer::kUser:
+ {
+ CArchMutexLock lock(m_mutex);
+ event = removeEvent(dataID);
+ return true;
+ }
+
+ default:
+ assert(0 && "invalid event type");
+ return false;
+ }
+}
+
+bool
+CEventQueue::dispatchEvent(const CEvent& event)
+{
+ void* target = event.getTarget();
+ IEventJob* job = getHandler(event.getType(), target);
+ if (job == NULL) {
+ job = getHandler(CEvent::kUnknown, target);
+ }
+ if (job != NULL) {
+ job->run(event);
+ return true;
+ }
+ return false;
+}
+
+void
+CEventQueue::addEvent(const CEvent& event)
+{
+ // discard bogus event types
+ switch (event.getType()) {
+ case CEvent::kUnknown:
+ case CEvent::kSystem:
+ case CEvent::kTimer:
+ return;
+
+ default:
+ break;
+ }
+
+ if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) {
+ dispatchEvent(event);
+ CEvent::deleteData(event);
+ }
+ else {
+ CArchMutexLock lock(m_mutex);
+
+ // store the event's data locally
+ UInt32 eventID = saveEvent(event);
+
+ // add it
+ if (!m_buffer->addEvent(eventID)) {
+ // failed to send event
+ removeEvent(eventID);
+ CEvent::deleteData(event);
+ }
+ }
+}
+
+CEventQueueTimer*
+CEventQueue::newTimer(double duration, void* target)
+{
+ assert(duration > 0.0);
+
+ CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
+ if (target == NULL) {
+ target = timer;
+ }
+ CArchMutexLock lock(m_mutex);
+ m_timers.insert(timer);
+ // initial duration is requested duration plus whatever's on
+ // the clock currently because the latter will be subtracted
+ // the next time we check for timers.
+ m_timerQueue.push(CTimer(timer, duration,
+ duration + m_time.getTime(), target, false));
+ return timer;
+}
+
+CEventQueueTimer*
+CEventQueue::newOneShotTimer(double duration, void* target)
+{
+ assert(duration > 0.0);
+
+ CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
+ if (target == NULL) {
+ target = timer;
+ }
+ CArchMutexLock lock(m_mutex);
+ m_timers.insert(timer);
+ // initial duration is requested duration plus whatever's on
+ // the clock currently because the latter will be subtracted
+ // the next time we check for timers.
+ m_timerQueue.push(CTimer(timer, duration,
+ duration + m_time.getTime(), target, true));
+ return timer;
+}
+
+void
+CEventQueue::deleteTimer(CEventQueueTimer* timer)
+{
+ CArchMutexLock lock(m_mutex);
+ for (CTimerQueue::iterator index = m_timerQueue.begin();
+ index != m_timerQueue.end(); ++index) {
+ if (index->getTimer() == timer) {
+ m_timerQueue.erase(index);
+ break;
+ }
+ }
+ CTimers::iterator index = m_timers.find(timer);
+ if (index != m_timers.end()) {
+ m_timers.erase(index);
+ }
+ m_buffer->deleteTimer(timer);
+}
+
+void
+CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler)
+{
+ CArchMutexLock lock(m_mutex);
+ IEventJob*& job = m_handlers[target][type];
+ delete job;
+ job = handler;
+}
+
+void
+CEventQueue::removeHandler(CEvent::Type type, void* target)
+{
+ IEventJob* handler = NULL;
+ {
+ CArchMutexLock lock(m_mutex);
+ CHandlerTable::iterator index = m_handlers.find(target);
+ if (index != m_handlers.end()) {
+ CTypeHandlerTable& typeHandlers = index->second;
+ CTypeHandlerTable::iterator index2 = typeHandlers.find(type);
+ if (index2 != typeHandlers.end()) {
+ handler = index2->second;
+ typeHandlers.erase(index2);
+ }
+ }
+ }
+ delete handler;
+}
+
+void
+CEventQueue::removeHandlers(void* target)
+{
+ std::vector handlers;
+ {
+ CArchMutexLock lock(m_mutex);
+ CHandlerTable::iterator index = m_handlers.find(target);
+ if (index != m_handlers.end()) {
+ // copy to handlers array and clear table for target
+ CTypeHandlerTable& typeHandlers = index->second;
+ for (CTypeHandlerTable::iterator index2 = typeHandlers.begin();
+ index2 != typeHandlers.end(); ++index2) {
+ handlers.push_back(index2->second);
+ }
+ typeHandlers.clear();
+ }
+ }
+
+ // delete handlers
+ for (std::vector::iterator index = handlers.begin();
+ index != handlers.end(); ++index) {
+ delete *index;
+ }
+}
+
+bool
+CEventQueue::isEmpty() const
+{
+ return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
+}
+
+IEventJob*
+CEventQueue::getHandler(CEvent::Type type, void* target) const
+{
+ CArchMutexLock lock(m_mutex);
+ CHandlerTable::const_iterator index = m_handlers.find(target);
+ if (index != m_handlers.end()) {
+ const CTypeHandlerTable& typeHandlers = index->second;
+ CTypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
+ if (index2 != typeHandlers.end()) {
+ return index2->second;
+ }
+ }
+ return NULL;
+}
+
+UInt32
+CEventQueue::saveEvent(const CEvent& event)
+{
+ // choose id
+ UInt32 id;
+ if (!m_oldEventIDs.empty()) {
+ // reuse an id
+ id = m_oldEventIDs.back();
+ m_oldEventIDs.pop_back();
+ }
+ else {
+ // make a new id
+ id = static_cast(m_events.size());
+ }
+
+ // save data
+ m_events[id] = event;
+ return id;
+}
+
+CEvent
+CEventQueue::removeEvent(UInt32 eventID)
+{
+ // look up id
+ CEventTable::iterator index = m_events.find(eventID);
+ if (index == m_events.end()) {
+ return CEvent();
+ }
+
+ // get data
+ CEvent event = index->second;
+ m_events.erase(index);
+
+ // save old id for reuse
+ m_oldEventIDs.push_back(eventID);
+
+ return event;
+}
+
+bool
+CEventQueue::hasTimerExpired(CEvent& event)
+{
+ // return true if there's a timer in the timer priority queue that
+ // has expired. if returning true then fill in event appropriately
+ // and reset and reinsert the timer.
+ if (m_timerQueue.empty()) {
+ return false;
+ }
+
+ // get time elapsed since last check
+ const double time = m_time.getTime();
+ m_time.reset();
+
+ // countdown elapsed time
+ for (CTimerQueue::iterator index = m_timerQueue.begin();
+ index != m_timerQueue.end(); ++index) {
+ (*index) -= time;
+ }
+
+ // done if no timers are expired
+ if (m_timerQueue.top() > 0.0) {
+ return false;
+ }
+
+ // remove timer from queue
+ CTimer timer = m_timerQueue.top();
+ m_timerQueue.pop();
+
+ // prepare event and reset the timer's clock
+ timer.fillEvent(m_timerEvent);
+ event = CEvent(CEvent::kTimer, timer.getTarget(), &m_timerEvent);
+ timer.reset();
+
+ // reinsert timer into queue if it's not a one-shot
+ if (!timer.isOneShot()) {
+ m_timerQueue.push(timer);
+ }
+
+ return true;
+}
+
+double
+CEventQueue::getNextTimerTimeout() const
+{
+ // return -1 if no timers, 0 if the top timer has expired, otherwise
+ // the time until the top timer in the timer priority queue will
+ // expire.
+ if (m_timerQueue.empty()) {
+ return -1.0;
+ }
+ if (m_timerQueue.top() <= 0.0) {
+ return 0.0;
+ }
+ return m_timerQueue.top();
+}
+
+
+//
+// CEventQueue::CTimer
+//
+
+CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
+ double initialTime, void* target, bool oneShot) :
+ m_timer(timer),
+ m_timeout(timeout),
+ m_target(target),
+ m_oneShot(oneShot),
+ m_time(initialTime)
+{
+ assert(m_timeout > 0.0);
+}
+
+CEventQueue::CTimer::~CTimer()
+{
+ // do nothing
+}
+
+void
+CEventQueue::CTimer::reset()
+{
+ m_time = m_timeout;
+}
+
+CEventQueue::CTimer&
+CEventQueue::CTimer::operator-=(double dt)
+{
+ m_time -= dt;
+ return *this;
+}
+
+CEventQueue::CTimer::operator double() const
+{
+ return m_time;
+}
+
+bool
+CEventQueue::CTimer::isOneShot() const
+{
+ return m_oneShot;
+}
+
+CEventQueueTimer*
+CEventQueue::CTimer::getTimer() const
+{
+ return m_timer;
+}
+
+void*
+CEventQueue::CTimer::getTarget() const
+{
+ return m_target;
+}
+
+void
+CEventQueue::CTimer::fillEvent(CTimerEvent& event) const
+{
+ event.m_timer = m_timer;
+ event.m_count = 0;
+ if (m_time <= 0.0) {
+ event.m_count = static_cast((m_timeout - m_time) / m_timeout);
+ }
+}
+
+bool
+CEventQueue::CTimer::operator<(const CTimer& t) const
+{
+ return m_time < t.m_time;
+}
diff --git a/lib/base/CEventQueue.h b/lib/base/CEventQueue.h
new file mode 100644
index 00000000..a63c7b16
--- /dev/null
+++ b/lib/base/CEventQueue.h
@@ -0,0 +1,123 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CEVENTQUEUE_H
+#define CEVENTQUEUE_H
+
+#include "IEventQueue.h"
+#include "CEvent.h"
+#include "CPriorityQueue.h"
+#include "CStopwatch.h"
+#include "IArchMultithread.h"
+#include "stdmap.h"
+#include "stdset.h"
+
+//! Event queue
+/*!
+An event queue that implements the platform independent parts and
+delegates the platform dependent parts to a subclass.
+*/
+class CEventQueue : public IEventQueue {
+public:
+ CEventQueue();
+ virtual ~CEventQueue();
+
+ // IEventQueue overrides
+ virtual void adoptBuffer(IEventQueueBuffer*);
+ virtual bool getEvent(CEvent& event, double timeout = -1.0);
+ virtual bool dispatchEvent(const CEvent& event);
+ virtual void addEvent(const CEvent& event);
+ virtual CEventQueueTimer*
+ newTimer(double duration, void* target);
+ virtual CEventQueueTimer*
+ newOneShotTimer(double duration, void* target);
+ virtual void deleteTimer(CEventQueueTimer*);
+ virtual void adoptHandler(CEvent::Type type,
+ void* target, IEventJob* handler);
+ virtual void removeHandler(CEvent::Type type, void* target);
+ virtual void removeHandlers(void* target);
+ virtual CEvent::Type
+ registerType(const char* name);
+ virtual CEvent::Type
+ registerTypeOnce(CEvent::Type& type, const char* name);
+ virtual bool isEmpty() const;
+ virtual IEventJob* getHandler(CEvent::Type type, void* target) const;
+ virtual const char* getTypeName(CEvent::Type type);
+
+private:
+ UInt32 saveEvent(const CEvent& event);
+ CEvent removeEvent(UInt32 eventID);
+ bool hasTimerExpired(CEvent& event);
+ double getNextTimerTimeout() const;
+
+private:
+ class CTimer {
+ public:
+ CTimer(CEventQueueTimer*, double timeout, double initialTime,
+ void* target, bool oneShot);
+ ~CTimer();
+
+ void reset();
+
+ CTimer& operator-=(double);
+
+ operator double() const;
+
+ bool isOneShot() const;
+ CEventQueueTimer*
+ getTimer() const;
+ void* getTarget() const;
+ void fillEvent(CTimerEvent&) const;
+
+ bool operator<(const CTimer&) const;
+
+ private:
+ CEventQueueTimer* m_timer;
+ double m_timeout;
+ void* m_target;
+ bool m_oneShot;
+ double m_time;
+ };
+ typedef std::set CTimers;
+ typedef CPriorityQueue CTimerQueue;
+ typedef std::map CEventTable;
+ typedef std::vector CEventIDList;
+ typedef std::map CTypeMap;
+ typedef std::map CTypeHandlerTable;
+ typedef std::map CHandlerTable;
+
+ CArchMutex m_mutex;
+
+ // registered events
+ CEvent::Type m_nextType;
+ CTypeMap m_typeMap;
+
+ // buffer of events
+ IEventQueueBuffer* m_buffer;
+
+ // saved events
+ CEventTable m_events;
+ CEventIDList m_oldEventIDs;
+
+ // timers
+ CStopwatch m_time;
+ CTimers m_timers;
+ CTimerQueue m_timerQueue;
+ CTimerEvent m_timerEvent;
+
+ // event handlers
+ CHandlerTable m_handlers;
+};
+
+#endif
diff --git a/lib/base/CFunctionEventJob.cpp b/lib/base/CFunctionEventJob.cpp
new file mode 100644
index 00000000..5afdc988
--- /dev/null
+++ b/lib/base/CFunctionEventJob.cpp
@@ -0,0 +1,40 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CFunctionEventJob.h"
+
+//
+// CFunctionEventJob
+//
+
+CFunctionEventJob::CFunctionEventJob(
+ void (*func)(const CEvent&, void*), void* arg) :
+ m_func(func),
+ m_arg(arg)
+{
+ // do nothing
+}
+
+CFunctionEventJob::~CFunctionEventJob()
+{
+ // do nothing
+}
+
+void
+CFunctionEventJob::run(const CEvent& event)
+{
+ if (m_func != NULL) {
+ m_func(event, m_arg);
+ }
+}
diff --git a/lib/base/CFunctionEventJob.h b/lib/base/CFunctionEventJob.h
new file mode 100644
index 00000000..517b9c45
--- /dev/null
+++ b/lib/base/CFunctionEventJob.h
@@ -0,0 +1,38 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CFUNCTIONEVENTJOB_H
+#define CFUNCTIONEVENTJOB_H
+
+#include "IEventJob.h"
+
+//! Use a function as an event job
+/*!
+An event job class that invokes a function.
+*/
+class CFunctionEventJob : public IEventJob {
+public:
+ //! run() invokes \c func(arg)
+ CFunctionEventJob(void (*func)(const CEvent&, void*), void* arg = NULL);
+ virtual ~CFunctionEventJob();
+
+ // IEventJob overrides
+ virtual void run(const CEvent&);
+
+private:
+ void (*m_func)(const CEvent&, void*);
+ void* m_arg;
+};
+
+#endif
diff --git a/lib/base/CFunctionJob.cpp b/lib/base/CFunctionJob.cpp
new file mode 100644
index 00000000..bc16c509
--- /dev/null
+++ b/lib/base/CFunctionJob.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "CFunctionJob.h"
+
+//
+// CFunctionJob
+//
+
+CFunctionJob::CFunctionJob(void (*func)(void*), void* arg) :
+ m_func(func),
+ m_arg(arg)
+{
+ // do nothing
+}
+
+CFunctionJob::~CFunctionJob()
+{
+ // do nothing
+}
+
+void
+CFunctionJob::run()
+{
+ if (m_func != NULL) {
+ m_func(m_arg);
+ }
+}
diff --git a/lib/base/CFunctionJob.h b/lib/base/CFunctionJob.h
new file mode 100644
index 00000000..e30bbfa2
--- /dev/null
+++ b/lib/base/CFunctionJob.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef CFUNCTIONJOB_H
+#define CFUNCTIONJOB_H
+
+#include "IJob.h"
+
+//! Use a function as a job
+/*!
+A job class that invokes a function.
+*/
+class CFunctionJob : public IJob {
+public:
+ //! run() invokes \c func(arg)
+ CFunctionJob(void (*func)(void*), void* arg = NULL);
+ virtual ~CFunctionJob();
+
+ // IJob overrides
+ virtual void run();
+
+private:
+ void (*m_func)(void*);
+ void* m_arg;
+};
+
+#endif
diff --git a/lib/base/CLog.cpp b/lib/base/CLog.cpp
new file mode 100644
index 00000000..7c73ac87
--- /dev/null
+++ b/lib/base/CLog.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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 "CLog.h"
+#include "CString.h"
+#include "CStringUtil.h"
+#include "LogOutputters.h"
+#include "CArch.h"
+#include "Version.h"
+#include
+#include
+
+// names of priorities
+static const char* g_priority[] = {
+ "FATAL",
+ "ERROR",
+ "WARNING",
+ "NOTE",
+ "INFO",
+ "DEBUG",
+ "DEBUG1",
+ "DEBUG2"
+ };
+
+// number of priorities
+static const int g_numPriority = (int)(sizeof(g_priority) /
+ sizeof(g_priority[0]));
+
+// the default priority
+#if defined(NDEBUG)
+static const int g_defaultMaxPriority = 4;
+#else
+static const int g_defaultMaxPriority = 5;
+#endif
+
+// length of longest string in g_priority
+static const int g_maxPriorityLength = 7;
+
+// length of suffix string (": ")
+static const int g_prioritySuffixLength = 2;
+
+// amount of padded required to fill in the priority prefix
+static const int g_priorityPad = g_maxPriorityLength +
+ g_prioritySuffixLength;
+
+
+//
+// CLog
+//
+
+CLog* CLog::s_log = NULL;
+
+CLog::CLog()
+{
+ assert(s_log == NULL);
+
+ // create mutex for multithread safe operation
+ m_mutex = ARCH->newMutex();
+
+ // other initalization
+ m_maxPriority = g_defaultMaxPriority;
+ m_maxNewlineLength = 0;
+ insert(new CConsoleLogOutputter);
+}
+
+CLog::~CLog()
+{
+ // clean up
+ for (COutputterList::iterator index = m_outputters.begin();
+ index != m_outputters.end(); ++index) {
+ delete *index;
+ }
+ for (COutputterList::iterator index = m_alwaysOutputters.begin();
+ index != m_alwaysOutputters.end(); ++index) {
+ delete *index;
+ }
+ ARCH->closeMutex(m_mutex);
+ s_log = NULL;
+}
+
+CLog*
+CLog::getInstance()
+{
+ // note -- not thread safe; client must initialize log safely
+ if (s_log == NULL) {
+ s_log = new CLog;
+ }
+ return s_log;
+}
+
+void
+CLog::print(const char* file, int line, const char* fmt, ...) const
+{
+ // check if fmt begins with a priority argument
+ int priority = 4;
+ if (fmt[0] == '%' && fmt[1] == 'z') {
+ priority = fmt[2] - '\060';
+ fmt += 3;
+ }
+
+ // done if below priority threshold
+ if (priority > getFilter()) {
+ return;
+ }
+
+ // compute prefix padding length
+ char stack[1024];
+ int pPad = g_priorityPad;
+ if (file != NULL) {
+ sprintf(stack, "%d", line);
+ pPad += strlen(file) + 1 /* comma */ +
+ strlen(stack) + 1 /* colon */ + 1 /* space */;
+ }
+
+ // compute suffix padding length
+ int sPad = m_maxNewlineLength;
+
+ // print to buffer, leaving space for a newline at the end and prefix
+ // at the beginning.
+ char* buffer = stack;
+ int len = (int)(sizeof(stack) / sizeof(stack[0]));
+ while (true) {
+ // try printing into the buffer
+ va_list args;
+ va_start(args, fmt);
+ int n = ARCH->vsnprintf(buffer + pPad, len - pPad - sPad, fmt, args);
+ va_end(args);
+
+ // if the buffer wasn't big enough then make it bigger and try again
+ if (n < 0 || n > (int)len) {
+ if (buffer != stack) {
+ delete[] buffer;
+ }
+ len *= 2;
+ buffer = new char[len];
+ }
+
+ // if the buffer was big enough then continue
+ else {
+ break;
+ }
+ }
+
+ // print the prefix to the buffer. leave space for priority label.
+ char* message = buffer;
+ if (file != NULL) {
+ sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
+ buffer[pPad - 1] = ' ';
+
+ // discard file and line if priority < 0
+ if (priority < 0) {
+ message += pPad - g_priorityPad;
+ }
+ }
+
+ // output buffer
+ output(priority, message);
+
+ // clean up
+ if (buffer != stack) {
+ delete[] buffer;
+ }
+}
+
+void
+CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
+{
+ assert(outputter != NULL);
+ assert(outputter->getNewline() != NULL);
+
+ CArchMutexLock lock(m_mutex);
+ if (alwaysAtHead) {
+ m_alwaysOutputters.push_front(outputter);
+ }
+ else {
+ m_outputters.push_front(outputter);
+ }
+ int newlineLength = strlen(outputter->getNewline());
+ if (newlineLength > m_maxNewlineLength) {
+ m_maxNewlineLength = newlineLength;
+ }
+ outputter->open(kAppVersion);
+ outputter->show(false);
+}
+
+void
+CLog::remove(ILogOutputter* outputter)
+{
+ CArchMutexLock lock(m_mutex);
+ m_outputters.remove(outputter);
+ m_alwaysOutputters.remove(outputter);
+}
+
+void
+CLog::pop_front(bool alwaysAtHead)
+{
+ CArchMutexLock lock(m_mutex);
+ COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
+ if (!list->empty()) {
+ delete list->front();
+ list->pop_front();
+ }
+}
+
+bool
+CLog::setFilter(const char* maxPriority)
+{
+ if (maxPriority != NULL) {
+ for (int i = 0; i < g_numPriority; ++i) {
+ if (strcmp(maxPriority, g_priority[i]) == 0) {
+ setFilter(i);
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+void
+CLog::setFilter(int maxPriority)
+{
+ CArchMutexLock lock(m_mutex);
+ m_maxPriority = maxPriority;
+}
+
+int
+CLog::getFilter() const
+{
+ CArchMutexLock lock(m_mutex);
+ return m_maxPriority;
+}
+
+void
+CLog::output(int priority, char* msg) const
+{
+ assert(priority >= -1 && priority < g_numPriority);
+ assert(msg != NULL);
+
+ // 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);
+
+ // write to each outputter
+ 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
+ strcpy(end, outputter->getNewline());
+
+ // write message
+ outputter->write(static_cast(priority),
+ msg + 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
+ strcpy(end, outputter->getNewline());
+
+ // write message and break out of loop if it returns false
+ if (!outputter->write(static_cast(priority),
+ msg + g_maxPriorityLength - n)) {
+ break;
+ }
+ }
+}
diff --git a/lib/base/CLog.h b/lib/base/CLog.h
new file mode 100644
index 00000000..391480e2
--- /dev/null
+++ b/lib/base/CLog.h
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+#ifndef CLOG_H
+#define CLOG_H
+
+#include "common.h"
+#include "IArchMultithread.h"
+#include "stdlist.h"
+#include
+
+#define CLOG (CLog::getInstance())
+
+class ILogOutputter;
+
+//! Logging facility
+/*!
+The logging class; all console output should go through this class.
+It supports multithread safe operation, several message priority levels,
+filtering by priority, and output redirection. The macros LOG() and
+LOGC() provide convenient access.
+*/
+class CLog {
+public:
+ //! Log levels
+ /*!
+ The logging priority levels in order of highest to lowest priority.
+ */
+ enum ELevel {
+ kFATAL, //!< For fatal errors
+ kERROR, //!< For serious errors
+ kWARNING, //!< For minor errors and warnings
+ kNOTE, //!< For messages about notable events
+ kINFO, //!< For informational messages
+ kDEBUG, //!< For important debugging messages
+ kDEBUG1, //!< For more detailed debugging messages
+ kDEBUG2 //!< For even more detailed debugging messages
+ };
+
+ ~CLog();
+
+ //! @name manipulators
+ //@{
+
+ //! Add an outputter to the head of the list
+ /*!
+ Inserts an outputter to the head of the outputter list. When the
+ logger writes a message, it goes to the outputter at the head of
+ the outputter list. If that outputter's \c write() method returns
+ true then it also goes to the next outputter, as so on until an
+ outputter returns false or there are no more outputters. Outputters
+ still in the outputter list when the log is destroyed will be
+ deleted. If \c alwaysAtHead is true then the outputter is always
+ called before all outputters with \c alwaysAtHead false and the
+ return value of the outputter is ignored.
+
+ By default, the logger has one outputter installed which writes to
+ the console.
+ */
+ void insert(ILogOutputter* adopted,
+ bool alwaysAtHead = false);
+
+ //! Remove an outputter from the list
+ /*!
+ Removes the first occurrence of the given outputter from the
+ outputter list. It does nothing if the outputter is not in the
+ list. The outputter is not deleted.
+ */
+ void remove(ILogOutputter* orphaned);
+
+ //! Remove the outputter from the head of the list
+ /*!
+ Removes and deletes the outputter at the head of the outputter list.
+ This does nothing if the outputter list is empty. Only removes
+ outputters that were inserted with the matching \c alwaysAtHead.
+ */
+ void pop_front(bool alwaysAtHead = false);
+
+ //! Set the minimum priority filter.
+ /*!
+ Set the filter. Messages below this priority are discarded.
+ The default priority is 4 (INFO) (unless built without NDEBUG
+ in which case it's 5 (DEBUG)). setFilter(const char*) returns
+ true if the priority \c name was recognized; if \c name is NULL
+ then it simply returns true.
+ */
+ bool setFilter(const char* name);
+ void setFilter(int);
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Print a log message
+ /*!
+ Print a log message using the printf-like \c format and arguments
+ preceded by the filename and line number. If \c file is NULL then
+ neither the file nor the line are printed.
+ */
+ void print(const char* file, int line,
+ const char* format, ...) const;
+
+ //! Get the minimum priority level.
+ int getFilter() const;
+
+ //! Get the singleton instance of the log
+ static CLog* getInstance();
+
+ //@}
+
+private:
+ CLog();
+
+ void output(int priority, char* msg) const;
+
+private:
+ typedef std::list COutputterList;
+
+ static CLog* s_log;
+
+ CArchMutex m_mutex;
+ COutputterList m_outputters;
+ COutputterList m_alwaysOutputters;
+ int m_maxNewlineLength;
+ int m_maxPriority;
+};
+
+/*!
+\def LOG(arg)
+Write to the log. Because macros cannot accept variable arguments, this
+should be invoked like so:
+\code
+LOG((CLOG_XXX "%d and %d are %s", x, y, x == y ? "equal" : "not equal"));
+\endcode
+In particular, notice the double open and close parentheses. Also note
+that there is no comma after the \c CLOG_XXX. The \c XXX should be
+replaced by one of enumerants in \c CLog::ELevel without the leading
+\c k. For example, \c CLOG_INFO. The special \c CLOG_PRINT level will
+not be filtered and is never prefixed by the filename and line number.
+
+If \c NOLOGGING is defined during the build then this macro expands to
+nothing. If \c NDEBUG is defined during the build then it expands to a
+call to CLog::print. Otherwise it expands to a call to CLog::printt,
+which includes the filename and line number.
+*/
+
+/*!
+\def LOGC(expr, arg)
+Write to the log if and only if expr is true. Because macros cannot accept
+variable arguments, this should be invoked like so:
+\code
+LOGC(x == y, (CLOG_XXX "%d and %d are equal", x, y));
+\endcode
+In particular, notice the parentheses around everything after the boolean
+expression. Also note that there is no comma after the \c CLOG_XXX.
+The \c XXX should be replaced by one of enumerants in \c CLog::ELevel
+without the leading \c k. For example, \c CLOG_INFO. The special
+\c CLOG_PRINT level will not be filtered and is never prefixed by the
+filename and line number.
+
+If \c NOLOGGING is defined during the build then this macro expands to
+nothing. If \c NDEBUG is not defined during the build then it expands
+to a call to CLog::print that prints the filename and line number,
+otherwise it expands to a call that doesn't.
+*/
+
+#if defined(NOLOGGING)
+#define LOG(_a1)
+#define LOGC(_a1, _a2)
+#define CLOG_TRACE
+#elif defined(NDEBUG)
+#define LOG(_a1) CLOG->print _a1
+#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
+#define CLOG_TRACE NULL, 0,
+#else
+#define LOG(_a1) CLOG->print _a1
+#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
+#define CLOG_TRACE __FILE__, __LINE__,
+#endif
+
+#define CLOG_PRINT CLOG_TRACE "%z\057"
+#define CLOG_CRIT CLOG_TRACE "%z\060"
+#define CLOG_ERR CLOG_TRACE "%z\061"
+#define CLOG_WARN CLOG_TRACE "%z\062"
+#define CLOG_NOTE CLOG_TRACE "%z\063"
+#define CLOG_INFO CLOG_TRACE "%z\064"
+#define CLOG_DEBUG CLOG_TRACE "%z\065"
+#define CLOG_DEBUG1 CLOG_TRACE "%z\066"
+#define CLOG_DEBUG2 CLOG_TRACE "%z\067"
+
+#endif
diff --git a/lib/base/CPriorityQueue.h b/lib/base/CPriorityQueue.h
new file mode 100644
index 00000000..29129e31
--- /dev/null
+++ b/lib/base/CPriorityQueue.h
@@ -0,0 +1,136 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2003 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CPRIORITYQUEUE_H
+#define CPRIORITYQUEUE_H
+
+#include "stdvector.h"
+#include
+#include
+
+//! A priority queue with an iterator
+/*!
+This priority queue is the same as a standard priority queue except:
+it sorts by std::greater, it has a forward iterator through the elements
+(which can appear in any order), and its contents can be swapped.
+*/
+template ,
+#if defined(_MSC_VER)
+ class Compare = std::greater >
+#else
+ class Compare = std::greater >
+#endif
+class CPriorityQueue {
+public:
+ typedef typename Container::value_type value_type;
+ typedef typename Container::size_type size_type;
+ typedef typename Container::iterator iterator;
+ typedef typename Container::const_iterator const_iterator;
+ typedef Container container_type;
+
+ CPriorityQueue() { }
+ CPriorityQueue(Container& swappedIn) { swap(swappedIn); }
+ ~CPriorityQueue() { }
+
+ //! @name manipulators
+ //@{
+
+ //! Add element
+ void push(const value_type& v)
+ {
+ c.push_back(v);
+ std::push_heap(c.begin(), c.end(), comp);
+ }
+
+ //! Remove head element
+ void pop()
+ {
+ std::pop_heap(c.begin(), c.end(), comp);
+ c.pop_back();
+ }
+
+ //! Erase element
+ void erase(iterator i)
+ {
+ c.erase(i);
+ std::make_heap(c.begin(), c.end(), comp);
+ }
+
+ //! Get start iterator
+ iterator begin()
+ {
+ return c.begin();
+ }
+
+ //! Get end iterator
+ iterator end()
+ {
+ return c.end();
+ }
+
+ //! Swap contents with another priority queue
+ void swap(CPriorityQueue& q)
+ {
+ c.swap(q.c);
+ }
+
+ //! Swap contents with another container
+ void swap(Container& c2)
+ {
+ c.swap(c2);
+ std::make_heap(c.begin(), c.end(), comp);
+ }
+
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Returns true if there are no elements
+ bool empty() const
+ {
+ return c.empty();
+ }
+
+ //! Returns the number of elements
+ size_type size() const
+ {
+ return c.size();
+ }
+
+ //! Returns the head element
+ const value_type& top() const
+ {
+ return c.front();
+ }
+
+ //! Get start iterator
+ const_iterator begin() const
+ {
+ return c.begin();
+ }
+
+ //! Get end iterator
+ const_iterator end() const
+ {
+ return c.end();
+ }
+
+ //@}
+
+private:
+ Container c;
+ Compare comp;
+};
+
+#endif
diff --git a/lib/base/CSimpleEventQueueBuffer.cpp b/lib/base/CSimpleEventQueueBuffer.cpp
new file mode 100644
index 00000000..8f2dbd14
--- /dev/null
+++ b/lib/base/CSimpleEventQueueBuffer.cpp
@@ -0,0 +1,97 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "CSimpleEventQueueBuffer.h"
+#include "CStopwatch.h"
+#include "CArch.h"
+
+class CEventQueueTimer { };
+
+//
+// CSimpleEventQueueBuffer
+//
+
+CSimpleEventQueueBuffer::CSimpleEventQueueBuffer()
+{
+ m_queueMutex = ARCH->newMutex();
+ m_queueReadyCond = ARCH->newCondVar();
+ m_queueReady = false;
+}
+
+CSimpleEventQueueBuffer::~CSimpleEventQueueBuffer()
+{
+ ARCH->closeCondVar(m_queueReadyCond);
+ ARCH->closeMutex(m_queueMutex);
+}
+
+void
+CSimpleEventQueueBuffer::waitForEvent(double timeout)
+{
+ CArchMutexLock lock(m_queueMutex);
+ CStopwatch timer(true);
+ while (!m_queueReady) {
+ double timeLeft = timeout;
+ if (timeLeft >= 0.0) {
+ timeLeft -= timer.getTime();
+ if (timeLeft < 0.0) {
+ return;
+ }
+ }
+ ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft);
+ }
+}
+
+IEventQueueBuffer::Type
+CSimpleEventQueueBuffer::getEvent(CEvent&, UInt32& dataID)
+{
+ CArchMutexLock lock(m_queueMutex);
+ if (!m_queueReady) {
+ return kNone;
+ }
+ dataID = m_queue.back();
+ m_queue.pop_back();
+ m_queueReady = !m_queue.empty();
+ return kUser;
+}
+
+bool
+CSimpleEventQueueBuffer::addEvent(UInt32 dataID)
+{
+ CArchMutexLock lock(m_queueMutex);
+ m_queue.push_front(dataID);
+ if (!m_queueReady) {
+ m_queueReady = true;
+ ARCH->broadcastCondVar(m_queueReadyCond);
+ }
+ return true;
+}
+
+bool
+CSimpleEventQueueBuffer::isEmpty() const
+{
+ CArchMutexLock lock(m_queueMutex);
+ return !m_queueReady;
+}
+
+CEventQueueTimer*
+CSimpleEventQueueBuffer::newTimer(double, bool) const
+{
+ return new CEventQueueTimer;
+}
+
+void
+CSimpleEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
+{
+ delete timer;
+}
diff --git a/lib/base/CSimpleEventQueueBuffer.h b/lib/base/CSimpleEventQueueBuffer.h
new file mode 100644
index 00000000..c395fabd
--- /dev/null
+++ b/lib/base/CSimpleEventQueueBuffer.h
@@ -0,0 +1,49 @@
+/*
+ * synergy -- mouse and keyboard sharing utility
+ * Copyright (C) 2004 Chris Schoeneman
+ *
+ * This package is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * found in the file COPYING that should have accompanied this file.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef CSIMPLEEVENTQUEUEBUFFER_H
+#define CSIMPLEEVENTQUEUEBUFFER_H
+
+#include "IEventQueueBuffer.h"
+#include "IArchMultithread.h"
+#include "stddeque.h"
+
+//! In-memory event queue buffer
+/*!
+An event queue buffer provides a queue of events for an IEventQueue.
+*/
+class CSimpleEventQueueBuffer : public IEventQueueBuffer {
+public:
+ CSimpleEventQueueBuffer();
+ ~CSimpleEventQueueBuffer();
+
+ // IEventQueueBuffer overrides
+ virtual void waitForEvent(double timeout);
+ virtual Type getEvent(CEvent& event, UInt32& dataID);
+ virtual bool addEvent(UInt32 dataID);
+ virtual bool isEmpty() const;
+ virtual CEventQueueTimer*
+ newTimer(double duration, bool oneShot) const;
+ virtual void deleteTimer(CEventQueueTimer*) const;
+
+private:
+ typedef std::deque CEventDeque;
+
+ CArchMutex m_queueMutex;
+ CArchCond m_queueReadyCond;
+ bool m_queueReady;
+ CEventDeque m_queue;
+};
+
+#endif
diff --git a/lib/base/CStopwatch.cpp b/lib/base/CStopwatch.cpp
new file mode 100644
index 00000000..89edce2b
--- /dev/null
+++ b/lib/base/CStopwatch.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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 "CStopwatch.h"
+#include "CArch.h"
+
+//
+// CStopwatch
+//
+
+CStopwatch::CStopwatch(bool triggered) :
+ m_mark(0.0),
+ m_triggered(triggered),
+ m_stopped(triggered)
+{
+ if (!triggered) {
+ m_mark = ARCH->time();
+ }
+}
+
+CStopwatch::~CStopwatch()
+{
+ // do nothing
+}
+
+double
+CStopwatch::reset()
+{
+ if (m_stopped) {
+ const double dt = m_mark;
+ m_mark = 0.0;
+ return dt;
+ }
+ else {
+ const double t = ARCH->time();
+ const double dt = t - m_mark;
+ m_mark = t;
+ return dt;
+ }
+}
+
+void
+CStopwatch::stop()
+{
+ if (m_stopped) {
+ return;
+ }
+
+ // save the elapsed time
+ m_mark = ARCH->time() - m_mark;
+ m_stopped = true;
+}
+
+void
+CStopwatch::start()
+{
+ m_triggered = false;
+ if (!m_stopped) {
+ return;
+ }
+
+ // set the mark such that it reports the time elapsed at stop()
+ m_mark = ARCH->time() - m_mark;
+ m_stopped = false;
+}
+
+void
+CStopwatch::setTrigger()
+{
+ stop();
+ m_triggered = true;
+}
+
+double
+CStopwatch::getTime()
+{
+ if (m_triggered) {
+ const double dt = m_mark;
+ start();
+ return dt;
+ }
+ else if (m_stopped) {
+ return m_mark;
+ }
+ else {
+ return ARCH->time() - m_mark;
+ }
+}
+
+CStopwatch::operator double()
+{
+ return getTime();
+}
+
+bool
+CStopwatch::isStopped() const
+{
+ return m_stopped;
+}
+
+double
+CStopwatch::getTime() const
+{
+ if (m_stopped) {
+ return m_mark;
+ }
+ else {
+ return ARCH->time() - m_mark;
+ }
+}
+
+CStopwatch::operator double() const
+{
+ return getTime();
+}
diff --git a/lib/base/CStopwatch.h b/lib/base/CStopwatch.h
new file mode 100644
index 00000000..e6a34719
--- /dev/null
+++ b/lib/base/CStopwatch.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#ifndef CSTOPWATCH_H
+#define CSTOPWATCH_H
+
+#include "common.h"
+
+//! A timer class
+/*!
+This class measures time intervals. All time interval measurement
+should use this class.
+*/
+class CStopwatch {
+public:
+ /*!
+ The default constructor does an implicit reset() or setTrigger().
+ If triggered == false then the clock starts ticking.
+ */
+ CStopwatch(bool triggered = false);
+ ~CStopwatch();
+
+ //! @name manipulators
+ //@{
+
+ //! Reset the timer to zero
+ /*!
+ Set the start time to the current time, returning the time since
+ the last reset. This does not remove the trigger if it's set nor
+ does it start a stopped clock. If the clock is stopped then
+ subsequent reset()'s will return 0.
+ */
+ double reset();
+
+ //! Stop the timer
+ /*!
+ Stop the stopwatch. The time interval while stopped is not
+ counted by the stopwatch. stop() does not remove the trigger.
+ Has no effect if already stopped.
+ */
+ void stop();
+
+ //! Start the timer
+ /*!
+ Start the stopwatch. start() removes the trigger, even if the
+ stopwatch was already started.
+ */
+ void start();
+
+ //! Stop the timer and set the trigger
+ /*!
+ setTrigger() stops the clock like stop() except there's an
+ implicit start() the next time (non-const) getTime() is called.
+ This is useful when you want the clock to start the first time
+ you check it.
+ */
+ void setTrigger();
+
+ //! Get elapsed time
+ /*!
+ Returns the time since the last reset() (or calls reset() and
+ returns zero if the trigger is set).
+ */
+ double getTime();
+ //! Same as getTime()
+ operator double();
+ //@}
+ //! @name accessors
+ //@{
+
+ //! Check if timer is stopped
+ /*!
+ Returns true if the stopwatch is stopped.
+ */
+ bool isStopped() const;
+
+ // return the time since the last reset().
+ //! Get elapsed time
+ /*!
+ Returns the time since the last reset(). This cannot trigger the
+ stopwatch to start and will not clear the trigger.
+ */
+ double getTime() const;
+ //! Same as getTime() const
+ operator double() const;
+ //@}
+
+private:
+ double getClock() const;
+
+private:
+ double m_mark;
+ bool m_triggered;
+ bool m_stopped;
+};
+
+#endif
diff --git a/lib/base/CString.h b/lib/base/CString.h
new file mode 100644
index 00000000..bc905009
--- /dev/null
+++ b/lib/base/CString.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#ifndef CSTRING_H
+#define CSTRING_H
+
+#include "common.h"
+#include "stdstring.h"
+
+// use standard C++ string class for our string class
+typedef std::string CString;
+
+#endif
+
diff --git a/lib/base/CStringUtil.cpp b/lib/base/CStringUtil.cpp
new file mode 100644
index 00000000..46361932
--- /dev/null
+++ b/lib/base/CStringUtil.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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 "CStringUtil.h"
+#include "CArch.h"
+#include "common.h"
+#include "stdvector.h"
+#include
+#include
+#include
+#include