changeset 0:4689cc86d6cb

create TreeViewer2 Repository
author Yu Taninari <you@cr.ie.u-ryukyu.ac.jp>
date Tue, 03 Jul 2012 13:20:49 +0900
parents
children 75b54fd9e73a 17b702648079
files .gradle/1.0/taskArtifacts/cache.properties .gradle/1.0/taskArtifacts/cache.properties.lock .gradle/1.0/taskArtifacts/fileHashes.bin .gradle/1.0/taskArtifacts/fileSnapshots.bin .gradle/1.0/taskArtifacts/outputFileStates.bin .gradle/1.0/taskArtifacts/taskArtifacts.bin .project .settings/org.eclipse.jdt.core.prefs LICENSE.txt README.txt build.gradle build/classes/main/com/glavsoft/core/SettingsChangedEvent.class build/classes/main/com/glavsoft/drawing/ColorDecoder.class build/classes/main/com/glavsoft/drawing/Renderer.class build/classes/main/com/glavsoft/drawing/SoftCursor.class build/classes/main/com/glavsoft/exceptions/AuthenticationFailedException.class build/classes/main/com/glavsoft/exceptions/ClosedConnectionException.class build/classes/main/com/glavsoft/exceptions/CommonException.class build/classes/main/com/glavsoft/exceptions/CryptoException.class build/classes/main/com/glavsoft/exceptions/FatalException.class build/classes/main/com/glavsoft/exceptions/ProtocolException.class build/classes/main/com/glavsoft/exceptions/TransportException.class build/classes/main/com/glavsoft/exceptions/UnsupportedProtocolVersionException.class build/classes/main/com/glavsoft/exceptions/UnsupportedSecurityTypeException.class build/classes/main/com/glavsoft/log/Logger.class build/classes/main/com/glavsoft/log/LoggerFactory.class build/classes/main/com/glavsoft/rfb/CapabilityContainer.class build/classes/main/com/glavsoft/rfb/ClipboardController.class build/classes/main/com/glavsoft/rfb/IChangeSettingsListener.class build/classes/main/com/glavsoft/rfb/IPasswordRetriever.class build/classes/main/com/glavsoft/rfb/IRepaintController.class build/classes/main/com/glavsoft/rfb/IRfbSessionListener.class build/classes/main/com/glavsoft/rfb/RfbCapabilityInfo.class build/classes/main/com/glavsoft/rfb/client/ClientCutTextMessage.class build/classes/main/com/glavsoft/rfb/client/ClientToServerMessage.class build/classes/main/com/glavsoft/rfb/client/FramebufferUpdateRequestMessage.class build/classes/main/com/glavsoft/rfb/client/KeyEventMessage.class build/classes/main/com/glavsoft/rfb/client/PointerEventMessage.class build/classes/main/com/glavsoft/rfb/client/SetEncodingsMessage.class build/classes/main/com/glavsoft/rfb/client/SetPixelFormatMessage.class build/classes/main/com/glavsoft/rfb/encoding/EncodingType.class build/classes/main/com/glavsoft/rfb/encoding/PixelFormat.class build/classes/main/com/glavsoft/rfb/encoding/ServerInitMessage.class build/classes/main/com/glavsoft/rfb/encoding/decoder/ByteBuffer.class build/classes/main/com/glavsoft/rfb/encoding/decoder/CopyRectDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/Decoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/DecodersContainer.class build/classes/main/com/glavsoft/rfb/encoding/decoder/FramebufferUpdateRectangle.class build/classes/main/com/glavsoft/rfb/encoding/decoder/HextileDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/RREDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/RawDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/RichCursorDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/TightDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.class build/classes/main/com/glavsoft/rfb/encoding/decoder/ZlibDecoder.class build/classes/main/com/glavsoft/rfb/protocol/LocalPointer.class build/classes/main/com/glavsoft/rfb/protocol/MessageQueue.class build/classes/main/com/glavsoft/rfb/protocol/Protocol.class build/classes/main/com/glavsoft/rfb/protocol/ProtocolContext.class build/classes/main/com/glavsoft/rfb/protocol/ProtocolSettings$1.class build/classes/main/com/glavsoft/rfb/protocol/ProtocolSettings.class build/classes/main/com/glavsoft/rfb/protocol/ReceiverTask.class build/classes/main/com/glavsoft/rfb/protocol/SenderTask.class build/classes/main/com/glavsoft/rfb/protocol/auth/AuthHandler.class build/classes/main/com/glavsoft/rfb/protocol/auth/NoneAuthentication.class build/classes/main/com/glavsoft/rfb/protocol/auth/SecurityType$1.class build/classes/main/com/glavsoft/rfb/protocol/auth/SecurityType.class build/classes/main/com/glavsoft/rfb/protocol/auth/TightAuthentication.class build/classes/main/com/glavsoft/rfb/protocol/auth/VncAuthentication.class build/classes/main/com/glavsoft/rfb/protocol/state/AuthenticationState.class build/classes/main/com/glavsoft/rfb/protocol/state/HandshakeState.class build/classes/main/com/glavsoft/rfb/protocol/state/InitState.class build/classes/main/com/glavsoft/rfb/protocol/state/InitTightState.class build/classes/main/com/glavsoft/rfb/protocol/state/ProtocolState.class build/classes/main/com/glavsoft/rfb/protocol/state/SecurityType33State.class build/classes/main/com/glavsoft/rfb/protocol/state/SecurityType37State.class build/classes/main/com/glavsoft/rfb/protocol/state/SecurityTypeState.class build/classes/main/com/glavsoft/transport/Reader.class build/classes/main/com/glavsoft/transport/Writer.class build/classes/main/com/glavsoft/utils/Keymap.class build/classes/main/com/glavsoft/utils/Strings.class build/classes/main/com/glavsoft/viewer/ConnectionManager.class build/classes/main/com/glavsoft/viewer/ContainerManager$1.class build/classes/main/com/glavsoft/viewer/ContainerManager$2.class build/classes/main/com/glavsoft/viewer/ContainerManager$3.class build/classes/main/com/glavsoft/viewer/ContainerManager$4.class build/classes/main/com/glavsoft/viewer/ContainerManager$5.class build/classes/main/com/glavsoft/viewer/ContainerManager$6.class build/classes/main/com/glavsoft/viewer/ContainerManager.class build/classes/main/com/glavsoft/viewer/Viewer$1.class build/classes/main/com/glavsoft/viewer/Viewer$10.class build/classes/main/com/glavsoft/viewer/Viewer$11.class build/classes/main/com/glavsoft/viewer/Viewer$2.class build/classes/main/com/glavsoft/viewer/Viewer$3.class build/classes/main/com/glavsoft/viewer/Viewer$4.class build/classes/main/com/glavsoft/viewer/Viewer$5.class build/classes/main/com/glavsoft/viewer/Viewer$6.class build/classes/main/com/glavsoft/viewer/Viewer$7.class build/classes/main/com/glavsoft/viewer/Viewer$8.class build/classes/main/com/glavsoft/viewer/Viewer$9.class build/classes/main/com/glavsoft/viewer/Viewer$PasswordChooser.class build/classes/main/com/glavsoft/viewer/Viewer.class build/classes/main/com/glavsoft/viewer/cli/Parser$Option.class build/classes/main/com/glavsoft/viewer/cli/Parser.class build/classes/main/com/glavsoft/viewer/swing/ClipboardControllerImpl.class build/classes/main/com/glavsoft/viewer/swing/KeyEventListener.class build/classes/main/com/glavsoft/viewer/swing/KeyboardConvertor$1.class build/classes/main/com/glavsoft/viewer/swing/KeyboardConvertor$CodePair.class build/classes/main/com/glavsoft/viewer/swing/KeyboardConvertor.class build/classes/main/com/glavsoft/viewer/swing/ModifierButtonEventListener.class build/classes/main/com/glavsoft/viewer/swing/MouseEventListener.class build/classes/main/com/glavsoft/viewer/swing/ParametersHandler$ConnectionParams.class build/classes/main/com/glavsoft/viewer/swing/ParametersHandler.class build/classes/main/com/glavsoft/viewer/swing/RendererImpl.class build/classes/main/com/glavsoft/viewer/swing/SoftCursorImpl.class build/classes/main/com/glavsoft/viewer/swing/Surface.class build/classes/main/com/glavsoft/viewer/swing/UiSettings.class build/classes/main/com/glavsoft/viewer/swing/Utils.class build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog$1.class build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog$2.class build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog$3.class build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$1.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$2.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$3.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$4.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$5.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$6.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$7.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$ColorDepthSelectItem.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$EncodingSelectItem.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$RadioButtonSelectedState.class build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog.class build/classes/main/com/glavsoft/viewer/swing/gui/PasswordDialog$1.class build/classes/main/com/glavsoft/viewer/swing/gui/PasswordDialog$2.class build/classes/main/com/glavsoft/viewer/swing/gui/PasswordDialog.class build/libs/tightvnc-jviewer.jar build/resources/main/com/glavsoft/viewer/images/button-alt.png build/resources/main/com/glavsoft/viewer/images/button-close.png build/resources/main/com/glavsoft/viewer/images/button-ctrl-alt-del.png build/resources/main/com/glavsoft/viewer/images/button-ctrl.png build/resources/main/com/glavsoft/viewer/images/button-file-transfer.png build/resources/main/com/glavsoft/viewer/images/button-fullscreen.png build/resources/main/com/glavsoft/viewer/images/button-info.png build/resources/main/com/glavsoft/viewer/images/button-new-connection.png build/resources/main/com/glavsoft/viewer/images/button-options.png build/resources/main/com/glavsoft/viewer/images/button-rec.png build/resources/main/com/glavsoft/viewer/images/button-refresh.png build/resources/main/com/glavsoft/viewer/images/button-save.png build/resources/main/com/glavsoft/viewer/images/button-win.png build/resources/main/com/glavsoft/viewer/images/button-zoom-100.png build/resources/main/com/glavsoft/viewer/images/button-zoom-fit.png build/resources/main/com/glavsoft/viewer/images/button-zoom-in.png build/resources/main/com/glavsoft/viewer/images/button-zoom-out.png build/resources/main/com/glavsoft/viewer/images/tightvnc-logo-16x16.png build/resources/main/com/glavsoft/viewer/images/tightvnc-logo-32x32.png build/tmp/jar/MANIFEST.MF dist/tightvnc-jviewer-2.5.0/tightvnc-jviewer.jar dist/tightvnc-jviewer-2.5.0/viewer-applet-example.html src/main/java/com/glavsoft/core/SettingsChangedEvent.java src/main/java/com/glavsoft/drawing/ColorDecoder.java src/main/java/com/glavsoft/drawing/Renderer.java src/main/java/com/glavsoft/drawing/SoftCursor.java src/main/java/com/glavsoft/exceptions/AuthenticationFailedException.java src/main/java/com/glavsoft/exceptions/ClosedConnectionException.java src/main/java/com/glavsoft/exceptions/CommonException.java src/main/java/com/glavsoft/exceptions/CryptoException.java src/main/java/com/glavsoft/exceptions/FatalException.java src/main/java/com/glavsoft/exceptions/ProtocolException.java src/main/java/com/glavsoft/exceptions/TransportException.java src/main/java/com/glavsoft/exceptions/UnsupportedProtocolVersionException.java src/main/java/com/glavsoft/exceptions/UnsupportedSecurityTypeException.java src/main/java/com/glavsoft/log/Logger.java src/main/java/com/glavsoft/log/LoggerFactory.java src/main/java/com/glavsoft/rfb/CapabilityContainer.java src/main/java/com/glavsoft/rfb/ClipboardController.java src/main/java/com/glavsoft/rfb/IChangeSettingsListener.java src/main/java/com/glavsoft/rfb/IPasswordRetriever.java src/main/java/com/glavsoft/rfb/IRepaintController.java src/main/java/com/glavsoft/rfb/IRfbSessionListener.java src/main/java/com/glavsoft/rfb/RfbCapabilityInfo.java src/main/java/com/glavsoft/rfb/client/ClientCutTextMessage.java src/main/java/com/glavsoft/rfb/client/ClientToServerMessage.java src/main/java/com/glavsoft/rfb/client/FramebufferUpdateRequestMessage.java src/main/java/com/glavsoft/rfb/client/KeyEventMessage.java src/main/java/com/glavsoft/rfb/client/PointerEventMessage.java src/main/java/com/glavsoft/rfb/client/SetEncodingsMessage.java src/main/java/com/glavsoft/rfb/client/SetPixelFormatMessage.java src/main/java/com/glavsoft/rfb/encoding/EncodingType.java src/main/java/com/glavsoft/rfb/encoding/PixelFormat.java src/main/java/com/glavsoft/rfb/encoding/ServerInitMessage.java src/main/java/com/glavsoft/rfb/encoding/decoder/ByteBuffer.java src/main/java/com/glavsoft/rfb/encoding/decoder/CopyRectDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/Decoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/DecodersContainer.java src/main/java/com/glavsoft/rfb/encoding/decoder/FramebufferUpdateRectangle.java src/main/java/com/glavsoft/rfb/encoding/decoder/HextileDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/RREDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/RawDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/RichCursorDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/TightDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java src/main/java/com/glavsoft/rfb/encoding/decoder/ZlibDecoder.java src/main/java/com/glavsoft/rfb/protocol/LocalPointer.java src/main/java/com/glavsoft/rfb/protocol/MessageQueue.java src/main/java/com/glavsoft/rfb/protocol/Protocol.java src/main/java/com/glavsoft/rfb/protocol/ProtocolContext.java src/main/java/com/glavsoft/rfb/protocol/ProtocolSettings.java src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java src/main/java/com/glavsoft/rfb/protocol/SenderTask.java src/main/java/com/glavsoft/rfb/protocol/auth/AuthHandler.java src/main/java/com/glavsoft/rfb/protocol/auth/NoneAuthentication.java src/main/java/com/glavsoft/rfb/protocol/auth/SecurityType.java src/main/java/com/glavsoft/rfb/protocol/auth/TightAuthentication.java src/main/java/com/glavsoft/rfb/protocol/auth/VncAuthentication.java src/main/java/com/glavsoft/rfb/protocol/state/AuthenticationState.java src/main/java/com/glavsoft/rfb/protocol/state/HandshakeState.java src/main/java/com/glavsoft/rfb/protocol/state/InitState.java src/main/java/com/glavsoft/rfb/protocol/state/InitTightState.java src/main/java/com/glavsoft/rfb/protocol/state/ProtocolState.java src/main/java/com/glavsoft/rfb/protocol/state/SecurityType33State.java src/main/java/com/glavsoft/rfb/protocol/state/SecurityType37State.java src/main/java/com/glavsoft/rfb/protocol/state/SecurityTypeState.java src/main/java/com/glavsoft/transport/Reader.java src/main/java/com/glavsoft/transport/Writer.java src/main/java/com/glavsoft/utils/Keymap.java src/main/java/com/glavsoft/utils/Strings.java src/viewer_swing/java/com/glavsoft/viewer/ConnectionManager.java src/viewer_swing/java/com/glavsoft/viewer/ContainerManager.java src/viewer_swing/java/com/glavsoft/viewer/Viewer.java src/viewer_swing/java/com/glavsoft/viewer/cli/Parser.java src/viewer_swing/java/com/glavsoft/viewer/swing/ClipboardControllerImpl.java src/viewer_swing/java/com/glavsoft/viewer/swing/KeyEventListener.java src/viewer_swing/java/com/glavsoft/viewer/swing/KeyboardConvertor.java src/viewer_swing/java/com/glavsoft/viewer/swing/ModifierButtonEventListener.java src/viewer_swing/java/com/glavsoft/viewer/swing/MouseEventListener.java src/viewer_swing/java/com/glavsoft/viewer/swing/ParametersHandler.java src/viewer_swing/java/com/glavsoft/viewer/swing/RendererImpl.java src/viewer_swing/java/com/glavsoft/viewer/swing/SoftCursorImpl.java src/viewer_swing/java/com/glavsoft/viewer/swing/Surface.java src/viewer_swing/java/com/glavsoft/viewer/swing/UiSettings.java src/viewer_swing/java/com/glavsoft/viewer/swing/Utils.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/ConnectionDialog.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/OptionsDialog.java src/viewer_swing/java/com/glavsoft/viewer/swing/gui/PasswordDialog.java src/viewer_swing/resources/com/glavsoft/viewer/images/button-alt.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-close.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-ctrl-alt-del.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-ctrl.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-file-transfer.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-fullscreen.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-info.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-new-connection.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-options.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-rec.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-refresh.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-save.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-win.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-100.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-fit.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-in.png src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-out.png src/viewer_swing/resources/com/glavsoft/viewer/images/tightvnc-logo-16x16.png src/viewer_swing/resources/com/glavsoft/viewer/images/tightvnc-logo-32x32.png src/web/viewer-applet-example.html src/web/viewer-java-web-start-example.html src/web/viewer-java-web-start-example.jnlp
diffstat 267 files changed, 11226 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gradle/1.0/taskArtifacts/cache.properties	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,1 @@
+#Tue Jun 19 20:20:09 JST 2012
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gradle/1.0/taskArtifacts/cache.properties.lock	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,1 @@
+
\ No newline at end of file
Binary file .gradle/1.0/taskArtifacts/fileHashes.bin has changed
Binary file .gradle/1.0/taskArtifacts/fileSnapshots.bin has changed
Binary file .gradle/1.0/taskArtifacts/outputFileStates.bin has changed
Binary file .gradle/1.0/taskArtifacts/taskArtifacts.bin has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>TreeViewer2</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.settings/org.eclipse.jdt.core.prefs	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,13 @@
+#
+#Sun Jun 24 14:19:09 JST 2012
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE.txt	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.txt	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,52 @@
+
+TightVNC Java Viewer version 2.5.0
+Copyright (C) 2011 GlavSoft LLC. All rights reserved.
+======================================================================
+
+This software is distributed under the GNU General Public Licence
+as published by the Free Software Foundation. Please see the file
+LICENCE.txt for the exact licensing terms and conditions.
+
+The license does not permit incorporating this software into
+proprietary programs. If you wish to do so, please order commercial
+source code license. See the details here:
+
+  http://www.tightvnc.com/licensing/
+
+
+Using TightVNC Java Viewer
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+TightVNC Java Viewer can work either as a normal application or as
+an applet. To run it as an application, just execute the JAR file
+(tightvnc-jviewer.jar), e.g. double-click it in the Windows Explorer.
+If Java Runtime is installed on your computer correctly, that should
+be enough. You will be prompted for the TightVNC Server to connect to.
+
+If you would like to start the viewer from the command line, here are
+a few examples:
+
+  java -jar tightvnc-jviewer.jar
+  java -jar tightvnc-jviewer.jar hostname
+  java -jar tightvnc-jviewer.jar -port=nnn hostname
+  java -jar tightvnc-jviewer.jar -port=nnn -host=hostname
+
+... where hostname and nnn should be replaced with the actual hostname
+and port number correspondingly. Note that you can use an IP address
+as a hostname. Port 5900 will be used if not specified.
+
+Important: the syntax like hostname:display or hostname::port is not
+           supported in this version of TightVNC Java Viewer.
+
+For more command line params info run:
+
+  java -jar tightvnc-jviewer.jar -help
+
+Finally, if you would like to use the viewer as an applet, please see
+the example HTML page included (viewer-applet-example.html).
+
+======================================================================
+
+Thank you for using TightVNC!
+
+Visit our Web site:    http://www.tightvnc.com/
+Follow us on Twitter:  http://www.twitter.com/tighvnc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build.gradle	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,387 @@
+apply plugin:'java'
+apply plugin: 'eclipse'
+
+sourceCompatibility = 1.6
+targetCompatibility = 1.6
+version = '2.5.0'
+
+baseName = 'tightvnc-jviewer'
+
+defaultTasks 'clean', 'dist'
+
+configurations {
+	viewerSwingCompile { extendsFrom compile }
+	viewerSwingRuntime { extendsFrom viewerSwingCompile, runtime }
+}
+
+sourceSets {
+	viewerSwing {
+		java {
+			srcDir 'src/viewer_swing/java'
+		}
+		resources {
+			srcDir 'src/viewer_swing/resources'
+		}
+	}
+	main {
+		java.srcDirs += viewerSwing.java.srcDirs
+		resources.srcDirs += viewerSwing.resources.srcDirs
+	}
+}
+
+jar {
+	baseName = project.baseName
+	version = null
+    manifest {
+        attributes 'Main-Class': 'com.glavsoft.viewer.Viewer'
+        attributes 'Implementation-Version': "${project.version}"
+    }
+}
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testCompile group: 'junit', name: 'junit', version: '4.+'
+    archives fileTree(dir: 'src/web', include: '*.html')
+}
+
+uploadArchives {
+    repositories {
+		add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
+			name = 'repo'
+			addArtifactPattern "$projectDir/dist/${project.baseName}-${project.version}/${project.baseName}.[ext]"
+			descriptor = 'optional'
+			checkmodified = true
+		}
+	}
+	uploadDescriptor = false
+}
+
+task dist(dependsOn: uploadArchives) << {
+	otherFilesUpload("$projectDir/dist/${project.baseName}-${project.version}")
+}
+def otherFilesUpload(repoDir) {
+	copy {
+		from 'src/web'
+		include '*-applet-*.html'
+		expand (['archive_name' : project.baseName])
+		into repoDir
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Binary file build/classes/main/com/glavsoft/core/SettingsChangedEvent.class has changed
Binary file build/classes/main/com/glavsoft/drawing/ColorDecoder.class has changed
Binary file build/classes/main/com/glavsoft/drawing/Renderer.class has changed
Binary file build/classes/main/com/glavsoft/drawing/SoftCursor.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/AuthenticationFailedException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/ClosedConnectionException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/CommonException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/CryptoException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/FatalException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/ProtocolException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/TransportException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/UnsupportedProtocolVersionException.class has changed
Binary file build/classes/main/com/glavsoft/exceptions/UnsupportedSecurityTypeException.class has changed
Binary file build/classes/main/com/glavsoft/log/Logger.class has changed
Binary file build/classes/main/com/glavsoft/log/LoggerFactory.class has changed
Binary file build/classes/main/com/glavsoft/rfb/CapabilityContainer.class has changed
Binary file build/classes/main/com/glavsoft/rfb/ClipboardController.class has changed
Binary file build/classes/main/com/glavsoft/rfb/IChangeSettingsListener.class has changed
Binary file build/classes/main/com/glavsoft/rfb/IPasswordRetriever.class has changed
Binary file build/classes/main/com/glavsoft/rfb/IRepaintController.class has changed
Binary file build/classes/main/com/glavsoft/rfb/IRfbSessionListener.class has changed
Binary file build/classes/main/com/glavsoft/rfb/RfbCapabilityInfo.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/ClientCutTextMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/ClientToServerMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/FramebufferUpdateRequestMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/KeyEventMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/PointerEventMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/SetEncodingsMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/client/SetPixelFormatMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/EncodingType.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/PixelFormat.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/ServerInitMessage.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/ByteBuffer.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/CopyRectDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/Decoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/DecodersContainer.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/FramebufferUpdateRectangle.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/HextileDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/RREDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/RawDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/RichCursorDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/TightDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/encoding/decoder/ZlibDecoder.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/LocalPointer.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/MessageQueue.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/Protocol.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/ProtocolContext.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/ProtocolSettings$1.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/ProtocolSettings.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/ReceiverTask.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/SenderTask.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/auth/AuthHandler.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/auth/NoneAuthentication.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/auth/SecurityType$1.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/auth/SecurityType.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/auth/TightAuthentication.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/auth/VncAuthentication.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/AuthenticationState.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/HandshakeState.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/InitState.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/InitTightState.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/ProtocolState.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/SecurityType33State.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/SecurityType37State.class has changed
Binary file build/classes/main/com/glavsoft/rfb/protocol/state/SecurityTypeState.class has changed
Binary file build/classes/main/com/glavsoft/transport/Reader.class has changed
Binary file build/classes/main/com/glavsoft/transport/Writer.class has changed
Binary file build/classes/main/com/glavsoft/utils/Keymap.class has changed
Binary file build/classes/main/com/glavsoft/utils/Strings.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ConnectionManager.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager$1.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager$2.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager$3.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager$4.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager$5.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager$6.class has changed
Binary file build/classes/main/com/glavsoft/viewer/ContainerManager.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$1.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$10.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$11.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$2.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$3.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$4.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$5.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$6.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$7.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$8.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$9.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer$PasswordChooser.class has changed
Binary file build/classes/main/com/glavsoft/viewer/Viewer.class has changed
Binary file build/classes/main/com/glavsoft/viewer/cli/Parser$Option.class has changed
Binary file build/classes/main/com/glavsoft/viewer/cli/Parser.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/ClipboardControllerImpl.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/KeyEventListener.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/KeyboardConvertor$1.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/KeyboardConvertor$CodePair.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/KeyboardConvertor.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/ModifierButtonEventListener.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/MouseEventListener.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/ParametersHandler$ConnectionParams.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/ParametersHandler.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/RendererImpl.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/SoftCursorImpl.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/Surface.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/UiSettings.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/Utils.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog$1.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog$2.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog$3.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/ConnectionDialog.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$1.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$2.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$3.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$4.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$5.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$6.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$7.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$ColorDepthSelectItem.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$EncodingSelectItem.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog$RadioButtonSelectedState.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/OptionsDialog.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/PasswordDialog$1.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/PasswordDialog$2.class has changed
Binary file build/classes/main/com/glavsoft/viewer/swing/gui/PasswordDialog.class has changed
Binary file build/libs/tightvnc-jviewer.jar has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-alt.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-close.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-ctrl-alt-del.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-ctrl.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-file-transfer.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-fullscreen.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-info.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-new-connection.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-options.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-rec.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-refresh.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-save.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-win.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-zoom-100.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-zoom-fit.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-zoom-in.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/button-zoom-out.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/tightvnc-logo-16x16.png has changed
Binary file build/resources/main/com/glavsoft/viewer/images/tightvnc-logo-32x32.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build/tmp/jar/MANIFEST.MF	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Main-Class: com.glavsoft.viewer.Viewer
+Implementation-Version: 2.5.0
+
Binary file dist/tightvnc-jviewer-2.5.0/tightvnc-jviewer.jar has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/tightvnc-jviewer-2.5.0/viewer-applet-example.html	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,36 @@
+<!-- Copyright (C) 2010, 2011, 2012 GlavSoft LLC. -->
+<!-- All rights reserved. -->
+<!-- -->
+<!-- DO NOT USE OR REDISTRIBUTE THE CODE, UNLESS YOU HAVE OBTAINED A LICENSE. -->
+<!--  -->
+
+<html>
+	<title>TightVNC desktop</title>
+	<body>
+		<applet archive="tightvnc-jviewer.jar"
+			code="com.glavsoft.viewer.Viewer"
+			width="1" height="1">
+			<param name="Host" value="localhost" /> <!-- Host to connect. Default:  the host from which the applet was loaded. -->
+			<param name="Port" value="5900" /> <!-- Port number to connect. Default: 5900 -->
+			<!--param name="Password" value="" /--> <!-- Password to the server (not recommended to use this parameter here) -->
+			<param name="OpenNewWindow" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="ShowControls" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="ViewOnly" value="no" /> <!-- yes/true or no/false. Default: no/false -->
+			<param name="AllowClipboardTransfer" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+            <param name="RemoteCharset" value="standard" /> <!-- Charset encoding is used on remote system. Use this option to specify character encoding will be used for encoding clipboard text content to. Default value (when parameter is empty): local system default character encoding. Set the value to 'standard' for using 'Latin-1' charset which is only specified by rfb standard for clipboard transfers. -->
+
+			<param name="ShareDesktop" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="AllowCopyRect" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="Encoding" value="Tight" /> <!-- Possible values: "Tight", "Hextile", "ZRLE", and "Raw". Default: Tight -->
+			<param name="CompressionLevel" value="" /> <!-- 1-9 or empty. Empty means server default -->
+			<param name="JpegImageQuality" value="" /> <!-- 1-9, Lossless or empty. When param is set to "Lossless" no jpeg compression used. Empty means server default -->
+			<param name="LocalPointer" value="On" /> <!-- Possible values: on/yes/true (draw pointer locally), off/no/false (let server draw pointer), hide). Default: "On"-->
+			<param name="ConvertToASCII" value="no" /> <!-- Whether to convert keyboard input to ASCII ignoring locale. Possible values: yes/true, no/false). Default: "No"-->
+
+			<param name="colorDepth" value="" /> <!-- Reserved for future. Possible values: 6, 8, 16, 24, 32 (equals to 24). Only 24/32 is supported now -->
+			<param name="ScalingFactor" value="100" /> <!-- Scale local representation of the remote desktop on startup. Default is 100 means 100% -->
+		</applet>
+		<br />
+		<a href="http://www.tightvnc.com/">TightVNC Web Site</a>
+	</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/core/SettingsChangedEvent.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,41 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.core;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class SettingsChangedEvent {
+	private final Object source;
+
+	public SettingsChangedEvent(Object source) {
+		this.source = source;
+	}
+
+	public Object getSource() {
+		return source;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/drawing/ColorDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,132 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.drawing;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.transport.Reader;
+
+public class ColorDecoder {
+	protected byte redShift;
+	protected byte greenShift;
+	protected byte blueShift;
+	public short redMax;
+	public short greenMax;
+	public short blueMax;
+	private final int bytesPerPixel;
+	private final int bytesPerPixelSignificant;
+	private final byte[] buff;
+
+	private int startShift;
+	private int startShiftCompact;
+	private int addShiftItem;
+	private final boolean isTightSpecific;
+
+	public ColorDecoder(PixelFormat pf) {
+		redShift = pf.redShift;
+		greenShift = pf.greenShift;
+		blueShift = pf.blueShift;
+		redMax = pf.redMax;
+		greenMax = pf.greenMax;
+		blueMax = pf.blueMax;
+		bytesPerPixel = pf.bitsPerPixel / 8;
+		bytesPerPixelSignificant = 24 == pf.depth && 32 == pf.bitsPerPixel ? 3 : bytesPerPixel;
+		buff = new byte[bytesPerPixel];
+		if (0 == pf.bigEndianFlag) {
+			startShift = 0;
+			startShiftCompact = 0;
+			addShiftItem = 8;
+		} else {
+			startShift = pf.bitsPerPixel - 8;
+			startShiftCompact = Math.max(0, pf.depth - 8);
+			addShiftItem = -8;
+		}
+		isTightSpecific = 4==bytesPerPixel && 3==bytesPerPixelSignificant &&
+				255 == redMax && 255 == greenMax && 255 == blueMax;
+	}
+
+	protected int readColor(Reader reader) throws TransportException {
+		return getColor(reader.readBytes(buff, 0, bytesPerPixel), 0);
+	}
+
+	protected int readCompactColor(Reader reader) throws TransportException {
+		return getCompactColor(reader.readBytes(buff, 0, bytesPerPixelSignificant), 0);
+	}
+
+	protected int readTightColor(Reader reader) throws TransportException {
+		return getTightColor(reader.readBytes(buff, 0, bytesPerPixelSignificant), 0);
+	}
+
+	protected int convertColor(int rawColor) {
+		return  255 * (rawColor >> redShift & redMax) / redMax << 16 |
+				255 * (rawColor >> greenShift & greenMax) / greenMax << 8 |
+				255 * (rawColor >> blueShift & blueMax) / blueMax;
+	}
+
+	public void fillRawComponents(byte[] comp, byte[] bytes, int offset) {
+		int rawColor = getRawTightColor(bytes, offset);
+		comp[0] = (byte) (rawColor >> redShift & redMax);
+		comp[1] = (byte) (rawColor >> greenShift & greenMax);
+		comp[2] = (byte) (rawColor >> blueShift & blueMax);
+	}
+
+	protected int getTightColor(byte[] bytes, int offset) {
+		return convertColor(getRawTightColor(bytes, offset));
+	}
+
+	private int getRawTightColor(byte[] bytes, int offset) {
+		if (isTightSpecific)
+			return (bytes[offset++] & 0xff)<<16 |
+					(bytes[offset++] & 0xff)<<8 |
+					bytes[offset++] & 0xff;
+		else
+			return getRawColor(bytes, offset);
+	}
+
+	protected int getColor(byte[] bytes, int offset) {
+		return convertColor(getRawColor(bytes, offset));
+	}
+
+	private int getRawColor(byte[] bytes, int offset) {
+		int shift = startShift;
+		int item = addShiftItem;
+		int rawColor = (bytes[offset++] & 0xff)<<shift;
+		for (int i=1; i<bytesPerPixel; ++i) {
+			rawColor |= (bytes[offset++] & 0xff)<<(shift+=item);
+		}
+		return rawColor;
+	}
+
+	protected int getCompactColor(byte[] bytes, int offset) {
+		int shift = startShiftCompact;
+		int item = addShiftItem;
+		int rawColor = (bytes[offset++] & 0xff)<<shift;
+		for (int i=1; i<bytesPerPixelSignificant; ++i) {
+			rawColor |= (bytes[offset++] & 0xff)<<(shift+=item);
+		}
+		return convertColor(rawColor);
+	}
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/drawing/Renderer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,328 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.drawing;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.transport.Reader;
+
+import java.util.Arrays;
+
+/**
+ * Render bitmap data
+ *
+ * @author dime @ tightvnc.com
+ */
+public abstract class Renderer {
+
+	protected Reader reader;
+
+	public abstract void drawJpegImage(byte[] bytes, int offset,
+			int jpegBufferLength, FramebufferUpdateRectangle rect);
+
+	protected int width;
+	protected int height;
+	protected int bytesPerPixel;
+	protected int bytesPerPixelSignificant;
+	protected int[] pixels;
+	protected SoftCursor cursor;
+	protected PixelFormat pixelFormat;
+	private ColorDecoder colorDecoder;
+
+	protected void init(Reader reader, int width, int height, PixelFormat pixelFormat) {
+		this.reader = reader;
+		this.width = width;
+		this.height = height;
+		initPixelFormat(pixelFormat);
+		pixels = new int[width * height];
+		Arrays.fill(pixels, 0);
+	}
+
+	public synchronized void initPixelFormat(PixelFormat pixelFormat) {
+		this.pixelFormat = pixelFormat;
+		bytesPerPixel = pixelFormat.bitsPerPixel / 8;
+		bytesPerPixelSignificant =
+				24 == pixelFormat.depth && 32 == pixelFormat.bitsPerPixel ? 3 : bytesPerPixel;
+		colorDecoder = new ColorDecoder(pixelFormat);
+	}
+
+	/**
+	 * Draw byte array bitmap data
+	 *
+	 * @param bytes bitmap data
+	 * @param x bitmap x position
+	 * @param y bitmap y position
+	 * @param width bitmap width
+	 * @param height bitmap height
+	 */
+	public void drawBytes(byte[] bytes, int x, int y, int width, int height) {
+		int i = 0;
+		for (int ly = y; ly < y + height; ++ly) {
+			int end = ly * this.width + x + width;
+			for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+				pixels[pixelsOffset] = getPixelColor(bytes, i);
+				i += bytesPerPixel;
+			}
+		}
+	}
+
+	/**
+	 * Draw byte array bitmap data (for ZRLE)
+	 */
+	public synchronized int  drawCompactBytes(byte[] bytes, int offset, int x, int y, int width, int height) {
+		int i = offset;
+		for (int ly = y; ly < y + height; ++ly) {
+			int end = ly * this.width + x + width;
+			for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+				pixels[pixelsOffset] = getCompactPixelColor(bytes, i);
+				i += bytesPerPixelSignificant;
+			}
+		}
+		return i - offset;
+	}
+
+	/**
+	 * Draw int (colors) array bitmap data (for ZRLE)
+	 */
+	public synchronized void  drawColoredBitmap(int[] colors, int x, int y, int width, int height) {
+		int i = 0;
+		for (int ly = y; ly < y + height; ++ly) {
+			int end = ly * this.width + x + width;
+			for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+				pixels[pixelsOffset] = colors[i++];
+			}
+		}
+	}
+
+	/**
+	 * Draw byte array bitmap data (for Tight)
+	 */
+	public synchronized int drawTightBytes(byte[] bytes, int offset, int x, int y, int width, int height) {
+		int i = offset;
+		for (int ly = y; ly < y + height; ++ly) {
+			int end = ly * this.width + x + width;
+			for (int pixelsOffset = ly * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+				pixels[pixelsOffset] = colorDecoder.getTightColor(bytes, i);
+				i += bytesPerPixelSignificant;
+			}
+		}
+		return i - offset;
+	}
+
+	/**
+	 * Draw byte array bitmap data (from array with plain RGB color components. Assumed: rrrrrrrr gggggggg bbbbbbbb)
+	 */
+	public synchronized void drawUncaliberedRGBLine(byte[] bytes, int x, int y, int width) {
+		int end = y * this.width + x + width;
+		for (int i=3, pixelsOffset = y * this.width + x; pixelsOffset < end; ++pixelsOffset) {
+			pixels[pixelsOffset] =
+//					(0xff & bytes[i++]) << 16 |
+//					(0xff & bytes[i++]) << 8 |
+//					0xff & bytes[i++];
+					(0xff & 255 * (colorDecoder.redMax & bytes[i++]) / colorDecoder.redMax) << 16 |
+					(0xff & 255 * (colorDecoder.greenMax & bytes[i++]) / colorDecoder.greenMax) << 8 |
+					0xff & 255 * (colorDecoder.blueMax & bytes[i++]) / colorDecoder.blueMax;
+		}
+	}
+
+	/**
+	 * Draw paletted byte array bitmap data
+	 *
+	 * @param buffer bitmap data
+	 * @param rect bitmap location and dimensions
+	 * @param palette colour palette
+	 */
+	public synchronized void drawBytesWithPalette(byte[] buffer, FramebufferUpdateRectangle rect,
+			int[] palette) {
+				// 2 colors
+				if (palette.length == 2) {
+					int dx, dy, n;
+					int i = rect.y * this.width + rect.x;
+					int rowBytes = (rect.width + 7) / 8;
+					byte b;
+
+					for (dy = 0; dy < rect.height; dy++) {
+						for (dx = 0; dx < rect.width / 8; dx++) {
+							b = buffer[dy * rowBytes + dx];
+							for (n = 7; n >= 0; n--) {
+								pixels[i++] = palette[b >> n & 1];
+							}
+						}
+						for (n = 7; n >= 8 - rect.width % 8; n--) {
+							pixels[i++] = palette[buffer[dy * rowBytes + dx] >> n & 1];
+						}
+						i += this.width- rect.width;
+					}
+				} else {
+					// 3..255 colors (assuming bytesPixel == 4).
+					int i = 0;
+					for (int ly =  rect.y; ly < rect.y + rect.height; ++ly) {
+						for (int lx = rect.x; lx < rect.x + rect.width; ++lx) {
+							int pixelsOffset = ly * this.width + lx;
+							pixels[pixelsOffset] = palette[buffer[i++] & 0xFF];
+						}
+					}
+				}
+
+			}
+
+	/**
+	 * Copy rectangle region from one position to another. Regions may be overlapped.
+	 *
+	 * @param srcX source rectangle x position
+	 * @param srcY source rectangle y position
+	 * @param dstRect destination rectangle
+	 */
+	public synchronized void copyRect(int srcX, int srcY, FramebufferUpdateRectangle dstRect) {
+		int startSrcY, endSrcY, dstY, deltaY;
+		if (srcY > dstRect.y) {
+			startSrcY = srcY;
+			endSrcY = srcY + dstRect.height;
+			dstY = dstRect.y;
+			deltaY = +1;
+		} else {
+			startSrcY = srcY + dstRect.height - 1;
+			endSrcY = srcY -1;
+			dstY = dstRect.y + dstRect.height - 1;
+			deltaY = -1;
+		}
+		for (int y = startSrcY; y != endSrcY; y += deltaY) {
+			System.arraycopy(pixels, y * width + srcX,
+					pixels, dstY * width + dstRect.x, dstRect.width);
+			dstY += deltaY;
+		}
+	}
+
+	/**
+	 * Fill rectangle region with specified colour
+	 *
+	 * @param color colour to fill with
+	 * @param rect rectangle region posions and dimensions
+	 */
+	public void fillRect(int color, FramebufferUpdateRectangle rect) {
+		fillRect(color, rect.x, rect.y, rect.width, rect.height);
+	}
+
+	/**
+	 * Fill rectangle region with specified colour
+	 *
+	 * @param color colour to fill with
+	 * @param x rectangle x position
+	 * @param y rectangle y position
+	 * @param width rectangle width
+	 * @param height rectangle height
+	 */
+	public synchronized void fillRect(int color, int x, int y, int width, int height) {
+		int sy = y * this.width + x;
+		int ey = sy + height * this.width;
+		for (int i = sy; i < ey; i += this.width) {
+			Arrays.fill(pixels, i, i + width, color);
+		}
+	}
+
+	/**
+	 * Reads color bytes (PIXEL) from reader, returns int combined RGB
+	 * value consisting of the red component in bits 16-23, the green component
+	 * in bits 8-15, and the blue component in bits 0-7. May be used directly for
+	 * creation awt.Color object
+	 */
+	public int readPixelColor(Reader reader) throws TransportException {
+		return colorDecoder.readColor(reader);
+	}
+
+	public int readTightPixelColor(Reader reader) throws TransportException {
+		return colorDecoder.readTightColor(reader);
+	}
+
+	public ColorDecoder getColorDecoder() {
+		return colorDecoder;
+	}
+
+	public int getCompactPixelColor(byte[] bytes, int offset) {
+		return colorDecoder.getCompactColor(bytes, offset);
+	}
+
+	public int getPixelColor(byte[] bytes, int offset) {
+		return colorDecoder.getColor(bytes, offset);
+	}
+
+	public int getBytesPerPixel() {
+		return bytesPerPixel;
+	}
+
+	public int getBytesPerPixelSignificant() {
+		return bytesPerPixelSignificant;
+	}
+
+	public void fillColorBitmapWithColor(int[] bitmapData, int decodedOffset, int rlength, int color) {
+		while (rlength-- > 0) {
+			bitmapData[decodedOffset++] = color;
+		}
+	}
+
+	/**
+	 * Width of rendered image
+	 *
+	 * @return width
+	 */
+	public int getWidth() {
+		return width;
+	}
+
+	/**
+	 * Height of rendered image
+	 *
+	 * @return height
+	 */
+	public int getHeight() {
+		return height;
+	}
+
+	/**
+	 * Read and decode cursor image
+	 *
+	 * @param rect new cursor hot point position and cursor dimensions
+	 * @throws TransportException
+	 */
+	public void createCursor(int[] cursorPixels, FramebufferUpdateRectangle rect)
+		throws TransportException {
+		synchronized (cursor) {
+			cursor.createCursor(cursorPixels, rect.x, rect.y, rect.width, rect.height);
+		}
+	}
+
+	/**
+	 * Read and decode new cursor position
+	 *
+	 * @param rect cursor position
+	 */
+	public void decodeCursorPosition(FramebufferUpdateRectangle rect) {
+		synchronized (cursor) {
+			cursor.updatePosition(rect.x, rect.y);
+		}
+	}
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/drawing/SoftCursor.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,88 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.drawing;
+
+/**
+ * Abstract class for operations with soft cursor positions, dimensions and
+ * hot point position.
+ */
+public abstract class SoftCursor {
+
+	protected int hotX, hotY;
+	private int x, y;
+	public int width, height;
+	public int rX, rY;
+	public int oldRX, oldRY;
+	public int oldWidth, oldHeight;
+
+	public SoftCursor(int hotX, int hotY, int width, int height) {
+		this.hotX = hotX;
+		this.hotY = hotY;
+		oldWidth = this.width = width;
+		oldHeight = this.height = height;
+		oldRX = rX = 0;
+		oldRY = rY = 0;
+	}
+
+	/**
+	 * Update cursor position
+	 *
+	 * @param newX
+	 * @param newY
+	 */
+	public void updatePosition(int newX, int newY) {
+		oldRX = rX; oldRY = rY;
+		oldWidth = width; oldHeight = height;
+		x = newX; y = newY;
+		rX = x - hotX; rY = y - hotY;
+	}
+
+	/**
+	 * Set new cursor dimensions and hot point position
+	 *
+	 * @param hotX
+	 * @param hotY
+	 * @param width
+	 * @param height
+	 */
+	public void setNewDimensions(int hotX, int hotY, int width,	int height) {
+		this.hotX = hotX;
+		this.hotY = hotY;
+		oldWidth = this.width;
+		oldHeight = this.height;
+		oldRX = rX; oldRY = rY;
+		rX = x - hotX; rY = y - hotY;
+		this.width = width;
+		this.height = height;
+	}
+
+	public void createCursor(int[] cursorPixels, int hotX, int hotY, int width, int height) {
+		createNewCursorImage(cursorPixels, hotX, hotY, width, height);
+		setNewDimensions(hotX, hotY, width, height);
+	}
+
+	protected abstract void createNewCursorImage(int[] cursorPixels, int hotX, int hotY, int width, int height);
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/AuthenticationFailedException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,46 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Throws when authentication was wrong
+ */
+@SuppressWarnings("serial")
+public class AuthenticationFailedException extends ProtocolException {
+
+	private String reason;
+
+	public AuthenticationFailedException(String message) {
+		super(message);
+	}
+	public AuthenticationFailedException(String message, String reason) {
+		super(message);
+		this.reason = reason;
+	}
+	public String getReason() {
+		return reason;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/ClosedConnectionException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,37 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Throwed when connection closed (EOF)
+ */
+@SuppressWarnings("serial")
+public class ClosedConnectionException extends TransportException {
+
+	public ClosedConnectionException(Throwable exception) {
+		super(exception);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/CommonException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,40 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class CommonException extends Exception {
+
+	public CommonException(Throwable exception) {
+		super(exception);
+	}
+	public CommonException(String message, Throwable exception) {
+		super(message, exception);
+	}
+	public CommonException(String message) {
+		super(message);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/CryptoException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,35 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Throws when problem with DES (or smth else) cryptosystem occured
+ */
+@SuppressWarnings("serial")
+public class CryptoException extends FatalException {
+	public CryptoException(String message, Throwable exception) {
+		super(message, exception);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/FatalException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,35 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+/**
+ * Trhows when further normal program execution unavailable
+ */
+@SuppressWarnings("serial")
+public class FatalException extends CommonException {
+	public FatalException(String message, Throwable e) {
+		super(message, e);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/ProtocolException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,32 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class ProtocolException extends CommonException {
+	public ProtocolException(String message) {
+		super(message);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/TransportException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,37 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+
+@SuppressWarnings("serial")
+public class TransportException extends CommonException {
+	public TransportException(String message, Throwable exception) {
+		super(message, exception);
+	}
+	public TransportException(Throwable exception) {
+		super(exception);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/UnsupportedProtocolVersionException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,33 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class UnsupportedProtocolVersionException extends ProtocolException {
+	public UnsupportedProtocolVersionException(String message) {
+		super(message);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/exceptions/UnsupportedSecurityTypeException.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,33 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.exceptions;
+
+@SuppressWarnings("serial")
+public class UnsupportedSecurityTypeException extends ProtocolException {
+	public UnsupportedSecurityTypeException(String message) {
+		super(message);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/log/Logger.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,32 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.log;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class Logger {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/log/LoggerFactory.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,39 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.log;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class LoggerFactory {
+	public static Logger getLogger(String name) {
+		return null;
+	}
+
+	public static Logger getLogger(Class<?> klass) {
+		return getLogger(klass.getName());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/CapabilityContainer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,107 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Container for Tight extention protocol capabilities
+ *
+ * Needed to set what capabilities we support, which of them supported
+ * by server and for enabling/disabling ops on them.
+ */
+public class CapabilityContainer {
+	public CapabilityContainer() { }
+
+	private final Map<Integer, RfbCapabilityInfo> caps = new HashMap<Integer, RfbCapabilityInfo>();
+
+	public void add(RfbCapabilityInfo capabilityInfo) {
+		caps.put(capabilityInfo.getCode(), capabilityInfo);
+	}
+
+	public void add(int code, String vendor, String name) {
+		caps.put(code, new RfbCapabilityInfo(code, vendor, name));
+	}
+
+	public void addEnabled(int code, String vendor, String name) {
+		RfbCapabilityInfo capability = new RfbCapabilityInfo(code, vendor, name);
+		capability.setEnable(true);
+		caps.put(code, capability);
+	}
+
+	public void setEnable(int id, boolean enable) {
+		RfbCapabilityInfo c = caps.get(id);
+		if (c != null) {
+			c.setEnable(enable);
+		}
+	}
+
+	public void setAllEnable(boolean enable) {
+		for (RfbCapabilityInfo c : caps.values()) {
+			c.setEnable(enable);
+		}
+	}
+
+	public Collection<EncodingType> getEnabledEncodingTypes() {
+		Collection<EncodingType> types = new LinkedList<EncodingType>();
+		for (RfbCapabilityInfo c : caps.values()) {
+			if (c.isEnabled()) {
+				types.add(EncodingType.byId(c.getCode()));
+			}
+		}
+		return types;
+	}
+
+	public void read(Reader reader, int count) throws TransportException {
+		while (count-- > 0) {
+			RfbCapabilityInfo capInfoReceived = new RfbCapabilityInfo(reader);
+			Logger.getLogger("com.glavsoft.rfb").fine(capInfoReceived.toString());
+			RfbCapabilityInfo myCapInfo = caps.get(capInfoReceived.getCode());
+			if (myCapInfo != null) {
+				myCapInfo.setEnable(true);
+			}
+		}
+	}
+
+	public boolean isSupported(int code) {
+		RfbCapabilityInfo myCapInfo = caps.get(code);
+		if (myCapInfo != null)
+			return myCapInfo.isEnabled();
+		return false;
+	}
+
+	public boolean isSupported(RfbCapabilityInfo rfbCapabilityInfo) {
+		return isSupported(rfbCapabilityInfo.getCode());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/ClipboardController.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,59 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+/**
+ * Interface for handling clipboard texts
+ */
+public interface ClipboardController extends IChangeSettingsListener {
+	void updateSystemClipboard(byte[] bytes);
+
+	/**
+	 * Get text clipboard contens when needed send to remote, or null vise versa
+	 * Implement this method such a way in swing context, because swing's clipboard
+	 * update listener invoked only on DataFlavor changes not content changes.
+	 * Implement as returned null on systems where clipboard listeners work correctly.
+	 *
+	 * @return clipboad string contents if it is changed from last method call
+	 * or null when clipboard contains non text object or clipboard contents didn't changed
+	 */
+	String getRenewedClipboardText();
+
+	/**
+	 * Returns clipboard text content previously retrieved frim system clipboard by
+	 * updateSavedClippoardContent()
+	 *
+	 * @return clipboard text content
+	 */
+	String getClipboardText();
+
+	/**
+	 * Enable/disable clipboard transfer
+	 *
+	 * @param enable
+	 */
+	void setEnabled(boolean enable);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IChangeSettingsListener.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,34 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import com.glavsoft.core.SettingsChangedEvent;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public interface IChangeSettingsListener {
+	void settingsChanged(SettingsChangedEvent event);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IPasswordRetriever.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,29 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+public interface IPasswordRetriever {
+	String getPassword();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IRepaintController.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,42 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Interface for sending repaint event from worker thread to GUI thread
+ */
+public interface IRepaintController extends IChangeSettingsListener {
+	void repaintBitmap(FramebufferUpdateRectangle rect);
+	void repaintBitmap(int x, int y, int width, int height);
+	void repaintCursor();
+	void updateCursorPosition(short x, short y);
+	Renderer createRenderer(Reader reader, int width, int height, PixelFormat pixelFormat);
+	void setPixelFormat(PixelFormat pixelFormat);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/IRfbSessionListener.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,39 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+/**
+ * Fires Rfb session [start]-stop events
+ */
+public interface IRfbSessionListener {
+
+	/**
+	 * Fired after rfb session closed (threads stopped, other resources fried).
+	 * Note: this event may be fired from unpredictable thread.
+	 * @param reason reason to show why session closed
+	 */
+	void rfbSessionStopped(String reason);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/RfbCapabilityInfo.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,122 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Structure used to describe protocol options such as tunneling methods,
+ * authentication schemes and message types (protocol versions 3.7t, 3.8t).
+ * typedef struct _rfbCapabilityInfo {
+ *  CARD32 code;                // numeric identifier
+ *  CARD8 vendorSignature[4];   // vendor identification
+ *  CARD8 nameSignature[8];     // abbreviated option name
+ * } rfbCapabilityInfo;
+ */
+public class RfbCapabilityInfo {
+	/*
+	 * Vendors known by TightVNC: standard VNC/RealVNC, TridiaVNC, and TightVNC.
+	 * #define rfbStandardVendor "STDV"
+	 * #define rfbTridiaVncVendor "TRDV"
+	 * #define rfbTightVncVendor "TGHT"
+	 */
+	public static final String VENDOR_STANDARD = "STDV";
+	public static final String VENDOR_TRIADA = "TRDV";
+	public static final String VENDOR_TIGHT = "TGHT";
+
+	public static final String TUNNELING_NO_TUNNELING = "NOTUNNEL";
+
+	public static final String AUTHENTICATION_NO_AUTH = "NOAUTH__";
+	public static final String AUTHENTICATION_VNC_AUTH ="VNCAUTH_";
+
+	public static final String ENCODING_COPYRECT = "COPYRECT";
+	public static final String ENCODING_HEXTILE = "HEXTILE_";
+	public static final String ENCODING_ZLIB = "ZLIB____";
+	public static final String ENCODING_ZRLE = "ZRLE____";
+	public static final String ENCODING_RRE = "RRE_____";
+	public static final String ENCODING_TIGHT = "TIGHT___";
+	// "Pseudo" encoding types
+	public static final String ENCODING_RICH_CURSOR = "RCHCURSR";
+	public static final String ENCODING_CURSOR_POS = "POINTPOS";
+	public static final String ENCODING_DESKTOP_SIZE = "NEWFBSIZ";
+
+	private int code;
+	private String vendorSignature;
+	private String nameSignature;
+	private boolean enable;
+
+	public RfbCapabilityInfo(int code, String vendorSignature, String nameSignature) {
+		this.code = code;
+		this.vendorSignature = vendorSignature;
+		this.nameSignature = nameSignature;
+		enable = true;
+	}
+
+	public RfbCapabilityInfo(Reader reader) throws TransportException {
+		code = reader.readInt32();
+		vendorSignature = reader.readString(4);
+		nameSignature = reader.readString(8);
+	}
+
+	@Override
+	public boolean equals(Object otherObj) {
+		if (this == otherObj) { return true; }
+		if (null == otherObj) { return false; }
+		if (getClass() != otherObj.getClass()) { return false; }
+		RfbCapabilityInfo other = (RfbCapabilityInfo) otherObj;
+		return code == other.code &&
+			vendorSignature.equals(other.vendorSignature) &&
+			nameSignature.equals(other.nameSignature);
+	}
+
+	public void setEnable(boolean enable) {
+		this.enable = enable;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public String getVendorSignature() {
+		return vendorSignature;
+	}
+
+	public String getNameSignature() {
+		return nameSignature;
+	}
+
+	public boolean isEnabled() {
+		return enable;
+	}
+
+	@Override
+	public String toString() {
+		return "RfbCapabilityInfo: [code: " + code +
+		", vendor: " + vendorSignature +
+		", name: " + nameSignature +
+		"]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/ClientCutTextMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,61 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+/**
+ * ClientCutText
+ * The client has new ISO 8859-1 (Latin-1) text in its cut buffer. Ends of lines are repre-
+ * sented by the linefeed / newline character (value 10) alone. No carriage-return (value
+ * 13) is needed. There is currently no way to transfer text outside the Latin-1 character
+ * set.
+ * 1      - U8       - 6
+ * 3      -          - padding
+ * 4      - U32      - length
+ * length - U8 array - text
+ */
+public class ClientCutTextMessage implements ClientToServerMessage {
+	private final byte [] bytes;
+
+	public ClientCutTextMessage(byte[] bytes) {
+		this.bytes = bytes;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.write(CLIENT_CUT_TEXT);
+		writer.writeByte(0); writer.writeInt16(0); // padding
+		writer.write(bytes.length);
+		writer.write(bytes); // TODO: [dime] convert 'text' String to byte arrya using right charset
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "ClientCutTextMessage: [length: " + bytes.length +", text: ...]";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/ClientToServerMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,39 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+public interface ClientToServerMessage {
+	byte SET_PIXEL_FORMAT = 0;
+	byte SET_ENCODINGS = 2;
+	byte FRAMEBUFFER_UPDATE_REQUEST = 3;
+	byte KEY_EVENT = 4;
+	byte POINTER_EVENT = 5;
+	byte CLIENT_CUT_TEXT = 6;
+
+	void send(Writer writer) throws TransportException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/FramebufferUpdateRequestMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,65 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+
+public class FramebufferUpdateRequestMessage implements ClientToServerMessage {
+	private final boolean incremental;
+	private final int height;
+	private final int width;
+	private final int y;
+	private final int x;
+
+	public FramebufferUpdateRequestMessage(int x, int y, int width,
+			int height, boolean incremental) {
+		this.x = x;
+		this.y = y;
+		this.width = width;
+		this.height = height;
+		this.incremental = incremental;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(FRAMEBUFFER_UPDATE_REQUEST);
+		writer.writeByte(incremental ? 1 : 0);
+		writer.writeInt16(x);
+		writer.writeInt16(y);
+		writer.writeInt16(width);
+		writer.writeInt16(height);
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "FramebufferUpdateRequestMessage: [x: " + x + " y: " + y
+		+ " width: " + width + " height: " + height +
+		" incremental: " + incremental + "]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/KeyEventMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,67 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+/**
+ * A key press or release. Down-flag is non-zero (true) if the key is now pressed, zero
+ * (false) if it is now released. The key itself is specified using the “keysym” values
+ * defined by the X Window System.
+ * 1 - U8  - message-type
+ * 1 - U8  - down-flag
+ * 2 - -   - padding
+ * 4 - U32 - key
+ * For most ordinary keys, the “keysym” is the same as the corresponding ASCII value.
+ * For full details, see The Xlib Reference Manual, published by O’Reilly & Associates,
+ * or see the header file <X11/keysymdef.h> from any X Window System installa-
+ * tion.
+ */
+public class KeyEventMessage implements ClientToServerMessage {
+
+	private final int key;
+	private final boolean downFlag;
+
+	public KeyEventMessage(int key, boolean downFlag) {
+		this.downFlag = downFlag;
+		this.key = key;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(KEY_EVENT);
+		writer.writeByte(downFlag ? 1 : 0);
+		writer.writeInt16(0); // padding
+		writer.write(key);
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "[KeyEventMessage: [down-flag: "+downFlag + ", key: " + key +"("+Integer.toHexString(key)+")]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/PointerEventMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,56 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Writer;
+
+public class PointerEventMessage implements ClientToServerMessage {
+	private final byte buttonMask;
+	private final short x;
+	private final short y;
+
+	public PointerEventMessage(byte buttonMask, short x, short y) {
+		this.buttonMask = buttonMask;
+		this.x = x;
+		this.y = y;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(POINTER_EVENT);
+		writer.writeByte(buttonMask);
+		writer.writeInt16(x);
+		writer.writeInt16(y);
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		return "PointerEventMessage: [x: "+ x +", y: "+ y + ", button-mask: " +
+		buttonMask +"]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/SetEncodingsMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,61 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import java.util.Set;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.transport.Writer;
+
+public class SetEncodingsMessage implements ClientToServerMessage {
+	private final Set<EncodingType> encodings;
+
+	public SetEncodingsMessage(Set<EncodingType> set) {
+		this.encodings = set;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(SET_ENCODINGS);
+		writer.writeByte(0); // padding byte
+		writer.writeInt16(encodings.size());
+		for (EncodingType enc : encodings) {
+			writer.writeInt32(enc.getId());
+		}
+		writer.flush();
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("SetEncodingsMessage: [encodings: ");
+		for (EncodingType enc : encodings) {
+			sb.append(enc.name()).append(',');
+		}
+		sb.setLength(sb.length()-1);
+		return sb.append(']').toString();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/client/SetPixelFormatMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,47 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.client;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.transport.Writer;
+
+public class SetPixelFormatMessage implements ClientToServerMessage {
+	private final PixelFormat pixelFormat;
+
+	public SetPixelFormatMessage(PixelFormat pixelFormat) {
+		this.pixelFormat = pixelFormat;
+	}
+
+	@Override
+	public void send(Writer writer) throws TransportException {
+		writer.writeByte(SET_PIXEL_FORMAT);
+		writer.writeInt16(0);
+		writer.writeByte(0);
+		pixelFormat.send(writer);
+		writer.flush();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/EncodingType.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,147 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding;
+
+import java.util.LinkedHashSet;
+
+/**
+ * Encoding types
+ */
+public enum EncodingType {
+	/**
+	 * Desktop data representes as raw bytes stream
+	 */
+	RAW_ENCODING(0, "Raw"),
+	/**
+	 * Specfies encodings which allow to copy part of image in client's
+	 * framebuffer from one place to another.
+	 */
+	COPY_RECT(1, "CopyRect"),
+	RRE(2, "RRE"),
+	/**
+	 *  Hextile encoding, uses palettes, filling and raw subencoding
+	 */
+    HEXTILE(5, "Hextile"),
+    /**
+     * This encoding is like raw but previously all data compressed with zlib.
+     */
+    ZLIB(6, "ZLib"),
+	/**
+	 * Tight Encoding for slow connection. It is uses raw data, palettes, filling
+	 * and jpeg subencodings
+	 */
+	TIGHT(7, "Tight"),
+    //ZlibHex(8),
+	/**
+	 * ZRLE Encoding is like Hextile but previously all data compressed with zlib.
+	 */
+    ZRLE(16, "ZRLE"),
+
+    /**
+     * Rich Cursor pseudo encoding which allows to transfer cursor shape
+     * with transparency
+     */
+    RICH_CURSOR(0xFFFFFF11, "RichCursor"),
+    /**
+     * Desktop Size Pseudo encoding allows to notificate client about
+     *  remote screen resolution changed.
+     */
+    DESKTOP_SIZE(0xFFFFFF21, "DesctopSize"),
+    /**
+     * Cusros position encoding allows to transfer remote cursor position to
+     * client side.
+     */
+	CURSOR_POS(0xFFFFFF18, "CursorPos"),
+
+	COMPRESS_LEVEL_0(0xFFFFFF00 + 0, "CompressionLevel0"),
+	COMPRESS_LEVEL_1(0xFFFFFF00 + 1, "CompressionLevel1"),
+	COMPRESS_LEVEL_2(0xFFFFFF00 + 2, "CompressionLevel2"),
+	COMPRESS_LEVEL_3(0xFFFFFF00 + 3, "CompressionLevel3"),
+	COMPRESS_LEVEL_4(0xFFFFFF00 + 4, "CompressionLevel4"),
+	COMPRESS_LEVEL_5(0xFFFFFF00 + 5, "CompressionLevel5"),
+	COMPRESS_LEVEL_6(0xFFFFFF00 + 6, "CompressionLevel6"),
+	COMPRESS_LEVEL_7(0xFFFFFF00 + 7, "CompressionLevel7"),
+	COMPRESS_LEVEL_8(0xFFFFFF00 + 8, "CompressionLevel8"),
+	COMPRESS_LEVEL_9(0xFFFFFF00 + 9, "CompressionLevel9"),
+
+	JPEG_QUALITY_LEVEL_0(0xFFFFFFE0 + 0, "JpegQualityLevel0"),
+	JPEG_QUALITY_LEVEL_1(0xFFFFFFE0 + 1, "JpegQualityLevel1"),
+	JPEG_QUALITY_LEVEL_2(0xFFFFFFE0 + 2, "JpegQualityLevel2"),
+	JPEG_QUALITY_LEVEL_3(0xFFFFFFE0 + 3, "JpegQualityLevel3"),
+	JPEG_QUALITY_LEVEL_4(0xFFFFFFE0 + 4, "JpegQualityLevel4"),
+	JPEG_QUALITY_LEVEL_5(0xFFFFFFE0 + 5, "JpegQualityLevel5"),
+	JPEG_QUALITY_LEVEL_6(0xFFFFFFE0 + 6, "JpegQualityLevel6"),
+	JPEG_QUALITY_LEVEL_7(0xFFFFFFE0 + 7, "JpegQualityLevel7"),
+	JPEG_QUALITY_LEVEL_8(0xFFFFFFE0 + 8, "JpegQualityLevel8"),
+	JPEG_QUALITY_LEVEL_9(0xFFFFFFE0 + 9, "JpegQualityLevel9");
+
+	private int id;
+	private final String name;
+	private EncodingType(int id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public int getId() {
+		return id;
+	}
+	public String getName() {
+		return name;
+	}
+
+	public static LinkedHashSet<EncodingType> ordinaryEncodings = new LinkedHashSet<EncodingType>();
+	static {
+		ordinaryEncodings.add(TIGHT);
+		ordinaryEncodings.add(HEXTILE);
+		ordinaryEncodings.add(ZRLE);
+		ordinaryEncodings.add(ZLIB);
+		ordinaryEncodings.add(RRE);
+		ordinaryEncodings.add(COPY_RECT);
+//		ordinaryEncodings.add(RAW_ENCODING);
+	}
+
+	public static LinkedHashSet<EncodingType> pseudoEncodings = new LinkedHashSet<EncodingType>();
+	static {
+		pseudoEncodings.add(RICH_CURSOR);
+		pseudoEncodings.add(CURSOR_POS);
+		pseudoEncodings.add(DESKTOP_SIZE);
+	}
+
+	public static LinkedHashSet<EncodingType> compressionEncodings = new LinkedHashSet<EncodingType>();
+	static {
+		compressionEncodings.add(COMPRESS_LEVEL_0);
+		compressionEncodings.add(JPEG_QUALITY_LEVEL_0);
+	}
+
+	public static EncodingType byId(int id) {
+		// TODO needs to speedup with hash usage?
+		for (EncodingType type : values()) {
+			if (type.getId() == id)
+				return type;
+		}
+		throw new IllegalArgumentException("Unsupported encoding id: " + id);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/PixelFormat.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,187 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+/**
+ * Pixel Format:
+ * 1 - U8  - bits-per-pixel
+ * 1 - U8  - depth
+ * 1 - U8  - big-endian-flag
+ * 1 - U8  - true-color-flag
+ * 2 - U16 - red-max
+ * 2 - U16 - green-max
+ * 2 - U16 - blue-max
+ * 1 - U8  - red-shift
+ * 1 - U8  - green-shift
+ * 1 - U8  - blue-shift
+ * 3 -     - padding
+ */
+public class PixelFormat {
+	public byte bitsPerPixel;
+	public byte depth;
+	public byte bigEndianFlag;
+	public byte trueColourFlag;
+	public short redMax;
+	public short greenMax;
+	public short blueMax;
+	public byte redShift;
+	public byte greenShift;
+	public byte blueShift;
+
+	public void fill(Reader reader) throws TransportException {
+		bitsPerPixel = reader.readByte();
+		depth = reader.readByte();
+	    bigEndianFlag = reader.readByte();
+	    trueColourFlag = reader.readByte();
+	    redMax = reader.readInt16();
+	    greenMax = reader.readInt16();
+	    blueMax = reader.readInt16();
+	    redShift = reader.readByte();
+	    greenShift = reader.readByte();
+	    blueShift = reader.readByte();
+	    reader.readBytes(3); // skip padding bytes
+	}
+
+    public void send(Writer writer) throws TransportException {
+    	writer.write(bitsPerPixel);
+    	writer.write(depth);
+    	writer.write(bigEndianFlag);
+    	writer.write(trueColourFlag);
+    	writer.write(redMax);
+    	writer.write(greenMax);
+    	writer.write(blueMax);
+    	writer.write(redShift);
+    	writer.write(greenShift);
+    	writer.write(blueShift);
+    	writer.writeInt16(0); // padding bytes
+    	writer.writeByte(0); // padding bytes
+    }
+
+    public static PixelFormat create32bppPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 32;
+		pixelFormat.blueMax = 255;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 255;
+		pixelFormat.greenShift = 8;
+		pixelFormat.redMax = 255;
+		pixelFormat.redShift = 16;
+		pixelFormat.depth = 24;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 65536 colors, 5bit per Red, 6bit per Green, 5bit per Blue
+     */
+    public static PixelFormat create16bppPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 16;
+		pixelFormat.blueMax = 31;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 63;
+		pixelFormat.greenShift = 5;
+		pixelFormat.redMax = 31;
+		pixelFormat.redShift = 11;
+		pixelFormat.depth = 16;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 256 colors, 2bit per Blue, 3bit per Green & Red
+     */
+    public static PixelFormat create8bppBGRPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 8;
+		pixelFormat.redMax = 7;
+		pixelFormat.redShift = 0;
+		pixelFormat.greenMax = 7;
+		pixelFormat.greenShift = 3;
+		pixelFormat.blueMax = 3;
+		pixelFormat.blueShift = 6;
+		pixelFormat.depth = 8;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 64 colors, 2bit per Red, Green & Blue
+     */
+    public static PixelFormat create6bppPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 8;
+		pixelFormat.blueMax = 3;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 3;
+		pixelFormat.greenShift = 2;
+		pixelFormat.redMax = 3;
+		pixelFormat.redShift = 4;
+		pixelFormat.depth = 6;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    /**
+     * specifies 8 colors, 1bit per Red, Green & Blue
+     */
+    public static PixelFormat create3bppPixelFormat(int bigEndianFlag) {
+    	final PixelFormat pixelFormat = new PixelFormat();
+    	pixelFormat.bigEndianFlag = (byte) bigEndianFlag;
+		pixelFormat.bitsPerPixel = 8;
+		pixelFormat.blueMax = 1;
+		pixelFormat.blueShift = 0;
+		pixelFormat.greenMax = 1;
+		pixelFormat.greenShift = 1;
+		pixelFormat.redMax = 1;
+		pixelFormat.redShift = 2;
+		pixelFormat.depth = 3;
+		pixelFormat.trueColourFlag = 1;
+		return pixelFormat;
+    }
+
+    @Override
+    public String toString() {
+    	return "PixelFormat: [bits-per-pixel: " + String.valueOf(0xff & bitsPerPixel) +
+    	", depth: " + String.valueOf(0xff & depth) +
+    	", big-endian-flag: " + String.valueOf(0xff & bigEndianFlag) +
+    	", true-color-flag: " + String.valueOf(0xff & trueColourFlag) +
+    	", red-max: " + String.valueOf(0xffff & redMax) +
+    	", green-max: " + String.valueOf(0xffff & greenMax) +
+    	", blue-max: " + String.valueOf(0xffff & blueMax) +
+    	", red-shift: " + String.valueOf(0xff & redShift) +
+    	", green-shift: " + String.valueOf(0xff & greenShift) +
+    	", blue-shift: " + String.valueOf(0xff & blueShift) +
+    	"]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/ServerInitMessage.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,80 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Struct filled from the ServerInit message
+ * 2  - U16         - framebuffer-width
+ * 2  - U16         - framebuffer-height
+ * 16 - PixelFormat - server-pixel-format
+ * 4  - U32         - name-length
+ * name-length - U8 array - name-string
+ */
+public class ServerInitMessage {
+	protected int frameBufferWidth;
+    protected int frameBufferHeight;
+    protected PixelFormat pixelFormat;
+    protected String name;
+
+	public ServerInitMessage(Reader reader) throws TransportException {
+		frameBufferWidth = reader.readUInt16();
+		frameBufferHeight = reader.readUInt16();
+		pixelFormat = new PixelFormat();
+		pixelFormat.fill(reader);
+		name = reader.readString();
+	}
+
+	protected ServerInitMessage() {
+		// empty
+	}
+
+	public int getFrameBufferWidth() {
+		return frameBufferWidth;
+	}
+
+	public int getFrameBufferHeight() {
+		return frameBufferHeight;
+	}
+
+	public PixelFormat getPixelFormat() {
+		return pixelFormat;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+    @Override
+    public String toString() {
+    	return "ServerInitMessage: [name: "+ name +
+    	", framebuffer-width: " + String.valueOf(frameBufferWidth) +
+    	", framebuffer-height: " + String.valueOf(frameBufferHeight) +
+    	", server-pixel-format: " + pixelFormat +
+    	"]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ByteBuffer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,58 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+/**
+ * Resizeable to needed length byte buffer
+ * Singleton for share among decoders.
+ */
+public class ByteBuffer {
+	private static ByteBuffer instance = new ByteBuffer();
+	private byte [] buffer = new byte[0];
+
+	private ByteBuffer() { /*empty*/ }
+	public static ByteBuffer getInstance() {
+		return instance;
+	}
+
+	/**
+	 * Checks for buffer capacity is enougth ( < length) and enlarge it if not
+	 *
+	 * @param length
+	 */
+	public void correctBufferCapacity(int length) {
+		// procondition: buffer != null
+		assert (buffer != null);
+		if (buffer.length < length) {
+			buffer = new byte[length];
+		}
+	}
+
+	public byte[] getBuffer(int length) {
+		correctBufferCapacity(length);
+		return buffer;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/CopyRectDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,42 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class CopyRectDecoder extends Decoder {
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int srcX = reader.readUInt16();
+		int srcY = reader.readUInt16();
+		if (rect.width == 0  || rect.height == 0) return;
+		renderer.copyRect(srcX, srcY, rect);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/Decoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,45 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+
+public abstract class Decoder {
+
+	/**
+	 * Decode rectangle data.
+	 */
+	abstract public void decode(Reader reader, Renderer renderer,
+    		FramebufferUpdateRectangle rect) throws TransportException;
+
+	/**
+	 * Reset decoder when needed. Ex. reset ZLib stream inflaters for Z* and Tight decoders.
+	 */
+    public void reset() { /*empty*/ }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/DecodersContainer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,93 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.rfb.encoding.EncodingType;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+
+/**
+ * Decoders container class
+ */
+public class DecodersContainer {
+	private static Map<EncodingType, Class<? extends Decoder>> knownDecoders =
+		new HashMap<EncodingType, Class<? extends Decoder>>();
+	static {
+		knownDecoders.put(EncodingType.TIGHT, TightDecoder.class);
+		knownDecoders.put(EncodingType.HEXTILE, HextileDecoder.class);
+		knownDecoders.put(EncodingType.ZRLE, ZRLEDecoder.class);
+		knownDecoders.put(EncodingType.ZLIB, ZlibDecoder.class);
+		knownDecoders.put(EncodingType.RRE, RREDecoder.class);
+		knownDecoders.put(EncodingType.COPY_RECT, CopyRectDecoder.class);
+//		knownDecoders.put(EncodingType.RAW_ENCODING, RawDecoder.class);
+	}
+	private final Map<EncodingType, Decoder> decoders =
+		new HashMap<EncodingType, Decoder>();
+
+	public DecodersContainer() {
+		decoders.put(EncodingType.RAW_ENCODING, RawDecoder.getInstance());
+	}
+
+	/**
+	 * Instantiate decoders for encodings we are going to use.
+	 *
+	 * @param encodings encodings we need to handle
+	 */
+	public void instantiateDecodersWhenNeeded(Collection<EncodingType> encodings) {
+		for (EncodingType enc : encodings) {
+			if (EncodingType.ordinaryEncodings.contains(enc) && ! decoders.containsKey(enc)) {
+				try {
+					decoders.put(enc, knownDecoders.get(enc).newInstance());
+				} catch (InstantiationException e) {
+					logError(enc, e);
+				} catch (IllegalAccessException e) {
+					logError(enc, e);
+				}
+			}
+		}
+	}
+
+	private void logError(EncodingType enc, Exception e) {
+		Logger.getLogger(this.getClass().getName()).severe("Can not instantiate decoder for encoding type '" +
+				enc.getName() + "' " + e.getMessage());
+	}
+
+	public Decoder getDecoderByType(EncodingType type) {
+		return decoders.get(type);
+	}
+
+	public void resetDecoders() {
+		for (Decoder decoder : decoders.values()) {
+			if (decoder != null) {
+				decoder.reset();
+			}
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/FramebufferUpdateRectangle.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,77 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Header for framebuffer-update-rectangle header server message
+ * 2 - U16 - x-position
+ * 2 - U16 - y-position
+ * 2 - U16 - width
+ * 2 - U16 - height
+ * 4 - S32 - encoding-type
+ * and then follows the pixel data in the specified encoding
+ */
+public class FramebufferUpdateRectangle {
+	public int x;
+	public int y;
+	public int width;
+	public int height;
+    private EncodingType encodingType;
+
+	public FramebufferUpdateRectangle() {
+		// nop
+	}
+
+	public FramebufferUpdateRectangle(int x, int y, int w, int h) {
+		this.x = x; this.y = y;
+		width = w; height = h;
+	}
+
+	public void fill(Reader reader) throws TransportException {
+    	x = reader.readUInt16();
+        y = reader.readUInt16();
+        width = reader.readUInt16();
+        height = reader.readUInt16();
+        int encoding = reader.readInt32();
+		encodingType = EncodingType.byId(encoding);
+    }
+
+	public EncodingType getEncodingType() {
+		return encodingType;
+	}
+
+	@Override
+	public String toString() {
+		return "FramebufferUpdateRect: [x: " + x + ", y: " + y +
+			", width: " + width + ", height: " + height +
+			", encodingType: " + encodingType +
+			"]";
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/HextileDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,110 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+
+public class HextileDecoder extends Decoder {
+	private static final int DEFAULT_TILE_SIZE = 16;
+	private static final int RAW_MASK = 1;
+	private static final int BACKGROUND_SPECIFIED_MASK = 2;
+	private static final int FOREGROUND_SPECIFIED_MASK = 4;
+	private static final int ANY_SUBRECTS_MASK = 8;
+	private static final int SUBRECTS_COLOURED_MASK = 16;
+	private static final int FG_COLOR_INDEX = 0;
+	private static final int BG_COLOR_INDEX = 1;
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		if (rect.width == 0  || rect.height == 0) return;
+		int[] colors = new int[] {-1, -1};
+		int maxX = rect.x + rect.width;
+		int maxY = rect.y + rect.height;
+		for (int tileY = rect.y; tileY < maxY;
+		tileY += DEFAULT_TILE_SIZE) {
+			int tileHeight = Math.min(maxY - tileY, DEFAULT_TILE_SIZE);
+			for (int tileX = rect.x; tileX < maxX;
+			tileX += DEFAULT_TILE_SIZE) {
+				int tileWidth = Math.min(maxX - tileX, DEFAULT_TILE_SIZE);
+				decodeHextileSubrectangle(reader, renderer, colors, tileX,
+						tileY, tileWidth, tileHeight);
+			}
+		}
+
+	}
+
+	private void decodeHextileSubrectangle(Reader reader,
+			Renderer renderer, int[] colors,
+			int tileX, int tileY, int tileWidth, int tileHeight)
+			throws TransportException {
+
+		int subencoding = reader.readUInt8();
+
+		if ((subencoding & RAW_MASK) != 0) {
+			RawDecoder.getInstance().decode(reader, renderer,
+					tileX, tileY, tileWidth, tileHeight);
+			return;
+		}
+
+		if ((subencoding & BACKGROUND_SPECIFIED_MASK) != 0) {
+			colors[BG_COLOR_INDEX] = renderer.readPixelColor(reader);
+		}
+		assert colors[BG_COLOR_INDEX] != -1;
+		renderer.fillRect(colors[BG_COLOR_INDEX],
+				tileX, tileY, tileWidth, tileHeight);
+
+		if ((subencoding & FOREGROUND_SPECIFIED_MASK) != 0) {
+			colors[FG_COLOR_INDEX] = renderer.readPixelColor(reader);
+		}
+
+		if ((subencoding & ANY_SUBRECTS_MASK) == 0)
+			return;
+
+		int numberOfSubrectangles = reader.readUInt8();
+		boolean colorSpecified =
+			(subencoding & SUBRECTS_COLOURED_MASK) != 0;
+		for (int i = 0; i < numberOfSubrectangles; ++i) {
+			if (colorSpecified) {
+				colors[FG_COLOR_INDEX] = renderer.readPixelColor(reader);
+			}
+			byte dimensions = reader.readByte(); // bits 7-4 for x, bits 3-0 for y
+			int subtileX = dimensions >> 4 & 0x0f;
+			int subtileY = dimensions & 0x0f;
+			dimensions = reader.readByte(); // bits 7-4 for w, bits 3-0 for h
+			int subtileWidth = 1 + (dimensions >> 4 & 0x0f);
+			int subtileHeight = 1 + (dimensions & 0x0f);
+			assert colors[FG_COLOR_INDEX] != -1;
+			renderer.fillRect(colors[FG_COLOR_INDEX],
+					tileX + subtileX, tileY + subtileY,
+					subtileWidth, subtileHeight);
+		}
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/RREDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,50 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class RREDecoder extends Decoder {
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int numOfSubrectangles = reader.readInt32();
+		int color = renderer.readPixelColor(reader);
+		renderer.fillRect(color, rect);
+		for (int i = 0; i < numOfSubrectangles; ++i) {
+			color = renderer.readPixelColor(reader);
+			int x = reader.readUInt16();
+			int y = reader.readUInt16();
+			int width = reader.readUInt16();
+			int height = reader.readUInt16();
+			renderer.fillRect(color, rect.x + x, rect.y + y, width, height);
+		}
+
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/RawDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,52 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class RawDecoder extends Decoder {
+	private static RawDecoder instance = new RawDecoder();
+	public static RawDecoder getInstance() {
+		return instance;
+	}
+	private RawDecoder() { /*empty*/ }
+
+	@Override
+	public void decode(Reader reader,
+			Renderer renderer, FramebufferUpdateRectangle rect) throws TransportException {
+		decode(reader, renderer, rect.x, rect.y, rect.width, rect.height);
+	}
+
+	public void decode(Reader reader, Renderer renderer, int x, int y,
+			int width, int height) throws TransportException {
+		int length = width * height * renderer.getBytesPerPixel();
+		byte [] bytes = ByteBuffer.getInstance().getBuffer(length);
+		reader.readBytes(bytes, 0, length);
+		renderer.drawBytes(bytes, x, y, width, height);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/RichCursorDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,81 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Decoder for RichCursor pseudo encoding
+ */
+public class RichCursorDecoder extends Decoder {
+	private static RichCursorDecoder instance = new RichCursorDecoder();
+
+	private RichCursorDecoder() { /*empty*/ }
+
+	public static RichCursorDecoder getInstance() {
+		return instance;
+	}
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int bytesPerPixel = renderer.getBytesPerPixel();
+		int length = rect.width * rect.height * bytesPerPixel;
+		if (0 == length)
+			return;
+		byte[] buffer = ByteBuffer.getInstance().getBuffer(length);
+		reader.readBytes(buffer, 0, length);
+
+		StringBuilder sb = new StringBuilder(" ");
+		for (int i=0; i<length; ++i) {
+			sb.append(Integer.toHexString(buffer[i]&0xff)).append(" ");
+		}
+		int scanLine = (int) Math.floor((rect.width + 7) / 8);
+		byte[] bitmask = new byte[scanLine * rect.height];
+		reader.readBytes(bitmask, 0, bitmask.length);
+
+		sb = new StringBuilder(" ");
+		for (int i=0; i<bitmask.length; ++i) {
+			sb.append(Integer.toHexString(bitmask[i]&0xff)).append(" ");
+		}
+		int[] cursorPixels = new int[rect.width * rect.height];
+		for (int y = 0; y < rect.height; ++y) {
+			for (int x = 0; x < rect.width; ++x) {
+				int offset = y * rect.width + x;
+				cursorPixels[offset] = isBitSet(bitmask[y * scanLine + x / 8], x % 8) ?
+					0xFF000000 | renderer.getPixelColor(buffer, offset * bytesPerPixel) :
+					0; // transparent
+			}
+		}
+		renderer.createCursor(cursorPixels, rect);
+	}
+
+	private boolean isBitSet(byte aByte, int index) {
+		return (aByte & 1 << 7 - index) > 0;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/TightDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,301 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import java.util.logging.Logger;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import com.glavsoft.drawing.ColorDecoder;
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+/**
+ * Tight protocol extention decoder
+ */
+public class TightDecoder extends Decoder {
+	private static Logger logger = Logger.getLogger("com.glavsoft.rfb.encoding.decoder");
+
+    private static final int FILL_TYPE = 0x08;
+    private static final int JPEG_TYPE = 0x09;
+
+    private static final int FILTER_ID_MASK = 0x40;
+    private static final int STREAM_ID_MASK = 0x30;
+
+    private static final int BASIC_FILTER = 0x00;
+    private static final int PALETTE_FILTER = 0x01;
+    private static final int GRADIENT_FILTER = 0x02;
+    private static final int MIN_SIZE_TO_COMPRESS = 12;
+
+    static final int DECODERS_NUM = 4;
+	Inflater[] decoders;
+
+    private int decoderId;
+
+    final static int tightZlibBufferSize = 512;
+
+	public TightDecoder() {
+		reset();
+	}
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int bytesPerPixel = renderer.getBytesPerPixelSignificant();
+
+		/**
+		 * bits
+		 * 7 - FILL or JPEG type
+		 * 6 - filter presence flag
+		 * 5, 4 - decoder to use when Basic type (bit 7 not set)
+		 *    or
+		 * 4 - JPEG type when set bit 7
+		 * 3 - reset decoder #3
+		 * 2 - reset decoder #2
+		 * 1 - reset decoder #1
+		 * 0 - reset decoder #0
+		 */
+		int compControl = reader.readUInt8();
+		resetDecoders(compControl);
+
+		int compType = compControl >> 4 & 0x0F;
+		switch (compType) {
+		case FILL_TYPE:
+			int color = renderer.readTightPixelColor(reader);
+			renderer.fillRect(color, rect);
+			break;
+		case JPEG_TYPE:
+			if (bytesPerPixel != 3) {
+//				throw new EncodingException(
+//						"Tight doesn't support JPEG subencoding while depth not equal to 24bpp is used");
+			}
+			processJpegType(reader, renderer, rect);
+			break;
+		default:
+			if (compType > JPEG_TYPE) {
+//				throw new EncodingException(
+//						"Compression control byte is incorrect!");
+			} else {
+				processBasicType(compControl, reader, renderer, rect);
+			}
+		}
+	}
+
+	private void processBasicType(int compControl, Reader reader,
+			Renderer renderer, FramebufferUpdateRectangle rect) throws TransportException {
+		decoderId = (compControl & STREAM_ID_MASK) >> 4;
+
+		int filterId = 0;
+		if ((compControl & FILTER_ID_MASK) > 0) { // filter byte presence
+			filterId = reader.readUInt8();
+		}
+		int bytesPerCPixel = renderer.getBytesPerPixelSignificant();
+		int lengthCurrentbpp = bytesPerCPixel * rect.width * rect.height;
+		byte [] buffer;
+		switch (filterId) {
+		case BASIC_FILTER:
+			buffer = readTightData(lengthCurrentbpp, reader);
+			renderer.drawTightBytes(buffer, 0, rect.x, rect.y, rect.width, rect.height);
+			break;
+		case PALETTE_FILTER:
+			int paletteSize = reader.readUInt8() + 1;
+			int[] palette = readPalette(paletteSize, reader, renderer);
+			int dataLength = paletteSize == 2 ?
+				rect.height * ((rect.width + 7) / 8) :
+				rect.width * rect.height;
+			buffer = readTightData(dataLength, reader);
+			renderer.drawBytesWithPalette(buffer, rect, palette);
+			break;
+		case GRADIENT_FILTER:
+/*
+ * The "gradient" filter pre-processes pixel data with a simple algorithm
+ * which converts each color component to a difference between a "predicted"
+ * intensity and the actual intensity. Such a technique does not affect
+ * uncompressed data size, but helps to compress photo-like images better.
+ * Pseudo-code for converting intensities to differences is the following:
+ *
+ * 	P[i,j] := V[i-1,j] + V[i,j-1] - V[i-1,j-1];
+ * 	if (P[i,j] < 0) then P[i,j] := 0;
+ * 	if (P[i,j] > MAX) then P[i,j] := MAX;
+ * 	D[i,j] := V[i,j] - P[i,j];
+ *
+ * Here V[i,j] is the intensity of a color component for a pixel at
+ * coordinates (i,j). MAX is the maximum value of intensity for a color
+ * component.*/
+			buffer = readTightData(bytesPerCPixel * rect.width * rect.height, reader);
+			byte [][] opRows = new byte[2][rect.width * 3 + 3];
+			int opRowIndex = 0;
+			byte [] components = new byte[3];
+			int pixelOffset = 0;
+			ColorDecoder colorDecoder = renderer.getColorDecoder();
+			for (int i = 0; i < rect.height; ++i) {
+				// exchange thisRow and prevRow:
+				byte [] thisRow = opRows[opRowIndex];
+				byte [] prevRow = opRows[opRowIndex = (opRowIndex + 1) % 2];
+				for (int j = 3; j < rect.width * 3 + 3; j += 3) {
+					colorDecoder.fillRawComponents(components, buffer, pixelOffset);
+					pixelOffset += bytesPerCPixel;
+					int
+					d = (0xff & prevRow[j + 0]) + // "upper" pixel (from prev row)
+						(0xff & thisRow[j + 0 - 3]) - // prev pixel
+						(0xff & prevRow[j + 0 - 3]); // "diagonal" prev pixel
+					thisRow[j + 0] = (byte) (components[0] + (d < 0 ? 0 : d > colorDecoder.redMax ? colorDecoder.redMax: d) & colorDecoder.redMax);
+					d = (0xff & prevRow[j + 1]) +
+						(0xff & thisRow[j + 1 - 3]) -
+						(0xff & prevRow[j + 1 - 3]);
+					thisRow[j + 1] = (byte) (components[1] + (d < 0 ? 0 : d > colorDecoder.greenMax ? colorDecoder.greenMax: d) & colorDecoder.greenMax);
+					d = (0xff & prevRow[j + 2]) +
+						(0xff & thisRow[j + 2 - 3]) -
+						(0xff & prevRow[j + 2 - 3]);
+					thisRow[j + 2] = (byte) (components[2] + (d < 0 ? 0 : d > colorDecoder.blueMax ? colorDecoder.blueMax: d) & colorDecoder.blueMax);
+				}
+				renderer.drawUncaliberedRGBLine(thisRow, rect.x, rect.y + i, rect.width);
+			}
+
+			break;
+		default:
+			break;
+		}
+	}
+
+	/**
+	 * Read palette from reader
+	 */
+	private int[] readPalette(int paletteSize, Reader reader, Renderer renderer) throws TransportException {
+		/**
+		 * When bytesPerPixel == 1 && paletteSize == 2 read 2 bytes of palette
+		 * When bytesPerPixel == 1 && paletteSize != 2 - error
+		 * When bytesPerPixel == 3 (4) read (paletteSize * 3) bytes of palette
+		 * so use renderer.readPixelColor
+		 */
+		int[] palette = new int[paletteSize];
+		for (int i = 0; i < palette.length; ++i) {
+			palette[i] = renderer.readTightPixelColor(reader);
+		}
+		return palette;
+	}
+
+	/**
+	 * Reads compressed (expected length >= MIN_SIZE_TO_COMPRESS) or
+	 * uncompressed data. When compressed decompresses it.
+	 *
+	 * @param expectedLength expected data length in bytes
+	 * @param reader
+	 * @return result data
+	 * @throws TransportException
+	 */
+	private byte[] readTightData(int expectedLength, Reader reader) throws TransportException {
+		if (expectedLength < MIN_SIZE_TO_COMPRESS) {
+			byte [] buffer = ByteBuffer.getInstance().getBuffer(expectedLength);
+			reader.readBytes(buffer, 0, expectedLength);
+			return buffer;
+		} else
+			return readCompressedData(expectedLength, reader);
+	}
+
+	/**
+	 * Reads compressed data length, then read compressed data into rawBuffer
+     * and decompress data with expected length == length
+     *
+     * Note: returned data contains not only decompressed data but raw data at array tail
+     * which need to be ignored. Use only first expectedLength bytes.
+     *
+	 * @param expectedLength expected data length
+	 * @param reader
+	 * @return decompressed data (length == expectedLength) / + followed raw data (ignore, please)
+	 * @throws TransportException
+	 */
+	private byte[] readCompressedData(int expectedLength, Reader reader) throws TransportException {
+		int rawDataLength = readCompactSize(reader);
+
+		byte [] buffer = ByteBuffer.getInstance().getBuffer(expectedLength + rawDataLength);
+		// read compressed (raw) data behind space allocated for decompressed data
+		reader.readBytes(buffer, expectedLength, rawDataLength);
+		if (null == decoders[decoderId]) {
+			decoders[decoderId] = new Inflater();
+		}
+		Inflater decoder = decoders[decoderId];
+		decoder.setInput(buffer, expectedLength, rawDataLength);
+		try {
+			decoder.inflate(buffer, 0, expectedLength);
+		} catch (DataFormatException e) {
+			logger.throwing("TightDecoder", "readCompressedData", e);
+			throw new TransportException("cannot inflate tight compressed data", e);
+		}
+		return buffer;
+	}
+
+	private void processJpegType(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int jpegBufferLength = readCompactSize(reader);
+		byte [] bytes = ByteBuffer.getInstance().getBuffer(jpegBufferLength);
+		reader.readBytes(bytes, 0, jpegBufferLength);
+		renderer.drawJpegImage(bytes, 0, jpegBufferLength, rect);
+	}
+
+	/**
+	 * Read an integer from reader in compact representation (from 1 to 3 bytes).
+	 * Highest bit of read byte set to 1 means next byte contains data.
+	 * Lower 7 bit of each byte contains significant data. Max bytes = 3.
+	 * Less significant bytes first order.
+	 *
+	 * @param reader
+	 * @return int value
+	 * @throws TransportException
+	 */
+	private int readCompactSize(Reader reader) throws TransportException {
+		int b = reader.readUInt8();
+		int size = b & 0x7F;
+		if ((b & 0x80) != 0) {
+			b = reader.readUInt8();
+			size += (b & 0x7F) << 7;
+			if ((b & 0x80) != 0) {
+				size += reader.readUInt8() << 14;
+			}
+		}
+		return size;
+	}
+
+	/**
+	 * Flush (reset) zlib decoders when bits 3, 2, 1, 0 of compControl is set
+	 * @param compControl
+	 */
+	private void resetDecoders(int compControl) {
+		for (int i=0; i < DECODERS_NUM; ++i) {
+			if ((compControl & 1) != 0 && decoders[i] != null) {
+				decoders[i].reset();
+			}
+			compControl >>= 1;
+		}
+
+	}
+
+	@Override
+	public void reset() {
+		decoders = new Inflater[DECODERS_NUM];
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,165 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+public class ZRLEDecoder extends ZlibDecoder {
+	private static final int DEFAULT_TILE_SIZE = 64;
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int zippedLength = (int) reader.readUInt32();
+		if (0 == zippedLength) return;
+		int length = rect.width * rect.height * renderer.getBytesPerPixel();
+		byte[] bytes = unzip(reader, zippedLength, length);
+		int offset = zippedLength;
+		int maxX = rect.x + rect.width;
+		int maxY = rect.y + rect.height;
+		int [] palette = new int [128];
+		for (int tileY = rect.y; tileY < maxY; tileY += DEFAULT_TILE_SIZE) {
+			int tileHeight = Math.min(maxY - tileY, DEFAULT_TILE_SIZE);
+
+			for (int tileX = rect.x; tileX < maxX; tileX += DEFAULT_TILE_SIZE) {
+				int tileWidth = Math.min(maxX - tileX, DEFAULT_TILE_SIZE);
+				int subencoding = bytes[offset++] & 0x0ff;
+				// 128 -plain RLE, 130-255 - Palette RLE
+				boolean isRle = (subencoding & 128) != 0;
+				// 2 to 16 for raw packed palette data, 130 to 255 for Palette RLE (subencoding - 128)
+				int paletteSize = subencoding & 127;
+				offset += readPalette(bytes, offset, renderer, palette, paletteSize);
+				if (1 == subencoding) { // A solid tile consisting of a single colour
+					renderer.fillRect(palette[0], tileX, tileY, tileWidth, tileHeight);
+					continue;
+				}
+				if (isRle) {
+					if (0 == paletteSize) { // subencoding == 128 (or paletteSize == 0) - Plain RLE
+						offset += decodePlainRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+					} else {
+						offset += decodePaletteRle(bytes, offset, renderer, palette, tileX, tileY, tileWidth, tileHeight, paletteSize);
+					}
+				} else {
+					if (0 == paletteSize) { // subencoding == 0 (or paletteSize == 0) - raw CPIXEL data
+						offset += decodeRaw(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+					} else {
+						offset += decodePacked(bytes, offset, renderer, palette, paletteSize, tileX, tileY, tileWidth, tileHeight);
+					}
+				}
+			}
+		}
+
+	}
+
+	private int decodePlainRle(byte[] bytes, int offset, Renderer renderer,
+			int tileX, int tileY, int tileWidth, int tileHeight) {
+		int bytesPerCPixel = renderer.getBytesPerPixelSignificant();
+		int [] decodedBitmap = new int[tileWidth * tileHeight];
+		int decodedOffset = 0;
+		int decodedEnd = tileWidth * tileHeight;
+		int index = offset;
+		while (decodedOffset < decodedEnd) {
+			int color = renderer.getCompactPixelColor(bytes, index);
+			index += bytesPerCPixel;
+			int rlength = 1;
+			do {
+				rlength += bytes[index] & 0x0ff;
+			} while ((bytes[index++] & 0x0ff) == 255);
+			assert rlength <= decodedEnd - decodedOffset;
+			renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, rlength, color);
+			decodedOffset += rlength;
+		}
+		renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight);
+		return index - offset;
+	}
+
+	private int decodePaletteRle(byte[] bytes, int offset, Renderer renderer,
+			int[] palette, int tileX, int tileY, int tileWidth, int tileHeight, int paletteSize) {
+		int [] decodedBitmap = new int[tileWidth * tileHeight];
+		int decodedOffset = 0;
+		int decodedEnd = tileWidth * tileHeight;
+		int index = offset;
+		while (decodedOffset < decodedEnd) {
+			int colorIndex = bytes[index++];
+			int color = palette[colorIndex & 127];
+			int rlength = 1;
+			if ((colorIndex & 128) != 0) {
+				do {
+					rlength += bytes[index] & 0x0ff;
+				} while (bytes[index++] == (byte) 255);
+			}
+			assert rlength <= decodedEnd - decodedOffset;
+			renderer.fillColorBitmapWithColor(decodedBitmap, decodedOffset, rlength, color);
+			decodedOffset += rlength;
+		}
+		renderer.drawColoredBitmap(decodedBitmap, tileX, tileY, tileWidth, tileHeight);
+		return index - offset;
+	}
+
+	private int decodePacked(byte[] bytes, int offset, Renderer renderer,
+			int[] palette, int paletteSize, int tileX, int tileY, int tileWidth, int tileHeight) {
+		int [] decodedBytes = new int[tileWidth * tileHeight];
+		int bitsPerPalletedPixel = paletteSize > 16 ? 8 : paletteSize > 4 ? 4
+				: paletteSize > 2 ? 2 : 1;
+		int packedOffset = offset;
+		int decodedOffset = 0;
+		for (int i = 0; i < tileHeight; ++i) {
+			int decodedRowEnd = decodedOffset + tileWidth;
+			int byteProcessed = 0;
+			int bitsRemain = 0;
+
+			while (decodedOffset < decodedRowEnd) {
+				if (bitsRemain == 0) {
+					byteProcessed = bytes[packedOffset++];
+					bitsRemain = 8;
+				}
+				bitsRemain -= bitsPerPalletedPixel;
+				int index = byteProcessed >> bitsRemain & (1 << bitsPerPalletedPixel) - 1 & 127;
+				int color = palette[index];
+				renderer.fillColorBitmapWithColor(decodedBytes, decodedOffset, 1, color);
+				++decodedOffset;
+			}
+		}
+		renderer.drawColoredBitmap(decodedBytes, tileX, tileY, tileWidth, tileHeight);
+		return packedOffset - offset;
+	}
+
+	private int decodeRaw(byte[] bytes, int offset, Renderer renderer,
+			int tileX, int tileY, int tileWidth, int tileHeight) throws TransportException {
+		return renderer.drawCompactBytes(bytes, offset, tileX, tileY, tileWidth, tileHeight);
+	}
+
+	private int readPalette(byte[] bytes, int offset, Renderer renderer,
+			int[] palette, int paletteSize) {
+		for (int i=0; i<paletteSize; ++i) {
+			palette[i] = renderer.getCompactPixelColor(bytes,
+					offset + i*renderer.getBytesPerPixelSignificant());
+		}
+		return paletteSize * renderer.getBytesPerPixelSignificant();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZlibDecoder.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,72 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.encoding.decoder;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.transport.Reader;
+
+import java.io.ByteArrayInputStream;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+public class ZlibDecoder extends Decoder {
+	private Inflater decoder;
+
+	@Override
+	public void decode(Reader reader, Renderer renderer,
+			FramebufferUpdateRectangle rect) throws TransportException {
+		int zippedLength = (int) reader.readUInt32();
+		if (0 == zippedLength) return;
+		int length = rect.width * rect.height * renderer.getBytesPerPixel();
+		byte[] bytes = unzip(reader, zippedLength, length);
+		Reader unzippedReader =
+			new Reader(
+					new ByteArrayInputStream(bytes, zippedLength, length));
+		RawDecoder.getInstance().decode(unzippedReader, renderer, rect);
+	}
+
+	protected byte[] unzip(Reader reader, int zippedLength, int length)
+			throws TransportException {
+		byte [] bytes = ByteBuffer.getInstance().getBuffer(zippedLength + length);
+		reader.readBytes(bytes, 0, zippedLength);
+		if (null == decoder) {
+			decoder = new Inflater();
+		}
+		decoder.setInput(bytes, 0, zippedLength);
+		try {
+			decoder.inflate(bytes, zippedLength, length);
+		} catch (DataFormatException e) {
+			throw new TransportException("cannot inflate Zlib data", e);
+		}
+		return bytes;
+	}
+
+	@Override
+	public void reset() {
+		decoder = null;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/LocalPointer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,34 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+/**
+ * How to track local mouse cursor.
+ */
+public enum LocalPointer {
+	ON,
+	OFF,
+	HIDE,
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/MessageQueue.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,50 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import com.glavsoft.rfb.client.ClientToServerMessage;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class MessageQueue {
+	private final BlockingQueue<ClientToServerMessage> queue;
+
+	public MessageQueue() {
+		queue = new LinkedBlockingQueue<ClientToServerMessage>();
+	}
+
+	public void put(ClientToServerMessage message) {
+		queue.offer(message);
+	}
+
+	public ClientToServerMessage get() throws InterruptedException {
+		return queue.take();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/Protocol.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,278 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.exceptions.*;
+import com.glavsoft.rfb.*;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.rfb.client.FramebufferUpdateRequestMessage;
+import com.glavsoft.rfb.client.SetEncodingsMessage;
+import com.glavsoft.rfb.client.SetPixelFormatMessage;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.DecodersContainer;
+import com.glavsoft.rfb.protocol.state.HandshakeState;
+import com.glavsoft.rfb.protocol.state.ProtocolState;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+import java.util.logging.Logger;
+
+public class Protocol implements ProtocolContext, IChangeSettingsListener {
+	private ProtocolState state;
+	private final Logger logger = Logger.getLogger("com.glavsoft.rfb.protocol");
+	private final IPasswordRetriever passwordRetriever;
+	private final ProtocolSettings settings;
+	private int fbWidth;
+	private int fbHeight;
+	private PixelFormat pixelFormat;
+	private final Reader reader;
+	private final Writer writer;
+	private String remoteDesctopName;
+	private MessageQueue messageQueue;
+	private final DecodersContainer decoders;
+	private SenderTask senderTask;
+	private ReceiverTask receiverTask;
+	private IRfbSessionListener rfbSessionListener;
+	private IRepaintController repaintController;
+	private PixelFormat serverPixelFormat;
+	private Thread senderThread;
+	private Thread receiverThread;
+
+	public Protocol(Reader reader, Writer writer,
+			IPasswordRetriever passwordRetriever, ProtocolSettings settings) {
+		this.reader = reader;
+		this.writer = writer;
+		this.passwordRetriever = passwordRetriever;
+		this.settings = settings;
+		decoders = new DecodersContainer();
+		decoders.instantiateDecodersWhenNeeded(settings.encodings);
+		state = new HandshakeState(this);
+	}
+
+	@Override
+	public void changeStateTo(ProtocolState state) {
+		this.state = state;
+	}
+
+	public void handshake() throws UnsupportedProtocolVersionException, UnsupportedSecurityTypeException,
+			AuthenticationFailedException, TransportException, FatalException {
+		while (state.next()) {
+			continue;
+		}
+		this.messageQueue = new MessageQueue();
+	}
+
+	@Override
+	public PixelFormat getPixelFormat() {
+		return pixelFormat;
+	}
+
+	@Override
+	public void setPixelFormat(PixelFormat pixelFormat) {
+		this.pixelFormat = pixelFormat;
+		if (repaintController != null) {
+			repaintController.setPixelFormat(pixelFormat);
+		}
+	}
+
+	@Override
+	public String getRemoteDesktopName() {
+		return remoteDesctopName;
+	}
+
+	@Override
+	public void setRemoteDesktopName(String name) {
+		remoteDesctopName = name;
+	}
+
+	@Override
+	public int getFbWidth() {
+		return fbWidth;
+	}
+
+	@Override
+	public void setFbWidth(int fbWidth) {
+		this.fbWidth = fbWidth;
+	}
+
+	@Override
+	public int getFbHeight() {
+		return fbHeight;
+	}
+
+	@Override
+	public void setFbHeight(int fbHeight) {
+		this.fbHeight = fbHeight;
+	}
+
+	@Override
+	public IPasswordRetriever getPasswordRetriever() {
+		return passwordRetriever;
+	}
+
+	@Override
+	public ProtocolSettings getSettings() {
+		return settings;
+	}
+
+	@Override
+	public Logger getLogger() {
+		return logger;
+	}
+
+	@Override
+	public Writer getWriter() {
+		return writer;
+	}
+
+	@Override
+	public Reader getReader() {
+		return reader;
+	}
+
+	/**
+	 * Following the server initialisation message it's up to the client to send
+	 * whichever protocol messages it wants.  Typically it will send a
+	 * SetPixelFormat message and a SetEncodings message, followed by a
+	 * FramebufferUpdateRequest.  From then on the server will send
+	 * FramebufferUpdate messages in response to the client's
+	 * FramebufferUpdateRequest messages.  The client should send
+	 * FramebufferUpdateRequest messages with incremental set to true when it has
+	 * finished processing one FramebufferUpdate and is ready to process another.
+	 * With a fast client, the rate at which FramebufferUpdateRequests are sent
+	 * should be regulated to avoid hogging the network.
+	 */
+	public void startNormalHandling(IRfbSessionListener rfbSessionListener,
+			IRepaintController repaintController, ClipboardController clipboardController) {
+		this.rfbSessionListener = rfbSessionListener;
+		this.repaintController = repaintController;
+//		if (settings.getBitsPerPixel() == 0) {
+//			settings.setBitsPerPixel(pixelFormat.bitsPerPixel); // the same the server sent when not initialized yet
+//		}
+		serverPixelFormat = pixelFormat;
+		serverPixelFormat.trueColourFlag = 1; // correct flag - we don't support color maps
+		setPixelFormat(createPixelFormat(settings));
+		sendMessage(new SetPixelFormatMessage(pixelFormat));
+		logger.fine("sent: "+pixelFormat);
+
+		sendSupportedEncodingsMessage(settings);
+		settings.addListener(this); // to support pixel format (color depth), and encodings changes
+		settings.addListener(repaintController);
+
+		sendRefreshMessage();
+		senderTask = new SenderTask(messageQueue, writer, this);
+		senderThread = new Thread(senderTask);
+		senderThread.start();
+		decoders.resetDecoders();
+		receiverTask = new ReceiverTask(
+				reader, repaintController,
+				clipboardController,
+				decoders, this);
+		receiverThread = new Thread(receiverTask);
+		receiverThread.start();
+	}
+
+	@Override
+	public void sendMessage(ClientToServerMessage message) {
+		messageQueue.put(message);
+	}
+
+	private void sendSupportedEncodingsMessage(ProtocolSettings settings) {
+		decoders.instantiateDecodersWhenNeeded(settings.encodings);
+		SetEncodingsMessage encodingsMessage = new SetEncodingsMessage(settings.encodings);
+		sendMessage(encodingsMessage);
+		logger.fine("sent: " + encodingsMessage.toString());
+	}
+
+	/**
+	 * create pixel format by bpp
+	 */
+	private PixelFormat createPixelFormat(ProtocolSettings settings) {
+		int serverBigEndianFlag = serverPixelFormat.bigEndianFlag;
+		switch (settings.getBitsPerPixel()) {
+		case ProtocolSettings.BPP_32:
+			return PixelFormat.create32bppPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.BPP_16:
+			return PixelFormat.create16bppPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.BPP_8:
+			return PixelFormat.create8bppBGRPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.BPP_6:
+			return PixelFormat.create6bppPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.BPP_3:
+			return PixelFormat.create3bppPixelFormat(serverBigEndianFlag);
+		case ProtocolSettings.BPP_SERVER_SETTINGS:
+			return serverPixelFormat;
+		default:
+			// unsupported bpp, use default
+			return PixelFormat.create32bppPixelFormat(serverBigEndianFlag);
+		}
+	}
+
+	@Override
+	public void settingsChanged(SettingsChangedEvent e) {
+		ProtocolSettings settings = (ProtocolSettings) e.getSource();
+		if (settings.isChangedEncodings()) {
+			sendSupportedEncodingsMessage(settings);
+		}
+		if (settings.changedBitsPerPixel() && receiverTask != null) {
+			receiverTask.queueUpdatePixelFormat(createPixelFormat(settings));
+		}
+	}
+
+	@Override
+	public void sendRefreshMessage() {
+		sendMessage(new FramebufferUpdateRequestMessage(0, 0, fbWidth, fbHeight, false));
+		logger.fine("sent: full FB Refresh");
+	}
+
+	@Override
+	public void cleanUpSession(String message) {
+		cleanUpSession();
+		rfbSessionListener.rfbSessionStopped(message);
+	}
+
+	public synchronized void cleanUpSession() {
+		if (senderTask != null) { senderTask.stopTask(); }
+		if (receiverTask != null) { receiverTask.stopTask(); }
+		if (senderTask != null) {
+			try {
+				senderThread.join(1000);
+			} catch (InterruptedException e) {
+				// nop
+			}
+			senderTask = null;
+		}
+		if (receiverTask != null) {
+			try {
+				receiverThread.join(1000);
+			} catch (InterruptedException e) {
+				// nop
+			}
+			receiverTask = null;
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/ProtocolContext.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,68 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.protocol.state.ProtocolState;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+import java.util.logging.Logger;
+
+public interface ProtocolContext {
+
+	void changeStateTo(ProtocolState state);
+
+	IPasswordRetriever getPasswordRetriever();
+
+	ProtocolSettings getSettings();
+
+	Logger getLogger();
+
+	Writer getWriter();
+	Reader getReader();
+
+	int getFbWidth();
+	void setFbWidth(int frameBufferWidth);
+
+	int getFbHeight();
+	void setFbHeight(int frameBufferHeight);
+
+	PixelFormat getPixelFormat();
+	void setPixelFormat(PixelFormat pixelFormat);
+
+	void setRemoteDesktopName(String name);
+
+	void sendMessage(ClientToServerMessage message);
+
+	String getRemoteDesktopName();
+
+	void sendRefreshMessage();
+	
+	void cleanUpSession(String message);
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/ProtocolSettings.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,434 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IChangeSettingsListener;
+import com.glavsoft.rfb.RfbCapabilityInfo;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.protocol.auth.SecurityType;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Protocol Settings class
+ */
+public class ProtocolSettings implements Cloneable {
+    private static final EncodingType DEFAULT_PREFERRED_ENCODING = EncodingType.TIGHT;
+	public static final int DEFAULT_JPEG_QUALITY = 6;
+	private static final int DEFAULT_COMPRESSION_LEVEL = -6;
+
+	// bits per pixel constants
+	public static final int BPP_32 = 32;
+	public static final int BPP_16 = 16;
+	public static final int BPP_8 = 8;
+	public static final int BPP_6 = 6;
+	public static final int BPP_3 = 3;
+
+	public static final int BPP_SERVER_SETTINGS = 0;
+
+	private static final int DEFAULT_BITS_PER_PIXEL = BPP_32;
+
+	public static final int CHANGED_VIEW_ONLY                   = 1 << 0;
+	public static final int CHANGED_ENCODINGS                   = 1 << 1;
+	public static final int CHANGED_ALLOW_COPY_RECT             = 1 << 2;
+	public static final int CHANGED_SHOW_REMOTE_CURSOR          = 1 << 3;
+	public static final int CHANGED_MOUSE_CURSOR_TRACK          = 1 << 4;
+	public static final int CHANGED_COMPRESSION_LEVEL           = 1 << 5;
+	public static final int CHANGED_JPEG_QUALITY                = 1 << 6;
+	public static final int CHANGED_ALLOW_CLIPBOARD_TRANSFER    = 1 << 7;
+	public static final int CHANGED_CONVERT_TO_ASCII            = 1 << 8;
+	public static final int CHANGED_BITS_PER_PIXEL              = 1 << 9;
+
+	private int changedSettingsMask;
+
+    private boolean sharedFlag;
+    private boolean viewOnly;
+    private EncodingType preferredEncoding;
+    private boolean allowCopyRect;
+    private boolean showRemoteCursor;
+    private LocalPointer mouseCursorTrack;
+    private int compressionLevel;
+    private int jpegQuality;
+	private boolean allowClipboardTransfer;
+	private boolean convertToAscii;
+	private int bitsPerPixel;
+
+	private String protocolVersion;
+	private boolean isTight;
+
+	public LinkedHashSet<EncodingType> encodings;
+
+	private final List<IChangeSettingsListener> listeners;
+
+    public CapabilityContainer
+		tunnelingCapabilities,
+		authCapabilities,
+		serverMessagesCapabilities,
+		clientMessagesCapabilities,
+		encodingTypesCapabilities;
+	private String remoteCharsetName;
+
+	public static ProtocolSettings getDefaultSettings() {
+    	ProtocolSettings settings = new ProtocolSettings();
+	    settings.initKnownAuthCapabilities(settings.authCapabilities);
+	    settings.initKnownEncodingTypesCapabilities(settings.encodingTypesCapabilities);
+
+        settings.sharedFlag = true;
+        settings.viewOnly = false;
+        settings.showRemoteCursor = true;
+        settings.mouseCursorTrack = LocalPointer.ON;
+        settings.preferredEncoding = DEFAULT_PREFERRED_ENCODING;
+        settings.allowCopyRect = true;
+        settings.compressionLevel = DEFAULT_COMPRESSION_LEVEL;
+        settings.jpegQuality = DEFAULT_JPEG_QUALITY;
+        settings.convertToAscii = false;
+        settings.allowClipboardTransfer = true;
+        settings.bitsPerPixel = 0;//DEFAULT_BITS_PER_PIXEL;
+        settings.refine();
+	    settings.changedSettingsMask = 0;
+        return settings;
+    }
+
+	private ProtocolSettings() {
+		listeners = new LinkedList<IChangeSettingsListener>();
+		tunnelingCapabilities = new CapabilityContainer();
+		authCapabilities = new CapabilityContainer();
+		serverMessagesCapabilities = new CapabilityContainer();
+		clientMessagesCapabilities = new CapabilityContainer();
+		encodingTypesCapabilities = new CapabilityContainer();
+		changedSettingsMask = 0;
+	}
+
+	private ProtocolSettings(ProtocolSettings s) {
+		this();
+
+		changedSettingsMask = s.changedSettingsMask;
+
+        sharedFlag = s.sharedFlag;
+        viewOnly = s.viewOnly;
+        preferredEncoding = s.preferredEncoding;
+        allowCopyRect = s.allowCopyRect;
+        showRemoteCursor = s.showRemoteCursor;
+        mouseCursorTrack = s.mouseCursorTrack;
+        compressionLevel = s.compressionLevel;
+        jpegQuality = s.jpegQuality;
+		allowClipboardTransfer = s.allowClipboardTransfer;
+		convertToAscii = s.convertToAscii;
+		bitsPerPixel = s.bitsPerPixel;
+
+		encodings = s.encodings;
+
+		protocolVersion = s.protocolVersion;
+		isTight = s.isTight;
+	}
+
+	private void initKnownAuthCapabilities(CapabilityContainer cc) {
+		cc.addEnabled(SecurityType.NONE_AUTHENTICATION.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.AUTHENTICATION_NO_AUTH);
+		cc.addEnabled(SecurityType.VNC_AUTHENTICATION.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.AUTHENTICATION_VNC_AUTH);
+	    //cc.addEnabled( 19, "VENC", "VENCRYPT");
+	    //cc.addEnabled( 20, "GTKV", "SASL____");
+	    //cc.addEnabled(129, RfbCapabilityInfo.TIGHT_VNC_VENDOR, "ULGNAUTH");
+	    //cc.addEnabled(130, RfbCapabilityInfo.TIGHT_VNC_VENDOR, "XTRNAUTH");
+	}
+
+	private void initKnownEncodingTypesCapabilities(CapabilityContainer cc) {
+		cc.add(EncodingType.COPY_RECT.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.ENCODING_COPYRECT);
+		cc.add(EncodingType.HEXTILE.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.ENCODING_HEXTILE);
+		cc.add(EncodingType.ZLIB.getId(),
+				RfbCapabilityInfo.VENDOR_TRIADA, RfbCapabilityInfo.ENCODING_ZLIB);
+		cc.add(EncodingType.ZRLE.getId(),
+				RfbCapabilityInfo.VENDOR_TRIADA, RfbCapabilityInfo.ENCODING_ZRLE);
+		cc.add(EncodingType.RRE.getId(),
+				RfbCapabilityInfo.VENDOR_STANDARD, RfbCapabilityInfo.ENCODING_RRE);
+		cc.add(EncodingType.TIGHT.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_TIGHT);
+
+		cc.add(EncodingType.RICH_CURSOR.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_RICH_CURSOR);
+		cc.add(EncodingType.CURSOR_POS.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_CURSOR_POS);
+		cc.add(EncodingType.DESKTOP_SIZE.getId(),
+				RfbCapabilityInfo.VENDOR_TIGHT, RfbCapabilityInfo.ENCODING_DESKTOP_SIZE);
+	}
+
+	public void addListener(IChangeSettingsListener listener) {
+		listeners.add(listener);
+	}
+
+	public byte getSharedFlag() {
+		return (byte) (sharedFlag ? 1 : 0);
+	}
+
+	public boolean isShared() {
+		return sharedFlag;
+	}
+
+	public void setSharedFlag(boolean sharedFlag) {
+		this.sharedFlag = sharedFlag;
+	}
+
+	public boolean isViewOnly() {
+		return viewOnly;
+	}
+
+	public void setViewOnly(boolean viewOnly) {
+		if (this.viewOnly != viewOnly) {
+			this.viewOnly = viewOnly;
+			changedSettingsMask |= CHANGED_VIEW_ONLY;
+		}
+	}
+
+	public void enableAllEncodingCaps() {
+		encodingTypesCapabilities.setAllEnable(true);
+
+	}
+
+	public int getBitsPerPixel() {
+		return bitsPerPixel;
+	}
+
+	/**
+	 * Set bpp only in 3, 6, 8, 16, 32. When bpp is wrong, it resets to {@link #DEFAULT_BITS_PER_PIXEL}
+	 */
+	public void setBitsPerPixel(int bpp) {
+		if (bitsPerPixel != bpp) {
+			changedSettingsMask |= CHANGED_BITS_PER_PIXEL;
+			switch (bpp) {
+			case BPP_32:
+			case BPP_16:
+			case BPP_8:
+			case BPP_6:
+			case BPP_3:
+			case BPP_SERVER_SETTINGS:
+				bitsPerPixel = bpp;
+				break;
+			default:
+				bitsPerPixel = DEFAULT_BITS_PER_PIXEL;
+			}
+			refine();
+		}
+	}
+
+	private void refine() {
+		LinkedHashSet<EncodingType> encodings = new LinkedHashSet<EncodingType>();
+		if (EncodingType.RAW_ENCODING == preferredEncoding) {
+			// when RAW selected send no ordinary encodings so only default RAW encoding will be enabled
+		} else {
+			encodings.add(preferredEncoding); // preferred first
+			encodings.addAll(EncodingType.ordinaryEncodings);
+			if (compressionLevel > 0 && compressionLevel < 10) {
+				encodings.add(EncodingType.byId(
+						EncodingType.COMPRESS_LEVEL_0.getId() + compressionLevel));
+			}
+			if (jpegQuality > 0 && jpegQuality < 10 &&
+					(bitsPerPixel == BPP_32 || bitsPerPixel == BPP_SERVER_SETTINGS)) {
+				encodings.add(EncodingType.byId(
+						EncodingType.JPEG_QUALITY_LEVEL_0.getId() + jpegQuality));
+			}
+			if (allowCopyRect) {
+				encodings.add(EncodingType.COPY_RECT);
+			}
+		}
+		switch(mouseCursorTrack) {
+		case OFF:
+			setShowRemoteCursor(false);
+			break;
+		case HIDE:
+			setShowRemoteCursor(false);
+			encodings.add(EncodingType.RICH_CURSOR);
+			encodings.add(EncodingType.CURSOR_POS);
+			break;
+		case ON:
+		default:
+			setShowRemoteCursor(true);
+			encodings.add(EncodingType.RICH_CURSOR);
+			encodings.add(EncodingType.CURSOR_POS);
+		}
+		encodings.add(EncodingType.DESKTOP_SIZE);
+		if ( isEncodingsChanged(this.encodings, encodings) || isChangedEncodings()) {
+			this.encodings = encodings;
+			changedSettingsMask |= CHANGED_ENCODINGS;
+		}
+	}
+
+	private boolean isEncodingsChanged(LinkedHashSet<EncodingType> encodings1, LinkedHashSet<EncodingType> encodings2) {
+		if (null == encodings1 || encodings1.size() != encodings2.size()) return true;
+		Iterator<EncodingType> it1 = encodings1.iterator();
+		Iterator<EncodingType> it2 = encodings2.iterator();
+		while (it1.hasNext()) {
+			EncodingType v1 = it1.next();
+			EncodingType v2 = it2.next();
+			if (v1 != v2) return true;
+		}
+		return false;
+	}
+
+	public void fireListeners() {
+		final SettingsChangedEvent event = new SettingsChangedEvent(new ProtocolSettings(this));
+		changedSettingsMask = 0;
+		for (IChangeSettingsListener listener : listeners) {
+			listener.settingsChanged(event);
+		}
+	}
+
+	public static boolean isRfbSettingsChangedFired(SettingsChangedEvent event) {
+		return event.getSource() instanceof ProtocolSettings;
+	}
+
+	public void setPreferredEncoding(EncodingType preferredEncoding) {
+		if (this.preferredEncoding != preferredEncoding) {
+			this.preferredEncoding = preferredEncoding;
+			changedSettingsMask |= CHANGED_ENCODINGS;
+			refine();
+		}
+	}
+
+	public EncodingType getPreferredEncoding() {
+		return preferredEncoding;
+	}
+
+	public void setAllowCopyRect(boolean allowCopyRect) {
+		if (this.allowCopyRect != allowCopyRect) {
+			this.allowCopyRect = allowCopyRect;
+			changedSettingsMask |= CHANGED_ALLOW_COPY_RECT;
+			refine();
+		}
+	}
+
+	public boolean isAllowCopyRect() {
+		return allowCopyRect;
+	}
+
+	private void setShowRemoteCursor(boolean showRemoteCursor) {
+		if (this.showRemoteCursor != showRemoteCursor) {
+			this.showRemoteCursor = showRemoteCursor;
+			changedSettingsMask |= CHANGED_SHOW_REMOTE_CURSOR;
+		}
+	}
+
+	public boolean isShowRemoteCursor() {
+		return showRemoteCursor;
+	}
+
+	public void setMouseCursorTrack(LocalPointer mouseCursorTrack) {
+		if (this.mouseCursorTrack != mouseCursorTrack) {
+			this.mouseCursorTrack = mouseCursorTrack;
+			changedSettingsMask |= CHANGED_MOUSE_CURSOR_TRACK;
+			refine();
+		}
+	}
+
+	public LocalPointer getMouseCursorTrack() {
+		return mouseCursorTrack;
+	}
+
+	public void setCompressionLevel(int compressionLevel) {
+		if (this.compressionLevel != compressionLevel) {
+			this.compressionLevel = compressionLevel;
+			changedSettingsMask |= CHANGED_COMPRESSION_LEVEL;
+			refine();
+		}
+	}
+
+	public int getCompressionLevel() {
+		return compressionLevel;
+	}
+
+	public void setJpegQuality(int jpegQuality) {
+		if (this.jpegQuality != jpegQuality) {
+			this.jpegQuality = jpegQuality;
+			changedSettingsMask |= CHANGED_JPEG_QUALITY;
+			refine();
+		}
+	}
+
+	public int getJpegQuality() {
+		return jpegQuality;
+	}
+
+	public void setAllowClipboardTransfer(boolean enable) {
+		if (this.allowClipboardTransfer != enable) {
+			this.allowClipboardTransfer = enable;
+			changedSettingsMask |= CHANGED_ALLOW_CLIPBOARD_TRANSFER;
+		}
+	}
+
+	public boolean isAllowClipboardTransfer() {
+		return allowClipboardTransfer;
+	}
+
+	public void setTight(boolean isTight) {
+		this.isTight = isTight;
+	}
+
+	public boolean isTight() {
+		return isTight;
+	}
+
+	public void setProtocolVersion(String protocolVersion) {
+		this.protocolVersion = protocolVersion;
+	}
+
+	public String getProtocolVersion() {
+		return protocolVersion;
+	}
+
+	public boolean isConvertToAscii() {
+		return convertToAscii;
+	}
+
+	public void setConvertToAscii(boolean convertToAscii) {
+		if (this.convertToAscii != convertToAscii) {
+			this.convertToAscii = convertToAscii;
+			changedSettingsMask |= CHANGED_CONVERT_TO_ASCII;
+		}
+	}
+
+	public boolean isChangedEncodings() {
+		return (changedSettingsMask & CHANGED_ENCODINGS) == CHANGED_ENCODINGS;
+	}
+
+	public boolean changedBitsPerPixel() {
+		return (changedSettingsMask & CHANGED_BITS_PER_PIXEL) == CHANGED_BITS_PER_PIXEL;
+	}
+
+	public void setRemoteCharsetName(String remoteCharsetName) {
+		this.remoteCharsetName = remoteCharsetName;
+	}
+
+	public  String getRemoteCharsetName() {
+		return remoteCharsetName;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/ReceiverTask.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,209 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.exceptions.CommonException;
+import com.glavsoft.exceptions.ProtocolException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.ClipboardController;
+import com.glavsoft.rfb.IRepaintController;
+import com.glavsoft.rfb.client.FramebufferUpdateRequestMessage;
+import com.glavsoft.rfb.client.SetPixelFormatMessage;
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.Decoder;
+import com.glavsoft.rfb.encoding.decoder.DecodersContainer;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.rfb.encoding.decoder.RichCursorDecoder;
+import com.glavsoft.transport.Reader;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Logger;
+
+public class ReceiverTask implements Runnable {
+	private static final byte FRAMEBUFFER_UPDATE = 0;
+	private static final byte SET_COLOR_MAP_ENTRIES = 1;
+	private static final byte BELL = 2;
+	private static final byte SERVER_CUT_TEXT = 3;
+
+
+	private static Logger logger = Logger.getLogger("com.glavsoft.rfb.protocol.ReceiverTask");
+	private final Reader reader;
+	private volatile boolean isRunning = false;
+	private Renderer renderer;
+	private final IRepaintController repaintController;
+	private final ClipboardController clipboardController;
+	private final DecodersContainer decoders;
+	private FramebufferUpdateRequestMessage fullscreenFbUpdateIncrementalRequest;
+	private final ProtocolContext context;
+	private PixelFormat pixelFormat;
+	private boolean needSendPixelFormat;
+
+	public ReceiverTask(Reader reader,
+	                    IRepaintController repaintController, ClipboardController clipboardController,
+	                    DecodersContainer decoders, ProtocolContext context) {
+		this.reader = reader;
+		this.repaintController = repaintController;
+		this.clipboardController = clipboardController;
+		this.context = context;
+		this.decoders = decoders;
+		renderer = repaintController.createRenderer(reader, context.getFbWidth(), context.getFbHeight(),
+				context.getPixelFormat());
+		fullscreenFbUpdateIncrementalRequest =
+			new FramebufferUpdateRequestMessage(0, 0, context.getFbWidth(), context.getFbHeight(), true);
+	}
+
+	@Override
+	public void run() {
+		isRunning = true;
+		while (isRunning) {
+			try {
+				byte messageId = reader.readByte();
+				switch (messageId) {
+				case FRAMEBUFFER_UPDATE:
+//					logger.fine("Server message: FramebufferUpdate (0)");
+					framebufferUpdateMessage();
+					break;
+				case SET_COLOR_MAP_ENTRIES:
+					logger.severe("Server message SetColorMapEntries is not implemented. Skip.");
+					setColorMapEntries();
+					break;
+				case BELL:
+					logger.fine("Server message: Bell");
+					System.out.print("\0007");
+				    System.out.flush();
+					break;
+				case SERVER_CUT_TEXT:
+					logger.fine("Server message: CutText (3)");
+					serverCutText();
+					break;
+				default:
+					logger.severe("Unsupported server message. Id = " + messageId);
+				}
+			} catch (TransportException e) {
+				logger.severe("Close session: " + e.getMessage());
+				if (isRunning) {
+					context.cleanUpSession("Connection closed.");
+				}
+				stopTask();
+			} catch (ProtocolException e) {
+				logger.severe(e.getMessage());
+				if (isRunning) {
+					context.cleanUpSession(e.getMessage() + "\nConnection closed.");
+				}
+				stopTask();
+			} catch (CommonException e) {
+				logger.severe(e.getMessage());
+				if (isRunning) {
+					context.cleanUpSession("Connection closed.");
+				}
+				stopTask();
+			} catch (Throwable te) {
+				StringWriter sw = new StringWriter();
+				PrintWriter pw = new PrintWriter(sw);
+				te.printStackTrace(pw);
+				if (isRunning) {
+					context.cleanUpSession(te.getMessage() + "\n" + sw.toString());
+				}
+				stopTask();
+			}
+		}
+	}
+
+	private void setColorMapEntries() throws TransportException {
+		reader.readByte();  // padding
+		reader.readUInt16(); // first color index
+		int length = reader.readUInt16();
+		while (length-- > 0) {
+			reader.readUInt16(); // R
+			reader.readUInt16(); // G
+			reader.readUInt16(); // B
+		}
+	}
+
+	private void serverCutText() throws TransportException {
+		reader.readByte();  // padding
+		reader.readInt16(); // padding
+		int length = reader.readInt32() & Integer.MAX_VALUE;
+		clipboardController.updateSystemClipboard(reader.readBytes(length));
+	}
+
+	public void framebufferUpdateMessage() throws CommonException {
+		reader.readByte(); // padding
+		int numberOfRectangles = reader.readUInt16();
+		while (numberOfRectangles-- > 0) {
+			FramebufferUpdateRectangle rect = new FramebufferUpdateRectangle();
+			rect.fill(reader);
+
+			Decoder decoder = decoders.getDecoderByType(rect.getEncodingType());
+			logger.finest(rect.toString() + (0 == numberOfRectangles ? "\n---" : ""));
+			if (decoder != null) {
+				decoder.decode(reader, renderer, rect);
+				repaintController.repaintBitmap(rect);
+			} else if (rect.getEncodingType() == EncodingType.RICH_CURSOR) {
+				RichCursorDecoder.getInstance().decode(reader, renderer, rect);
+				repaintController.repaintCursor();
+			} else if (rect.getEncodingType() == EncodingType.CURSOR_POS) {
+				renderer.decodeCursorPosition(rect);
+				repaintController.repaintCursor();
+			} else if (rect.getEncodingType() == EncodingType.DESKTOP_SIZE) {
+				fullscreenFbUpdateIncrementalRequest =
+					new FramebufferUpdateRequestMessage(0, 0, rect.width, rect.height, true);
+				synchronized (renderer) {
+					renderer = repaintController.createRenderer(reader, rect.width, rect.height,
+							context.getPixelFormat());
+				}
+				context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, rect.width, rect.height, false));
+//				repaintController.repaintCursor();
+			} else
+				throw new CommonException("Unprocessed encoding: " + rect.toString());
+		}
+		synchronized (this) {
+			if (needSendPixelFormat) {
+				needSendPixelFormat = false;
+				context.setPixelFormat(pixelFormat);
+				context.sendMessage(new SetPixelFormatMessage(pixelFormat));
+				logger.fine("sent: "+pixelFormat);
+				context.sendRefreshMessage();
+				logger.fine("sent: nonincremental fb update");
+			} else {
+				context.sendMessage(fullscreenFbUpdateIncrementalRequest);
+			}
+		}
+	}
+
+	public synchronized void queueUpdatePixelFormat(PixelFormat pf) {
+		pixelFormat = pf;
+		needSendPixelFormat = true;
+//		context.sendMessage(new FramebufferUpdateRequestMessage(0, 0, 1, 1, false));
+	}
+
+	public void stopTask() {
+		isRunning = false;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/SenderTask.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,91 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.client.ClientToServerMessage;
+import com.glavsoft.transport.Writer;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.logging.Logger;
+
+public class SenderTask implements Runnable {
+
+	private final MessageQueue queue;
+	private final Writer writer;
+	private final ProtocolContext protocolContext;
+	private volatile boolean isRunning = false;
+
+	/**
+	 * Create sender task
+	 * Task runs as thread, receive messages from queue and sends them to writer.
+	 * When no messages appears in queue longer than timeout period, sends FramebufferUpdate
+	 * request
+	 * @param messageQueue queue to poll messages
+	 * @param writer writer to send messages out
+	 * @param protocolContext
+	 */
+	public SenderTask(MessageQueue messageQueue, Writer writer, ProtocolContext protocolContext) {
+		this.queue = messageQueue;
+		this.writer = writer;
+		this.protocolContext = protocolContext;
+	}
+
+	@Override
+	public void run() {
+		isRunning = true;
+		while (isRunning) {
+			ClientToServerMessage message;
+			try {
+				message = queue.get();
+				if (message != null) {
+					message.send(writer);
+				}
+			} catch (InterruptedException e) {
+				// nop
+			} catch (TransportException e) {
+				Logger.getLogger("com.glavsoft.rfb.protocol").severe("Close session: " + e.getMessage());
+				if (isRunning) {
+					protocolContext.cleanUpSession("Connection closed");
+				}
+				stopTask();
+			} catch (Throwable te) {
+				StringWriter sw = new StringWriter();
+				PrintWriter pw = new PrintWriter(sw);
+				te.printStackTrace(pw);
+				if (isRunning) {
+					protocolContext.cleanUpSession(te.getMessage() + "\n" + sw.toString());
+				}
+				stopTask();
+			}
+		}
+	}
+
+	public void stopTask() {
+		isRunning = false;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/AuthHandler.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,66 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+public abstract class AuthHandler {
+	/**
+	 * Authenticate using apropriate auth scheme
+	 * @param reader
+	 * @param writer
+	 * @param passwordRetriever interface that realise callback function for password retrieving,
+	 * ex. by asking user with dialog frame etc.
+	 * @param authCaps authentication capabilities
+	 *
+	 * @return true if there was Tight protocol extention used, false - in the other way
+	 * @throws TransportException
+	 * @throws FatalException
+	 * @throws UnsupportedSecurityTypeException
+	 */
+	public abstract boolean authenticate(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+		throws TransportException, FatalException, UnsupportedSecurityTypeException;
+	protected boolean useSecurityResult = true;
+	public abstract SecurityType getType();
+	public int getId() {
+		return getType().getId();
+	}
+	public String getName() {
+		return getType().name();
+	}
+	public boolean useSecurityResult() {
+		return useSecurityResult;
+	}
+	public void setUseSecurityResult(boolean enabled) {
+		useSecurityResult = enabled;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/NoneAuthentication.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,45 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+public class NoneAuthentication extends AuthHandler {
+
+	@Override
+	public boolean authenticate(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever) {
+		return false;
+	}
+
+	@Override
+	public SecurityType getType() {
+		return SecurityType.NONE_AUTHENTICATION;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/SecurityType.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,72 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+
+/**
+ * Security types that implemented
+ */
+public enum SecurityType {
+	NONE_AUTHENTICATION(1),
+	VNC_AUTHENTICATION(2),
+//	int RA2_AUTHENTICATION = 5;
+//	int RA2NE_AUTHENTICATION = 6;
+	TIGHT_AUTHENTICATION(16);
+//	int ULTRA_AUTHENTICATION = 17;
+//	int TLS_AUTHENTICATION = 18;
+//	int VENCRYPT_AUTHENTICATION = 19;
+
+	private int id;
+	private SecurityType(int id) {
+		this.id = id;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	@SuppressWarnings("serial")
+	public
+	static Map<Integer, AuthHandler> implementedSecurityTypes =
+		new LinkedHashMap<Integer, AuthHandler>() {{
+			put(TIGHT_AUTHENTICATION.getId(), new TightAuthentication());
+			put(VNC_AUTHENTICATION.getId(), new VncAuthentication());
+			put(NONE_AUTHENTICATION.getId(), new NoneAuthentication());
+	}};
+
+	public static AuthHandler getAuthHandlerById(int id) throws UnsupportedSecurityTypeException {
+		AuthHandler typeSelected = null;
+		typeSelected = implementedSecurityTypes.get(id);
+		if (null == typeSelected) {
+			throw new UnsupportedSecurityTypeException("Not supported: " + id);
+		}
+		return typeSelected;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/TightAuthentication.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,153 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import java.util.logging.Logger;
+
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.rfb.RfbCapabilityInfo;
+import com.glavsoft.rfb.protocol.state.SecurityTypeState;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+/**
+ *
+ */
+public class TightAuthentication extends AuthHandler {
+
+	@Override
+	public SecurityType getType() {
+		return SecurityType.TIGHT_AUTHENTICATION;
+	}
+
+	@Override
+	public boolean authenticate(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+	throws TransportException, FatalException, UnsupportedSecurityTypeException {
+	      initTunnelling(reader, writer);
+	      initAuthorization(reader, writer, authCaps, passwordRetriever);
+	      return true;
+	}
+
+	/**
+	 * Negotiation of Tunneling Capabilities (protocol versions 3.7t, 3.8t)
+	 *
+	 * If the chosen security type is rfbSecTypeTight, the server sends a list of
+	 * supported tunneling methods ("tunneling" refers to any additional layer of
+	 * data transformation, such as encryption or external compression.)
+	 *
+	 * nTunnelTypes specifies the number of following rfbCapabilityInfo structures
+	 * that list all supported tunneling methods in the order of preference.
+	 *
+	 * NOTE: If nTunnelTypes is 0, that tells the client that no tunneling can be
+	 * used, and the client should not send a response requesting a tunneling
+	 * method.
+	 *
+	 * typedef struct _rfbTunnelingCapsMsg {
+	 *     CARD32 nTunnelTypes;
+	 *     //followed by nTunnelTypes * rfbCapabilityInfo structures
+	 *  } rfbTunnelingCapsMsg;
+	 * #define sz_rfbTunnelingCapsMsg 4
+	 * ----------------------------------------------------------------------------
+	 * Tunneling Method Request (protocol versions 3.7t, 3.8t)
+	 *
+	 * If the list of tunneling capabilities sent by the server was not empty, the
+	 * client should reply with a 32-bit code specifying a particular tunneling
+	 * method.  The following code should be used for no tunneling.
+	 *
+	 * #define rfbNoTunneling 0
+	 * #define sig_rfbNoTunneling "NOTUNNEL"
+	 *
+	 */
+	private void initTunnelling(Reader reader, Writer writer)
+			throws TransportException {
+		long tunnelsCount;
+		tunnelsCount = reader.readUInt32();
+		if (tunnelsCount > 0) {
+			for (int i = 0; i < tunnelsCount; ++i) {
+				RfbCapabilityInfo rfbCapabilityInfo = new RfbCapabilityInfo(reader);
+				Logger.getLogger("com.glavsoft.rfb.protocol.auth").fine(rfbCapabilityInfo.toString());
+			}
+			writer.writeInt32(0); // NOTUNNEL
+		}
+	}
+
+	/**
+	 * Negotiation of Authentication Capabilities (protocol versions 3.7t, 3.8t)
+	 *
+	 * After setting up tunneling, the server sends a list of supported
+	 * authentication schemes.
+	 *
+	 * nAuthTypes specifies the number of following rfbCapabilityInfo structures
+	 * that list all supported authentication schemes in the order of preference.
+	 *
+	 * NOTE: If nAuthTypes is 0, that tells the client that no authentication is
+	 * necessary, and the client should not send a response requesting an
+	 * authentication scheme.
+	 *
+	 * typedef struct _rfbAuthenticationCapsMsg {
+	 *     CARD32 nAuthTypes;
+	 *     // followed by nAuthTypes * rfbCapabilityInfo structures
+	 * } rfbAuthenticationCapsMsg;
+	 * #define sz_rfbAuthenticationCapsMsg 4
+	 * @param authCaps TODO
+	 * @param passwordRetriever
+	 * @throws UnsupportedSecurityTypeException
+	 * @throws TransportException
+	 * @throws FatalException
+	 */
+	private void initAuthorization(Reader reader, Writer writer,
+			CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+	throws UnsupportedSecurityTypeException, TransportException, FatalException {
+		int authCount;
+		authCount = reader.readInt32();
+		byte[] cap = new byte[authCount];
+		for (int i = 0; i < authCount; ++i) {
+			RfbCapabilityInfo rfbCapabilityInfo = new RfbCapabilityInfo(reader);
+			cap[i] = (byte) rfbCapabilityInfo.getCode();
+			Logger.getLogger("com.glavsoft.rfb.protocol.auth").fine(rfbCapabilityInfo.toString());
+		}
+		AuthHandler authHandler = null;
+		if (authCount > 0) {
+			authHandler = SecurityTypeState.selectAuthHandler(cap, authCaps);
+			for (int i = 0; i < authCount; ++i) {
+				if (authCaps.isSupported(cap[i])) {
+					//sending back RFB capability code
+					writer.writeInt32(cap[i]);
+					break;
+				}
+			}
+    	} else {
+    		authHandler = SecurityType.getAuthHandlerById(SecurityType.NONE_AUTHENTICATION.getId());
+    	}
+		Logger.getLogger("com.glavsoft.rfb.protocol.auth").info("Auth capability accepted: " + authHandler.getName());
+		authHandler.authenticate(reader, writer, authCaps, passwordRetriever);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/auth/VncAuthentication.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,102 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.auth;
+
+import com.glavsoft.exceptions.CryptoException;
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+import javax.crypto.*;
+import javax.crypto.spec.DESKeySpec;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+
+public class VncAuthentication extends AuthHandler {
+	@Override
+	public SecurityType getType() {
+		return SecurityType.VNC_AUTHENTICATION;
+	}
+
+	@Override
+	public boolean authenticate(Reader reader,
+			Writer writer, CapabilityContainer authCaps, IPasswordRetriever passwordRetriever)
+	throws TransportException, FatalException {
+		byte [] challenge = reader.readBytes(16);
+		String password = passwordRetriever.getPassword();
+		byte [] key = new byte[8];
+        System.arraycopy(password.getBytes(), 0, key, 0, Math.min(key.length, password.getBytes().length));
+	    writer.write(encrypt(challenge, key));
+	    return false;
+	}
+
+  /**
+	 * Encript challenge by key using DES
+	 * @param challenge
+	 * @param key
+	 * @return encripted bytes
+	 * @throws CryptoException on problem with DES algorithm support or smth about
+	 */
+	public byte[] encrypt(byte[] challenge, byte[] key) throws CryptoException {
+		try {
+		    DESKeySpec desKeySpec = new DESKeySpec(mirrorBits(key));
+		    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
+		    SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
+		    Cipher desCipher = Cipher.getInstance("DES/ECB/NoPadding");
+		    desCipher.init(Cipher.ENCRYPT_MODE, secretKey);
+		    byte[] textEncrypted = desCipher.doFinal(challenge);
+		    return textEncrypted;
+		} catch (NoSuchAlgorithmException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (NoSuchPaddingException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (IllegalBlockSizeException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (BadPaddingException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (InvalidKeyException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		} catch (InvalidKeySpecException e) {
+			throw new CryptoException("Cannot encrypt challenge", e);
+		}
+	}
+
+	private byte[] mirrorBits(byte[] k) {
+		byte[] key = new byte[8];
+		for (int i = 0; i < 8; i++) {
+			byte s = k[i];
+			s = (byte) (((s >> 1) & 0x55) | ((s << 1) & 0xaa));
+	        s = (byte) (((s >> 2) & 0x33) | ((s << 2) & 0xcc));
+	        s = (byte) (((s >> 4) & 0x0f) | ((s << 4) & 0xf0));
+	        key[i] = s;
+		}
+		return key;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/AuthenticationState.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,89 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.AuthenticationFailedException;
+import com.glavsoft.exceptions.ClosedConnectionException;
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+
+public class AuthenticationState extends ProtocolState {
+
+	private static final int AUTH_RESULT_OK = 0;
+//	private static final int AUTH_RESULT_FAILED = 1;
+//	private static final int AUTH_RESULT_TOO_MANY = 2;
+	private final AuthHandler authHandler;
+
+	public AuthenticationState(ProtocolContext context,
+			AuthHandler authHandler) {
+		super(context);
+		this.authHandler = authHandler;
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException,
+			UnsupportedSecurityTypeException, AuthenticationFailedException, FatalException {
+		authenticate();
+		return true;
+	}
+
+	private void authenticate() throws TransportException, AuthenticationFailedException,
+			FatalException, UnsupportedSecurityTypeException {
+		boolean isTight = authHandler.authenticate(reader, writer,
+				context.getSettings().authCapabilities, context.getPasswordRetriever());
+		// skip when protocol < 3.8 and NONE_AUTH
+		if (authHandler.useSecurityResult()) {
+			checkSecurityResult();
+		}
+		changeStateTo(isTight ? new InitTightState(context) : new InitState(context));
+		context.getSettings().setTight(isTight);
+	}
+
+	/**
+	 * Check Security Result received from server
+	 * May be:
+	 * * 0 - OK
+	 * * 1 - Failed
+	 * @throws TransportException
+	 * @throws AuthenticationFailedException
+	 */
+	protected void checkSecurityResult() throws TransportException,
+	AuthenticationFailedException {
+		if (reader.readInt32() != AUTH_RESULT_OK) {
+			try {
+				String reason = reader.readString();
+				throw new AuthenticationFailedException(reason);
+			} catch (ClosedConnectionException e) {
+				// protocol version 3.3 and 3.7 does not send reason string,
+				// but silently closes the connection
+				throw new AuthenticationFailedException("Authentication failed");
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/HandshakeState.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,96 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HandshakeState extends ProtocolState {
+
+	public static final String PROTOCOL_VERSION_3_8 = "3.8";
+	public static final String PROTOCOL_VERSION_3_7 = "3.7";
+	public static final String PROTOCOL_VERSION_3_3 = "3.3";
+	private static final int PROTOCOL_STRING_LENGTH = 12;
+	private static final String PROTOCOL_STRING_REGEXP = "^RFB (\\d\\d\\d).(\\d\\d\\d)\n$";
+
+	private static final int MIN_SUPPORTED_VERSION_MAJOR = 3;
+	private static final int MIN_SUPPORTED_VERSION_MINOR = 3;
+
+	private static final int MAX_SUPPORTED_VERSION_MAJOR = 3;
+	private static final int MAX_SUPPORTED_VERSION_MINOR = 8;
+
+	public HandshakeState(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException {
+		handshake();
+		return true;
+	}
+
+	private void handshake() throws TransportException, UnsupportedProtocolVersionException {
+		String protocolString = reader.readString(PROTOCOL_STRING_LENGTH);
+		logger.info("Server sent protocol string: " + protocolString.substring(0, protocolString.length() - 1));
+		Pattern pattern = Pattern.compile(PROTOCOL_STRING_REGEXP);
+		final Matcher matcher = pattern.matcher(protocolString);
+		if ( ! matcher.matches())
+			throw new UnsupportedProtocolVersionException(
+					"Unsupported protocol version: " + protocolString);
+		int major = Integer.parseInt(matcher.group(1));
+		int minor = Integer.parseInt(matcher.group(2));
+		if (major < MIN_SUPPORTED_VERSION_MAJOR ||
+				MIN_SUPPORTED_VERSION_MAJOR == major && minor <MIN_SUPPORTED_VERSION_MINOR)
+			throw new UnsupportedProtocolVersionException(
+					"Unsupported protocol version: " + major + "." + minor);
+		if (major > MAX_SUPPORTED_VERSION_MAJOR) {
+			major = MAX_SUPPORTED_VERSION_MAJOR;
+			minor = MAX_SUPPORTED_VERSION_MINOR;
+		}
+
+		if (minor >= MIN_SUPPORTED_VERSION_MINOR && minor < 7) {
+			changeStateTo(new SecurityType33State(context));
+			context.getSettings().setProtocolVersion(PROTOCOL_VERSION_3_3);
+			minor = 3;
+		} else if (7 == minor) {
+			changeStateTo(new SecurityType37State(context));
+			context.getSettings().setProtocolVersion(PROTOCOL_VERSION_3_7);
+			minor = 7;
+		} else if (minor >= MAX_SUPPORTED_VERSION_MINOR) {
+			changeStateTo(new SecurityTypeState(context));
+			context.getSettings().setProtocolVersion(PROTOCOL_VERSION_3_8);
+			minor = 8;
+		} else
+			throw new UnsupportedProtocolVersionException(
+					"Unsupported protocol version: " + protocolString);
+		writer.write(("RFB 00" + major + ".00" + minor + "\n").getBytes());
+		logger.info("Set protocol version to: " + context.getSettings().getProtocolVersion());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/InitState.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,92 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.AuthenticationFailedException;
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.encoding.ServerInitMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+
+/**
+ * ClientInit
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message onl@!,@!,y consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ *
+ * 1 - U8 - shared-flag
+ *
+ * Shared-flag is non-zero (true) if the server should try to share the desktop by leaving
+ * other clients connected, zero (false) if it should give exclusive access to this client by
+ * disconnecting all other clients.
+ *
+ * ServerInit
+ *
+ * After receiving the ClientInit message, the server sends a ServerInit message. This
+ * tells the client the width and height of the server’s framebuffer, its pixel format and the
+ * name associated with the desktop.
+ */
+public class InitState extends ProtocolState {
+
+	public InitState(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException,
+			UnsupportedSecurityTypeException, AuthenticationFailedException, FatalException {
+		clientAndServerInit();
+		return false;
+	}
+
+	protected void clientAndServerInit() throws TransportException {
+		ServerInitMessage serverInitMessage = getServerInitMessage();
+		ProtocolSettings settings = context.getSettings();
+		settings.enableAllEncodingCaps();
+		completeContextData(serverInitMessage);
+	}
+
+	protected void completeContextData(ServerInitMessage serverInitMessage) {
+		context.setPixelFormat(serverInitMessage.getPixelFormat());
+		context.setFbWidth(serverInitMessage.getFrameBufferWidth());
+		context.setFbHeight(serverInitMessage.getFrameBufferHeight());
+		context.setRemoteDesktopName(serverInitMessage.getName());
+		logger.fine(serverInitMessage.toString());
+	}
+
+	protected ServerInitMessage getServerInitMessage() throws TransportException {
+		writer.write(context.getSettings().getSharedFlag());
+		ServerInitMessage serverInitMessage = new ServerInitMessage(reader);
+		return serverInitMessage;
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/InitTightState.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,75 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.rfb.encoding.ServerInitMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+
+/**
+ * Server Interaction Capabilities Message (protocol versions 3.7t, 3.8t)
+ *
+ * If TightVNC protocol extensions are enabled, the server informs the client
+ * what message types it supports in addition to ones defined in the standard
+ * RFB protocol.
+ * Also, the server sends the list of all supported encodings (note that it's
+ * not necessary to advertise the "raw" encoding sinse it MUST be supported in
+ * RFB 3.x protocols).
+ *
+ * This data immediately follows the server initialisation message.
+ */
+public class InitTightState extends InitState {
+
+	public InitTightState(ProtocolContext context) {
+		super(context);
+	}
+
+	/**
+	 * typedef struct _rfbInteractionCapsMsg {
+	 * 		CARD16 nServerMessageTypes;
+	 * 		CARD16 nClientMessageTypes;
+	 * 		CARD16 nEncodingTypes;
+	 * 		CARD16 pad;><------><------>// reserved, must be 0
+	 * 		// followed by nServerMessageTypes * rfbCapabilityInfo structures
+	 * 		// followed by nClientMessageTypes * rfbCapabilityInfo structures
+	 * } rfbInteractionCapsMsg;
+	 * #define sz_rfbInteractionCapsMsg 8
+	 */
+	@Override
+	protected void clientAndServerInit() throws TransportException {
+		ServerInitMessage serverInitMessage = getServerInitMessage();
+		int nServerMessageTypes = reader.readUInt16();
+		int nClientMessageTypes = reader.readUInt16();
+		int nEncodingTypes = reader.readUInt16();
+		reader.readUInt16(); //padding
+		ProtocolSettings settings = context.getSettings();
+		settings.serverMessagesCapabilities.read(reader, nServerMessageTypes);
+		settings.clientMessagesCapabilities.read(reader, nClientMessageTypes);
+		settings.encodingTypesCapabilities.read(reader, nEncodingTypes);
+		completeContextData(serverInitMessage);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/ProtocolState.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,68 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import java.util.logging.Logger;
+
+import com.glavsoft.exceptions.AuthenticationFailedException;
+import com.glavsoft.exceptions.FatalException;
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+
+abstract public class ProtocolState {
+	protected ProtocolContext context;
+	protected Logger logger;
+	protected Reader reader;
+	protected Writer writer;
+
+	public ProtocolState(ProtocolContext context) {
+		this.context = context;
+		this.logger = context.getLogger();
+		this.reader = context.getReader();
+		this.writer = context.getWriter();
+	}
+
+	/**
+	 * Change state of finite machine.
+	 *
+	 * @param state state, the Finite Machine will switched to
+	 */
+	protected void changeStateTo(ProtocolState state) {
+		context.changeStateTo(state);
+	}
+
+	/**
+	 * Carry out next step of protocol flow.
+	 *
+	 * @return false when no next protocol steps availabe, true - when need to continue
+	 */
+	abstract public boolean next() throws UnsupportedProtocolVersionException, TransportException,
+			UnsupportedSecurityTypeException, AuthenticationFailedException, FatalException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/SecurityType33State.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,59 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+
+public class SecurityType33State extends SecurityType37State {
+
+	public SecurityType33State(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	protected void negotiateAboutSecurityType()
+			throws TransportException, UnsupportedSecurityTypeException {
+		logger.info("Get Security Type");
+		int type = reader.readInt32();
+		logger.info("Type received: " + type);
+		if (0 == type)
+			// throw exception with reason
+			throw new UnsupportedSecurityTypeException(reader.readString());
+		AuthHandler typeSelected = selectAuthHandler(new byte[] {(byte) (0xff & type)},
+					context.getSettings().authCapabilities);
+		if (typeSelected != null) {
+			setUseSecurityResult(typeSelected);
+			logger.info("Type accepted: " + typeSelected.getName());
+		} else
+			throw new UnsupportedSecurityTypeException(
+					"No security types supported. Server sent '" +
+					type + "' security type, but we do not support it.");
+		changeStateTo(new AuthenticationState(context, typeSelected));
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/SecurityType37State.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,43 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+import com.glavsoft.rfb.protocol.auth.SecurityType;
+
+public class SecurityType37State extends SecurityTypeState {
+
+	public SecurityType37State(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	protected void setUseSecurityResult(AuthHandler type) {
+		if (SecurityType.NONE_AUTHENTICATION == type.getType()) {
+			type.setUseSecurityResult(false);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/rfb/protocol/state/SecurityTypeState.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,105 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.rfb.protocol.state;
+
+import com.glavsoft.exceptions.TransportException;
+import com.glavsoft.exceptions.UnsupportedProtocolVersionException;
+import com.glavsoft.exceptions.UnsupportedSecurityTypeException;
+import com.glavsoft.rfb.CapabilityContainer;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.auth.AuthHandler;
+import com.glavsoft.rfb.protocol.auth.SecurityType;
+import com.glavsoft.utils.Strings;
+
+public class SecurityTypeState extends ProtocolState {
+
+	public SecurityTypeState(ProtocolContext context) {
+		super(context);
+	}
+
+	@Override
+	public boolean next() throws UnsupportedProtocolVersionException, TransportException, UnsupportedSecurityTypeException {
+		negotiateAboutSecurityType();
+		return true;
+	}
+
+	protected void negotiateAboutSecurityType() throws TransportException,
+			UnsupportedSecurityTypeException {
+		int secTypesNum = reader.readUInt8();
+		if (0 == secTypesNum)
+			// throw exception with reason
+			throw new UnsupportedSecurityTypeException(reader.readString());
+		byte[] secTypes = reader.readBytes(secTypesNum);
+		logger.info("Security Types received (" + secTypesNum + "): "
+				+ Strings.toString(secTypes));
+		AuthHandler typeSelected = selectAuthHandler(
+				secTypes, context.getSettings().authCapabilities);
+		setUseSecurityResult(typeSelected);
+		writer.writeByte(typeSelected.getId());
+		logger.info("Security Type accepted: " + typeSelected.getName());
+
+		changeStateTo(new AuthenticationState(context, typeSelected));
+	}
+
+	/**
+	 * Select apropriate security type we supporded from types which server sent
+	 *
+	 * @param secTypes - byte array with security types server supported
+	 * @param authCapabilities
+	 * @return {@link AuthHandler} of selected type
+	 * @throws UnsupportedSecurityTypeException when no security types server sent we support
+	 */
+	public static AuthHandler selectAuthHandler(byte[] secTypes, CapabilityContainer authCapabilities)
+	throws UnsupportedSecurityTypeException {
+		AuthHandler typeSelected = null;
+		// Tigh Authentication first
+		for (byte type : secTypes) {
+			if (SecurityType.TIGHT_AUTHENTICATION.getId() == (0xff & type)) {
+				typeSelected = SecurityType.implementedSecurityTypes
+					.get(SecurityType.TIGHT_AUTHENTICATION.getId());
+				if (typeSelected != null)
+					return typeSelected;
+			}
+		}
+		for (byte type : secTypes) {
+			typeSelected = SecurityType.implementedSecurityTypes.get(0xff & type);
+			if (typeSelected != null &&
+					authCapabilities.isSupported(typeSelected.getId()))
+				return typeSelected;
+		}
+		throw new UnsupportedSecurityTypeException(
+				"No security types supported. Server sent '"
+						+ Strings.toString(secTypes)
+						+ "' security types, but we do not support any of their.");
+	}
+
+	/**
+	 * @param typeSelected
+	 */
+	protected void setUseSecurityResult(AuthHandler typeSelected) {
+		// nop for Protocol version 3.8 and above
+	}
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/transport/Reader.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,131 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.transport;
+
+import com.glavsoft.exceptions.ClosedConnectionException;
+import com.glavsoft.exceptions.TransportException;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+public class Reader {
+	final static Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+	private final DataInputStream is;
+
+	public Reader(InputStream is) {
+		this.is = new DataInputStream(new BufferedInputStream(is));
+	}
+
+	public byte readByte() throws TransportException {
+		try {
+			byte readByte = is.readByte();
+			return readByte;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read byte", e);
+		}
+
+	}
+
+	public int readUInt8() throws TransportException {
+		return readByte() & 0x0ff;
+	}
+
+	public int readUInt16() throws TransportException {
+		return readInt16() & 0x0ffff;
+	}
+
+	public short readInt16() throws TransportException {
+		try {
+			short readShort = is.readShort();
+			return readShort;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read int16", e);
+		}
+	}
+
+	public long readUInt32() throws TransportException {
+		return readInt32() & 0xffffffffL;
+	}
+
+	public int readInt32() throws TransportException {
+		try {
+			int readInt = is.readInt();
+			return readInt;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read int16", e);
+		}
+	}
+
+	/**
+	 * Read string by it length.
+	 * Use this method only when sure no character accept ASCII will be read.
+	 * Use readBytes and character encoding conversion instead.
+	 *
+	 * @return String read
+	 */
+	public String readString(int length) throws TransportException {
+        return new String(readBytes(length));
+	}
+
+	/**
+	 * Read 32-bit string length and then string themself by it length
+	 * Use this method only when sure no character accept ASCII will be read.
+	 * Use readBytes and character encoding conversion instead.
+	 *
+	 * @return String read
+	 * @throws TransportException
+	 */
+	public String readString() throws TransportException {
+		// unset most sighificant (sign) bit 'cause InputStream#readFully
+		// reads
+		// [int] length bytes from stream. Change when realy need read sthing more
+		// than
+		// 2147483647 bytes lenght
+		int length = readInt32() & Integer.MAX_VALUE;
+		return readString(length);
+	}
+
+	public byte[] readBytes(int length) throws TransportException {
+		byte b[] = new byte[length];
+		return readBytes(b, 0, length);
+	}
+
+	public byte[] readBytes(byte[] b, int offset, int length) throws TransportException {
+		try {
+			is.readFully(b, offset, length);
+			return b;
+		} catch (EOFException e) {
+			throw new ClosedConnectionException(e);
+		} catch (IOException e) {
+			throw new TransportException("Cannot read " + length + " bytes array", e);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/transport/Writer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,100 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.transport;
+
+import com.glavsoft.exceptions.TransportException;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Writer {
+	private final DataOutputStream os;
+
+	public Writer(OutputStream os) {
+		this.os = new DataOutputStream(os);
+	}
+
+	public void flush() throws TransportException {
+		try {
+			os.flush();
+		} catch (IOException e) {
+			throw new TransportException("Cannot flush output stream", e);
+		}
+	}
+
+	public void writeByte(int b) throws TransportException {
+		write((byte) (b & 0xff));
+	}
+
+	public void write(byte b) throws TransportException {
+		try {
+			os.writeByte(b);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write byte", e);
+		}
+	}
+
+	public void writeInt16(int sh) throws TransportException {
+		write((short) (sh & 0xffff));
+	}
+
+	public void write(short sh) throws TransportException {
+		try {
+			os.writeShort(sh);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write short", e);
+		}
+	}
+
+	public void writeInt32(int i) throws TransportException {
+		write(i);
+	}
+
+	public void write(int i) throws TransportException {
+		try {
+			os.writeInt(i);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write int", e);
+		}
+	}
+
+	public void write(byte[] b) throws TransportException {
+		write(b, 0, b.length);
+	}
+
+	public void write(byte[] b, int length) throws TransportException {
+		write(b, 0, length);
+	}
+
+	public void write(byte[] b, int offset, int length)
+			throws TransportException {
+		try {
+			os.write(b, offset, length <= b.length ? length : b.length);
+		} catch (IOException e) {
+			throw new TransportException("Cannot write " + length + " bytes", e);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/utils/Keymap.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,905 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.utils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class Keymap {
+
+	public static final int K_F1 = 0xffbe;
+	public static final int K_F2 = 0xffbf;
+	public static final int K_F3 = 0xffc0;
+	public static final int K_F4 = 0xffc1;
+	public static final int K_F5 = 0xffc2;
+	public static final int K_F6 = 0xffc3;
+	public static final int K_F7 = 0xffc4;
+	public static final int K_F8 = 0xffc5;
+	public static final int K_F9 = 0xffc6;
+	public static final int K_F10 = 0xffc7;
+	public static final int K_F11 = 0xffc8;
+	public static final int K_F12 = 0xffc9;
+	public static final int K_INSERT = 0xff63;
+	public static final int K_DELETE = 0xffff;
+	public static final int K_HOME = 0xff50;
+	public static final int K_END = 0xff57;
+	public static final int K_PAGE_DOWN = 0xff56;
+	public static final int K_PAGE_UP = 0xff55;
+	public static final int K_DOWN = 0xff54;
+	public static final int K_RIGHT = 0xff53;
+	public static final int K_UP = 0xff52;
+	public static final int K_LEFT = 0xff51;
+	public static final int K_ESCAPE = 0xff1b;
+	public static final int K_ENTER = 0xff0d;
+	public static final int K_TAB = 0xff09;
+	public static final int K_BACK_SPACE = 0xff08;
+	public static final int K_ALT_LEFT = 0xffe9;
+	public static final int K_META_LEFT = 0xffe7;
+	public static final int K_SHIFT_LEFT = 0xffe1;
+	public static final int K_CTRL_LEFT = 0xffe3;
+	public static final int K_SUPER_LEFT = 0xffeb;
+	public static final int K_HYPER_LEFT = 0xffed;
+
+	public static final int K_KP_SPACE = 0xFF80;
+	public static final int K_KP_TAB = 0xFF89;
+	public static final int K_KP_ENTER = 0xFF8D;
+	public static final int K_KP_F1 = 0xFF91;
+	public static final int K_KP_F2 = 0xFF92;
+	public static final int K_KP_F3 = 0xFF93;
+	public static final int K_KP_F4 = 0xFF94;
+	public static final int K_KP_HOME = 0xFF95;
+	public static final int K_KP_LEFT = 0xFF96;
+	public static final int K_KP_UP = 0xFF97;
+	public static final int K_KP_RIGHT = 0xFF98;
+	public static final int K_KP_DOWN = 0xFF99;
+	public static final int K_KP_PRIOR = 0xFF9A;
+	public static final int K_KP_PAGE_UP = 0xFF9A;
+	public static final int K_KP_NEXT = 0xFF9B;
+	public static final int K_KP_PAGE_DOWN = 0xFF9B;
+	public static final int K_KP_END = 0xFF9C;
+	public static final int K_KP_BEGIN = 0xFF9D;
+	public static final int K_KP_INSERT = 0xFF9E;
+	public static final int K_KP_DELETE = 0xFF9F;
+	public static final int K_KP_EQUAL = 0xFFBD;
+
+	public static final int K_KP_MULTIPLY = 0xFFAA;
+	public static final int K_KP_ADD = 0xFFAB;
+	public static final int K_KP_SEPARATOR = 0xFFAC; /* separator, often comma */
+	public static final int K_KP_SUBTRACT = 0xFFAD;
+	public static final int K_KP_DECIMAL = 0xFFAE;
+	public static final int K_KP_DIVIDE = 0xFFAF;
+
+	public static final int K_KP_0 = 0xFFB0;
+	public static final int K_KP_1 = 0xFFB1;
+	public static final int K_KP_2 = 0xFFB2;
+	public static final int K_KP_3 = 0xFFB3;
+	public static final int K_KP_4 = 0xFFB4;
+	public static final int K_KP_5 = 0xFFB5;
+	public static final int K_KP_6 = 0xFFB6;
+	public static final int K_KP_7 = 0xFFB7;
+	public static final int K_KP_8 = 0xFFB8;
+	public static final int K_KP_9 = 0xFFB9;
+
+	private static Map<Integer, Integer> keyMap = toMap(new int[][] {
+		// X      Unicode
+		{ 0x01a1, 0x0104 }, /*                     Aogonek  LATIN CAPITAL LETTER A WITH OGONEK */
+		{ 0x01a2, 0x02d8 }, /*                       breve  BREVE */
+		{ 0x01a3, 0x0141 }, /*                     Lstroke  LATIN CAPITAL LETTER L WITH STROKE */
+		{ 0x01a5, 0x013d }, /*                      Lcaron  LATIN CAPITAL LETTER L WITH CARON */
+		{ 0x01a6, 0x015a }, /*                      Sacute  LATIN CAPITAL LETTER S WITH ACUTE */
+		{ 0x01a9, 0x0160 }, /*                      Scaron  LATIN CAPITAL LETTER S WITH CARON */
+		{ 0x01aa, 0x015e }, /*                    Scedilla  LATIN CAPITAL LETTER S WITH CEDILLA */
+		{ 0x01ab, 0x0164 }, /*                      Tcaron  LATIN CAPITAL LETTER T WITH CARON */
+		{ 0x01ac, 0x0179 }, /*                      Zacute  LATIN CAPITAL LETTER Z WITH ACUTE */
+		{ 0x01ae, 0x017d }, /*                      Zcaron  LATIN CAPITAL LETTER Z WITH CARON */
+		{ 0x01af, 0x017b }, /*                   Zabovedot  LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+		{ 0x01b1, 0x0105 }, /*                     aogonek  LATIN SMALL LETTER A WITH OGONEK */
+		{ 0x01b2, 0x02db }, /*                      ogonek  OGONEK */
+		{ 0x01b3, 0x0142 }, /*                     lstroke  LATIN SMALL LETTER L WITH STROKE */
+		{ 0x01b5, 0x013e }, /*                      lcaron  LATIN SMALL LETTER L WITH CARON */
+		{ 0x01b6, 0x015b }, /*                      sacute  LATIN SMALL LETTER S WITH ACUTE */
+		{ 0x01b7, 0x02c7 }, /*                       caron  CARON */
+		{ 0x01b9, 0x0161 }, /*                      scaron  LATIN SMALL LETTER S WITH CARON */
+		{ 0x01ba, 0x015f }, /*                    scedilla  LATIN SMALL LETTER S WITH CEDILLA */
+		{ 0x01bb, 0x0165 }, /*                      tcaron  LATIN SMALL LETTER T WITH CARON */
+		{ 0x01bc, 0x017a }, /*                      zacute  LATIN SMALL LETTER Z WITH ACUTE */
+		{ 0x01bd, 0x02dd }, /*                 doubleacute  DOUBLE ACUTE ACCENT */
+		{ 0x01be, 0x017e }, /*                      zcaron  LATIN SMALL LETTER Z WITH CARON */
+		{ 0x01bf, 0x017c }, /*                   zabovedot  LATIN SMALL LETTER Z WITH DOT ABOVE */
+		{ 0x01c0, 0x0154 }, /*                      Racute  LATIN CAPITAL LETTER R WITH ACUTE */
+		{ 0x01c3, 0x0102 }, /*                      Abreve  LATIN CAPITAL LETTER A WITH BREVE */
+		{ 0x01c5, 0x0139 }, /*                      Lacute  LATIN CAPITAL LETTER L WITH ACUTE */
+		{ 0x01c6, 0x0106 }, /*                      Cacute  LATIN CAPITAL LETTER C WITH ACUTE */
+		{ 0x01c8, 0x010c }, /*                      Ccaron  LATIN CAPITAL LETTER C WITH CARON */
+		{ 0x01ca, 0x0118 }, /*                     Eogonek  LATIN CAPITAL LETTER E WITH OGONEK */
+		{ 0x01cc, 0x011a }, /*                      Ecaron  LATIN CAPITAL LETTER E WITH CARON */
+		{ 0x01cf, 0x010e }, /*                      Dcaron  LATIN CAPITAL LETTER D WITH CARON */
+		{ 0x01d0, 0x0110 }, /*                     Dstroke  LATIN CAPITAL LETTER D WITH STROKE */
+		{ 0x01d1, 0x0143 }, /*                      Nacute  LATIN CAPITAL LETTER N WITH ACUTE */
+		{ 0x01d2, 0x0147 }, /*                      Ncaron  LATIN CAPITAL LETTER N WITH CARON */
+		{ 0x01d5, 0x0150 }, /*                Odoubleacute  LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+		{ 0x01d8, 0x0158 }, /*                      Rcaron  LATIN CAPITAL LETTER R WITH CARON */
+		{ 0x01d9, 0x016e }, /*                       Uring  LATIN CAPITAL LETTER U WITH RING ABOVE */
+		{ 0x01db, 0x0170 }, /*                Udoubleacute  LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+		{ 0x01de, 0x0162 }, /*                    Tcedilla  LATIN CAPITAL LETTER T WITH CEDILLA */
+		{ 0x01e0, 0x0155 }, /*                      racute  LATIN SMALL LETTER R WITH ACUTE */
+		{ 0x01e3, 0x0103 }, /*                      abreve  LATIN SMALL LETTER A WITH BREVE */
+		{ 0x01e5, 0x013a }, /*                      lacute  LATIN SMALL LETTER L WITH ACUTE */
+		{ 0x01e6, 0x0107 }, /*                      cacute  LATIN SMALL LETTER C WITH ACUTE */
+		{ 0x01e8, 0x010d }, /*                      ccaron  LATIN SMALL LETTER C WITH CARON */
+		{ 0x01ea, 0x0119 }, /*                     eogonek  LATIN SMALL LETTER E WITH OGONEK */
+		{ 0x01ec, 0x011b }, /*                      ecaron  LATIN SMALL LETTER E WITH CARON */
+		{ 0x01ef, 0x010f }, /*                      dcaron  LATIN SMALL LETTER D WITH CARON */
+		{ 0x01f0, 0x0111 }, /*                     dstroke  LATIN SMALL LETTER D WITH STROKE */
+		{ 0x01f1, 0x0144 }, /*                      nacute  LATIN SMALL LETTER N WITH ACUTE */
+		{ 0x01f2, 0x0148 }, /*                      ncaron  LATIN SMALL LETTER N WITH CARON */
+		{ 0x01f5, 0x0151 }, /*                odoubleacute  LATIN SMALL LETTER O WITH DOUBLE ACUTE */
+		{ 0x01f8, 0x0159 }, /*                      rcaron  LATIN SMALL LETTER R WITH CARON */
+		{ 0x01f9, 0x016f }, /*                       uring  LATIN SMALL LETTER U WITH RING ABOVE */
+		{ 0x01fb, 0x0171 }, /*                udoubleacute  LATIN SMALL LETTER U WITH DOUBLE ACUTE */
+		{ 0x01fe, 0x0163 }, /*                    tcedilla  LATIN SMALL LETTER T WITH CEDILLA */
+		{ 0x01ff, 0x02d9 }, /*                    abovedot  DOT ABOVE */
+		{ 0x02a1, 0x0126 }, /*                     Hstroke  LATIN CAPITAL LETTER H WITH STROKE */
+		{ 0x02a6, 0x0124 }, /*                 Hcircumflex  LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+		{ 0x02a9, 0x0130 }, /*                   Iabovedot  LATIN CAPITAL LETTER I WITH DOT ABOVE */
+		{ 0x02ab, 0x011e }, /*                      Gbreve  LATIN CAPITAL LETTER G WITH BREVE */
+		{ 0x02ac, 0x0134 }, /*                 Jcircumflex  LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+		{ 0x02b1, 0x0127 }, /*                     hstroke  LATIN SMALL LETTER H WITH STROKE */
+		{ 0x02b6, 0x0125 }, /*                 hcircumflex  LATIN SMALL LETTER H WITH CIRCUMFLEX */
+		{ 0x02b9, 0x0131 }, /*                    idotless  LATIN SMALL LETTER DOTLESS I */
+		{ 0x02bb, 0x011f }, /*                      gbreve  LATIN SMALL LETTER G WITH BREVE */
+		{ 0x02bc, 0x0135 }, /*                 jcircumflex  LATIN SMALL LETTER J WITH CIRCUMFLEX */
+		{ 0x02c5, 0x010a }, /*                   Cabovedot  LATIN CAPITAL LETTER C WITH DOT ABOVE */
+		{ 0x02c6, 0x0108 }, /*                 Ccircumflex  LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+		{ 0x02d5, 0x0120 }, /*                   Gabovedot  LATIN CAPITAL LETTER G WITH DOT ABOVE */
+		{ 0x02d8, 0x011c }, /*                 Gcircumflex  LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+		{ 0x02dd, 0x016c }, /*                      Ubreve  LATIN CAPITAL LETTER U WITH BREVE */
+		{ 0x02de, 0x015c }, /*                 Scircumflex  LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+		{ 0x02e5, 0x010b }, /*                   cabovedot  LATIN SMALL LETTER C WITH DOT ABOVE */
+		{ 0x02e6, 0x0109 }, /*                 ccircumflex  LATIN SMALL LETTER C WITH CIRCUMFLEX */
+		{ 0x02f5, 0x0121 }, /*                   gabovedot  LATIN SMALL LETTER G WITH DOT ABOVE */
+		{ 0x02f8, 0x011d }, /*                 gcircumflex  LATIN SMALL LETTER G WITH CIRCUMFLEX */
+		{ 0x02fd, 0x016d }, /*                      ubreve  LATIN SMALL LETTER U WITH BREVE */
+		{ 0x02fe, 0x015d }, /*                 scircumflex  LATIN SMALL LETTER S WITH CIRCUMFLEX */
+		{ 0x03a2, 0x0138 }, /*                         kra  LATIN SMALL LETTER KRA */
+		{ 0x03a3, 0x0156 }, /*                    Rcedilla  LATIN CAPITAL LETTER R WITH CEDILLA */
+		{ 0x03a5, 0x0128 }, /*                      Itilde  LATIN CAPITAL LETTER I WITH TILDE */
+		{ 0x03a6, 0x013b }, /*                    Lcedilla  LATIN CAPITAL LETTER L WITH CEDILLA */
+		{ 0x03aa, 0x0112 }, /*                     Emacron  LATIN CAPITAL LETTER E WITH MACRON */
+		{ 0x03ab, 0x0122 }, /*                    Gcedilla  LATIN CAPITAL LETTER G WITH CEDILLA */
+		{ 0x03ac, 0x0166 }, /*                      Tslash  LATIN CAPITAL LETTER T WITH STROKE */
+		{ 0x03b3, 0x0157 }, /*                    rcedilla  LATIN SMALL LETTER R WITH CEDILLA */
+		{ 0x03b5, 0x0129 }, /*                      itilde  LATIN SMALL LETTER I WITH TILDE */
+		{ 0x03b6, 0x013c }, /*                    lcedilla  LATIN SMALL LETTER L WITH CEDILLA */
+		{ 0x03ba, 0x0113 }, /*                     emacron  LATIN SMALL LETTER E WITH MACRON */
+		{ 0x03bb, 0x0123 }, /*                    gcedilla  LATIN SMALL LETTER G WITH CEDILLA */
+		{ 0x03bc, 0x0167 }, /*                      tslash  LATIN SMALL LETTER T WITH STROKE */
+		{ 0x03bd, 0x014a }, /*                         ENG  LATIN CAPITAL LETTER ENG */
+		{ 0x03bf, 0x014b }, /*                         eng  LATIN SMALL LETTER ENG */
+		{ 0x03c0, 0x0100 }, /*                     Amacron  LATIN CAPITAL LETTER A WITH MACRON */
+		{ 0x03c7, 0x012e }, /*                     Iogonek  LATIN CAPITAL LETTER I WITH OGONEK */
+		{ 0x03cc, 0x0116 }, /*                   Eabovedot  LATIN CAPITAL LETTER E WITH DOT ABOVE */
+		{ 0x03cf, 0x012a }, /*                     Imacron  LATIN CAPITAL LETTER I WITH MACRON */
+		{ 0x03d1, 0x0145 }, /*                    Ncedilla  LATIN CAPITAL LETTER N WITH CEDILLA */
+		{ 0x03d2, 0x014c }, /*                     Omacron  LATIN CAPITAL LETTER O WITH MACRON */
+		{ 0x03d3, 0x0136 }, /*                    Kcedilla  LATIN CAPITAL LETTER K WITH CEDILLA */
+		{ 0x03d9, 0x0172 }, /*                     Uogonek  LATIN CAPITAL LETTER U WITH OGONEK */
+		{ 0x03dd, 0x0168 }, /*                      Utilde  LATIN CAPITAL LETTER U WITH TILDE */
+		{ 0x03de, 0x016a }, /*                     Umacron  LATIN CAPITAL LETTER U WITH MACRON */
+		{ 0x03e0, 0x0101 }, /*                     amacron  LATIN SMALL LETTER A WITH MACRON */
+		{ 0x03e7, 0x012f }, /*                     iogonek  LATIN SMALL LETTER I WITH OGONEK */
+		{ 0x03ec, 0x0117 }, /*                   eabovedot  LATIN SMALL LETTER E WITH DOT ABOVE */
+		{ 0x03ef, 0x012b }, /*                     imacron  LATIN SMALL LETTER I WITH MACRON */
+		{ 0x03f1, 0x0146 }, /*                    ncedilla  LATIN SMALL LETTER N WITH CEDILLA */
+		{ 0x03f2, 0x014d }, /*                     omacron  LATIN SMALL LETTER O WITH MACRON */
+		{ 0x03f3, 0x0137 }, /*                    kcedilla  LATIN SMALL LETTER K WITH CEDILLA */
+		{ 0x03f9, 0x0173 }, /*                     uogonek  LATIN SMALL LETTER U WITH OGONEK */
+		{ 0x03fd, 0x0169 }, /*                      utilde  LATIN SMALL LETTER U WITH TILDE */
+		{ 0x03fe, 0x016b }, /*                     umacron  LATIN SMALL LETTER U WITH MACRON */
+		{ 0x047e, 0x203e }, /*                    overline  OVERLINE */
+		{ 0x04a1, 0x3002 }, /*               kana_fullstop  IDEOGRAPHIC FULL STOP */
+		{ 0x04a2, 0x300c }, /*         kana_openingbracket  LEFT CORNER BRACKET */
+		{ 0x04a3, 0x300d }, /*         kana_closingbracket  RIGHT CORNER BRACKET */
+		{ 0x04a4, 0x3001 }, /*                  kana_comma  IDEOGRAPHIC COMMA */
+		{ 0x04a5, 0x30fb }, /*            kana_conjunctive  KATAKANA MIDDLE DOT */
+		{ 0x04a6, 0x30f2 }, /*                     kana_WO  KATAKANA LETTER WO */
+		{ 0x04a7, 0x30a1 }, /*                      kana_a  KATAKANA LETTER SMALL A */
+		{ 0x04a8, 0x30a3 }, /*                      kana_i  KATAKANA LETTER SMALL I */
+		{ 0x04a9, 0x30a5 }, /*                      kana_u  KATAKANA LETTER SMALL U */
+		{ 0x04aa, 0x30a7 }, /*                      kana_e  KATAKANA LETTER SMALL E */
+		{ 0x04ab, 0x30a9 }, /*                      kana_o  KATAKANA LETTER SMALL O */
+		{ 0x04ac, 0x30e3 }, /*                     kana_ya  KATAKANA LETTER SMALL YA */
+		{ 0x04ad, 0x30e5 }, /*                     kana_yu  KATAKANA LETTER SMALL YU */
+		{ 0x04ae, 0x30e7 }, /*                     kana_yo  KATAKANA LETTER SMALL YO */
+		{ 0x04af, 0x30c3 }, /*                    kana_tsu  KATAKANA LETTER SMALL TU */
+		{ 0x04b0, 0x30fc }, /*              prolongedsound  KATAKANA-HIRAGANA PROLONGED SOUND MARK */
+		{ 0x04b1, 0x30a2 }, /*                      kana_A  KATAKANA LETTER A */
+		{ 0x04b2, 0x30a4 }, /*                      kana_I  KATAKANA LETTER I */
+		{ 0x04b3, 0x30a6 }, /*                      kana_U  KATAKANA LETTER U */
+		{ 0x04b4, 0x30a8 }, /*                      kana_E  KATAKANA LETTER E */
+		{ 0x04b5, 0x30aa }, /*                      kana_O  KATAKANA LETTER O */
+		{ 0x04b6, 0x30ab }, /*                     kana_KA  KATAKANA LETTER KA */
+		{ 0x04b7, 0x30ad }, /*                     kana_KI  KATAKANA LETTER KI */
+		{ 0x04b8, 0x30af }, /*                     kana_KU  KATAKANA LETTER KU */
+		{ 0x04b9, 0x30b1 }, /*                     kana_KE  KATAKANA LETTER KE */
+		{ 0x04ba, 0x30b3 }, /*                     kana_KO  KATAKANA LETTER KO */
+		{ 0x04bb, 0x30b5 }, /*                     kana_SA  KATAKANA LETTER SA */
+		{ 0x04bc, 0x30b7 }, /*                    kana_SHI  KATAKANA LETTER SI */
+		{ 0x04bd, 0x30b9 }, /*                     kana_SU  KATAKANA LETTER SU */
+		{ 0x04be, 0x30bb }, /*                     kana_SE  KATAKANA LETTER SE */
+		{ 0x04bf, 0x30bd }, /*                     kana_SO  KATAKANA LETTER SO */
+		{ 0x04c0, 0x30bf }, /*                     kana_TA  KATAKANA LETTER TA */
+		{ 0x04c1, 0x30c1 }, /*                    kana_CHI  KATAKANA LETTER TI */
+		{ 0x04c2, 0x30c4 }, /*                    kana_TSU  KATAKANA LETTER TU */
+		{ 0x04c3, 0x30c6 }, /*                     kana_TE  KATAKANA LETTER TE */
+		{ 0x04c4, 0x30c8 }, /*                     kana_TO  KATAKANA LETTER TO */
+		{ 0x04c5, 0x30ca }, /*                     kana_NA  KATAKANA LETTER NA */
+		{ 0x04c6, 0x30cb }, /*                     kana_NI  KATAKANA LETTER NI */
+		{ 0x04c7, 0x30cc }, /*                     kana_NU  KATAKANA LETTER NU */
+		{ 0x04c8, 0x30cd }, /*                     kana_NE  KATAKANA LETTER NE */
+		{ 0x04c9, 0x30ce }, /*                     kana_NO  KATAKANA LETTER NO */
+		{ 0x04ca, 0x30cf }, /*                     kana_HA  KATAKANA LETTER HA */
+		{ 0x04cb, 0x30d2 }, /*                     kana_HI  KATAKANA LETTER HI */
+		{ 0x04cc, 0x30d5 }, /*                     kana_FU  KATAKANA LETTER HU */
+		{ 0x04cd, 0x30d8 }, /*                     kana_HE  KATAKANA LETTER HE */
+		{ 0x04ce, 0x30db }, /*                     kana_HO  KATAKANA LETTER HO */
+		{ 0x04cf, 0x30de }, /*                     kana_MA  KATAKANA LETTER MA */
+		{ 0x04d0, 0x30df }, /*                     kana_MI  KATAKANA LETTER MI */
+		{ 0x04d1, 0x30e0 }, /*                     kana_MU  KATAKANA LETTER MU */
+		{ 0x04d2, 0x30e1 }, /*                     kana_ME  KATAKANA LETTER ME */
+		{ 0x04d3, 0x30e2 }, /*                     kana_MO  KATAKANA LETTER MO */
+		{ 0x04d4, 0x30e4 }, /*                     kana_YA  KATAKANA LETTER YA */
+		{ 0x04d5, 0x30e6 }, /*                     kana_YU  KATAKANA LETTER YU */
+		{ 0x04d6, 0x30e8 }, /*                     kana_YO  KATAKANA LETTER YO */
+		{ 0x04d7, 0x30e9 }, /*                     kana_RA  KATAKANA LETTER RA */
+		{ 0x04d8, 0x30ea }, /*                     kana_RI  KATAKANA LETTER RI */
+		{ 0x04d9, 0x30eb }, /*                     kana_RU  KATAKANA LETTER RU */
+		{ 0x04da, 0x30ec }, /*                     kana_RE  KATAKANA LETTER RE */
+		{ 0x04db, 0x30ed }, /*                     kana_RO  KATAKANA LETTER RO */
+		{ 0x04dc, 0x30ef }, /*                     kana_WA  KATAKANA LETTER WA */
+		{ 0x04dd, 0x30f3 }, /*                      kana_N  KATAKANA LETTER N */
+		{ 0x04de, 0x309b }, /*                 voicedsound  KATAKANA-HIRAGANA VOICED SOUND MARK */
+		{ 0x04df, 0x309c }, /*             semivoicedsound  KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+		{ 0x05ac, 0x060c }, /*                Arabic_comma  ARABIC COMMA */
+		{ 0x05bb, 0x061b }, /*            Arabic_semicolon  ARABIC SEMICOLON */
+		{ 0x05bf, 0x061f }, /*        Arabic_question_mark  ARABIC QUESTION MARK */
+		{ 0x05c1, 0x0621 }, /*                Arabic_hamza  ARABIC LETTER HAMZA */
+		{ 0x05c2, 0x0622 }, /*          Arabic_maddaonalef  ARABIC LETTER ALEF WITH MADDA ABOVE */
+		{ 0x05c3, 0x0623 }, /*          Arabic_hamzaonalef  ARABIC LETTER ALEF WITH HAMZA ABOVE */
+		{ 0x05c4, 0x0624 }, /*           Arabic_hamzaonwaw  ARABIC LETTER WAW WITH HAMZA ABOVE */
+		{ 0x05c5, 0x0625 }, /*       Arabic_hamzaunderalef  ARABIC LETTER ALEF WITH HAMZA BELOW */
+		{ 0x05c6, 0x0626 }, /*           Arabic_hamzaonyeh  ARABIC LETTER YEH WITH HAMZA ABOVE */
+		{ 0x05c7, 0x0627 }, /*                 Arabic_alef  ARABIC LETTER ALEF */
+		{ 0x05c8, 0x0628 }, /*                  Arabic_beh  ARABIC LETTER BEH */
+		{ 0x05c9, 0x0629 }, /*           Arabic_tehmarbuta  ARABIC LETTER TEH MARBUTA */
+		{ 0x05ca, 0x062a }, /*                  Arabic_teh  ARABIC LETTER TEH */
+		{ 0x05cb, 0x062b }, /*                 Arabic_theh  ARABIC LETTER THEH */
+		{ 0x05cc, 0x062c }, /*                 Arabic_jeem  ARABIC LETTER JEEM */
+		{ 0x05cd, 0x062d }, /*                  Arabic_hah  ARABIC LETTER HAH */
+		{ 0x05ce, 0x062e }, /*                 Arabic_khah  ARABIC LETTER KHAH */
+		{ 0x05cf, 0x062f }, /*                  Arabic_dal  ARABIC LETTER DAL */
+		{ 0x05d0, 0x0630 }, /*                 Arabic_thal  ARABIC LETTER THAL */
+		{ 0x05d1, 0x0631 }, /*                   Arabic_ra  ARABIC LETTER REH */
+		{ 0x05d2, 0x0632 }, /*                 Arabic_zain  ARABIC LETTER ZAIN */
+		{ 0x05d3, 0x0633 }, /*                 Arabic_seen  ARABIC LETTER SEEN */
+		{ 0x05d4, 0x0634 }, /*                Arabic_sheen  ARABIC LETTER SHEEN */
+		{ 0x05d5, 0x0635 }, /*                  Arabic_sad  ARABIC LETTER SAD */
+		{ 0x05d6, 0x0636 }, /*                  Arabic_dad  ARABIC LETTER DAD */
+		{ 0x05d7, 0x0637 }, /*                  Arabic_tah  ARABIC LETTER TAH */
+		{ 0x05d8, 0x0638 }, /*                  Arabic_zah  ARABIC LETTER ZAH */
+		{ 0x05d9, 0x0639 }, /*                  Arabic_ain  ARABIC LETTER AIN */
+		{ 0x05da, 0x063a }, /*                Arabic_ghain  ARABIC LETTER GHAIN */
+		{ 0x05e0, 0x0640 }, /*              Arabic_tatweel  ARABIC TATWEEL */
+		{ 0x05e1, 0x0641 }, /*                  Arabic_feh  ARABIC LETTER FEH */
+		{ 0x05e2, 0x0642 }, /*                  Arabic_qaf  ARABIC LETTER QAF */
+		{ 0x05e3, 0x0643 }, /*                  Arabic_kaf  ARABIC LETTER KAF */
+		{ 0x05e4, 0x0644 }, /*                  Arabic_lam  ARABIC LETTER LAM */
+		{ 0x05e5, 0x0645 }, /*                 Arabic_meem  ARABIC LETTER MEEM */
+		{ 0x05e6, 0x0646 }, /*                 Arabic_noon  ARABIC LETTER NOON */
+		{ 0x05e7, 0x0647 }, /*                   Arabic_ha  ARABIC LETTER HEH */
+		{ 0x05e8, 0x0648 }, /*                  Arabic_waw  ARABIC LETTER WAW */
+		{ 0x05e9, 0x0649 }, /*          Arabic_alefmaksura  ARABIC LETTER ALEF MAKSURA */
+		{ 0x05ea, 0x064a }, /*                  Arabic_yeh  ARABIC LETTER YEH */
+		{ 0x05eb, 0x064b }, /*             Arabic_fathatan  ARABIC FATHATAN */
+		{ 0x05ec, 0x064c }, /*             Arabic_dammatan  ARABIC DAMMATAN */
+		{ 0x05ed, 0x064d }, /*             Arabic_kasratan  ARABIC KASRATAN */
+		{ 0x05ee, 0x064e }, /*                Arabic_fatha  ARABIC FATHA */
+		{ 0x05ef, 0x064f }, /*                Arabic_damma  ARABIC DAMMA */
+		{ 0x05f0, 0x0650 }, /*                Arabic_kasra  ARABIC KASRA */
+		{ 0x05f1, 0x0651 }, /*               Arabic_shadda  ARABIC SHADDA */
+		{ 0x05f2, 0x0652 }, /*                Arabic_sukun  ARABIC SUKUN */
+		{ 0x06a1, 0x0452 }, /*                 Serbian_dje  CYRILLIC SMALL LETTER DJE */
+		{ 0x06a2, 0x0453 }, /*               Macedonia_gje  CYRILLIC SMALL LETTER GJE */
+		{ 0x06a3, 0x0451 }, /*                 Cyrillic_io  CYRILLIC SMALL LETTER IO */
+		{ 0x06a4, 0x0454 }, /*                Ukrainian_ie  CYRILLIC SMALL LETTER UKRAINIAN IE */
+		{ 0x06a5, 0x0455 }, /*               Macedonia_dse  CYRILLIC SMALL LETTER DZE */
+		{ 0x06a6, 0x0456 }, /*                 Ukrainian_i  CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+		{ 0x06a7, 0x0457 }, /*                Ukrainian_yi  CYRILLIC SMALL LETTER YI */
+		{ 0x06a8, 0x0458 }, /*                 Cyrillic_je  CYRILLIC SMALL LETTER JE */
+		{ 0x06a9, 0x0459 }, /*                Cyrillic_lje  CYRILLIC SMALL LETTER LJE */
+		{ 0x06aa, 0x045a }, /*                Cyrillic_nje  CYRILLIC SMALL LETTER NJE */
+		{ 0x06ab, 0x045b }, /*                Serbian_tshe  CYRILLIC SMALL LETTER TSHE */
+		{ 0x06ac, 0x045c }, /*               Macedonia_kje  CYRILLIC SMALL LETTER KJE */
+		{ 0x06ae, 0x045e }, /*         Byelorussian_shortu  CYRILLIC SMALL LETTER SHORT U */
+		{ 0x06af, 0x045f }, /*               Cyrillic_dzhe  CYRILLIC SMALL LETTER DZHE */
+		{ 0x06b0, 0x2116 }, /*                  numerosign  NUMERO SIGN */
+		{ 0x06b1, 0x0402 }, /*                 Serbian_DJE  CYRILLIC CAPITAL LETTER DJE */
+		{ 0x06b2, 0x0403 }, /*               Macedonia_GJE  CYRILLIC CAPITAL LETTER GJE */
+		{ 0x06b3, 0x0401 }, /*                 Cyrillic_IO  CYRILLIC CAPITAL LETTER IO */
+		{ 0x06b4, 0x0404 }, /*                Ukrainian_IE  CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+		{ 0x06b5, 0x0405 }, /*               Macedonia_DSE  CYRILLIC CAPITAL LETTER DZE */
+		{ 0x06b6, 0x0406 }, /*                 Ukrainian_I  CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+		{ 0x06b7, 0x0407 }, /*                Ukrainian_YI  CYRILLIC CAPITAL LETTER YI */
+		{ 0x06b8, 0x0408 }, /*                 Cyrillic_JE  CYRILLIC CAPITAL LETTER JE */
+		{ 0x06b9, 0x0409 }, /*                Cyrillic_LJE  CYRILLIC CAPITAL LETTER LJE */
+		{ 0x06ba, 0x040a }, /*                Cyrillic_NJE  CYRILLIC CAPITAL LETTER NJE */
+		{ 0x06bb, 0x040b }, /*                Serbian_TSHE  CYRILLIC CAPITAL LETTER TSHE */
+		{ 0x06bc, 0x040c }, /*               Macedonia_KJE  CYRILLIC CAPITAL LETTER KJE */
+		{ 0x06be, 0x040e }, /*         Byelorussian_SHORTU  CYRILLIC CAPITAL LETTER SHORT U */
+		{ 0x06bf, 0x040f }, /*               Cyrillic_DZHE  CYRILLIC CAPITAL LETTER DZHE */
+		{ 0x06c0, 0x044e }, /*                 Cyrillic_yu  CYRILLIC SMALL LETTER YU */
+		{ 0x06c1, 0x0430 }, /*                  Cyrillic_a  CYRILLIC SMALL LETTER A */
+		{ 0x06c2, 0x0431 }, /*                 Cyrillic_be  CYRILLIC SMALL LETTER BE */
+		{ 0x06c3, 0x0446 }, /*                Cyrillic_tse  CYRILLIC SMALL LETTER TSE */
+		{ 0x06c4, 0x0434 }, /*                 Cyrillic_de  CYRILLIC SMALL LETTER DE */
+		{ 0x06c5, 0x0435 }, /*                 Cyrillic_ie  CYRILLIC SMALL LETTER IE */
+		{ 0x06c6, 0x0444 }, /*                 Cyrillic_ef  CYRILLIC SMALL LETTER EF */
+		{ 0x06c7, 0x0433 }, /*                Cyrillic_ghe  CYRILLIC SMALL LETTER GHE */
+		{ 0x06c8, 0x0445 }, /*                 Cyrillic_ha  CYRILLIC SMALL LETTER HA */
+		{ 0x06c9, 0x0438 }, /*                  Cyrillic_i  CYRILLIC SMALL LETTER I */
+		{ 0x06ca, 0x0439 }, /*             Cyrillic_shorti  CYRILLIC SMALL LETTER SHORT I */
+		{ 0x06cb, 0x043a }, /*                 Cyrillic_ka  CYRILLIC SMALL LETTER KA */
+		{ 0x06cc, 0x043b }, /*                 Cyrillic_el  CYRILLIC SMALL LETTER EL */
+		{ 0x06cd, 0x043c }, /*                 Cyrillic_em  CYRILLIC SMALL LETTER EM */
+		{ 0x06ce, 0x043d }, /*                 Cyrillic_en  CYRILLIC SMALL LETTER EN */
+		{ 0x06cf, 0x043e }, /*                  Cyrillic_o  CYRILLIC SMALL LETTER O */
+		{ 0x06d0, 0x043f }, /*                 Cyrillic_pe  CYRILLIC SMALL LETTER PE */
+		{ 0x06d1, 0x044f }, /*                 Cyrillic_ya  CYRILLIC SMALL LETTER YA */
+		{ 0x06d2, 0x0440 }, /*                 Cyrillic_er  CYRILLIC SMALL LETTER ER */
+		{ 0x06d3, 0x0441 }, /*                 Cyrillic_es  CYRILLIC SMALL LETTER ES */
+		{ 0x06d4, 0x0442 }, /*                 Cyrillic_te  CYRILLIC SMALL LETTER TE */
+		{ 0x06d5, 0x0443 }, /*                  Cyrillic_u  CYRILLIC SMALL LETTER U */
+		{ 0x06d6, 0x0436 }, /*                Cyrillic_zhe  CYRILLIC SMALL LETTER ZHE */
+		{ 0x06d7, 0x0432 }, /*                 Cyrillic_ve  CYRILLIC SMALL LETTER VE */
+		{ 0x06d8, 0x044c }, /*           Cyrillic_softsign  CYRILLIC SMALL LETTER SOFT SIGN */
+		{ 0x06d9, 0x044b }, /*               Cyrillic_yeru  CYRILLIC SMALL LETTER YERU */
+		{ 0x06da, 0x0437 }, /*                 Cyrillic_ze  CYRILLIC SMALL LETTER ZE */
+		{ 0x06db, 0x0448 }, /*                Cyrillic_sha  CYRILLIC SMALL LETTER SHA */
+		{ 0x06dc, 0x044d }, /*                  Cyrillic_e  CYRILLIC SMALL LETTER E */
+		{ 0x06dd, 0x0449 }, /*              Cyrillic_shcha  CYRILLIC SMALL LETTER SHCHA */
+		{ 0x06de, 0x0447 }, /*                Cyrillic_che  CYRILLIC SMALL LETTER CHE */
+		{ 0x06df, 0x044a }, /*           Cyrillic_hardsign  CYRILLIC SMALL LETTER HARD SIGN */
+		{ 0x06e0, 0x042e }, /*                 Cyrillic_YU  CYRILLIC CAPITAL LETTER YU */
+		{ 0x06e1, 0x0410 }, /*                  Cyrillic_A  CYRILLIC CAPITAL LETTER A */
+		{ 0x06e2, 0x0411 }, /*                 Cyrillic_BE  CYRILLIC CAPITAL LETTER BE */
+		{ 0x06e3, 0x0426 }, /*                Cyrillic_TSE  CYRILLIC CAPITAL LETTER TSE */
+		{ 0x06e4, 0x0414 }, /*                 Cyrillic_DE  CYRILLIC CAPITAL LETTER DE */
+		{ 0x06e5, 0x0415 }, /*                 Cyrillic_IE  CYRILLIC CAPITAL LETTER IE */
+		{ 0x06e6, 0x0424 }, /*                 Cyrillic_EF  CYRILLIC CAPITAL LETTER EF */
+		{ 0x06e7, 0x0413 }, /*                Cyrillic_GHE  CYRILLIC CAPITAL LETTER GHE */
+		{ 0x06e8, 0x0425 }, /*                 Cyrillic_HA  CYRILLIC CAPITAL LETTER HA */
+		{ 0x06e9, 0x0418 }, /*                  Cyrillic_I  CYRILLIC CAPITAL LETTER I */
+		{ 0x06ea, 0x0419 }, /*             Cyrillic_SHORTI  CYRILLIC CAPITAL LETTER SHORT I */
+		{ 0x06eb, 0x041a }, /*                 Cyrillic_KA  CYRILLIC CAPITAL LETTER KA */
+		{ 0x06ec, 0x041b }, /*                 Cyrillic_EL  CYRILLIC CAPITAL LETTER EL */
+		{ 0x06ed, 0x041c }, /*                 Cyrillic_EM  CYRILLIC CAPITAL LETTER EM */
+		{ 0x06ee, 0x041d }, /*                 Cyrillic_EN  CYRILLIC CAPITAL LETTER EN */
+		{ 0x06ef, 0x041e }, /*                  Cyrillic_O  CYRILLIC CAPITAL LETTER O */
+		{ 0x06f0, 0x041f }, /*                 Cyrillic_PE  CYRILLIC CAPITAL LETTER PE */
+		{ 0x06f1, 0x042f }, /*                 Cyrillic_YA  CYRILLIC CAPITAL LETTER YA */
+		{ 0x06f2, 0x0420 }, /*                 Cyrillic_ER  CYRILLIC CAPITAL LETTER ER */
+		{ 0x06f3, 0x0421 }, /*                 Cyrillic_ES  CYRILLIC CAPITAL LETTER ES */
+		{ 0x06f4, 0x0422 }, /*                 Cyrillic_TE  CYRILLIC CAPITAL LETTER TE */
+		{ 0x06f5, 0x0423 }, /*                  Cyrillic_U  CYRILLIC CAPITAL LETTER U */
+		{ 0x06f6, 0x0416 }, /*                Cyrillic_ZHE  CYRILLIC CAPITAL LETTER ZHE */
+		{ 0x06f7, 0x0412 }, /*                 Cyrillic_VE  CYRILLIC CAPITAL LETTER VE */
+		{ 0x06f8, 0x042c }, /*           Cyrillic_SOFTSIGN  CYRILLIC CAPITAL LETTER SOFT SIGN */
+		{ 0x06f9, 0x042b }, /*               Cyrillic_YERU  CYRILLIC CAPITAL LETTER YERU */
+		{ 0x06fa, 0x0417 }, /*                 Cyrillic_ZE  CYRILLIC CAPITAL LETTER ZE */
+		{ 0x06fb, 0x0428 }, /*                Cyrillic_SHA  CYRILLIC CAPITAL LETTER SHA */
+		{ 0x06fc, 0x042d }, /*                  Cyrillic_E  CYRILLIC CAPITAL LETTER E */
+		{ 0x06fd, 0x0429 }, /*              Cyrillic_SHCHA  CYRILLIC CAPITAL LETTER SHCHA */
+		{ 0x06fe, 0x0427 }, /*                Cyrillic_CHE  CYRILLIC CAPITAL LETTER CHE */
+		{ 0x06ff, 0x042a }, /*           Cyrillic_HARDSIGN  CYRILLIC CAPITAL LETTER HARD SIGN */
+		{ 0x07a1, 0x0386 }, /*           Greek_ALPHAaccent  GREEK CAPITAL LETTER ALPHA WITH TONOS */
+		{ 0x07a2, 0x0388 }, /*         Greek_EPSILONaccent  GREEK CAPITAL LETTER EPSILON WITH TONOS */
+		{ 0x07a3, 0x0389 }, /*             Greek_ETAaccent  GREEK CAPITAL LETTER ETA WITH TONOS */
+		{ 0x07a4, 0x038a }, /*            Greek_IOTAaccent  GREEK CAPITAL LETTER IOTA WITH TONOS */
+		{ 0x07a5, 0x03aa }, /*         Greek_IOTAdiaeresis  GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+		{ 0x07a7, 0x038c }, /*         Greek_OMICRONaccent  GREEK CAPITAL LETTER OMICRON WITH TONOS */
+		{ 0x07a8, 0x038e }, /*         Greek_UPSILONaccent  GREEK CAPITAL LETTER UPSILON WITH TONOS */
+		{ 0x07a9, 0x03ab }, /*       Greek_UPSILONdieresis  GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+		{ 0x07ab, 0x038f }, /*           Greek_OMEGAaccent  GREEK CAPITAL LETTER OMEGA WITH TONOS */
+		{ 0x07ae, 0x0385 }, /*        Greek_accentdieresis  GREEK DIALYTIKA TONOS */
+		{ 0x07af, 0x2015 }, /*              Greek_horizbar  HORIZONTAL BAR */
+		{ 0x07b1, 0x03ac }, /*           Greek_alphaaccent  GREEK SMALL LETTER ALPHA WITH TONOS */
+		{ 0x07b2, 0x03ad }, /*         Greek_epsilonaccent  GREEK SMALL LETTER EPSILON WITH TONOS */
+		{ 0x07b3, 0x03ae }, /*             Greek_etaaccent  GREEK SMALL LETTER ETA WITH TONOS */
+		{ 0x07b4, 0x03af }, /*            Greek_iotaaccent  GREEK SMALL LETTER IOTA WITH TONOS */
+		{ 0x07b5, 0x03ca }, /*          Greek_iotadieresis  GREEK SMALL LETTER IOTA WITH DIALYTIKA */
+		{ 0x07b6, 0x0390 }, /*    Greek_iotaaccentdieresis  GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+		{ 0x07b7, 0x03cc }, /*         Greek_omicronaccent  GREEK SMALL LETTER OMICRON WITH TONOS */
+		{ 0x07b8, 0x03cd }, /*         Greek_upsilonaccent  GREEK SMALL LETTER UPSILON WITH TONOS */
+		{ 0x07b9, 0x03cb }, /*       Greek_upsilondieresis  GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
+		{ 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis  GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+		{ 0x07bb, 0x03ce }, /*           Greek_omegaaccent  GREEK SMALL LETTER OMEGA WITH TONOS */
+		{ 0x07c1, 0x0391 }, /*                 Greek_ALPHA  GREEK CAPITAL LETTER ALPHA */
+		{ 0x07c2, 0x0392 }, /*                  Greek_BETA  GREEK CAPITAL LETTER BETA */
+		{ 0x07c3, 0x0393 }, /*                 Greek_GAMMA  GREEK CAPITAL LETTER GAMMA */
+		{ 0x07c4, 0x0394 }, /*                 Greek_DELTA  GREEK CAPITAL LETTER DELTA */
+		{ 0x07c5, 0x0395 }, /*               Greek_EPSILON  GREEK CAPITAL LETTER EPSILON */
+		{ 0x07c6, 0x0396 }, /*                  Greek_ZETA  GREEK CAPITAL LETTER ZETA */
+		{ 0x07c7, 0x0397 }, /*                   Greek_ETA  GREEK CAPITAL LETTER ETA */
+		{ 0x07c8, 0x0398 }, /*                 Greek_THETA  GREEK CAPITAL LETTER THETA */
+		{ 0x07c9, 0x0399 }, /*                  Greek_IOTA  GREEK CAPITAL LETTER IOTA */
+		{ 0x07ca, 0x039a }, /*                 Greek_KAPPA  GREEK CAPITAL LETTER KAPPA */
+		{ 0x07cb, 0x039b }, /*                Greek_LAMBDA  GREEK CAPITAL LETTER LAMDA */
+		{ 0x07cc, 0x039c }, /*                    Greek_MU  GREEK CAPITAL LETTER MU */
+		{ 0x07cd, 0x039d }, /*                    Greek_NU  GREEK CAPITAL LETTER NU */
+		{ 0x07ce, 0x039e }, /*                    Greek_XI  GREEK CAPITAL LETTER XI */
+		{ 0x07cf, 0x039f }, /*               Greek_OMICRON  GREEK CAPITAL LETTER OMICRON */
+		{ 0x07d0, 0x03a0 }, /*                    Greek_PI  GREEK CAPITAL LETTER PI */
+		{ 0x07d1, 0x03a1 }, /*                   Greek_RHO  GREEK CAPITAL LETTER RHO */
+		{ 0x07d2, 0x03a3 }, /*                 Greek_SIGMA  GREEK CAPITAL LETTER SIGMA */
+		{ 0x07d4, 0x03a4 }, /*                   Greek_TAU  GREEK CAPITAL LETTER TAU */
+		{ 0x07d5, 0x03a5 }, /*               Greek_UPSILON  GREEK CAPITAL LETTER UPSILON */
+		{ 0x07d6, 0x03a6 }, /*                   Greek_PHI  GREEK CAPITAL LETTER PHI */
+		{ 0x07d7, 0x03a7 }, /*                   Greek_CHI  GREEK CAPITAL LETTER CHI */
+		{ 0x07d8, 0x03a8 }, /*                   Greek_PSI  GREEK CAPITAL LETTER PSI */
+		{ 0x07d9, 0x03a9 }, /*                 Greek_OMEGA  GREEK CAPITAL LETTER OMEGA */
+		{ 0x07e1, 0x03b1 }, /*                 Greek_alpha  GREEK SMALL LETTER ALPHA */
+		{ 0x07e2, 0x03b2 }, /*                  Greek_beta  GREEK SMALL LETTER BETA */
+		{ 0x07e3, 0x03b3 }, /*                 Greek_gamma  GREEK SMALL LETTER GAMMA */
+		{ 0x07e4, 0x03b4 }, /*                 Greek_delta  GREEK SMALL LETTER DELTA */
+		{ 0x07e5, 0x03b5 }, /*               Greek_epsilon  GREEK SMALL LETTER EPSILON */
+		{ 0x07e6, 0x03b6 }, /*                  Greek_zeta  GREEK SMALL LETTER ZETA */
+		{ 0x07e7, 0x03b7 }, /*                   Greek_eta  GREEK SMALL LETTER ETA */
+		{ 0x07e8, 0x03b8 }, /*                 Greek_theta  GREEK SMALL LETTER THETA */
+		{ 0x07e9, 0x03b9 }, /*                  Greek_iota  GREEK SMALL LETTER IOTA */
+		{ 0x07ea, 0x03ba }, /*                 Greek_kappa  GREEK SMALL LETTER KAPPA */
+		{ 0x07eb, 0x03bb }, /*                Greek_lambda  GREEK SMALL LETTER LAMDA */
+		{ 0x07ec, 0x03bc }, /*                    Greek_mu  GREEK SMALL LETTER MU */
+		{ 0x07ed, 0x03bd }, /*                    Greek_nu  GREEK SMALL LETTER NU */
+		{ 0x07ee, 0x03be }, /*                    Greek_xi  GREEK SMALL LETTER XI */
+		{ 0x07ef, 0x03bf }, /*               Greek_omicron  GREEK SMALL LETTER OMICRON */
+		{ 0x07f0, 0x03c0 }, /*                    Greek_pi  GREEK SMALL LETTER PI */
+		{ 0x07f1, 0x03c1 }, /*                   Greek_rho  GREEK SMALL LETTER RHO */
+		{ 0x07f2, 0x03c3 }, /*                 Greek_sigma  GREEK SMALL LETTER SIGMA */
+		{ 0x07f3, 0x03c2 }, /*       Greek_finalsmallsigma  GREEK SMALL LETTER FINAL SIGMA */
+		{ 0x07f4, 0x03c4 }, /*                   Greek_tau  GREEK SMALL LETTER TAU */
+		{ 0x07f5, 0x03c5 }, /*               Greek_upsilon  GREEK SMALL LETTER UPSILON */
+		{ 0x07f6, 0x03c6 }, /*                   Greek_phi  GREEK SMALL LETTER PHI */
+		{ 0x07f7, 0x03c7 }, /*                   Greek_chi  GREEK SMALL LETTER CHI */
+		{ 0x07f8, 0x03c8 }, /*                   Greek_psi  GREEK SMALL LETTER PSI */
+		{ 0x07f9, 0x03c9 }, /*                 Greek_omega  GREEK SMALL LETTER OMEGA */
+		{ 0x08a1, 0x23b7 }, /*                 leftradical  ??? */
+		{ 0x08a2, 0x250c }, /*              topleftradical  BOX DRAWINGS LIGHT DOWN AND RIGHT */
+		{ 0x08a3, 0x2500 }, /*              horizconnector  BOX DRAWINGS LIGHT HORIZONTAL */
+		{ 0x08a4, 0x2320 }, /*                 topintegral  TOP HALF INTEGRAL */
+		{ 0x08a5, 0x2321 }, /*                 botintegral  BOTTOM HALF INTEGRAL */
+		{ 0x08a6, 0x2502 }, /*               vertconnector  BOX DRAWINGS LIGHT VERTICAL */
+		{ 0x08a7, 0x23a1 }, /*            topleftsqbracket  ??? */
+		{ 0x08a8, 0x23a3 }, /*            botleftsqbracket  ??? */
+		{ 0x08a9, 0x23a4 }, /*           toprightsqbracket  ??? */
+		{ 0x08aa, 0x23a6 }, /*           botrightsqbracket  ??? */
+		{ 0x08ab, 0x239b }, /*               topleftparens  ??? */
+		{ 0x08ac, 0x239d }, /*               botleftparens  ??? */
+		{ 0x08ad, 0x239e }, /*              toprightparens  ??? */
+		{ 0x08ae, 0x23a0 }, /*              botrightparens  ??? */
+		{ 0x08af, 0x23a8 }, /*        leftmiddlecurlybrace  ??? */
+		{ 0x08b0, 0x23ac }, /*       rightmiddlecurlybrace  ??? */
+		/*  0x08b1                          topleftsummation  ??? */
+		/*  0x08b2                          botleftsummation  ??? */
+		/*  0x08b3                 topvertsummationconnector  ??? */
+		/*  0x08b4                 botvertsummationconnector  ??? */
+		/*  0x08b5                         toprightsummation  ??? */
+		/*  0x08b6                         botrightsummation  ??? */
+		/*  0x08b7                      rightmiddlesummation  ??? */
+		{ 0x08bc, 0x2264 }, /*               lessthanequal  LESS-THAN OR EQUAL TO */
+		{ 0x08bd, 0x2260 }, /*                    notequal  NOT EQUAL TO */
+		{ 0x08be, 0x2265 }, /*            greaterthanequal  GREATER-THAN OR EQUAL TO */
+		{ 0x08bf, 0x222b }, /*                    integral  INTEGRAL */
+		{ 0x08c0, 0x2234 }, /*                   therefore  THEREFORE */
+		{ 0x08c1, 0x221d }, /*                   variation  PROPORTIONAL TO */
+		{ 0x08c2, 0x221e }, /*                    infinity  INFINITY */
+		{ 0x08c5, 0x2207 }, /*                       nabla  NABLA */
+		{ 0x08c8, 0x223c }, /*                 approximate  TILDE OPERATOR */
+		{ 0x08c9, 0x2243 }, /*                similarequal  ASYMPTOTICALLY EQUAL TO */
+		{ 0x08cd, 0x21d4 }, /*                    ifonlyif  LEFT RIGHT DOUBLE ARROW */
+		{ 0x08ce, 0x21d2 }, /*                     implies  RIGHTWARDS DOUBLE ARROW */
+		{ 0x08cf, 0x2261 }, /*                   identical  IDENTICAL TO */
+		{ 0x08d6, 0x221a }, /*                     radical  SQUARE ROOT */
+		{ 0x08da, 0x2282 }, /*                  includedin  SUBSET OF */
+		{ 0x08db, 0x2283 }, /*                    includes  SUPERSET OF */
+		{ 0x08dc, 0x2229 }, /*                intersection  INTERSECTION */
+		{ 0x08dd, 0x222a }, /*                       union  UNION */
+		{ 0x08de, 0x2227 }, /*                  logicaland  LOGICAL AND */
+		{ 0x08df, 0x2228 }, /*                   logicalor  LOGICAL OR */
+		{ 0x08ef, 0x2202 }, /*           partialderivative  PARTIAL DIFFERENTIAL */
+		{ 0x08f6, 0x0192 }, /*                    function  LATIN SMALL LETTER F WITH HOOK */
+		{ 0x08fb, 0x2190 }, /*                   leftarrow  LEFTWARDS ARROW */
+		{ 0x08fc, 0x2191 }, /*                     uparrow  UPWARDS ARROW */
+		{ 0x08fd, 0x2192 }, /*                  rightarrow  RIGHTWARDS ARROW */
+		{ 0x08fe, 0x2193 }, /*                   downarrow  DOWNWARDS ARROW */
+		/*  0x09df                                     blank  ??? */
+		{ 0x09e0, 0x25c6 }, /*                soliddiamond  BLACK DIAMOND */
+		{ 0x09e1, 0x2592 }, /*                checkerboard  MEDIUM SHADE */
+		{ 0x09e2, 0x2409 }, /*                          ht  SYMBOL FOR HORIZONTAL TABULATION */
+		{ 0x09e3, 0x240c }, /*                          ff  SYMBOL FOR FORM FEED */
+		{ 0x09e4, 0x240d }, /*                          cr  SYMBOL FOR CARRIAGE RETURN */
+		{ 0x09e5, 0x240a }, /*                          lf  SYMBOL FOR LINE FEED */
+		{ 0x09e8, 0x2424 }, /*                          nl  SYMBOL FOR NEWLINE */
+		{ 0x09e9, 0x240b }, /*                          vt  SYMBOL FOR VERTICAL TABULATION */
+		{ 0x09ea, 0x2518 }, /*              lowrightcorner  BOX DRAWINGS LIGHT UP AND LEFT */
+		{ 0x09eb, 0x2510 }, /*               uprightcorner  BOX DRAWINGS LIGHT DOWN AND LEFT */
+		{ 0x09ec, 0x250c }, /*                upleftcorner  BOX DRAWINGS LIGHT DOWN AND RIGHT */
+		{ 0x09ed, 0x2514 }, /*               lowleftcorner  BOX DRAWINGS LIGHT UP AND RIGHT */
+		{ 0x09ee, 0x253c }, /*               crossinglines  BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+		{ 0x09ef, 0x23ba }, /*              horizlinescan1  HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
+		{ 0x09f0, 0x23bb }, /*              horizlinescan3  HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
+		{ 0x09f1, 0x2500 }, /*              horizlinescan5  BOX DRAWINGS LIGHT HORIZONTAL */
+		{ 0x09f2, 0x23bc }, /*              horizlinescan7  HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
+		{ 0x09f3, 0x23bd }, /*              horizlinescan9  HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
+		{ 0x09f4, 0x251c }, /*                       leftt  BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+		{ 0x09f5, 0x2524 }, /*                      rightt  BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+		{ 0x09f6, 0x2534 }, /*                        bott  BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+		{ 0x09f7, 0x252c }, /*                        topt  BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+		{ 0x09f8, 0x2502 }, /*                     vertbar  BOX DRAWINGS LIGHT VERTICAL */
+		{ 0x0aa1, 0x2003 }, /*                     emspace  EM SPACE */
+		{ 0x0aa2, 0x2002 }, /*                     enspace  EN SPACE */
+		{ 0x0aa3, 0x2004 }, /*                    em3space  THREE-PER-EM SPACE */
+		{ 0x0aa4, 0x2005 }, /*                    em4space  FOUR-PER-EM SPACE */
+		{ 0x0aa5, 0x2007 }, /*                  digitspace  FIGURE SPACE */
+		{ 0x0aa6, 0x2008 }, /*                  punctspace  PUNCTUATION SPACE */
+		{ 0x0aa7, 0x2009 }, /*                   thinspace  THIN SPACE */
+		{ 0x0aa8, 0x200a }, /*                   hairspace  HAIR SPACE */
+		{ 0x0aa9, 0x2014 }, /*                      emdash  EM DASH */
+		{ 0x0aaa, 0x2013 }, /*                      endash  EN DASH */
+		/*  0x0aac                               signifblank  ??? */
+		{ 0x0aae, 0x2026 }, /*                    ellipsis  HORIZONTAL ELLIPSIS */
+		{ 0x0aaf, 0x2025 }, /*             doubbaselinedot  TWO DOT LEADER */
+		{ 0x0ab0, 0x2153 }, /*                    onethird  VULGAR FRACTION ONE THIRD */
+		{ 0x0ab1, 0x2154 }, /*                   twothirds  VULGAR FRACTION TWO THIRDS */
+		{ 0x0ab2, 0x2155 }, /*                    onefifth  VULGAR FRACTION ONE FIFTH */
+		{ 0x0ab3, 0x2156 }, /*                   twofifths  VULGAR FRACTION TWO FIFTHS */
+		{ 0x0ab4, 0x2157 }, /*                 threefifths  VULGAR FRACTION THREE FIFTHS */
+		{ 0x0ab5, 0x2158 }, /*                  fourfifths  VULGAR FRACTION FOUR FIFTHS */
+		{ 0x0ab6, 0x2159 }, /*                    onesixth  VULGAR FRACTION ONE SIXTH */
+		{ 0x0ab7, 0x215a }, /*                  fivesixths  VULGAR FRACTION FIVE SIXTHS */
+		{ 0x0ab8, 0x2105 }, /*                      careof  CARE OF */
+		{ 0x0abb, 0x2012 }, /*                     figdash  FIGURE DASH */
+		{ 0x0abc, 0x2329 }, /*            leftanglebracket  LEFT-POINTING ANGLE BRACKET */
+		/*  0x0abd                              decimalpoint  ??? */
+		{ 0x0abe, 0x232a }, /*           rightanglebracket  RIGHT-POINTING ANGLE BRACKET */
+		/*  0x0abf                                    marker  ??? */
+		{ 0x0ac3, 0x215b }, /*                   oneeighth  VULGAR FRACTION ONE EIGHTH */
+		{ 0x0ac4, 0x215c }, /*                threeeighths  VULGAR FRACTION THREE EIGHTHS */
+		{ 0x0ac5, 0x215d }, /*                 fiveeighths  VULGAR FRACTION FIVE EIGHTHS */
+		{ 0x0ac6, 0x215e }, /*                seveneighths  VULGAR FRACTION SEVEN EIGHTHS */
+		{ 0x0ac9, 0x2122 }, /*                   trademark  TRADE MARK SIGN */
+		{ 0x0aca, 0x2613 }, /*               signaturemark  SALTIRE */
+		/*  0x0acb                         trademarkincircle  ??? */
+		{ 0x0acc, 0x25c1 }, /*            leftopentriangle  WHITE LEFT-POINTING TRIANGLE */
+		{ 0x0acd, 0x25b7 }, /*           rightopentriangle  WHITE RIGHT-POINTING TRIANGLE */
+		{ 0x0ace, 0x25cb }, /*                emopencircle  WHITE CIRCLE */
+		{ 0x0acf, 0x25af }, /*             emopenrectangle  WHITE VERTICAL RECTANGLE */
+		{ 0x0ad0, 0x2018 }, /*         leftsinglequotemark  LEFT SINGLE QUOTATION MARK */
+		{ 0x0ad1, 0x2019 }, /*        rightsinglequotemark  RIGHT SINGLE QUOTATION MARK */
+		{ 0x0ad2, 0x201c }, /*         leftdoublequotemark  LEFT DOUBLE QUOTATION MARK */
+		{ 0x0ad3, 0x201d }, /*        rightdoublequotemark  RIGHT DOUBLE QUOTATION MARK */
+		{ 0x0ad4, 0x211e }, /*                prescription  PRESCRIPTION TAKE */
+		{ 0x0ad6, 0x2032 }, /*                     minutes  PRIME */
+		{ 0x0ad7, 0x2033 }, /*                     seconds  DOUBLE PRIME */
+		{ 0x0ad9, 0x271d }, /*                  latincross  LATIN CROSS */
+		/*  0x0ada                                  hexagram  ??? */
+		{ 0x0adb, 0x25ac }, /*            filledrectbullet  BLACK RECTANGLE */
+		{ 0x0adc, 0x25c0 }, /*         filledlefttribullet  BLACK LEFT-POINTING TRIANGLE */
+		{ 0x0add, 0x25b6 }, /*        filledrighttribullet  BLACK RIGHT-POINTING TRIANGLE */
+		{ 0x0ade, 0x25cf }, /*              emfilledcircle  BLACK CIRCLE */
+		{ 0x0adf, 0x25ae }, /*                emfilledrect  BLACK VERTICAL RECTANGLE */
+		{ 0x0ae0, 0x25e6 }, /*            enopencircbullet  WHITE BULLET */
+		{ 0x0ae1, 0x25ab }, /*          enopensquarebullet  WHITE SMALL SQUARE */
+		{ 0x0ae2, 0x25ad }, /*              openrectbullet  WHITE RECTANGLE */
+		{ 0x0ae3, 0x25b3 }, /*             opentribulletup  WHITE UP-POINTING TRIANGLE */
+		{ 0x0ae4, 0x25bd }, /*           opentribulletdown  WHITE DOWN-POINTING TRIANGLE */
+		{ 0x0ae5, 0x2606 }, /*                    openstar  WHITE STAR */
+		{ 0x0ae6, 0x2022 }, /*          enfilledcircbullet  BULLET */
+		{ 0x0ae7, 0x25aa }, /*            enfilledsqbullet  BLACK SMALL SQUARE */
+		{ 0x0ae8, 0x25b2 }, /*           filledtribulletup  BLACK UP-POINTING TRIANGLE */
+		{ 0x0ae9, 0x25bc }, /*         filledtribulletdown  BLACK DOWN-POINTING TRIANGLE */
+		{ 0x0aea, 0x261c }, /*                 leftpointer  WHITE LEFT POINTING INDEX */
+		{ 0x0aeb, 0x261e }, /*                rightpointer  WHITE RIGHT POINTING INDEX */
+		{ 0x0aec, 0x2663 }, /*                        club  BLACK CLUB SUIT */
+		{ 0x0aed, 0x2666 }, /*                     diamond  BLACK DIAMOND SUIT */
+		{ 0x0aee, 0x2665 }, /*                       heart  BLACK HEART SUIT */
+		{ 0x0af0, 0x2720 }, /*                maltesecross  MALTESE CROSS */
+		{ 0x0af1, 0x2020 }, /*                      dagger  DAGGER */
+		{ 0x0af2, 0x2021 }, /*                doubledagger  DOUBLE DAGGER */
+		{ 0x0af3, 0x2713 }, /*                   checkmark  CHECK MARK */
+		{ 0x0af4, 0x2717 }, /*                 ballotcross  BALLOT X */
+		{ 0x0af5, 0x266f }, /*                musicalsharp  MUSIC SHARP SIGN */
+		{ 0x0af6, 0x266d }, /*                 musicalflat  MUSIC FLAT SIGN */
+		{ 0x0af7, 0x2642 }, /*                  malesymbol  MALE SIGN */
+		{ 0x0af8, 0x2640 }, /*                femalesymbol  FEMALE SIGN */
+		{ 0x0af9, 0x260e }, /*                   telephone  BLACK TELEPHONE */
+		{ 0x0afa, 0x2315 }, /*           telephonerecorder  TELEPHONE RECORDER */
+		{ 0x0afb, 0x2117 }, /*         phonographcopyright  SOUND RECORDING COPYRIGHT */
+		{ 0x0afc, 0x2038 }, /*                       caret  CARET */
+		{ 0x0afd, 0x201a }, /*          singlelowquotemark  SINGLE LOW-9 QUOTATION MARK */
+		{ 0x0afe, 0x201e }, /*          doublelowquotemark  DOUBLE LOW-9 QUOTATION MARK */
+		/*  0x0aff                                    cursor  ??? */
+		{ 0x0ba3, 0x003c }, /*                   leftcaret  LESS-THAN SIGN */
+		{ 0x0ba6, 0x003e }, /*                  rightcaret  GREATER-THAN SIGN */
+		{ 0x0ba8, 0x2228 }, /*                   downcaret  LOGICAL OR */
+		{ 0x0ba9, 0x2227 }, /*                     upcaret  LOGICAL AND */
+		{ 0x0bc0, 0x00af }, /*                     overbar  MACRON */
+		{ 0x0bc2, 0x22a5 }, /*                    downtack  UP TACK */
+		{ 0x0bc3, 0x2229 }, /*                      upshoe  INTERSECTION */
+		{ 0x0bc4, 0x230a }, /*                   downstile  LEFT FLOOR */
+		{ 0x0bc6, 0x005f }, /*                    underbar  LOW LINE */
+		{ 0x0bca, 0x2218 }, /*                         jot  RING OPERATOR */
+		{ 0x0bcc, 0x2395 }, /*                        quad  APL FUNCTIONAL SYMBOL QUAD */
+		{ 0x0bce, 0x22a4 }, /*                      uptack  DOWN TACK */
+		{ 0x0bcf, 0x25cb }, /*                      circle  WHITE CIRCLE */
+		{ 0x0bd3, 0x2308 }, /*                     upstile  LEFT CEILING */
+		{ 0x0bd6, 0x222a }, /*                    downshoe  UNION */
+		{ 0x0bd8, 0x2283 }, /*                   rightshoe  SUPERSET OF */
+		{ 0x0bda, 0x2282 }, /*                    leftshoe  SUBSET OF */
+		{ 0x0bdc, 0x22a2 }, /*                    lefttack  RIGHT TACK */
+		{ 0x0bfc, 0x22a3 }, /*                   righttack  LEFT TACK */
+		{ 0x0cdf, 0x2017 }, /*        hebrew_doublelowline  DOUBLE LOW LINE */
+		{ 0x0ce0, 0x05d0 }, /*                hebrew_aleph  HEBREW LETTER ALEF */
+		{ 0x0ce1, 0x05d1 }, /*                  hebrew_bet  HEBREW LETTER BET */
+		{ 0x0ce2, 0x05d2 }, /*                hebrew_gimel  HEBREW LETTER GIMEL */
+		{ 0x0ce3, 0x05d3 }, /*                hebrew_dalet  HEBREW LETTER DALET */
+		{ 0x0ce4, 0x05d4 }, /*                   hebrew_he  HEBREW LETTER HE */
+		{ 0x0ce5, 0x05d5 }, /*                  hebrew_waw  HEBREW LETTER VAV */
+		{ 0x0ce6, 0x05d6 }, /*                 hebrew_zain  HEBREW LETTER ZAYIN */
+		{ 0x0ce7, 0x05d7 }, /*                 hebrew_chet  HEBREW LETTER HET */
+		{ 0x0ce8, 0x05d8 }, /*                  hebrew_tet  HEBREW LETTER TET */
+		{ 0x0ce9, 0x05d9 }, /*                  hebrew_yod  HEBREW LETTER YOD */
+		{ 0x0cea, 0x05da }, /*            hebrew_finalkaph  HEBREW LETTER FINAL KAF */
+		{ 0x0ceb, 0x05db }, /*                 hebrew_kaph  HEBREW LETTER KAF */
+		{ 0x0cec, 0x05dc }, /*                hebrew_lamed  HEBREW LETTER LAMED */
+		{ 0x0ced, 0x05dd }, /*             hebrew_finalmem  HEBREW LETTER FINAL MEM */
+		{ 0x0cee, 0x05de }, /*                  hebrew_mem  HEBREW LETTER MEM */
+		{ 0x0cef, 0x05df }, /*             hebrew_finalnun  HEBREW LETTER FINAL NUN */
+		{ 0x0cf0, 0x05e0 }, /*                  hebrew_nun  HEBREW LETTER NUN */
+		{ 0x0cf1, 0x05e1 }, /*               hebrew_samech  HEBREW LETTER SAMEKH */
+		{ 0x0cf2, 0x05e2 }, /*                 hebrew_ayin  HEBREW LETTER AYIN */
+		{ 0x0cf3, 0x05e3 }, /*              hebrew_finalpe  HEBREW LETTER FINAL PE */
+		{ 0x0cf4, 0x05e4 }, /*                   hebrew_pe  HEBREW LETTER PE */
+		{ 0x0cf5, 0x05e5 }, /*            hebrew_finalzade  HEBREW LETTER FINAL TSADI */
+		{ 0x0cf6, 0x05e6 }, /*                 hebrew_zade  HEBREW LETTER TSADI */
+		{ 0x0cf7, 0x05e7 }, /*                 hebrew_qoph  HEBREW LETTER QOF */
+		{ 0x0cf8, 0x05e8 }, /*                 hebrew_resh  HEBREW LETTER RESH */
+		{ 0x0cf9, 0x05e9 }, /*                 hebrew_shin  HEBREW LETTER SHIN */
+		{ 0x0cfa, 0x05ea }, /*                  hebrew_taw  HEBREW LETTER TAV */
+		{ 0x0da1, 0x0e01 }, /*                  Thai_kokai  THAI CHARACTER KO KAI */
+		{ 0x0da2, 0x0e02 }, /*                Thai_khokhai  THAI CHARACTER KHO KHAI */
+		{ 0x0da3, 0x0e03 }, /*               Thai_khokhuat  THAI CHARACTER KHO KHUAT */
+		{ 0x0da4, 0x0e04 }, /*               Thai_khokhwai  THAI CHARACTER KHO KHWAI */
+		{ 0x0da5, 0x0e05 }, /*                Thai_khokhon  THAI CHARACTER KHO KHON */
+		{ 0x0da6, 0x0e06 }, /*             Thai_khorakhang  THAI CHARACTER KHO RAKHANG */
+		{ 0x0da7, 0x0e07 }, /*                 Thai_ngongu  THAI CHARACTER NGO NGU */
+		{ 0x0da8, 0x0e08 }, /*                Thai_chochan  THAI CHARACTER CHO CHAN */
+		{ 0x0da9, 0x0e09 }, /*               Thai_choching  THAI CHARACTER CHO CHING */
+		{ 0x0daa, 0x0e0a }, /*               Thai_chochang  THAI CHARACTER CHO CHANG */
+		{ 0x0dab, 0x0e0b }, /*                   Thai_soso  THAI CHARACTER SO SO */
+		{ 0x0dac, 0x0e0c }, /*                Thai_chochoe  THAI CHARACTER CHO CHOE */
+		{ 0x0dad, 0x0e0d }, /*                 Thai_yoying  THAI CHARACTER YO YING */
+		{ 0x0dae, 0x0e0e }, /*                Thai_dochada  THAI CHARACTER DO CHADA */
+		{ 0x0daf, 0x0e0f }, /*                Thai_topatak  THAI CHARACTER TO PATAK */
+		{ 0x0db0, 0x0e10 }, /*                Thai_thothan  THAI CHARACTER THO THAN */
+		{ 0x0db1, 0x0e11 }, /*          Thai_thonangmontho  THAI CHARACTER THO NANGMONTHO */
+		{ 0x0db2, 0x0e12 }, /*             Thai_thophuthao  THAI CHARACTER THO PHUTHAO */
+		{ 0x0db3, 0x0e13 }, /*                  Thai_nonen  THAI CHARACTER NO NEN */
+		{ 0x0db4, 0x0e14 }, /*                  Thai_dodek  THAI CHARACTER DO DEK */
+		{ 0x0db5, 0x0e15 }, /*                  Thai_totao  THAI CHARACTER TO TAO */
+		{ 0x0db6, 0x0e16 }, /*               Thai_thothung  THAI CHARACTER THO THUNG */
+		{ 0x0db7, 0x0e17 }, /*              Thai_thothahan  THAI CHARACTER THO THAHAN */
+		{ 0x0db8, 0x0e18 }, /*               Thai_thothong  THAI CHARACTER THO THONG */
+		{ 0x0db9, 0x0e19 }, /*                   Thai_nonu  THAI CHARACTER NO NU */
+		{ 0x0dba, 0x0e1a }, /*               Thai_bobaimai  THAI CHARACTER BO BAIMAI */
+		{ 0x0dbb, 0x0e1b }, /*                  Thai_popla  THAI CHARACTER PO PLA */
+		{ 0x0dbc, 0x0e1c }, /*               Thai_phophung  THAI CHARACTER PHO PHUNG */
+		{ 0x0dbd, 0x0e1d }, /*                   Thai_fofa  THAI CHARACTER FO FA */
+		{ 0x0dbe, 0x0e1e }, /*                Thai_phophan  THAI CHARACTER PHO PHAN */
+		{ 0x0dbf, 0x0e1f }, /*                  Thai_fofan  THAI CHARACTER FO FAN */
+		{ 0x0dc0, 0x0e20 }, /*             Thai_phosamphao  THAI CHARACTER PHO SAMPHAO */
+		{ 0x0dc1, 0x0e21 }, /*                   Thai_moma  THAI CHARACTER MO MA */
+		{ 0x0dc2, 0x0e22 }, /*                  Thai_yoyak  THAI CHARACTER YO YAK */
+		{ 0x0dc3, 0x0e23 }, /*                  Thai_rorua  THAI CHARACTER RO RUA */
+		{ 0x0dc4, 0x0e24 }, /*                     Thai_ru  THAI CHARACTER RU */
+		{ 0x0dc5, 0x0e25 }, /*                 Thai_loling  THAI CHARACTER LO LING */
+		{ 0x0dc6, 0x0e26 }, /*                     Thai_lu  THAI CHARACTER LU */
+		{ 0x0dc7, 0x0e27 }, /*                 Thai_wowaen  THAI CHARACTER WO WAEN */
+		{ 0x0dc8, 0x0e28 }, /*                 Thai_sosala  THAI CHARACTER SO SALA */
+		{ 0x0dc9, 0x0e29 }, /*                 Thai_sorusi  THAI CHARACTER SO RUSI */
+		{ 0x0dca, 0x0e2a }, /*                  Thai_sosua  THAI CHARACTER SO SUA */
+		{ 0x0dcb, 0x0e2b }, /*                  Thai_hohip  THAI CHARACTER HO HIP */
+		{ 0x0dcc, 0x0e2c }, /*                Thai_lochula  THAI CHARACTER LO CHULA */
+		{ 0x0dcd, 0x0e2d }, /*                   Thai_oang  THAI CHARACTER O ANG */
+		{ 0x0dce, 0x0e2e }, /*               Thai_honokhuk  THAI CHARACTER HO NOKHUK */
+		{ 0x0dcf, 0x0e2f }, /*              Thai_paiyannoi  THAI CHARACTER PAIYANNOI */
+		{ 0x0dd0, 0x0e30 }, /*                  Thai_saraa  THAI CHARACTER SARA A */
+		{ 0x0dd1, 0x0e31 }, /*             Thai_maihanakat  THAI CHARACTER MAI HAN-AKAT */
+		{ 0x0dd2, 0x0e32 }, /*                 Thai_saraaa  THAI CHARACTER SARA AA */
+		{ 0x0dd3, 0x0e33 }, /*                 Thai_saraam  THAI CHARACTER SARA AM */
+		{ 0x0dd4, 0x0e34 }, /*                  Thai_sarai  THAI CHARACTER SARA I */
+		{ 0x0dd5, 0x0e35 }, /*                 Thai_saraii  THAI CHARACTER SARA II */
+		{ 0x0dd6, 0x0e36 }, /*                 Thai_saraue  THAI CHARACTER SARA UE */
+		{ 0x0dd7, 0x0e37 }, /*                Thai_sarauee  THAI CHARACTER SARA UEE */
+		{ 0x0dd8, 0x0e38 }, /*                  Thai_sarau  THAI CHARACTER SARA U */
+		{ 0x0dd9, 0x0e39 }, /*                 Thai_sarauu  THAI CHARACTER SARA UU */
+		{ 0x0dda, 0x0e3a }, /*                Thai_phinthu  THAI CHARACTER PHINTHU */
+		/*  0x0dde                    Thai_maihanakat_maitho  ??? */
+		{ 0x0ddf, 0x0e3f }, /*                   Thai_baht  THAI CURRENCY SYMBOL BAHT */
+		{ 0x0de0, 0x0e40 }, /*                  Thai_sarae  THAI CHARACTER SARA E */
+		{ 0x0de1, 0x0e41 }, /*                 Thai_saraae  THAI CHARACTER SARA AE */
+		{ 0x0de2, 0x0e42 }, /*                  Thai_sarao  THAI CHARACTER SARA O */
+		{ 0x0de3, 0x0e43 }, /*          Thai_saraaimaimuan  THAI CHARACTER SARA AI MAIMUAN */
+		{ 0x0de4, 0x0e44 }, /*         Thai_saraaimaimalai  THAI CHARACTER SARA AI MAIMALAI */
+		{ 0x0de5, 0x0e45 }, /*            Thai_lakkhangyao  THAI CHARACTER LAKKHANGYAO */
+		{ 0x0de6, 0x0e46 }, /*               Thai_maiyamok  THAI CHARACTER MAIYAMOK */
+		{ 0x0de7, 0x0e47 }, /*              Thai_maitaikhu  THAI CHARACTER MAITAIKHU */
+		{ 0x0de8, 0x0e48 }, /*                  Thai_maiek  THAI CHARACTER MAI EK */
+		{ 0x0de9, 0x0e49 }, /*                 Thai_maitho  THAI CHARACTER MAI THO */
+		{ 0x0dea, 0x0e4a }, /*                 Thai_maitri  THAI CHARACTER MAI TRI */
+		{ 0x0deb, 0x0e4b }, /*            Thai_maichattawa  THAI CHARACTER MAI CHATTAWA */
+		{ 0x0dec, 0x0e4c }, /*            Thai_thanthakhat  THAI CHARACTER THANTHAKHAT */
+		{ 0x0ded, 0x0e4d }, /*               Thai_nikhahit  THAI CHARACTER NIKHAHIT */
+		{ 0x0df0, 0x0e50 }, /*                 Thai_leksun  THAI DIGIT ZERO */
+		{ 0x0df1, 0x0e51 }, /*                Thai_leknung  THAI DIGIT ONE */
+		{ 0x0df2, 0x0e52 }, /*                Thai_leksong  THAI DIGIT TWO */
+		{ 0x0df3, 0x0e53 }, /*                 Thai_leksam  THAI DIGIT THREE */
+		{ 0x0df4, 0x0e54 }, /*                  Thai_leksi  THAI DIGIT FOUR */
+		{ 0x0df5, 0x0e55 }, /*                  Thai_lekha  THAI DIGIT FIVE */
+		{ 0x0df6, 0x0e56 }, /*                 Thai_lekhok  THAI DIGIT SIX */
+		{ 0x0df7, 0x0e57 }, /*                Thai_lekchet  THAI DIGIT SEVEN */
+		{ 0x0df8, 0x0e58 }, /*                Thai_lekpaet  THAI DIGIT EIGHT */
+		{ 0x0df9, 0x0e59 }, /*                 Thai_lekkao  THAI DIGIT NINE */
+		{ 0x0ea1, 0x3131 }, /*               Hangul_Kiyeog  HANGUL LETTER KIYEOK */
+		{ 0x0ea2, 0x3132 }, /*          Hangul_SsangKiyeog  HANGUL LETTER SSANGKIYEOK */
+		{ 0x0ea3, 0x3133 }, /*           Hangul_KiyeogSios  HANGUL LETTER KIYEOK-SIOS */
+		{ 0x0ea4, 0x3134 }, /*                Hangul_Nieun  HANGUL LETTER NIEUN */
+		{ 0x0ea5, 0x3135 }, /*           Hangul_NieunJieuj  HANGUL LETTER NIEUN-CIEUC */
+		{ 0x0ea6, 0x3136 }, /*           Hangul_NieunHieuh  HANGUL LETTER NIEUN-HIEUH */
+		{ 0x0ea7, 0x3137 }, /*               Hangul_Dikeud  HANGUL LETTER TIKEUT */
+		{ 0x0ea8, 0x3138 }, /*          Hangul_SsangDikeud  HANGUL LETTER SSANGTIKEUT */
+		{ 0x0ea9, 0x3139 }, /*                Hangul_Rieul  HANGUL LETTER RIEUL */
+		{ 0x0eaa, 0x313a }, /*          Hangul_RieulKiyeog  HANGUL LETTER RIEUL-KIYEOK */
+		{ 0x0eab, 0x313b }, /*           Hangul_RieulMieum  HANGUL LETTER RIEUL-MIEUM */
+		{ 0x0eac, 0x313c }, /*           Hangul_RieulPieub  HANGUL LETTER RIEUL-PIEUP */
+		{ 0x0ead, 0x313d }, /*            Hangul_RieulSios  HANGUL LETTER RIEUL-SIOS */
+		{ 0x0eae, 0x313e }, /*           Hangul_RieulTieut  HANGUL LETTER RIEUL-THIEUTH */
+		{ 0x0eaf, 0x313f }, /*          Hangul_RieulPhieuf  HANGUL LETTER RIEUL-PHIEUPH */
+		{ 0x0eb0, 0x3140 }, /*           Hangul_RieulHieuh  HANGUL LETTER RIEUL-HIEUH */
+		{ 0x0eb1, 0x3141 }, /*                Hangul_Mieum  HANGUL LETTER MIEUM */
+		{ 0x0eb2, 0x3142 }, /*                Hangul_Pieub  HANGUL LETTER PIEUP */
+		{ 0x0eb3, 0x3143 }, /*           Hangul_SsangPieub  HANGUL LETTER SSANGPIEUP */
+		{ 0x0eb4, 0x3144 }, /*            Hangul_PieubSios  HANGUL LETTER PIEUP-SIOS */
+		{ 0x0eb5, 0x3145 }, /*                 Hangul_Sios  HANGUL LETTER SIOS */
+		{ 0x0eb6, 0x3146 }, /*            Hangul_SsangSios  HANGUL LETTER SSANGSIOS */
+		{ 0x0eb7, 0x3147 }, /*                Hangul_Ieung  HANGUL LETTER IEUNG */
+		{ 0x0eb8, 0x3148 }, /*                Hangul_Jieuj  HANGUL LETTER CIEUC */
+		{ 0x0eb9, 0x3149 }, /*           Hangul_SsangJieuj  HANGUL LETTER SSANGCIEUC */
+		{ 0x0eba, 0x314a }, /*                Hangul_Cieuc  HANGUL LETTER CHIEUCH */
+		{ 0x0ebb, 0x314b }, /*               Hangul_Khieuq  HANGUL LETTER KHIEUKH */
+		{ 0x0ebc, 0x314c }, /*                Hangul_Tieut  HANGUL LETTER THIEUTH */
+		{ 0x0ebd, 0x314d }, /*               Hangul_Phieuf  HANGUL LETTER PHIEUPH */
+		{ 0x0ebe, 0x314e }, /*                Hangul_Hieuh  HANGUL LETTER HIEUH */
+		{ 0x0ebf, 0x314f }, /*                    Hangul_A  HANGUL LETTER A */
+		{ 0x0ec0, 0x3150 }, /*                   Hangul_AE  HANGUL LETTER AE */
+		{ 0x0ec1, 0x3151 }, /*                   Hangul_YA  HANGUL LETTER YA */
+		{ 0x0ec2, 0x3152 }, /*                  Hangul_YAE  HANGUL LETTER YAE */
+		{ 0x0ec3, 0x3153 }, /*                   Hangul_EO  HANGUL LETTER EO */
+		{ 0x0ec4, 0x3154 }, /*                    Hangul_E  HANGUL LETTER E */
+		{ 0x0ec5, 0x3155 }, /*                  Hangul_YEO  HANGUL LETTER YEO */
+		{ 0x0ec6, 0x3156 }, /*                   Hangul_YE  HANGUL LETTER YE */
+		{ 0x0ec7, 0x3157 }, /*                    Hangul_O  HANGUL LETTER O */
+		{ 0x0ec8, 0x3158 }, /*                   Hangul_WA  HANGUL LETTER WA */
+		{ 0x0ec9, 0x3159 }, /*                  Hangul_WAE  HANGUL LETTER WAE */
+		{ 0x0eca, 0x315a }, /*                   Hangul_OE  HANGUL LETTER OE */
+		{ 0x0ecb, 0x315b }, /*                   Hangul_YO  HANGUL LETTER YO */
+		{ 0x0ecc, 0x315c }, /*                    Hangul_U  HANGUL LETTER U */
+		{ 0x0ecd, 0x315d }, /*                  Hangul_WEO  HANGUL LETTER WEO */
+		{ 0x0ece, 0x315e }, /*                   Hangul_WE  HANGUL LETTER WE */
+		{ 0x0ecf, 0x315f }, /*                   Hangul_WI  HANGUL LETTER WI */
+		{ 0x0ed0, 0x3160 }, /*                   Hangul_YU  HANGUL LETTER YU */
+		{ 0x0ed1, 0x3161 }, /*                   Hangul_EU  HANGUL LETTER EU */
+		{ 0x0ed2, 0x3162 }, /*                   Hangul_YI  HANGUL LETTER YI */
+		{ 0x0ed3, 0x3163 }, /*                    Hangul_I  HANGUL LETTER I */
+		{ 0x0ed4, 0x11a8 }, /*             Hangul_J_Kiyeog  HANGUL JONGSEONG KIYEOK */
+		{ 0x0ed5, 0x11a9 }, /*        Hangul_J_SsangKiyeog  HANGUL JONGSEONG SSANGKIYEOK */
+		{ 0x0ed6, 0x11aa }, /*         Hangul_J_KiyeogSios  HANGUL JONGSEONG KIYEOK-SIOS */
+		{ 0x0ed7, 0x11ab }, /*              Hangul_J_Nieun  HANGUL JONGSEONG NIEUN */
+		{ 0x0ed8, 0x11ac }, /*         Hangul_J_NieunJieuj  HANGUL JONGSEONG NIEUN-CIEUC */
+		{ 0x0ed9, 0x11ad }, /*         Hangul_J_NieunHieuh  HANGUL JONGSEONG NIEUN-HIEUH */
+		{ 0x0eda, 0x11ae }, /*             Hangul_J_Dikeud  HANGUL JONGSEONG TIKEUT */
+		{ 0x0edb, 0x11af }, /*              Hangul_J_Rieul  HANGUL JONGSEONG RIEUL */
+		{ 0x0edc, 0x11b0 }, /*        Hangul_J_RieulKiyeog  HANGUL JONGSEONG RIEUL-KIYEOK */
+		{ 0x0edd, 0x11b1 }, /*         Hangul_J_RieulMieum  HANGUL JONGSEONG RIEUL-MIEUM */
+		{ 0x0ede, 0x11b2 }, /*         Hangul_J_RieulPieub  HANGUL JONGSEONG RIEUL-PIEUP */
+		{ 0x0edf, 0x11b3 }, /*          Hangul_J_RieulSios  HANGUL JONGSEONG RIEUL-SIOS */
+		{ 0x0ee0, 0x11b4 }, /*         Hangul_J_RieulTieut  HANGUL JONGSEONG RIEUL-THIEUTH */
+		{ 0x0ee1, 0x11b5 }, /*        Hangul_J_RieulPhieuf  HANGUL JONGSEONG RIEUL-PHIEUPH */
+		{ 0x0ee2, 0x11b6 }, /*         Hangul_J_RieulHieuh  HANGUL JONGSEONG RIEUL-HIEUH */
+		{ 0x0ee3, 0x11b7 }, /*              Hangul_J_Mieum  HANGUL JONGSEONG MIEUM */
+		{ 0x0ee4, 0x11b8 }, /*              Hangul_J_Pieub  HANGUL JONGSEONG PIEUP */
+		{ 0x0ee5, 0x11b9 }, /*          Hangul_J_PieubSios  HANGUL JONGSEONG PIEUP-SIOS */
+		{ 0x0ee6, 0x11ba }, /*               Hangul_J_Sios  HANGUL JONGSEONG SIOS */
+		{ 0x0ee7, 0x11bb }, /*          Hangul_J_SsangSios  HANGUL JONGSEONG SSANGSIOS */
+		{ 0x0ee8, 0x11bc }, /*              Hangul_J_Ieung  HANGUL JONGSEONG IEUNG */
+		{ 0x0ee9, 0x11bd }, /*              Hangul_J_Jieuj  HANGUL JONGSEONG CIEUC */
+		{ 0x0eea, 0x11be }, /*              Hangul_J_Cieuc  HANGUL JONGSEONG CHIEUCH */
+		{ 0x0eeb, 0x11bf }, /*             Hangul_J_Khieuq  HANGUL JONGSEONG KHIEUKH */
+		{ 0x0eec, 0x11c0 }, /*              Hangul_J_Tieut  HANGUL JONGSEONG THIEUTH */
+		{ 0x0eed, 0x11c1 }, /*             Hangul_J_Phieuf  HANGUL JONGSEONG PHIEUPH */
+		{ 0x0eee, 0x11c2 }, /*              Hangul_J_Hieuh  HANGUL JONGSEONG HIEUH */
+		{ 0x0eef, 0x316d }, /*     Hangul_RieulYeorinHieuh  HANGUL LETTER RIEUL-YEORINHIEUH */
+		{ 0x0ef0, 0x3171 }, /*    Hangul_SunkyeongeumMieum  HANGUL LETTER KAPYEOUNMIEUM */
+		{ 0x0ef1, 0x3178 }, /*    Hangul_SunkyeongeumPieub  HANGUL LETTER KAPYEOUNPIEUP */
+		{ 0x0ef2, 0x317f }, /*              Hangul_PanSios  HANGUL LETTER PANSIOS */
+		{ 0x0ef3, 0x3181 }, /*    Hangul_KkogjiDalrinIeung  HANGUL LETTER YESIEUNG */
+		{ 0x0ef4, 0x3184 }, /*   Hangul_SunkyeongeumPhieuf  HANGUL LETTER KAPYEOUNPHIEUPH */
+		{ 0x0ef5, 0x3186 }, /*          Hangul_YeorinHieuh  HANGUL LETTER YEORINHIEUH */
+		{ 0x0ef6, 0x318d }, /*                Hangul_AraeA  HANGUL LETTER ARAEA */
+		{ 0x0ef7, 0x318e }, /*               Hangul_AraeAE  HANGUL LETTER ARAEAE */
+		{ 0x0ef8, 0x11eb }, /*            Hangul_J_PanSios  HANGUL JONGSEONG PANSIOS */
+		{ 0x0ef9, 0x11f0 }, /*  Hangul_J_KkogjiDalrinIeung  HANGUL JONGSEONG YESIEUNG */
+		{ 0x0efa, 0x11f9 }, /*        Hangul_J_YeorinHieuh  HANGUL JONGSEONG YEORINHIEUH */
+		{ 0x0eff, 0x20a9 }, /*                  Korean_Won  WON SIGN */
+		{ 0x13a4, 0x20ac }, /*                        Euro  EURO SIGN */
+		{ 0x13bc, 0x0152 }, /*                          OE  LATIN CAPITAL LIGATURE OE */
+		{ 0x13bd, 0x0153 }, /*                          oe  LATIN SMALL LIGATURE OE */
+		{ 0x13be, 0x0178 }, /*                  Ydiaeresis  LATIN CAPITAL LETTER Y WITH DIAERESIS */
+		{ 0x20ac, 0x20ac }, /*                    EuroSign  EURO SIGN */
+	});
+
+	private static Map<Integer, Integer> toMap(int[][] keys) {
+		Map<Integer, Integer> keyMap = new HashMap<Integer, Integer>();
+		for (int[] km: keys) {
+			keyMap.put(km[1], km[0]);
+		}
+		return keyMap;
+	}
+
+	public static int unicode2keysym(int ch) {
+		if (ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255)
+			return ch;
+		Integer converted = keyMap.get(ch);
+		return converted != null ?
+				converted :
+				// No variants has been found for the unicode symbol then pass as unicode
+				// with the special flag.
+				// Note this method is valid only for 0x100-0x10ffff unicode value range.
+				ch | 0x01000000;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/com/glavsoft/utils/Strings.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,46 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.utils;
+
+public class Strings {
+	public static String toString(byte[] byteArray) {
+		StringBuilder sb = new StringBuilder("[");
+		boolean notFirst = false;
+		for (byte b : byteArray) {
+			if (notFirst) {
+				sb.append(", ");
+			} else {
+				notFirst = true;
+			}
+			sb.append(b);
+		}
+		return sb.append("]").toString();
+	}
+
+	public static boolean isTrimmedEmpty(String s) {
+		return null == s || (s.trim().length() == 0);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/ConnectionManager.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,132 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.viewer.swing.ParametersHandler;
+import com.glavsoft.viewer.swing.Utils;
+import com.glavsoft.viewer.swing.gui.ConnectionDialog;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.WindowListener;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+
+public class ConnectionManager implements Serializable {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private final WindowListener appWindowListener;
+	volatile boolean forceConnectionDialog;
+	private JFrame containerFrame;
+	private final boolean isApplet;
+
+	public ConnectionManager(WindowListener appWindowListener, boolean isApplet) {
+		this.appWindowListener = appWindowListener;
+		this.isApplet = isApplet;
+	}
+
+	public void showReconnectDialog(String title, String message) {
+		JOptionPane reconnectPane = new JOptionPane(message + "\nTry another connection?",
+				JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION);
+		final JDialog reconnectDialog = reconnectPane.createDialog(containerFrame, title);
+		reconnectDialog.setModalityType(isApplet ?
+				Dialog.ModalityType.APPLICATION_MODAL : Dialog.ModalityType.TOOLKIT_MODAL);
+		try {
+			reconnectDialog.setAlwaysOnTop(true);
+		} catch (SecurityException e) { /*nop*/ }
+		java.util.List<Image> icons = Utils.getIcons();
+		if (icons.size() != 0) {
+			reconnectDialog.setIconImages(icons);
+		}
+		reconnectDialog.setVisible(true);
+		if (reconnectPane.getValue() == null ||
+				(Integer)reconnectPane.getValue() == JOptionPane.NO_OPTION) {
+			appWindowListener.windowClosing(null);
+		} else {
+			forceConnectionDialog = !isApplet;
+		}
+	}
+
+	public Socket connectToHost(final ParametersHandler.ConnectionParams connectionParams, ProtocolSettings settings) {
+		Socket socket = null;
+		ConnectionDialog connectionDialog = null;
+		boolean wasError = false;
+		do {
+			if (forceConnectionDialog || wasError ||
+					connectionParams.isHostNameEmpty() ||
+					-1 == connectionParams.portNumber) {
+				forceConnectionDialog = false;
+				if (null == connectionDialog) {
+					connectionDialog = new ConnectionDialog(containerFrame,
+							appWindowListener, connectionParams.hostName, connectionParams.portNumber,
+							settings, isApplet);
+				}
+				connectionDialog.setVisible(true);
+				connectionParams.hostName = connectionDialog.getServerNameString();
+				connectionParams.portNumber = connectionDialog.getPort();
+			}
+			Viewer.logger.info("Connecting to host " + connectionParams.hostName + ":" + connectionParams.portNumber);
+			try {
+				socket = new Socket(connectionParams.hostName, connectionParams.portNumber);
+				wasError = false;
+			} catch (UnknownHostException e) {
+				Viewer.logger.severe("Unknown host: " + connectionParams.hostName);
+				showConnectionErrorDialog("Unknown host: '" + connectionParams.hostName + "'");
+				wasError = true;
+			} catch (IOException e) {
+				Viewer.logger.severe("Couldn't connect to: " +
+						connectionParams.hostName + ":" + connectionParams.portNumber +
+						": " + e.getMessage());
+				showConnectionErrorDialog("Couldn't connect to: '" + connectionParams.hostName +
+						"'\n" + e.getMessage());
+				wasError = true;
+			}
+		} while (!isApplet && (connectionParams.isHostNameEmpty() || wasError));
+		if (connectionDialog != null) {
+			connectionDialog.dispose();
+		}
+		return socket;
+	}
+
+	public void showConnectionErrorDialog(final String message) {
+		JOptionPane errorPane = new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
+		final JDialog errorDialog = errorPane.createDialog(containerFrame, "Connection error");
+		errorDialog.setModalityType(isApplet ? Dialog.ModalityType.APPLICATION_MODAL : Dialog.ModalityType.TOOLKIT_MODAL);
+		try {
+			errorDialog.setAlwaysOnTop(true);
+		} catch (SecurityException e) { /*nop*/ }
+		errorDialog.setVisible(true);
+	}
+
+	public void setContainerFrame(JFrame containerFrame) {
+		this.containerFrame = containerFrame;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/ContainerManager.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,279 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.viewer.swing.Surface;
+import com.glavsoft.viewer.swing.UiSettings;
+import com.glavsoft.viewer.swing.Utils;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.Serializable;
+
+public class ContainerManager implements Serializable {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private final Viewer viewer;
+	private JToggleButton zoomFitButton;
+	private JButton zoomInButton;
+	private JButton zoomOutButton;
+	private JButton zoomAsIsButton;
+	private JPanel outerPanel;
+	private JScrollPane scroller;
+	private Container container;
+	private JPanel buttonBar;
+
+	public ContainerManager(Viewer viewer) { this.viewer = viewer; }
+
+
+	public Container createContainer(final Surface surface, boolean isSeparateFrame, boolean isApplet) {
+		outerPanel = System.getProperty("os.name").toLowerCase().startsWith("windows") ?
+				new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)) {
+					/**
+					 * 
+					 */
+					private static final long serialVersionUID = 1L;
+
+					@Override
+					public Dimension getSize() {
+						return surface.getPreferredSize();
+					}
+				} :
+				new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+
+		outerPanel.add(surface);
+
+		JFrame frame;
+		scroller = new JScrollPane(outerPanel);
+		if (isSeparateFrame) {
+			frame = new JFrame();
+			if ( ! isApplet) {
+				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+			}
+			java.util.List<Image> icons = Utils.getIcons();
+			if (icons.size() != 0) {
+				frame.setIconImages(icons);
+			}
+			container = frame;
+		} else {
+			container = viewer;
+		}
+		container.setLayout(new BorderLayout(0, 0));
+		container.add(scroller, BorderLayout.CENTER);
+
+		if (isSeparateFrame) {
+//			frame.pack();
+			outerPanel.setSize(surface.getPreferredSize());
+			internalPack(null);
+			container.setVisible(true);
+		}
+		container.validate();
+		return container;
+	}
+
+	public void pack() {
+		final Dimension outerPanelOldSize = outerPanel.getSize();
+		outerPanel.setSize(viewer.getSurface().getPreferredSize());
+		if (container != viewer && ! viewer.isZoomToFitSelected()) {
+			internalPack(outerPanelOldSize);
+		}
+		scroller.validate();
+		updateZoomButtonsState();
+		viewer.updateFrameTitle();
+	}
+
+	private void internalPack(Dimension outerPanelOldSize) {
+		final Rectangle workareaRectangle = getWorkareaRectangle();
+		final boolean isHScrollBar = scroller.getHorizontalScrollBar().isShowing();
+		final boolean isVScrollBar = scroller.getVerticalScrollBar().isShowing();
+
+		container.validate();
+
+		final Insets containerInsets = container.getInsets();
+		Dimension preferredSize = container.getPreferredSize();
+		Rectangle preferredRectangle = new Rectangle(container.getLocation(), preferredSize);
+
+//		if (workareaRectangle.contains(preferredRectangle)) {
+		if (null == outerPanelOldSize && workareaRectangle.contains(preferredRectangle)) {
+			((JFrame)container).pack();
+		} else {
+			Dimension minDimension = new Dimension(
+					containerInsets.left + containerInsets.right, containerInsets.top + containerInsets.bottom);
+			if (buttonBar != null) {
+				minDimension.width += buttonBar.getMinimumSize().width;
+				minDimension.height += buttonBar.getMinimumSize().height;
+			}
+			Dimension dim = new Dimension(preferredSize);
+			Point location = container.getLocation();
+			if (isHScrollBar) {
+				dim.width = container.getWidth();
+			} else {
+				if (isVScrollBar) dim.width += scroller.getVerticalScrollBar().getWidth();
+				if (dim.width < minDimension.width) dim.width = minDimension.width;
+
+				int dx = location.x - workareaRectangle.x;
+				int w = workareaRectangle.width - dx;
+				if (w < dim.width) {
+					int dw = dim.width - w;
+					if (dw < dx) {
+						location.x -= dw;
+					} else {
+						dim.width = workareaRectangle.width;
+						location.x = workareaRectangle.x;
+					}
+				}
+			}
+			if (isVScrollBar) {
+				dim.height = container.getHeight();
+			} else {
+
+				if (isHScrollBar) dim.height += scroller.getHorizontalScrollBar().getHeight();
+				if (dim.height < minDimension.height) dim.height = minDimension.height;
+
+				int dy = location.y - workareaRectangle.y;
+				int h = workareaRectangle.height - dy;
+				if (h < dim.height) {
+					int dh = dim.height - h;
+					if (dh < dy) {
+//						h = dim.height;
+						location.y -= dh;
+					} else {
+//						h =
+						dim.height = workareaRectangle.height;
+						location.y = workareaRectangle.y;
+					}
+				}
+			}
+			if ( ! location.equals(container.getLocation())) {
+				container.setLocation(location);
+			}
+			container.setSize(dim);
+		}
+	}
+
+	private Rectangle getWorkareaRectangle() {
+		final GraphicsConfiguration graphicsConfiguration = container.getGraphicsConfiguration();
+		final Rectangle screenBounds = graphicsConfiguration.getBounds();
+		final Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration);
+
+		screenBounds.x += screenInsets.left;
+		screenBounds.y += screenInsets.top;
+		screenBounds.width -= screenInsets.left + screenInsets.right;
+		screenBounds.height -= screenInsets.top + screenInsets.bottom;
+		return screenBounds;
+	}
+
+	void addZoomButtons(JPanel buttonBar, Insets margin) {
+		this.buttonBar = buttonBar;
+		buttonBar.add(Box.createHorizontalStrut(10));
+
+		zoomFitButton = new JToggleButton(Utils.getButtonIcon("zoom-fit"));
+
+		zoomOutButton = new JButton(Utils.getButtonIcon("zoom-out"));
+		zoomOutButton.setToolTipText("Zoom Out");
+		zoomOutButton.setMargin(margin);
+		buttonBar.add(zoomOutButton);
+		zoomOutButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				zoomFitButton.setSelected(false);
+				viewer.getUiSettings().zoomOut();
+			}
+		});
+
+		zoomInButton = new JButton(Utils.getButtonIcon("zoom-in"));
+		zoomInButton.setToolTipText("Zoom In");
+		zoomInButton.setMargin(margin);
+		buttonBar.add(zoomInButton);
+		zoomInButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				zoomFitButton.setSelected(false);
+				viewer.getUiSettings().zoomIn();
+			}
+		});
+
+		zoomAsIsButton = new JButton(Utils.getButtonIcon("zoom-100"));
+		zoomAsIsButton.setToolTipText("Zoom 100%");
+		zoomAsIsButton.setMargin(margin);
+		buttonBar.add(zoomAsIsButton);
+		zoomAsIsButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				zoomFitButton.setSelected(false);
+				viewer.getUiSettings().zoomAsIs();
+			}
+		});
+
+		zoomFitButton.setToolTipText("Zoom to Fit Window");
+		zoomFitButton.setMargin(margin);
+		buttonBar.add(zoomFitButton);
+
+		zoomFitButton.addItemListener(new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent e) {
+				if (e.getStateChange() == ItemEvent.SELECTED) {
+					viewer.setZoomToFitSelected(true);
+					zoomToFit();
+					updateZoomButtonsState();
+				} else {
+					viewer.setZoomToFitSelected(false);
+				}
+				viewer.setSurfaceToHandleKbdFocus();
+			}
+		});
+	}
+
+	private void zoomToFit() {
+		Dimension scrollerSize = scroller.getSize();
+		Insets scrollerInsets = scroller.getInsets();
+		viewer.getUiSettings().zoomToFit(scrollerSize.width - scrollerInsets.left - scrollerInsets.right,
+				scrollerSize.height - scrollerInsets.top - scrollerInsets.bottom,
+				viewer.getWorkingProtocol().getFbWidth(), viewer.getWorkingProtocol().getFbHeight());
+	}
+
+	void registerResizeListener(Container container) {
+		container.addComponentListener(new ComponentAdapter() {
+			@Override
+			public void componentResized(ComponentEvent e) {
+				if (viewer.isZoomToFitSelected()) {
+					zoomToFit();
+					updateZoomButtonsState();
+					viewer.updateFrameTitle();
+					viewer.setSurfaceToHandleKbdFocus();
+				}
+			}
+		});
+	}
+
+	void updateZoomButtonsState() {
+		zoomOutButton.setEnabled(viewer.getUiSettings().getScalePercent() > UiSettings.MIN_SCALE_PERCENT);
+		zoomInButton.setEnabled(viewer.getUiSettings().getScalePercent() < UiSettings.MAX_SCALE_PERCENT);
+		zoomAsIsButton.setEnabled(viewer.getUiSettings().getScalePercent() != 100);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/Viewer.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,603 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.exceptions.*;
+import com.glavsoft.rfb.IChangeSettingsListener;
+import com.glavsoft.rfb.IPasswordRetriever;
+import com.glavsoft.rfb.IRfbSessionListener;
+import com.glavsoft.rfb.client.KeyEventMessage;
+import com.glavsoft.rfb.protocol.Protocol;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.transport.Writer;
+import com.glavsoft.utils.Keymap;
+import com.glavsoft.utils.Strings;
+import com.glavsoft.viewer.cli.Parser;
+import com.glavsoft.viewer.swing.*;
+import com.glavsoft.viewer.swing.gui.OptionsDialog;
+import com.glavsoft.viewer.swing.gui.PasswordDialog;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.Dialog.ModalityType;
+import java.awt.event.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.logging.Logger;
+
+@SuppressWarnings("serial")
+public class Viewer extends JApplet implements Runnable, IRfbSessionListener, WindowListener,
+		IChangeSettingsListener {
+	public static final int DEFAULT_PORT = 5900;
+
+	public static Logger logger = Logger.getLogger("com.glavsoft");
+	private static final Insets BUTTONS_MARGIN = new Insets(2, 2, 2, 2);
+	private boolean isZoomToFitSelected;
+	private boolean forceReconnection;
+	private String reconnectionReason;
+	private ContainerManager containerManager;
+
+	public Protocol getWorkingProtocol() {
+		return workingProtocol;
+	}
+
+	public boolean isZoomToFitSelected() {
+		return isZoomToFitSelected;
+	}
+
+	public Surface getSurface() {
+		return surface;
+	}
+
+	public UiSettings getUiSettings() {
+		return uiSettings;
+	}
+
+	public void setZoomToFitSelected(boolean zoomToFitSelected) {
+		isZoomToFitSelected = zoomToFitSelected;
+	}
+
+	/**
+	 * Ask user for password if needed
+	 */
+	public class PasswordChooser implements IPasswordRetriever {
+		private final String passwordPredefined;
+		private final ParametersHandler.ConnectionParams connectionParams;
+		PasswordDialog passwordDialog;
+		private final JFrame owner;
+		private final WindowListener onClose;
+
+		public PasswordChooser(String passwordPredefined, ParametersHandler.ConnectionParams connectionParams,
+				JFrame owner, WindowListener onClose) {
+			this.passwordPredefined = passwordPredefined;
+			this.connectionParams = connectionParams;
+			this.owner = owner;
+			this.onClose = onClose;
+		}
+
+		@Override
+		public String getPassword() {
+			return Strings.isTrimmedEmpty(passwordPredefined) ?
+					getPasswordFromGUI() :
+					passwordPredefined;
+		}
+
+		private String getPasswordFromGUI() {
+			if (null == passwordDialog) {
+				passwordDialog = new PasswordDialog(owner, onClose, isApplet);
+			}
+			passwordDialog.setServerHostName(connectionParams.hostName);
+			passwordDialog.setVisible(true);
+			return passwordDialog.getPassword();
+		}
+	}
+
+	public static void main(String[] args) {
+		Parser parser = new Parser();
+		ParametersHandler.completeParserOptions(parser);
+
+		parser.parse(args);
+		if (parser.isSet(ParametersHandler.ARG_HELP)) {
+			printUsage(parser.optionsUsage());
+			System.exit(0);
+		}
+		Viewer viewer = new Viewer(parser);
+		SwingUtilities.invokeLater(viewer);
+	}
+
+	public static void printUsage(String additional) {
+		System.out.println("Usage: java -jar (progfilename) [hostname [port_number]] [Options]\n" +
+				"    or\n"+
+				" java -jar (progfilename) [Options]\n" +
+				"    or\n java -jar (progfilename) -help\n    to view this help\n\n" +
+				"Where Options are:\n" + additional +
+				"\nOptions format: -optionName=optionValue. Ex. -host=localhost -port=5900 -viewonly=yes\n" +
+				"Both option name and option value are case insensitive.");
+	}
+
+
+	private final ParametersHandler.ConnectionParams connectionParams;
+	protected String passwordFromParams;
+	protected Socket workingSocket;
+	protected Protocol workingProtocol;
+	protected JFrame containerFrame;
+	boolean isSeparateFrame = true;
+	protected boolean isApplet = true;
+	protected boolean showControls = true;
+	protected Surface surface;
+	protected final ProtocolSettings settings;
+	protected final UiSettings uiSettings;
+    protected boolean tryAgain;
+	private boolean isAppletStopped = false;
+	private volatile boolean isStoppingProcess;
+	private List<JComponent> kbdButtons;
+
+	public Viewer() {
+		connectionParams = new ParametersHandler.ConnectionParams();
+		settings = ProtocolSettings.getDefaultSettings();
+		uiSettings = new UiSettings();
+	}
+
+	private Viewer(Parser parser) {
+		this();
+		ParametersHandler.completeSettingsFromCLI(parser, connectionParams, settings, uiSettings);
+		showControls = ParametersHandler.showControls;
+		passwordFromParams = parser.getValueFor(ParametersHandler.ARG_PASSWORD);
+		logger.info("TightVNC Viewer version " + ver());
+		isApplet = false;
+	}
+
+
+	@Override
+	public void rfbSessionStopped(final String reason) {
+		if (isStoppingProcess)
+			return;
+		cleanUpUISessionAndConnection();
+		SwingUtilities.invokeLater(new Runnable() {
+			@Override
+			public void run() {
+				forceReconnection = true;
+				reconnectionReason = reason;
+			}
+		});
+		// start new session
+		SwingUtilities.invokeLater(this);
+	}
+
+	private synchronized void cleanUpUISessionAndConnection() {
+		isStoppingProcess = true;
+		if (workingSocket != null && workingSocket.isConnected()) {
+			try {
+				workingSocket.close();
+			} catch (IOException e) { /*nop*/ }
+		}
+		if (containerFrame != null) {
+			containerFrame.dispose();
+			containerFrame = null;
+		}
+		isStoppingProcess = false;
+	}
+
+	@Override
+	public void windowClosing(WindowEvent e) {
+		if (e != null && e.getComponent() != null) {
+			e.getWindow().setVisible(false);
+		}
+		closeApp();
+	}
+
+	/**
+	 * Closes App(lication) or stops App(let).
+	 */
+	protected void closeApp() {
+		if (workingProtocol != null) {
+			workingProtocol.cleanUpSession();
+		}
+		cleanUpUISessionAndConnection();
+		tryAgain = false;
+		if (isApplet) {
+			logger.severe("Applet is stopped.");
+			isAppletStopped  = true;
+			repaint();
+		} else {
+			System.exit(0);
+		}
+	}
+
+	@Override
+	public void paint(Graphics g) {
+		if ( ! isAppletStopped) {
+			super.paint(g);
+		} else {
+			getContentPane().removeAll();
+			g.clearRect(0, 0, getWidth(), getHeight());
+			g.drawString("Disconnected", 10, 20);
+		}
+	}
+
+	@Override
+	public void destroy() {
+		closeApp();
+		super.destroy();
+	}
+
+	@Override
+	public void init() {
+		ParametersHandler.completeSettingsFromApplet(this, connectionParams, settings, uiSettings);
+		showControls = ParametersHandler.showControls;
+		isSeparateFrame = ParametersHandler.isSeparateFrame;
+		passwordFromParams = getParameter(ParametersHandler.ARG_PASSWORD);
+		isApplet = true;
+
+		repaint();
+		SwingUtilities.invokeLater(this);
+	}
+
+	@Override
+	public void start() {
+		setSurfaceToHandleKbdFocus();
+		super.start();
+	}
+
+	@Override
+	public void run() {
+		ConnectionManager connectionManager = new ConnectionManager(this, isApplet);
+
+		if (forceReconnection) {
+			connectionManager.showReconnectDialog("Connection lost", reconnectionReason);
+			forceReconnection = false;
+		}
+		tryAgain = true;
+		while (tryAgain) {
+			workingSocket = connectionManager.connectToHost(connectionParams, settings);
+			if (null == workingSocket) {
+				closeApp();
+				break;
+			}
+			logger.info("Connected");
+
+			try {
+				workingSocket.setTcpNoDelay(true); // disable Nagle algorithm
+				Reader reader = new Reader(workingSocket.getInputStream());
+				Writer writer = new Writer(workingSocket.getOutputStream());
+
+				workingProtocol = new Protocol(reader, writer,
+						new PasswordChooser(passwordFromParams, connectionParams, containerFrame, this),
+						settings);
+				workingProtocol.handshake();
+
+                ClipboardControllerImpl clipboardController =
+		                new ClipboardControllerImpl(workingProtocol, settings.getRemoteCharsetName());
+				clipboardController.setEnabled(settings.isAllowClipboardTransfer());
+				settings.addListener(clipboardController);
+
+				surface = new Surface(workingProtocol, this, uiSettings.getScaleFactor());
+				settings.addListener(this);
+				uiSettings.addListener(surface);
+				containerFrame = createContainer();
+				connectionManager.setContainerFrame(containerFrame);
+				updateFrameTitle();
+
+				workingProtocol.startNormalHandling(this, surface, clipboardController);
+				tryAgain = false;
+			} catch (UnsupportedProtocolVersionException e) {
+				connectionManager.showReconnectDialog("Unsupported Protocol Version", e.getMessage());
+				logger.severe(e.getMessage());
+			} catch (UnsupportedSecurityTypeException e) {
+				connectionManager.showReconnectDialog("Unsupported Security Type", e.getMessage());
+				logger.severe(e.getMessage());
+			} catch (AuthenticationFailedException e) {
+				passwordFromParams = null;
+				connectionManager.showReconnectDialog("Authentication Failed", e.getMessage());
+				logger.severe(e.getMessage());
+			} catch (TransportException e) {
+				connectionManager.showReconnectDialog("Connection Error", "Connection Error" + ": " + e.getMessage());
+				logger.severe(e.getMessage());
+			} catch (IOException e) {
+				connectionManager.showReconnectDialog("Connection Error", "Connection Error" + ": " + e.getMessage());
+				logger.severe(e.getMessage());
+			} catch (FatalException e) {
+				connectionManager.showReconnectDialog("Connection Error", "Connection Error" + ": " + e.getMessage());
+				logger.severe(e.getMessage());
+			}
+		}
+	}
+
+	protected JFrame createContainer() {
+		containerManager = new ContainerManager(this);
+		Container container = containerManager.createContainer(surface, isSeparateFrame, isApplet);
+
+		if (showControls) {
+			createButtonsPanel(container, workingProtocol, containerManager);
+			containerManager.registerResizeListener(container);
+			containerManager.updateZoomButtonsState();
+		}
+		setSurfaceToHandleKbdFocus();
+		return isSeparateFrame ? (JFrame)container : null;
+	}
+
+	public void packContainer() {
+		containerManager.pack();
+	}
+
+	protected void createButtonsPanel(final Container container, final ProtocolContext context, ContainerManager containerManager) {
+		JPanel buttonBar = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 1));
+
+		JButton optionsButton = new JButton(Utils.getButtonIcon("options"));
+		optionsButton.setToolTipText("Set Options");
+		optionsButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(optionsButton);
+		optionsButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				showOptionsDialog();
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+
+		JButton infoButton = new JButton(Utils.getButtonIcon("info"));
+		infoButton.setToolTipText("Show connection info");
+		infoButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(infoButton);
+		infoButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				showConnectionInfoMessage(context.getRemoteDesktopName());
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+
+		buttonBar.add(Box.createHorizontalStrut(10));
+		JButton refreshButton = new JButton(Utils.getButtonIcon("refresh"));
+		refreshButton.setToolTipText("Refresh screen");
+		refreshButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(refreshButton);
+		refreshButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				context.sendRefreshMessage();
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+
+		containerManager.addZoomButtons(buttonBar, BUTTONS_MARGIN);
+
+		kbdButtons = new LinkedList<JComponent>();
+		buttonBar.add(Box.createHorizontalStrut(10));
+		JButton ctrlAltDelButton = new JButton(Utils.getButtonIcon("ctrl-alt-del"));
+		ctrlAltDelButton.setToolTipText("Send 'Ctrl-Alt-Del'");
+		ctrlAltDelButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(ctrlAltDelButton);
+		kbdButtons.add(ctrlAltDelButton);
+		ctrlAltDelButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				sendCtrlAltDel(context);
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+
+		JButton winButton = new JButton(Utils.getButtonIcon("win"));
+		winButton.setToolTipText("Send 'Win' key as 'Ctrl-Esc'");
+		winButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(winButton);
+		kbdButtons.add(winButton);
+		winButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				sendWinKey(context);
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+
+		JToggleButton ctrlButton = new JToggleButton(Utils.getButtonIcon("ctrl"));
+		ctrlButton.setToolTipText("Ctrl Lock");
+		ctrlButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(ctrlButton);
+		kbdButtons.add(ctrlButton);
+		ctrlButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+		ctrlButton.addItemListener(new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent e) {
+				if (e.getStateChange() == ItemEvent.SELECTED) {
+					context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true));
+				} else {
+					context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false));
+				}
+			}
+		});
+
+		JToggleButton altButton = new JToggleButton(Utils.getButtonIcon("alt"));
+		kbdButtons.add(altButton);
+		altButton.setToolTipText("Alt Lock");
+		altButton.setMargin(BUTTONS_MARGIN);
+		buttonBar.add(altButton);
+		kbdButtons.add(altButton);
+		altButton.addItemListener(new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent e) {
+				if (e.getStateChange() == ItemEvent.SELECTED) {
+					context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, true));
+				} else {
+					context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, false));
+				}
+			}
+		});
+		altButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setSurfaceToHandleKbdFocus();
+			}
+		});
+		ModifierButtonEventListener modifierButtonListener = new ModifierButtonEventListener();
+		modifierButtonListener.addButton(KeyEvent.VK_CONTROL, ctrlButton);
+		modifierButtonListener.addButton(KeyEvent.VK_ALT, altButton);
+		surface.addModifierListener(modifierButtonListener);
+
+//		JButton fileTransferButton = new JButton(Utils.getButtonIcon("file-transfer"));
+//		fileTransferButton.setMargin(buttonsMargin);
+//		buttonBar.add(fileTransferButton);
+
+		buttonBar.add(Box.createHorizontalStrut(10));
+
+		JButton closeButton = new JButton(Utils.getButtonIcon("close"));
+		closeButton.setToolTipText(isApplet ? "Disconnect" : "Close");
+		closeButton.setMargin(BUTTONS_MARGIN);
+		closeButton.setAlignmentX(RIGHT_ALIGNMENT);
+		buttonBar.add(closeButton);
+		closeButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				closeApp();
+			}
+		});
+
+		container.add(buttonBar, BorderLayout.NORTH);
+	}
+
+	protected void updateFrameTitle() {
+		if (containerFrame != null) {
+			containerFrame.setTitle(
+					workingProtocol.getRemoteDesktopName() + " [zoom: " + uiSettings.getScalePercentFormatted() + "%]");
+		}
+	}
+
+	protected void setSurfaceToHandleKbdFocus() {
+		if (surface != null && ! surface.requestFocusInWindow()) {
+			surface.requestFocus();
+		}
+	}
+
+	@Override
+	public void settingsChanged(SettingsChangedEvent e) {
+		ProtocolSettings settings = (ProtocolSettings) e.getSource();
+		setEnabledKbdButtons( ! settings.isViewOnly());
+	}
+
+	private void setEnabledKbdButtons(boolean enabled) {
+		if (kbdButtons != null) {
+			for (JComponent b : kbdButtons) {
+				b.setEnabled(enabled);
+			}
+		}
+	}
+
+	private void showOptionsDialog() {
+		OptionsDialog optionsDialog = new OptionsDialog(containerFrame);
+		optionsDialog.initControlsFromSettings(settings, false);
+		optionsDialog.setVisible(true);
+	}
+
+	private void showConnectionInfoMessage(final String title) {
+		StringBuilder message = new StringBuilder();
+		message.append("Connected to: ").append(title).append("\n");
+		message.append("Host: ").append(connectionParams.hostName)
+			.append(" Port: ").append(connectionParams.portNumber).append("\n\n");
+
+		message.append("Desktop geometry: ")
+			.append(String.valueOf(surface.getWidth()))
+			.append(" \u00D7 ") // multiplication sign
+			.append(String.valueOf(surface.getHeight())).append("\n");
+		message.append("Color format: ")
+			.append(String.valueOf(Math.round(Math.pow(2, workingProtocol.getPixelFormat().depth))))
+			.append(" colors (")
+			.append(String.valueOf(workingProtocol.getPixelFormat().depth))
+			.append(" bits)\n");
+		message.append("Current protocol version: ")
+			.append(settings.getProtocolVersion());
+		if (settings.isTight()) {
+			message.append("tight");
+		}
+		message.append("\n");
+
+		JOptionPane infoPane = new JOptionPane(message.toString(), JOptionPane.INFORMATION_MESSAGE);
+		final JDialog infoDialog = infoPane.createDialog(containerFrame, "VNC connection info");
+		infoDialog.setModalityType(ModalityType.MODELESS);
+		try {
+			infoDialog.setAlwaysOnTop(true);
+		} catch (SecurityException e) { /*nop*/ }
+		infoDialog.setVisible(true);
+	}
+
+	private void sendCtrlAltDel(ProtocolContext context) {
+		context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true));
+		context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, true));
+		context.sendMessage(new KeyEventMessage(Keymap.K_DELETE, true));
+		context.sendMessage(new KeyEventMessage(Keymap.K_DELETE, false));
+		context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, false));
+		context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false));
+	}
+
+	private void sendWinKey(ProtocolContext context) {
+		context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true));
+		context.sendMessage(new KeyEventMessage(Keymap.K_ESCAPE, true));
+		context.sendMessage(new KeyEventMessage(Keymap.K_ESCAPE, false));
+		context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false));
+	}
+
+	@Override
+	public void windowOpened(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowClosed(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowIconified(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowDeiconified(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowActivated(WindowEvent e) { /* nop */ }
+	@Override
+	public void windowDeactivated(WindowEvent e) { /* nop */ }
+
+	protected static String ver() {
+		final InputStream mfStream = Viewer.class.getClassLoader().getResourceAsStream(
+				"META-INF/MANIFEST.MF");
+		if (null == mfStream) {
+			System.out.println("No Manifest file found.");
+			return "-1";
+		}
+		try {
+			Manifest mf = new Manifest();
+			mf.read(mfStream);
+			Attributes atts = mf.getMainAttributes();
+			return atts.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+		} catch (IOException e) {
+			return "-2";
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/cli/Parser.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,118 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.cli;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.glavsoft.utils.Strings;
+
+/**
+ * Command line interface parameters parser
+ */
+public class Parser {
+	private final Map<String, Option> options = new LinkedHashMap<String, Option>();
+	private final List<String> plainOptions = new ArrayList<String>();
+	private boolean isSetPlainOptions = false;
+
+	public void addOption(String opName, String defaultValue, String desc) {
+		Option op = new Option(opName, defaultValue, desc);
+		options.put(opName.toLowerCase(), op);
+	}
+
+	public void parse(String [] args) {
+		for (String p : args) {
+			if (p.startsWith("-")) {
+				int skipMinuses = p.startsWith("--") ? 2 : 1;
+				String[] params = p.split("=", 2);
+				Option op = options.get(params[0].toLowerCase().substring(skipMinuses));
+				if (op != null) {
+					op.isSet = true;
+					if (params.length > 1 && ! Strings.isTrimmedEmpty(params[1])) {
+						op.value = params[1];
+					}
+				}
+			} else if ( ! p.startsWith("-")) {
+				isSetPlainOptions = true;
+				plainOptions.add(p);
+			}
+		}
+	}
+
+	public String getValueFor(String param) {
+		Option op = options.get(param.toLowerCase());
+		return op != null ? op.value : null;
+	}
+
+	public boolean isSet(String param) {
+		Option op = options.get(param.toLowerCase());
+		return op != null ? op.isSet : false;
+	}
+
+	public boolean isSetPlainOptions() {
+		return isSetPlainOptions;
+	}
+
+	public String getPlainOptionAt(int index) {
+		return plainOptions.get(index);
+	}
+
+	public int getPlainOptionsNumber() {
+		return plainOptions.size();
+	}
+
+	/**
+	 * Command line interface option
+	 */
+	private static class Option {
+		@SuppressWarnings("unused")
+		protected String opName, defaultValue, desc, value;
+		protected boolean isSet = false;
+		public Option(String opName, String defaultValue, String desc) {
+			this.opName = opName;
+			this.defaultValue = defaultValue;
+			this.desc = desc;
+			this.value = defaultValue;
+		}
+	}
+
+	public String optionsUsage() {
+		StringBuilder sb = new StringBuilder();
+		int maxNameLength = 0;
+		for (Option op : options.values()) {
+			maxNameLength = Math.max(maxNameLength, op.opName.length());
+		}
+		for (Option op : options.values()) {
+			sb.append(" -").append(op.opName);
+			for (int i=0; i<maxNameLength - op.opName.length(); ++i) {
+				sb.append(' ');
+			}
+			sb.append(" : ").append(op.desc).append('\n');
+		}
+		return sb.toString();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/ClipboardControllerImpl.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,154 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.rfb.ClipboardController;
+import com.glavsoft.rfb.client.ClientCutTextMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.utils.Strings;
+
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.security.AccessControlException;
+
+public class ClipboardControllerImpl implements ClipboardController, Runnable {
+	private static final String STANDARD_CHARSET = "ISO-8859-1"; // aka Latin-1
+	private static final long CLIPBOARD_UPDATE_CHECK_INTERVAL_MILS = 1000L;
+	private Clipboard clipboard;
+	private String clipboardText = null;
+	private volatile boolean isRunning;
+	private boolean isEnabled;
+	private final ProtocolContext context;
+	private Charset charset;
+
+	public ClipboardControllerImpl(ProtocolContext context, String charsetName) {
+		this.context = context;
+		try {
+			clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+			updateSavedClipboardContent(); // prevent onstart clipboard content sending
+		} catch (AccessControlException e) { /*nop*/ }
+		
+		if (Strings.isTrimmedEmpty(charsetName)) {
+			charset = Charset.defaultCharset();
+		} else if ("standard".equalsIgnoreCase(charsetName)) {
+			charset = Charset.forName(STANDARD_CHARSET);
+		} else {
+			charset = Charset.isSupported(charsetName) ? Charset.forName(charsetName) : Charset.defaultCharset();
+		}
+		// not supported UTF-charsets as they are multibytes.
+		// add others multibytes charsets on need
+		if (charset.name().startsWith("UTF")) {
+			charset = Charset.forName(STANDARD_CHARSET);
+		}
+	}
+
+	@Override
+	public void updateSystemClipboard(byte[] bytes) {
+		if (clipboard != null) {
+			StringSelection stringSelection = new StringSelection(new String(bytes, charset));
+			if (isEnabled) {
+				clipboard.setContents(stringSelection, null);
+			}
+		}
+	}
+
+	/**
+	 *	Callback for clipboard changes listeners
+	 *  Retrieves text content from system clipboard which then available
+	 *  through getClipboardText().
+	 */
+	private void updateSavedClipboardContent() {
+		if (clipboard != null && clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
+			try {
+				clipboardText = (String)clipboard.getData(DataFlavor.stringFlavor);
+			} catch (UnsupportedFlavorException e) {
+				// ignore
+			} catch (IOException e) {
+				// ignore
+			}
+		} else {
+			clipboardText = null;
+		}
+	}
+
+	@Override
+	public String getClipboardText() {
+		return clipboardText;
+	}
+
+	/**
+	 * Get text clipboard contents when needed send to remote, or null vise versa
+	 *
+	 * @return clipboard string contents if it is changed from last method call
+	 * or null when clipboard contains non text object or clipboard contents didn't changed
+	 */
+	@Override
+	public String getRenewedClipboardText() {
+		String old = clipboardText;
+		updateSavedClipboardContent();
+		if (clipboardText != null && ! clipboardText.equals(old))
+			return clipboardText;
+		return null;
+	}
+
+	@Override
+	public void setEnabled(boolean enable) {
+		if (! enable) {
+			isRunning = false;
+		}
+		if (enable && ! isEnabled) {
+			new Thread(this).start();
+		}
+		isEnabled = enable;
+	}
+
+	@Override
+	public void run() {
+		isRunning = true;
+		while (isRunning) {
+			String clipboardText = getRenewedClipboardText();
+			if (clipboardText != null) {
+				context.sendMessage(new ClientCutTextMessage(clipboardText.getBytes(charset)));
+			}
+			try {
+				Thread.sleep(CLIPBOARD_UPDATE_CHECK_INTERVAL_MILS);
+			} catch (InterruptedException e) { continue; }
+		}
+	}
+
+	@Override
+	public void settingsChanged(SettingsChangedEvent e) {
+		ProtocolSettings settings = (ProtocolSettings) e.getSource();
+		setEnabled(settings.isAllowClipboardTransfer());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/KeyEventListener.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,209 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import com.glavsoft.rfb.client.KeyEventMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import static com.glavsoft.utils.Keymap.*;
+
+public class KeyEventListener implements KeyListener {
+
+
+	private ModifierButtonEventListener modifierButtonListener;
+	private boolean convertToAscii;
+	private final ProtocolContext context;
+	private KeyboardConvertor convertor;
+
+	public KeyEventListener(ProtocolContext context) {
+		this.context = context;
+		this.convertToAscii = false;
+	}
+
+	private void processKeyEvent(KeyEvent e) {
+		if (processModifierKeys(e)) return;
+		if (processSpecialKeys(e)) return;
+		if (processActionKey(e)) return;
+
+		int keyChar = e.getKeyChar();
+		final int location = e.getKeyLocation();
+		if (0xffff == keyChar) { keyChar = convertToAscii? convertor.convert(keyChar, e) : 0; }
+		if (keyChar < 0x20) {
+			if (e.isControlDown()) {
+				keyChar += 0x60; // TODO: From legacy code. What's this?
+			} else {
+				switch (keyChar) {
+				case KeyEvent.VK_BACK_SPACE: keyChar = K_BACK_SPACE; break;
+				case KeyEvent.VK_TAB: keyChar = K_TAB; break;
+				case KeyEvent.VK_ESCAPE: keyChar = K_ESCAPE; break;
+				case KeyEvent.VK_ENTER:
+					keyChar = KeyEvent.KEY_LOCATION_NUMPAD == location ? K_KP_ENTER : K_ENTER;
+					break;
+				}
+			}
+		} else if (KeyEvent.VK_DELETE == keyChar) {
+			keyChar = K_DELETE;
+		} else if (convertToAscii) {
+			keyChar = convertor.convert(keyChar, e);
+		} else {
+			keyChar = unicode2keysym(keyChar);
+		}
+
+		sendKeyEvent(keyChar, e);
+	}
+
+
+	/**
+	 * Process AltGraph, num pad keys...
+	 */
+	private boolean processSpecialKeys(KeyEvent e) {
+		int keyCode = e.getKeyCode();
+		if (KeyEvent.VK_ALT_GRAPH == keyCode) {
+			sendKeyEvent(K_CTRL_LEFT, e);
+			sendKeyEvent(K_ALT_LEFT, e);
+			return true;
+		}
+		switch (keyCode) {
+		case KeyEvent.VK_NUMPAD0: keyCode = K_KP_0;break;
+		case KeyEvent.VK_NUMPAD1: keyCode = K_KP_1;break;
+		case KeyEvent.VK_NUMPAD2: keyCode = K_KP_2;break;
+		case KeyEvent.VK_NUMPAD3: keyCode = K_KP_3;break;
+		case KeyEvent.VK_NUMPAD4: keyCode = K_KP_4;break;
+		case KeyEvent.VK_NUMPAD5: keyCode = K_KP_5;break;
+		case KeyEvent.VK_NUMPAD6: keyCode = K_KP_6;break;
+		case KeyEvent.VK_NUMPAD7: keyCode = K_KP_7;break;
+		case KeyEvent.VK_NUMPAD8: keyCode = K_KP_8;break;
+		case KeyEvent.VK_NUMPAD9: keyCode = K_KP_9;break;
+
+		case KeyEvent.VK_MULTIPLY: keyCode = K_KP_MULTIPLY;break;
+		case KeyEvent.VK_ADD: keyCode = K_KP_ADD;break;
+		case KeyEvent.VK_SEPARATOR: keyCode = K_KP_SEPARATOR;break;
+		case KeyEvent.VK_SUBTRACT: keyCode = K_KP_SUBTRACT;break;
+		case KeyEvent.VK_DECIMAL: keyCode = K_KP_DECIMAL;break;
+		case KeyEvent.VK_DIVIDE: keyCode = K_KP_DIVIDE;break;
+
+		default: return false;
+		}
+		sendKeyEvent(keyCode, e);
+		return true;
+	}
+
+	private boolean processActionKey(KeyEvent e) {
+		int keyCode = e.getKeyCode();
+		final int location = e.getKeyLocation();
+		if (e.isActionKey()) {
+			switch (keyCode) {
+			case KeyEvent.VK_HOME: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_HOME: K_HOME; break;
+			case KeyEvent.VK_LEFT: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_LEFT: K_LEFT; break;
+			case KeyEvent.VK_UP: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_UP: K_UP; break;
+			case KeyEvent.VK_RIGHT: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_RIGHT: K_RIGHT; break;
+			case KeyEvent.VK_DOWN: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_DOWN: K_DOWN; break;
+			case KeyEvent.VK_PAGE_UP: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_PAGE_UP: K_PAGE_UP; break;
+			case KeyEvent.VK_PAGE_DOWN: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_PAGE_DOWN: K_PAGE_DOWN; break;
+			case KeyEvent.VK_END: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_END: K_END; break;
+			case KeyEvent.VK_INSERT: keyCode = KeyEvent.KEY_LOCATION_NUMPAD == location? K_KP_INSERT: K_INSERT; break;
+			case KeyEvent.VK_F1: keyCode = K_F1; break;
+			case KeyEvent.VK_F2: keyCode = K_F2; break;
+			case KeyEvent.VK_F3: keyCode = K_F3; break;
+			case KeyEvent.VK_F4: keyCode = K_F4; break;
+			case KeyEvent.VK_F5: keyCode = K_F5; break;
+			case KeyEvent.VK_F6: keyCode = K_F6; break;
+			case KeyEvent.VK_F7: keyCode = K_F7; break;
+			case KeyEvent.VK_F8: keyCode = K_F8; break;
+			case KeyEvent.VK_F9: keyCode = K_F9; break;
+			case KeyEvent.VK_F10: keyCode = K_F10; break;
+			case KeyEvent.VK_F11: keyCode = K_F11; break;
+			case KeyEvent.VK_F12: keyCode = K_F12; break;
+
+			case KeyEvent.VK_KP_LEFT: keyCode = K_KP_LEFT; break;
+			case KeyEvent.VK_KP_UP: keyCode = K_KP_UP; break;
+			case KeyEvent.VK_KP_RIGHT: keyCode = K_KP_RIGHT; break;
+			case KeyEvent.VK_KP_DOWN: keyCode = K_KP_DOWN; break;
+
+			default: return false; // ignore other 'action' keys
+			}
+			sendKeyEvent(keyCode, e);
+			return true;
+		}
+		return false;
+	}
+
+	private boolean processModifierKeys(KeyEvent e) {
+		int keyCode = e.getKeyCode();
+		switch (keyCode) {
+			case KeyEvent.VK_CONTROL: keyCode = K_CTRL_LEFT; break;
+			case KeyEvent.VK_SHIFT: keyCode = K_SHIFT_LEFT; break;
+			case KeyEvent.VK_ALT: keyCode = K_ALT_LEFT; break;
+			case KeyEvent.VK_META: keyCode = K_META_LEFT; break;
+			// follow two are 'action' keys in java terms but modifier keys actualy
+			case KeyEvent.VK_WINDOWS: keyCode = K_SUPER_LEFT; break;
+			case KeyEvent.VK_CONTEXT_MENU: keyCode = K_HYPER_LEFT; break;
+			default: return false;
+		}
+		if (modifierButtonListener != null) {
+			modifierButtonListener.fireEvent(e);
+		}
+		sendKeyEvent(keyCode +
+				(e.getKeyLocation() == KeyEvent.KEY_LOCATION_RIGHT ? 1 : 0), // "Right" Ctrl/Alt/Shift/Meta deffers frim "Left" ones by +1
+				e);
+		return true;
+	}
+
+	private void sendKeyEvent(int keyChar, KeyEvent e) {
+		context.sendMessage(new KeyEventMessage(keyChar, e.getID() == KeyEvent.KEY_PRESSED));
+	}
+
+	@Override
+	public void keyTyped(KeyEvent e) {
+		e.consume();
+	}
+
+	@Override
+	public void keyPressed(KeyEvent e) {
+		processKeyEvent(e);
+		e.consume();
+	}
+
+	@Override
+	public void keyReleased(KeyEvent e) {
+		processKeyEvent(e);
+		e.consume();
+	}
+
+	public void addModifierListener(ModifierButtonEventListener modifierButtonListener) {
+		this.modifierButtonListener = modifierButtonListener;
+	}
+
+	public void setConvertToAscii(boolean convertToAscii) {
+		this.convertToAscii = convertToAscii;
+		if (convertToAscii && null == convertor) {
+			convertor = new KeyboardConvertor();
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/KeyboardConvertor.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,151 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class KeyboardConvertor {
+	private static final boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
+	private static final String PATTERN_STRING_FOR_SCANCODE = "scancode=(\\d+)";
+	private Pattern patternForScancode;
+	@SuppressWarnings("serial")
+	private static final Map<Integer, CodePair> keyMap = new HashMap<Integer, CodePair>() {{
+		put(192 /* Back Quote */, new CodePair('`' /*96*/, '~' /*126*/));
+		put(49 /* 1 */, new CodePair('1' /*49*/, '!' /*33*/));
+		put(50 /* 2 */, new CodePair('2' /*50*/, '@' /*64*/));
+		put(51 /* 3 */, new CodePair('3' /*51*/, '#' /*35*/));
+		put(52 /* 4 */, new CodePair('4' /*52*/, '$' /*36*/));
+		put(53 /* 5 */, new CodePair('5' /*53*/, '%' /*37*/));
+		put(54 /* 6 */, new CodePair('6' /*54*/, '^' /*94*/));
+		put(55 /* 7 */, new CodePair('7' /*55*/, '&' /*38*/));
+		put(56 /* 8 */, new CodePair('8' /*56*/, '*' /*42*/));
+		put(57 /* 9 */, new CodePair('9' /*57*/, '(' /*40*/));
+		put(48 /* 0 */, new CodePair('0' /*48*/, ')' /*41*/));
+		put(45 /* Minus */, new CodePair('-' /*45*/, '_' /*95*/));
+		put(61 /* Equals */, new CodePair('=' /*61*/, '+' /*43*/));
+		put(92 /* Back Slash */, new CodePair('\\' /*92*/, '|' /*124*/));
+
+		put(81 /* Q */, new CodePair('q' /*113*/, 'Q' /*81*/));
+		put(87 /* W */, new CodePair('w' /*119*/, 'W' /*87*/));
+		put(69 /* E */, new CodePair('e' /*101*/, 'E' /*69*/));
+		put(82 /* R */, new CodePair('r' /*114*/, 'R' /*82*/));
+		put(84 /* T */, new CodePair('t' /*116*/, 'T' /*84*/));
+		put(89 /* Y */, new CodePair('y' /*121*/, 'Y' /*89*/));
+		put(85 /* U */, new CodePair('u' /*117*/, 'U' /*85*/));
+		put(73 /* I */, new CodePair('i' /*105*/, 'I' /*73*/));
+		put(79 /* O */, new CodePair('o' /*111*/, 'O' /*79*/));
+		put(80 /* P */, new CodePair('p' /*112*/, 'P' /*80*/));
+		put(91 /* Open Bracket */, new CodePair('[' /*91*/, '{' /*123*/));
+		put(93 /* Close Bracket */, new CodePair(']' /*93*/, '}' /*125*/));
+
+		put(65 /* A */, new CodePair('a' /*97*/, 'A' /*65*/));
+		put(83 /* S */, new CodePair('s' /*115*/, 'S' /*83*/));
+		put(68 /* D */, new CodePair('d' /*100*/, 'D' /*68*/));
+		put(70 /* F */, new CodePair('f' /*102*/, 'F' /*70*/));
+		put(71 /* G */, new CodePair('g' /*103*/, 'G' /*71*/));
+		put(72 /* H */, new CodePair('h' /*104*/, 'H' /*72*/));
+		put(74 /* J */, new CodePair('j' /*106*/, 'J' /*74*/));
+		put(75 /* K */, new CodePair('k' /*107*/, 'K' /*75*/));
+		put(76 /* L */, new CodePair('l' /*108*/, 'L' /*76*/));
+		put(59 /* Semicolon */, new CodePair(';' /*59*/, ':' /*58*/));
+		put(222 /* Quote */, new CodePair('\'' /*39*/, '"' /*34*/));
+
+		put(90 /* Z */, new CodePair('z' /*122*/, 'Z' /*90*/));
+		put(88 /* X */, new CodePair('x' /*120*/, 'X' /*88*/));
+		put(67 /* C */, new CodePair('c' /*99*/, 'C' /*67*/));
+		put(86 /* V */, new CodePair('v' /*118*/, 'V' /*86*/));
+		put(66 /* B */, new CodePair('b' /*98*/, 'B' /*66*/));
+		put(78 /* N */, new CodePair('n' /*110*/, 'N' /*78*/));
+		put(77 /* M */, new CodePair('m' /*109*/, 'M' /*77*/));
+		put(44 /* Comma */, new CodePair(',' /*44*/, '<' /*60*/));
+		put(46 /* Period */, new CodePair('.' /*46*/, '>' /*62*/));
+		put(47 /* Slash */, new CodePair('/' /*47*/, '?' /*63*/));
+
+//		put(60 /* Less */, new CodePair('<' /*60*/, '>')); // 105-th key on 105-keys keyboard (less/greather/bar)
+		put(KeyEvent.VK_LESS /* Less */, new CodePair('<' /*60*/, '>')); // 105-th key on 105-keys keyboard (less/greather/bar)
+//		put(KeyEvent.VK_GREATER /* Greater */, new CodePair('<' /*60*/, '>')); // 105-th key on 105-keys keyboard (less/greather/bar)
+	}};
+
+	private static boolean canCheckCapsWithToolkit;
+
+	public KeyboardConvertor() {
+		try {
+			Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK);
+			canCheckCapsWithToolkit = true;
+		} catch (Exception e) {
+			canCheckCapsWithToolkit = false;
+		}
+		if (isWindows) {
+			patternForScancode = Pattern.compile(PATTERN_STRING_FOR_SCANCODE);
+		}
+	}
+
+	public int convert(int keyChar, KeyEvent ev) {
+		int keyCode = ev.getKeyCode();
+		boolean isShiftDown = ev.isShiftDown();
+		CodePair codePair = keyMap.get(keyCode);
+		if (null == codePair)
+			return keyChar;
+		if (isWindows) {
+			final Matcher matcher = patternForScancode.matcher(ev.paramString());
+			if (matcher.matches()) {
+				try {
+				int scancode = Integer.parseInt(matcher.group(1));
+				if (90 == keyCode && 21 == scancode) { // deutsch z->y
+					codePair = keyMap.get(89); // y
+				} else if (89 == keyCode && 44 == scancode) { // deutsch y->z
+					codePair = keyMap.get(90); // z
+				}
+				} catch (NumberFormatException e) { /*nop*/ };
+			}
+		}
+		boolean isCapsLock = false;
+		if (Character.isLetter(codePair.code)) {
+			if (canCheckCapsWithToolkit) {
+				try {
+					isCapsLock =
+						Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK);
+				} catch (Exception ex) { /* nop */ }
+			}
+		}
+		return isShiftDown && ! isCapsLock || ! isShiftDown && isCapsLock ?
+				codePair.codeShifted :
+				codePair.code;
+	}
+
+	private static class CodePair {
+		public int code, codeShifted;
+		public CodePair(int code, int codeShifted) {
+			this.code = code;
+			this.codeShifted = codeShifted;
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/ModifierButtonEventListener.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,44 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import java.awt.event.KeyEvent;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.JToggleButton;
+
+public class ModifierButtonEventListener {
+	Map<Integer, JToggleButton> buttons = new HashMap<Integer, JToggleButton>();
+	public void addButton(int keyCode, JToggleButton button) {
+		buttons.put(keyCode, button);
+	}
+	public void fireEvent(KeyEvent e) {
+		int code = e.getKeyCode();
+		if (buttons.containsKey(code)) {
+			buttons.get(code).setSelected(e.getID() == KeyEvent.KEY_PRESSED);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/MouseEventListener.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,131 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+
+import javax.swing.event.MouseInputAdapter;
+
+import com.glavsoft.rfb.IRepaintController;
+import com.glavsoft.rfb.client.PointerEventMessage;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+
+public class MouseEventListener extends MouseInputAdapter
+implements MouseWheelListener {
+	private static final byte BUTTON_LEFT = 1;
+	private static final byte BUTTON_MIDDLE = 1 << 1;
+	private static final byte BUTTON_RIGHT = 1 << 2;
+	private static final byte WHEEL_UP = 1 << 3;
+	private static final byte WHEEL_DOWN = 1 << 4;
+
+	private final IRepaintController repaintController;
+	private final ProtocolContext context;
+	private volatile double scaleFactor;
+
+	public MouseEventListener(IRepaintController repaintController, ProtocolContext context,
+			double scaleFactor) {
+		this.repaintController = repaintController;
+		this.context = context;
+		this.scaleFactor = scaleFactor;
+	}
+
+	public void processMouseEvent(MouseEvent mouseEvent,
+			MouseWheelEvent mouseWheelEvent, boolean moved) {
+		// TODO handle scaling
+
+		byte buttonMask = 0;
+		if (null == mouseEvent && mouseWheelEvent != null) {
+			mouseEvent = mouseWheelEvent;
+		}
+		assert mouseEvent != null;
+		short x = (short) (mouseEvent.getX() / scaleFactor);
+		short y = (short) (mouseEvent.getY() / scaleFactor);
+		if (moved) {
+			repaintController.updateCursorPosition(x, y);
+		}
+
+		int modifiersEx = mouseEvent.getModifiersEx();
+		// left
+		buttonMask |= (modifiersEx & InputEvent.BUTTON1_DOWN_MASK) != 0 ?
+				BUTTON_LEFT : 0;
+		// middle
+		buttonMask |= (modifiersEx & InputEvent.BUTTON2_DOWN_MASK) != 0 ?
+				BUTTON_MIDDLE : 0;
+		// right
+		buttonMask |= (modifiersEx & InputEvent.BUTTON3_DOWN_MASK) != 0 ?
+				BUTTON_RIGHT : 0;
+
+		// wheel
+		if (mouseWheelEvent != null) {
+			int notches = mouseWheelEvent.getWheelRotation();
+			byte wheelMask = notches < 0 ? WHEEL_UP : WHEEL_DOWN;
+			// handle more then 1 notches
+			notches = Math.abs(notches);
+			for (int i=1; i<notches; ++i) {
+				context.sendMessage(new PointerEventMessage((byte) (buttonMask | wheelMask), x, y));
+				context.sendMessage(new PointerEventMessage(buttonMask, x, y));
+			}
+			context.sendMessage(new PointerEventMessage((byte) (buttonMask | wheelMask), x, y));
+		}
+		context.sendMessage(new PointerEventMessage(buttonMask, x, y));
+	}
+
+	@Override
+	public void mousePressed(MouseEvent mouseEvent) {
+		processMouseEvent(mouseEvent, null, false);
+	}
+
+	@Override
+	public void mouseReleased(MouseEvent mouseEvent) {
+		processMouseEvent(mouseEvent, null, false);
+	}
+
+	@Override
+	public void mouseEntered(MouseEvent mouseEvent) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public void mouseDragged(MouseEvent mouseEvent) {
+		processMouseEvent(mouseEvent, null, true);
+	}
+
+	@Override
+	public void mouseMoved(MouseEvent mouseEvent) {
+		processMouseEvent(mouseEvent, null, true);
+	}
+
+	@Override
+	public void mouseWheelMoved(MouseWheelEvent emouseWheelEvent) {
+		processMouseEvent(null, emouseWheelEvent, false);
+	}
+
+	public void setScaleFactor(double scaleFactor) {
+		this.scaleFactor = scaleFactor;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/ParametersHandler.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,262 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.protocol.LocalPointer;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.utils.Strings;
+import com.glavsoft.viewer.Viewer;
+import com.glavsoft.viewer.cli.Parser;
+
+import javax.swing.*;
+
+public class ParametersHandler {
+	public static final String ARG_LOCAL_POINTER = "LocalPointer";
+	public static final String ARG_SCALING_FACTOR = "ScalingFactor";
+	public static final String ARG_COLOR_DEPTH = "ColorDepth";
+	public static final String ARG_JPEG_IMAGE_QUALITY = "JpegImageQuality";
+	public static final String ARG_COMPRESSION_LEVEL = "CompressionLevel";
+	public static final String ARG_ENCODING = "Encoding";
+	public static final String ARG_SHARE_DESKTOP = "ShareDesktop";
+	public static final String ARG_ALLOW_COPY_RECT = "AllowCopyRect";
+	public static final String ARG_VIEW_ONLY = "ViewOnly";
+	public static final String ARG_SHOW_CONTROLS = "ShowControls";
+	public static final String ARG_OPEN_NEW_WINDOW = "OpenNewWindow";
+	public static final String ARG_PASSWORD = "password";
+	public static final String ARG_PORT = "port";
+	public static final String ARG_HOST = "host";
+	public static final String ARG_HELP = "help";
+	public static final String ARG_CONVERT_TO_ASCII = "ConvertToASCII";
+	public static final String ARG_ALLOW_CLIPBOARD_TRANSFER = "AllowClipboardTransfer";
+	public static final String ARG_REMOTE_CHARSET = "RemoteCharset";
+
+	public static class ConnectionParams {
+		public String hostName;
+		public int portNumber = Viewer.DEFAULT_PORT;
+		public boolean isHostNameEmpty() {
+			return Strings.isTrimmedEmpty(hostName);
+		}
+		void parsePortNumber(String port) {
+			try {
+				portNumber = Integer.parseInt(port);
+			} catch (NumberFormatException e) { /*nop*/ }
+		}
+	}
+
+	public static boolean showControls;
+	public static boolean isSeparateFrame;
+
+	public static void completeParserOptions(Parser parser) {
+		parser.addOption(ARG_HELP, null, "Print this help.");
+		parser.addOption(ARG_HOST, null, "Server host name.");
+		parser.addOption(ARG_PORT, "5900", "Port number.");
+		parser.addOption(ARG_PASSWORD, null, "Password to the server.");
+		parser.addOption(ARG_SHOW_CONTROLS, null, "Set to \"No\" if you want to get rid of that " +
+				"button panel at the top. Default: \"Yes\".");
+		parser.addOption(ARG_VIEW_ONLY, null, "When set to \"Yes\", then all keyboard and mouse " +
+				"events in the desktop window will be silently ignored and will not be passed " +
+				"to the remote side. Default: \"No\".");
+		parser.addOption(ARG_ALLOW_CLIPBOARD_TRANSFER, null, "When set to \"Yes\", transfer of clipboard contents is allowed. " +
+				"Default: \"Yes\".");
+		parser.addOption(ARG_REMOTE_CHARSET, null, "Charset encoding is used on remote system. Use this option to specify character encoding will be used for encoding clipboard text content to. Default value: local system default character encoding. Set the value to 'standard' for using 'Latin-1' charset which is only specified by rfb standard for clipboard transfers.");
+		parser.addOption(ARG_SHARE_DESKTOP, null, "Share the connection with other clients " +
+				"on the same VNC server. The exact behaviour in each case depends on the server " +
+				"configuration. Default: \"Yes\".");
+		parser.addOption(ARG_ALLOW_COPY_RECT, null, "The \"CopyRect\" encoding saves bandwidth " +
+				"and drawing time when parts of the remote screen are moving around. " +
+				"Most likely, you don't want to change this setting. Default: \"Yes\".");
+		parser.addOption(ARG_ENCODING, null, "The preferred encoding. Possible values: \"Tight\", " +
+				"\"Hextile\", \"ZRLE\", and \"Raw\". Default: \"Tight\".");
+		parser.addOption(ARG_COMPRESSION_LEVEL, null, "Use specified compression level for " +
+				"\"Tight\" and \"Zlib\" encodings. Values: 1-9. Level 1 uses minimum of CPU " +
+				"time on the server but achieves weak compression ratios. Level 9 offers best " +
+				"compression but may be slow.");
+		parser.addOption(ARG_JPEG_IMAGE_QUALITY, null, "Use the specified image quality level " +
+				"in \"Tight\" encoding. Values: 1-9, Lossless. Default value: " +
+				(String.valueOf(ProtocolSettings.DEFAULT_JPEG_QUALITY))
+				+ ". To prevent server of using " +
+				"lossy JPEG compression in \"Tight\" encoding, use \"Lossless\" value here.");
+		parser.addOption(ARG_LOCAL_POINTER, null, "Possible values: on/yes/true (draw pointer locally), off/no/false (let server draw pointer), hide). " +
+		"Default: \"On\".");
+		parser.addOption(ARG_CONVERT_TO_ASCII, null, "Whether to convert keyboard input to ASCII ignoring locale. Possible values: yes/true, no/false). " +
+		"Default: \"No\".");
+		parser.addOption(ARG_COLOR_DEPTH, null, "Bits per pixel color format. Possible values: 3 (for 8 colors), 6 (64 colors), 8 (256 colors), 16 (65 536 colors), 24 (16 777 216 colors), 32 (same as 24).");
+		parser.addOption(ARG_SCALING_FACTOR, null, "Scale local representation of the remote desktop on startup. " +
+				"The value is interpreted as scaling factor in percents. The default value of 100% " +
+				"corresponds to the original framebuffer size.");
+	}
+
+	public static void completeSettingsFromCLI(Parser parser, ConnectionParams connectionParams, ProtocolSettings rfbSettings, UiSettings uiSettings) {
+		completeSettings(parser.getValueFor(ARG_HOST), parser.getValueFor(ARG_PORT),
+				parser.getValueFor(ARG_SHOW_CONTROLS), parser.getValueFor(ARG_VIEW_ONLY),
+				parser.getValueFor(ARG_ALLOW_CLIPBOARD_TRANSFER), parser.getValueFor(ARG_REMOTE_CHARSET),
+				parser.getValueFor(ARG_ALLOW_COPY_RECT), parser.getValueFor(ARG_SHARE_DESKTOP),
+				parser.getValueFor(ARG_ENCODING), parser.getValueFor(ARG_COMPRESSION_LEVEL),
+				parser.getValueFor(ARG_JPEG_IMAGE_QUALITY), parser.getValueFor(ARG_COLOR_DEPTH),
+				parser.getValueFor(ARG_SCALING_FACTOR), parser.getValueFor(ARG_LOCAL_POINTER),
+				parser.getValueFor(ARG_CONVERT_TO_ASCII), connectionParams, rfbSettings, uiSettings);
+		// when hostName == a.b.c.d:3 where :3 is display num (X Window) we need add display num to port number
+		if ( ! Strings.isTrimmedEmpty(connectionParams.hostName)) {
+			splitConnectionParams(connectionParams, connectionParams.hostName);
+		}
+		if (parser.isSetPlainOptions()) {
+			splitConnectionParams(connectionParams, parser.getPlainOptionAt(0));
+			if (parser.getPlainOptionsNumber() > 1) {
+				connectionParams.parsePortNumber(parser.getPlainOptionAt(1));
+			}
+		}
+	}
+
+
+	/**
+	 * Split host string into hostName + port number and set ConnectionParans.
+	 * a.b.c.d:5000 -> hostName == a.b.c.d, portNumber == 5000
+	 * a.b.c.d::5000 -> hostName == a.b.c.d, portNumber == 5000
+	 */
+	public static void splitConnectionParams(final ConnectionParams connectionParams, String host) {
+		int indexOfColon = host.indexOf(':');
+		if (indexOfColon > 0) {
+			String[] splitted = host.split(":");
+			connectionParams.hostName = splitted[0];
+			if (splitted.length > 1) {
+				connectionParams.parsePortNumber(splitted[splitted.length - 1]);
+			}
+		} else {
+			connectionParams.hostName = host;
+		}
+	}
+
+	private static void completeSettings(String hostName, String portNumber,
+	                                     String showControlsParam, String viewOnlyParam, String allowClipboardTransfer,
+	                                     String remoteCharsetName,
+	                                     String allowCopyRectParam,
+	                                     String shareDesktopParam, String encodingParam, String compressionLevelParam,
+	                                     String jpegQualityParam, String colorDepthParam, String scaleFactorParam,
+	                                     String localPointerParam,
+	                                     String convertToAsciiParam, ConnectionParams connectionParams, ProtocolSettings rfbSettings, UiSettings uiSettings) {
+		connectionParams.hostName = hostName;
+		try {
+			connectionParams.portNumber = Integer.parseInt(portNumber);
+		} catch (NumberFormatException e) { /* nop */ }
+
+		showControls = parseBooleanOrDefault(showControlsParam, true);
+		rfbSettings.setViewOnly(parseBooleanOrDefault(viewOnlyParam, false));
+		rfbSettings.setAllowClipboardTransfer(parseBooleanOrDefault(allowClipboardTransfer, true));
+		rfbSettings.setRemoteCharsetName(remoteCharsetName);
+	    rfbSettings.setAllowCopyRect(parseBooleanOrDefault(allowCopyRectParam, true));
+		rfbSettings.setSharedFlag(parseBooleanOrDefault(shareDesktopParam, true));
+		rfbSettings.setConvertToAscii(parseBooleanOrDefault(convertToAsciiParam, false));
+		if (EncodingType.TIGHT.getName().equalsIgnoreCase(encodingParam)) {
+			rfbSettings.setPreferredEncoding(EncodingType.TIGHT);
+		}
+		if (EncodingType.HEXTILE.getName().equalsIgnoreCase(encodingParam)) {
+			rfbSettings.setPreferredEncoding(EncodingType.HEXTILE);
+		}
+		if (EncodingType.ZRLE.getName().equalsIgnoreCase(encodingParam)) {
+			rfbSettings.setPreferredEncoding(EncodingType.ZRLE);
+		}
+		if (EncodingType.RAW_ENCODING.getName().equalsIgnoreCase(encodingParam)) {
+			rfbSettings.setPreferredEncoding(EncodingType.RAW_ENCODING);
+		}
+		try {
+			int compLevel = Integer.parseInt(compressionLevelParam);
+			if (compLevel > 0 && compLevel <= 9) {
+				rfbSettings.setCompressionLevel(compLevel);
+			}
+		} catch (NumberFormatException e) { /* nop */ }
+		try {
+			int jpegQuality = Integer.parseInt(jpegQualityParam);
+			if (jpegQuality > 0 && jpegQuality <= 9) {
+				rfbSettings.setJpegQuality(jpegQuality);
+			}
+		} catch (NumberFormatException e) {
+			if ("lossless".equalsIgnoreCase(jpegQualityParam)) {
+				rfbSettings.setJpegQuality( - Math.abs(rfbSettings.getJpegQuality()));
+			}
+		}
+		try {
+			int colorDepth = Integer.parseInt(colorDepthParam);
+			rfbSettings.setBitsPerPixel(colorDepth);
+		} catch (NumberFormatException e) { /* nop */ }
+		if (scaleFactorParam != null) {
+			try {
+				int scaleFactor = Integer.parseInt(scaleFactorParam.replaceAll("\\D", ""));
+				if (scaleFactor >= 10 && scaleFactor <= 200) {
+					uiSettings.setScalePercent(scaleFactor);
+				}
+			} catch (NumberFormatException e) { /* nop */ }
+		}
+
+		if ("on".equalsIgnoreCase(localPointerParam) ||
+			"true".equalsIgnoreCase(localPointerParam) ||
+			"yes".equalsIgnoreCase(localPointerParam)) {
+				rfbSettings.setMouseCursorTrack(LocalPointer.ON);
+		}
+		if ("off".equalsIgnoreCase(localPointerParam) ||
+			"no".equalsIgnoreCase(localPointerParam) ||
+			"false".equalsIgnoreCase(localPointerParam)) {
+				rfbSettings.setMouseCursorTrack(LocalPointer.OFF);
+		}
+		if ("hide".equalsIgnoreCase(localPointerParam) ||
+			"hidden".equalsIgnoreCase(localPointerParam)) {
+				rfbSettings.setMouseCursorTrack(LocalPointer.HIDE);
+		}
+	}
+
+	static boolean parseBooleanOrDefault(String param, boolean defaultValue) {
+		return defaultValue ?
+				! ("no".equalsIgnoreCase(param) || "false".equalsIgnoreCase(param)) :
+				"yes".equalsIgnoreCase(param) || "true".equalsIgnoreCase(param);
+	}
+
+	public static void completeSettingsFromApplet(JApplet applet,
+			ConnectionParams connectionParams, ProtocolSettings rfbSettings, UiSettings uiSettings) {
+
+		String host = applet.getParameter(ARG_HOST);
+		if (Strings.isTrimmedEmpty(host)) {
+			host = applet.getCodeBase().getHost();
+		}
+		completeSettings(host,
+				applet.getParameter(ARG_PORT),
+				applet.getParameter(ARG_SHOW_CONTROLS),
+				applet.getParameter(ARG_VIEW_ONLY),
+				applet.getParameter(ARG_ALLOW_CLIPBOARD_TRANSFER),
+				applet.getParameter(ARG_REMOTE_CHARSET),
+				applet.getParameter(ARG_ALLOW_COPY_RECT),
+				applet.getParameter(ARG_SHARE_DESKTOP),
+				applet.getParameter(ARG_ENCODING),
+				applet.getParameter(ARG_COMPRESSION_LEVEL),
+				applet.getParameter(ARG_JPEG_IMAGE_QUALITY),
+				applet.getParameter(ARG_COLOR_DEPTH),
+				applet.getParameter(ARG_SCALING_FACTOR),
+				applet.getParameter(ARG_LOCAL_POINTER),
+				applet.getParameter(ARG_CONVERT_TO_ASCII),
+				connectionParams, rfbSettings, uiSettings);
+		isSeparateFrame = parseBooleanOrDefault(applet.getParameter(ARG_OPEN_NEW_WINDOW), true);
+	}
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/RendererImpl.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,109 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.transport.Reader;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class RendererImpl extends Renderer implements ImageObserver {
+	private final Image offscreanImage;
+	public RendererImpl(Reader reader, int width, int height, PixelFormat pixelFormat) {
+		if (0 == width) width = 1;
+		if (0 == height) height = 1;
+		init(reader, width, height, pixelFormat);
+		ColorModel colorModel = new DirectColorModel(24, 0xff0000, 0xff00, 0xff);
+		SampleModel sampleModel = colorModel.createCompatibleSampleModel(width,
+				height);
+
+		DataBuffer dataBuffer = new DataBufferInt(pixels, width * height);
+		WritableRaster raster = Raster.createWritableRaster(sampleModel,
+				dataBuffer, null);
+		offscreanImage = new BufferedImage(colorModel, raster, false, null);
+		cursor = new SoftCursorImpl(0, 0, 0, 0);
+	}
+
+	/**
+	 * Draw jpeg image data
+	 *
+	 * @param bytes jpeg image data array
+	 * @param offset start offset at data array
+	 * @param jpegBufferLength jpeg image data array length
+	 * @param rect image location and dimensions
+	 */
+	CyclicBarrier barier = new CyclicBarrier(2);
+	@Override
+	public void drawJpegImage(byte[] bytes, int offset, int jpegBufferLength,
+			FramebufferUpdateRectangle rect) {
+		Image jpegImage = Toolkit.getDefaultToolkit().createImage(bytes,
+				offset, jpegBufferLength);
+		Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this);
+		try {
+			barier.await(3, TimeUnit.SECONDS);
+		} catch (InterruptedException e) {
+			// nop
+		} catch (BrokenBarrierException e) {
+			// nop
+		} catch (TimeoutException e) {
+			// nop
+		}
+		Graphics graphics = offscreanImage.getGraphics();
+		graphics.drawImage(jpegImage, rect.x, rect.y, rect.width, rect.height, this);
+	}
+
+	@Override
+	public boolean imageUpdate(Image img, int infoflags, int x, int y,
+			int width, int height) {
+		boolean isReady = (infoflags & (ALLBITS | ABORT)) != 0;
+		if (isReady) {
+			try {
+				barier.await();
+			} catch (InterruptedException e) {
+				// nop
+			} catch (BrokenBarrierException e) {
+				// nop
+			}
+		}
+		return ! isReady;
+	}
+
+	/* Swing specific interface */
+	public Image getOffscreenImage() {
+		return offscreanImage;
+	}
+
+	public SoftCursorImpl getCursor() {
+		return (SoftCursorImpl) cursor;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/SoftCursorImpl.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,51 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.MemoryImageSource;
+
+import com.glavsoft.drawing.SoftCursor;
+
+public class SoftCursorImpl extends SoftCursor {
+	private Image cursorImage;
+
+	public SoftCursorImpl(int hotX, int hotY, int width, int height) {
+		super(hotX, hotY, width, height);
+	}
+
+	public Image getImage() {
+		return cursorImage;
+	}
+
+	@Override
+	protected void createNewCursorImage(int[] cursorPixels, int hotX, int hotY, int width,	int height) {
+		cursorImage = Toolkit.getDefaultToolkit().createImage(
+				new MemoryImageSource(width, height, cursorPixels, 0, width));
+
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/Surface.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,232 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.drawing.Renderer;
+import com.glavsoft.rfb.IChangeSettingsListener;
+import com.glavsoft.rfb.IRepaintController;
+import com.glavsoft.rfb.encoding.PixelFormat;
+import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle;
+import com.glavsoft.rfb.protocol.ProtocolContext;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.transport.Reader;
+import com.glavsoft.viewer.Viewer;
+
+import javax.swing.*;
+import java.awt.*;
+
+@SuppressWarnings("serial")
+public class Surface extends JPanel implements IRepaintController, IChangeSettingsListener {
+
+	private int width;
+	private int height;
+	private SoftCursorImpl cursor;
+	private RendererImpl renderer;
+	private MouseEventListener mouseEventListener;
+	private KeyEventListener keyEventListener;
+	private boolean showCursor;
+	private ModifierButtonEventListener modifierButtonListener;
+	private boolean isUserInputEnabled = false;
+	private final ProtocolContext context;
+	private double scaleFactor;
+	private final Viewer viewer;
+
+	@Override
+	public boolean isDoubleBuffered() {
+		// TODO returning false in some reason may speed ups drawing, but may
+		// not. Needed in challenging.
+		return false;
+	}
+
+	public Surface(ProtocolContext context, Viewer viewer, double scaleFactor) {
+		this.context = context;
+		this.viewer = viewer;
+		this.scaleFactor = scaleFactor;
+		init(context.getFbWidth(), context.getFbHeight());
+
+		if ( ! context.getSettings().isViewOnly()) {
+			setUserInputEnabled(true, context.getSettings().isConvertToAscii());
+		}
+		showCursor = context.getSettings().isShowRemoteCursor();
+	}
+
+	private void setUserInputEnabled(boolean enable, boolean convertToAscii) {
+		if (enable == isUserInputEnabled) return;
+		isUserInputEnabled = enable;
+		if (enable) {
+			if (null == mouseEventListener) {
+				mouseEventListener = new MouseEventListener(this, context, scaleFactor);
+			}
+			addMouseListener(mouseEventListener);
+			addMouseMotionListener(mouseEventListener);
+			addMouseWheelListener(mouseEventListener);
+
+			setFocusTraversalKeysEnabled(false);
+			if (null == keyEventListener) {
+				keyEventListener = new KeyEventListener(context);
+				if (modifierButtonListener != null) {
+					keyEventListener.addModifierListener(modifierButtonListener);
+				}
+			}
+			keyEventListener.setConvertToAscii(convertToAscii);
+			addKeyListener(keyEventListener);
+			enableInputMethods(false);
+		} else {
+			removeMouseListener(mouseEventListener);
+			removeMouseMotionListener(mouseEventListener);
+			removeMouseWheelListener(mouseEventListener);
+			removeKeyListener(keyEventListener);
+		}
+	}
+
+	@Override
+	public Renderer createRenderer(Reader reader, int width, int height, PixelFormat pixelFormat) {
+		renderer = new RendererImpl(reader, width, height, pixelFormat);
+		synchronized (renderer) {
+			cursor = renderer.getCursor();
+		}
+		init(renderer.getWidth(), renderer.getHeight());
+		updateFrameSize();
+		return renderer;
+	}
+
+	private void init(int width, int height) {
+		this.width = width;
+		this.height = height;
+		setSize(getPreferredSize());
+	}
+
+	private void updateFrameSize() {
+		setSize(getPreferredSize());
+		viewer.packContainer();
+		requestFocus();
+	}
+
+	@Override
+	public void paintComponent(Graphics g) {
+		((Graphics2D)g).scale(scaleFactor, scaleFactor);
+		((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+		synchronized (renderer) {
+			Image offscreenImage = renderer.getOffscreenImage();
+			if (offscreenImage != null) {
+				g.drawImage(offscreenImage, 0, 0, null);
+			}
+		}
+		synchronized (cursor) {
+			Image cursorImage = cursor.getImage();
+			if (showCursor && cursorImage != null &&
+					(scaleFactor != 1 ||
+							g.getClipBounds().intersects(cursor.rX, cursor.rY, cursor.width, cursor.height))) {
+				g.drawImage(cursorImage, cursor.rX, cursor.rY, null);
+			}
+		}
+	}
+
+	@Override
+	public Dimension getPreferredSize() {
+		return new Dimension((int)(this.width * scaleFactor), (int)(this.height * scaleFactor));
+	}
+
+	@Override
+	public Dimension getMinimumSize() {
+		return getPreferredSize();
+	}
+
+	@Override
+	public Dimension getMaximumSize() {
+		return getPreferredSize();
+	}
+
+	/**
+	 * Saves context and simply invokes native JPanel repaint method which
+	 * asyncroniously register repaint request using invokeLater to repaint be
+	 * runned in Swing event dispatcher thread. So may be called from other
+	 * threads.
+	 */
+	@Override
+	public void repaintBitmap(FramebufferUpdateRectangle rect) {
+		repaintBitmap(rect.x, rect.y, rect.width, rect.height);
+	}
+
+	@Override
+	public void repaintBitmap(int x, int y, int width, int height) {
+		repaint((int)(x * scaleFactor), (int)(y * scaleFactor),
+                (int)Math.ceil(width * scaleFactor), (int)Math.ceil(height * scaleFactor));
+	}
+
+	@Override
+	public void repaintCursor() {
+		synchronized (cursor) {
+			repaint((int)(cursor.oldRX * scaleFactor), (int)(cursor.oldRY * scaleFactor),
+					(int)Math.ceil(cursor.oldWidth * scaleFactor) + 1, (int)Math.ceil(cursor.oldHeight * scaleFactor) + 1);
+			repaint((int)(cursor.rX * scaleFactor), (int)(cursor.rY * scaleFactor),
+					(int)Math.ceil(cursor.width * scaleFactor) + 1, (int)Math.ceil(cursor.height * scaleFactor) + 1);
+		}
+	}
+
+	@Override
+	public void updateCursorPosition(short x, short y) {
+		synchronized (cursor) {
+			cursor.updatePosition(x, y);
+			repaintCursor();
+		}
+	}
+
+	private void showCursor(boolean show) {
+		synchronized (cursor) {
+			showCursor = show;
+		}
+	}
+
+	public void addModifierListener(ModifierButtonEventListener modifierButtonListener) {
+		this.modifierButtonListener = modifierButtonListener;
+		if (keyEventListener != null) {
+			keyEventListener.addModifierListener(modifierButtonListener);
+		}
+	}
+
+	@Override
+	public void settingsChanged(SettingsChangedEvent e) {
+		if (ProtocolSettings.isRfbSettingsChangedFired(e)) {
+			ProtocolSettings settings = (ProtocolSettings) e.getSource();
+			setUserInputEnabled( ! settings.isViewOnly(), settings.isConvertToAscii());
+			showCursor(settings.isShowRemoteCursor());
+		} else if (UiSettings.isUiSettingsChangedFired(e)) {
+			UiSettings settings = (UiSettings) e.getSource();
+			scaleFactor = settings.getScaleFactor();
+		}
+		mouseEventListener.setScaleFactor(scaleFactor);
+		updateFrameSize();
+	}
+
+	@Override
+	public void setPixelFormat(PixelFormat pixelFormat) {
+		if (renderer != null) {
+			renderer.initPixelFormat(pixelFormat);
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/UiSettings.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,140 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import com.glavsoft.core.SettingsChangedEvent;
+import com.glavsoft.rfb.IChangeSettingsListener;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author dime at tightvnc.com
+ */
+public class UiSettings {
+    public static final int MIN_SCALE_PERCENT = 10;
+	public static final int MAX_SCALE_PERCENT = 500;
+    private static final int SCALE_PERCENT_ZOOMING_STEP = 10;
+	
+	public static final int CHANGED_SCALE_FACTOR = 1 << 0;
+	public static final int CHANGED_SYSTEM_CURSOR = 1 << 1;
+
+	private int changedSettingsMask = 0;
+
+	private double scalePercent = 100;
+	private final List<IChangeSettingsListener> listeners = new LinkedList<IChangeSettingsListener>();
+
+	public UiSettings() {
+		scalePercent = 100;
+		changedSettingsMask = 0;
+	}
+
+	private UiSettings(UiSettings uiSettings) {
+		this.scalePercent = uiSettings.scalePercent;
+		this.changedSettingsMask = uiSettings.changedSettingsMask;
+	}
+
+	public double getScaleFactor() {
+		return scalePercent / 100.;
+	}
+
+	public void setScalePercent(double scalePercent) {
+		this.scalePercent = scalePercent;
+		changedSettingsMask |= CHANGED_SCALE_FACTOR;
+	}
+
+	public void addListener(IChangeSettingsListener listener) {
+		listeners.add(listener);
+	}
+
+	public void fireListeners() {
+		final SettingsChangedEvent event = new SettingsChangedEvent(new UiSettings(this));
+		changedSettingsMask = 0;
+		for (IChangeSettingsListener listener : listeners) {
+			listener.settingsChanged(event);
+		}
+	}
+
+    public void zoomOut() {
+	    double oldScaleFactor = scalePercent;
+	    double scaleFactor = (int)(this.scalePercent / SCALE_PERCENT_ZOOMING_STEP) * SCALE_PERCENT_ZOOMING_STEP;
+	    if (scaleFactor == oldScaleFactor) {
+		    scaleFactor -= SCALE_PERCENT_ZOOMING_STEP;
+	    }
+	    if (scaleFactor < MIN_SCALE_PERCENT) {
+		    scaleFactor = MIN_SCALE_PERCENT;
+	    }
+	    setScalePercent(scaleFactor);
+	    fireListeners();
+    }
+
+    public void zoomIn() {
+	    double scaleFactor = (int)(this.scalePercent / SCALE_PERCENT_ZOOMING_STEP) * SCALE_PERCENT_ZOOMING_STEP + SCALE_PERCENT_ZOOMING_STEP;
+	    if (scaleFactor > MAX_SCALE_PERCENT) {
+		    scaleFactor = MAX_SCALE_PERCENT;
+	    }
+	    setScalePercent(scaleFactor);
+	    fireListeners();
+    }
+
+    public void zoomAsIs() {
+	    setScalePercent(100);
+	    fireListeners();
+    }
+
+	public void zoomToFit(int containerWidth, int containerHeight, int fbWidth, int fbHeight) {
+		int scalePromille = Math.min(1000 * containerWidth / fbWidth,
+				1000 * containerHeight / fbHeight);
+		while (fbWidth * scalePromille / 1000. > containerWidth ||
+				fbHeight * scalePromille / 1000. > containerHeight) {
+			scalePromille -= 1;
+		}
+		setScalePercent(scalePromille / 10.);
+		fireListeners();
+	}
+
+	public boolean isChangedScaleFactor() {
+		return (changedSettingsMask & CHANGED_SCALE_FACTOR) == CHANGED_SCALE_FACTOR;
+	}
+
+	public boolean isChangedSystemCursor() {
+		return (changedSettingsMask & CHANGED_SYSTEM_CURSOR) == CHANGED_SYSTEM_CURSOR;
+	}
+
+	public static boolean isUiSettingsChangedFired(SettingsChangedEvent event) {
+		return event.getSource() instanceof UiSettings;
+	}
+
+	public double getScalePercent() {
+		return scalePercent;
+	}
+
+	public String getScalePercentFormatted() {
+		NumberFormat numberFormat = new DecimalFormat("###.#");
+		return numberFormat.format(scalePercent);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/Utils.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,72 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.ImageIcon;
+
+/**
+ * Utils for Swing GUI
+ */
+public class Utils {
+	private static List<Image> icons;
+
+	/**
+	 * Get application icons
+	 *
+	 * @return icons list
+	 */
+	public static List<Image> getIcons() {
+		if (icons != null) {
+			return icons;
+		}
+		icons = new LinkedList<Image>();
+		URL resource = Utils.class.getResource("/com/glavsoft/viewer/images/tightvnc-logo-16x16.png");
+		Image image = resource != null ?
+				Toolkit.getDefaultToolkit().getImage(resource) :
+				null;
+		if (image != null) {
+			icons.add(image);
+		}
+		resource = Utils.class.getResource("/com/glavsoft/viewer/images/tightvnc-logo-32x32.png");
+		image = resource != null ?
+				Toolkit.getDefaultToolkit().getImage(resource) :
+				null;
+		if (image != null) {
+			icons.add(image);
+		}
+		return icons;
+	}
+
+	public static ImageIcon getButtonIcon(String name) {
+		URL resource = Utils.class.getResource("/com/glavsoft/viewer/images/button-"+name+".png");
+		return resource != null ? new ImageIcon(resource) : null;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/gui/ConnectionDialog.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,204 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing.gui;
+
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+import com.glavsoft.utils.Strings;
+import com.glavsoft.viewer.Viewer;
+import com.glavsoft.viewer.swing.Utils;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowListener;
+import java.util.List;
+
+/**
+ * Dialog window for connection parameters get from.
+ */
+@SuppressWarnings("serial")
+public class ConnectionDialog extends JDialog {
+	private static final int PADDING = 4;
+	private String serverNameString;
+	private int serverPort;
+
+	public ConnectionDialog(final JFrame owner, final WindowListener appWindowListener, String serverNameString,
+	                        int serverPort, final ProtocolSettings settings, boolean isApplet) {
+		super(owner, "New TightVNC Connection",
+				isApplet ? ModalityType.APPLICATION_MODAL : ModalityType.TOOLKIT_MODAL);
+		try {
+			setAlwaysOnTop(true);
+		} catch (SecurityException e) { /*nop*/ }
+		this.serverNameString = serverNameString;
+		this.serverPort = serverPort;
+
+		JPanel pane = new JPanel(new GridBagLayout());
+		add(pane);
+		pane.setBorder(new EmptyBorder(PADDING, PADDING, PADDING, PADDING));
+
+		setLayout(new GridBagLayout());
+		GridBagConstraints cServerLabel = new GridBagConstraints();
+		cServerLabel.gridx = 0; cServerLabel.gridy = 0;
+		cServerLabel.weightx = 100; cServerLabel.weighty = 100;
+		cServerLabel.gridwidth = 1; cServerLabel.gridheight = 1;
+		cServerLabel.anchor = GridBagConstraints.LINE_END;
+		cServerLabel.ipadx = PADDING;
+		pane.add(new JLabel("TightVNC Server:"), cServerLabel);
+
+		final JTextField serverNameField = new JTextField(
+				null == serverNameString ? "" : serverNameString, 20);
+		GridBagConstraints cServerName = new GridBagConstraints();
+		cServerName.gridx = 1; cServerName.gridy = 0;
+		cServerName.weightx = 0; cServerName.weighty = 100;
+		cServerName.gridwidth = 1; cServerName.gridheight = 1;
+		cServerName.anchor = GridBagConstraints.LINE_START;
+		pane.add(serverNameField, cServerName);
+
+		GridBagConstraints cPortLabel = new GridBagConstraints();
+		cPortLabel.gridx = 0; cPortLabel.gridy = 1;
+		cPortLabel.weightx = 100; cPortLabel.weighty = 100;
+		cPortLabel.gridwidth = 1; cPortLabel.gridheight = 1;
+		cPortLabel.anchor = GridBagConstraints.LINE_END;
+		cPortLabel.ipadx = PADDING;
+		cPortLabel.ipady = 10;
+		pane.add(new JLabel("Port:"), cPortLabel);
+
+		GridBagConstraints cPort = new GridBagConstraints();
+		cPort.gridx = 1; cPort.gridy = 1;
+		cPort.weightx = 0; cPort.weighty = 100;
+		cPort.gridwidth = 1; cPort.gridheight = 1;
+		cPort.anchor = GridBagConstraints.LINE_START;
+		final JTextField serverPortField = new JTextField(
+				String.valueOf(0 == serverPort ? Viewer.DEFAULT_PORT : serverPort), 10);
+		pane.add(serverPortField, cPort);
+
+		JPanel buttonPanel = new JPanel();
+
+		JButton connectButton = new JButton("Connect");
+		buttonPanel.add(connectButton);
+		connectButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setServerNameString(serverNameField.getText());
+				setPort(serverPortField.getText());
+				if (validateFields()) {
+					setVisible(false);
+				} else {
+					serverNameField.requestFocusInWindow();
+				}
+			}
+		});
+
+		JButton optionsButton = new JButton("Options...");
+		buttonPanel.add(optionsButton);
+		optionsButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				OptionsDialog od = new OptionsDialog(ConnectionDialog.this);
+				od.initControlsFromSettings(settings, true);
+
+				final ModalityType savedModalityType = getModalityType();
+				setModal(false);
+				try {
+					setAlwaysOnTop(false);
+				} catch (SecurityException se) { /*nop*/ }
+				setEnabled(false);
+
+				try {
+					od.setAlwaysOnTop(true);
+				} catch (SecurityException se) { /*nop*/ }
+				od.setModal(true);
+				od.setEnabled(true);
+				od.setVisible(true);
+
+				try {
+					setAlwaysOnTop(true);
+				} catch (SecurityException se) { /*nop*/ }
+				setModalityType(savedModalityType);
+				setEnabled(true);
+			}
+		});
+
+		JButton closeButton = new JButton("Close");
+		buttonPanel.add(closeButton);
+		closeButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setVisible(false);
+				appWindowListener.windowClosing(null);
+			}
+		});
+
+		GridBagConstraints cButtons = new GridBagConstraints();
+		cButtons.gridx = 0; cButtons.gridy = 2;
+		cButtons.weightx = 100; cButtons.weighty = 100;
+		cButtons.gridwidth = 2; cButtons.gridheight = 1;
+		pane.add(buttonPanel, cButtons);
+
+		getRootPane().setDefaultButton(connectButton);
+
+		List<Image> icons = Utils.getIcons();
+		if (icons.size() != 0) {
+			setIconImages(icons);
+		}
+		addWindowListener(appWindowListener);
+
+		// center dialog
+		Point locationPoint = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
+		pack();
+		setResizable(false);
+		Rectangle bounds = getBounds();
+		locationPoint.setLocation(
+				locationPoint.x - bounds.width/2, locationPoint.y - bounds.height/2);
+		setLocation(locationPoint);
+	}
+
+	protected boolean validateFields() {
+		return ! Strings.isTrimmedEmpty(serverNameString);
+	}
+
+	protected void setServerNameString(String text) {
+		serverNameString = text;
+	}
+
+	public String getServerNameString() {
+		return serverNameString;
+	}
+
+	public void setPort(String text) {
+		try {
+			serverPort = Integer.parseInt(text);
+		} catch (NumberFormatException e) {
+			serverPort = Viewer.DEFAULT_PORT;
+		}
+	}
+
+	public int getPort() {
+		return serverPort;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/gui/OptionsDialog.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,518 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing.gui;
+
+import com.glavsoft.rfb.encoding.EncodingType;
+import com.glavsoft.rfb.protocol.LocalPointer;
+import com.glavsoft.rfb.protocol.ProtocolSettings;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Options dialog
+ */
+@SuppressWarnings("serial")
+public class OptionsDialog extends JDialog {
+	private JSlider jpegQuality;
+	private JSlider compressionLevel;
+	private JCheckBox viewOnlyCheckBox;
+	private ProtocolSettings settings;
+	private JCheckBox sharedSession;
+
+	private RadioButtonSelectedState<LocalPointer> mouseCursorTrackSelected;
+	private Map<LocalPointer, JRadioButton> mouseCursorTrackMap;
+
+//	private RadioButtonSelectedState<Integer> colorDepthSelected;
+//	private Map<Integer, JRadioButton> colorDepthMap;
+
+	private JCheckBox useCompressionLevel;
+	private JCheckBox useJpegQuality;
+	private JLabel jpegQualityPoorLabel;
+	private JLabel jpegQualityBestLabel;
+	private JLabel compressionLevelFastLabel;
+	private JLabel compressionLevelBestLabel;
+	private JCheckBox allowCopyRect;
+	private JComboBox encodings;
+	private JCheckBox disableClipboardTransfer;
+	private JComboBox colorDepth;
+
+	public OptionsDialog(Window owner) {
+		super(owner, "Connection Options", ModalityType.MODELESS);
+		final WindowAdapter onClose = new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				setVisible(false);
+			}
+		};
+		addWindowListener(onClose);
+
+		JPanel optionsPane = new JPanel(new GridLayout(0, 2));
+		add(optionsPane, BorderLayout.CENTER);
+
+		optionsPane.add(createLeftPane());
+		optionsPane.add(createRightPane());
+
+		addButtons(onClose);
+
+		pack();
+	}
+
+	public void initControlsFromSettings(ProtocolSettings settings, boolean isOnConnect) {
+		this.settings = settings;
+
+		viewOnlyCheckBox.setSelected(settings.isViewOnly());
+
+//		String scaling = String.valueOf((int)(settings.scaling * 100));
+//		int i = 0; boolean isNotSetScale = true;
+//		while ( scaleCombo.getItemAt(i) != null) {
+//			String item = (String)scaleCombo.getItemAt(i);
+//			if (item.equals(scaling)) {
+//				scaleCombo.setSelectedIndex(i);
+//				isNotSetScale = false;
+//				break;
+//			}
+//			++i;
+//		}
+//		if (isNotSetScale) {
+//			scaleCombo.setSelectedItem(SCALE_100);
+//		}
+
+		int i = 0; boolean isNotSetEncoding = true;
+		while ( encodings.getItemAt(i) != null) {
+			EncodingType item = ((EncodingSelectItem)encodings.getItemAt(i)).type;
+			if (item.equals(settings.getPreferredEncoding())) {
+				encodings.setSelectedIndex(i);
+				isNotSetEncoding = false;
+				break;
+			}
+			++i;
+		}
+		if (isNotSetEncoding) {
+			encodings.setSelectedItem(0);
+		}
+
+		sharedSession.setSelected(settings.isShared());
+		sharedSession.setEnabled(isOnConnect);
+
+		mouseCursorTrackMap.get(settings.getMouseCursorTrack()).setSelected(true);
+		mouseCursorTrackSelected.setSelected(settings.getMouseCursorTrack());
+
+//		settings.setBitsPerPixel(settings.getBitsPerPixel()); // when 0 set default bpp value
+//		final JRadioButton colorDepthRadioButton = colorDepthMap.get(settings.getBitsPerPixel());
+//		if (colorDepthRadioButton != null) {
+//			colorDepthRadioButton.setSelected(true);
+//		}
+//		colorDepthSelected.setSelected(settings.getBitsPerPixel());
+
+		int bpp = settings.getBitsPerPixel();
+		i = 0; boolean isNotSet = true;
+		while ( colorDepth.getItemAt(i) != null) {
+			int itemBpp = ((ColorDepthSelectItem)colorDepth.getItemAt(i)).bpp;
+			if (itemBpp == bpp) {
+				colorDepth.setSelectedIndex(i);
+				isNotSet = false;
+				break;
+			}
+			++i;
+		}
+		if (isNotSet) {
+			colorDepth.setSelectedItem(0);
+		}
+
+		useCompressionLevel.setSelected(settings.getCompressionLevel() > 0);
+		compressionLevel.setValue(Math.abs(settings.getCompressionLevel()));
+		setCompressionLevelPaneEnable();
+
+		useJpegQuality.setSelected(settings.getJpegQuality() > 0);
+		jpegQuality.setValue(Math.abs(settings.getJpegQuality()));
+		setJpegQualityPaneEnable();
+
+		allowCopyRect.setSelected(settings.isAllowCopyRect());
+		disableClipboardTransfer.setSelected( ! settings.isAllowClipboardTransfer());
+}
+
+	private void setSettingsFromControls() {
+		settings.setViewOnly(viewOnlyCheckBox.isSelected());
+		settings.setPreferredEncoding(((EncodingSelectItem)encodings.getSelectedItem()).type);
+
+		settings.setSharedFlag(sharedSession.isSelected());
+		settings.setMouseCursorTrack(mouseCursorTrackSelected.getSelected());
+
+		settings.setBitsPerPixel(((ColorDepthSelectItem)colorDepth.getSelectedItem()).bpp);
+
+		settings.setCompressionLevel(useCompressionLevel.isSelected() ?
+				compressionLevel.getValue() :
+				- Math.abs(settings.getCompressionLevel()));
+		settings.setJpegQuality(useJpegQuality.isSelected() ?
+				jpegQuality.getValue() :
+				- Math.abs(settings.getJpegQuality()));
+		settings.setAllowCopyRect(allowCopyRect.isSelected());
+		settings.setAllowClipboardTransfer( ! disableClipboardTransfer.isSelected());
+		settings.fireListeners();
+	}
+
+	private Component createLeftPane() {
+		Box box = Box.createVerticalBox();
+		box.setAlignmentX(LEFT_ALIGNMENT);
+
+		box.add(createEncodingsPanel());
+
+		box.add(Box.createVerticalGlue());
+		return box;
+	}
+
+	private Component createRightPane() {
+		Box box = Box.createVerticalBox();
+		box.setAlignmentX(LEFT_ALIGNMENT);
+
+		box.add(createRestrictionsPanel());
+//		box.add(createDisplayPanel());
+		box.add(createMouseCursorPanel());
+//		box.add(createLocalShapePanel());
+
+		sharedSession = new JCheckBox("Request shared session");
+		box.add(new JPanel(new FlowLayout(FlowLayout.LEFT)).add(sharedSession));
+
+		box.add(Box.createVerticalGlue());
+		return box;
+	}
+
+	private JPanel createRestrictionsPanel() {
+		JPanel restrictionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+//		restrictionsPanel.setAlignmentX(LEFT_ALIGNMENT);
+		restrictionsPanel.setBorder(
+				BorderFactory.createTitledBorder(
+						BorderFactory.createEtchedBorder(), "Restrictions"));
+
+		Box restrictionsBox = Box.createVerticalBox();
+		restrictionsBox.setAlignmentX(LEFT_ALIGNMENT);
+		restrictionsPanel.add(restrictionsBox);
+		viewOnlyCheckBox = new JCheckBox("View only (inputs ignored)");
+		viewOnlyCheckBox.setAlignmentX(LEFT_ALIGNMENT);
+		restrictionsBox.add(viewOnlyCheckBox);
+
+		disableClipboardTransfer = new JCheckBox("Disable clipboard transfer");
+		disableClipboardTransfer.setAlignmentX(LEFT_ALIGNMENT);
+		restrictionsBox.add(disableClipboardTransfer);
+
+		return restrictionsPanel;
+	}
+
+	private JPanel createEncodingsPanel() {
+		JPanel encodingsPanel = new JPanel();
+		encodingsPanel.setAlignmentX(LEFT_ALIGNMENT);
+		encodingsPanel.setLayout(new BoxLayout(encodingsPanel, BoxLayout.Y_AXIS));
+		encodingsPanel.setBorder(
+				BorderFactory.createTitledBorder(
+						BorderFactory.createEtchedBorder(), "Format and Encodings"));
+
+		JPanel encPane = new JPanel(new FlowLayout(FlowLayout.LEFT));
+		encPane.setAlignmentX(LEFT_ALIGNMENT);
+		encPane.add(new JLabel("Preferred encoding: "));
+
+		encodings = new JComboBox();
+		encodings.addItem(new EncodingSelectItem(EncodingType.TIGHT));
+		encodings.addItem(new EncodingSelectItem(EncodingType.HEXTILE));
+
+//		encodings.addItem(new EncodingSelectItem(EncodingType.RRE));
+//		encodings.addItem(new EncodingSelectItem(EncodingType.ZLIB));
+
+		encodings.addItem(new EncodingSelectItem(EncodingType.ZRLE));
+		encodings.addItem(new EncodingSelectItem(EncodingType.RAW_ENCODING));
+		encPane.add(encodings);
+		encodingsPanel.add(encPane);
+
+		encodingsPanel.add(createColorDepthPanel());
+
+		addCompressionLevelPane(encodingsPanel);
+		addJpegQualityLevelPane(encodingsPanel);
+
+		allowCopyRect = new JCheckBox("Allow CopyRect encoding");
+		allowCopyRect.setAlignmentX(LEFT_ALIGNMENT);
+		encodingsPanel.add(allowCopyRect);
+
+		return encodingsPanel;
+	}
+
+	private static class EncodingSelectItem {
+		final EncodingType type;
+		public EncodingSelectItem(EncodingType type) {
+			this.type = type;
+		}
+		@Override
+		public String toString() {
+			return type.getName();
+		}
+	}
+
+	private static class ColorDepthSelectItem {
+		final int bpp;
+		final String title;
+		public ColorDepthSelectItem(int bpp, String title) {
+			this.bpp = bpp;
+			this.title = title;
+		}
+		@Override
+		public String toString() {
+			return title;
+		}
+	}
+
+	private JPanel createColorDepthPanel() {
+		JPanel colorDepthPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+		colorDepthPanel.setAlignmentX(LEFT_ALIGNMENT);
+		colorDepthPanel.add(new JLabel("Color format: "));
+
+		colorDepth = new JComboBox();
+		colorDepth.addItem(new ColorDepthSelectItem(ProtocolSettings.BPP_SERVER_SETTINGS,
+				"Server's default"));
+		colorDepth.addItem(new ColorDepthSelectItem(ProtocolSettings.BPP_32,
+				"16 777 216 colors"));
+		colorDepth.addItem(new ColorDepthSelectItem(ProtocolSettings.BPP_16,
+				"65 536 colors"));
+		colorDepth.addItem(new ColorDepthSelectItem(ProtocolSettings.BPP_8,
+				"256 colors"));
+		colorDepth.addItem(new ColorDepthSelectItem(ProtocolSettings.BPP_6,
+				"64 colors"));
+		colorDepth.addItem(new ColorDepthSelectItem(ProtocolSettings.BPP_3,
+				"8 colors"));
+
+		colorDepthPanel.add(colorDepth);
+		colorDepth.addItemListener(new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent e) {
+				final ColorDepthSelectItem selectedItem =
+						(ColorDepthSelectItem) colorDepth.getSelectedItem();
+				setEnabled(selectedItem.bpp > ProtocolSettings.BPP_8 ||
+						selectedItem.bpp == ProtocolSettings.BPP_SERVER_SETTINGS,
+						useJpegQuality);
+				setEnabled(useJpegQuality.isSelected() &&
+						(selectedItem.bpp > ProtocolSettings.BPP_8 ||
+							selectedItem.bpp == ProtocolSettings.BPP_SERVER_SETTINGS),
+						jpegQuality, jpegQualityPoorLabel, jpegQualityBestLabel);
+			}
+		});
+		return colorDepthPanel;
+	}
+
+	private void addJpegQualityLevelPane(JPanel encodingsPanel) {
+		useJpegQuality = new JCheckBox("Allow JPEG, set quality level:");
+		useJpegQuality.setAlignmentX(LEFT_ALIGNMENT);
+		encodingsPanel.add(useJpegQuality);
+
+		JPanel jpegQualityPane = new JPanel();
+		jpegQualityPane.setAlignmentX(LEFT_ALIGNMENT);
+		jpegQualityPoorLabel = new JLabel("poor");
+		jpegQualityPane.add(jpegQualityPoorLabel);
+		jpegQuality = new JSlider(1, 9, 9);
+		jpegQualityPane.add(jpegQuality);
+		jpegQuality.setPaintTicks(true);
+		jpegQuality.setMinorTickSpacing(1);
+		jpegQuality.setMajorTickSpacing(1);
+		jpegQuality.setPaintLabels(true);
+		jpegQuality.setSnapToTicks(true);
+		jpegQuality.setFont(
+				jpegQuality.getFont().deriveFont((float) 8));
+		jpegQualityBestLabel = new JLabel("best");
+		jpegQualityPane.add(jpegQualityBestLabel);
+		encodingsPanel.add(jpegQualityPane);
+
+		jpegQualityPoorLabel.setFont(jpegQualityPoorLabel.getFont().deriveFont((float) 10));
+		jpegQualityBestLabel.setFont(jpegQualityBestLabel.getFont().deriveFont((float) 10));
+
+		useJpegQuality.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setJpegQualityPaneEnable();
+			}
+		});
+	}
+
+	protected void setJpegQualityPaneEnable() {
+		if (useJpegQuality != null && colorDepth != null) {
+			int bpp = ((ColorDepthSelectItem)colorDepth.getSelectedItem()).bpp;
+			setEnabled(
+				bpp > ProtocolSettings.BPP_8 || bpp == ProtocolSettings.BPP_SERVER_SETTINGS,
+				useJpegQuality);
+			setEnabled(useJpegQuality.isSelected() &&
+				(bpp > ProtocolSettings.BPP_8 || bpp == ProtocolSettings.BPP_SERVER_SETTINGS),
+					jpegQuality, jpegQualityPoorLabel, jpegQualityBestLabel);
+		}
+	}
+
+	private void addCompressionLevelPane(JPanel encodingsPanel) {
+		useCompressionLevel = new JCheckBox("Custom compression level:");
+		useCompressionLevel.setAlignmentX(LEFT_ALIGNMENT);
+		encodingsPanel.add(useCompressionLevel);
+
+		JPanel compressionLevelPane = new JPanel();
+		compressionLevelPane.setAlignmentX(LEFT_ALIGNMENT);
+		compressionLevelFastLabel = new JLabel("fast");
+		compressionLevelPane.add(compressionLevelFastLabel);
+		compressionLevel = new JSlider(1, 9, 1);
+		compressionLevelPane.add(compressionLevel);
+		compressionLevel.setPaintTicks(true);
+		compressionLevel.setMinorTickSpacing(1);
+		compressionLevel.setMajorTickSpacing(1);
+		compressionLevel.setPaintLabels(true);
+		compressionLevel.setSnapToTicks(true);
+		compressionLevel.setFont(compressionLevel.getFont().deriveFont((float) 8));
+		compressionLevelBestLabel = new JLabel("best");
+		compressionLevelPane.add(compressionLevelBestLabel);
+		encodingsPanel.add(compressionLevelPane);
+
+		compressionLevelFastLabel.setFont(compressionLevelFastLabel.getFont().deriveFont((float) 10));
+		compressionLevelBestLabel.setFont(compressionLevelBestLabel.getFont().deriveFont((float) 10));
+
+		useCompressionLevel.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setEnabled(useCompressionLevel.isSelected(),
+						compressionLevel, compressionLevelFastLabel, compressionLevelBestLabel);
+			}
+		});
+		setCompressionLevelPaneEnable();
+	}
+
+	protected void setCompressionLevelPaneEnable() {
+		setEnabled(useCompressionLevel.isSelected(),
+				compressionLevel, compressionLevelFastLabel, compressionLevelBestLabel);
+	}
+	private void setEnabled(boolean isEnabled, JComponent ... comp) {
+		for (JComponent c : comp) {
+			c.setEnabled(isEnabled);
+		}
+	}
+
+	/*
+	private JPanel createLocalShapePanel() {
+		JPanel localCursorShapePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+//		localCursorShapePanel.setLayout(new BoxLayout(localCursorShapePanel, BoxLayout.Y_AXIS));
+		localCursorShapePanel.setBorder(
+				BorderFactory.createTitledBorder(
+						BorderFactory.createEtchedBorder(), "Local cursor shape"));
+		Box localCursorShapeBox = Box.createVerticalBox();
+		localCursorShapePanel.add(localCursorShapeBox);
+
+		JRadioButton dotCursorRadio = new JRadioButton("Dot cursor");
+		JRadioButton smallDotCursorRadio = new JRadioButton("Small dot cursor");
+		JRadioButton arrowCursorRadio = new JRadioButton("Default cursor");
+		JRadioButton noCursorRadio = new JRadioButton("No local cursor");
+		localCursorShapeBox.add(dotCursorRadio);
+		localCursorShapeBox.add(smallDotCursorRadio);
+		localCursorShapeBox.add(arrowCursorRadio);
+		localCursorShapeBox.add(noCursorRadio);
+		ButtonGroup localCursorButtonGroup = new ButtonGroup();
+		localCursorButtonGroup.add(dotCursorRadio);
+		localCursorButtonGroup.add(smallDotCursorRadio);
+		localCursorButtonGroup.add(arrowCursorRadio);
+		localCursorButtonGroup.add(noCursorRadio);
+		return localCursorShapePanel;
+	}
+*/
+	
+	private JPanel createMouseCursorPanel() {
+		JPanel mouseCursorPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+		mouseCursorPanel.setBorder(
+				BorderFactory.createTitledBorder(
+						BorderFactory.createEtchedBorder(), "Mouse Cursor"));
+		Box mouseCursorBox = Box.createVerticalBox();
+		mouseCursorPanel.add(mouseCursorBox);
+
+		ButtonGroup mouseCursorTrackGroup = new ButtonGroup();
+
+		mouseCursorTrackSelected = new RadioButtonSelectedState<LocalPointer>();
+		mouseCursorTrackMap = new HashMap<LocalPointer, JRadioButton>();
+
+		addRadioButton("Track remote cursor locally", LocalPointer.ON,
+				mouseCursorTrackSelected, mouseCursorTrackMap, mouseCursorBox,
+				mouseCursorTrackGroup);
+		addRadioButton("Let remote server deal with mouse cursor",
+				LocalPointer.OFF,
+				mouseCursorTrackSelected, mouseCursorTrackMap, mouseCursorBox,
+				mouseCursorTrackGroup);
+		addRadioButton("Don't show remote cursor", LocalPointer.HIDE,
+				mouseCursorTrackSelected, mouseCursorTrackMap, mouseCursorBox,
+				mouseCursorTrackGroup);
+		return mouseCursorPanel;
+	}
+
+	private static class RadioButtonSelectedState<T> {
+		private T state;
+
+		public void setSelected(T state) {
+			this.state = state;
+		}
+
+		public T getSelected() {
+			return state;
+		}
+
+	}
+
+	private <T> JRadioButton addRadioButton(String text, final T state,
+			final RadioButtonSelectedState<T> selected,
+			Map<T, JRadioButton> state2buttonMap, JComponent component, ButtonGroup group) {
+		JRadioButton radio = new JRadioButton(text);
+		radio.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				selected.setSelected(state);
+			}
+		});
+		component.add(radio);
+		group.add(radio);
+		state2buttonMap.put(state, radio);
+		return radio;
+	}
+
+	private void addButtons(final WindowListener onClose) {
+		JPanel buttonPanel = new JPanel();
+		JButton loginButton = new JButton("Ok");
+		buttonPanel.add(loginButton);
+		loginButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setSettingsFromControls();
+				setVisible(false);
+			}
+		});
+
+		JButton closeButton = new JButton("Cancel");
+		buttonPanel.add(closeButton);
+		closeButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				onClose.windowClosing(null);
+			}
+		});
+		add(buttonPanel, BorderLayout.SOUTH);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/gui/PasswordDialog.java	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,114 @@
+// Copyright (C) 2010, 2011 GlavSoft LLC.
+// All rights reserved.
+//
+//-------------------------------------------------------------------------
+// This file is part of the TightVNC software.  Please visit our Web site:
+//
+//                       http://www.tightvnc.com/
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//-------------------------------------------------------------------------
+//
+
+package com.glavsoft.viewer.swing.gui;
+
+import com.glavsoft.viewer.swing.Utils;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowListener;
+import java.util.List;
+
+/**
+ * Dialog to ask password
+ */
+@SuppressWarnings("serial")
+public class PasswordDialog extends JDialog {
+
+	private String password = "";
+
+	private static final int PADDING = 4;
+	private final JLabel messageLabel;
+	public PasswordDialog(Frame owner, final WindowListener onClose, boolean isApplet) {
+		super(owner, "Login", isApplet ? ModalityType.APPLICATION_MODAL : ModalityType.TOOLKIT_MODAL);
+		try {
+			setAlwaysOnTop(true);
+		} catch (SecurityException e) { /*nop*/ }
+		addWindowListener(onClose);
+		JPanel pane = new JPanel(new GridLayout(0, 1, PADDING, PADDING));
+		add(pane);
+		pane.setBorder(new EmptyBorder(PADDING, PADDING, PADDING, PADDING));
+
+		messageLabel = new JLabel("Server requires password authentication");
+		pane.add(messageLabel);
+
+		JPanel passwordPanel = new JPanel();
+		passwordPanel.add(new JLabel("Password:"));
+		final JPasswordField passwordField = new JPasswordField("", 20);
+		passwordPanel.add(passwordField);
+		pane.add(passwordPanel);
+
+		JPanel buttonPanel = new JPanel();
+		JButton loginButton = new JButton("Login");
+		buttonPanel.add(loginButton);
+		loginButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				password = new String(passwordField.getPassword());
+				setVisible(false);
+			}
+		});
+
+		JButton closeButton = new JButton("Close");
+		buttonPanel.add(closeButton);
+		closeButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				setVisible(false);
+				onClose.windowClosing(null);
+			}
+		});
+
+		pane.add(buttonPanel);
+
+		getRootPane().setDefaultButton(loginButton);
+
+		List<Image> icons = Utils.getIcons();
+		if (icons.size() != 0) {
+			setIconImages(icons);
+		}
+
+		// center dialog
+		Point locationPoint = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
+		pack();
+		Rectangle bounds = getBounds();
+		locationPoint.setLocation(
+				locationPoint.x - bounds.width/2, locationPoint.y - bounds.height/2);
+		setLocation(locationPoint);
+	}
+
+	public void setServerHostName(String serverHostName) {
+		messageLabel.setText("Server '" + serverHostName + "' requires password authentication");
+		pack();
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+}
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-alt.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-close.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-ctrl-alt-del.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-ctrl.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-file-transfer.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-fullscreen.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-info.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-new-connection.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-options.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-rec.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-refresh.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-save.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-win.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-100.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-fit.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-in.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/button-zoom-out.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/tightvnc-logo-16x16.png has changed
Binary file src/viewer_swing/resources/com/glavsoft/viewer/images/tightvnc-logo-32x32.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/web/viewer-applet-example.html	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,36 @@
+<!-- Copyright (C) 2010, 2011, 2012 GlavSoft LLC. -->
+<!-- All rights reserved. -->
+<!-- -->
+<!-- DO NOT USE OR REDISTRIBUTE THE CODE, UNLESS YOU HAVE OBTAINED A LICENSE. -->
+<!--  -->
+
+<html>
+	<title>TightVNC desktop</title>
+	<body>
+		<applet archive="${archive_name}.jar"
+			code="com.glavsoft.viewer.Viewer"
+			width="1" height="1">
+			<param name="Host" value="localhost" /> <!-- Host to connect. Default:  the host from which the applet was loaded. -->
+			<param name="Port" value="5900" /> <!-- Port number to connect. Default: 5900 -->
+			<!--param name="Password" value="" /--> <!-- Password to the server (not recommended to use this parameter here) -->
+			<param name="OpenNewWindow" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="ShowControls" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="ViewOnly" value="no" /> <!-- yes/true or no/false. Default: no/false -->
+			<param name="AllowClipboardTransfer" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+            <param name="RemoteCharset" value="standard" /> <!-- Charset encoding is used on remote system. Use this option to specify character encoding will be used for encoding clipboard text content to. Default value (when parameter is empty): local system default character encoding. Set the value to 'standard' for using 'Latin-1' charset which is only specified by rfb standard for clipboard transfers. -->
+
+			<param name="ShareDesktop" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="AllowCopyRect" value="yes" /> <!-- yes/true or no/false. Default: yes/true -->
+			<param name="Encoding" value="Tight" /> <!-- Possible values: "Tight", "Hextile", "ZRLE", and "Raw". Default: Tight -->
+			<param name="CompressionLevel" value="" /> <!-- 1-9 or empty. Empty means server default -->
+			<param name="JpegImageQuality" value="" /> <!-- 1-9, Lossless or empty. When param is set to "Lossless" no jpeg compression used. Empty means server default -->
+			<param name="LocalPointer" value="On" /> <!-- Possible values: on/yes/true (draw pointer locally), off/no/false (let server draw pointer), hide). Default: "On"-->
+			<param name="ConvertToASCII" value="no" /> <!-- Whether to convert keyboard input to ASCII ignoring locale. Possible values: yes/true, no/false). Default: "No"-->
+
+			<param name="colorDepth" value="" /> <!-- Reserved for future. Possible values: 6, 8, 16, 24, 32 (equals to 24). Only 24/32 is supported now -->
+			<param name="ScalingFactor" value="100" /> <!-- Scale local representation of the remote desktop on startup. Default is 100 means 100% -->
+		</applet>
+		<br />
+		<a href="http://www.tightvnc.com/">TightVNC Web Site</a>
+	</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/web/viewer-java-web-start-example.html	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,8 @@
+<html>
+	<title>TightVNC desktop</title>
+	<body>
+		<a href="viewer-java-web-start-example.jnlp">Start viewer</a> with Java Web Start.
+		<br />
+		<a href="http://www.tightvnc.com/">TightVNC Web Site</a>
+	</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/web/viewer-java-web-start-example.jnlp	Tue Jul 03 13:20:49 2012 +0900
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE jnlp PUBLIC "-//Sun Microsystems, Inc.//DTD JNLP 1.5//EN" "http://www.netbeans.org/jnlp/DTD/jnlp.dtd">
+<jnlp spec="1.0" codebase="http://localhost/" href="viewer-java-web-start-example.jnlp">
+	<information>
+		<title>TightVNC Viewer</title>
+		<vendor>GlavSoft LLC.</vendor>
+		<homepage href="http://www.tightvnc.com/"/>
+		<description>TightVNC Viewer</description>
+		<icon href="tightvnc-logo-16x16.png" width="16" height="16"/>
+		<icon href="tightvnc-logo-32x32.png" width="32" height="32"/>
+		<offline-allowed/>
+		<shortcut online="true">
+			<desktop/>
+			<menu submenu="Accessories"/>
+		</shortcut>
+	</information>
+	<resources>
+		<j2se href="http://java.sun.com/products/autodl/j2se" version="1.6+"/>
+		<jar href="${archive_name}.jar" main="true"/>
+	</resources>
+	<application-desc/>
+</jnlp>
\ No newline at end of file