diff --git a/ChangeLog b/ChangeLog
index 7d1f8d2b..10ccab7b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1897 @@
+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
diff --git a/acinclude.m4 b/acinclude.m4
index 12d80bda..e7666464 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -300,6 +300,8 @@ 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
@@ -310,11 +312,11 @@ acx_pthread_ok=no
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
- save_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ 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 CXXFLAGS=$PTHREAD_CFLAGS])
+ 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
@@ -322,7 +324,7 @@ if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
- CXXFLAGS="$save_CXXFLAGS"
+ CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
@@ -332,9 +334,10 @@ fi
# 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.
+# 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"
+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:
@@ -353,6 +356,7 @@ acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -m
# 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*)
@@ -382,6 +386,13 @@ for flag in $acx_pthread_flags; do
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"
@@ -389,9 +400,9 @@ for flag in $acx_pthread_flags; do
esac
save_LIBS="$LIBS"
- save_CXXFLAGS="$CXXFLAGS"
+ save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
- CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
@@ -409,7 +420,7 @@ for flag in $acx_pthread_flags; do
[acx_pthread_ok=yes])
LIBS="$save_LIBS"
- CXXFLAGS="$save_CXXFLAGS"
+ CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($acx_pthread_ok)
if test "x$acx_pthread_ok" = xyes; then
@@ -425,69 +436,61 @@ fi
if test "x$acx_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
- save_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- # Detect AIX lossage: threads are created detached by default
- # and the JOINABLE attribute has a nonstandard name (UNDETACHED).
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
- AC_TRY_LINK([#include ],
- [int attr=PTHREAD_CREATE_JOINABLE;],
- ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
- if test x"$ok" = xunknown; then
- AC_TRY_LINK([#include ],
- [int attr=PTHREAD_CREATE_UNDETACHED;],
- ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
- fi
- if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
- AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
- [Define to the necessary symbol if this constant
- uses a non-standard name on your system.])
- fi
- AC_MSG_RESULT(${ok})
- if test x"$ok" = xunknown; then
- AC_MSG_WARN([we do not know how to create joinable pthreads])
+ 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*) flag="-D_THREAD_SAFE";;
- alpha*-osf*) flag="-D_REENTRANT";;
- *solaris*) flag="-D_REENTRANT";;
+ *-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()
+ # Detect POSIX sigwait()
AC_MSG_CHECKING([for POSIX sigwait])
AC_TRY_LINK([#include
- #include ],
- [sigset_t sigset; int signal; sigwait(&sigset, &signal);],
+ #include ],
+ [sigset_t sigset; int signal; sigwait(&sigset, &signal);],
ok=yes, ok=unknown)
if test x"$ok" = xunknown; then
- save_CXXFLAGS2="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS -D_POSIX_PTHREAD_SEMANTICS"
+ 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)
- CXXFLAGS="$save_CXXFLAGS2"
+ #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
+ PTHREAD_CFLAGS="$ok $PTHREAD_CFLAGS"
+ fi
fi
- # Detect pthread signal functions
+ # Detect pthread signal functions
AC_MSG_CHECKING([for pthread signal functions])
AC_TRY_LINK([#include
- #include ],
+ #include ],
[pthread_kill(pthread_self(), SIGTERM);],
ok=yes, ok=no)
AC_MSG_RESULT(${ok})
@@ -496,7 +499,7 @@ if test "x$acx_pthread_ok" = xyes; then
fi
LIBS="$save_LIBS"
- CXXFLAGS="$save_CXXFLAGS"
+ CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with cc_r
AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
@@ -516,6 +519,7 @@ else
acx_pthread_ok=no
$2
fi
+AC_LANG_RESTORE
])dnl ACX_PTHREAD
dnl enable maximum compiler warnings. must ignore unknown pragmas to
diff --git a/cmd/launcher/CAddScreen.cpp b/cmd/launcher/CAddScreen.cpp
new file mode 100644
index 00000000..bc65f283
--- /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, (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
index 4c72e8d4..ee5b45ea 100644
--- a/cmd/launcher/CAdvancedOptions.cpp
+++ b/cmd/launcher/CAdvancedOptions.cpp
@@ -206,7 +206,7 @@ CAdvancedOptions::save(HWND hwnd)
m_interface = iface;
// save values to registry
- HKEY key = CArchMiscWindows::openKey(HKEY_CURRENT_USER, getSettingsPath());
+ HKEY key = CArchMiscWindows::addKey(HKEY_CURRENT_USER, getSettingsPath());
if (key != NULL) {
CArchMiscWindows::setValue(key, "port", m_port);
CArchMiscWindows::setValue(key, "name", m_screenName);
diff --git a/cmd/launcher/CAutoStart.cpp b/cmd/launcher/CAutoStart.cpp
index d5eee0ce..7b390a58 100644
--- a/cmd/launcher/CAutoStart.cpp
+++ b/cmd/launcher/CAutoStart.cpp
@@ -21,10 +21,10 @@
#include "LaunchUtil.h"
#include "resource.h"
-#define CLIENT_DAEMON_NAME "Synergy Client"
-#define SERVER_DAEMON_NAME "Synergy Server"
-#define CLIENT_DAEMON_INFO "Shares this system's mouse and keyboard with others."
-#define SERVER_DAEMON_INFO "Shares this system's mouse and keyboard with others."
+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
@@ -40,6 +40,7 @@ public:
// 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 ""; }
@@ -63,14 +64,11 @@ CAutoStartOutputter::write(ELevel level, const char* message)
CAutoStart* CAutoStart::s_singleton = NULL;
-CAutoStart::CAutoStart(HWND parent, CConfig* config, const CString& cmdLine) :
+CAutoStart::CAutoStart(HWND parent, bool isServer, const CString& cmdLine) :
m_parent(parent),
- m_config(config),
- m_isServer(config != NULL),
+ m_isServer(isServer),
m_cmdLine(cmdLine),
- m_name((config != NULL) ? SERVER_DAEMON_NAME : CLIENT_DAEMON_NAME),
- m_userConfigSaved(false)
-
+ m_name(isServer ? SERVER_DAEMON_NAME : CLIENT_DAEMON_NAME)
{
assert(s_singleton == NULL);
s_singleton = this;
@@ -87,9 +85,6 @@ CAutoStart::doModal()
// install our log outputter
CLOG->insert(new CAutoStartOutputter(&m_errorMessage));
- // reset saved flag
- m_userConfigSaved = false;
-
// do dialog
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART),
m_parent, dlgProc, (LPARAM)this);
@@ -98,10 +93,98 @@ CAutoStart::doModal()
CLOG->pop_front();
}
-bool
-CAutoStart::wasUserConfigSaved() const
+void
+CAutoStart::reinstallDaemon(bool isClient, const CString& cmdLine)
{
- return m_userConfigSaved;
+ // 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
@@ -177,22 +260,6 @@ CAutoStart::onInstall(bool allUsers)
return onUninstall(allUsers);
}
- // try saving configuration. if we can't then don't try
- // installing the daemon.
- if (m_config != NULL) {
- if (!saveConfig(*m_config, allUsers)) {
- showError(m_hwnd, CStringUtil::format(
- getString(IDS_SAVE_FAILED).c_str(),
- getErrorString(GetLastError()).c_str()));
- return false;
- }
-
- // note if we've saved the user's configuration
- if (!allUsers) {
- m_userConfigSaved = true;
- }
- }
-
// get the app path
CString appPath = getAppPath(m_isServer ? SERVER_APP : CLIENT_APP);
diff --git a/cmd/launcher/CAutoStart.h b/cmd/launcher/CAutoStart.h
index e931530e..46aad100 100644
--- a/cmd/launcher/CAutoStart.h
+++ b/cmd/launcher/CAutoStart.h
@@ -20,14 +20,10 @@
#define WINDOWS_LEAN_AND_MEAN
#include
-class CConfig;
-
//! Auto start dialog for Microsoft Windows launcher
class CAutoStart {
public:
- // if config == NULL then it's assumed we're installing/uninstalling
- // the client, otherwise the server.
- CAutoStart(HWND parent, CConfig* config, const CString& cmdLine);
+ CAutoStart(HWND parent, bool isServer, const CString& cmdLine);
~CAutoStart();
//! @name manipulators
@@ -39,16 +35,34 @@ public:
*/
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
//@{
- //! Test if user configuration was saved
+ //! Tests if any daemons are installed
/*!
- Returns true if the user's configuration (as opposed to the system-wide
- configuration) was saved successfully while in doModal().
+ Returns \c true if any daemons are installed.
*/
- bool wasUserConfigSaved() const;
+ static bool isDaemonInstalled();
//@}
@@ -65,14 +79,12 @@ private:
static CAutoStart* s_singleton;
HWND m_parent;
- CConfig* m_config;
bool m_isServer;
CString m_cmdLine;
CString m_name;
HWND m_hwnd;
bool m_install;
CString m_errorMessage;
- bool m_userConfigSaved;
};
#endif
diff --git a/cmd/launcher/CGlobalOptions.cpp b/cmd/launcher/CGlobalOptions.cpp
index 1777863b..b7c15801 100644
--- a/cmd/launcher/CGlobalOptions.cpp
+++ b/cmd/launcher/CGlobalOptions.cpp
@@ -79,6 +79,8 @@ CGlobalOptions::init(HWND hwnd)
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("");
@@ -122,6 +124,10 @@ CGlobalOptions::init(HWND hwnd)
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));
+ }
}
}
}
@@ -187,6 +193,7 @@ CGlobalOptions::save(HWND hwnd)
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);
@@ -209,6 +216,10 @@ CGlobalOptions::save(HWND hwnd)
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;
diff --git a/cmd/launcher/CHotkeyOptions.cpp b/cmd/launcher/CHotkeyOptions.cpp
new file mode 100644
index 00000000..7e7a1b56
--- /dev/null
+++ b/cmd/launcher/CHotkeyOptions.cpp
@@ -0,0 +1,1864 @@
+/*
+ * 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, (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;
+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_LOCK_MODE_OFF).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_LOCK_MODE_ON).c_str());
+ SendMessage(child, CB_ADDSTRING, 0,
+ (LPARAM)getString(IDS_LOCK_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);
+
+ // 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);
+ 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);
+ }
+ 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;
+ }
+
+ // 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);
+
+ // 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));
+ }
+}
+
+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_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_SCREENS:
+ CScreensDialog::doModal(hwnd, s_config,
+ dynamic_cast(s_action));
+ fillHotkey(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..b63fcf2b
--- /dev/null
+++ b/cmd/launcher/CHotkeyOptions.h
@@ -0,0 +1,225 @@
+/*
+ * 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 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 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..f2292db8
--- /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, (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..dbbca67b
--- /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, (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
index 240fd1d9..05b517e7 100644
--- a/cmd/launcher/LaunchUtil.cpp
+++ b/cmd/launcher/LaunchUtil.cpp
@@ -19,7 +19,7 @@
#include "resource.h"
#include "stdfstream.h"
-#define CONFIG_NAME "synergy.sgc"
+size_t s_showingDialog = 0;
CString
getString(DWORD id)
@@ -37,24 +37,36 @@ 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)
{
@@ -109,6 +121,39 @@ getAppPath(const CString& 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)
@@ -127,7 +172,7 @@ loadConfig(const CString& pathname, CConfig& config)
}
bool
-loadConfig(CConfig& config)
+loadConfig(CConfig& config, time_t& t, bool& userConfig)
{
// load configuration
bool configLoaded = false;
@@ -137,6 +182,8 @@ loadConfig(CConfig& config)
path = ARCH->concatPath(path, CONFIG_NAME);
if (loadConfig(path, config)) {
configLoaded = true;
+ userConfig = true;
+ getFileTime(path, t);
}
else {
// try the system-wide config file
@@ -145,6 +192,8 @@ loadConfig(CConfig& config)
path = ARCH->concatPath(path, CONFIG_NAME);
if (loadConfig(path, config)) {
configLoaded = true;
+ userConfig = false;
+ getFileTime(path, t);
}
}
}
@@ -170,7 +219,7 @@ saveConfig(const CString& pathname, const CConfig& config)
}
bool
-saveConfig(const CConfig& config, bool sysOnly)
+saveConfig(const CConfig& config, bool sysOnly, time_t& t)
{
// try saving the user's configuration
if (!sysOnly) {
@@ -178,6 +227,7 @@ saveConfig(const CConfig& config, bool sysOnly)
if (!path.empty()) {
path = ARCH->concatPath(path, CONFIG_NAME);
if (saveConfig(path, config)) {
+ getFileTime(path, t);
return true;
}
}
@@ -189,6 +239,7 @@ saveConfig(const CConfig& config, bool sysOnly)
if (!path.empty()) {
path = ARCH->concatPath(path, CONFIG_NAME);
if (saveConfig(path, config)) {
+ getFileTime(path, t);
return true;
}
}
diff --git a/cmd/launcher/LaunchUtil.h b/cmd/launcher/LaunchUtil.h
index 48889264..75954046 100644
--- a/cmd/launcher/LaunchUtil.h
+++ b/cmd/launcher/LaunchUtil.h
@@ -19,9 +19,12 @@
#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;
@@ -35,6 +38,7 @@ 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);
@@ -47,8 +51,10 @@ bool isItemChecked(HWND);
CString getAppPath(const CString& appName);
-bool loadConfig(CConfig& config);
-bool saveConfig(const CConfig& config, bool sysOnly);
+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();
diff --git a/cmd/launcher/Makefile.am b/cmd/launcher/Makefile.am
index 4998a89a..729aeb79 100644
--- a/cmd/launcher/Makefile.am
+++ b/cmd/launcher/Makefile.am
@@ -14,14 +14,22 @@
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 \
diff --git a/cmd/launcher/launcher.cpp b/cmd/launcher/launcher.cpp
index 66019f01..07eab676 100644
--- a/cmd/launcher/launcher.cpp
+++ b/cmd/launcher/launcher.cpp
@@ -20,29 +20,23 @@
#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 "CAdvancedOptions.h"
-
-#define CONFIG_NAME "synergy.sgc"
-#define CLIENT_APP "synergyc.exe"
-#define SERVER_APP "synergys.exe"
+#include "CHotkeyOptions.h"
+#include "CInfo.h"
+#include "CScreensLinks.h"
typedef std::vector CStringList;
-class CScreenInfo {
-public:
- CString m_screen;
- CStringList m_aliases;
- CConfig::CScreenOptions m_options;
-};
-
class CChildWaitInfo {
public:
HWND m_dialog;
@@ -52,29 +46,6 @@ public:
HANDLE m_stop;
};
-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;
-
static const char* s_debugName[][2] = {
{ TEXT("Error"), "ERROR" },
{ TEXT("Warning"), "WARNING" },
@@ -84,16 +55,30 @@ static const char* s_debugName[][2] = {
{ TEXT("Debug1"), "DEBUG1" },
{ TEXT("Debug2"), "DEBUG2" }
};
-static const int s_defaultDebug = 3; // INFO
+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
//
@@ -108,7 +93,6 @@ public:
public:
static CArgs* s_instance;
CConfig m_config;
- CConfig m_oldConfig;
CStringList m_screens;
};
@@ -119,40 +103,6 @@ static
BOOL CALLBACK
addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-static
-void
-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);
-}
-
-static
-bool
-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;
-}
-
static
bool
isClientChecked(HWND hwnd)
@@ -161,44 +111,6 @@ isClientChecked(HWND hwnd)
return isItemChecked(child);
}
-static
-void
-enableSaveControls(HWND hwnd)
-{
- enableItem(hwnd, IDC_MAIN_SAVE, ARG->m_config != ARG->m_oldConfig);
-}
-
-static
-void
-enableScreensControls(HWND hwnd)
-{
- // decide if edit and remove buttons should be enabled
- bool client = isClientChecked(hwnd);
- bool screenSelected = false;
- if (!client) {
- HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- if (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR) {
- screenSelected = true;
- }
- }
-
- // enable/disable controls
- enableItem(hwnd, IDC_MAIN_SERVER_SCREENS_LABEL, !client);
- enableItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST, !client);
- enableItem(hwnd, IDC_MAIN_SERVER_ADD_BUTTON, !client);
- enableItem(hwnd, IDC_MAIN_SERVER_EDIT_BUTTON, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_REMOVE_BUTTON, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_LAYOUT_LABEL, !client);
- enableItem(hwnd, IDC_MAIN_SERVER_LEFT_COMBO, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_RIGHT_COMBO, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_TOP_COMBO, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_BOTTOM_COMBO, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_LEFT_LABEL, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_RIGHT_LABEL, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_TOP_LABEL, screenSelected);
- enableItem(hwnd, IDC_MAIN_SERVER_BOTTOM_LABEL, screenSelected);
-}
-
static
void
enableMainWindowControls(HWND hwnd)
@@ -206,248 +118,10 @@ 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);
- enableScreensControls(hwnd);
- enableSaveControls(hwnd);
-}
-
-static
-void
-updateNeighbor(HWND hwnd, const CString& screen, EDirection direction)
-{
- // remove all neighbors from combo box
- SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
-
- // add all screens to combo box
- if (!screen.empty()) {
- for (CConfig::const_iterator index = ARG->m_config.begin();
- index != ARG->m_config.end(); ++index) {
- SendMessage(hwnd, CB_INSERTSTRING,
- (WPARAM)-1, (LPARAM)index->c_str());
- }
- }
-
- // add empty neighbor to combo box
- SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)TEXT("---"));
-
- // select neighbor in combo box
- LRESULT index = 0;
- if (!screen.empty()) {
- const CString& neighbor = ARG->m_config.getNeighbor(screen, direction);
- if (!neighbor.empty()) {
- index = SendMessage(hwnd, CB_FINDSTRINGEXACT,
- 0, (LPARAM)neighbor.c_str());
- if (index == LB_ERR) {
- index = 0;
- }
- }
- }
- SendMessage(hwnd, CB_SETCURSEL, index, 0);
-}
-
-static
-void
-updateNeighbors(HWND hwnd)
-{
- // get selected screen name or empty string if no selection
- CString screen;
- HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
- if (index != LB_ERR) {
- screen = ARG->m_screens[index];
- }
-
- // set neighbor combo boxes
- child = getItem(hwnd, IDC_MAIN_SERVER_LEFT_COMBO);
- updateNeighbor(child, screen, kLeft);
- child = getItem(hwnd, IDC_MAIN_SERVER_RIGHT_COMBO);
- updateNeighbor(child, screen, kRight);
- child = getItem(hwnd, IDC_MAIN_SERVER_TOP_COMBO);
- updateNeighbor(child, screen, kTop);
- child = getItem(hwnd, IDC_MAIN_SERVER_BOTTOM_COMBO);
- updateNeighbor(child, screen, kBottom);
-}
-
-static
-void
-addScreen(HWND hwnd)
-{
- // empty screen info
- CScreenInfo info;
-
- // run dialog
- if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
- hwnd, addDlgProc, (LPARAM)&info) != 0) {
- // get current number of screens
- UInt32 i = ARG->m_screens.size();
-
- // add screen to list control
- HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- CString item = CStringUtil::print("%d. %s",
- i + 1, info.m_screen.c_str());
- SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
-
- // add screen to screen list
- ARG->m_screens.push_back(info.m_screen);
-
- // add screen to config
- ARG->m_config.addScreen(info.m_screen);
-
- // add aliases to config
- for (CStringList::const_iterator index = info.m_aliases.begin();
- index != info.m_aliases.end(); ++index) {
- ARG->m_config.addAlias(info.m_screen, *index);
- }
-
- // set options
- ARG->m_config.removeOptions(info.m_screen);
- for (CConfig::CScreenOptions::const_iterator
- index = info.m_options.begin();
- index != info.m_options.end(); ++index) {
- ARG->m_config.addOption(info.m_screen, index->first, index->second);
- }
-
- // update neighbors
- updateNeighbors(hwnd);
- enableScreensControls(hwnd);
- enableSaveControls(hwnd);
- }
-}
-
-static
-void
-editScreen(HWND hwnd)
-{
- // get selected list item
- HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
- if (index == LB_ERR) {
- // no selection
- return;
- }
-
- // fill in screen info
- CScreenInfo info;
- info.m_screen = ARG->m_screens[index];
- for (CConfig::all_const_iterator index = ARG->m_config.beginAll();
- index != ARG->m_config.endAll(); ++index) {
- if (CStringUtil::CaselessCmp::equal(index->second, info.m_screen) &&
- !CStringUtil::CaselessCmp::equal(index->second, index->first)) {
- info.m_aliases.push_back(index->first);
- }
- }
- const CConfig::CScreenOptions* options =
- ARG->m_config.getOptions(info.m_screen);
- if (options != NULL) {
- info.m_options = *options;
- }
-
- // save current info
- CScreenInfo oldInfo = info;
-
- // run dialog
- if (DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADD),
- hwnd, addDlgProc, (LPARAM)&info) != 0) {
- // replace screen
- ARG->m_screens[index] = info.m_screen;
-
- // remove old aliases
- for (CStringList::const_iterator index = oldInfo.m_aliases.begin();
- index != oldInfo.m_aliases.end(); ++index) {
- ARG->m_config.removeAlias(*index);
- }
-
- // replace name
- ARG->m_config.renameScreen(oldInfo.m_screen, info.m_screen);
-
- // add new aliases
- for (CStringList::const_iterator index = info.m_aliases.begin();
- index != info.m_aliases.end(); ++index) {
- ARG->m_config.addAlias(info.m_screen, *index);
- }
-
- // set options
- ARG->m_config.removeOptions(info.m_screen);
- for (CConfig::CScreenOptions::const_iterator
- index = info.m_options.begin();
- index != info.m_options.end(); ++index) {
- ARG->m_config.addOption(info.m_screen, index->first, index->second);
- }
-
- // update list
- CString item = CStringUtil::print("%d. %s",
- index + 1, info.m_screen.c_str());
- SendMessage(child, LB_DELETESTRING, index, 0);
- SendMessage(child, LB_INSERTSTRING, index,
- (LPARAM)item.c_str());
- SendMessage(child, LB_SETCURSEL, index, 0);
-
- // update neighbors
- updateNeighbors(hwnd);
- enableSaveControls(hwnd);
- }
-}
-
-static
-void
-removeScreen(HWND hwnd)
-{
- // get selected list item
- HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
- if (index == LB_ERR) {
- // no selection
- return;
- }
-
- // get screen name
- CString name = ARG->m_screens[index];
-
- // remove screen from list control
- SendMessage(child, LB_DELETESTRING, index, 0);
-
- // remove screen from screen list
- ARG->m_screens.erase(&ARG->m_screens[index]);
-
- // remove screen from config (this also removes aliases)
- ARG->m_config.removeScreen(name);
-
- // update neighbors
- updateNeighbors(hwnd);
- enableScreensControls(hwnd);
- enableSaveControls(hwnd);
-}
-
-static
-void
-changeNeighbor(HWND hwnd, HWND combo, EDirection direction)
-{
- // get selected screen
- HWND child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0);
- if (index == LB_ERR) {
- // no selection
- return;
- }
-
- // get screen name
- CString screen = ARG->m_screens[index];
-
- // get selected neighbor
- index = SendMessage(combo, CB_GETCURSEL, 0, 0);
-
- // remove old connection
- ARG->m_config.disconnect(screen, direction);
-
- // add new connection
- if (index != LB_ERR && index != 0) {
- LRESULT size = SendMessage(combo, CB_GETLBTEXTLEN, index, 0);
- char* neighbor = new char[size + 1];
- SendMessage(combo, CB_GETLBTEXT, index, (LPARAM)neighbor);
- ARG->m_config.connect(screen, direction, CString(neighbor));
- delete[] neighbor;
- }
-
- enableSaveControls(hwnd);
+ 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
@@ -505,7 +179,7 @@ execApp(const char* app, const CString& cmdLine, PROCESS_INFORMATION* procInfo)
static
CString
-getCommandLine(HWND hwnd, bool testing)
+getCommandLine(HWND hwnd, bool testing, bool silent)
{
CString cmdLine;
@@ -527,9 +201,11 @@ getCommandLine(HWND hwnd, bool testing)
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
server = getWindowText(child);
if (!ARG->m_config.isValidScreenName(server)) {
- showError(hwnd, CStringUtil::format(
+ if (!silent) {
+ showError(hwnd, CStringUtil::format(
getString(IDS_INVALID_SERVER_NAME).c_str(),
server.c_str()));
+ }
SetFocus(child);
return CString();
}
@@ -539,9 +215,11 @@ getCommandLine(HWND hwnd, bool testing)
// don't bother to check the addresses though that'd be
// more accurate.
if (CStringUtil::CaselessCmp::equal(ARCH->getHostName(), server)) {
- showError(hwnd, CStringUtil::format(
+ if (!silent) {
+ showError(hwnd, CStringUtil::format(
getString(IDS_SERVER_IS_CLIENT).c_str(),
server.c_str()));
+ }
SetFocus(child);
return CString();
}
@@ -549,8 +227,16 @@ getCommandLine(HWND hwnd, bool testing)
// debug level. always include this.
if (true) {
- HWND child = getItem(hwnd, IDC_MAIN_DEBUG);
- DWORD debug = SendMessage(child, CB_GETCURSEL, 0, 0);
+ 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];
}
@@ -562,17 +248,29 @@ getCommandLine(HWND hwnd, bool testing)
}
static
-HANDLE
-launchApp(HWND hwnd, bool testing, DWORD* threadID)
+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);
+ CString cmdLine = getCommandLine(hwnd, testing, false);
if (cmdLine.empty()) {
- return NULL;
+ return false;
}
// start child
@@ -581,19 +279,21 @@ launchApp(HWND hwnd, bool testing, DWORD* threadID)
showError(hwnd, CStringUtil::format(
getString(IDS_STARTUP_FAILED).c_str(),
getErrorString(GetLastError()).c_str()));
- return NULL;
+ return false;
}
// don't need process handle
CloseHandle(procInfo.hProcess);
- // save thread ID if desired
+ // save thread handle and thread ID if desired
+ if (thread != NULL) {
+ *thread = procInfo.hThread;
+ }
if (threadID != NULL) {
*threadID = procInfo.dwThreadId;
}
- // return thread handle
- return procInfo.hThread;
+ return true;
}
static
@@ -701,9 +401,11 @@ initMainWindow(HWND hwnd)
setWindowText(hwnd, CStringUtil::format(titleFormat.c_str(), VERSION));
// load configuration
- bool configLoaded = loadConfig(ARG->m_config);
- ARG->m_oldConfig = ARG->m_config;
- enableSaveControls(hwnd);
+ bool configLoaded =
+ loadConfig(ARG->m_config, s_configTime, s_userConfig);
+ if (configLoaded) {
+ s_lastConfig = ARG->m_config;
+ }
// get settings from registry
bool isServer = configLoaded;
@@ -739,18 +441,6 @@ initMainWindow(HWND hwnd)
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
setWindowText(child, server);
- // if config is loaded then initialize server controls
- if (configLoaded) {
- int i = 1;
- child = getItem(hwnd, IDC_MAIN_SERVER_SCREENS_LIST);
- for (CConfig::const_iterator index = ARG->m_config.begin();
- index != ARG->m_config.end(); ++i, ++index) {
- ARG->m_screens.push_back(*index);
- CString item = CStringUtil::print("%d. %s", i, index->c_str());
- SendMessage(child, LB_ADDSTRING, 0, (LPARAM)item.c_str());
- }
- }
-
// debug level
child = getItem(hwnd, IDC_MAIN_DEBUG);
for (unsigned int i = 0; i < sizeof(s_debugName) /
@@ -759,16 +449,21 @@ initMainWindow(HWND hwnd)
}
SendMessage(child, CB_SETCURSEL, debugLevel, 0);
- // update neighbor combo boxes
+ // update controls
enableMainWindowControls(hwnd);
- updateNeighbors(hwnd);
}
static
-void
-saveMainWindow(HWND hwnd)
+bool
+saveMainWindow(HWND hwnd, SaveMode mode, CString* cmdLineOut = NULL)
{
- HKEY key = CArchMiscWindows::openKey(HKEY_CURRENT_USER, getSettingsPath());
+ 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);
@@ -776,214 +471,78 @@ saveMainWindow(HWND hwnd)
child = getItem(hwnd, IDC_MAIN_DEBUG);
CArchMiscWindows::setValue(key, "debug",
SendMessage(child, CB_GETCURSEL, 0, 0));
- CArchMiscWindows::setValue(key, "isServer",
- isClientChecked(hwnd) ? 0 : 1);
+ CArchMiscWindows::setValue(key, "isServer", isClient ? 0 : 1);
CArchMiscWindows::closeKey(key);
}
-}
-static
-BOOL CALLBACK
-addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- // only one add dialog at a time!
- static CScreenInfo* info = NULL;
-
- switch (message) {
- case WM_INITDIALOG: {
- info = (CScreenInfo*)lParam;
-
- // set title
- CString title;
- if (info->m_screen.empty()) {
- title = getString(IDS_ADD_SCREEN);
+ // 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;
}
- else {
- title = CStringUtil::format(
- getString(IDS_EDIT_SCREEN).c_str(),
- info->m_screen.c_str());
+ if (s_userConfig) {
+ s_configTime = t;
+ s_lastConfig = ARG->m_config;
}
- 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)info->m_screen.c_str());
-
- // fill in aliases
- CString aliases;
- for (CStringList::const_iterator index = info->m_aliases.begin();
- index != info->m_aliases.end(); ++index) {
- if (!aliases.empty()) {
- aliases += "\r\n";
- }
- aliases += *index;
- }
- child = getItem(hwnd, IDC_ADD_ALIASES_EDIT);
- SendMessage(child, WM_SETTEXT, 0, (LPARAM)aliases.c_str());
-
- // set options
- CConfig::CScreenOptions::const_iterator index;
- child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
- index = info->m_options.find(kOptionHalfDuplexCapsLock);
- setItemChecked(child, (index != info->m_options.end() &&
- index->second != 0));
- child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
- index = info->m_options.find(kOptionHalfDuplexNumLock);
- setItemChecked(child, (index != info->m_options.end() &&
- index->second != 0));
- child = getItem(hwnd, IDC_ADD_HD_SCROLL_CHECK);
- index = info->m_options.find(kOptionHalfDuplexScrollLock);
- setItemChecked(child, (index != info->m_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 = info->m_options.find(s_modifiers[i].m_optionID);
- KeyModifierID id = s_modifiers[i].m_modifierID;
- if (index != info->m_options.end()) {
- id = index->second;
- }
- SendMessage(child, CB_SETCURSEL, id - baseModifier, 0);
- }
-
- return TRUE;
}
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK: {
- CString newName;
- CStringList newAliases;
-
- // extract name and aliases
- HWND child = getItem(hwnd, IDC_ADD_SCREEN_NAME_EDIT);
- newName = getWindowText(child);
- child = getItem(hwnd, IDC_ADD_ALIASES_EDIT);
- tokenize(newAliases, getWindowText(child));
-
- // name must be valid
- if (!ARG->m_config.isValidScreenName(newName)) {
- showError(hwnd, CStringUtil::format(
- getString(IDS_INVALID_SCREEN_NAME).c_str(),
- newName.c_str()));
- return TRUE;
+ // 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;
}
-
- // aliases must be valid
- for (CStringList::const_iterator index = newAliases.begin();
- index != newAliases.end(); ++index) {
- if (!ARG->m_config.isValidScreenName(*index)) {
- showError(hwnd, CStringUtil::format(
- getString(IDS_INVALID_SCREEN_NAME).c_str(),
- index->c_str()));
- return TRUE;
- }
+ if (!s_userConfig) {
+ s_configTime = t;
+ s_lastConfig = ARG->m_config;
}
-
- // 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 TRUE;
- }
-
- // 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 (ARG->m_config.isScreen(newName) &&
- !CStringUtil::CaselessCmp::equal(newName, info->m_screen) &&
- !isNameInList(info->m_aliases, newName)) {
- showError(hwnd, CStringUtil::format(
- getString(IDS_DUPLICATE_SCREEN_NAME).c_str(),
- newName.c_str()));
- return TRUE;
- }
-
- // 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 (ARG->m_config.isScreen(*index) &&
- !CStringUtil::CaselessCmp::equal(*index, info->m_screen) &&
- !isNameInList(info->m_aliases, *index)) {
- showError(hwnd, CStringUtil::format(
- getString(IDS_DUPLICATE_SCREEN_NAME).c_str(),
- index->c_str()));
- return TRUE;
- }
- }
-
- // save name data
- info->m_screen = newName;
- info->m_aliases = newAliases;
-
- // save options
- child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
- if (isItemChecked(child)) {
- info->m_options[kOptionHalfDuplexCapsLock] = 1;
- }
- else {
- info->m_options.erase(kOptionHalfDuplexCapsLock);
- }
- child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
- if (isItemChecked(child)) {
- info->m_options[kOptionHalfDuplexNumLock] = 1;
- }
- else {
- info->m_options.erase(kOptionHalfDuplexNumLock);
- }
- child = getItem(hwnd, IDC_ADD_HD_SCROLL_CHECK);
- if (isItemChecked(child)) {
- info->m_options[kOptionHalfDuplexScrollLock] = 1;
- }
- else {
- info->m_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) {
- info->m_options[s_modifiers[i].m_optionID] = id;
- }
- else {
- info->m_options.erase(s_modifiers[i].m_optionID);
- }
- }
-
- // success
- EndDialog(hwnd, 1);
- info = NULL;
- return TRUE;
}
-
- case IDCANCEL:
- EndDialog(hwnd, 0);
- info = NULL;
- return TRUE;
- }
-
- default:
- break;
}
- return FALSE;
+ // 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
@@ -991,18 +550,46 @@ 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:
- // test for unsaved data
- if (ARG->m_config != ARG->m_oldConfig) {
- if (!askVerify(hwnd, getString(IDS_UNSAVED_DATA_REALLY_QUIT))) {
- return 0;
- }
+ // save data
+ if (saveMainWindow(hwnd, SAVE_QUITING)) {
+ // quit
+ PostQuitMessage(0);
}
-
- // quit
- PostQuitMessage(0);
return 0;
case IDOK:
@@ -1011,139 +598,72 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST);
// save data
- if (ARG->m_config != ARG->m_oldConfig) {
- if (!saveConfig(ARG->m_config, false)) {
- showError(hwnd, CStringUtil::format(
- getString(IDS_SAVE_FAILED).c_str(),
- getErrorString(GetLastError()).c_str()));
+ if (saveMainWindow(hwnd, SAVE_NORMAL)) {
+ // launch child app
+ DWORD threadID;
+ HANDLE thread;
+ if (!launchApp(hwnd, testing, &thread, &threadID)) {
return 0;
}
- ARG->m_oldConfig = ARG->m_config;
- enableSaveControls(hwnd);
- }
- // launch child app
- DWORD threadID;
- HANDLE thread = launchApp(hwnd, testing, &threadID);
- if (thread == NULL) {
- return 0;
- }
+ // handle child program
+ if (testing) {
+ // wait for process to stop, allowing the user to kill it
+ waitForChild(hwnd, thread, threadID);
- // 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);
+ }
- // clean up
- CloseHandle(thread);
- }
- else {
- // don't need thread handle
- CloseHandle(thread);
+ // notify of success
+ askOkay(hwnd, getString(IDS_STARTED_TITLE),
+ getString(IDS_STARTED));
- // notify of success
- askOkay(hwnd, getString(IDS_STARTED_TITLE),
- getString(IDS_STARTED));
-
- // quit
- PostQuitMessage(0);
+ // quit
+ PostQuitMessage(0);
+ }
}
return 0;
}
case IDC_MAIN_AUTOSTART: {
- // construct command line
- CString cmdLine = getCommandLine(hwnd, false);
- if (!cmdLine.empty()) {
+ CString cmdLine;
+ if (saveMainWindow(hwnd, SAVE_NORMAL, &cmdLine)) {
// run dialog
- CAutoStart autoStart(hwnd,
- isClientChecked(hwnd) ? NULL : &ARG->m_config,
- cmdLine);
+ CAutoStart autoStart(hwnd, !isClientChecked(hwnd), cmdLine);
autoStart.doModal();
- if (autoStart.wasUserConfigSaved()) {
- ARG->m_oldConfig = ARG->m_config;
- enableSaveControls(hwnd);
- }
}
return 0;
}
- case IDC_MAIN_SAVE:
- if (!saveConfig(ARG->m_config, false)) {
- showError(hwnd, CStringUtil::format(
- getString(IDS_SAVE_FAILED).c_str(),
- getErrorString(GetLastError()).c_str()));
- }
- else {
- ARG->m_oldConfig = ARG->m_config;
- enableSaveControls(hwnd);
- }
- return 0;
-
case IDC_MAIN_CLIENT_RADIO:
case IDC_MAIN_SERVER_RADIO:
enableMainWindowControls(hwnd);
return 0;
- case IDC_MAIN_SERVER_ADD_BUTTON:
- addScreen(hwnd);
- return 0;
-
- case IDC_MAIN_SERVER_EDIT_BUTTON:
- editScreen(hwnd);
- return 0;
-
- case IDC_MAIN_SERVER_REMOVE_BUTTON:
- removeScreen(hwnd);
- return 0;
-
- case IDC_MAIN_SERVER_SCREENS_LIST:
- if (HIWORD(wParam) == LBN_SELCHANGE) {
- enableScreensControls(hwnd);
- updateNeighbors(hwnd);
- }
- else if (HIWORD(wParam) == LBN_DBLCLK) {
- editScreen(hwnd);
- return 0;
- }
- break;
-
- case IDC_MAIN_SERVER_LEFT_COMBO:
- if (HIWORD(wParam) == CBN_SELENDOK) {
- changeNeighbor(hwnd, (HWND)lParam, kLeft);
- return 0;
- }
- break;
-
- case IDC_MAIN_SERVER_RIGHT_COMBO:
- if (HIWORD(wParam) == CBN_SELENDOK) {
- changeNeighbor(hwnd, (HWND)lParam, kRight);
- return 0;
- }
- break;
-
- case IDC_MAIN_SERVER_TOP_COMBO:
- if (HIWORD(wParam) == CBN_SELENDOK) {
- changeNeighbor(hwnd, (HWND)lParam, kTop);
- return 0;
- }
- break;
-
- case IDC_MAIN_SERVER_BOTTOM_COMBO:
- if (HIWORD(wParam) == CBN_SELENDOK) {
- changeNeighbor(hwnd, (HWND)lParam, kBottom);
- return 0;
- }
+ case IDC_MAIN_SCREENS:
+ s_screensLinks->doModal();
break;
case IDC_MAIN_OPTIONS:
s_globalOptions->doModal();
- enableSaveControls(hwnd);
break;
case IDC_MAIN_ADVANCED:
s_advancedOptions->doModal(isClientChecked(hwnd));
- enableSaveControls(hwnd);
+ break;
+
+ case IDC_MAIN_HOTKEYS:
+ s_hotkeyOptions->doModal();
+ break;
+
+ case IDC_MAIN_INFO:
+ s_info->doModal();
break;
}
@@ -1154,7 +674,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
}
int WINAPI
-WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
+WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmdLine, int nCmdShow)
{
CArch arch(instance);
CLOG;
@@ -1162,6 +682,15 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
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);
@@ -1190,8 +719,11 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
// prep windows
initMainWindow(mainWindow);
- s_globalOptions = new CGlobalOptions(mainWindow, &ARG->m_config);
+ 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);
@@ -1219,8 +751,5 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
}
} while (!done);
- // save values to registry
- saveMainWindow(mainWindow);
-
return msg.wParam;
}
diff --git a/cmd/launcher/launcher.dsp b/cmd/launcher/launcher.dsp
index b1ce64d4..f799afc9 100644
--- a/cmd/launcher/launcher.dsp
+++ b/cmd/launcher/launcher.dsp
@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W4 /GX /O2 /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" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\build\launcher.pdb" /FD /c
+# ADD CPP /nologo /MT /W4 /GR /GX /O2 /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" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\build\launcher.pdb" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@@ -71,7 +71,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /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" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\debug\launcher.pdb" /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GR /GX /ZI /Od /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" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\debug\launcher.pdb" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
@@ -95,6 +95,10 @@ LINK32=link.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
+SOURCE=.\CAddScreen.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\CAdvancedOptions.cpp
# End Source File
# Begin Source File
@@ -107,6 +111,18 @@ SOURCE=.\CGlobalOptions.cpp
# End Source File
# Begin Source File
+SOURCE=.\CHotkeyOptions.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CScreensLinks.cpp
+# End Source File
+# Begin Source File
+
SOURCE=.\launcher.cpp
# End Source File
# Begin Source File
@@ -123,6 +139,10 @@ SOURCE=.\LaunchUtil.cpp
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
+SOURCE=.\CAddScreen.h
+# End Source File
+# Begin Source File
+
SOURCE=.\CAdvancedOptions.h
# End Source File
# Begin Source File
@@ -135,6 +155,18 @@ SOURCE=.\CGlobalOptions.h
# End Source File
# Begin Source File
+SOURCE=.\CHotkeyOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CScreensLinks.h
+# End Source File
+# Begin Source File
+
SOURCE=.\LaunchUtil.h
# End Source File
# Begin Source File
diff --git a/cmd/launcher/launcher.rc b/cmd/launcher/launcher.rc
index 53f15770..802f3d3e 100644
--- a/cmd/launcher/launcher.rc
+++ b/cmd/launcher/launcher.rc
@@ -7,10 +7,7 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
-#include "winres.h"
-#if !defined(IDC_STATIC)
-#define IDC_STATIC (-1)
-#endif
+#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -55,55 +52,41 @@ END
// Dialog
//
-IDD_MAIN DIALOG DISCARDABLE 32768, 0, 300, 262
+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 start either the Client or Server and provide the requested information. Then click Test to check your settings or Start to save your settings and start Synergy.",
+ 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,31
- GROUPBOX "",IDC_STATIC,7,67,286,103
- GROUPBOX "Options",IDC_STATIC,7,177,286,56
- CONTROL "&Client",IDC_MAIN_CLIENT_RADIO,"Button",
- BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,29,33,10
- CONTROL "Server",IDC_MAIN_SERVER_RADIO,"Button",
- BS_AUTORADIOBUTTON,11,67,37,10
- LTEXT "Server &Host Name:",IDC_MAIN_CLIENT_SERVER_NAME_LABEL,
- 12,41,61,8
- EDITTEXT IDC_MAIN_CLIENT_SERVER_NAME_EDIT,79,39,106,12,
+ 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:",IDC_MAIN_SERVER_SCREENS_LABEL,12,79,29,8
- LISTBOX IDC_MAIN_SERVER_SCREENS_LIST,12,91,106,36,
- LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
- PUSHBUTTON "&Add",IDC_MAIN_SERVER_ADD_BUTTON,12,132,50,14
- PUSHBUTTON "&Edit",IDC_MAIN_SERVER_EDIT_BUTTON,68,132,50,14
- PUSHBUTTON "&Remove",IDC_MAIN_SERVER_REMOVE_BUTTON,12,150,50,14
- LTEXT "&Layout:",IDC_MAIN_SERVER_LAYOUT_LABEL,138,79,24,8
- LTEXT "Left:",IDC_MAIN_SERVER_LEFT_LABEL,144,93,15,8
- COMBOBOX IDC_MAIN_SERVER_LEFT_COMBO,175,91,111,75,
- CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "Right:",IDC_MAIN_SERVER_RIGHT_LABEL,144,109,20,8
- COMBOBOX IDC_MAIN_SERVER_RIGHT_COMBO,175,107,112,75,
- CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "Above:",IDC_MAIN_SERVER_TOP_LABEL,144,125,24,8
- COMBOBOX IDC_MAIN_SERVER_TOP_COMBO,175,123,112,75,
- CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "Below:",IDC_MAIN_SERVER_BOTTOM_LABEL,144,141,22,8
- COMBOBOX IDC_MAIN_SERVER_BOTTOM_COMBO,175,139,112,75,
- CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- PUSHBUTTON "&Options...",IDC_MAIN_OPTIONS,12,191,50,14
- PUSHBUTTON "Adva&nced...",IDC_MAIN_ADVANCED,68,191,50,14
- LTEXT "Automatic Startup:",IDC_STATIC,138,193,59,8
- PUSHBUTTON "Con&figure...",IDC_MAIN_AUTOSTART,202,191,50,14
- LTEXT "Lo&gging Level:",IDC_STATIC,12,216,48,8
- COMBOBOX IDC_MAIN_DEBUG,68,213,61,60,CBS_DROPDOWNLIST |
+ 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 "Sa&ve",IDC_MAIN_SAVE,75,241,50,14
- DEFPUSHBUTTON "&Test",IDC_MAIN_TEST,131,241,50,14
- PUSHBUTTON "Start",IDOK,187,241,50,14
- PUSHBUTTON "Quit",IDCANCEL,243,241,50,14
+ 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
@@ -114,33 +97,46 @@ 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,40,ES_MULTILINE |
+ EDITTEXT IDC_ADD_ALIASES_EDIT,79,26,106,24,ES_MULTILINE |
ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
- GROUPBOX "Options",IDC_STATIC,7,72,178,80
+ 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,82,165,25
- CONTROL "Half-duplex &Caps Lock",IDC_ADD_HD_CAPS_CHECK,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,13,110,165,10
- CONTROL "Half-duplex &Num Lock",IDC_ADD_HD_NUM_CHECK,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,13,122,165,10
- CONTROL "Half-duplex Sc&roll Lock",IDC_ADD_HD_SCROLL_CHECK,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,134,165,10
- GROUPBOX "Modifiers",IDC_STATIC,7,155,178,65
- LTEXT "Shift",IDC_STATIC,13,171,15,8
- COMBOBOX IDC_ADD_MOD_SHIFT,37,168,48,60,CBS_DROPDOWNLIST |
+ 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,186,11,8
- COMBOBOX IDC_ADD_MOD_CTRL,37,184,48,60,CBS_DROPDOWNLIST |
+ 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,202,9,8
- COMBOBOX IDC_ADD_MOD_ALT,37,200,48,60,CBS_DROPDOWNLIST |
+ 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,170,17,8
- COMBOBOX IDC_ADD_MOD_META,125,168,48,60,CBS_DROPDOWNLIST |
+ 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,186,20,8
- COMBOBOX IDC_ADD_MOD_SUPER,125,184,48,60,CBS_DROPDOWNLIST |
+ 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
@@ -175,7 +171,7 @@ BEGIN
IDC_STATIC,7,43,181,17
END
-IDD_GLOBAL_OPTIONS DIALOG DISCARDABLE 0, 0, 207, 269
+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"
@@ -207,12 +203,15 @@ BEGIN
IDC_STATIC,7,176,193,8
CONTROL "Synchronize screen savers",IDC_GLOBAL_SCREENSAVER_SYNC,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,192,101,10
- LTEXT "Experimental: Relative mouse moves on secondary screens.",
- IDC_STATIC,7,213,193,8
+ 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
- DEFPUSHBUTTON "OK",IDOK,94,248,50,14
- PUSHBUTTON "Cancel",IDCANCEL,150,248,50,14
+ 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
@@ -238,6 +237,158 @@ BEGIN
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, 202
+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
+ 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
+ LTEXT "Action takes place &when:",IDC_STATIC,7,137,81,8
+ CONTROL "Hot key is pressed",IDC_HOTKEY_ACTION_ON_ACTIVATE,
+ "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,149,74,10
+ CONTROL "Hot key is released",IDC_HOTKEY_ACTION_ON_DEACTIVATE,
+ "Button",BS_AUTORADIOBUTTON,7,161,76,10
+ DEFPUSHBUTTON "OK",IDOK,70,181,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,126,181,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
+
/////////////////////////////////////////////////////////////////////////////
//
@@ -252,7 +403,7 @@ BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 293
TOPMARGIN, 7
- BOTTOMMARGIN, 255
+ BOTTOMMARGIN, 192
END
IDD_ADD, DIALOG
@@ -284,7 +435,7 @@ BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 200
TOPMARGIN, 7
- BOTTOMMARGIN, 262
+ BOTTOMMARGIN, 283
END
IDD_ADVANCED_OPTIONS, DIALOG
@@ -294,6 +445,54 @@ BEGIN
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
@@ -358,13 +557,37 @@ BEGIN
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 computer name of the synergy server, not\nthe name of this computer, in the Server Host Name field."
+ IDS_SERVER_IS_CLIENT "Please enter the 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_LOCK_MODE_OFF "off"
+ IDS_LOCK_MODE_ON "on"
+ IDS_LOCK_MODE_TOGGLE "toggle"
+ IDS_ALL_SCREENS "All Screens"
+ IDS_ACTIVE_SCREEN "Active Screen"
END
#endif // English (U.S.) resources
diff --git a/cmd/launcher/resource.h b/cmd/launcher/resource.h
index caa48052..e4e7b487 100644
--- a/cmd/launcher/resource.h
+++ b/cmd/launcher/resource.h
@@ -44,6 +44,26 @@
#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_LOCK_MODE_OFF 57
+#define IDS_LOCK_MODE_ON 58
+#define IDS_LOCK_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
@@ -51,45 +71,36 @@
#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_EDIT 1002
-#define IDC_MAIN_ADVANCED_NAME_EDIT 1006
-#define IDC_MAIN_ADVANCED_PORT_EDIT 1008
+#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_CLIENT_SERVER_NAME_LABEL 1011
-#define IDC_MAIN_SERVER_SCREENS_LIST 1012
-#define IDC_MAIN_SERVER_SCREENS_LABEL 1013
-#define IDC_MAIN_SERVER_LAYOUT_LABEL 1014
-#define IDC_MAIN_SERVER_ADD_BUTTON 1018
-#define IDC_MAIN_SERVER_EDIT_BUTTON 1019
+#define IDC_MAIN_HOTKEYS 1010
+#define IDC_MAIN_DEBUG 1011
#define IDC_ADD_SCREEN_NAME_EDIT 1020
-#define IDC_MAIN_SERVER_REMOVE_BUTTON 1020
#define IDC_ADD_ALIASES_EDIT 1021
-#define IDC_MAIN_SERVER_OPTIONS_BUTTON 1021
-#define IDC_MAIN_SERVER_LEFT_COMBO 1022
-#define IDC_MAIN_SERVER_RIGHT_COMBO 1023
-#define IDC_MAIN_SERVER_TOP_COMBO 1024
-#define IDC_MAIN_SERVER_BOTTOM_COMBO 1025
-#define IDC_MAIN_SERVER_LEFT_LABEL 1026
-#define IDC_MAIN_SERVER_RIGHT_LABEL 1027
-#define IDC_MAIN_SERVER_TOP_LABEL 1028
-#define IDC_MAIN_SERVER_BOTTOM_LABEL 1029
-#define IDC_MAIN_UNINSTALL 1030
#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_MAIN_AUTOSTART 1035
-#define IDC_MAIN_OPTIONS 1036
#define IDC_ADD_HD_CAPS_CHECK 1037
-#define IDC_MAIN_ADVANCED 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_MAIN_DEBUG 1040
#define IDC_ADVANCED_INTERFACE_EDIT 1040
#define IDC_GLOBAL_DELAY_CHECK 1041
#define IDC_GLOBAL_DELAY_TIME 1042
@@ -105,15 +116,68 @@
#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
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
-#define _APS_NEXT_RESOURCE_VALUE 110
+#define _APS_NEXT_RESOURCE_VALUE 116
#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1052
+#define _APS_NEXT_CONTROL_VALUE 1098
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
diff --git a/cmd/launcher/synergy.ico b/cmd/launcher/synergy.ico
index 39e0ff8d..89f965f4 100644
Binary files a/cmd/launcher/synergy.ico and b/cmd/launcher/synergy.ico differ
diff --git a/cmd/synergyc/CClientTaskBarReceiver.cpp b/cmd/synergyc/CClientTaskBarReceiver.cpp
index ddd8ec5a..025b43f6 100644
--- a/cmd/synergyc/CClientTaskBarReceiver.cpp
+++ b/cmd/synergyc/CClientTaskBarReceiver.cpp
@@ -15,8 +15,10 @@
#include "CClientTaskBarReceiver.h"
#include "CClient.h"
#include "CLock.h"
+#include "CStringUtil.h"
#include "IEventQueue.h"
#include "CArch.h"
+#include "Version.h"
//
// CClientTaskBarReceiver
@@ -48,6 +50,8 @@ CClientTaskBarReceiver::updateStatus(CClient* client, const CString& errorMsg)
}
}
else {
+ m_server = client->getServerAddress().getHostname();
+
if (client->isConnected()) {
m_state = kConnected;
}
@@ -108,19 +112,23 @@ CClientTaskBarReceiver::getToolTip() const
{
switch (m_state) {
case kNotRunning:
- return "Synergy: Not running";
+ return CStringUtil::print("%s: Not running", kAppVersion);
case kNotWorking:
- return CString("Synergy: ") + m_errorMessage;
+ return CStringUtil::print("%s: %s",
+ kAppVersion, m_errorMessage.c_str());
case kNotConnected:
- return CString("Synergy: Not connected: ") + m_errorMessage;
+ return CStringUtil::print("%s: Not connected: %s",
+ kAppVersion, m_errorMessage.c_str());
case kConnecting:
- return "Synergy: Connecting...";
+ return CStringUtil::print("%s: Connecting to %s...",
+ kAppVersion, m_server.c_str());
case kConnected:
- return "Synergy: Connected";
+ 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
index a9fe50c2..0e3440e1 100644
--- a/cmd/synergyc/CClientTaskBarReceiver.h
+++ b/cmd/synergyc/CClientTaskBarReceiver.h
@@ -77,6 +77,7 @@ protected:
private:
EState m_state;
CString m_errorMessage;
+ CString m_server;
};
#endif
diff --git a/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp b/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
index c53ea1c8..5c31f4a5 100644
--- a/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
+++ b/cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
@@ -139,6 +139,9 @@ CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
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 |
@@ -157,6 +160,38 @@ CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
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;
diff --git a/cmd/synergyc/Makefile.am b/cmd/synergyc/Makefile.am
index 783472c2..89942666 100644
--- a/cmd/synergyc/Makefile.am
+++ b/cmd/synergyc/Makefile.am
@@ -67,6 +67,12 @@ 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 \
diff --git a/cmd/synergyc/resource.h b/cmd/synergyc/resource.h
index 1a5455a1..eeee6e1e 100644
--- a/cmd/synergyc/resource.h
+++ b/cmd/synergyc/resource.h
@@ -16,13 +16,21 @@
#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 40004
+#define _APS_NEXT_COMMAND_VALUE 40016
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
diff --git a/cmd/synergyc/synergyc.cpp b/cmd/synergyc/synergyc.cpp
index 2b548be8..eabddb49 100644
--- a/cmd/synergyc/synergyc.cpp
+++ b/cmd/synergyc/synergyc.cpp
@@ -60,10 +60,6 @@
typedef int (*StartupFunc)(int, char**);
static bool startClient();
static void parse(int argc, const char* const* argv);
-#if WINAPI_MSWINDOWS
-static void handleSystemSuspend(void*);
-static void handleSystemResume(void*);
-#endif
//
// program arguments
@@ -108,9 +104,7 @@ CScreen*
createScreen()
{
#if WINAPI_MSWINDOWS
- return new CScreen(new CMSWindowsScreen(false,
- new CFunctionJob(&handleSystemSuspend),
- new CFunctionJob(&handleSystemResume)));
+ return new CScreen(new CMSWindowsScreen(false));
#elif WINAPI_XWINDOWS
return new CScreen(new CXWindowsScreen(ARG->m_display, false));
#elif WINAPI_CARBON
@@ -199,26 +193,6 @@ handleScreenError(const CEvent&, void*)
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}
-#if WINAPI_MSWINDOWS
-static
-void
-handleSystemSuspend(void*)
-{
- LOG((CLOG_NOTE "system suspending"));
- s_suspened = true;
- s_client->disconnect(NULL);
-}
-
-static
-void
-handleSystemResume(void*)
-{
- LOG((CLOG_NOTE "system resuming"));
- s_suspened = false;
- startClient();
-}
-#endif
-
static
CScreen*
openClientScreen()
@@ -252,9 +226,7 @@ handleClientRestart(const CEvent&, void* vtimer)
EVENTQUEUE->removeHandler(CEvent::kTimer, timer);
// reconnect
- if (!s_suspened) {
- startClient();
- }
+ startClient();
}
static
@@ -287,6 +259,7 @@ handleClientFailed(const CEvent& e, void*)
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));
@@ -441,7 +414,11 @@ static
int
daemonMainLoop(int, const char**)
{
- CSystemLogger sysLogger(DAEMON_NAME);
+#if SYSAPI_WIN32
+ CSystemLogger sysLogger(DAEMON_NAME, false);
+#else
+ CSystemLogger sysLogger(DAEMON_NAME, true);
+#endif
return mainLoop();
}
@@ -449,6 +426,10 @@ static
int
standardStartup(int argc, char** argv)
{
+ if (!ARG->m_daemon) {
+ ARCH->showConsole(false);
+ }
+
// parse command line
parse(argc, argv);
@@ -758,6 +739,7 @@ public:
// 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 ""; }
};
@@ -802,11 +784,24 @@ static
int
daemonNTStartup(int, char**)
{
- CSystemLogger sysLogger(DAEMON_NAME);
+ 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)
@@ -820,12 +815,23 @@ 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
@@ -833,8 +839,13 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
StartupFunc startup = &standardStartup;
- if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
- startup = &daemonNTStartup;
+ if (!CArchMiscWindows::isWindows95Family()) {
+ if (__argc <= 1) {
+ startup = &daemonNTStartup;
+ }
+ else {
+ startup = &foregroundStartup;
+ }
}
// send PRINT and FATAL output to a message box
diff --git a/cmd/synergyc/synergyc.dsp b/cmd/synergyc/synergyc.dsp
index ff793b14..4238ea03 100644
--- a/cmd/synergyc/synergyc.dsp
+++ b/cmd/synergyc/synergyc.dsp
@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c /Fd..\..\gen\build\synergyc.pdb
+# ADD CPP /nologo /MT /W4 /GR /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\build\synergyc.pdb" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@@ -70,7 +70,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c /Fd..\..\gen\debug\synergyc.pdb
+# ADD CPP /nologo /MTd /W4 /Gm /GR /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\io" /I "..\..\lib\mt" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\client" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\debug\synergyc.pdb" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
diff --git a/cmd/synergyc/synergyc.ico b/cmd/synergyc/synergyc.ico
index 23d9a090..89f965f4 100644
Binary files a/cmd/synergyc/synergyc.ico and b/cmd/synergyc/synergyc.ico differ
diff --git a/cmd/synergyc/synergyc.rc b/cmd/synergyc/synergyc.rc
index e168a3b3..519e8e48 100644
--- a/cmd/synergyc/synergyc.rc
+++ b/cmd/synergyc/synergyc.rc
@@ -87,7 +87,25 @@ 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
diff --git a/cmd/synergyc/tb_error.ico b/cmd/synergyc/tb_error.ico
index a304dc18..746a87c9 100644
Binary files a/cmd/synergyc/tb_error.ico and b/cmd/synergyc/tb_error.ico differ
diff --git a/cmd/synergyc/tb_idle.ico b/cmd/synergyc/tb_idle.ico
index 9ba599de..4e13a264 100644
Binary files a/cmd/synergyc/tb_idle.ico and b/cmd/synergyc/tb_idle.ico differ
diff --git a/cmd/synergyc/tb_run.ico b/cmd/synergyc/tb_run.ico
index 86aa9f3a..88e160cb 100644
Binary files a/cmd/synergyc/tb_run.ico and b/cmd/synergyc/tb_run.ico differ
diff --git a/cmd/synergyc/tb_wait.ico b/cmd/synergyc/tb_wait.ico
index 3e2edd5f..257be0a1 100644
Binary files a/cmd/synergyc/tb_wait.ico and b/cmd/synergyc/tb_wait.ico differ
diff --git a/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp b/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
index a1011fda..21a61954 100644
--- a/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
+++ b/cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
@@ -157,6 +157,9 @@ CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
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 |
@@ -175,6 +178,10 @@ CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
copyLog();
break;
+ case IDC_TASKBAR_SHOW_LOG:
+ ARCH->showConsole(true);
+ break;
+
case IDC_RELOAD_CONFIG:
EVENTQUEUE->addEvent(CEvent(getReloadConfigEvent(),
IEventQueue::getSystemTarget()));
@@ -185,6 +192,34 @@ CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
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;
diff --git a/cmd/synergys/CServerTaskBarReceiver.cpp b/cmd/synergys/CServerTaskBarReceiver.cpp
index ee04d79e..6555b214 100644
--- a/cmd/synergys/CServerTaskBarReceiver.cpp
+++ b/cmd/synergys/CServerTaskBarReceiver.cpp
@@ -15,8 +15,10 @@
#include "CServerTaskBarReceiver.h"
#include "CServer.h"
#include "CLock.h"
+#include "CStringUtil.h"
#include "IEventQueue.h"
#include "CArch.h"
+#include "Version.h"
//
// CServerTaskBarReceiver
@@ -113,16 +115,17 @@ CServerTaskBarReceiver::getToolTip() const
{
switch (m_state) {
case kNotRunning:
- return "Synergy: Not running";
+ return CStringUtil::print("%s: Not running", kAppVersion);
case kNotWorking:
- return std::string("Synergy: ") + m_errorMessage;
-
+ return CStringUtil::print("%s: %s",
+ kAppVersion, m_errorMessage.c_str());
+
case kNotConnected:
- return "Synergy: Waiting for clients";
+ return CStringUtil::print("%s: Waiting for clients", kAppVersion);
case kConnected:
- return "Synergy: Connected";
+ return CStringUtil::print("%s: Connected", kAppVersion);
default:
return "";
diff --git a/cmd/synergys/Makefile.am b/cmd/synergys/Makefile.am
index c45e6b4f..3e02739d 100644
--- a/cmd/synergys/Makefile.am
+++ b/cmd/synergys/Makefile.am
@@ -67,6 +67,12 @@ 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 \
diff --git a/cmd/synergys/resource.h b/cmd/synergys/resource.h
index f3127816..0ad5868a 100644
--- a/cmd/synergys/resource.h
+++ b/cmd/synergys/resource.h
@@ -19,13 +19,21 @@
#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 40008
+#define _APS_NEXT_COMMAND_VALUE 40016
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
diff --git a/cmd/synergys/synergys.cpp b/cmd/synergys/synergys.cpp
index a8530dec..6821a4e2 100644
--- a/cmd/synergys/synergys.cpp
+++ b/cmd/synergys/synergys.cpp
@@ -121,7 +121,7 @@ CScreen*
createScreen()
{
#if WINAPI_MSWINDOWS
- return new CScreen(new CMSWindowsScreen(true, NULL, NULL));
+ return new CScreen(new CMSWindowsScreen(true));
#elif WINAPI_XWINDOWS
return new CScreen(new CXWindowsScreen(ARG->m_display, true));
#elif WINAPI_CARBON
@@ -148,6 +148,16 @@ createTaskBarReceiver(const CBufferedLogOutputter* logBuffer)
// 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;
@@ -155,6 +165,8 @@ 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()
@@ -224,6 +236,10 @@ handleScreenError(const CEvent&, void*)
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}
+
+static void handleSuspend(const CEvent& event, void*);
+static void handleResume(const CEvent& event, void*);
+
static
CScreen*
openServerScreen()
@@ -233,6 +249,14 @@ openServerScreen()
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;
}
@@ -243,6 +267,10 @@ 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;
}
}
@@ -319,80 +347,180 @@ closeServer(CServer* server)
delete server;
}
+static bool initServer();
static bool startServer();
static
void
-retryStartHandler(const CEvent&, void* vtimer)
+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
- CEventQueueTimer* timer = reinterpret_cast(vtimer);
- EVENTQUEUE->deleteTimer(timer);
- EVENTQUEUE->removeHandler(CEvent::kTimer, NULL);
+ assert(s_timer != NULL);
+ stopRetryTimer();
- // try starting the server again
- LOG((CLOG_DEBUG1 "retry starting server"));
- startServer();
+ // 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
-startServer()
+initServer()
{
+ // skip if already initialized or initializing
+ if (s_serverState != kUninitialized) {
+ return true;
+ }
+
double retryTime;
CScreen* serverScreen = NULL;
CPrimaryClient* primaryClient = NULL;
- CClientListener* listener = NULL;
try {
CString name = ARG->m_config->getCanonicalName(ARG->m_name);
serverScreen = openServerScreen();
primaryClient = openPrimaryClient(name, serverScreen);
- listener = openClientListener(ARG->m_config->getSynergyAddress());
- s_server = openServer(*ARG->m_config, primaryClient);
s_serverScreen = serverScreen;
s_primaryClient = primaryClient;
- s_listener = listener;
+ s_serverState = kInitialized;
updateStatus();
- LOG((CLOG_NOTE "started server"));
return true;
}
catch (XScreenUnavailable& e) {
LOG((CLOG_WARN "cannot open primary screen: %s", e.what()));
- closeClientListener(listener);
closePrimaryClient(primaryClient);
closeServerScreen(serverScreen);
updateStatus(CString("cannot open primary screen: ") + e.what());
retryTime = e.getRetryTime();
}
- catch (XSocketAddressInUse& e) {
- LOG((CLOG_WARN "cannot listen for clients: %s", e.what()));
- closeClientListener(listener);
- closePrimaryClient(primaryClient);
- closeServerScreen(serverScreen);
- updateStatus(CString("cannot listen for clients: ") + e.what());
- retryTime = 10.0;
- }
catch (XScreenOpenFailure& e) {
LOG((CLOG_CRIT "cannot open primary screen: %s", e.what()));
- closeClientListener(listener);
closePrimaryClient(primaryClient);
closeServerScreen(serverScreen);
return false;
}
catch (XBase& e) {
LOG((CLOG_CRIT "failed to start server: %s", e.what()));
- closeClientListener(listener);
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));
- CEventQueueTimer* timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
- EVENTQUEUE->adoptHandler(CEvent::kTimer, timer,
- new CFunctionEventJob(&retryStartHandler, timer));
+ s_timer = EVENTQUEUE->newOneShotTimer(retryTime, NULL);
+ EVENTQUEUE->adoptHandler(CEvent::kTimer, s_timer,
+ new CFunctionEventJob(&retryHandler, NULL));
+ s_serverState = kStarting;
return true;
}
else {
@@ -405,14 +533,63 @@ static
void
stopServer()
{
- closeClientListener(s_listener);
- closeServer(s_server);
- closePrimaryClient(s_primaryClient);
- closeServerScreen(s_serverScreen);
- s_server = NULL;
- s_listener = NULL;
- s_primaryClient = NULL;
- s_serverScreen = NULL;
+ 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
@@ -517,7 +694,7 @@ mainLoop()
IEventQueue::getSystemTarget());
EVENTQUEUE->removeHandler(getReloadConfigEvent(),
IEventQueue::getSystemTarget());
- stopServer();
+ cleanupServer();
updateStatus();
LOG((CLOG_NOTE "stopped server"));
@@ -528,7 +705,11 @@ static
int
daemonMainLoop(int, const char**)
{
- CSystemLogger sysLogger(DAEMON_NAME);
+#if SYSAPI_WIN32
+ CSystemLogger sysLogger(DAEMON_NAME, false);
+#else
+ CSystemLogger sysLogger(DAEMON_NAME, true);
+#endif
return mainLoop();
}
@@ -536,6 +717,10 @@ static
int
standardStartup(int argc, char** argv)
{
+ if (!ARG->m_daemon) {
+ ARCH->showConsole(false);
+ }
+
// parse command line
parse(argc, argv);
@@ -952,6 +1137,7 @@ public:
// 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 ""; }
};
@@ -997,11 +1183,27 @@ static
int
daemonNTStartup(int, char**)
{
- CSystemLogger sysLogger(DAEMON_NAME);
+ 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)
@@ -1015,12 +1217,23 @@ 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
@@ -1028,8 +1241,13 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
// users on NT can use `--daemon' or `--no-daemon' to force us out
// of the service code path.
StartupFunc startup = &standardStartup;
- if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
- startup = &daemonNTStartup;
+ if (!CArchMiscWindows::isWindows95Family()) {
+ if (__argc <= 1) {
+ startup = &daemonNTStartup;
+ }
+ else {
+ startup = &foregroundStartup;
+ }
}
// send PRINT and FATAL output to a message box
diff --git a/cmd/synergys/synergys.dsp b/cmd/synergys/synergys.dsp
index 7fdf1f01..a8d791de 100644
--- a/cmd/synergys/synergys.dsp
+++ b/cmd/synergys/synergys.dsp
@@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W4 /GX /O2 /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" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\build\synergys.pdb" /FD /c
+# ADD CPP /nologo /MT /W4 /GR /GX /O2 /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" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\build\synergys.pdb" /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
@@ -70,7 +70,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /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" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\debug\synergys.pdb" /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GR /GX /ZI /Od /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" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fd"..\..\gen\debug\synergys.pdb" /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
diff --git a/cmd/synergys/synergys.ico b/cmd/synergys/synergys.ico
index 23d9a090..89f965f4 100644
Binary files a/cmd/synergys/synergys.ico and b/cmd/synergys/synergys.ico differ
diff --git a/cmd/synergys/synergys.rc b/cmd/synergys/synergys.rc
index c8f7da21..117b1852 100644
--- a/cmd/synergys/synergys.rc
+++ b/cmd/synergys/synergys.rc
@@ -73,7 +73,25 @@ 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
diff --git a/cmd/synergys/tb_error.ico b/cmd/synergys/tb_error.ico
index a304dc18..746a87c9 100644
Binary files a/cmd/synergys/tb_error.ico and b/cmd/synergys/tb_error.ico differ
diff --git a/cmd/synergys/tb_idle.ico b/cmd/synergys/tb_idle.ico
index 9ba599de..4e13a264 100644
Binary files a/cmd/synergys/tb_idle.ico and b/cmd/synergys/tb_idle.ico differ
diff --git a/cmd/synergys/tb_run.ico b/cmd/synergys/tb_run.ico
index 86aa9f3a..88e160cb 100644
Binary files a/cmd/synergys/tb_run.ico and b/cmd/synergys/tb_run.ico differ
diff --git a/cmd/synergys/tb_wait.ico b/cmd/synergys/tb_wait.ico
index e94db3c3..257be0a1 100644
Binary files a/cmd/synergys/tb_wait.ico and b/cmd/synergys/tb_wait.ico differ
diff --git a/configure.in b/configure.in
index 41727153..b33bf5f1 100644
--- a/configure.in
+++ b/configure.in
@@ -53,10 +53,19 @@ 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
@@ -88,7 +97,7 @@ ACX_CHECK_INET_ATON
dnl checks for header files
AC_HEADER_STDC
-AC_CHECK_HEADERS([unistd.h sys/time.h sys/types.h wchar.h alloca.h])
+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])
@@ -109,6 +118,33 @@ if test x"$acx_host_winapi" = xXWINDOWS; then
,
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,
@@ -149,7 +185,7 @@ if test x"$acx_host_winapi" = xXWINDOWS; then
AC_MSG_CHECKING(for prototypes in X11/extensions/dpms.h)
acx_have_dpms_protos=no
AC_TRY_COMPILE([
- #include
+ #include
extern "C" {
#include
}
@@ -207,8 +243,25 @@ 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
diff --git a/dist/nullsoft/synergy.nsi b/dist/nullsoft/synergy.nsi
index e7d61938..bbc26cfc 100644
--- a/dist/nullsoft/synergy.nsi
+++ b/dist/nullsoft/synergy.nsi
@@ -62,20 +62,31 @@ Section "Synergy (required)"
File COPYING.txt
File ChangeLog.txt
File ${DEPTH}\doc\PORTING
+ File ${DEPTH}\doc\about.html
File ${DEPTH}\doc\authors.html
File ${DEPTH}\doc\autostart.html
+ File ${DEPTH}\doc\banner.html
File ${DEPTH}\doc\compiling.html
File ${DEPTH}\doc\configuration.html
+ File ${DEPTH}\doc\contact.html
File ${DEPTH}\doc\developer.html
File ${DEPTH}\doc\faq.html
File ${DEPTH}\doc\history.html
+ File ${DEPTH}\doc\home.html
File ${DEPTH}\doc\index.html
File ${DEPTH}\doc\license.html
File ${DEPTH}\doc\news.html
+ File ${DEPTH}\doc\roadmap.html
File ${DEPTH}\doc\running.html
File ${DEPTH}\doc\security.html
+ File ${DEPTH}\doc\synergy.css
File ${DEPTH}\doc\tips.html
- File ${DEPTH}\doc\todo.html
+ File ${DEPTH}\doc\toc.html
+ File ${DEPTH}\doc\trouble.html
+
+ SetOutPath $INSTDIR\images
+ File ${DEPTH}\doc\images\logo.gif
+ File ${DEPTH}\doc\images\warp.gif
; Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\Synergy "Install_Dir" "$INSTDIR"
@@ -95,18 +106,26 @@ 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\FAQ.lnk" "$INSTDIR\faq.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"
@@ -136,6 +155,7 @@ Section "Uninstall"
; Remove shortcuts, if any
Delete "$SMPROGRAMS\Synergy\*.*"
+ Delete "$DESKTOP\Synergy.lnk"
; Remove directories used
RMDir "$SMPROGRAMS\Synergy"
diff --git a/dist/rpm/synergy.spec.in b/dist/rpm/synergy.spec.in
index a4b368ba..0d2b6f48 100644
--- a/dist/rpm/synergy.spec.in
+++ b/dist/rpm/synergy.spec.in
@@ -3,7 +3,7 @@ Name: @PACKAGE@
Version: @VERSION@
Release: 1
License: GPL
-Packager: Chris Schoeneman
+Packager: Chris Schoeneman
Group: System Environment/Daemons
Prefixes: /usr/bin
Source: @PACKAGE@-@VERSION@.tar.gz
@@ -41,19 +41,26 @@ rm -rf $RPM_BUILD_ROOT
%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/todo.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
index 45494563..2efec24c 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -17,20 +17,29 @@ 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 \
- todo.html \
+ toc.html \
+ trouble.html \
+ images/logo.gif \
+ images/warp.gif \
$(NULL)
MAINTAINERCLEANFILES = \
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
-
+
+
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
@@ -46,10 +46,9 @@ 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
-
+
+
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
@@ -57,34 +56,33 @@ 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. Typical file names
-are:
-
-
+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
gdm
-
1
xdm/Xsetup
gdm/Init/Default (*)
-
2
xdm/Xstartup
gdm/PostLogin/Default (*)
-
3
xdm/Xsession
gdm/Sessions/Default (*, **)
+
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)
@@ -95,8 +93,7 @@ in that order, before and instead of Default.
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
@@ -105,15 +102,13 @@ For a synergy client, add the following to the first file:
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
@@ -124,8 +119,7 @@ Note that <options>-f or --no-daemon or
the script will never exit and you won't be able to log in.
-
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
-
+
+
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:
@@ -180,14 +168,12 @@ There are three different ways to automatically start Synergy
-
-
+
The second method will launch Synergy from the
LoginWindow application, once a particular
user has logged in.
-
-
+
Pros:
@@ -202,13 +188,11 @@ There are three different ways to automatically start Synergy
-
-
+
The third method is to launch a startup script from the
"Startup Items" tab under System Preferences -> Accounts.
-
-
+
Pros:
@@ -222,17 +206,14 @@ There are three different ways to automatically start Synergy
-
-
+
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:
@@ -250,8 +231,7 @@ logged in. A Mac OS X Synergy server setup will be quite similar.
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
@@ -312,39 +290,32 @@ RunService "$1"
In the same folder, create a file named
StartupParameters.plist containing:
-
-
That's it! If you want to test this setup, you can run the
-startup script as follow:
-
-
+startup script as follows:
+
# /Library/StartupItems/Synergy/Synergy start
-
-
+
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
@@ -352,57 +323,48 @@ cookie and stores it in the environment variable
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 /Library/Preferences/com.apple.loginwindow LoginHook
+ # 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 (/Library/Preferences/com.apple.loginwindow, LoginHook) does not exist
+ 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:
@@ -410,16 +372,13 @@ one.
# mkdir -p /Library/LoginWindow
-
-
In this folder, create a new script file (let's name it
LoginHook.sh), containing the following text:
-
-
+ Make this script executable:
+
+ # chmod 755 /Library/LoginWindow/LoginHook.sh
+
+
Create a login hook to call the script you just created:
- # defaults write /Library/Preferences/com.apple.loginwindow \
- LoginHook /Library/LoginWindow/LoginHook.sh
+ # defaults write com.apple.loginwindow LoginHook /Library/LoginWindow/LoginHook.sh
- You can instead type the above all on one line but remove the backslash.
-
-
+
+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
@@ -448,21 +411,18 @@ 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
-StartupItems.plist file specifies that this
+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).
+
+
diff --git a/doc/border.html b/doc/border.html
new file mode 100644
index 00000000..ce45847a
--- /dev/null
+++ b/doc/border.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Synergy
+
+
+
+
+
+
diff --git a/doc/compiling.html b/doc/compiling.html
index 49f2c764..3fe5c393 100644
--- a/doc/compiling.html
+++ b/doc/compiling.html
@@ -1,39 +1,40 @@
-
+
-
- Building and Installing Synergy
+
+
+
+
+ Building and Installing Synergy
-
Prerequisites for building
+
Prerequisites for building
+
To build synergy from the sources you'll need the following:
-
Windows
-
-
VC++ 6.0 or up
-
-
+
+
VC++ 6.0 or up
+
+
Unix
-
-
gcc 2.95 or up
-
X11R4 or up headers and libraries
-
-
+
+
gcc 2.95 or up
+
X11R4 or up headers and libraries
+
+
Mac OS X
-
-
XCode; or gcc 2.95 or up
-
Carbon development headers and libraries
-
+
+
XCode; or gcc 2.95 or up
+
Carbon development headers and libraries
+
-
-
-
Configuring the build
-
+
+
Configuring the build
+
This step is not necessary when using VC++ or XCode.
-
-
+
To configure the build for your platform use the configure script:
./configure
@@ -47,80 +48,73 @@ On Solaris you may need to use:
./configure --x-includes=/usr/openwin/include --x-libraries=/usr/openwin/lib
so synergy can find the X11 includes and libraries.
-
-
-
Building
+
+
Building
Windows
-
+
Start VC++ and open synergy.dsw. Set the
active configuration (Build > Set Active Configuration) to
All - Debug or All -
Release then build. Binaries are built into
./debug or ./build.
-
-
+
Unix or Mac OS X without XCode
-
+
Simply enter:
make
This will build the client and server and leave them in their
respective source directories.
-
-
+
Mac OS X with XCode
-
+
Start XCode and open the synergy.xcode
project. Build the all project using
the Deployment flavor.
-
+ You'll need NSIS, the
Nullsoft Scriptable Install System. Build All -
Release then build Installer - Release.
This creates SynergyInstaller.exe in the
build directory. Run this to install synergy.
-
-
+
Alternatively, you can simply copy the following files from the
debug or build
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 without XCode
-
+
make install
will install the client and server into
/usr/local/bin unless you
specified a different directory when you ran configure.
-
-
+
Mac OS X with XCode
-
+
Copy the following files from ./build to a convenient location:
-
+
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: nameargs
end
-
+
Comments are introduced by # and continue to
the end of the line. name must be one of the
following:
@@ -36,8 +39,7 @@ 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
@@ -45,9 +47,9 @@ they've been defined in the screens or
must appear after the screens and links
cannot refer to aliases unless the aliases
appear before the links.
-
-
screens
-
+
+
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
@@ -60,30 +62,28 @@ 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:
+ moe:
+ larry:
halfDuplexCapsLock = true
halfDuplexNumLock = true
- curly:
+ 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
@@ -93,22 +93,32 @@ A screen can have the following options:
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 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. Use it to prevent accidental switching.
-
+ 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
@@ -118,33 +128,31 @@ A screen can have the following options:
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
+ 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
-
+
+
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
@@ -152,102 +160,163 @@ A screen can have the following options:
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
+ larry.stooges.com and can connect as
either name. Screen curly is also
known as shemp (hey, it's just an example).
-
-
-
links
-
+
+
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} =
- name. A link indicates which screen is
- adjacent in the given direction.
-
-
+ 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 = curly
+ right = larry
+ up(50,100) = curly(0,50)
larry:
- left = moe
- up = curly
+ left = moe
+ up(0,50) = curly(50,100)
curly:
- down = larry
+ 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),
- curly is above moe,
+ the left half of
+ curly is above the right half of
+ moe,
moe is to the left of
- larry, curly is
- above larry, and
- larry is below
- curly. Note that links do not have to be
- symmetrical; moving up from moe then down
- from curly lands the cursor on
- larry.
-
-
-
options
-
+ 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
@@ -255,29 +324,337 @@ A screen can have the following options:
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.
-
+
+ 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 Scroll Lock is
- toggled on (i.e. the cursor is locked to the screen).
- This is intended to make synergy work better with certain
- games. If set to false or not
- set then all mouse moves are absolute.
-
+
+ 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.
+
+ 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.
+
+
+
+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
+doc/PORTING
file in the synergy source code for more high-level information.
-
-
-
How it works
-
+
+
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
@@ -34,8 +34,7 @@ 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
@@ -43,15 +42,13 @@ 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
@@ -60,25 +57,25 @@ 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
-
+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
+in the code using doxygen.
+Use make doxygen to build it yourself
from the source code into the doc/doxygen/html
directory.
Why doesn't ctrl+alt+del work on secondary screens?
Synergy isn't able to capture ctrl+alt+del on PC compatible
- systems because it's handled completely differently than
+ 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 running as a service for this to work.)
+ 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?
@@ -60,7 +79,6 @@
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
@@ -70,7 +88,6 @@
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.
@@ -78,33 +95,30 @@
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.
+ 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
+ OpenSSH. For
Windows there's a port of OpenSSH using
- Cygwin.
+ Cygwin.
-
What should I call my screens in the configuration?
You can use any unique name in the configuration file for each
@@ -115,8 +129,7 @@
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
@@ -124,32 +137,29 @@
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 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.
-
-
+ 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, add any or all of these lines as appropriate:
-
+ 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)
@@ -157,13 +167,11 @@
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.
@@ -173,7 +181,6 @@
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
@@ -181,7 +188,6 @@
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
@@ -192,36 +198,33 @@
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.
+ 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
@@ -229,7 +232,6 @@
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
@@ -237,7 +239,6 @@
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
@@ -245,6 +246,21 @@
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.
+
+
+
diff --git a/doc/history.html b/doc/history.html
index dedbb016..48f921c3 100644
--- a/doc/history.html
+++ b/doc/history.html
@@ -1,12 +1,16 @@
-
+
-
- Synergy History
+
+
+
+
+ Synergy History
-
Synergy History
+
Synergy History
+
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
@@ -16,11 +20,11 @@ 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.
+
-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.
-
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),
-non-US English keyboards are untested and probably don't work, and there
-may be problems with mouse pointer and mouse wheel acceleration. Other
-problems should be filed as bugs.
-
Synergy is copyright (C) 2002 Chris Schoeneman.
Synergy is distributed under the GNU GENERAL PUBLIC LICENSE.
-
-
GNU GENERAL PUBLIC 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
-
+
+
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
@@ -29,55 +33,48 @@ 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
-
+
+
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,
@@ -87,16 +84,14 @@ 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
@@ -104,31 +99,26 @@ 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
@@ -139,10 +129,9 @@ above, provided that you also meet all of these conditions:
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
@@ -152,50 +141,43 @@ 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
@@ -206,15 +188,13 @@ 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
@@ -222,8 +202,7 @@ 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
@@ -232,8 +211,7 @@ 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
@@ -241,8 +219,7 @@ 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
@@ -255,14 +232,12 @@ 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
@@ -273,12 +248,10 @@ 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
@@ -286,14 +259,12 @@ 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
@@ -301,8 +272,7 @@ 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
@@ -310,11 +280,9 @@ 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
@@ -325,8 +293,7 @@ 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
@@ -338,9 +305,9 @@ 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
@@ -42,23 +184,19 @@ Made following changes:
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 OS X
+
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
@@ -89,12 +227,10 @@ Made following changes:
Worked around win32 command prompt stealing shift key events
@@ -110,12 +246,10 @@ Made following changes:
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
@@ -125,12 +259,10 @@ Made following changes:
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
@@ -141,21 +273,17 @@ Made following changes:
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
@@ -171,24 +299,20 @@ Made following changes:
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
@@ -199,17 +323,13 @@ Made following changes:
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
@@ -217,20 +337,18 @@ Made following changes:
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
@@ -244,12 +362,11 @@ Made following changes:
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
@@ -268,12 +385,48 @@ Made following changes:
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
@@ -285,14 +438,33 @@ Made following changes:
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:
-
+
-
Support for X11 keymaps with only uppercase letters
+
Added support for X11 keymaps with only uppercase letters
Fixed memory leaks
Added documentation on using synergy with SSH
Fixed unnecessary left-handed mouse button swapping
@@ -300,31 +472,28 @@ Made following changes:
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)
@@ -333,19 +502,16 @@ Made following changes:
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)
@@ -358,12 +524,11 @@ Made following changes:
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)
@@ -376,12 +541,11 @@ Made following changes:
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
@@ -389,51 +553,47 @@ Made following changes:
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 KP_Enter buttons were not working correctly on windows
+
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
-
+
+
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
-
+
+
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.
-
-
-
Step 3 - Configure and start the server
-
+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 Server radio button
-
Click Add to add the server to the
+
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 Add to add your other computers
+
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 dialog
+
Choose desired screen options on the Add Screen dialog
-
Use the controls under Layout to link screens together
+
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 ---
@@ -71,6 +74,7 @@ Configure 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:
@@ -80,16 +84,14 @@ Configure the server:
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.
-
-
-
+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:
@@ -119,34 +121,41 @@ 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
-
+
+
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 Client radio button
-
Enter the server's computer name in Server Host Name
+
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
@@ -158,45 +167,81 @@ Configure the client:
Click OK
-
-
+
Now click Test.
-
-
+
Unix or Mac OS X
-To start a client, enter the following:
+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.
-
-
Step 5 - Test
-
+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. Here are the typical problems and possible
-solutions:
+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;
+ 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; the server cannot open the desired port, stop
- the program using that port (24800) and restart the server.
-
+
+ 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.
@@ -204,33 +249,34 @@ 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
-
+
+
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.
-
-
+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
-
+
+
Command Line Options Guide
+
Common Command Line Options
The following options are supported by synergys
and synergyc.
-
-d,
@@ -242,16 +288,16 @@ and synergyc.
--daemon
run as a daemon (Unix) or background (Windows)
-
-
-
--display display
-
connect to X server at display (X11 only)
-
-f,
--no-daemon
run in the foreground
+
+
+
--display display
+
connect to X server at display (X11 only)
+
-n,
--name name
@@ -276,10 +322,9 @@ and synergyc.
--version
print version information and exit
-
+
-
-
+
Debug levels are from highest to lowest: FATAL,
ERROR, WARNING,
NOTE, INFO,
@@ -291,28 +336,24 @@ 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).
-
@@ -325,8 +366,7 @@ The server accepts the common options and:
read configuration from pathname
-
-
+
address has one of the following forms:
hostname
@@ -338,10 +378,9 @@ 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]
@@ -351,4 +390,5 @@ port on the server to connect to. The client accepts the
common options.
+
diff --git a/doc/security.html b/doc/security.html
index db8ad3f5..c8013c27 100644
--- a/doc/security.html
+++ b/doc/security.html
@@ -1,39 +1,37 @@
-
+
-
- Synergy Security Guide
+
+
+
+
+ Synergy Network Security Guide
-
Authentication and Encryption
+
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
+of SSH is called OpenSSH and runs
on Linux, many Unixes, and Windows (in combination with
-Cygwin).
-
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
-
+
+
Configuring the Clients
Install the OpenSSH client on each synergy client computer. Then, on
each client, start the OpenSSH client using port forwarding:
@@ -53,4 +51,5 @@ Synergy will then run normally except all communication is passed
through OpenSSH which decrypts/encrypts it on behalf of synergy.
+
diff --git a/doc/synergy.css b/doc/synergy.css
index 9085c706..8d831aa0 100644
--- a/doc/synergy.css
+++ b/doc/synergy.css
@@ -53,8 +53,9 @@ pre {
font-variant: small-caps;
font-size: 400%;
width: 100%;
- padding: 0px 0px 0px 5px;
- border-bottom: solid #6699ff 1px;
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
}
.banner a {
color: #000000;
@@ -63,6 +64,15 @@ pre {
text-decoration: none;
color: #000000;
}
+.bannerb {
+ color: #ffffff;
+ background-color: #ffffff;
+ width: 100%;
+ height: 1px;
+ padding: 0px;
+ margin: 0px;
+ border-bottom: solid #6699ff 1px;
+}
.nav {
font-size: x-small;
@@ -71,6 +81,7 @@ pre {
padding: 2px 0px 2px 0px;
margin: 0px;
+ border-bottom: solid #d4d4d4 300px;
}
.nav a:hover {
text-decoration: none;
@@ -82,7 +93,7 @@ pre {
text-indent: 1em;
}
.nav .section {
- width: 100%;
+ width: 120px;
text-indent: 0em;
border-top: 0px;
border-left: 0px;
diff --git a/doc/tips.html b/doc/tips.html
index 175c094a..9f8e9e24 100644
--- a/doc/tips.html
+++ b/doc/tips.html
@@ -1,45 +1,42 @@
-
+
-
- Synergy Tips and Tricks
+
+
+
+
+ Synergy Tips and Tricks
-
Tips and Tricks
+
+
Tips and Tricks
-
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 installed as a service 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.
-
-
+ (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.
-
-
+ 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
@@ -49,45 +46,36 @@
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.
-
+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
+