summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDRC <dcommander@users.sourceforge.net>2011-05-13 21:42:14 +0000
committerDRC <dcommander@users.sourceforge.net>2011-05-13 21:42:14 +0000
commitc5dc03809027dfac6b88153304bf30d4adb5ec8a (patch)
tree9125624d0d913dc1cfd6610b0a3ca88eef8c15a7
parent561ff0cba91b23fcb5c19793764fc2510fc4d366 (diff)
downloadtigervnc-c5dc03809027dfac6b88153304bf30d4adb5ec8a.tar.gz
tigervnc-c5dc03809027dfac6b88153304bf30d4adb5ec8a.zip
Completely reworked Java viewer (contributed by Brian Hinz)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4413 3789f03b-4d11-0410-bbf8-ca57d06f2519
-rw-r--r--java/src/com/tigervnc/decoder/CoRREDecoder.java85
-rw-r--r--java/src/com/tigervnc/decoder/CopyRectDecoder.java50
-rw-r--r--java/src/com/tigervnc/decoder/HextileDecoder.java228
-rw-r--r--java/src/com/tigervnc/decoder/RREDecoder.java85
-rw-r--r--java/src/com/tigervnc/decoder/RawDecoder.java223
-rw-r--r--java/src/com/tigervnc/decoder/TightDecoder.java525
-rw-r--r--java/src/com/tigervnc/decoder/ZRLEDecoder.java310
-rw-r--r--java/src/com/tigervnc/decoder/ZlibDecoder.java103
-rw-r--r--java/src/com/tigervnc/decoder/common/Repaintable.java7
-rw-r--r--java/src/com/tigervnc/rdr/EndOfStream.java25
-rw-r--r--java/src/com/tigervnc/rdr/Exception.java25
-rw-r--r--java/src/com/tigervnc/rdr/IOException.java27
-rw-r--r--java/src/com/tigervnc/rdr/InStream.java (renamed from java/src/com/tigervnc/vncviewer/InStream.java)123
-rw-r--r--java/src/com/tigervnc/rdr/JavaInStream.java147
-rw-r--r--java/src/com/tigervnc/rdr/JavaOutStream.java82
-rw-r--r--java/src/com/tigervnc/rdr/MemInStream.java (renamed from java/src/com/tigervnc/vncviewer/MemInStream.java)6
-rw-r--r--java/src/com/tigervnc/rdr/MemOutStream.java53
-rw-r--r--java/src/com/tigervnc/rdr/OutStream.java141
-rw-r--r--java/src/com/tigervnc/rdr/ZlibInStream.java (renamed from java/src/com/tigervnc/vncviewer/ZlibInStream.java)8
-rw-r--r--java/src/com/tigervnc/rfb/AliasParameter.java35
-rw-r--r--java/src/com/tigervnc/rfb/AuthFailureException.java23
-rw-r--r--java/src/com/tigervnc/rfb/BoolParameter.java51
-rw-r--r--java/src/com/tigervnc/rfb/CConnection.java370
-rw-r--r--java/src/com/tigervnc/rfb/CMsgHandler.java85
-rw-r--r--java/src/com/tigervnc/rfb/CMsgReader.java173
-rw-r--r--java/src/com/tigervnc/rfb/CMsgReaderV3.java139
-rw-r--r--java/src/com/tigervnc/rfb/CMsgWriter.java164
-rw-r--r--java/src/com/tigervnc/rfb/CMsgWriterV3.java39
-rw-r--r--java/src/com/tigervnc/rfb/CSecurity.java46
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityManaged.java71
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityNone.java27
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityPlain.java50
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityStack.java69
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityTLS.java251
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityVeNCrypt.java199
-rw-r--r--java/src/com/tigervnc/rfb/CSecurityVncAuth.java60
-rw-r--r--java/src/com/tigervnc/rfb/Configuration.java91
-rw-r--r--java/src/com/tigervnc/rfb/ConnFailedException.java23
-rw-r--r--java/src/com/tigervnc/rfb/ConnParams.java172
-rw-r--r--java/src/com/tigervnc/rfb/Cursor.java34
-rw-r--r--java/src/com/tigervnc/rfb/Decoder.java51
-rw-r--r--java/src/com/tigervnc/rfb/DesCipher.java (renamed from java/src/com/tigervnc/vncviewer/DesCipher.java)6
-rw-r--r--java/src/com/tigervnc/rfb/Encoder.java25
-rw-r--r--java/src/com/tigervnc/rfb/Encodings.java69
-rw-r--r--java/src/com/tigervnc/rfb/Exception.java23
-rw-r--r--java/src/com/tigervnc/rfb/Hextile.java27
-rw-r--r--java/src/com/tigervnc/rfb/HextileDecoder.java101
-rw-r--r--java/src/com/tigervnc/rfb/Hostname.java41
-rw-r--r--java/src/com/tigervnc/rfb/IntParameter.java44
-rw-r--r--java/src/com/tigervnc/rfb/Keysyms.java88
-rw-r--r--java/src/com/tigervnc/rfb/LogWriter.java99
-rw-r--r--java/src/com/tigervnc/rfb/ManagedPixelBuffer.java38
-rw-r--r--java/src/com/tigervnc/rfb/MsgTypes.java40
-rw-r--r--java/src/com/tigervnc/rfb/PixelBuffer.java116
-rw-r--r--java/src/com/tigervnc/rfb/PixelFormat.java163
-rw-r--r--java/src/com/tigervnc/rfb/Point.java40
-rw-r--r--java/src/com/tigervnc/rfb/RREDecoder.java46
-rw-r--r--java/src/com/tigervnc/rfb/RawDecoder.java45
-rw-r--r--java/src/com/tigervnc/rfb/Rect.java89
-rw-r--r--java/src/com/tigervnc/rfb/Screen.java48
-rw-r--r--java/src/com/tigervnc/rfb/ScreenSet.java89
-rw-r--r--java/src/com/tigervnc/rfb/Security.java189
-rw-r--r--java/src/com/tigervnc/rfb/SecurityClient.java77
-rw-r--r--java/src/com/tigervnc/rfb/StringParameter.java46
-rw-r--r--java/src/com/tigervnc/rfb/TightDecoder.java427
-rw-r--r--java/src/com/tigervnc/rfb/UnicodeToKeysym.java795
-rw-r--r--java/src/com/tigervnc/rfb/UserMsgBox.java27
-rw-r--r--java/src/com/tigervnc/rfb/UserPasswdGetter.java27
-rw-r--r--java/src/com/tigervnc/rfb/VncAuth.java67
-rw-r--r--java/src/com/tigervnc/rfb/VoidParameter.java41
-rw-r--r--java/src/com/tigervnc/rfb/ZRLEDecoder.java166
-rw-r--r--java/src/com/tigervnc/rfb/screenTypes.java36
-rw-r--r--java/src/com/tigervnc/vncviewer/AuthPanel.java125
-rw-r--r--java/src/com/tigervnc/vncviewer/ButtonPanel.java154
-rw-r--r--java/src/com/tigervnc/vncviewer/CConn.java1137
-rw-r--r--java/src/com/tigervnc/vncviewer/ClipboardDialog.java107
-rw-r--r--java/src/com/tigervnc/vncviewer/ClipboardFrame.java135
-rw-r--r--java/src/com/tigervnc/vncviewer/DesktopWindow.java480
-rw-r--r--java/src/com/tigervnc/vncviewer/Dialog.java92
-rw-r--r--java/src/com/tigervnc/vncviewer/F8Menu.java133
-rw-r--r--java/src/com/tigervnc/vncviewer/HTTPConnectSocket.java61
-rw-r--r--java/src/com/tigervnc/vncviewer/HTTPConnectSocketFactory.java88
-rw-r--r--java/src/com/tigervnc/vncviewer/Makefile36
-rw-r--r--java/src/com/tigervnc/vncviewer/MessageBox.java83
-rw-r--r--java/src/com/tigervnc/vncviewer/OptionsDialog.java380
-rw-r--r--java/src/com/tigervnc/vncviewer/OptionsDialogCallback.java (renamed from java/src/com/tigervnc/vncviewer/TLSTunnel.java)41
-rw-r--r--java/src/com/tigervnc/vncviewer/OptionsFrame.java441
-rw-r--r--java/src/com/tigervnc/vncviewer/PasswdDialog.java88
-rw-r--r--java/src/com/tigervnc/vncviewer/PixelBufferImage.java185
-rw-r--r--java/src/com/tigervnc/vncviewer/README2
-rw-r--r--java/src/com/tigervnc/vncviewer/RecordOutputStream.java60
-rw-r--r--java/src/com/tigervnc/vncviewer/RecordingFrame.java313
-rw-r--r--java/src/com/tigervnc/vncviewer/ReloginPanel.java66
-rw-r--r--java/src/com/tigervnc/vncviewer/RfbInputStream.java45
-rw-r--r--java/src/com/tigervnc/vncviewer/RfbProto.java1202
-rw-r--r--java/src/com/tigervnc/vncviewer/ServerDialog.java178
-rw-r--r--java/src/com/tigervnc/vncviewer/SessionRecorder.java195
-rw-r--r--java/src/com/tigervnc/vncviewer/SocketFactory.java38
-rw-r--r--java/src/com/tigervnc/vncviewer/TLSTunnelBase.java86
-rw-r--r--java/src/com/tigervnc/vncviewer/UserPrefs.java258
-rw-r--r--java/src/com/tigervnc/vncviewer/VncCanvas.java1092
-rw-r--r--java/src/com/tigervnc/vncviewer/VncCanvas2.java65
-rw-r--r--java/src/com/tigervnc/vncviewer/VncViewer.java1286
-rw-r--r--java/src/com/tigervnc/vncviewer/X509Tunnel.java103
-rw-r--r--java/src/com/tigervnc/vncviewer/tigervnc.icobin0 -> 798 bytes
-rw-r--r--java/src/com/tigervnc/vncviewer/tigervnc.pngbin0 -> 3041 bytes
106 files changed, 9200 insertions, 7166 deletions
diff --git a/java/src/com/tigervnc/decoder/CoRREDecoder.java b/java/src/com/tigervnc/decoder/CoRREDecoder.java
deleted file mode 100644
index dd509253..00000000
--- a/java/src/com/tigervnc/decoder/CoRREDecoder.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.awt.Color;
-import java.io.IOException;
-
-//
-// Class that used for decoding CoRRE encoded data.
-//
-
-public class CoRREDecoder extends RawDecoder {
-
- final static int EncodingCoRRE = 4;
-
- public CoRREDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public CoRREDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method to decode CoRRE encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(CoRREDecoder.EncodingCoRRE);
- }
-
- int nSubrects = rfbis.readU32();
-
- byte[] bg_buf = new byte[bytesPerPixel];
- rfbis.readFully(bg_buf);
- Color pixel;
- if (bytesPerPixel == 1) {
- pixel = getColor256()[bg_buf[0] & 0xFF];
- } else {
- pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
- }
- graphics.setColor(pixel);
- graphics.fillRect(x, y, w, h);
-
- byte[] buf = new byte[nSubrects * (bytesPerPixel + 4)];
- rfbis.readFully(buf);
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.writeInt(nSubrects);
- dos.write(bg_buf);
- dos.write(buf);
- }
-
- int sx, sy, sw, sh;
- int i = 0;
-
- for (int j = 0; j < nSubrects; j++) {
- if (bytesPerPixel == 1) {
- pixel = getColor256()[buf[i++] & 0xFF];
- } else {
- pixel = new Color(buf[i+2] & 0xFF, buf[i+1] & 0xFF, buf[i] & 0xFF);
- i += 4;
- }
- sx = x + (buf[i++] & 0xFF);
- sy = y + (buf[i++] & 0xFF);
- sw = buf[i++] & 0xFF;
- sh = buf[i++] & 0xFF;
-
- graphics.setColor(pixel);
- graphics.fillRect(sx, sy, sw, sh);
- }
- }
-}
diff --git a/java/src/com/tigervnc/decoder/CopyRectDecoder.java b/java/src/com/tigervnc/decoder/CopyRectDecoder.java
deleted file mode 100644
index c3f1c8cb..00000000
--- a/java/src/com/tigervnc/decoder/CopyRectDecoder.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.io.IOException;
-
-//
-// Class that used for decoding CopyRect encoded data.
-//
-
-public class CopyRectDecoder extends RawDecoder {
-
- final static int EncodingCopyRect = 1;
-
- public CopyRectDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public CopyRectDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method handle CopyRect
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(CopyRectDecoder.EncodingCopyRect);
- }
-
- int copyRectSrcX = rfbis.readU16();
- int copyRectSrcY = rfbis.readU16();
-
- // If the session is being recorded:
- if (dos != null) {
- dos.writeShort(copyRectSrcX);
- dos.writeShort(copyRectSrcY);
- }
-
- graphics.copyArea(copyRectSrcX, copyRectSrcY, w, h,
- x - copyRectSrcX, y - copyRectSrcY);
- }
-}
diff --git a/java/src/com/tigervnc/decoder/HextileDecoder.java b/java/src/com/tigervnc/decoder/HextileDecoder.java
deleted file mode 100644
index 7052ff41..00000000
--- a/java/src/com/tigervnc/decoder/HextileDecoder.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.decoder.common.Repaintable;
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.awt.Color;
-import java.awt.Graphics;
-import java.io.IOException;
-
-//
-// Class that used for decoding hextile encoded data.
-//
-
-public class HextileDecoder extends RawDecoder {
-
- final static int EncodingHextile = 5;
-
- // Contstants used in the Hextile decoder
- final static int
- HextileRaw = 1,
- HextileBackgroundSpecified = 2,
- HextileForegroundSpecified = 4,
- HextileAnySubrects = 8,
- HextileSubrectsColoured = 16;
-
- public HextileDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public HextileDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Set private members methods
- //
-
- public void setRepainableControl(Repaintable r) {
- repainableControl = r;
- }
-
- //
- // Override handleRect method to decode Hextile encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException,
- Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(HextileDecoder.EncodingHextile);
- }
-
- hextile_bg = new Color(0);
- hextile_fg = new Color(0);
-
- for (int ty = y; ty < y + h; ty += 16) {
- int th = 16;
- if (y + h - ty < 16)
- th = y + h - ty;
-
- for (int tx = x; tx < x + w; tx += 16) {
- int tw = 16;
- if (x + w - tx < 16)
- tw = x + w - tx;
-
- handleHextileSubrect(tx, ty, tw, th);
- }
- if (repainableControl != null)
- repainableControl.scheduleRepaint(x, y, w, h);
- }
- if (repainableControl != null)
- repainableControl.scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle one tile in the Hextile-encoded data.
- //
-
- private void handleHextileSubrect(int tx, int ty, int tw, int th)
- throws IOException, Exception {
-
- int subencoding = rfbis.readU8();
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.writeByte((byte)subencoding);
- }
-
- // Is it a raw-encoded sub-rectangle?
- if ((subencoding & HextileRaw) != 0) {
- //
- // Disable encoding id writting to record stream
- // in super (RawDecoder) class, cause we write subencoding ID
- // in this class (see code above).
- //
-
- super.enableEncodingRecordWritting(false);
- super.handleRect(tx, ty, tw, th);
- super.handleUpdatedPixels(tx, ty, tw, th);
- super.enableEncodingRecordWritting(true);
- return;
- }
-
- // Read and draw the background if specified.
- byte[] cbuf = new byte[bytesPerPixel];
- if ((subencoding & HextileBackgroundSpecified) != 0) {
- rfbis.readFully(cbuf);
- if (bytesPerPixel == 1) {
- hextile_bg = getColor256()[cbuf[0] & 0xFF];
- } else {
- hextile_bg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
- }
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.write(cbuf);
- }
- }
- graphics.setColor(hextile_bg);
- graphics.fillRect(tx, ty, tw, th);
-
- // Read the foreground color if specified.
- if ((subencoding & HextileForegroundSpecified) != 0) {
- rfbis.readFully(cbuf);
- if (bytesPerPixel == 1) {
- hextile_fg = getColor256()[cbuf[0] & 0xFF];
- } else {
- hextile_fg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF);
- }
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.write(cbuf);
- }
- }
-
- // Done with this tile if there is no sub-rectangles.
- if ((subencoding & HextileAnySubrects) == 0)
- return;
-
- int nSubrects = rfbis.readU8();
- int bufsize = nSubrects * 2;
- if ((subencoding & HextileSubrectsColoured) != 0) {
- bufsize += nSubrects * bytesPerPixel;
- }
- byte[] buf = new byte[bufsize];
- rfbis.readFully(buf);
-
- //
- // Save decoded data to data output stream
- //
-
- if (dos != null) {
- dos.writeByte((byte)nSubrects);
- dos.write(buf);
- }
-
- int b1, b2, sx, sy, sw, sh;
- int i = 0;
-
- if ((subencoding & HextileSubrectsColoured) == 0) {
-
- // Sub-rectangles are all of the same color.
- graphics.setColor(hextile_fg);
- for (int j = 0; j < nSubrects; j++) {
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- graphics.fillRect(sx, sy, sw, sh);
- }
- } else if (bytesPerPixel == 1) {
-
- // BGR233 (8-bit color) version for colored sub-rectangles.
- for (int j = 0; j < nSubrects; j++) {
- hextile_fg = getColor256()[buf[i++] & 0xFF];
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- graphics.setColor(hextile_fg);
- graphics.fillRect(sx, sy, sw, sh);
- }
-
- } else {
-
- // Full-color (24-bit) version for colored sub-rectangles.
- for (int j = 0; j < nSubrects; j++) {
- hextile_fg = new Color(buf[i+2] & 0xFF,
- buf[i+1] & 0xFF,
- buf[i] & 0xFF);
- i += 4;
- b1 = buf[i++] & 0xFF;
- b2 = buf[i++] & 0xFF;
- sx = tx + (b1 >> 4);
- sy = ty + (b1 & 0xf);
- sw = (b2 >> 4) + 1;
- sh = (b2 & 0xf) + 1;
- graphics.setColor(hextile_fg);
- graphics.fillRect(sx, sy, sw, sh);
- }
-
- }
- }
-
- // These colors should be kept between handleHextileSubrect() calls.
- private Color hextile_bg, hextile_fg;
- // Repaitable object
- private Repaintable repainableControl = null;
-}
diff --git a/java/src/com/tigervnc/decoder/RREDecoder.java b/java/src/com/tigervnc/decoder/RREDecoder.java
deleted file mode 100644
index f6a67aec..00000000
--- a/java/src/com/tigervnc/decoder/RREDecoder.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.awt.Color;
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-
-//
-// Class that used for decoding RRE encoded data.
-//
-
-public class RREDecoder extends RawDecoder {
-
- final static int EncodingRRE = 2;
-
- public RREDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public RREDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method to decode RRE encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(RREDecoder.EncodingRRE);
- }
-
- int nSubrects = rfbis.readU32();
- byte[] bg_buf = new byte[bytesPerPixel];
- rfbis.readFully(bg_buf);
- Color pixel;
- if (bytesPerPixel == 1) {
- pixel = getColor256()[bg_buf[0] & 0xFF];
- } else {
- pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF);
- }
- graphics.setColor(pixel);
- graphics.fillRect(x, y, w, h);
- byte[] buf = new byte[nSubrects * (bytesPerPixel + 8)];
- rfbis.readFully(buf);
- DataInputStream ds = new DataInputStream(new ByteArrayInputStream(buf));
-
- //
- // Save decoded data to data output stream
- //
- if (dos != null) {
- dos.writeInt(nSubrects);
- dos.write(bg_buf);
- dos.write(buf);
- }
-
- int sx, sy, sw, sh;
- for (int j = 0; j < nSubrects; j++) {
- if (bytesPerPixel == 1) {
- pixel = getColor256()[ds.readUnsignedByte()];
- } else {
- ds.skip(4);
- pixel = new Color(buf[j*12+2] & 0xFF,
- buf[j*12+1] & 0xFF,
- buf[j*12] & 0xFF);
- }
- sx = x + ds.readUnsignedShort();
- sy = y + ds.readUnsignedShort();
- sw = ds.readUnsignedShort();
- sh = ds.readUnsignedShort();
-
- graphics.setColor(pixel);
- graphics.fillRect(sx, sy, sw, sh);
- }
- }
-}
diff --git a/java/src/com/tigervnc/decoder/RawDecoder.java b/java/src/com/tigervnc/decoder/RawDecoder.java
deleted file mode 100644
index 478a668e..00000000
--- a/java/src/com/tigervnc/decoder/RawDecoder.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.io.IOException;
-import java.io.DataOutput;
-import java.awt.Graphics;
-import java.awt.Image;
-import java.awt.image.ColorModel;
-import java.awt.image.DirectColorModel;
-import java.awt.image.MemoryImageSource;
-import java.awt.Color;
-import java.awt.Toolkit;
-
-//
-// This is base decoder class.
-// Other classes will be childs of RawDecoder.
-//
-
-public class RawDecoder {
- final static int EncodingRaw = 0;
-
- public RawDecoder(Graphics g, RfbInputStream is) {
- setGraphics(g);
- setRfbInputStream(is);
- }
-
- public RawDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- setGraphics(g);
- setRfbInputStream(is);
- setFrameBufferSize(frameBufferW, frameBufferH);
- // FIXME: cm24 created in getColorModel24.
- // Remove if no bugs
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
- }
-
- //
- // Set methods to set value of non-static protected members of class
- //
-
- public void setRfbInputStream(RfbInputStream is) {
- rfbis = is;
- }
-
- public void setGraphics(Graphics g) {
- graphics = g;
- }
-
- public void setBPP(int bpp) {
- bytesPerPixel = bpp;
- }
-
- public void setFrameBufferSize(int w, int h) {
- framebufferWidth = w;
- framebufferHeight = h;
- }
-
- //
- // FIXME: Rename this method after we don't need RecordInterface
- // in RawDecoder class to record session
- //
-
- public void setDataOutputStream(DataOutput os) {
- dos = os;
- }
-
- //
- // Decodes Raw Pixels data and draw it into graphics
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if ((dos != null) && (enableEncodingRecordWritting)) {
- dos.writeInt(RawDecoder.EncodingRaw);
- }
-
- if (bytesPerPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- if (pixels8 != null) {
- rfbis.readFully(pixels8, dy * framebufferWidth + x, w);
- }
- //
- // Save decoded data to record output stream
- //
- if (dos != null) {
- dos.write(pixels8, dy * framebufferWidth + x, w);
- }
- }
- } else {
- byte[] buf = new byte[w * 4];
- int i, offset;
- for (int dy = y; dy < y + h; dy++) {
- rfbis.readFully(buf);
- //
- // Save decoded data to record output stream
- //
- if (dos != null) {
- dos.write(buf);
- }
- offset = dy * framebufferWidth + x;
- if (pixels24 != null) {
- for (i = 0; i < w; i++) {
- pixels24[offset + i] =
- (buf[i * 4 + 2] & 0xFF) << 16 |
- (buf[i * 4 + 1] & 0xFF) << 8 |
- (buf[i * 4] & 0xFF);
- } //for
- } // if
- } // for
- } // else
- handleUpdatedPixels(x, y, w, h);
- } // void
-
- //
- // Display newly updated area of pixels.
- //
-
- protected void handleUpdatedPixels(int x, int y, int w, int h) {
- // Draw updated pixels of the off-screen image.
- pixelsSource.newPixels(x, y, w, h);
- graphics.setClip(x, y, w, h);
- graphics.drawImage(rawPixelsImage, 0, 0, null);
- graphics.setClip(0, 0, framebufferWidth, framebufferHeight);
- }
-
- //
- // Updates pixels data.
- // This method must be called when framebuffer is resized
- // or BPP is changed.
- //
-
- public void update() {
- // Images with raw pixels should be re-allocated on every change
- // of geometry or pixel format.
- int fbWidth = framebufferWidth;
- int fbHeight = framebufferHeight;
-
- if (bytesPerPixel == 1) {
- pixels24 = null;
- pixels8 = new byte[fbWidth * fbHeight];
- pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(),
- pixels8, 0, fbWidth);
- } else {
- pixels8 = null;
- pixels24 = new int[fbWidth * fbHeight];
- pixelsSource =
- new MemoryImageSource(fbWidth, fbHeight, cm24, pixels24, 0, fbWidth);
- }
- pixelsSource.setAnimated(true);
- rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
- }
-
- //
- // Private static members access methods
- //
-
- protected ColorModel getColorModel8() {
- if (cm8 == null) {
- cm8 = cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
- }
- return cm8;
- }
-
- protected ColorModel getColorModel24() {
- if (cm24 == null) {
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
- }
- return cm24;
- }
-
- protected Color[]getColor256() {
- if (color256 == null) {
- color256 = new Color[256];
- for (int i = 0; i < 256; i++)
- color256[i] = new Color(cm8.getRGB(i));
- }
- return color256;
- }
-
- //
- // This method will be used by HextileDecoder to disable
- // double writting encoding id to record stream.
- //
- // FIXME: Try to find better solution than this.
- //
-
- protected void enableEncodingRecordWritting(boolean enable) {
- enableEncodingRecordWritting = enable;
- }
-
- //
- // Unique data for every decoder (? maybe not ?)
- //
-
- protected int bytesPerPixel = 4;
- protected int framebufferWidth = 0;
- protected int framebufferHeight = 0;
- protected RfbInputStream rfbis = null;
- protected Graphics graphics = null;
- protected DataOutput dos = null;
- protected boolean enableEncodingRecordWritting = true;
-
- //
- // This data must be shared between decoders
- //
-
- protected static byte []pixels8 = null;
- protected static int []pixels24 = null;
- protected static MemoryImageSource pixelsSource = null;
- protected static Image rawPixelsImage = null;
-
- //
- // Access to this static members only though protected methods
- //
-
- private static ColorModel cm8 = null;
- private static ColorModel cm24 = null;
- private static Color []color256 = null;
-}
diff --git a/java/src/com/tigervnc/decoder/TightDecoder.java b/java/src/com/tigervnc/decoder/TightDecoder.java
deleted file mode 100644
index 4e9969c7..00000000
--- a/java/src/com/tigervnc/decoder/TightDecoder.java
+++ /dev/null
@@ -1,525 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.decoder.common.Repaintable;
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.awt.Color;
-import java.awt.Image;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.image.ImageObserver;
-import java.io.IOException;
-import java.util.zip.Deflater;
-import java.util.zip.Inflater;
-
-//
-// Class that used for decoding Tight encoded data.
-//
-
-public class TightDecoder extends RawDecoder implements ImageObserver {
-
- final static int EncodingTight = 7;
-
- //
- // Tight decoder constants
- //
-
- final static int TightExplicitFilter = 0x04;
- final static int TightFill = 0x08;
- final static int TightJpeg = 0x09;
- final static int TightMaxSubencoding = 0x09;
- final static int TightFilterCopy = 0x00;
- final static int TightFilterPalette = 0x01;
- final static int TightFilterGradient = 0x02;
- final static int TightMinToCompress = 12;
-
- // Tight encoder's data.
- final static int tightZlibBufferSize = 512;
-
- public TightDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- tightInflaters = new Inflater[4];
- }
-
- public TightDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- tightInflaters = new Inflater[4];
- }
-
- //
- // Set and get methods for private TightDecoder
- //
-
- public void setRepainableControl(Repaintable r) {
- repainatableControl = r;
- }
-
- //
- // JPEG processing statistic methods
- //
-
- public long getNumJPEGRects() {
- return statNumRectsTightJPEG;
- }
-
- public void setNumJPEGRects(int v) {
- statNumRectsTightJPEG = v;
- }
-
- //
- // Tight processing statistic methods
- //
-
- public long getNumTightRects() {
- return statNumRectsTight;
- }
-
- public void setNumTightRects(int v) {
- statNumRectsTight = v;
- }
-
- //
- // Handle a Tight-encoded rectangle.
- //
-
- public void handleRect(int x, int y, int w, int h) throws Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(TightDecoder.EncodingTight);
- }
-
- int comp_ctl = rfbis.readU8();
-
- if (dos != null) {
- // Tell the decoder to flush each of the four zlib streams.
- dos.writeByte(comp_ctl | 0x0F);
- }
-
- // Flush zlib streams if we are told by the server to do so.
- for (int stream_id = 0; stream_id < 4; stream_id++) {
- if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {
- tightInflaters[stream_id] = null;
- }
- comp_ctl >>= 1;
- }
-
- // Check correctness of subencoding value.
- if (comp_ctl > TightDecoder.TightMaxSubencoding) {
- throw new Exception("Incorrect tight subencoding: " + comp_ctl);
- }
-
- // Handle solid-color rectangles.
- if (comp_ctl == TightDecoder.TightFill) {
-
- if (bytesPerPixel == 1) {
- int idx = rfbis.readU8();
- graphics.setColor(getColor256()[idx]);
- if (dos != null) {
- dos.writeByte(idx);
- }
- } else {
- byte[] buf = new byte[3];
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- Color bg = new Color(0xFF000000 | (buf[0] & 0xFF) << 16 |
- (buf[1] & 0xFF) << 8 | (buf[2] & 0xFF));
- graphics.setColor(bg);
- }
- graphics.fillRect(x, y, w, h);
- repainatableControl.scheduleRepaint(x, y, w, h);
- return;
-
- }
-
- if (comp_ctl == TightDecoder.TightJpeg) {
-
- statNumRectsTightJPEG++;
-
- // Read JPEG data.
- byte[] jpegData = new byte[rfbis.readCompactLen()];
- rfbis.readFully(jpegData);
- if (dos != null) {
- recordCompactLen(jpegData.length);
- dos.write(jpegData);
- }
-
- // Create an Image object from the JPEG data.
- Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData);
-
- // Remember the rectangle where the image should be drawn.
- jpegRect = new Rectangle(x, y, w, h);
-
- // Let the imageUpdate() method do the actual drawing, here just
- // wait until the image is fully loaded and drawn.
- synchronized(jpegRect) {
- Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this);
- try {
- // Wait no longer than three seconds.
- jpegRect.wait(3000);
- } catch (InterruptedException e) {
- throw new Exception("Interrupted while decoding JPEG image");
- }
- }
-
- // Done, jpegRect is not needed any more.
- jpegRect = null;
- return;
-
- } else {
- statNumRectsTight++;
- }
-
- // Read filter id and parameters.
- int numColors = 0, rowSize = w;
- byte[] palette8 = new byte[2];
- int[] palette24 = new int[256];
- boolean useGradient = false;
- if ((comp_ctl & TightDecoder.TightExplicitFilter) != 0) {
- int filter_id = rfbis.readU8();
- if (dos != null) {
- dos.writeByte(filter_id);
- }
- if (filter_id == TightDecoder.TightFilterPalette) {
- numColors = rfbis.readU8() + 1;
- if (dos != null) {
- dos.writeByte((numColors - 1));
- }
- if (bytesPerPixel == 1) {
- if (numColors != 2) {
- throw new Exception("Incorrect tight palette size: " + numColors);
- }
- rfbis.readFully(palette8);
- if (dos != null) {
- dos.write(palette8);
- }
- } else {
- byte[] buf = new byte[numColors * 3];
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- for (int i = 0; i < numColors; i++) {
- palette24[i] = ((buf[i * 3] & 0xFF) << 16 |
- (buf[i * 3 + 1] & 0xFF) << 8 |
- (buf[i * 3 + 2] & 0xFF));
- }
- }
- if (numColors == 2) {
- rowSize = (w + 7) / 8;
- }
- } else if (filter_id == TightDecoder.TightFilterGradient) {
- useGradient = true;
- } else if (filter_id != TightDecoder.TightFilterCopy) {
- throw new Exception("Incorrect tight filter id: " + filter_id);
- }
- }
- if (numColors == 0 && bytesPerPixel == 4)
- rowSize *= 3;
-
- // Read, optionally uncompress and decode data.
- int dataSize = h * rowSize;
- if (dataSize < TightDecoder.TightMinToCompress) {
- // Data size is small - not compressed with zlib.
- if (numColors != 0) {
- // Indexed colors.
- byte[] indexedData = new byte[dataSize];
- rfbis.readFully(indexedData);
- if (dos != null) {
- dos.write(indexedData);
- }
- if (numColors == 2) {
- // Two colors.
- if (bytesPerPixel == 1) {
- decodeMonoData(x, y, w, h, indexedData, palette8);
- } else {
- decodeMonoData(x, y, w, h, indexedData, palette24);
- }
- } else {
- // 3..255 colors (assuming bytesPixel == 4).
- int i = 0;
- for (int dy = y; dy < y + h; dy++) {
- for (int dx = x; dx < x + w; dx++) {
- pixels24[dy * framebufferWidth + dx] =
- palette24[indexedData[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // "Gradient"-processed data
- byte[] buf = new byte[w * h * 3];
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- decodeGradientData(x, y, w, h, buf);
- } else {
- // Raw truecolor data.
- if (bytesPerPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- rfbis.readFully(pixels8, dy * framebufferWidth + x, w);
- if (dos != null) {
- dos.write(pixels8, dy * framebufferWidth + x, w);
- }
- }
- } else {
- byte[] buf = new byte[w * 3];
- int i, offset;
- for (int dy = y; dy < y + h; dy++) {
- rfbis.readFully(buf);
- if (dos != null) {
- dos.write(buf);
- }
- offset = dy * framebufferWidth + x;
- for (i = 0; i < w; i++) {
- pixels24[offset + i] =
- (buf[i * 3] & 0xFF) << 16 |
- (buf[i * 3 + 1] & 0xFF) << 8 |
- (buf[i * 3 + 2] & 0xFF);
- }
- }
- }
- }
- } else {
- // Data was compressed with zlib.
- int zlibDataLen = rfbis.readCompactLen();
- byte[] zlibData = new byte[zlibDataLen];
- rfbis.readFully(zlibData);
- int stream_id = comp_ctl & 0x03;
- if (tightInflaters[stream_id] == null) {
- tightInflaters[stream_id] = new Inflater();
- }
- Inflater myInflater = tightInflaters[stream_id];
- myInflater.setInput(zlibData);
- byte[] buf = new byte[dataSize];
- myInflater.inflate(buf);
- if (dos != null) {
- recordCompressedData(buf);
- }
-
- if (numColors != 0) {
- // Indexed colors.
- if (numColors == 2) {
- // Two colors.
- if (bytesPerPixel == 1) {
- decodeMonoData(x, y, w, h, buf, palette8);
- } else {
- decodeMonoData(x, y, w, h, buf, palette24);
- }
- } else {
- // More than two colors (assuming bytesPixel == 4).
- int i = 0;
- for (int dy = y; dy < y + h; dy++) {
- for (int dx = x; dx < x + w; dx++) {
- pixels24[dy * framebufferWidth + dx] =
- palette24[buf[i++] & 0xFF];
- }
- }
- }
- } else if (useGradient) {
- // Compressed "Gradient"-filtered data (assuming bytesPixel == 4).
- decodeGradientData(x, y, w, h, buf);
- } else {
- // Compressed truecolor data.
- if (bytesPerPixel == 1) {
- int destOffset = y * framebufferWidth + x;
- for (int dy = 0; dy < h; dy++) {
- System.arraycopy(buf, dy * w, pixels8, destOffset, w);
- destOffset += framebufferWidth;
- }
- } else {
- int srcOffset = 0;
- int destOffset, i;
- for (int dy = 0; dy < h; dy++) {
- myInflater.inflate(buf);
- destOffset = (y + dy) * framebufferWidth + x;
- for (i = 0; i < w; i++) {
- RawDecoder.pixels24[destOffset + i] =
- (buf[srcOffset] & 0xFF) << 16 |
- (buf[srcOffset + 1] & 0xFF) << 8 |
- (buf[srcOffset + 2] & 0xFF);
- srcOffset += 3;
- }
- }
- }
- }
- }
- handleUpdatedPixels(x, y, w, h);
- }
-
- //
- // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions).
- //
-
- private void decodeMonoData(int x, int y, int w, int h, byte[] src, byte[] palette) {
-
- int dx, dy, n;
- int i = y * framebufferWidth + x;
- int rowBytes = (w + 7) / 8;
- byte b;
-
- for (dy = 0; dy < h; dy++) {
- for (dx = 0; dx < w / 8; dx++) {
- b = src[dy*rowBytes+dx];
- for (n = 7; n >= 0; n--)
- pixels8[i++] = palette[b >> n & 1];
- }
- for (n = 7; n >= 8 - w % 8; n--) {
- pixels8[i++] = palette[src[dy*rowBytes+dx] >> n & 1];
- }
- i += (framebufferWidth - w);
- }
- }
-
- private void decodeMonoData(int x, int y, int w, int h, byte[] src, int[] palette) {
-
- int dx, dy, n;
- int i = y * framebufferWidth + x;
- int rowBytes = (w + 7) / 8;
- byte b;
-
- for (dy = 0; dy < h; dy++) {
- for (dx = 0; dx < w / 8; dx++) {
- b = src[dy*rowBytes+dx];
- for (n = 7; n >= 0; n--)
- pixels24[i++] = palette[b >> n & 1];
- }
- for (n = 7; n >= 8 - w % 8; n--) {
- pixels24[i++] = palette[src[dy*rowBytes+dx] >> n & 1];
- }
- i += (framebufferWidth - w);
- }
- }
-
- //
- // Decode data processed with the "Gradient" filter.
- //
-
- private void decodeGradientData (int x, int y, int w, int h, byte[] buf) {
-
- int dx, dy, c;
- byte[] prevRow = new byte[w * 3];
- byte[] thisRow = new byte[w * 3];
- byte[] pix = new byte[3];
- int[] est = new int[3];
-
- int offset = y * framebufferWidth + x;
-
- for (dy = 0; dy < h; dy++) {
-
- /* First pixel in a row */
- for (c = 0; c < 3; c++) {
- pix[c] = (byte)(prevRow[c] + buf[dy * w * 3 + c]);
- thisRow[c] = pix[c];
- }
- pixels24[offset++] =
- (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
-
- /* Remaining pixels of a row */
- for (dx = 1; dx < w; dx++) {
- for (c = 0; c < 3; c++) {
- est[c] = ((prevRow[dx * 3 + c] & 0xFF) + (pix[c] & 0xFF) -
- (prevRow[(dx-1) * 3 + c] & 0xFF));
- if (est[c] > 0xFF) {
- est[c] = 0xFF;
- } else if (est[c] < 0x00) {
- est[c] = 0x00;
- }
- pix[c] = (byte)(est[c] + buf[(dy * w + dx) * 3 + c]);
- thisRow[dx * 3 + c] = pix[c];
- }
- pixels24[offset++] =
- (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF);
- }
-
- System.arraycopy(thisRow, 0, prevRow, 0, w * 3);
- offset += (framebufferWidth - w);
- }
- }
-
- //
- // Override the ImageObserver interface method to handle drawing of
- // JPEG-encoded data.
- //
-
- public boolean imageUpdate(Image img, int infoflags,
- int x, int y, int width, int height) {
- if ((infoflags & (ALLBITS | ABORT)) == 0) {
- return true; // We need more image data.
- } else {
- // If the whole image is available, draw it now.
- if ((infoflags & ALLBITS) != 0) {
- if (jpegRect != null) {
- synchronized(jpegRect) {
- graphics.drawImage(img, jpegRect.x, jpegRect.y, null);
- repainatableControl.scheduleRepaint(jpegRect.x, jpegRect.y,
- jpegRect.width, jpegRect.height);
- jpegRect.notify();
- }
- }
- }
- return false; // All image data was processed.
- }
- }
-
- //
- // Write an integer in compact representation (1..3 bytes) into the
- // recorded session file.
- //
-
- void recordCompactLen(int len) throws IOException {
- byte[] buf = new byte[3];
- int bytes = 0;
- buf[bytes++] = (byte)(len & 0x7F);
- if (len > 0x7F) {
- buf[bytes-1] |= 0x80;
- buf[bytes++] = (byte)(len >> 7 & 0x7F);
- if (len > 0x3FFF) {
- buf[bytes-1] |= 0x80;
- buf[bytes++] = (byte)(len >> 14 & 0xFF);
- }
- }
- if (dos != null) dos.write(buf, 0, bytes);
- }
-
- //
- // Compress and write the data into the recorded session file.
- //
-
- void recordCompressedData(byte[] data, int off, int len) throws IOException {
- Deflater deflater = new Deflater();
- deflater.setInput(data, off, len);
- int bufSize = len + len / 100 + 12;
- byte[] buf = new byte[bufSize];
- deflater.finish();
- int compressedSize = deflater.deflate(buf);
- recordCompactLen(compressedSize);
- if (dos != null) dos.write(buf, 0, compressedSize);
- }
-
- void recordCompressedData(byte[] data) throws IOException {
- recordCompressedData(data, 0, data.length);
- }
-
- //
- // Private members
- //
-
- private Inflater[] tightInflaters;
- // Since JPEG images are loaded asynchronously, we have to remember
- // their position in the framebuffer. Also, this jpegRect object is
- // used for synchronization between the rfbThread and a JVM's thread
- // which decodes and loads JPEG images.
- private Rectangle jpegRect;
- private Repaintable repainatableControl = null;
- // Jpeg decoding statistics
- private long statNumRectsTightJPEG = 0;
- // Tight decoding statistics
- private long statNumRectsTight = 0;
-}
diff --git a/java/src/com/tigervnc/decoder/ZRLEDecoder.java b/java/src/com/tigervnc/decoder/ZRLEDecoder.java
deleted file mode 100644
index 91a9f9de..00000000
--- a/java/src/com/tigervnc/decoder/ZRLEDecoder.java
+++ /dev/null
@@ -1,310 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.vncviewer.InStream;
-import com.tigervnc.vncviewer.RfbInputStream;
-import com.tigervnc.vncviewer.ZlibInStream;
-import java.awt.Graphics;
-import com.tigervnc.vncviewer.MemInStream;
-import java.awt.Color;
-import java.awt.Toolkit;
-import java.awt.image.MemoryImageSource;
-import java.io.IOException;
-
-//
-// Class that used for decoding ZRLE encoded data.
-//
-
-public class ZRLEDecoder extends RawDecoder {
-
- final static int EncodingZRLE = 16;
-
- public ZRLEDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public ZRLEDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Handle a ZRLE-encoded rectangle.
- //
- // FIXME: Currently, session recording is not fully supported for ZRLE.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
-
- //
- // Write encoding ID to record output stream
- //
-
- if (dos != null) {
- dos.writeInt(ZRLEDecoder.EncodingZRLE);
- }
-
- if (zrleInStream == null)
- zrleInStream = new ZlibInStream();
-
- int nBytes = rfbis.readU32();
- if (nBytes > 64 * 1024 * 1024)
- throw new Exception("ZRLE decoder: illegal compressed data size");
-
- if (zrleBuf == null || zrleBufLen < nBytes) {
- zrleBufLen = nBytes + 4096;
- zrleBuf = new byte[zrleBufLen];
- }
-
- // FIXME: Do not wait for all the data before decompression.
- rfbis.readFully(zrleBuf, 0, nBytes);
-
- //
- // Override handleRect method to decode RRE encoded data insted of
- // raw pixel data.
- //
-
- if (dos != null) {
- if (!zrleRecWarningShown) {
- System.out.println("Warning: ZRLE session can be recorded" +
- " only from the beginning");
- System.out.println("Warning: Recorded file may be corrupted");
- zrleRecWarningShown = true;
- }
- }
-
- zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes);
-
- for (int ty = y; ty < y+h; ty += 64) {
-
- int th = Math.min(y+h-ty, 64);
-
- for (int tx = x; tx < x+w; tx += 64) {
-
- int tw = Math.min(x+w-tx, 64);
-
- int mode = zrleInStream.readU8();
- boolean rle = (mode & 128) != 0;
- int palSize = mode & 127;
- int[] palette = new int[128];
-
- readZrlePalette(palette, palSize);
-
- if (palSize == 1) {
- int pix = palette[0];
- Color c = (bytesPerPixel == 1) ?
- getColor256()[pix] : new Color(0xFF000000 | pix);
- graphics.setColor(c);
- graphics.fillRect(tx, ty, tw, th);
- continue;
- }
-
- if (!rle) {
- if (palSize == 0) {
- readZrleRawPixels(tw, th);
- } else {
- readZrlePackedPixels(tw, th, palette, palSize);
- }
- } else {
- if (palSize == 0) {
- readZrlePlainRLEPixels(tw, th);
- } else {
- readZrlePackedRLEPixels(tw, th, palette);
- }
- }
- handleUpdatedZrleTile(tx, ty, tw, th);
- }
- }
- zrleInStream.reset();
- }
-
- //
- // Override update() method cause we have own data that
- // must be updated when framebuffer is resized or BPP is changed
- //
-
- public void update() {
- // Images with raw pixels should be re-allocated on every change
- // of geometry or pixel format.
- int fbWidth = framebufferWidth;
- int fbHeight = framebufferHeight;
-
- if (bytesPerPixel == 1) {
- RawDecoder.pixels24 = null;
- RawDecoder.pixels8 = new byte[fbWidth * fbHeight];
- RawDecoder.pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(), pixels8, 0, fbWidth);
- zrleTilePixels24 = null;
- zrleTilePixels8 = new byte[64 * 64];
- } else {
- RawDecoder.pixels8 = null;
- RawDecoder.pixels24 = new int[fbWidth * fbHeight];
- RawDecoder.pixelsSource =
- new MemoryImageSource(fbWidth, fbHeight, getColorModel24(), pixels24, 0, fbWidth);
- zrleTilePixels8 = null;
- zrleTilePixels24 = new int[64 * 64];
- }
- RawDecoder.pixelsSource.setAnimated(true);
- RawDecoder.rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
- }
-
- //
- // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update.
- //
-
- private void handleUpdatedZrleTile(int x, int y, int w, int h) {
- Object src, dst;
- if (bytesPerPixel == 1) {
- src = zrleTilePixels8; dst = pixels8;
- } else {
- src = zrleTilePixels24; dst = pixels24;
- }
- int offsetSrc = 0;
- int offsetDst = (y * framebufferWidth + x);
- for (int j = 0; j < h; j++) {
- System.arraycopy(src, offsetSrc, dst, offsetDst, w);
- offsetSrc += w;
- offsetDst += framebufferWidth;
- }
- handleUpdatedPixels(x, y, w, h);
- }
-
- //
- // Private methods for reading ZRLE data
- //
-
- private int readPixel(InStream is) throws Exception {
- int pix;
- if (bytesPerPixel == 1) {
- pix = is.readU8();
- } else {
- int p1 = is.readU8();
- int p2 = is.readU8();
- int p3 = is.readU8();
- pix = (p3 & 0xFF) << 16 | (p2 & 0xFF) << 8 | (p1 & 0xFF);
- }
- return pix;
- }
-
- private void readPixels(InStream is, int[] dst, int count) throws Exception {
- if (bytesPerPixel == 1) {
- byte[] buf = new byte[count];
- is.readBytes(buf, 0, count);
- for (int i = 0; i < count; i++) {
- dst[i] = (int)buf[i] & 0xFF;
- }
- } else {
- byte[] buf = new byte[count * 3];
- is.readBytes(buf, 0, count * 3);
- for (int i = 0; i < count; i++) {
- dst[i] = ((buf[i*3+2] & 0xFF) << 16 |
- (buf[i*3+1] & 0xFF) << 8 |
- (buf[i*3] & 0xFF));
- }
- }
- }
-
- private void readZrlePalette(int[] palette, int palSize) throws Exception {
- readPixels(zrleInStream, palette, palSize);
- }
-
- private void readZrleRawPixels(int tw, int th) throws Exception {
- if (bytesPerPixel == 1) {
- zrleInStream.readBytes(zrleTilePixels8, 0, tw * th);
- } else {
- readPixels(zrleInStream, zrleTilePixels24, tw * th); ///
- }
- }
-
- private void readZrlePackedPixels(int tw, int th, int[] palette, int palSize)
- throws Exception {
-
- int bppp = ((palSize > 16) ? 8 :
- ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
- int ptr = 0;
-
- for (int i = 0; i < th; i++) {
- int eol = ptr + tw;
- int b = 0;
- int nbits = 0;
-
- while (ptr < eol) {
- if (nbits == 0) {
- b = zrleInStream.readU8();
- nbits = 8;
- }
- nbits -= bppp;
- int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
- if (bytesPerPixel == 1) {
- zrleTilePixels8[ptr++] = (byte)palette[index];
- } else {
- zrleTilePixels24[ptr++] = palette[index];
- }
- }
- }
- }
-
- private void readZrlePlainRLEPixels(int tw, int th) throws Exception {
- int ptr = 0;
- int end = ptr + tw * th;
- while (ptr < end) {
- int pix = readPixel(zrleInStream);
- int len = 1;
- int b;
- do {
- b = zrleInStream.readU8();
- len += b;
- } while (b == 255);
-
- if (!(len <= end - ptr))
- throw new Exception("ZRLE decoder: assertion failed" +
- " (len <= end-ptr)");
-
- if (bytesPerPixel == 1) {
- while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
- } else {
- while (len-- > 0) zrleTilePixels24[ptr++] = pix;
- }
- }
- }
-
- private void readZrlePackedRLEPixels(int tw, int th, int[] palette)
- throws Exception {
-
- int ptr = 0;
- int end = ptr + tw * th;
- while (ptr < end) {
- int index = zrleInStream.readU8();
- int len = 1;
- if ((index & 128) != 0) {
- int b;
- do {
- b = zrleInStream.readU8();
- len += b;
- } while (b == 255);
-
- if (!(len <= end - ptr))
- throw new Exception("ZRLE decoder: assertion failed" +
- " (len <= end - ptr)");
- }
-
- index &= 127;
- int pix = palette[index];
-
- if (bytesPerPixel == 1) {
- while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
- } else {
- while (len-- > 0) zrleTilePixels24[ptr++] = pix;
- }
- }
- }
-
- //
- // ZRLE encoder's data.
- //
-
- private byte[] zrleBuf;
- private int zrleBufLen = 0;
- private byte[] zrleTilePixels8;
- private int[] zrleTilePixels24;
- private ZlibInStream zrleInStream;
- private boolean zrleRecWarningShown = false;
-}
diff --git a/java/src/com/tigervnc/decoder/ZlibDecoder.java b/java/src/com/tigervnc/decoder/ZlibDecoder.java
deleted file mode 100644
index 0eeaef5f..00000000
--- a/java/src/com/tigervnc/decoder/ZlibDecoder.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package com.tigervnc.decoder;
-
-import com.tigervnc.vncviewer.RfbInputStream;
-import java.awt.Graphics;
-import java.io.IOException;
-import java.util.zip.DataFormatException;
-import java.util.zip.Inflater;
-
-//
-// Class that used for decoding ZLib encoded data.
-//
-
-public class ZlibDecoder extends RawDecoder {
-
- final static int EncodingZlib = 6;
-
- public ZlibDecoder(Graphics g, RfbInputStream is) {
- super(g, is);
- }
-
- public ZlibDecoder(Graphics g, RfbInputStream is, int frameBufferW,
- int frameBufferH) {
- super(g, is, frameBufferW, frameBufferH);
- }
-
- //
- // Override handleRect method to decode ZLib encoded data insted of
- // raw pixel data.
- //
-
- public void handleRect(int x, int y, int w, int h) throws IOException {
-
- //
- // Write encoding ID to record output stream.
- // Remark: we forced changed encoding from zlib to raw
- // cause at this moment we cannot save data in zlib encoding.
- //
-
- if (dos != null) {
- dos.writeInt(RawDecoder.EncodingRaw);
- }
-
- int nBytes = rfbis.readU32();
-
- if (zlibBuf == null || zlibBufLen < nBytes) {
- zlibBufLen = nBytes * 2;
- zlibBuf = new byte[zlibBufLen];
- }
-
- rfbis.readFully(zlibBuf, 0, nBytes);
-
- if (zlibInflater == null) {
- zlibInflater = new Inflater();
- }
- zlibInflater.setInput(zlibBuf, 0, nBytes);
-
- try {
- if (bytesPerPixel == 1) {
- for (int dy = y; dy < y + h; dy++) {
- zlibInflater.inflate(pixels8, dy * framebufferWidth + x, w);
-
- //
- // Save decoded raw data to data output stream
- //
-
- if (dos != null)
- dos.write(pixels8, dy * framebufferWidth + x, w);
- }
- } else {
- byte[] buf = new byte[w * 4];
- int i, offset;
- for (int dy = y; dy < y + h; dy++) {
- zlibInflater.inflate(buf);
- offset = dy * framebufferWidth + x;
- for (i = 0; i < w; i++) {
- RawDecoder.pixels24[offset + i] =
- (buf[i * 4 + 2] & 0xFF) << 16 |
- (buf[i * 4 + 1] & 0xFF) << 8 |
- (buf[i * 4] & 0xFF);
- }
-
- //
- // Save decoded raw data to data output stream
- //
-
- if (dos != null)
- dos.write(buf);
- }
- }
- } catch (DataFormatException ex) {
- ex.printStackTrace();
- }
- handleUpdatedPixels(x, y, w, h);
- }
-
- //
- // Zlib encoder's data.
- //
-
- protected byte[] zlibBuf;
- protected int zlibBufLen = 0;
- protected Inflater zlibInflater;
-}
diff --git a/java/src/com/tigervnc/decoder/common/Repaintable.java b/java/src/com/tigervnc/decoder/common/Repaintable.java
deleted file mode 100644
index 896f09fe..00000000
--- a/java/src/com/tigervnc/decoder/common/Repaintable.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.tigervnc.decoder.common;
-
-public interface Repaintable {
-
- public void scheduleRepaint(int x, int y, int w, int h);
-
-}
diff --git a/java/src/com/tigervnc/rdr/EndOfStream.java b/java/src/com/tigervnc/rdr/EndOfStream.java
new file mode 100644
index 00000000..bdcf7c27
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/EndOfStream.java
@@ -0,0 +1,25 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rdr;
+
+public class EndOfStream extends Exception {
+ public EndOfStream() {
+ super("EndOfStream");
+ }
+}
diff --git a/java/src/com/tigervnc/rdr/Exception.java b/java/src/com/tigervnc/rdr/Exception.java
new file mode 100644
index 00000000..a5fe938d
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/Exception.java
@@ -0,0 +1,25 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rdr;
+
+public class Exception extends RuntimeException {
+ public Exception(String s) {
+ super(s);
+ }
+}
diff --git a/java/src/com/tigervnc/rdr/IOException.java b/java/src/com/tigervnc/rdr/IOException.java
new file mode 100644
index 00000000..6343d7a4
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/IOException.java
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rdr;
+
+class IOException extends Exception {
+ public IOException(java.io.IOException ex_) {
+ super(ex_.toString());
+ ex = ex_;
+ }
+ java.io.IOException ex;
+}
diff --git a/java/src/com/tigervnc/vncviewer/InStream.java b/java/src/com/tigervnc/rdr/InStream.java
index 75ff91aa..ec2d6d7c 100644
--- a/java/src/com/tigervnc/vncviewer/InStream.java
+++ b/java/src/com/tigervnc/rdr/InStream.java
@@ -21,7 +21,7 @@
// Representation).
//
-package com.tigervnc.vncviewer;
+package com.tigervnc.rdr;
abstract public class InStream {
@@ -29,7 +29,7 @@ abstract public class InStream {
// itemSize bytes. Returns the number of items in the buffer (up to a
// maximum of nItems).
- public final int check(int itemSize, int nItems) throws Exception {
+ public int check(int itemSize, int nItems) {
if (ptr + itemSize * nItems > end) {
if (ptr + itemSize > end)
return overrun(itemSize, nItems);
@@ -39,45 +39,36 @@ abstract public class InStream {
return nItems;
}
- public final void check(int itemSize) throws Exception {
+ public final int check(int itemSize) {
if (ptr + itemSize > end)
- overrun(itemSize, 1);
+ return overrun(itemSize, 1);
+ return 1;
}
- // readU/SN() methods read unsigned and signed N-bit integers.
-
- public final int readS8() throws Exception {
- check(1); return b[ptr++];
- }
+ // checkNoWait() tries to make sure that the given number of bytes can
+ // be read without blocking. It returns true if this is the case, false
+ // otherwise. The length must be "small" (less than the buffer size).
- public final int readS16() throws Exception {
- check(2); int b0 = b[ptr++];
- int b1 = b[ptr++] & 0xff; return b0 << 8 | b1;
- }
+ public final boolean checkNoWait(int length) { return check(length, 1)!=0; }
- public final int readS32() throws Exception {
- check(4); int b0 = b[ptr++];
- int b1 = b[ptr++] & 0xff;
- int b2 = b[ptr++] & 0xff;
- int b3 = b[ptr++] & 0xff;
- return b0 << 24 | b1 << 16 | b2 << 8 | b3;
- }
-
- public final int readU8() throws Exception {
- return readS8() & 0xff;
- }
+ // readU/SN() methods read unsigned and signed N-bit integers.
- public final int readU16() throws Exception {
- return readS16() & 0xffff;
- }
+ public final int readS8() { check(1); return b[ptr++]; }
+ public final int readS16() { check(2); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff; return b0 << 8 | b1; }
+ public final int readS32() { check(4); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff;
+ int b2 = b[ptr++] & 0xff;
+ int b3 = b[ptr++] & 0xff;
+ return b0 << 24 | b1 << 16 | b2 << 8 | b3; }
- public final int readU32() throws Exception {
- return readS32() & 0xffffffff;
- }
+ public final int readU8() { return readS8() & 0xff; }
+ public final int readU16() { return readS16() & 0xffff; }
+ public final int readU32() { return readS32() & 0xffffffff; }
// readString() reads a string - a U32 length followed by the data.
- public final String readString() throws Exception {
+ public final String readString() {
int len = readU32();
if (len > maxStringLength)
throw new Exception("InStream max string length exceeded");
@@ -99,7 +90,7 @@ abstract public class InStream {
public static int maxStringLength = 65535;
- public final void skip(int bytes) throws Exception {
+ public final void skip(int bytes) {
while (bytes > 0) {
int n = check(1, bytes);
ptr += n;
@@ -109,7 +100,7 @@ abstract public class InStream {
// readBytes() reads an exact number of bytes into an array at an offset.
- public void readBytes(byte[] data, int offset, int length) throws Exception {
+ public void readBytes(byte[] data, int offset, int length) {
int offsetEnd = offset + length;
while (offset < offsetEnd) {
int n = check(1, offsetEnd - offset);
@@ -119,33 +110,59 @@ abstract public class InStream {
}
}
- // readOpaqueN() reads a quantity "without byte-swapping". Because java has
- // no byte-ordering, we just use big-endian.
-
- public final int readOpaque8() throws Exception {
- return readU8();
+ public void readBytes(int[] data, int offset, int length) {
+ int offsetEnd = offset + length;
+ while (offset < offsetEnd) {
+ int n = check(1, offsetEnd - offset);
+ System.arraycopy(b, ptr, data, offset, n);
+ ptr += n;
+ offset += n;
+ }
}
- public final int readOpaque16() throws Exception {
- return readU16();
- }
+ // readOpaqueN() reads a quantity "without byte-swapping". Because java has
+ // no byte-ordering, we just use big-endian.
- public final int readOpaque32() throws Exception {
- return readU32();
+ public final int readOpaque8() { return readU8(); }
+ public final int readOpaque16() { return readU16(); }
+ public final int readOpaque32() { return readU32(); }
+ public final int readOpaque24A() { check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 24 | b1 << 16 | b2 << 8; }
+ public final int readOpaque24B() { check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 16 | b1 << 8 | b2; }
+
+ public final int readPixel(int bytesPerPixel, boolean e) {
+ int[] pix = new int[4];
+ for (int i=0; i < bytesPerPixel; i++)
+ pix[i] = readU8();
+ if (e) {
+ return pix[0] << 16 | pix[1] << 8 | pix[2] | (0xff << 24);
+ } else {
+ return pix[2] << 16 | pix[1] << 8 | pix[0] | (0xff << 24);
+ }
}
- public final int readOpaque24A() throws Exception {
- check(3); int b0 = b[ptr++];
- int b1 = b[ptr++]; int b2 = b[ptr++];
- return b0 << 24 | b1 << 16 | b2 << 8;
+ public final void readPixels(int[] buf, int length, int bytesPerPixel, boolean e) {
+ for (int i = 0; i < length; i++)
+ buf[i] = readPixel(bytesPerPixel, e);
}
- public final int readOpaque24B() throws Exception {
- check(3); int b0 = b[ptr++];
- int b1 = b[ptr++]; int b2 = b[ptr++];
- return b0 << 16 | b1 << 8 | b2;
+ public final int readCompactLength() {
+ int b = readU8();
+ int result = b & 0x7F;
+ if ((b & 0x80) != 0) {
+ b = readU8();
+ result |= (b & 0x7F) << 7;
+ if ((b & 0x80) != 0) {
+ b = readU8();
+ result |= (b & 0xFF) << 14;
+ }
+ }
+ return result;
}
-
+
// pos() returns the position in the stream.
abstract public int pos();
@@ -170,7 +187,7 @@ abstract public class InStream {
// the number of items in the buffer (up to a maximum of nItems). itemSize
// is supposed to be "small" (a few bytes).
- abstract protected int overrun(int itemSize, int nItems) throws Exception;
+ abstract protected int overrun(int itemSize, int nItems);
protected InStream() {}
protected byte[] b;
diff --git a/java/src/com/tigervnc/rdr/JavaInStream.java b/java/src/com/tigervnc/rdr/JavaInStream.java
new file mode 100644
index 00000000..426a0e76
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/JavaInStream.java
@@ -0,0 +1,147 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// A JavaInStream reads from a java.io.InputStream
+//
+
+package com.tigervnc.rdr;
+
+public class JavaInStream extends InStream {
+
+ static final int defaultBufSize = 8192;
+ static final int minBulkSize = 1024;
+
+ public JavaInStream(java.io.InputStream jis_, int bufSize_) {
+ jis = jis_;
+ bufSize = bufSize_;
+ b = new byte[bufSize];
+ ptr = end = ptrOffset = 0;
+ timeWaitedIn100us = 5;
+ timedKbits = 0;
+ }
+
+ public JavaInStream(java.io.InputStream jis_) { this(jis_, defaultBufSize); }
+
+ public void readBytes(byte[] data, int offset, int length) {
+ if (length < minBulkSize) {
+ super.readBytes(data, offset, length);
+ return;
+ }
+
+ int n = end - ptr;
+ if (n > length) n = length;
+
+ System.arraycopy(b, ptr, data, offset, n);
+ offset += n;
+ length -= n;
+ ptr += n;
+
+ while (length > 0) {
+ n = read(data, offset, length);
+ offset += n;
+ length -= n;
+ ptrOffset += n;
+ }
+ }
+
+ public int pos() { return ptrOffset + ptr; }
+
+ public void startTiming() {
+ timing = true;
+
+ // Carry over up to 1s worth of previous rate for smoothing.
+
+ if (timeWaitedIn100us > 10000) {
+ timedKbits = timedKbits * 10000 / timeWaitedIn100us;
+ timeWaitedIn100us = 10000;
+ }
+ }
+
+ public void stopTiming() {
+ timing = false;
+ if (timeWaitedIn100us < timedKbits/2)
+ timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
+ }
+
+ public long kbitsPerSecond() {
+ return timedKbits * 10000 / timeWaitedIn100us;
+ }
+
+ public long timeWaited() { return timeWaitedIn100us; }
+
+ protected int overrun(int itemSize, int nItems) {
+ if (itemSize > bufSize)
+ throw new Exception("JavaInStream overrun: max itemSize exceeded");
+
+ if (end - ptr != 0)
+ System.arraycopy(b, ptr, b, 0, end - ptr);
+
+ ptrOffset += ptr;
+ end -= ptr;
+ ptr = 0;
+
+ while (end < itemSize) {
+ int n = read(b, end, bufSize - end);
+ end += n;
+ }
+
+ if (itemSize * nItems > end)
+ nItems = end / itemSize;
+
+ return nItems;
+ }
+
+ private int read(byte[] buf, int offset, int len) {
+ try {
+ long before = 0;
+ if (timing)
+ before = System.currentTimeMillis();
+
+ int n = jis.read(buf, offset, len);
+ if (n < 0) throw new EndOfStream();
+
+ if (timing) {
+ long after = System.currentTimeMillis();
+ long newTimeWaited = (after - before) * 10;
+ int newKbits = n * 8 / 1000;
+
+ // limit rate to between 10kbit/s and 40Mbit/s
+
+ if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
+ if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
+
+ timeWaitedIn100us += newTimeWaited;
+ timedKbits += newKbits;
+ }
+
+ return n;
+
+ } catch (java.io.IOException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private java.io.InputStream jis;
+ private int ptrOffset;
+ private int bufSize;
+
+ boolean timing;
+ long timeWaitedIn100us;
+ long timedKbits;
+}
diff --git a/java/src/com/tigervnc/rdr/JavaOutStream.java b/java/src/com/tigervnc/rdr/JavaOutStream.java
new file mode 100644
index 00000000..94791b9d
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/JavaOutStream.java
@@ -0,0 +1,82 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// A JavaOutStream writes to a java.io.OutputStream
+//
+
+package com.tigervnc.rdr;
+
+public class JavaOutStream extends OutStream {
+
+ static final int defaultBufSize = 16384;
+ static final int minBulkSize = 1024;
+
+ public JavaOutStream(java.io.OutputStream jos_, int bufSize_) {
+ jos = jos_;
+ bufSize = bufSize_;
+ b = new byte[bufSize];
+ ptr = 0;
+ end = bufSize;
+ }
+
+ public JavaOutStream(java.io.OutputStream jos) { this(jos, defaultBufSize); }
+
+ public void writeBytes(byte[] data, int offset, int length) {
+ if (length < minBulkSize) {
+ super.writeBytes(data, offset, length);
+ return;
+ }
+
+ flush();
+ try {
+ jos.write(data, offset, length);
+ } catch (java.io.IOException e) {
+ throw new IOException(e);
+ }
+ ptrOffset += length;
+ }
+
+ public void flush() {
+ try {
+ jos.write(b, 0, ptr);
+ } catch (java.io.IOException e) {
+ throw new IOException(e);
+ }
+ ptrOffset += ptr;
+ ptr = 0;
+ }
+
+ public int length() { return ptrOffset + ptr; }
+
+ protected int overrun(int itemSize, int nItems) {
+ if (itemSize > bufSize)
+ throw new Exception("JavaOutStream overrun: max itemSize exceeded");
+
+ flush();
+
+ if (itemSize * nItems > end)
+ nItems = end / itemSize;
+
+ return nItems;
+ }
+
+ private java.io.OutputStream jos;
+ private int ptrOffset;
+ private int bufSize;
+}
diff --git a/java/src/com/tigervnc/vncviewer/MemInStream.java b/java/src/com/tigervnc/rdr/MemInStream.java
index 41a4fc01..ce4f91e3 100644
--- a/java/src/com/tigervnc/vncviewer/MemInStream.java
+++ b/java/src/com/tigervnc/rdr/MemInStream.java
@@ -16,7 +16,7 @@
* USA.
*/
-package com.tigervnc.vncviewer;
+package com.tigervnc.rdr;
public class MemInStream extends InStream {
@@ -28,7 +28,7 @@ public class MemInStream extends InStream {
public int pos() { return ptr; }
- protected int overrun(int itemSize, int nItems) throws Exception {
- throw new Exception("MemInStream overrun: end of stream");
+ protected int overrun(int itemSize, int nItems) {
+ throw new EndOfStream();
}
}
diff --git a/java/src/com/tigervnc/rdr/MemOutStream.java b/java/src/com/tigervnc/rdr/MemOutStream.java
new file mode 100644
index 00000000..b3040793
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/MemOutStream.java
@@ -0,0 +1,53 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// A MemOutStream grows as needed when data is written to it.
+//
+
+package com.tigervnc.rdr;
+
+public class MemOutStream extends OutStream {
+
+ public MemOutStream(int len) {
+ b = new byte[len];
+ ptr = 0;
+ end = len;
+ }
+ public MemOutStream() { this(1024); }
+
+ public int length() { return ptr; }
+ public void clear() { ptr = 0; };
+ public void reposition(int pos) { ptr = pos; }
+
+ // overrun() either doubles the buffer or adds enough space for nItems of
+ // size itemSize bytes.
+
+ protected int overrun(int itemSize, int nItems) {
+ int len = ptr + itemSize * nItems;
+ if (len < end * 2)
+ len = end * 2;
+
+ byte[] newBuf = new byte[len];
+ System.arraycopy(b, 0, newBuf, 0, ptr);
+ b = newBuf;
+ end = len;
+
+ return nItems;
+ }
+}
diff --git a/java/src/com/tigervnc/rdr/OutStream.java b/java/src/com/tigervnc/rdr/OutStream.java
new file mode 100644
index 00000000..7b4869e0
--- /dev/null
+++ b/java/src/com/tigervnc/rdr/OutStream.java
@@ -0,0 +1,141 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// rdr::OutStream marshalls data into a buffer stored in RDR (RFB Data
+// Representation).
+//
+
+package com.tigervnc.rdr;
+
+abstract public class OutStream {
+
+ // check() ensures there is buffer space for at least one item of size
+ // itemSize bytes. Returns the number of items which fit (up to a maximum
+ // of nItems).
+
+ public final int check(int itemSize, int nItems) {
+ if (ptr + itemSize * nItems > end) {
+ if (ptr + itemSize > end)
+ return overrun(itemSize, nItems);
+
+ nItems = (end - ptr) / itemSize;
+ }
+ return nItems;
+ }
+
+ public final void check(int itemSize) {
+ if (ptr + itemSize > end)
+ overrun(itemSize, 1);
+ }
+
+ // writeU/SN() methods write unsigned and signed N-bit integers.
+
+ public final void writeU8( int u) { check(1); b[ptr++] = (byte)u; }
+ public final void writeU16(int u) { check(2); b[ptr++] = (byte)(u >> 8);
+ b[ptr++] = (byte)u; }
+ public final void writeU32(int u) { check(4); b[ptr++] = (byte)(u >> 24);
+ b[ptr++] = (byte)(u >> 16);
+ b[ptr++] = (byte)(u >> 8);
+ b[ptr++] = (byte)u; }
+
+ public final void writeS8( int s) { writeU8( s); }
+ public final void writeS16(int s) { writeU16(s); }
+ public final void writeS32(int s) { writeU32(s); }
+
+ // writeString() writes a string - a U32 length followed by the data.
+
+ public final void writeString(String str) {
+ int len = str.length();
+ writeU32(len);
+ for (int i = 0; i < len;) {
+ int j = i + check(1, len - i);
+ while (i < j) {
+ b[ptr++] = (byte)str.charAt(i++);
+ }
+ }
+ }
+
+ public final void pad(int bytes) {
+ while (bytes-- > 0) writeU8(0);
+ }
+
+ public final void skip(int bytes) {
+ while (bytes > 0) {
+ int n = check(1, bytes);
+ ptr += n;
+ bytes -= n;
+ }
+ }
+
+ // writeBytes() writes an exact number of bytes from an array at an offset.
+
+ public void writeBytes(byte[] data, int offset, int length) {
+ int offsetEnd = offset + length;
+ while (offset < offsetEnd) {
+ int n = check(1, offsetEnd - offset);
+ System.arraycopy(data, offset, b, ptr, n);
+ ptr += n;
+ offset += n;
+ }
+ }
+
+ // writeOpaqueN() writes a quantity without byte-swapping. Because java has
+ // no byte-ordering, we just use big-endian.
+
+ public final void writeOpaque8( int u) { writeU8( u); }
+ public final void writeOpaque16(int u) { writeU16(u); }
+ public final void writeOpaque32(int u) { writeU32(u); }
+ public final void writeOpaque24A(int u) { check(3);
+ b[ptr++] = (byte)(u >> 24);
+ b[ptr++] = (byte)(u >> 16);
+ b[ptr++] = (byte)(u >> 8); }
+ public final void writeOpaque24B(int u) { check(3);
+ b[ptr++] = (byte)(u >> 16);
+ b[ptr++] = (byte)(u >> 8);
+ b[ptr++] = (byte)u; }
+
+ // length() returns the length of the stream.
+
+ abstract public int length();
+
+ // flush() requests that the stream be flushed.
+
+ public void flush() {}
+
+ // getptr(), getend() and setptr() are "dirty" methods which allow you to
+ // manipulate the buffer directly. This is useful for a stream which is a
+ // wrapper around an underlying stream.
+
+ public final byte[] getbuf() { return b; }
+ public final int getptr() { return ptr; }
+ public final int getend() { return end; }
+ public final void setptr(int p) { ptr = p; }
+
+ // overrun() is implemented by a derived class to cope with buffer overrun.
+ // It ensures there are at least itemSize bytes of buffer space. Returns
+ // the number of items which fit (up to a maximum of nItems). itemSize is
+ // supposed to be "small" (a few bytes).
+
+ abstract protected int overrun(int itemSize, int nItems);
+
+ protected OutStream() {}
+ protected byte[] b;
+ protected int ptr;
+ protected int end;
+}
diff --git a/java/src/com/tigervnc/vncviewer/ZlibInStream.java b/java/src/com/tigervnc/rdr/ZlibInStream.java
index 2f2a3c07..64de00a1 100644
--- a/java/src/com/tigervnc/vncviewer/ZlibInStream.java
+++ b/java/src/com/tigervnc/rdr/ZlibInStream.java
@@ -20,7 +20,7 @@
// A ZlibInStream reads from a zlib.io.InputStream
//
-package com.tigervnc.vncviewer;
+package com.tigervnc.rdr;
public class ZlibInStream extends InStream {
@@ -41,7 +41,7 @@ public class ZlibInStream extends InStream {
ptr = end = 0;
}
- public void reset() throws Exception {
+ public void reset() {
ptr = end = 0;
if (underlying == null) return;
@@ -54,7 +54,7 @@ public class ZlibInStream extends InStream {
public int pos() { return ptrOffset + ptr; }
- protected int overrun(int itemSize, int nItems) throws Exception {
+ protected int overrun(int itemSize, int nItems) {
if (itemSize > bufSize)
throw new Exception("ZlibInStream overrun: max itemSize exceeded");
if (underlying == null)
@@ -82,7 +82,7 @@ public class ZlibInStream extends InStream {
// data. Returns false if wait is false and we would block on the underlying
// stream.
- private void decompress() throws Exception {
+ private void decompress() {
try {
underlying.check(1);
int avail_in = underlying.getend() - underlying.getptr();
diff --git a/java/src/com/tigervnc/rfb/AliasParameter.java b/java/src/com/tigervnc/rfb/AliasParameter.java
new file mode 100644
index 00000000..2570b877
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/AliasParameter.java
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class AliasParameter extends VoidParameter {
+ public AliasParameter(String name_, String desc_, VoidParameter v) {
+ super(name_, desc_);
+ param = v;
+ }
+
+ public boolean setParam(String v) { return param.setParam(v); }
+ public boolean setParam() { return param.setParam(); }
+
+ public String getDefaultStr() { return param.getDefaultStr(); }
+ public String getValueStr() { return param.getValueStr(); }
+ public boolean isBool() { return param.isBool(); }
+
+ protected VoidParameter param;
+}
diff --git a/java/src/com/tigervnc/rfb/AuthFailureException.java b/java/src/com/tigervnc/rfb/AuthFailureException.java
new file mode 100644
index 00000000..35fabef0
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/AuthFailureException.java
@@ -0,0 +1,23 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class AuthFailureException extends Exception {
+ public AuthFailureException(String s) { super(s); }
+}
diff --git a/java/src/com/tigervnc/rfb/BoolParameter.java b/java/src/com/tigervnc/rfb/BoolParameter.java
new file mode 100644
index 00000000..06c6ed79
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/BoolParameter.java
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class BoolParameter extends VoidParameter {
+ public BoolParameter(String name_, String desc_, boolean v) {
+ super(name_, desc_);
+ value = v;
+ defValue = v;
+ }
+
+ public boolean setParam(String v) {
+ if (v.equals("1") || v.equalsIgnoreCase("on") ||
+ v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes"))
+ value = true;
+ else if (v.equals("0") || v.equalsIgnoreCase("off") ||
+ v.equalsIgnoreCase("false") || v.equalsIgnoreCase("no"))
+ value = false;
+ else
+ return false;
+ return true;
+ }
+
+ public boolean setParam() { setParam(true); return true; }
+ public void setParam(boolean b) { value = b; }
+
+ public String getDefaultStr() { return defValue ? "1" : "0"; }
+ public String getValueStr() { return value ? "1" : "0"; }
+ public boolean isBool() { return true; }
+
+ final public boolean getValue() { return value; }
+
+ protected boolean value;
+ protected boolean defValue;
+}
diff --git a/java/src/com/tigervnc/rfb/CConnection.java b/java/src/com/tigervnc/rfb/CConnection.java
new file mode 100644
index 00000000..bca2e9df
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CConnection.java
@@ -0,0 +1,370 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+
+abstract public class CConnection extends CMsgHandler {
+
+ public CConnection() {
+ security = new SecurityClient();
+ }
+
+ // setStreams() sets the streams to be used for the connection. These must
+ // be set before initialiseProtocol() and processMsg() are called. The
+ // CSecurity object may call setStreams() again to provide alternative
+ // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
+ // streams). Ownership of the streams remains with the caller
+ // (i.e. SConnection will not delete them).
+ public void setStreams(InStream is_, OutStream os_) {
+ is = is_;
+ os = os_;
+ }
+
+ // initialiseProtocol() should be called once the streams and security
+ // types are set. Subsequently, processMsg() should be called whenever
+ // there is data to read on the InStream.
+ public void initialiseProtocol() {
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+ }
+
+ // processMsg() should be called whenever there is data to read on the
+ // InStream. You must have called initialiseProtocol() first.
+ public void processMsg() {
+ switch (state_) {
+
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader_.readMsg(); break;
+ case RFBSTATE_UNINITIALISED:
+ throw new Exception("CConnection.processMsg: not initialised yet?");
+ default:
+ throw new Exception("CConnection.processMsg: invalid state");
+ }
+ }
+
+ private void processVersionMsg() {
+ vlog.debug("reading protocol version");
+ boolean done = true;
+ if (!cp.readVersion(is, done)) {
+ state_ = RFBSTATE_INVALID;
+ throw new Exception("reading version failed: not an RFB server?");
+ }
+ if (!done) return;
+
+ vlog.info("Server supports RFB protocol version "+cp.majorVersion+"."+
+ cp.minorVersion);
+
+ // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+ if (cp.beforeVersion(3,3)) {
+ String msg = ("Server gave unsupported RFB protocol version "+
+ cp.majorVersion+"."+cp.minorVersion);
+ vlog.error(msg);
+ state_ = RFBSTATE_INVALID;
+ throw new Exception(msg);
+ } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
+ cp.setVersion(3,3);
+ } else if (cp.afterVersion(3,8)) {
+ cp.setVersion(3,8);
+ }
+
+ cp.writeVersion(os);
+ state_ = RFBSTATE_SECURITY_TYPES;
+
+ vlog.info("Using RFB protocol version "+
+ cp.majorVersion+"."+cp.minorVersion);
+ }
+
+ private void processSecurityTypesMsg() {
+ vlog.info("processing security types message");
+
+ int secType = Security.secTypeInvalid;
+ List<Integer> secTypes = new ArrayList<Integer>();
+ secTypes = security.GetEnabledSecTypes();
+ //for (Iterator i = secTypes.iterator(); i.hasNext(); )
+ // vlog.info(((Integer)i.next()).toString());
+
+ if (cp.isVersion(3,3)) {
+
+ // legacy 3.3 server may only offer "vnc authentication" or "none"
+
+ secType = is.readU32();
+ if (secType == Security.secTypeInvalid) {
+ throwConnFailedException();
+
+ } else if (secType == Security.secTypeNone || secType == Security.secTypeVncAuth) {
+ Iterator i;
+ for (i = secTypes.iterator(); i.hasNext(); ) {
+ int refType = (Integer)i.next();
+ if (refType == secType) {
+ secType = refType;
+ break;
+ }
+ }
+
+ if (!i.hasNext())
+ secType = Security.secTypeInvalid;
+ } else {
+ vlog.error("Unknown 3.3 security type "+secType);
+ throw new Exception("Unknown 3.3 security type");
+ }
+
+ } else {
+
+ // 3.7 server will offer us a list
+
+ int nServerSecTypes = is.readU8();
+ if (nServerSecTypes == 0)
+ throwConnFailedException();
+
+ for (int i = 0; i < nServerSecTypes; i++) {
+ int serverSecType = is.readU8();
+ vlog.info("Server offers security type "+
+ Security.secTypeName(serverSecType)+"("+serverSecType+")");
+
+ /*
+ * Use the first type sent by server which matches client's type.
+ * It means server's order specifies priority.
+ */
+ if (secType == Security.secTypeInvalid) {
+ for (Iterator j = secTypes.iterator(); j.hasNext(); ) {
+ int refType = (Integer)j.next();
+ if (refType == serverSecType) {
+ secType = refType;
+ break;
+ }
+ }
+ }
+ }
+
+ // Inform the server of our decision
+ if (secType != Security.secTypeInvalid) {
+ os.writeU8(secType);
+ os.flush();
+ vlog.info("Choosing security type "+Security.secTypeName(secType)+
+ "("+secType+")");
+ }
+ }
+
+ if (secType == Security.secTypeInvalid) {
+ state_ = RFBSTATE_INVALID;
+ vlog.error("No matching security types");
+ throw new Exception("No matching security types");
+ }
+
+ state_ = RFBSTATE_SECURITY;
+ csecurity = security.GetCSecurity(secType);
+ processSecurityMsg();
+ }
+
+ private void processSecurityMsg() {
+ vlog.debug("processing security message");
+ if (csecurity.processMsg(this)) {
+ state_ = RFBSTATE_SECURITY_RESULT;
+ processSecurityResultMsg();
+ }
+ }
+
+ private void processSecurityResultMsg() {
+ vlog.debug("processing security result message");
+ int result;
+ if (cp.beforeVersion(3,8) && csecurity.getType() == Security.secTypeNone) {
+ result = Security.secResultOK;
+ } else {
+ if (!is.checkNoWait(1)) return;
+ result = is.readU32();
+ }
+ switch (result) {
+ case Security.secResultOK:
+ securityCompleted();
+ return;
+ case Security.secResultFailed:
+ vlog.debug("auth failed");
+ break;
+ case Security.secResultTooMany:
+ vlog.debug("auth failed - too many tries");
+ break;
+ default:
+ throw new Exception("Unknown security result from server");
+ }
+ String reason;
+ if (cp.beforeVersion(3,8))
+ reason = "Authentication failure";
+ else
+ reason = is.readString();
+ state_ = RFBSTATE_INVALID;
+ throw new AuthFailureException(reason);
+ }
+
+ private void processInitMsg() {
+ vlog.debug("reading server initialisation");
+ reader_.readServerInit();
+ }
+
+ private void throwConnFailedException() {
+ state_ = RFBSTATE_INVALID;
+ String reason;
+ reason = is.readString();
+ throw new ConnFailedException(reason);
+ }
+
+ private void securityCompleted() {
+ state_ = RFBSTATE_INITIALISATION;
+ reader_ = new CMsgReaderV3(this, is);
+ writer_ = new CMsgWriterV3(cp, os);
+ vlog.debug("Authentication success!");
+ authSuccess();
+ writer_.writeClientInit(shared);
+ }
+
+ // Methods to initialise the connection
+
+ // setServerName() is used to provide a unique(ish) name for the server to
+ // which we are connected. This might be the result of getPeerEndpoint on
+ // a TcpSocket, for example, or a host specified by DNS name & port.
+ // The serverName is used when verifying the Identity of a host (see RA2).
+ public void setServerName(String name) {
+ serverName = name;
+ }
+
+ public void setServerPort(int port) {
+ serverPort = port;
+ }
+
+ //public void setEncryptionType(String type) {
+ // encryptionType = type;
+ //}
+
+ public void initSecTypes() {
+ nSecTypes = 0;
+ }
+
+ // addSecType() should be called once for each security type which the
+ // client supports. The order in which they're added is such that the
+ // first one is most preferred.
+/*
+ public void addSecType(int secType) {
+ if (nSecTypes == maxSecTypes)
+ throw new Exception("too many security types");
+ secTypes.set(nSecTypes++,secType);
+ }
+*/
+
+ // setShared sets the value of the shared flag which will be sent to the
+ // server upon initialisation.
+ public void setShared(boolean s) { shared = s; }
+
+ // setProtocol3_3 configures whether or not the CConnection should
+ // only ever support protocol version 3.3
+ public void setProtocol3_3(boolean s) { useProtocol3_3 = s; }
+
+ // Methods to be overridden in a derived class
+
+ // getCSecurity() gets the CSecurity object for the given type. The type
+ // is guaranteed to be one of the secTypes passed in to addSecType(). The
+ // CSecurity object's destroy() method will be called by the CConnection
+ // from its destructor.
+ //abstract public CSecurity getCSecurity(int secType);
+
+ // getCurrentCSecurity() gets the CSecurity instance used for this
+ // connection.
+ //public CSecurity getCurrentCSecurity() { return security; }
+
+ // setClientSecTypeOrder() determines whether the client should obey the
+ // server's security type preference, by picking the first server security
+ // type that the client supports, or whether it should pick the first type
+ // that the server supports, from the client-supported list of types.
+ public void setClientSecTypeOrder( boolean csto ) {
+ clientSecTypeOrder = csto;
+ }
+
+ // authSuccess() is called when authentication has succeeded.
+ public void authSuccess() {}
+
+ // serverInit() is called when the ServerInit message is received. The
+ // derived class must call on to CConnection::serverInit().
+ public void serverInit() {
+ state_ = RFBSTATE_NORMAL;
+ vlog.debug("initialisation done");
+ }
+
+ // Other methods
+
+ public CMsgReader reader() { return reader_; }
+ public CMsgWriter writer() { return writer_; }
+
+ public InStream getInStream() { return is; }
+ public OutStream getOutStream() { return os; }
+
+ public String getServerName() { return serverName; }
+ public int getServerPort() { return serverPort; }
+
+ public static final int RFBSTATE_UNINITIALISED = 0;
+ public static final int RFBSTATE_PROTOCOL_VERSION = 1;
+ public static final int RFBSTATE_SECURITY_TYPES = 2;
+ public static final int RFBSTATE_SECURITY = 3;
+ public static final int RFBSTATE_SECURITY_RESULT = 4;
+ public static final int RFBSTATE_INITIALISATION = 5;
+ public static final int RFBSTATE_NORMAL = 6;
+ public static final int RFBSTATE_INVALID = 7;
+
+ public int state() { return state_; }
+
+ protected void setState(int s) { state_ = s; }
+
+ private void throwAuthFailureException() {
+ String reason;
+ vlog.debug("state="+state()+", ver="+cp.majorVersion+"."+cp.minorVersion);
+ if (state() == RFBSTATE_SECURITY_RESULT && !cp.beforeVersion(3,8)) {
+ reason = is.readString();
+ } else {
+ reason = "Authentication failure";
+ }
+ state_ = RFBSTATE_INVALID;
+ vlog.error(reason);
+ throw new AuthFailureException(reason);
+ }
+
+ InStream is = null;
+ OutStream os = null;
+ CMsgReader reader_ = null;
+ CMsgWriter writer_ = null;
+ boolean shared = false;
+ public CSecurity csecurity;
+ public SecurityClient security;
+ public static final int maxSecTypes = 8;
+ int nSecTypes;
+ int[] secTypes;
+ int state_ = RFBSTATE_UNINITIALISED;
+ String serverName;
+ int serverPort;
+ boolean useProtocol3_3 = false;
+ boolean clientSecTypeOrder;
+ public static java.net.Socket sock;
+
+ public static java.net.Socket getSocket() { return sock; }
+ public static void setSocket(java.net.Socket sock_) { sock = sock_; }
+
+ static LogWriter vlog = new LogWriter("CConnection");
+}
diff --git a/java/src/com/tigervnc/rfb/CMsgHandler.java b/java/src/com/tigervnc/rfb/CMsgHandler.java
new file mode 100644
index 00000000..11d26815
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CMsgHandler.java
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// CMsgHandler
+//
+
+package com.tigervnc.rfb;
+
+public class CMsgHandler {
+
+ public CMsgHandler() {
+ cp = new ConnParams();
+ }
+
+ public void setDesktopSize(int width, int height)
+ {
+ cp.width = width;
+ cp.height = height;
+ }
+
+ public void setExtendedDesktopSize(int reason, int result,
+ int width, int height,
+ ScreenSet layout)
+ {
+ cp.supportsSetDesktopSize = true;
+
+ if ((reason == screenTypes.reasonClient) && (result != screenTypes.resultSuccess))
+ return;
+
+ if (!layout.validate(width, height))
+ vlog.error("Server sent us an invalid screen layout");
+
+ cp.width = width;
+ cp.height = height;
+ cp.screenLayout = layout;
+ }
+
+ public void setPixelFormat(PixelFormat pf)
+ {
+ cp.setPF(pf);
+ }
+
+ public void setName(String name)
+ {
+ cp.setName(name);
+ }
+
+ public void setCursor(int width, int height, Point hotspot,
+ int[] data, byte[] mask) {}
+ public void serverInit() {}
+
+ public void framebufferUpdateStart() {}
+ public void framebufferUpdateEnd() {}
+ public void beginRect(Rect r, int encoding) {}
+ public void endRect(Rect r, int encoding) {}
+
+ public void setColourMapEntries(int firstColour, int nColours,
+ int[] rgbs) { }
+ public void bell() {}
+ public void serverCutText(String str, int len) {}
+
+ public void fillRect(Rect r, int pix) {}
+ public void imageRect(Rect r, int[] pixels) {}
+ public void copyRect(Rect r, int srcX, int srcY) {}
+
+ public ConnParams cp;
+
+ static LogWriter vlog = new LogWriter("CMsgHandler");
+}
diff --git a/java/src/com/tigervnc/rfb/CMsgReader.java b/java/src/com/tigervnc/rfb/CMsgReader.java
new file mode 100644
index 00000000..66b9d174
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CMsgReader.java
@@ -0,0 +1,173 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// CMsgReader - class for reading RFB messages on the client side
+// (i.e. messages from server to client).
+//
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+abstract public class CMsgReader {
+
+ protected CMsgReader(CMsgHandler handler_, InStream is_)
+ {
+ imageBufIdealSize = 0;
+ handler = handler_;
+ is = is_;
+ imageBuf = null;
+ imageBufSize = 0;
+ decoders = new Decoder[Encodings.encodingMax+1];
+ }
+
+ protected void readSetColourMapEntries()
+ {
+ is.skip(1);
+ int firstColour = is.readU16();
+ int nColours = is.readU16();
+ int[] rgbs = new int[nColours * 3];
+ for (int i = 0; i < nColours * 3; i++)
+ rgbs[i] = is.readU16();
+ handler.setColourMapEntries(firstColour, nColours, rgbs);
+ }
+
+ protected void readBell()
+ {
+ handler.bell();
+ }
+
+ protected void readServerCutText()
+ {
+ is.skip(3);
+ int len = is.readU32();
+ if (len > 256*1024) {
+ is.skip(len);
+ vlog.error("cut text too long ("+len+" bytes) - ignoring");
+ return;
+ }
+ byte[] buf = new byte[len];
+ is.readBytes(buf, 0, len);
+ handler.serverCutText(new String(buf), len);
+ }
+
+ protected void readFramebufferUpdateStart()
+ {
+ handler.framebufferUpdateStart();
+ }
+
+ protected void readFramebufferUpdateEnd()
+ {
+ handler.framebufferUpdateEnd();
+ }
+
+ protected void readRect(Rect r, int encoding)
+ {
+ if ((r.br.x > handler.cp.width) || (r.br.y > handler.cp.height)) {
+ vlog.error("Rect too big: "+r.width()+"x"+r.height()+" at "+
+ r.tl.x+","+r.tl.y+" exceeds "+handler.cp.width+"x"+
+ handler.cp.height);
+ throw new Exception("Rect too big");
+ }
+
+ if (r.is_empty())
+ vlog.error("Ignoring zero size rect");
+
+ handler.beginRect(r, encoding);
+
+ if (encoding == Encodings.encodingCopyRect) {
+ readCopyRect(r);
+ } else {
+
+ if (decoders[encoding] == null) {
+ decoders[encoding] = Decoder.createDecoder(encoding, this);
+ if (decoders[encoding] == null) {
+ vlog.error("Unknown rect encoding "+encoding);
+ throw new Exception("Unknown rect encoding");
+ }
+ }
+ decoders[encoding].readRect(r, handler);
+ }
+
+ handler.endRect(r, encoding);
+ }
+
+ protected void readCopyRect(Rect r)
+ {
+ int srcX = is.readU16();
+ int srcY = is.readU16();
+ handler.copyRect(r, srcX, srcY);
+ }
+
+ protected void readSetCursor(int width, int height, Point hotspot)
+ {
+ int data_len = width * height;
+ int mask_len = ((width+7)/8) * height;
+ int[] data = new int[data_len];
+ byte[] mask = new byte[mask_len];
+
+ is.readPixels(data, data_len, (handler.cp.pf().bpp/8), handler.cp.pf().bigEndian);
+ is.readBytes(mask, 0, mask_len);
+
+ handler.setCursor(width, height, hotspot, data, mask);
+ }
+
+ public int[] getImageBuf(int required) { return getImageBuf(required, 0, 0); }
+
+ public int[] getImageBuf(int required, int requested, int nPixels)
+ {
+ int requiredBytes = required * (handler.cp.pf().bpp / 8);
+ int requestedBytes = requested * (handler.cp.pf().bpp / 8);
+ int size = requestedBytes;
+ if (size > imageBufIdealSize) size = imageBufIdealSize;
+
+ if (size < requiredBytes)
+ size = requiredBytes;
+
+ if (imageBufSize < size) {
+ imageBufSize = size;
+ imageBuf = new int[imageBufSize];
+ }
+ if (nPixels != 0)
+ nPixels = imageBufSize / (handler.cp.pf().bpp / 8);
+ return imageBuf;
+ }
+
+ public final int bpp()
+ {
+ return handler.cp.pf().bpp;
+ }
+
+ abstract public void readServerInit();
+
+ // readMsg() reads a message, calling the handler as appropriate.
+ abstract public void readMsg();
+
+ public InStream getInStream() { return is; }
+
+ public int imageBufIdealSize;
+
+ protected CMsgHandler handler;
+ protected InStream is;
+ protected Decoder[] decoders;
+ protected int[] imageBuf;
+ protected int imageBufSize;
+
+ static LogWriter vlog = new LogWriter("CMsgReader");
+}
diff --git a/java/src/com/tigervnc/rfb/CMsgReaderV3.java b/java/src/com/tigervnc/rfb/CMsgReaderV3.java
new file mode 100644
index 00000000..b865a6c7
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CMsgReaderV3.java
@@ -0,0 +1,139 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class CMsgReaderV3 extends CMsgReader {
+
+ public CMsgReaderV3(CMsgHandler handler_, InStream is_)
+ {
+ super(handler_, is_);
+ nUpdateRectsLeft = 0;
+ }
+
+ public void readServerInit()
+ {
+ int width = is.readU16();
+ int height = is.readU16();
+ handler.setDesktopSize(width, height);
+ PixelFormat pf = new PixelFormat();
+ pf.read(is);
+ handler.setPixelFormat(pf);
+ String name = is.readString();
+ handler.setName(name);
+ handler.serverInit();
+ }
+
+ public void readMsg()
+ {
+ if (nUpdateRectsLeft == 0) {
+
+ int type = is.readU8();
+ switch (type) {
+ case MsgTypes.msgTypeFramebufferUpdate: readFramebufferUpdate(); break;
+ case MsgTypes.msgTypeSetColourMapEntries: readSetColourMapEntries(); break;
+ case MsgTypes.msgTypeBell: readBell(); break;
+ case MsgTypes.msgTypeServerCutText: readServerCutText(); break;
+ default:
+ vlog.error("unknown message type "+type);
+ throw new Exception("unknown message type");
+ }
+
+ } else {
+
+ int x = is.readU16();
+ int y = is.readU16();
+ int w = is.readU16();
+ int h = is.readU16();
+ int encoding = is.readU32();
+
+ switch (encoding) {
+ case Encodings.pseudoEncodingDesktopSize:
+ handler.setDesktopSize(w, h);
+ break;
+ case Encodings.pseudoEncodingExtendedDesktopSize:
+ readExtendedDesktopSize(x, y, w, h);
+ break;
+ case Encodings.pseudoEncodingDesktopName:
+ readSetDesktopName(x, y, w, h);
+ break;
+ case Encodings.pseudoEncodingCursor:
+ readSetCursor(w, h, new Point(x,y));
+ break;
+ case Encodings.pseudoEncodingLastRect:
+ nUpdateRectsLeft = 1; // this rectangle is the last one
+ break;
+ default:
+ readRect(new Rect(x, y, x+w, y+h), encoding);
+ break;
+ }
+
+ nUpdateRectsLeft--;
+ if (nUpdateRectsLeft == 0) handler.framebufferUpdateEnd();
+ }
+ }
+
+ void readFramebufferUpdate()
+ {
+ is.skip(1);
+ nUpdateRectsLeft = is.readU16();
+ handler.framebufferUpdateStart();
+ }
+
+ void readSetDesktopName(int x, int y, int w, int h)
+ {
+ String name = is.readString();
+
+ if (x != 0 || y != 0 || w != 0 || h != 0) {
+ vlog.error("Ignoring DesktopName rect with non-zero position/size");
+ } else {
+ handler.setName(name);
+ }
+
+ }
+
+ void readExtendedDesktopSize(int x, int y, int w, int h)
+ {
+ int screens, i;
+ int id, flags;
+ int sx, sy, sw, sh;
+ ScreenSet layout = new ScreenSet();
+
+ screens = is.readU8();
+ is.skip(3);
+
+ for (i = 0;i < screens;i++) {
+ id = is.readU32();
+ sx = is.readU16();
+ sy = is.readU16();
+ sw = is.readU16();
+ sh = is.readU16();
+ flags = is.readU32();
+
+ layout.add_screen(new Screen(id, sx, sy, sw, sh, flags));
+ }
+
+ handler.setExtendedDesktopSize(x, y, w, h, layout);
+ }
+
+ int nUpdateRectsLeft;
+
+ static LogWriter vlog = new LogWriter("CMsgReaderV3");
+}
diff --git a/java/src/com/tigervnc/rfb/CMsgWriter.java b/java/src/com/tigervnc/rfb/CMsgWriter.java
new file mode 100644
index 00000000..79f5ee99
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CMsgWriter.java
@@ -0,0 +1,164 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+abstract public class CMsgWriter {
+
+ abstract public void writeClientInit(boolean shared);
+
+ public void writeSetPixelFormat(PixelFormat pf)
+ {
+ startMsg(MsgTypes.msgTypeSetPixelFormat);
+ os.pad(3);
+ pf.write(os);
+ endMsg();
+ }
+
+ public void writeSetEncodings(int nEncodings, int[] encodings)
+ {
+ startMsg(MsgTypes.msgTypeSetEncodings);
+ os.skip(1);
+ os.writeU16(nEncodings);
+ for (int i = 0; i < nEncodings; i++)
+ os.writeU32(encodings[i]);
+ endMsg();
+ }
+
+ // Ask for encodings based on which decoders are supported. Assumes higher
+ // encoding numbers are more desirable.
+
+ public void writeSetEncodings(int preferredEncoding, boolean useCopyRect)
+ {
+ int nEncodings = 0;
+ int[] encodings = new int[Encodings.encodingMax+3];
+ if (cp.supportsLocalCursor)
+ encodings[nEncodings++] = Encodings.pseudoEncodingCursor;
+ if (cp.supportsDesktopResize)
+ encodings[nEncodings++] = Encodings.pseudoEncodingDesktopSize;
+ if (cp.supportsExtendedDesktopSize)
+ encodings[nEncodings++] = Encodings.pseudoEncodingExtendedDesktopSize;
+ if (cp.supportsDesktopRename)
+ encodings[nEncodings++] = Encodings.pseudoEncodingDesktopName;
+ if (Decoder.supported(preferredEncoding)) {
+ encodings[nEncodings++] = preferredEncoding;
+ }
+ if (useCopyRect) {
+ encodings[nEncodings++] = Encodings.encodingCopyRect;
+ }
+
+ /*
+ * Prefer encodings in this order:
+ *
+ * Tight, ZRLE, Hextile, *
+ */
+
+ if ((preferredEncoding != Encodings.encodingTight) &&
+ Decoder.supported(Encodings.encodingTight))
+ encodings[nEncodings++] = Encodings.encodingTight;
+
+ if ((preferredEncoding != Encodings.encodingZRLE) &&
+ Decoder.supported(Encodings.encodingZRLE))
+ encodings[nEncodings++] = Encodings.encodingZRLE;
+
+ if ((preferredEncoding != Encodings.encodingHextile) &&
+ Decoder.supported(Encodings.encodingHextile))
+ encodings[nEncodings++] = Encodings.encodingHextile;
+
+ // Remaining encodings
+ for (int i = Encodings.encodingMax; i >= 0; i--) {
+ switch (i) {
+ case Encodings.encodingTight:
+ case Encodings.encodingZRLE:
+ case Encodings.encodingHextile:
+ break;
+ default:
+ if ((i != preferredEncoding) && Decoder.supported(i))
+ encodings[nEncodings++] = i;
+ }
+ }
+
+ encodings[nEncodings++] = Encodings.pseudoEncodingLastRect;
+ if (cp.customCompressLevel && cp.compressLevel >= 0 && cp.compressLevel <= 9)
+ encodings[nEncodings++] = Encodings.pseudoEncodingCompressLevel0 + cp.compressLevel;
+ if (!cp.noJpeg && cp.qualityLevel >= 0 && cp.qualityLevel <= 9)
+ encodings[nEncodings++] = Encodings.pseudoEncodingQualityLevel0 + cp.qualityLevel;
+
+ writeSetEncodings(nEncodings, encodings);
+ }
+
+ public void writeFramebufferUpdateRequest(Rect r, boolean incremental)
+ {
+ startMsg(MsgTypes.msgTypeFramebufferUpdateRequest);
+ os.writeU8(incremental?1:0);
+ os.writeU16(r.tl.x);
+ os.writeU16(r.tl.y);
+ os.writeU16(r.width());
+ os.writeU16(r.height());
+ endMsg();
+ }
+
+ public void writeKeyEvent(int key, boolean down)
+ {
+ startMsg(MsgTypes.msgTypeKeyEvent);
+ os.writeU8(down?1:0);
+ os.pad(2);
+ os.writeU32(key);
+ endMsg();
+ }
+
+ public void writePointerEvent(Point pos, int buttonMask)
+ {
+ Point p = new Point(pos.x,pos.y);
+ if (p.x < 0) p.x = 0;
+ if (p.y < 0) p.y = 0;
+ if (p.x >= cp.width) p.x = cp.width - 1;
+ if (p.y >= cp.height) p.y = cp.height - 1;
+
+ startMsg(MsgTypes.msgTypePointerEvent);
+ os.writeU8(buttonMask);
+ os.writeU16(p.x);
+ os.writeU16(p.y);
+ endMsg();
+ }
+
+ public void writeClientCutText(String str, int len)
+ {
+ startMsg(MsgTypes.msgTypeClientCutText);
+ os.pad(3);
+ os.writeU32(len);
+ os.writeBytes(str.getBytes(), 0, len);
+ endMsg();
+ }
+
+ abstract public void startMsg(int type);
+ abstract public void endMsg();
+
+ public void setOutStream(OutStream os_) { os = os_; }
+
+ ConnParams getConnParams() { return cp; }
+ OutStream getOutStream() { return os; }
+
+ protected CMsgWriter(ConnParams cp_, OutStream os_) {cp = cp_; os = os_;}
+
+ ConnParams cp;
+ OutStream os;
+ static LogWriter vlog = new LogWriter("CMsgWriter");
+}
diff --git a/java/src/com/tigervnc/rfb/CMsgWriterV3.java b/java/src/com/tigervnc/rfb/CMsgWriterV3.java
new file mode 100644
index 00000000..24d47567
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CMsgWriterV3.java
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class CMsgWriterV3 extends CMsgWriter {
+
+ public CMsgWriterV3(ConnParams cp_, OutStream os_) { super(cp_, os_); }
+
+ public void writeClientInit(boolean shared) {
+ os.writeU8(shared?1:0);
+ endMsg();
+ }
+
+ public void startMsg(int type) {
+ os.writeU8(type);
+ }
+
+ public void endMsg() {
+ os.flush();
+ }
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurity.java b/java/src/com/tigervnc/rfb/CSecurity.java
new file mode 100644
index 00000000..e5b300f6
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurity.java
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// CSecurity - class on the client side for handling security handshaking. A
+// derived class for a particular security type overrides the processMsg()
+// method. processMsg() is called first when the security type has been
+// decided on, and will keep being called whenever there is data to read from
+// the server until either it returns 0, indicating authentication/security
+// failure, or it returns 1, to indicate success. A return value of 2
+// (actually anything other than 0 or 1) indicates that it should be called
+// back when there is more data to read.
+//
+// Note that the first time processMsg() is called, there is no guarantee that
+// there is any data to read from the CConnection's InStream, but subsequent
+// calls guarantee there is at least one byte which can be read without
+// blocking.
+
+package com.tigervnc.rfb;
+
+abstract public class CSecurity {
+ abstract public boolean processMsg(CConnection cc);
+ abstract public int getType();
+ abstract public String description();
+
+ /*
+ * Use variable directly instead of dumb get/set methods.
+ * It MUST be set by viewer.
+ */
+ static UserPasswdGetter upg;
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityManaged.java b/java/src/com/tigervnc/rfb/CSecurityManaged.java
new file mode 100644
index 00000000..3502289f
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityManaged.java
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import java.io.IOException;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityManaged extends CSecurity {
+
+ public CSecurityManaged() { }
+
+ public boolean processMsg(CConnection cc) {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ StringBuffer username = new StringBuffer();
+
+ CConn.upg.getUserPasswd(username, null);
+
+ // Return the response to the server
+ os.writeU8(username.length());
+ os.writeBytes(username.toString().getBytes(), 0, username.length());
+ os.flush();
+ int serverPort = is.readU16();
+ //if (serverPort==0) { return true; };
+ String serverName = cc.getServerName();
+ vlog.debug("Redirected to "+serverName+" port "+serverPort);
+ try {
+ CConn.getSocket().close();
+ cc.setServerPort(serverPort);
+ sock = new java.net.Socket(serverName, serverPort);
+ sock.setTcpNoDelay(true);
+ sock.setTrafficClass(0x10);
+ CConn.setSocket(sock);
+ vlog.debug("connected to host "+serverName+" port "+serverPort);
+ cc.setStreams(new JavaInStream(sock.getInputStream()),
+ new JavaOutStream(sock.getOutputStream()));
+ cc.initialiseProtocol();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public int getType() { return Security.secTypeManaged; }
+
+ java.net.Socket sock;
+ UserPasswdGetter upg;
+
+ static LogWriter vlog = new LogWriter("Managed");
+ public String description() { return "No Encryption"; }
+
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityNone.java b/java/src/com/tigervnc/rfb/CSecurityNone.java
new file mode 100644
index 00000000..e31056da
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityNone.java
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class CSecurityNone extends CSecurity {
+
+ public boolean processMsg(CConnection cc) { return true; }
+ public int getType() { return Security.secTypeNone; }
+ public String description() { return "No Encryption"; }
+ static LogWriter vlog = new LogWriter("CSecurityNone");
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityPlain.java b/java/src/com/tigervnc/rfb/CSecurityPlain.java
new file mode 100644
index 00000000..c790852b
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityPlain.java
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityPlain extends CSecurity {
+
+ public CSecurityPlain() { }
+
+ public boolean processMsg(CConnection cc)
+ {
+ OutStream os = cc.getOutStream();
+
+ StringBuffer username = new StringBuffer();
+ StringBuffer password = new StringBuffer();
+
+ CConn.upg.getUserPasswd(username, password);
+
+ // Return the response to the server
+ os.writeU32(username.length());
+ os.writeU32(password.length());
+ os.writeBytes(username.toString().getBytes(), 0, username.length());
+ os.writeBytes(password.toString().getBytes(), 0, password.length());
+ os.flush();
+ return true;
+ }
+
+ public int getType() { return Security.secTypePlain; }
+ public String description() { return "ask for username and password"; }
+
+ static LogWriter vlog = new LogWriter("Plain");
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityStack.java b/java/src/com/tigervnc/rfb/CSecurityStack.java
new file mode 100644
index 00000000..5886268e
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityStack.java
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005 Martin Koegler
+ * Copyright (C) 2010 TigerVNC Team
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class CSecurityStack extends CSecurity {
+
+ public CSecurityStack(int Type, String Name, CSecurity s0,
+ CSecurity s1)
+ {
+ name = Name;
+ type = Type;
+ state = 0;
+ state0 = s0;
+ state1 = s1;
+ }
+
+ public boolean processMsg(CConnection cc)
+ {
+ boolean res = true;
+ if (state == 0) {
+ if (state0 != null)
+ res = state0.processMsg(cc);
+
+ if (!res)
+ return res;
+
+ state++;
+ }
+
+ if (state == 1) {
+ if(state1 != null)
+ res = state1.processMsg(cc);
+
+ if(!res)
+ return res;
+
+ state++;
+ }
+
+ return res;
+ }
+
+ public final int getType() { return type; }
+ public final String description() { return name; }
+
+ private int state;
+ private CSecurity state0;
+ private CSecurity state1;
+ private String name;
+ private int type;
+
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityTLS.java b/java/src/com/tigervnc/rfb/CSecurityTLS.java
new file mode 100644
index 00000000..977987ea
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityTLS.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.KeyStore;
+import java.io.File;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import com.tigervnc.vncviewer.UserPrefs;
+import com.tigervnc.rdr.*;
+
+public class CSecurityTLS extends CSecurity {
+
+ public static StringParameter x509ca
+ = new StringParameter("x509ca",
+ "X509 CA certificate", "");
+ public static StringParameter x509crl
+ = new StringParameter("x509crl",
+ "X509 CRL file", "");
+
+ private void initGlobal()
+ {
+ try {
+ SSLSocketFactory sslfactory;
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ if (anon) {
+ ctx.init(null, null, null);
+ } else {
+ TrustManager[] myTM = new TrustManager[] {
+ new MyX509TrustManager()
+ };
+ ctx.init (null, myTM, null);
+ }
+ sslfactory = ctx.getSocketFactory();
+ try {
+ ssl = (SSLSocket)sslfactory.createSocket(cc.sock,
+ cc.sock.getInetAddress().getHostName(),
+ cc.sock.getPort(), true);
+ } catch (java.io.IOException e) {
+ throw new Exception(e.toString());
+ }
+
+ if (anon) {
+ String[] supported;
+ ArrayList enabled = new ArrayList();
+
+ supported = ssl.getSupportedCipherSuites();
+
+ for (int i = 0; i < supported.length; i++)
+ if (supported[i].matches("TLS_DH_anon.*"))
+ enabled.add(supported[i]);
+
+ ssl.setEnabledCipherSuites((String[])enabled.toArray(new String[0]));
+ } else {
+ ssl.setEnabledCipherSuites(ssl.getSupportedCipherSuites());
+ }
+
+ ssl.setEnabledProtocols(new String[]{"SSLv3","TLSv1"});
+ ssl.addHandshakeCompletedListener(new MyHandshakeListener());
+ }
+ catch (java.security.GeneralSecurityException e)
+ {
+ vlog.error ("TLS handshake failed " + e.toString ());
+ return;
+ }
+ }
+
+ public CSecurityTLS(boolean _anon)
+ {
+ anon = _anon;
+ setDefaults();
+ cafile = x509ca.getData();
+ crlfile = x509crl.getData();
+ }
+
+ public static void setDefaults()
+ {
+ String homeDir = null;
+
+ if ((homeDir=UserPrefs.getHomeDir()) == null) {
+ vlog.error("Could not obtain VNC home directory path");
+ return;
+ }
+
+ String vnchomedir = homeDir+UserPrefs.getFileSeperator()+".vnc"+
+ UserPrefs.getFileSeperator();
+ String caDefault = new String(vnchomedir+"x509_ca.pem");
+ String crlDefault = new String(vnchomedir+"x509_crl.pem");
+
+ if (new File(caDefault).exists())
+ x509ca.setDefaultStr(caDefault);
+ if (new File(crlDefault).exists())
+ x509crl.setDefaultStr(crlDefault);
+ }
+
+ public boolean processMsg(CConnection cc) {
+ is = cc.getInStream();
+ os = cc.getOutStream();
+
+ initGlobal();
+
+ if (!is.checkNoWait(1))
+ return false;
+
+ if (is.readU8() == 0) {
+ int result = is.readU32();
+ String reason;
+ if (result == Security.secResultFailed ||
+ result == Security.secResultTooMany)
+ reason = is.readString();
+ else
+ reason = new String("Authentication failure (protocol error)");
+ throw new AuthFailureException(reason);
+ }
+
+ // SSLSocket.getSession blocks until the handshake is complete
+ session = ssl.getSession();
+ if (!session.isValid())
+ throw new Exception("TLS Handshake failed!");
+
+ try {
+ cc.setStreams(new JavaInStream(ssl.getInputStream()),
+ new JavaOutStream(ssl.getOutputStream()));
+ } catch (java.io.IOException e) {
+ throw new Exception("Failed to set streams");
+ }
+
+ return true;
+ }
+
+ class MyHandshakeListener implements HandshakeCompletedListener {
+ public void handshakeCompleted(HandshakeCompletedEvent e) {
+ vlog.info("Handshake succesful!");
+ vlog.info("Using cipher suite: " + e.getCipherSuite());
+ }
+ }
+
+ class MyX509TrustManager implements X509TrustManager
+ {
+
+ X509TrustManager tm;
+
+ MyX509TrustManager() throws java.security.GeneralSecurityException
+ {
+ TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance("PKIX");
+ KeyStore ks = KeyStore.getInstance("JKS");
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ try {
+ ks.load(null, null);
+ File cacert = new File(cafile);
+ if (!cacert.exists() || !cacert.canRead())
+ return;
+ InputStream caStream = new FileInputStream(cafile);
+ X509Certificate ca = (X509Certificate)cf.generateCertificate(caStream);
+ ks.setCertificateEntry("CA", ca);
+ PKIXBuilderParameters params = new PKIXBuilderParameters(ks, new X509CertSelector());
+ File crlcert = new File(crlfile);
+ if (!crlcert.exists() || !crlcert.canRead()) {
+ params.setRevocationEnabled(false);
+ } else {
+ InputStream crlStream = new FileInputStream(crlfile);
+ Collection<? extends CRL> crls = cf.generateCRLs(crlStream);
+ CertStoreParameters csp = new CollectionCertStoreParameters(crls);
+ CertStore store = CertStore.getInstance("Collection", csp);
+ params.addCertStore(store);
+ params.setRevocationEnabled(true);
+ }
+ tmf.init(new CertPathTrustManagerParameters(params));
+ } catch (java.io.FileNotFoundException e) {
+ vlog.error(e.toString());
+ } catch (java.io.IOException e) {
+ vlog.error(e.toString());
+ }
+ tm = (X509TrustManager)tmf.getTrustManagers()[0];
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ tm.checkClientTrusted(chain, authType);
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ try {
+ tm.checkServerTrusted(chain, authType);
+ } catch (CertificateException e) {
+ Object[] answer = {"Proceed", "Exit"};
+ int ret = JOptionPane.showOptionDialog(null,
+ e.getCause().getLocalizedMessage()+"\n"+
+ "Continue connecting to this host?",
+ "Confirm certificate exception?",
+ JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, answer, answer[0]);
+ if (ret == JOptionPane.NO_OPTION)
+ System.exit(1);
+ } catch (java.lang.Exception e) {
+ throw new Exception(e.toString());
+ }
+ }
+
+ public X509Certificate[] getAcceptedIssuers ()
+ {
+ return tm.getAcceptedIssuers();
+ }
+ }
+
+ public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; }
+ public final String description()
+ { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
+
+
+ //protected void setParam();
+ //protected void checkSession();
+ protected CConnection cc;
+
+ private boolean anon;
+ private SSLSession session;
+ private String cafile, crlfile;
+ private InStream is;
+ private OutStream os;
+ private SSLSocket ssl;
+
+ static LogWriter vlog = new LogWriter("CSecurityTLS");
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityVeNCrypt.java b/java/src/com/tigervnc/rfb/CSecurityVeNCrypt.java
new file mode 100644
index 00000000..ae758e7f
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityVeNCrypt.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+
+public class CSecurityVeNCrypt extends CSecurity {
+
+ public CSecurityVeNCrypt(SecurityClient sec)
+ {
+ haveRecvdMajorVersion = false;
+ haveRecvdMinorVersion = false;
+ haveSentVersion = false;
+ haveAgreedVersion = false;
+ haveListOfTypes = false;
+ haveNumberOfTypes = false;
+ haveChosenType = false;
+ majorVersion = 0;
+ minorVersion = 0;
+ chosenType = Security.secTypeVeNCrypt;
+ nAvailableTypes = 0;
+ availableTypes = null;
+ iAvailableType = 0;
+ security = sec;
+ }
+
+ public boolean processMsg(CConnection cc) {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ /* get major, minor versions, send what we can support (or 0.0 for can't support it) */
+ if (!haveRecvdMinorVersion) {
+ minorVersion = is.readU8();
+ haveRecvdMinorVersion = true;
+
+ return false;
+ }
+
+ if (!haveRecvdMajorVersion) {
+ majorVersion = is.readU8();
+ haveRecvdMajorVersion = true;
+ }
+
+ /* major version in upper 8 bits and minor version in lower 8 bits */
+ int Version = (majorVersion << 8) | minorVersion;
+
+ if (!haveSentVersion) {
+ /* Currently we don't support former VeNCrypt 0.1 */
+ if (Version >= 0x0002) {
+ majorVersion = 0;
+ minorVersion = 2;
+ os.writeU8(majorVersion);
+ os.writeU8(minorVersion);
+ os.flush();
+ } else {
+ /* Send 0.0 to indicate no support */
+ majorVersion = 0;
+ minorVersion = 0;
+ os.writeU8(majorVersion);
+ os.writeU8(minorVersion);
+ os.flush();
+ throw new Exception("Server reported an unsupported VeNCrypt version");
+ }
+
+ haveSentVersion = true;
+ return false;
+ }
+
+ /* Check that the server is OK */
+ if (!haveAgreedVersion) {
+ if (is.readU8() != 0)
+ throw new Exception("Server reported it could not support the VeNCrypt version");
+
+ haveAgreedVersion = true;
+ return false;
+ }
+
+ /* get a number of types */
+ if (!haveNumberOfTypes) {
+ nAvailableTypes = is.readU8();
+ iAvailableType = 0;
+
+ if (nAvailableTypes <= 0)
+ throw new Exception("The server reported no VeNCrypt sub-types");
+
+ availableTypes = new int[nAvailableTypes];
+ haveNumberOfTypes = true;
+ return false;
+ }
+
+ if (nAvailableTypes > 0) {
+ /* read in the types possible */
+ if (!haveListOfTypes) {
+ if (is.checkNoWait(4)) {
+ availableTypes[iAvailableType++] = is.readU32();
+ haveListOfTypes = (iAvailableType >= nAvailableTypes);
+ vlog.debug("Server offers security type "+
+ Security.secTypeName(availableTypes[iAvailableType - 1])+" ("+
+ availableTypes[iAvailableType - 1]+")");
+
+ if (!haveListOfTypes)
+ return false;
+
+ } else
+ return false;
+ }
+
+ /* make a choice and send it to the server, meanwhile set up the stack */
+ if (!haveChosenType) {
+ chosenType = Security.secTypeInvalid;
+ int i;
+ Iterator j;
+ List<Integer> secTypes = new ArrayList<Integer>();
+
+ secTypes = security.GetEnabledExtSecTypes();
+
+ /* Honor server's security type order */
+ for (i = 0; i < nAvailableTypes; i++) {
+ for (j = secTypes.iterator(); j.hasNext(); ) {
+ int refType = (Integer)j.next();
+ if (refType == availableTypes[i]) {
+ chosenType = refType;
+ break;
+ }
+ }
+
+ if (chosenType != Security.secTypeInvalid)
+ break;
+ }
+
+ vlog.debug("Choosing security type "+Security.secTypeName(chosenType)+
+ " ("+chosenType+")");
+
+ /* Set up the stack according to the chosen type: */
+ if (chosenType == Security.secTypeInvalid || chosenType == Security.secTypeVeNCrypt)
+ throw new AuthFailureException("No valid VeNCrypt sub-type");
+
+ csecurity = security.GetCSecurity(chosenType);
+
+ /* send chosen type to server */
+ os.writeU32(chosenType);
+ os.flush();
+
+ haveChosenType = true;
+ }
+ } else {
+ /*
+ * Server told us that there are 0 types it can support - this should not
+ * happen, since if the server supports 0 sub-types, it doesn't support
+ * this security type
+ */
+ throw new AuthFailureException("The server reported 0 VeNCrypt sub-types");
+ }
+
+ return csecurity.processMsg(cc);
+ }
+
+ public final int getType() { return chosenType; }
+ public final String description() { return Security.secTypeName(chosenType); }
+
+ public static StringParameter secTypesStr;
+
+ private CSecurity csecurity;
+ SecurityClient security;
+ private boolean haveRecvdMajorVersion;
+ private boolean haveRecvdMinorVersion;
+ private boolean haveSentVersion;
+ private boolean haveAgreedVersion;
+ private boolean haveListOfTypes;
+ private boolean haveNumberOfTypes;
+ private boolean haveChosenType;
+ private int majorVersion, minorVersion;
+ private int chosenType;
+ private int nAvailableTypes;
+ private int[] availableTypes;
+ private int iAvailableType;
+ //private final String desc;
+
+ static LogWriter vlog = new LogWriter("CSecurityVeNCrypt");
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityVncAuth.java b/java/src/com/tigervnc/rfb/CSecurityVncAuth.java
new file mode 100644
index 00000000..f047f530
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/CSecurityVncAuth.java
@@ -0,0 +1,60 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityVncAuth extends CSecurity {
+
+ public CSecurityVncAuth() { }
+
+ private static final int vncAuthChallengeSize = 16;
+
+ public boolean processMsg(CConnection cc)
+ {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ // Read the challenge & obtain the user's password
+ byte[] challenge = new byte[vncAuthChallengeSize];
+ is.readBytes(challenge, 0, vncAuthChallengeSize);
+ StringBuffer passwd = new StringBuffer();
+ CConn.upg.getUserPasswd(null, passwd);
+
+ // Calculate the correct response
+ byte[] key = new byte[8];
+ int pwdLen = passwd.length();
+ for (int i=0; i<8; i++)
+ key[i] = i<pwdLen ? (byte)passwd.charAt(i) : 0;
+ DesCipher des = new DesCipher(key);
+ for (int j = 0; j < vncAuthChallengeSize; j += 8)
+ des.encrypt(challenge,j,challenge,j);
+
+ // Return the response to the server
+ os.writeBytes(challenge, 0, vncAuthChallengeSize);
+ os.flush();
+ return true;
+ }
+
+ public int getType() { return Security.secTypeVncAuth; }
+ public String description() { return "No Encryption"; }
+
+ static LogWriter vlog = new LogWriter("VncAuth");
+}
diff --git a/java/src/com/tigervnc/rfb/Configuration.java b/java/src/com/tigervnc/rfb/Configuration.java
new file mode 100644
index 00000000..bc676087
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Configuration.java
@@ -0,0 +1,91 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// Configuration - class for dealing with configuration parameters.
+//
+
+package com.tigervnc.rfb;
+
+public class Configuration {
+
+ // - Set named parameter to value
+ public static boolean setParam(String name, String value) {
+ VoidParameter param = getParam(name);
+ if (param == null) return false;
+ return param.setParam(value);
+ }
+
+ // - Set parameter to value (separated by "=")
+ public static boolean setParam(String config) {
+ boolean hyphen = false;
+ if (config.charAt(0) == '-') {
+ hyphen = true;
+ if (config.charAt(1) == '-')
+ config = config.substring(2); // allow gnu-style --<option>
+ else
+ config = config.substring(1);
+ }
+ int equal = config.indexOf('=');
+ if (equal != -1) {
+ return setParam(config.substring(0, equal), config.substring(equal+1));
+ } else if (hyphen) {
+ VoidParameter param = getParam(config);
+ if (param == null) return false;
+ return param.setParam();
+ }
+ return false;
+ }
+
+ // - Get named parameter
+ public static VoidParameter getParam(String name) {
+ VoidParameter current = head;
+ while (current != null) {
+ if (name.equalsIgnoreCase(current.getName()))
+ return current;
+ current = current.next;
+ }
+ return null;
+ }
+
+ public static String listParams() {
+ StringBuffer s = new StringBuffer();
+
+ VoidParameter current = head;
+ while (current != null) {
+ String def_str = current.getDefaultStr();
+ String desc = current.getDescription();
+ s.append(" "+current.getName()+" - "+desc+" (default="+def_str+")\n");
+ current = current.next;
+ }
+
+ return s.toString();
+ }
+
+ public static void readAppletParams(java.applet.Applet applet) {
+ VoidParameter current = head;
+ while (current != null) {
+ String str = applet.getParameter(current.getName());
+ if (str != null)
+ current.setParam(str);
+ current = current.next;
+ }
+ }
+
+ public static VoidParameter head;
+}
diff --git a/java/src/com/tigervnc/rfb/ConnFailedException.java b/java/src/com/tigervnc/rfb/ConnFailedException.java
new file mode 100644
index 00000000..d1ddcb4e
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/ConnFailedException.java
@@ -0,0 +1,23 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class ConnFailedException extends Exception {
+ public ConnFailedException(String s) { super(s); }
+}
diff --git a/java/src/com/tigervnc/rfb/ConnParams.java b/java/src/com/tigervnc/rfb/ConnParams.java
new file mode 100644
index 00000000..77acea0e
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/ConnParams.java
@@ -0,0 +1,172 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class ConnParams {
+ static LogWriter vlog = new LogWriter("ConnParams");
+
+ public ConnParams() {
+ majorVersion = 0; minorVersion = 0;
+ width = 0; height = 0; useCopyRect = false;
+ supportsLocalCursor = false; supportsLocalXCursor = false;
+ supportsDesktopResize = false; supportsExtendedDesktopSize = false;
+ supportsDesktopRename = false; supportsLastRect = false;
+ supportsSetDesktopSize = false;
+ customCompressLevel = false; compressLevel = 6;
+ noJpeg = false; qualityLevel = -1;
+ name_ = null; nEncodings_ = 0; encodings_ = null;
+ currentEncoding_ = Encodings.encodingRaw; verStrPos = 0;
+
+ setName("");
+ }
+
+ public boolean readVersion(InStream is, boolean done) {
+ if (verStrPos >= 12) return false;
+ byte[] verStr = new byte[13];
+ while (verStrPos < 12) {
+ verStr[verStrPos++] = (byte)is.readU8();
+ }
+
+ if (verStrPos < 12) {
+ done = false;
+ return true;
+ }
+ done = true;
+ verStr[12] = 0;
+ majorVersion = (verStr[4] - '0') * 100 + (verStr[5] - '0') * 10 + (verStr[6] - '0');
+ minorVersion = (verStr[8] - '0') * 100 + (verStr[9] - '0') * 10 + (verStr[10] - '0');
+ verStrPos = 0;
+ return true;
+ }
+
+ public void writeVersion(OutStream os) {
+ byte[] b = new byte[12];
+ b[0] = (byte)'R'; b[1] = (byte)'F'; b[2] = (byte)'B'; b[3] = (byte)' ';
+ b[4] = (byte)('0' + (majorVersion / 100) % 10);
+ b[5] = (byte)('0' + (majorVersion / 10) % 10);
+ b[6] = (byte)('0' + majorVersion % 10);
+ b[7] = (byte)'.';
+ b[8] = (byte)('0' + (minorVersion / 100) % 10);
+ b[9] = (byte)('0' + (minorVersion / 10) % 10);
+ b[10] = (byte)('0' + minorVersion % 10);
+ b[11] = (byte)'\n';
+ os.writeBytes(b, 0, 12);
+ os.flush();
+ }
+
+ public int majorVersion;
+ public int minorVersion;
+
+ public void setVersion(int major, int minor) {
+ majorVersion = major; minorVersion = minor;
+ }
+ public boolean isVersion(int major, int minor) {
+ return majorVersion == major && minorVersion == minor;
+ }
+ public boolean beforeVersion(int major, int minor) {
+ return (majorVersion < major ||
+ (majorVersion == major && minorVersion < minor));
+ }
+ public boolean afterVersion(int major, int minor) {
+ return !beforeVersion(major,minor+1);
+ }
+
+ public int width;
+ public int height;
+ public ScreenSet screenLayout;
+
+ public PixelFormat pf() { return pf_; }
+ public void setPF(PixelFormat pf) {
+ pf_ = pf;
+ if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) {
+ throw new Exception("setPF: not 8, 16 or 32 bpp?");
+ }
+ }
+
+ public String name() { return name_; }
+ public void setName(String name)
+ {
+ name_ = name;
+ }
+
+ public int currentEncoding() { return currentEncoding_; }
+ public int nEncodings() { return nEncodings_; }
+ public int[] encodings() { return encodings_; }
+ public void setEncodings(int nEncodings, int[] encodings)
+ {
+ if (nEncodings > nEncodings_) {
+ encodings_ = new int[nEncodings];
+ }
+ nEncodings_ = nEncodings;
+ useCopyRect = false;
+ supportsLocalCursor = false;
+ supportsDesktopResize = false;
+ customCompressLevel = false;
+ compressLevel = -1;
+ noJpeg = true;
+ qualityLevel = -1;
+ currentEncoding_ = Encodings.encodingRaw;
+
+ for (int i = nEncodings-1; i >= 0; i--) {
+ encodings_[i] = encodings[i];
+ if (encodings[i] == Encodings.encodingCopyRect)
+ useCopyRect = true;
+ else if (encodings[i] == Encodings.pseudoEncodingCursor)
+ supportsLocalCursor = true;
+ else if (encodings[i] == Encodings.pseudoEncodingDesktopSize)
+ supportsDesktopResize = true;
+ else if (encodings[i] >= Encodings.pseudoEncodingCompressLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingCompressLevel9) {
+ customCompressLevel = true;
+ compressLevel = encodings[i] - Encodings.pseudoEncodingCompressLevel0;
+ } else if (encodings[i] >= Encodings.pseudoEncodingQualityLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingQualityLevel9) {
+ noJpeg = false;
+ qualityLevel = encodings[i] - Encodings.pseudoEncodingQualityLevel0;
+ } else if (encodings[i] <= Encodings.encodingMax &&
+ Encoder.supported(encodings[i]))
+ currentEncoding_ = encodings[i];
+ }
+ }
+ public boolean useCopyRect;
+
+ public boolean supportsLocalCursor;
+ public boolean supportsLocalXCursor;
+ public boolean supportsDesktopResize;
+ public boolean supportsExtendedDesktopSize;
+ public boolean supportsDesktopRename;
+ public boolean supportsLastRect;
+
+ public boolean supportsSetDesktopSize;
+
+ public boolean customCompressLevel;
+ public int compressLevel;
+ public boolean noJpeg;
+ public int qualityLevel;
+
+ private PixelFormat pf_;
+ private String name_;
+ private int nEncodings_;
+ private int[] encodings_;
+ private int currentEncoding_;
+ private String verStr;
+ private int verStrPos;
+}
diff --git a/java/src/com/tigervnc/rfb/Cursor.java b/java/src/com/tigervnc/rfb/Cursor.java
new file mode 100644
index 00000000..420eb82a
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Cursor.java
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import java.awt.*;
+
+public class Cursor extends ManagedPixelBuffer {
+
+ public void setSize(int w, int h) {
+ super.setSize(w, h);
+ if (mask == null || mask.length < maskLen())
+ mask = new byte[maskLen()];
+ }
+ public int maskLen() { return (width() + 7) / 8 * height(); }
+
+ public Point hotspot;
+ public byte[] mask;
+}
diff --git a/java/src/com/tigervnc/rfb/Decoder.java b/java/src/com/tigervnc/rfb/Decoder.java
new file mode 100644
index 00000000..8d42ea5e
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Decoder.java
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+abstract public class Decoder {
+
+ abstract public void readRect(Rect r, CMsgHandler handler);
+
+ static public boolean supported(int encoding)
+ {
+/*
+ return encoding <= Encodings.encodingMax && createFns[encoding];
+*/
+ return (encoding == Encodings.encodingRaw ||
+ encoding == Encodings.encodingRRE ||
+ encoding == Encodings.encodingHextile ||
+ encoding == Encodings.encodingTight ||
+ encoding == Encodings.encodingZRLE);
+ }
+ static public Decoder createDecoder(int encoding, CMsgReader reader) {
+/*
+ if (encoding <= Encodings.encodingMax && createFns[encoding])
+ return (createFns[encoding])(reader);
+ return 0;
+*/
+ switch(encoding) {
+ case Encodings.encodingRaw: return new RawDecoder(reader);
+ case Encodings.encodingRRE: return new RREDecoder(reader);
+ case Encodings.encodingHextile: return new HextileDecoder(reader);
+ case Encodings.encodingTight: return new TightDecoder(reader);
+ case Encodings.encodingZRLE: return new ZRLEDecoder(reader);
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/tigervnc/vncviewer/DesCipher.java b/java/src/com/tigervnc/rfb/DesCipher.java
index 25362fee..f7ae9db9 100644
--- a/java/src/com/tigervnc/vncviewer/DesCipher.java
+++ b/java/src/com/tigervnc/rfb/DesCipher.java
@@ -70,10 +70,6 @@
// fine Java utilities: http://www.acme.com/java/
-package com.tigervnc.vncviewer;
-
-import java.io.*;
-
/// The DES encryption method.
// <P>
// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
@@ -90,6 +86,8 @@ import java.io.*;
// @see EncryptedOutputStream
// @see EncryptedInputStream
+package com.tigervnc.rfb;
+
public class DesCipher
{
diff --git a/java/src/com/tigervnc/rfb/Encoder.java b/java/src/com/tigervnc/rfb/Encoder.java
new file mode 100644
index 00000000..0964f88e
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Encoder.java
@@ -0,0 +1,25 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Encoder {
+ static public boolean supported(int encoding) {
+ return false;
+ }
+}
diff --git a/java/src/com/tigervnc/rfb/Encodings.java b/java/src/com/tigervnc/rfb/Encodings.java
new file mode 100644
index 00000000..215178dc
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Encodings.java
@@ -0,0 +1,69 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Encodings {
+
+ public static final int encodingRaw = 0;
+ public static final int encodingCopyRect = 1;
+ public static final int encodingRRE = 2;
+ public static final int encodingCoRRE = 4;
+ public static final int encodingHextile = 5;
+ public static final int encodingTight = 7;
+ public static final int encodingZRLE = 16;
+
+ public static final int encodingMax = 255;
+
+ public static final int pseudoEncodingXCursor = -240;
+ public static final int pseudoEncodingCursor = -239;
+ public static final int pseudoEncodingDesktopSize = -223;
+ public static final int pseudoEncodingExtendedDesktopSize = -308;
+ public static final int pseudoEncodingDesktopName = -307;
+
+ // TightVNC-specific
+ public static final int pseudoEncodingLastRect = -224;
+ public static final int pseudoEncodingQualityLevel0 = -32;
+ public static final int pseudoEncodingQualityLevel9 = -23;
+ public static final int pseudoEncodingCompressLevel0 = -256;
+ public static final int pseudoEncodingCompressLevel9 = -247;
+
+ public static int encodingNum(String name) {
+ if (name.equalsIgnoreCase("raw")) return encodingRaw;
+ if (name.equalsIgnoreCase("copyRect")) return encodingCopyRect;
+ if (name.equalsIgnoreCase("RRE")) return encodingRRE;
+ if (name.equalsIgnoreCase("coRRE")) return encodingCoRRE;
+ if (name.equalsIgnoreCase("hextile")) return encodingHextile;
+ if (name.equalsIgnoreCase("Tight")) return encodingTight;
+ if (name.equalsIgnoreCase("ZRLE")) return encodingZRLE;
+ return -1;
+ }
+
+ public static String encodingName(int num) {
+ switch (num) {
+ case encodingRaw: return "raw";
+ case encodingCopyRect: return "copyRect";
+ case encodingRRE: return "RRE";
+ case encodingCoRRE: return "CoRRE";
+ case encodingHextile: return "hextile";
+ case encodingTight: return "Tight";
+ case encodingZRLE: return "ZRLE";
+ default: return "[unknown encoding]";
+ }
+ }
+}
diff --git a/java/src/com/tigervnc/rfb/Exception.java b/java/src/com/tigervnc/rfb/Exception.java
new file mode 100644
index 00000000..26ac355b
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Exception.java
@@ -0,0 +1,23 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Exception extends com.tigervnc.rdr.Exception {
+ public Exception(String s) { super(s); }
+}
diff --git a/java/src/com/tigervnc/rfb/Hextile.java b/java/src/com/tigervnc/rfb/Hextile.java
new file mode 100644
index 00000000..9c05b729
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Hextile.java
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Hextile {
+ public static final int raw = (1 << 0);
+ public static final int bgSpecified = (1 << 1);
+ public static final int fgSpecified = (1 << 2);
+ public static final int anySubrects = (1 << 3);
+ public static final int subrectsColoured = (1 << 4);
+}
diff --git a/java/src/com/tigervnc/rfb/HextileDecoder.java b/java/src/com/tigervnc/rfb/HextileDecoder.java
new file mode 100644
index 00000000..4c32b52c
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/HextileDecoder.java
@@ -0,0 +1,101 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class HextileDecoder extends Decoder {
+
+ public HextileDecoder(CMsgReader reader_) { reader = reader_; }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ InStream is = reader.getInStream();
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+
+ int[] buf = reader.getImageBuf(16 * 16 * 4);
+
+ Rect t = new Rect();
+ int bg = 0;
+ int fg = 0;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+ t.br.y = Math.min(r.br.y, t.tl.y + 16);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+
+ t.br.x = Math.min(r.br.x, t.tl.x + 16);
+
+ int tileType = is.readU8();
+
+ if ((tileType & Hextile.raw) != 0) {
+ is.readPixels(buf, t.area(), bytesPerPixel, bigEndian);
+ handler.imageRect(t, buf);
+ continue;
+ }
+
+ if ((tileType & Hextile.bgSpecified) != 0)
+ bg = is.readPixel(bytesPerPixel, bigEndian);
+
+ int len = t.area();
+ int ptr = 0;
+ while (len-- > 0) buf[ptr++] = bg;
+
+ if ((tileType & Hextile.fgSpecified) != 0)
+ fg = is.readPixel(bytesPerPixel, bigEndian);
+
+ if ((tileType & Hextile.anySubrects) != 0) {
+ int nSubrects = is.readU8();
+
+ for (int i = 0; i < nSubrects; i++) {
+
+ if ((tileType & Hextile.subrectsColoured) != 0)
+ fg = is.readPixel(bytesPerPixel, bigEndian);
+
+ int xy = is.readU8();
+ int wh = is.readU8();
+
+/*
+ Rect s = new Rect();
+ s.tl.x = t.tl.x + ((xy >> 4) & 15);
+ s.tl.y = t.tl.y + (xy & 15);
+ s.br.x = s.tl.x + ((wh >> 4) & 15) + 1;
+ s.br.y = s.tl.y + (wh & 15) + 1;
+*/
+ int x = ((xy >> 4) & 15);
+ int y = (xy & 15);
+ int w = ((wh >> 4) & 15) + 1;
+ int h = (wh & 15) + 1;
+ ptr = y * t.width() + x;
+ int rowAdd = t.width() - w;
+ while (h-- > 0) {
+ len = w;
+ while (len-- > 0) buf[ptr++] = fg;
+ ptr += rowAdd;
+ }
+ }
+ }
+ handler.imageRect(t, buf);
+ }
+ }
+ }
+
+ CMsgReader reader;
+}
diff --git a/java/src/com/tigervnc/rfb/Hostname.java b/java/src/com/tigervnc/rfb/Hostname.java
new file mode 100644
index 00000000..42fda537
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Hostname.java
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Hostname {
+
+ public static String getHost(String vncServerName) {
+ int colonPos = vncServerName.indexOf(':');
+ if (colonPos == 0)
+ return "localhost";
+ if (colonPos == -1)
+ colonPos = vncServerName.length();
+ return vncServerName.substring(0, colonPos);
+ }
+
+ public static int getPort(String vncServerName) {
+ int colonPos = vncServerName.indexOf(':');
+ if (colonPos == -1 || colonPos == vncServerName.length()-1)
+ return 5900;
+ if (vncServerName.charAt(colonPos+1) == ':') {
+ return Integer.parseInt(vncServerName.substring(colonPos+2));
+ }
+ return Integer.parseInt(vncServerName.substring(colonPos+1)) + 5900;
+ }
+}
diff --git a/java/src/com/tigervnc/rfb/IntParameter.java b/java/src/com/tigervnc/rfb/IntParameter.java
new file mode 100644
index 00000000..877063e7
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/IntParameter.java
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class IntParameter extends VoidParameter {
+ public IntParameter(String name_, String desc_, int v) {
+ super(name_, desc_);
+ value = v;
+ defValue = v;
+ }
+
+ public boolean setParam(String v) {
+ try {
+ value = Integer.parseInt(v);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public String getDefaultStr() { return Integer.toString(defValue); }
+ public String getValueStr() { return Integer.toString(value); }
+
+ public int getValue() { return value; }
+
+ protected int value;
+ protected int defValue;
+}
diff --git a/java/src/com/tigervnc/rfb/Keysyms.java b/java/src/com/tigervnc/rfb/Keysyms.java
new file mode 100644
index 00000000..6bfafeaf
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Keysyms.java
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// Keysyms - defines X keysyms for non-character keys. All keysyms
+// corresponding to characters should be generated by calling
+// UnicodeToKeysym.translate().
+//
+
+package com.tigervnc.rfb;
+
+public class Keysyms {
+
+ public static final int BackSpace = 0xFF08;
+ public static final int Tab = 0xFF09;
+ public static final int Linefeed = 0xFF0A;
+ public static final int Clear = 0xFF0B;
+ public static final int Return = 0xFF0D;
+ public static final int Pause = 0xFF13;
+ public static final int Scroll_Lock = 0xFF14;
+ public static final int Sys_Req = 0xFF15;
+ public static final int Escape = 0xFF1B;
+ public static final int Delete = 0xFFFF;
+
+ public static final int Home = 0xFF50;
+ public static final int Left = 0xFF51;
+ public static final int Up = 0xFF52;
+ public static final int Right = 0xFF53;
+ public static final int Down = 0xFF54;
+ public static final int Prior = 0xFF55;
+ public static final int Page_Up = 0xFF55;
+ public static final int Next = 0xFF56;
+ public static final int Page_Down = 0xFF56;
+ public static final int End = 0xFF57;
+ public static final int Begin = 0xFF58;
+
+ public static final int Select = 0xFF60;
+ public static final int Print = 0xFF61;
+ public static final int Execute = 0xFF62;
+ public static final int Insert = 0xFF63;
+ public static final int Undo = 0xFF65;
+ public static final int Redo = 0xFF66;
+ public static final int Menu = 0xFF67;
+ public static final int Find = 0xFF68;
+ public static final int Cancel = 0xFF69;
+ public static final int Help = 0xFF6A;
+ public static final int Break = 0xFF6B;
+ public static final int Mode_switch = 0xFF7E;
+ public static final int script_switch = 0xFF7E;
+ public static final int Num_Lock = 0xFF7F;
+
+ public static final int F1 = 0xFFBE;
+ public static final int F2 = 0xFFBF;
+ public static final int F3 = 0xFFC0;
+ public static final int F4 = 0xFFC1;
+ public static final int F5 = 0xFFC2;
+ public static final int F6 = 0xFFC3;
+ public static final int F7 = 0xFFC4;
+ public static final int F8 = 0xFFC5;
+ public static final int F9 = 0xFFC6;
+ public static final int F10 = 0xFFC7;
+ public static final int F11 = 0xFFC8;
+ public static final int F12 = 0xFFC9;
+
+ public static final int Shift_L = 0xFFE1;
+ public static final int Shift_R = 0xFFE2;
+ public static final int Control_L = 0xFFE3;
+ public static final int Control_R = 0xFFE4;
+ public static final int Meta_L = 0xFFE7;
+ public static final int Meta_R = 0xFFE8;
+ public static final int Alt_L = 0xFFE9;
+ public static final int Alt_R = 0xFFEA;
+}
diff --git a/java/src/com/tigervnc/rfb/LogWriter.java b/java/src/com/tigervnc/rfb/LogWriter.java
new file mode 100644
index 00000000..c5730531
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/LogWriter.java
@@ -0,0 +1,99 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class LogWriter {
+
+ public LogWriter(String name_) {
+ name = name_;
+ level = globalLogLevel;
+ next = log_writers;
+ log_writers = this;
+ }
+
+ public void setLevel(int level_) { level = level_; }
+
+ public void write(int level, String str) {
+ if (level <= this.level) {
+ System.err.println(name+": "+str);
+ }
+ }
+
+ public void error(String str) { write(0, str); }
+ public void status(String str) { write(10, str); }
+ public void info(String str) { write(30, str); }
+ public void debug(String str) { write(100, str); }
+
+ public static boolean setLogParams(String params) {
+ globalLogLevel = Integer.parseInt(params);
+ LogWriter current = log_writers;
+ while (current != null) {
+ current.setLevel(globalLogLevel);
+ current = current.next;
+ }
+ return true;
+// int colon = params.indexOf(':');
+// String logwriter_name = params.substring(0, colon);
+// params = params.substring(colon+1);
+// colon = params.indexOf(':');
+// String logger_name = params.substring(0, colon);
+// params = params.substring(colon+1);
+// int level = Integer.parseInt(params);
+// // XXX ignore logger name for the moment
+
+// System.err.println("setting level to "+level);
+// System.err.println("logwriters is "+log_writers);
+// if (logwriter_name.equals("*")) {
+// LogWriter current = log_writers;
+// while (current != null) {
+// //current.setLog(logger);
+// System.err.println("setting level of "+current.name+" to "+level);
+// current.setLevel(level);
+// current = current.next;
+// }
+// return true;
+// }
+
+// LogWriter logwriter = getLogWriter(logwriter_name);
+// if (logwriter == null) {
+// System.err.println("no logwriter found: "+logwriter_name);
+// return false;
+// }
+
+// //logwriter.setLog(logger);
+// logwriter.setLevel(level);
+// return true;
+ }
+
+
+ static LogWriter getLogWriter(String name) {
+ LogWriter current = log_writers;
+ while (current != null) {
+ if (name.equalsIgnoreCase(current.name)) return current;
+ current = current.next;
+ }
+ return null;
+ }
+
+ String name;
+ int level;
+ LogWriter next;
+ static LogWriter log_writers;
+ static int globalLogLevel = 30;
+}
diff --git a/java/src/com/tigervnc/rfb/ManagedPixelBuffer.java b/java/src/com/tigervnc/rfb/ManagedPixelBuffer.java
new file mode 100644
index 00000000..46b5acf7
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/ManagedPixelBuffer.java
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class ManagedPixelBuffer extends PixelBuffer {
+ public void setSize(int w, int h) {
+ width_ = w;
+ height_ = h;
+ checkDataSize();
+ }
+ public void setPF(PixelFormat pf) {
+ super.setPF(pf);
+ checkDataSize();
+ }
+
+ public int dataLen() { return area(); }
+
+ final void checkDataSize() {
+ if (data == null || data.length < dataLen())
+ data = new int[dataLen()];
+ }
+}
diff --git a/java/src/com/tigervnc/rfb/MsgTypes.java b/java/src/com/tigervnc/rfb/MsgTypes.java
new file mode 100644
index 00000000..a009b396
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/MsgTypes.java
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class MsgTypes {
+ // server to client
+
+ public static final int msgTypeFramebufferUpdate = 0;
+ public static final int msgTypeSetColourMapEntries = 1;
+ public static final int msgTypeBell = 2;
+ public static final int msgTypeServerCutText = 3;
+
+ // client to server
+
+ public static final int msgTypeSetPixelFormat = 0;
+ public static final int msgTypeFixColourMapEntries = 1;
+ public static final int msgTypeSetEncodings = 2;
+ public static final int msgTypeFramebufferUpdateRequest = 3;
+ public static final int msgTypeKeyEvent = 4;
+ public static final int msgTypePointerEvent = 5;
+ public static final int msgTypeClientCutText = 6;
+
+ public static final int msgTypeSetDesktopSize = 251;
+}
diff --git a/java/src/com/tigervnc/rfb/PixelBuffer.java b/java/src/com/tigervnc/rfb/PixelBuffer.java
new file mode 100644
index 00000000..f87fead8
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/PixelBuffer.java
@@ -0,0 +1,116 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// PixelBuffer - note that this code is only written for the 8, 16, and 32 bpp cases at the
+// moment.
+//
+
+package com.tigervnc.rfb;
+
+import java.awt.image.*;
+
+public class PixelBuffer {
+
+ public PixelBuffer() {
+ setPF(new PixelFormat());
+ }
+
+ public void setPF(PixelFormat pf) {
+ if (!(pf.bpp == 32) && !(pf.bpp == 16) && !(pf.bpp == 8))
+ throw new Exception("Internal error: bpp must be 8, 16, or 32 in PixelBuffer ("+pf.bpp+")");
+ format = pf;
+ switch (pf.depth) {
+ case 8:
+ //cm = new IndexColorModel(8, 256, new byte[256], new byte[256], new byte[256]);
+ cm = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
+ break;
+ case 16:
+ cm = new DirectColorModel(32, 0xF800, 0x07C0, 0x003E, (0xff << 24));
+ break;
+ case 24:
+ cm = new DirectColorModel(32, (0xff << 16), (0xff << 8), 0xff, (0xff << 24));
+ break;
+ }
+ }
+ public PixelFormat getPF() { return format; }
+
+ public final int width() { return width_; }
+ public final int height() { return height_; }
+ public final int area() { return width_ * height_; }
+
+ public void fillRect(int x, int y, int w, int h, int pix) {
+ for (int ry = y; ry < y + h; ry++)
+ for (int rx = x; rx < x + w; rx++)
+ data[ry * width_ + rx] = pix;
+ }
+
+ public void imageRect(int x, int y, int w, int h, int[] pix) {
+ for (int j = 0; j < h; j++)
+ System.arraycopy(pix, (w * j), data, width_ * (y + j) + x, w);
+ }
+
+ public void copyRect(int x, int y, int w, int h, int srcX, int srcY) {
+ int dest = (width_ * y) + x;
+ int src = (width_ * srcY) + srcX;
+ int inc = width_;
+
+ if (y > srcY) {
+ src += (h-1) * inc;
+ dest += (h-1) * inc;
+ inc = -inc;
+ }
+ int destEnd = dest + h * inc;
+
+ while (dest != destEnd) {
+ System.arraycopy(data, src, data, dest, w);
+ src += inc;
+ dest += inc;
+ }
+ }
+
+ public void maskRect(int x, int y, int w, int h, int[] pix, byte[] mask) {
+ int maskBytesPerRow = (w + 7) / 8;
+
+ for (int j = 0; j < h; j++) {
+ int cy = y + j;
+
+ if (cy < 0 || cy >= height_)
+ continue;
+
+ for (int i = 0; i < w; i++) {
+ int cx = x + i;
+
+ if (cx < 0 || cx >= width_)
+ continue;
+
+ int byte_ = j * maskBytesPerRow + i / 8;
+ int bit = 7 - i % 8;
+
+ if ((mask[byte_] & (1 << bit)) != 0)
+ data[cy * width_ + cx] = pix[j * w + i];
+ }
+ }
+ }
+
+ public int[] data;
+ public ColorModel cm;
+
+ protected PixelFormat format;
+ protected int width_, height_;
+}
diff --git a/java/src/com/tigervnc/rfb/PixelFormat.java b/java/src/com/tigervnc/rfb/PixelFormat.java
new file mode 100644
index 00000000..a8ab5f11
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/PixelFormat.java
@@ -0,0 +1,163 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// PixelFormat
+//
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class PixelFormat {
+
+ public PixelFormat(int b, int d, boolean e, boolean t) {
+ bpp = b;
+ depth = d;
+ bigEndian = e;
+ trueColour = t;
+ }
+ public PixelFormat(int b, int d, boolean e, boolean t,
+ int rm, int gm, int bm, int rs, int gs, int bs) {
+ this(b, d, e, t);
+ redMax = rm;
+ greenMax = gm;
+ blueMax = bm;
+ redShift = rs;
+ greenShift = gs;
+ blueShift = bs;
+ }
+ public PixelFormat() { this(8,8,false,true,7,7,3,0,3,6); }
+
+ public boolean equal(PixelFormat x) {
+ return (bpp == x.bpp &&
+ depth == x.depth &&
+ (bigEndian == x.bigEndian || bpp == 8) &&
+ trueColour == x.trueColour &&
+ (!trueColour || (redMax == x.redMax &&
+ greenMax == x.greenMax &&
+ blueMax == x.blueMax &&
+ redShift == x.redShift &&
+ greenShift == x.greenShift &&
+ blueShift == x.blueShift)));
+ }
+
+ public void read(InStream is) {
+ bpp = is.readU8();
+ depth = is.readU8();
+ bigEndian = is.readU8()!=0;
+ trueColour = is.readU8()!=0;
+ redMax = is.readU16();
+ greenMax = is.readU16();
+ blueMax = is.readU16();
+ redShift = is.readU8();
+ greenShift = is.readU8();
+ blueShift = is.readU8();
+ is.skip(3);
+ }
+
+ public void write(OutStream os) {
+ os.writeU8(bpp);
+ os.writeU8(depth);
+ os.writeU8(bigEndian?1:0);
+ os.writeU8(trueColour?1:0);
+ os.writeU16(redMax);
+ os.writeU16(greenMax);
+ os.writeU16(blueMax);
+ os.writeU8(redShift);
+ os.writeU8(greenShift);
+ os.writeU8(blueShift);
+ os.pad(3);
+ }
+
+ public final boolean is888() {
+ if(!trueColour)
+ return false;
+ if(bpp != 32)
+ return false;
+ if(depth != 24)
+ return false;
+ if(redMax != 255)
+ return false;
+ if(greenMax != 255)
+ return false;
+ if(blueMax != 255)
+ return false;
+
+ return true;
+ }
+
+ public void bufferFromRGB(int dst, byte[] src) {
+ if (bigEndian) {
+ dst =
+ (src[0] & 0xFF) << 16 | (src[1] & 0xFF) << 8 | (src[2] & 0xFF) | 0xFF << 24;
+ } else {
+ dst =
+ (src[2] & 0xFF) << 16 | (src[1] & 0xFF) << 8 | (src[0] & 0xFF) | 0xFF << 24;
+ }
+ }
+
+ public String print() {
+ StringBuffer s = new StringBuffer();
+ s.append("depth "+depth+" ("+bpp+"bpp)");
+ if (bpp != 8) {
+ if (bigEndian)
+ s.append(" big-endian");
+ else
+ s.append(" little-endian");
+ }
+
+ if (!trueColour) {
+ s.append(" colour-map");
+ return s.toString();
+ }
+
+ if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
+ blueMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (redShift-greenShift)) - 1 &&
+ redMax == (1 << (depth-redShift)) - 1)
+ {
+ s.append(" rgb"+(depth-redShift)+(redShift-greenShift)+greenShift);
+ return s.toString();
+ }
+
+ if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
+ redMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (blueShift-greenShift)) - 1 &&
+ blueMax == (1 << (depth-blueShift)) - 1)
+ {
+ s.append(" bgr"+(depth-blueShift)+(blueShift-greenShift)+greenShift);
+ return s.toString();
+ }
+
+ s.append(" rgb max "+redMax+","+greenMax+","+blueMax+" shift "+redShift+
+ ","+greenShift+","+blueShift);
+ return s.toString();
+ }
+
+ public int bpp;
+ public int depth;
+ public boolean bigEndian;
+ public boolean trueColour;
+ public int redMax;
+ public int greenMax;
+ public int blueMax;
+ public int redShift;
+ public int greenShift;
+ public int blueShift;
+}
diff --git a/java/src/com/tigervnc/rfb/Point.java b/java/src/com/tigervnc/rfb/Point.java
new file mode 100644
index 00000000..25de8c20
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Point.java
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Point {
+
+ // Point
+ //
+ // Represents a point in 2D space, by X and Y coordinates.
+ // Can also be used to represent a delta, or offset, between
+ // two Points.
+ // Functions are provided to allow Points to be compared for
+ // equality and translated by a supplied offset.
+ // Functions are also provided to negate offset Points.
+
+ public Point() {x=0; y=0;}
+ public Point(int x_, int y_) { x=x_; y=y_;}
+ public final Point negate() {return new Point(-x, -y);}
+ public final boolean equals(Point p) {return (x==p.x && y==p.y);}
+ public final Point translate(Point p) {return new Point(x+p.x, y+p.y);}
+ public final Point subtract(Point p) {return new Point(x-p.x, y-p.y);}
+ public int x, y;
+
+}
diff --git a/java/src/com/tigervnc/rfb/RREDecoder.java b/java/src/com/tigervnc/rfb/RREDecoder.java
new file mode 100644
index 00000000..e0ff5cfe
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/RREDecoder.java
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class RREDecoder extends Decoder {
+
+ public RREDecoder(CMsgReader reader_) { reader = reader_; }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ InStream is = reader.getInStream();
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+ int nSubrects = is.readU32();
+ int bg = is.readPixel(bytesPerPixel, bigEndian);
+ handler.fillRect(r, bg);
+
+ for (int i = 0; i < nSubrects; i++) {
+ int pix = is.readPixel(bytesPerPixel, bigEndian);
+ int x = is.readU16();
+ int y = is.readU16();
+ int w = is.readU16();
+ int h = is.readU16();
+ handler.fillRect(new Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix);
+ }
+ }
+
+ CMsgReader reader;
+}
diff --git a/java/src/com/tigervnc/rfb/RawDecoder.java b/java/src/com/tigervnc/rfb/RawDecoder.java
new file mode 100644
index 00000000..79db8260
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/RawDecoder.java
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class RawDecoder extends Decoder {
+
+ public RawDecoder(CMsgReader reader_) { reader = reader_; }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ int x = r.tl.x;
+ int y = r.tl.y;
+ int w = r.width();
+ int h = r.height();
+ int[] imageBuf = reader.getImageBuf(w * h);
+ int nPixels = imageBuf.length / (reader.bpp() / 8);
+ int bytesPerRow = w * (reader.bpp() / 8);
+ while (h > 0) {
+ int nRows = nPixels / w;
+ if (nRows > h) nRows = h;
+ reader.is.readPixels(imageBuf, w * h, (reader.bpp() / 8), handler.cp.pf().bigEndian);
+ handler.imageRect(new Rect(x, y, x+w, y+nRows), imageBuf);
+ h -= nRows;
+ y += nRows;
+ }
+ }
+
+ CMsgReader reader;
+ static LogWriter vlog = new LogWriter("RawDecoder");
+}
diff --git a/java/src/com/tigervnc/rfb/Rect.java b/java/src/com/tigervnc/rfb/Rect.java
new file mode 100644
index 00000000..fab4f5dd
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Rect.java
@@ -0,0 +1,89 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class Rect {
+
+ // Rect
+ //
+ // Represents a rectangular region defined by its top-left (tl)
+ // and bottom-right (br) Points.
+ // Rects may be compared for equality, checked to determine whether
+ // or not they are empty, cleared (made empty), or intersected with
+ // one another. The bounding rectangle of two existing Rects
+ // may be calculated, as may the area of a Rect.
+ // Rects may also be translated, in the same way as Points, by
+ // an offset specified in a Point structure.
+
+ public Rect() {
+ tl=new Point(0,0);
+ br=new Point(0,0);
+ }
+ public Rect(Point tl_, Point br_) {
+ tl=new Point(tl_.x, tl_.y);
+ br=new Point(br_.x,br_.y);
+ }
+ public Rect(int x1, int y1, int x2, int y2) {
+ tl=new Point(x1, y1);
+ br=new Point(x2, y2);
+ }
+ public final void setXYWH(int x, int y, int w, int h) {
+ tl.x = x; tl.y = y; br.x = x+w; br.y = y+h;
+ }
+ public final Rect intersect(Rect r) {
+ Rect result = new Rect();
+ result.tl.x = Math.max(tl.x, r.tl.x);
+ result.tl.y = Math.max(tl.y, r.tl.y);
+ result.br.x = Math.max(Math.min(br.x, r.br.x), result.tl.x);
+ result.br.y = Math.max(Math.min(br.y, r.br.y), result.tl.y);
+ return result;
+ }
+ public final Rect union_boundary(Rect r) {
+ if (r.is_empty()) return this;
+ if (is_empty()) return r;
+ Rect result = new Rect();
+ result.tl.x = Math.min(tl.x, r.tl.x);
+ result.tl.y = Math.min(tl.y, r.tl.y);
+ result.br.x = Math.max(br.x, r.br.x);
+ result.br.y = Math.max(br.y, r.br.y);
+ return result;
+ }
+ public final Rect translate(Point p) {
+ return new Rect(tl.translate(p), br.translate(p));
+ }
+ public final boolean equals(Rect r) {return r.tl.equals(tl) && r.br.equals(br);}
+ public final boolean is_empty() {return (tl.x >= br.x) || (tl.y >= br.y);}
+ public final void clear() {tl = new Point(); br = new Point();}
+ public final boolean enclosed_by(Rect r) {
+ return (tl.x>=r.tl.x) && (tl.y>=r.tl.y) && (br.x<=r.br.x) && (br.y<=r.br.y);
+ }
+ public final boolean overlaps(Rect r) {
+ return tl.x < r.br.x && tl.y < r.br.y && br.x > r.tl.x && br.y > r.tl.y;
+ }
+ public final int area() {return is_empty() ? 0 : (br.x-tl.x)*(br.y-tl.y);}
+ public final Point dimensions() {return new Point(width(), height());}
+ public final int width() {return br.x-tl.x;}
+ public final int height() {return br.y-tl.y;}
+ public final boolean contains(Point p) {
+ return (tl.x<=p.x) && (tl.y<=p.y) && (br.x>p.x) && (br.y>p.y);
+ }
+ public Point tl;
+ public Point br;
+
+}
diff --git a/java/src/com/tigervnc/rfb/Screen.java b/java/src/com/tigervnc/rfb/Screen.java
new file mode 100644
index 00000000..90b22b6d
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Screen.java
@@ -0,0 +1,48 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// Represents a single RFB virtual screen, which includes
+// coordinates, an id and flags.
+
+package com.tigervnc.rfb;
+
+public class Screen {
+
+ public Screen() { id=0; flags=0; dimensions = new Rect(); }
+
+ public Screen(int id_, int x_, int y_, int w_, int h_, int flags_) {
+ id = id_;
+ dimensions = new Rect(x_, y_, x_+w_, y_+h_);
+ flags = flags_;
+ }
+
+ public final static boolean operator(Screen r) {
+ if (id != r.id)
+ return false;
+ if (!dimensions.equals(r.dimensions))
+ return false;
+ if (flags != r.flags)
+ return false;
+ return true;
+ }
+
+ public static int id;
+ public static Rect dimensions;
+ public static int flags;
+
+}
diff --git a/java/src/com/tigervnc/rfb/ScreenSet.java b/java/src/com/tigervnc/rfb/ScreenSet.java
new file mode 100644
index 00000000..071282ff
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/ScreenSet.java
@@ -0,0 +1,89 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// Management class for the RFB virtual screens
+
+package com.tigervnc.rfb;
+
+import java.util.*;
+
+public class ScreenSet {
+
+ // Represents a complete screen configuration, excluding framebuffer
+ // dimensions.
+
+ public ScreenSet() {
+ screens = new ArrayList<Screen>();
+ }
+
+ public static final int num_screens() { return screens.size(); }
+
+ public static final void add_screen(Screen screen) { screens.add(screen); }
+ public static final void remove_screen(int id) {
+ for (Iterator iter = screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ if (refScreen.id == id)
+ iter.remove();
+ }
+ }
+
+ public static final boolean validate(int fb_width, int fb_height) {
+ List<Integer> seen_ids = new ArrayList<Integer>();
+ Rect fb_rect = new Rect();
+
+ if (screens.isEmpty())
+ return false;
+ if (num_screens() > 255)
+ return false;
+
+ fb_rect.setXYWH(0, 0, fb_width, fb_height);
+
+ for (Iterator iter = screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ if (refScreen.dimensions.is_empty())
+ return false;
+ if (!refScreen.dimensions.enclosed_by(fb_rect))
+ return false;
+ //if (seen_ids.lastIndexOf(refScreen.id) != seen_ids.get(-1))
+ // return false;
+ seen_ids.add(refScreen.id);
+ }
+
+ return true;
+ }
+
+ public final void debug_print() {
+ for (Iterator iter = screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ vlog.error(" "+refScreen.id+" (0x"+refScreen.id+"): "+
+ refScreen.dimensions.width()+"x"+refScreen.dimensions.height()+
+ "+"+refScreen.dimensions.tl.x+"+"+refScreen.dimensions.tl.y+
+ " (flags 0x"+refScreen.flags+")");
+ }
+ }
+
+ // FIXME: List order shouldn't matter
+ //inline bool operator(const ScreenSet& r) const { return screens == r.screens; }
+ //inline bool operator(const ScreenSet& r) const { return screens != r.screens; }
+
+ public static List<Screen> screens;
+
+ static LogWriter vlog = new LogWriter("ScreenSet");
+
+}
+
diff --git a/java/src/com/tigervnc/rfb/Security.java b/java/src/com/tigervnc/rfb/Security.java
new file mode 100644
index 00000000..5e572e3f
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/Security.java
@@ -0,0 +1,189 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// SecTypes.java - constants for the various security types.
+//
+
+package com.tigervnc.rfb;
+import java.util.*;
+
+public class Security {
+
+ public static final int secTypeInvalid = 0;
+ public static final int secTypeNone = 1;
+ public static final int secTypeVncAuth = 2;
+
+ public static final int secTypeRA2 = 5;
+ public static final int secTypeRA2ne = 6;
+
+ public static final int secTypeSSPI = 7;
+ public static final int secTypeSSPIne = 8;
+
+ public static final int secTypeTight = 16;
+ public static final int secTypeUltra = 17;
+ public static final int secTypeTLS = 18;
+ public static final int secTypeVeNCrypt = 19;
+ public static final int secTypeManaged = 20;
+
+ /* VeNCrypt subtypes */
+ public static final int secTypePlain = 256;
+ public static final int secTypeTLSNone = 257;
+ public static final int secTypeTLSVnc = 258;
+ public static final int secTypeTLSPlain = 259;
+ public static final int secTypeX509None = 260;
+ public static final int secTypeX509Vnc = 261;
+ public static final int secTypeX509Plain = 262;
+
+ // result types
+
+ public static final int secResultOK = 0;
+ public static final int secResultFailed = 1;
+ public static final int secResultTooMany = 2; // deprecated
+
+ public Security(StringParameter secTypes)
+ {
+ String secTypesStr;
+
+ secTypesStr = secTypes.getData();
+ enabledSecTypes = parseSecTypes(secTypesStr);
+
+ secTypesStr = null;
+ }
+
+ public static List<Integer> enabledSecTypes = new ArrayList<Integer>();
+
+ public static final List<Integer> GetEnabledSecTypes()
+ {
+ List<Integer> result = new ArrayList<Integer>();
+
+ result.add(secTypeVeNCrypt);
+ for (Iterator i = enabledSecTypes.iterator(); i.hasNext(); ) {
+ int refType = (Integer)i.next();
+ if (refType < 0x100)
+ result.add(refType);
+ }
+
+ return (result);
+ }
+
+ public static final List<Integer> GetEnabledExtSecTypes()
+ {
+ List<Integer> result = new ArrayList<Integer>();
+
+ for (Iterator i = enabledSecTypes.iterator(); i.hasNext(); ) {
+ int refType = (Integer)i.next();
+ if (refType != secTypeVeNCrypt) /* Do not include VeNCrypt to avoid loops */
+ result.add(refType);
+ }
+
+ return (result);
+ }
+
+ public static final void EnableSecType(int secType)
+ {
+
+ for (Iterator i = enabledSecTypes.iterator(); i.hasNext(); )
+ if ((Integer)i.next() == secType)
+ return;
+
+ enabledSecTypes.add(secType);
+ }
+
+ public boolean IsSupported(int secType)
+ {
+ Iterator i;
+
+ for (i = enabledSecTypes.iterator(); i.hasNext(); )
+ if ((Integer)i.next() == secType)
+ return true;
+ if (secType == secTypeVeNCrypt)
+ return true;
+
+ return false;
+ }
+
+ public static void DisableSecType(int secType) { enabledSecTypes.remove(secType); }
+
+ public static int secTypeNum(String name) {
+ if (name.equalsIgnoreCase("None")) return secTypeNone;
+ if (name.equalsIgnoreCase("VncAuth")) return secTypeVncAuth;
+ if (name.equalsIgnoreCase("Tight")) return secTypeTight;
+ if (name.equalsIgnoreCase("RA2")) return secTypeRA2;
+ if (name.equalsIgnoreCase("RA2ne")) return secTypeRA2ne;
+ if (name.equalsIgnoreCase("SSPI")) return secTypeSSPI;
+ if (name.equalsIgnoreCase("SSPIne")) return secTypeSSPIne;
+ //if (name.equalsIgnoreCase("ultra")) return secTypeUltra;
+ //if (name.equalsIgnoreCase("TLS")) return secTypeTLS;
+ if (name.equalsIgnoreCase("VeNCrypt")) return secTypeVeNCrypt;
+ if (name.equalsIgnoreCase("Managed")) return secTypeManaged;
+
+ /* VeNCrypt subtypes */
+ if (name.equalsIgnoreCase("Plain")) return secTypePlain;
+ if (name.equalsIgnoreCase("TLSNone")) return secTypeTLSNone;
+ if (name.equalsIgnoreCase("TLSVnc")) return secTypeTLSVnc;
+ if (name.equalsIgnoreCase("TLSPlain")) return secTypeTLSPlain;
+ if (name.equalsIgnoreCase("X509None")) return secTypeX509None;
+ if (name.equalsIgnoreCase("X509Vnc")) return secTypeX509Vnc;
+ if (name.equalsIgnoreCase("X509Plain")) return secTypeX509Plain;
+
+ return secTypeInvalid;
+ }
+
+ public static String secTypeName(int num) {
+ switch (num) {
+ case secTypeNone: return "None";
+ case secTypeVncAuth: return "VncAuth";
+ case secTypeTight: return "Tight";
+ case secTypeRA2: return "RA2";
+ case secTypeRA2ne: return "RA2ne";
+ case secTypeSSPI: return "SSPI";
+ case secTypeSSPIne: return "SSPIne";
+ //case secTypeUltra: return "Ultra";
+ //case secTypeTLS: return "TLS";
+ case secTypeVeNCrypt: return "VeNCrypt";
+ case secTypeManaged: return "Managed";
+
+ /* VeNCrypt subtypes */
+ case secTypePlain: return "Plain";
+ case secTypeTLSNone: return "TLSNone";
+ case secTypeTLSVnc: return "TLSVnc";
+ case secTypeTLSPlain: return "TLSPlain";
+ case secTypeX509None: return "X509None";
+ case secTypeX509Vnc: return "X509Vnc";
+ case secTypeX509Plain: return "X509Plain";
+ default: return "[unknown secType]";
+ }
+ }
+
+ public final static List<Integer> parseSecTypes(String types_)
+ {
+ List<Integer> result = new ArrayList<Integer>();
+ String[] types = types_.split(",");
+ for (int i = 0; i < types.length; i++) {
+ int typeNum = secTypeNum(types[i]);
+ if (typeNum != secTypeInvalid)
+ result.add(typeNum);
+ }
+ return (result);
+ }
+
+ public final void SetSecTypes(List<Integer> secTypes) { enabledSecTypes = secTypes; }
+
+ static LogWriter vlog = new LogWriter("Security");
+}
diff --git a/java/src/com/tigervnc/rfb/SecurityClient.java b/java/src/com/tigervnc/rfb/SecurityClient.java
new file mode 100644
index 00000000..90c35d81
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/SecurityClient.java
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2010 TigerVNC Team
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class SecurityClient extends Security {
+
+ public SecurityClient() { super(secTypes); }
+
+ public CSecurity GetCSecurity(int secType)
+ {
+ //assert (CSecurity::upg != NULL); /* (upg == NULL) means bug in the viewer */
+ //assert (CSecurityTLS::msg != NULL);
+
+ if (!IsSupported(secType))
+ throw new Exception("Security type not supported");
+
+ switch (secType) {
+ case Security.secTypeManaged: return (new CSecurityManaged());
+ case Security.secTypeNone: return (new CSecurityNone());
+ case Security.secTypeVncAuth: return (new CSecurityVncAuth());
+ case Security.secTypeVeNCrypt: return (new CSecurityVeNCrypt(this));
+ case Security.secTypePlain: return (new CSecurityPlain());
+ case Security.secTypeTLSNone:
+ return (new CSecurityStack(secTypeTLSNone, "TLS with no password",
+ new CSecurityTLS(true), null));
+ case Security.secTypeTLSVnc:
+ return (new CSecurityStack(secTypeTLSVnc, "TLS with VNCAuth",
+ new CSecurityTLS(true), new CSecurityVncAuth()));
+ case Security.secTypeTLSPlain:
+ return (new CSecurityStack(secTypeTLSPlain, "TLS with Username/Password",
+ new CSecurityTLS(true), new CSecurityPlain()));
+ case Security.secTypeX509None:
+ return (new CSecurityStack(secTypeX509None, "X509 with no password",
+ new CSecurityTLS(false), null));
+ case Security.secTypeX509Vnc:
+ return (new CSecurityStack(secTypeX509None, "X509 with VNCAuth",
+ new CSecurityTLS(false), new CSecurityVncAuth()));
+ case Security.secTypeX509Plain:
+ return (new CSecurityStack(secTypeX509Plain, "X509 with Username/Password",
+ new CSecurityTLS(false), new CSecurityPlain()));
+ default:
+ throw new Exception("Security type not supported");
+ }
+
+ }
+
+ public static void setDefaults()
+ {
+ CSecurityTLS.setDefaults();
+ }
+
+ //UserPasswdGetter upg = null;
+ String msg = null;
+
+ static StringParameter secTypes
+ = new StringParameter("SecurityTypes",
+ "Specify which security scheme to use (None, VncAuth)",
+ "Managed,X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,VncAuth,None");
+
+}
diff --git a/java/src/com/tigervnc/rfb/StringParameter.java b/java/src/com/tigervnc/rfb/StringParameter.java
new file mode 100644
index 00000000..4f704d9b
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/StringParameter.java
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class StringParameter extends VoidParameter {
+ public StringParameter(String name_, String desc_, String v) {
+ super(name_, desc_);
+ value = v;
+ defValue = v;
+ }
+
+ public boolean setParam(String v) {
+ value = v;
+ return value != null;
+ }
+
+ public boolean setDefaultStr(String v) {
+ value = defValue = v;
+ return defValue != null;
+ }
+
+ public String getDefaultStr() { return defValue; }
+ public String getValueStr() { return value; }
+
+ public String getValue() { return value; }
+ public String getData() { return value; }
+
+ protected String value;
+ protected String defValue;
+}
diff --git a/java/src/com/tigervnc/rfb/TightDecoder.java b/java/src/com/tigervnc/rfb/TightDecoder.java
new file mode 100644
index 00000000..1065feb6
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/TightDecoder.java
@@ -0,0 +1,427 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ * Copyright (C) 2004-2005 Cendio AB. All rights reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.InStream;
+import com.tigervnc.rdr.ZlibInStream;
+import java.awt.image.PixelGrabber;
+import java.awt.Image;
+import java.util.ArrayList;
+
+public class TightDecoder extends Decoder {
+
+ final static int TIGHT_MAX_WIDTH = 2048;
+
+ // Compression control
+ final static int rfbTightExplicitFilter = 0x04;
+ final static int rfbTightFill = 0x08;
+ final static int rfbTightJpeg = 0x09;
+ final static int rfbTightMaxSubencoding = 0x09;
+
+ // Filters to improve compression efficiency
+ final static int rfbTightFilterCopy = 0x00;
+ final static int rfbTightFilterPalette = 0x01;
+ final static int rfbTightFilterGradient = 0x02;
+ final static int rfbTightMinToCompress = 12;
+
+ public TightDecoder(CMsgReader reader_) {
+ reader = reader_;
+ zis = new ZlibInStream[4];
+ for (int i = 0; i < 4; i++)
+ zis[i] = new ZlibInStream();
+ }
+
+ public void readRect(Rect r, CMsgHandler handler)
+ {
+ InStream is = reader.getInStream();
+ int[] buf = reader.getImageBuf(r.width() * r.height());
+ boolean cutZeros = false;
+ PixelFormat myFormat = handler.cp.pf();
+ int bpp = handler.cp.pf().bpp;
+ if (bpp == 32) {
+ if (myFormat.is888()) {
+ cutZeros = true;
+ }
+ }
+
+ int comp_ctl = is.readU8();
+
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+
+ // Flush zlib streams if we are told by the server to do so.
+ for (int i = 0; i < 4; i++) {
+ if ((comp_ctl & 1) != 0) {
+ zis[i].reset();
+ }
+ comp_ctl >>= 1;
+ }
+
+ // "Fill" compression type.
+ if (comp_ctl == rfbTightFill) {
+ int pix;
+ if (cutZeros) {
+ byte[] elem = new byte[3];
+ is.readBytes(elem, 0, 3);
+ if (bigEndian) {
+ pix =
+ (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
+ } else {
+ pix =
+ (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
+ }
+ } else {
+ pix = (bpp == 8) ? is.readOpaque8() : is.readOpaque24B();
+ }
+ handler.fillRect(r, pix);
+ return;
+ }
+
+ // "JPEG" compression type.
+ if (comp_ctl == rfbTightJpeg) {
+ // Read length
+ int compressedLen = is.readCompactLength();
+ if (compressedLen <= 0)
+ vlog.info("Incorrect data received from the server.");
+
+ // Allocate netbuf and read in data
+ byte[] netbuf = new byte[compressedLen];
+ is.readBytes(netbuf, 0, compressedLen);
+
+ // Create an Image object from the JPEG data.
+ Image jpeg = java.awt.Toolkit.getDefaultToolkit().createImage(netbuf);
+ PixelGrabber pg = new PixelGrabber(jpeg, 0, 0, r.width(), r.height(), true);
+ try {
+ boolean ret = pg.grabPixels();
+ if (!ret)
+ vlog.info("failed to grab pixels");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Object pixels = pg.getPixels();
+ buf = (pixels instanceof byte[]) ?
+ convertByteArrayToIntArray((byte[])pixels) : (int[])pixels;
+ handler.imageRect(r, buf);
+ return;
+ }
+
+ // Quit on unsupported compression type.
+ if (comp_ctl > rfbTightMaxSubencoding) {
+ throw new Exception("TightDecoder: bad subencoding value received");
+ }
+
+ // "Basic" compression type.
+ int palSize = 0;
+ int[] palette = new int[256];
+ boolean useGradient = false;
+
+ if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+ int filterId = is.readU8();
+
+ switch (filterId) {
+ case rfbTightFilterPalette:
+ palSize = is.readU8() + 1;
+ if (cutZeros) {
+ byte[] elem = new byte[3];
+ for (int i = 0; i < palSize; i++) {
+ is.readBytes(elem, 0, 3);
+ if (bigEndian) {
+ palette[i] =
+ (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
+ } else {
+ palette[i] =
+ (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
+ }
+ }
+ } else {
+ for (int i = 0; i < palSize; i++) {
+ palette[i] = (bpp == 8) ? is.readOpaque8() : is.readOpaque24B();
+ }
+ }
+ break;
+ case rfbTightFilterGradient:
+ useGradient = true;
+ break;
+ case rfbTightFilterCopy:
+ break;
+ default:
+ throw new Exception("TightDecoder: unknown filter code recieved");
+ }
+ }
+
+ int bppp = bpp;
+ if (palSize != 0) {
+ bppp = (palSize <= 2) ? 1 : 8;
+ } else if (cutZeros) {
+ bppp = 24;
+ }
+
+ // Determine if the data should be decompressed or just copied.
+ int rowSize = (r.width() * bppp + 7) / 8;
+ int dataSize = r.height() * rowSize;
+ int streamId = -1;
+ InStream input;
+ if (dataSize < rfbTightMinToCompress) {
+ input = is;
+ } else {
+ int length = is.readCompactLength();
+ streamId = comp_ctl & 0x03;
+ zis[streamId].setUnderlying(is, length);
+ input = (ZlibInStream)zis[streamId];
+ }
+
+ if (palSize == 0) {
+ // Truecolor data.
+ if (useGradient) {
+ vlog.info("useGradient");
+ if (bpp == 32 && cutZeros) {
+ vlog.info("FilterGradient24");
+ FilterGradient24(r, input, dataSize, buf, handler);
+ } else {
+ vlog.info("FilterGradient");
+ FilterGradient(r, input, dataSize, buf, handler);
+ }
+ } else {
+ if (cutZeros) {
+ byte[] elem = new byte[3];
+ for (int i = 0; i < r.width() * r.height(); i++) {
+ input.readBytes(elem, 0, 3);
+ if (bigEndian) {
+ buf[i] =
+ (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[i] =
+ (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
+ }
+ }
+ } else {
+ for (int i = 0; i < r.width() * r.height(); i++) {
+ buf[i] = input.readU8();
+ }
+ }
+ }
+ } else {
+ int ptr = 0;
+ int bits;
+ if (palSize <= 2) {
+ // 2-color palette
+ int dw = (r.width() + 7) / 8;
+ for (int dy = 0; dy < r.height(); dy++) {
+ for (int dx = 0; dx < r.width() / 8; dx++) {
+ bits = input.readU8();
+ for(int b = 7; b >= 0; b--) {
+ buf[ptr++] = palette[bits >> b & 1];
+ }
+ }
+ if (r.width() % 8 != 0) {
+ bits = input.readU8();
+ for (int b = 7; b >= 8 - r.width() % 8; b--) {
+ buf[ptr++] = palette[bits >> b & 1];
+ }
+ }
+ }
+ } else {
+ // 256-color palette
+ for (int dy = 0; dy < r.height(); dy++) {
+ for (int dx = 0; dx < r.width(); dx++) {
+ buf[ptr++] = palette[input.readU8()];
+ }
+ }
+ }
+ }
+
+ handler.imageRect(r, buf);
+
+ if (streamId != -1) {
+ zis[streamId].reset();
+ }
+ }
+
+ private CMsgReader reader;
+ private ZlibInStream[] zis;
+ static LogWriter vlog = new LogWriter("TightDecoder");
+
+ private static int convertByteArrayToInt(byte[] bytes) {
+ return (bytes[0] << 32) | (bytes[1] << 24) | (bytes[2] << 16) | (bytes[3] << 8) | bytes[4];
+ }
+
+ private static byte[] convertIntToByteArray(int integer) {
+ byte[] bytes = new byte[4];
+ bytes[0] =(byte)( integer >> 24 );
+ bytes[1] =(byte)( (integer << 8) >> 24 );
+ bytes[2] =(byte)( (integer << 16) >> 24 );
+ bytes[3] =(byte)( (integer << 24) >> 24 );
+ return bytes;
+ }
+ private static int[] convertByteArrayToIntArray(byte[] bytes) {
+ vlog.info("convertByteArrayToIntArray");
+ ArrayList integers = new ArrayList();
+ for (int index = 0; index < bytes.length; index += 4) {
+ byte[] fourBytes = new byte[4];
+ fourBytes[0] = bytes[index];
+ fourBytes[1] = bytes[index+1];
+ fourBytes[2] = bytes[index+2];
+ fourBytes[3] = bytes[index+3];
+ int integer = convertByteArrayToInt(fourBytes);
+ integers.add(new Integer(integer));
+ }
+ int[] ints = new int[bytes.length/4];
+ for (int index = 0; index < integers.size() ; index++) {
+ ints[index] = ((Integer)integers.get(index)).intValue();
+ }
+ return ints;
+ }
+
+ private static byte[] convertIntArrayToByteArray(int[] integers) {
+ byte[] bytes = new byte[integers.length*4];
+ for (int index = 0; index < integers.length; index++) {
+ byte[] integerBytes = convertIntToByteArray(integers[index]);
+ bytes[index*4] = integerBytes[0];
+ bytes[1 + (index*4)] = integerBytes[1];
+ bytes[2 + (index*4)] = integerBytes[2];
+ bytes[3 + (index*4)] = integerBytes[3];
+ }
+ return bytes;
+ }
+
+ //
+ // Decode data processed with the "Gradient" filter.
+ //
+
+ final private void FilterGradient24(Rect r, InStream is, int dataSize, int[] buf, CMsgHandler handler) {
+
+ int x, y, c;
+ int[] prevRow = new int[TIGHT_MAX_WIDTH * 3];
+ int[] thisRow = new int[TIGHT_MAX_WIDTH * 3];
+ int[] pix = new int[3];
+ int[] est = new int[3];
+
+ // Allocate netbuf and read in data
+ int[] netbuf = new int[dataSize];
+ for (int i = 0; i < dataSize; i++)
+ netbuf[i] = is.readU8();
+ //is.readBytes(netbuf, 0, dataSize);
+
+ PixelFormat myFormat = handler.cp.pf();
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
+ thisRow[c] = pix[c];
+ }
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ }
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 0xFF) {
+ est[c] = 0xFF;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+ thisRow[x*3+c] = pix[c];
+ }
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ }
+ }
+
+ System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
+ }
+ }
+
+ final private void FilterGradient(Rect r, InStream is, int dataSize, int[] buf, CMsgHandler handler) {
+
+ int x, y, c;
+ int[] prevRow = new int[TIGHT_MAX_WIDTH];
+ int[] thisRow = new int[TIGHT_MAX_WIDTH];
+ int[] pix = new int[3];
+ int[] est = new int[3];
+
+ // Allocate netbuf and read in data
+ int[] netbuf = new int[dataSize];
+ for (int i = 0; i < dataSize; i++)
+ netbuf[i] = is.readU8();
+ //is.readBytes(netbuf, 0, dataSize);
+
+ PixelFormat myFormat = handler.cp.pf();
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ /* First pixel in a row */
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ }
+ for (c = 0; c < 3; c++)
+ pix[c] += prevRow[c];
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 255) {
+ est[c] = 255;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ }
+
+ // FIXME?
+ System.arraycopy(pix, 0, netbuf, 0, netbuf.length);
+ for (c = 0; c < 3; c++)
+ pix[c] += est[c];
+
+ System.arraycopy(thisRow, x*3, pix, 0, pix.length);
+
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth+x] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth+x] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ }
+
+ }
+
+ System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
+ }
+ }
+
+}
diff --git a/java/src/com/tigervnc/rfb/UnicodeToKeysym.java b/java/src/com/tigervnc/rfb/UnicodeToKeysym.java
new file mode 100644
index 00000000..44f61ba6
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/UnicodeToKeysym.java
@@ -0,0 +1,795 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// UnicodeToKeysym - provides a translate() method to convert from unicode
+// characters to the equivalent X keysym.
+//
+
+package com.tigervnc.rfb;
+
+public class UnicodeToKeysym {
+
+ public static short[][] table = {
+ { 0x03c0, 0x0100 },
+ { 0x03e0, 0x0101 },
+ { 0x01c3, 0x0102 },
+ { 0x01e3, 0x0103 },
+ { 0x01a1, 0x0104 },
+ { 0x01b1, 0x0105 },
+ { 0x01c6, 0x0106 },
+ { 0x01e6, 0x0107 },
+ { 0x02c6, 0x0108 },
+ { 0x02e6, 0x0109 },
+ { 0x02c5, 0x010a },
+ { 0x02e5, 0x010b },
+ { 0x01c8, 0x010c },
+ { 0x01e8, 0x010d },
+ { 0x01cf, 0x010e },
+ { 0x01ef, 0x010f },
+ { 0x01d0, 0x0110 },
+ { 0x01f0, 0x0111 },
+ { 0x03aa, 0x0112 },
+ { 0x03ba, 0x0113 },
+ { 0x03cc, 0x0116 },
+ { 0x03ec, 0x0117 },
+ { 0x01ca, 0x0118 },
+ { 0x01ea, 0x0119 },
+ { 0x01cc, 0x011a },
+ { 0x01ec, 0x011b },
+ { 0x02d8, 0x011c },
+ { 0x02f8, 0x011d },
+ { 0x02ab, 0x011e },
+ { 0x02bb, 0x011f },
+ { 0x02d5, 0x0120 },
+ { 0x02f5, 0x0121 },
+ { 0x03ab, 0x0122 },
+ { 0x03bb, 0x0123 },
+ { 0x02a6, 0x0124 },
+ { 0x02b6, 0x0125 },
+ { 0x02a1, 0x0126 },
+ { 0x02b1, 0x0127 },
+ { 0x03a5, 0x0128 },
+ { 0x03b5, 0x0129 },
+ { 0x03cf, 0x012a },
+ { 0x03ef, 0x012b },
+ { 0x03c7, 0x012e },
+ { 0x03e7, 0x012f },
+ { 0x02a9, 0x0130 },
+ { 0x02b9, 0x0131 },
+ { 0x02ac, 0x0134 },
+ { 0x02bc, 0x0135 },
+ { 0x03d3, 0x0136 },
+ { 0x03f3, 0x0137 },
+ { 0x03a2, 0x0138 },
+ { 0x01c5, 0x0139 },
+ { 0x01e5, 0x013a },
+ { 0x03a6, 0x013b },
+ { 0x03b6, 0x013c },
+ { 0x01a5, 0x013d },
+ { 0x01b5, 0x013e },
+ { 0x01a3, 0x0141 },
+ { 0x01b3, 0x0142 },
+ { 0x01d1, 0x0143 },
+ { 0x01f1, 0x0144 },
+ { 0x03d1, 0x0145 },
+ { 0x03f1, 0x0146 },
+ { 0x01d2, 0x0147 },
+ { 0x01f2, 0x0148 },
+ { 0x03bd, 0x014a },
+ { 0x03bf, 0x014b },
+ { 0x03d2, 0x014c },
+ { 0x03f2, 0x014d },
+ { 0x01d5, 0x0150 },
+ { 0x01f5, 0x0151 },
+ { 0x13bc, 0x0152 },
+ { 0x13bd, 0x0153 },
+ { 0x01c0, 0x0154 },
+ { 0x01e0, 0x0155 },
+ { 0x03a3, 0x0156 },
+ { 0x03b3, 0x0157 },
+ { 0x01d8, 0x0158 },
+ { 0x01f8, 0x0159 },
+ { 0x01a6, 0x015a },
+ { 0x01b6, 0x015b },
+ { 0x02de, 0x015c },
+ { 0x02fe, 0x015d },
+ { 0x01aa, 0x015e },
+ { 0x01ba, 0x015f },
+ { 0x01a9, 0x0160 },
+ { 0x01b9, 0x0161 },
+ { 0x01de, 0x0162 },
+ { 0x01fe, 0x0163 },
+ { 0x01ab, 0x0164 },
+ { 0x01bb, 0x0165 },
+ { 0x03ac, 0x0166 },
+ { 0x03bc, 0x0167 },
+ { 0x03dd, 0x0168 },
+ { 0x03fd, 0x0169 },
+ { 0x03de, 0x016a },
+ { 0x03fe, 0x016b },
+ { 0x02dd, 0x016c },
+ { 0x02fd, 0x016d },
+ { 0x01d9, 0x016e },
+ { 0x01f9, 0x016f },
+ { 0x01db, 0x0170 },
+ { 0x01fb, 0x0171 },
+ { 0x03d9, 0x0172 },
+ { 0x03f9, 0x0173 },
+ { 0x13be, 0x0178 },
+ { 0x01ac, 0x0179 },
+ { 0x01bc, 0x017a },
+ { 0x01af, 0x017b },
+ { 0x01bf, 0x017c },
+ { 0x01ae, 0x017d },
+ { 0x01be, 0x017e },
+ { 0x08f6, 0x0192 },
+ { 0x01b7, 0x02c7 },
+ { 0x01a2, 0x02d8 },
+ { 0x01ff, 0x02d9 },
+ { 0x01b2, 0x02db },
+ { 0x01bd, 0x02dd },
+ { 0x07ae, 0x0385 },
+ { 0x07a1, 0x0386 },
+ { 0x07a2, 0x0388 },
+ { 0x07a3, 0x0389 },
+ { 0x07a4, 0x038a },
+ { 0x07a7, 0x038c },
+ { 0x07a8, 0x038e },
+ { 0x07ab, 0x038f },
+ { 0x07b6, 0x0390 },
+ { 0x07c1, 0x0391 },
+ { 0x07c2, 0x0392 },
+ { 0x07c3, 0x0393 },
+ { 0x07c4, 0x0394 },
+ { 0x07c5, 0x0395 },
+ { 0x07c6, 0x0396 },
+ { 0x07c7, 0x0397 },
+ { 0x07c8, 0x0398 },
+ { 0x07c9, 0x0399 },
+ { 0x07ca, 0x039a },
+ { 0x07cb, 0x039b },
+ { 0x07cc, 0x039c },
+ { 0x07cd, 0x039d },
+ { 0x07ce, 0x039e },
+ { 0x07cf, 0x039f },
+ { 0x07d0, 0x03a0 },
+ { 0x07d1, 0x03a1 },
+ { 0x07d2, 0x03a3 },
+ { 0x07d4, 0x03a4 },
+ { 0x07d5, 0x03a5 },
+ { 0x07d6, 0x03a6 },
+ { 0x07d7, 0x03a7 },
+ { 0x07d8, 0x03a8 },
+ { 0x07d9, 0x03a9 },
+ { 0x07a5, 0x03aa },
+ { 0x07a9, 0x03ab },
+ { 0x07b1, 0x03ac },
+ { 0x07b2, 0x03ad },
+ { 0x07b3, 0x03ae },
+ { 0x07b4, 0x03af },
+ { 0x07ba, 0x03b0 },
+ { 0x07e1, 0x03b1 },
+ { 0x07e2, 0x03b2 },
+ { 0x07e3, 0x03b3 },
+ { 0x07e4, 0x03b4 },
+ { 0x07e5, 0x03b5 },
+ { 0x07e6, 0x03b6 },
+ { 0x07e7, 0x03b7 },
+ { 0x07e8, 0x03b8 },
+ { 0x07e9, 0x03b9 },
+ { 0x07ea, 0x03ba },
+ { 0x07eb, 0x03bb },
+ { 0x07ec, 0x03bc },
+ { 0x07ed, 0x03bd },
+ { 0x07ee, 0x03be },
+ { 0x07ef, 0x03bf },
+ { 0x07f0, 0x03c0 },
+ { 0x07f1, 0x03c1 },
+ { 0x07f3, 0x03c2 },
+ { 0x07f2, 0x03c3 },
+ { 0x07f4, 0x03c4 },
+ { 0x07f5, 0x03c5 },
+ { 0x07f6, 0x03c6 },
+ { 0x07f7, 0x03c7 },
+ { 0x07f8, 0x03c8 },
+ { 0x07f9, 0x03c9 },
+ { 0x07b5, 0x03ca },
+ { 0x07b9, 0x03cb },
+ { 0x07b7, 0x03cc },
+ { 0x07b8, 0x03cd },
+ { 0x07bb, 0x03ce },
+ { 0x06b3, 0x0401 },
+ { 0x06b1, 0x0402 },
+ { 0x06b2, 0x0403 },
+ { 0x06b4, 0x0404 },
+ { 0x06b5, 0x0405 },
+ { 0x06b6, 0x0406 },
+ { 0x06b7, 0x0407 },
+ { 0x06b8, 0x0408 },
+ { 0x06b9, 0x0409 },
+ { 0x06ba, 0x040a },
+ { 0x06bb, 0x040b },
+ { 0x06bc, 0x040c },
+ { 0x06be, 0x040e },
+ { 0x06bf, 0x040f },
+ { 0x06e1, 0x0410 },
+ { 0x06e2, 0x0411 },
+ { 0x06f7, 0x0412 },
+ { 0x06e7, 0x0413 },
+ { 0x06e4, 0x0414 },
+ { 0x06e5, 0x0415 },
+ { 0x06f6, 0x0416 },
+ { 0x06fa, 0x0417 },
+ { 0x06e9, 0x0418 },
+ { 0x06ea, 0x0419 },
+ { 0x06eb, 0x041a },
+ { 0x06ec, 0x041b },
+ { 0x06ed, 0x041c },
+ { 0x06ee, 0x041d },
+ { 0x06ef, 0x041e },
+ { 0x06f0, 0x041f },
+ { 0x06f2, 0x0420 },
+ { 0x06f3, 0x0421 },
+ { 0x06f4, 0x0422 },
+ { 0x06f5, 0x0423 },
+ { 0x06e6, 0x0424 },
+ { 0x06e8, 0x0425 },
+ { 0x06e3, 0x0426 },
+ { 0x06fe, 0x0427 },
+ { 0x06fb, 0x0428 },
+ { 0x06fd, 0x0429 },
+ { 0x06ff, 0x042a },
+ { 0x06f9, 0x042b },
+ { 0x06f8, 0x042c },
+ { 0x06fc, 0x042d },
+ { 0x06e0, 0x042e },
+ { 0x06f1, 0x042f },
+ { 0x06c1, 0x0430 },
+ { 0x06c2, 0x0431 },
+ { 0x06d7, 0x0432 },
+ { 0x06c7, 0x0433 },
+ { 0x06c4, 0x0434 },
+ { 0x06c5, 0x0435 },
+ { 0x06d6, 0x0436 },
+ { 0x06da, 0x0437 },
+ { 0x06c9, 0x0438 },
+ { 0x06ca, 0x0439 },
+ { 0x06cb, 0x043a },
+ { 0x06cc, 0x043b },
+ { 0x06cd, 0x043c },
+ { 0x06ce, 0x043d },
+ { 0x06cf, 0x043e },
+ { 0x06d0, 0x043f },
+ { 0x06d2, 0x0440 },
+ { 0x06d3, 0x0441 },
+ { 0x06d4, 0x0442 },
+ { 0x06d5, 0x0443 },
+ { 0x06c6, 0x0444 },
+ { 0x06c8, 0x0445 },
+ { 0x06c3, 0x0446 },
+ { 0x06de, 0x0447 },
+ { 0x06db, 0x0448 },
+ { 0x06dd, 0x0449 },
+ { 0x06df, 0x044a },
+ { 0x06d9, 0x044b },
+ { 0x06d8, 0x044c },
+ { 0x06dc, 0x044d },
+ { 0x06c0, 0x044e },
+ { 0x06d1, 0x044f },
+ { 0x06a3, 0x0451 },
+ { 0x06a1, 0x0452 },
+ { 0x06a2, 0x0453 },
+ { 0x06a4, 0x0454 },
+ { 0x06a5, 0x0455 },
+ { 0x06a6, 0x0456 },
+ { 0x06a7, 0x0457 },
+ { 0x06a8, 0x0458 },
+ { 0x06a9, 0x0459 },
+ { 0x06aa, 0x045a },
+ { 0x06ab, 0x045b },
+ { 0x06ac, 0x045c },
+ { 0x06ae, 0x045e },
+ { 0x06af, 0x045f },
+ { 0x0ce0, 0x05d0 },
+ { 0x0ce1, 0x05d1 },
+ { 0x0ce2, 0x05d2 },
+ { 0x0ce3, 0x05d3 },
+ { 0x0ce4, 0x05d4 },
+ { 0x0ce5, 0x05d5 },
+ { 0x0ce6, 0x05d6 },
+ { 0x0ce7, 0x05d7 },
+ { 0x0ce8, 0x05d8 },
+ { 0x0ce9, 0x05d9 },
+ { 0x0cea, 0x05da },
+ { 0x0ceb, 0x05db },
+ { 0x0cec, 0x05dc },
+ { 0x0ced, 0x05dd },
+ { 0x0cee, 0x05de },
+ { 0x0cef, 0x05df },
+ { 0x0cf0, 0x05e0 },
+ { 0x0cf1, 0x05e1 },
+ { 0x0cf2, 0x05e2 },
+ { 0x0cf3, 0x05e3 },
+ { 0x0cf4, 0x05e4 },
+ { 0x0cf5, 0x05e5 },
+ { 0x0cf6, 0x05e6 },
+ { 0x0cf7, 0x05e7 },
+ { 0x0cf8, 0x05e8 },
+ { 0x0cf9, 0x05e9 },
+ { 0x0cfa, 0x05ea },
+ { 0x05ac, 0x060c },
+ { 0x05bb, 0x061b },
+ { 0x05bf, 0x061f },
+ { 0x05c1, 0x0621 },
+ { 0x05c2, 0x0622 },
+ { 0x05c3, 0x0623 },
+ { 0x05c4, 0x0624 },
+ { 0x05c5, 0x0625 },
+ { 0x05c6, 0x0626 },
+ { 0x05c7, 0x0627 },
+ { 0x05c8, 0x0628 },
+ { 0x05c9, 0x0629 },
+ { 0x05ca, 0x062a },
+ { 0x05cb, 0x062b },
+ { 0x05cc, 0x062c },
+ { 0x05cd, 0x062d },
+ { 0x05ce, 0x062e },
+ { 0x05cf, 0x062f },
+ { 0x05d0, 0x0630 },
+ { 0x05d1, 0x0631 },
+ { 0x05d2, 0x0632 },
+ { 0x05d3, 0x0633 },
+ { 0x05d4, 0x0634 },
+ { 0x05d5, 0x0635 },
+ { 0x05d6, 0x0636 },
+ { 0x05d7, 0x0637 },
+ { 0x05d8, 0x0638 },
+ { 0x05d9, 0x0639 },
+ { 0x05da, 0x063a },
+ { 0x05e0, 0x0640 },
+ { 0x05e1, 0x0641 },
+ { 0x05e2, 0x0642 },
+ { 0x05e3, 0x0643 },
+ { 0x05e4, 0x0644 },
+ { 0x05e5, 0x0645 },
+ { 0x05e6, 0x0646 },
+ { 0x05e7, 0x0647 },
+ { 0x05e8, 0x0648 },
+ { 0x05e9, 0x0649 },
+ { 0x05ea, 0x064a },
+ { 0x05eb, 0x064b },
+ { 0x05ec, 0x064c },
+ { 0x05ed, 0x064d },
+ { 0x05ee, 0x064e },
+ { 0x05ef, 0x064f },
+ { 0x05f0, 0x0650 },
+ { 0x05f1, 0x0651 },
+ { 0x05f2, 0x0652 },
+ { 0x0da1, 0x0e01 },
+ { 0x0da2, 0x0e02 },
+ { 0x0da3, 0x0e03 },
+ { 0x0da4, 0x0e04 },
+ { 0x0da5, 0x0e05 },
+ { 0x0da6, 0x0e06 },
+ { 0x0da7, 0x0e07 },
+ { 0x0da8, 0x0e08 },
+ { 0x0da9, 0x0e09 },
+ { 0x0daa, 0x0e0a },
+ { 0x0dab, 0x0e0b },
+ { 0x0dac, 0x0e0c },
+ { 0x0dad, 0x0e0d },
+ { 0x0dae, 0x0e0e },
+ { 0x0daf, 0x0e0f },
+ { 0x0db0, 0x0e10 },
+ { 0x0db1, 0x0e11 },
+ { 0x0db2, 0x0e12 },
+ { 0x0db3, 0x0e13 },
+ { 0x0db4, 0x0e14 },
+ { 0x0db5, 0x0e15 },
+ { 0x0db6, 0x0e16 },
+ { 0x0db7, 0x0e17 },
+ { 0x0db8, 0x0e18 },
+ { 0x0db9, 0x0e19 },
+ { 0x0dba, 0x0e1a },
+ { 0x0dbb, 0x0e1b },
+ { 0x0dbc, 0x0e1c },
+ { 0x0dbd, 0x0e1d },
+ { 0x0dbe, 0x0e1e },
+ { 0x0dbf, 0x0e1f },
+ { 0x0dc0, 0x0e20 },
+ { 0x0dc1, 0x0e21 },
+ { 0x0dc2, 0x0e22 },
+ { 0x0dc3, 0x0e23 },
+ { 0x0dc4, 0x0e24 },
+ { 0x0dc5, 0x0e25 },
+ { 0x0dc6, 0x0e26 },
+ { 0x0dc7, 0x0e27 },
+ { 0x0dc8, 0x0e28 },
+ { 0x0dc9, 0x0e29 },
+ { 0x0dca, 0x0e2a },
+ { 0x0dcb, 0x0e2b },
+ { 0x0dcc, 0x0e2c },
+ { 0x0dcd, 0x0e2d },
+ { 0x0dce, 0x0e2e },
+ { 0x0dcf, 0x0e2f },
+ { 0x0dd0, 0x0e30 },
+ { 0x0dd1, 0x0e31 },
+ { 0x0dd2, 0x0e32 },
+ { 0x0dd3, 0x0e33 },
+ { 0x0dd4, 0x0e34 },
+ { 0x0dd5, 0x0e35 },
+ { 0x0dd6, 0x0e36 },
+ { 0x0dd7, 0x0e37 },
+ { 0x0dd8, 0x0e38 },
+ { 0x0dd9, 0x0e39 },
+ { 0x0dda, 0x0e3a },
+ { 0x0ddf, 0x0e3f },
+ { 0x0de0, 0x0e40 },
+ { 0x0de1, 0x0e41 },
+ { 0x0de2, 0x0e42 },
+ { 0x0de3, 0x0e43 },
+ { 0x0de4, 0x0e44 },
+ { 0x0de5, 0x0e45 },
+ { 0x0de6, 0x0e46 },
+ { 0x0de7, 0x0e47 },
+ { 0x0de8, 0x0e48 },
+ { 0x0de9, 0x0e49 },
+ { 0x0dea, 0x0e4a },
+ { 0x0deb, 0x0e4b },
+ { 0x0dec, 0x0e4c },
+ { 0x0ded, 0x0e4d },
+ { 0x0df0, 0x0e50 },
+ { 0x0df1, 0x0e51 },
+ { 0x0df2, 0x0e52 },
+ { 0x0df3, 0x0e53 },
+ { 0x0df4, 0x0e54 },
+ { 0x0df5, 0x0e55 },
+ { 0x0df6, 0x0e56 },
+ { 0x0df7, 0x0e57 },
+ { 0x0df8, 0x0e58 },
+ { 0x0df9, 0x0e59 },
+ { 0x0ed4, 0x11a8 },
+ { 0x0ed5, 0x11a9 },
+ { 0x0ed6, 0x11aa },
+ { 0x0ed7, 0x11ab },
+ { 0x0ed8, 0x11ac },
+ { 0x0ed9, 0x11ad },
+ { 0x0eda, 0x11ae },
+ { 0x0edb, 0x11af },
+ { 0x0edc, 0x11b0 },
+ { 0x0edd, 0x11b1 },
+ { 0x0ede, 0x11b2 },
+ { 0x0edf, 0x11b3 },
+ { 0x0ee0, 0x11b4 },
+ { 0x0ee1, 0x11b5 },
+ { 0x0ee2, 0x11b6 },
+ { 0x0ee3, 0x11b7 },
+ { 0x0ee4, 0x11b8 },
+ { 0x0ee5, 0x11b9 },
+ { 0x0ee6, 0x11ba },
+ { 0x0ee7, 0x11bb },
+ { 0x0ee8, 0x11bc },
+ { 0x0ee9, 0x11bd },
+ { 0x0eea, 0x11be },
+ { 0x0eeb, 0x11bf },
+ { 0x0eec, 0x11c0 },
+ { 0x0eed, 0x11c1 },
+ { 0x0eee, 0x11c2 },
+ { 0x0ef8, 0x11eb },
+ { 0x0ef9, 0x11f0 },
+ { 0x0efa, 0x11f9 },
+ { 0x0aa2, 0x2002 },
+ { 0x0aa1, 0x2003 },
+ { 0x0aa3, 0x2004 },
+ { 0x0aa4, 0x2005 },
+ { 0x0aa5, 0x2007 },
+ { 0x0aa6, 0x2008 },
+ { 0x0aa7, 0x2009 },
+ { 0x0aa8, 0x200a },
+ { 0x0abb, 0x2012 },
+ { 0x0aaa, 0x2013 },
+ { 0x0aa9, 0x2014 },
+ { 0x07af, 0x2015 },
+ { 0x0cdf, 0x2017 },
+ { 0x0ad0, 0x2018 },
+ { 0x0ad1, 0x2019 },
+ { 0x0afd, 0x201a },
+ { 0x0ad2, 0x201c },
+ { 0x0ad3, 0x201d },
+ { 0x0afe, 0x201e },
+ { 0x0af1, 0x2020 },
+ { 0x0af2, 0x2021 },
+ { 0x0ae6, 0x2022 },
+ { 0x0aaf, 0x2025 },
+ { 0x0aae, 0x2026 },
+ { 0x0ad6, 0x2032 },
+ { 0x0ad7, 0x2033 },
+ { 0x0afc, 0x2038 },
+ { 0x047e, 0x203e },
+ { 0x0eff, 0x20a9 },
+ { 0x20ac, 0x20ac },
+ { 0x0ab8, 0x2105 },
+ { 0x06b0, 0x2116 },
+ { 0x0afb, 0x2117 },
+ { 0x0ad4, 0x211e },
+ { 0x0ac9, 0x2122 },
+ { 0x0ab0, 0x2153 },
+ { 0x0ab1, 0x2154 },
+ { 0x0ab2, 0x2155 },
+ { 0x0ab3, 0x2156 },
+ { 0x0ab4, 0x2157 },
+ { 0x0ab5, 0x2158 },
+ { 0x0ab6, 0x2159 },
+ { 0x0ab7, 0x215a },
+ { 0x0ac3, 0x215b },
+ { 0x0ac4, 0x215c },
+ { 0x0ac5, 0x215d },
+ { 0x0ac6, 0x215e },
+ { 0x08fb, 0x2190 },
+ { 0x08fc, 0x2191 },
+ { 0x08fd, 0x2192 },
+ { 0x08fe, 0x2193 },
+ { 0x08ce, 0x21d2 },
+ { 0x08cd, 0x21d4 },
+ { 0x08ef, 0x2202 },
+ { 0x08c5, 0x2207 },
+ { 0x0bca, 0x2218 },
+ { 0x08d6, 0x221a },
+ { 0x08c1, 0x221d },
+ { 0x08c2, 0x221e },
+ { 0x08de, 0x2227 },
+ { 0x08df, 0x2228 },
+ { 0x08dc, 0x2229 },
+ { 0x08dd, 0x222a },
+ { 0x08bf, 0x222b },
+ { 0x08c0, 0x2234 },
+ { 0x08c8, 0x223c },
+ { 0x08c9, 0x2243 },
+ { 0x08bd, 0x2260 },
+ { 0x08cf, 0x2261 },
+ { 0x08bc, 0x2264 },
+ { 0x08be, 0x2265 },
+ { 0x08da, 0x2282 },
+ { 0x08db, 0x2283 },
+ { 0x0bfc, 0x22a2 },
+ { 0x0bdc, 0x22a3 },
+ { 0x0bce, 0x22a4 },
+ { 0x0bc2, 0x22a5 },
+ { 0x0bd3, 0x2308 },
+ { 0x0bc4, 0x230a },
+ { 0x0afa, 0x2315 },
+ { 0x08a4, 0x2320 },
+ { 0x08a5, 0x2321 },
+ { 0x0abc, 0x2329 },
+ { 0x0abe, 0x232a },
+ { 0x0bcc, 0x2395 },
+ { 0x08ab, 0x239b },
+ { 0x08ac, 0x239d },
+ { 0x08ad, 0x239e },
+ { 0x08ae, 0x23a0 },
+ { 0x08a7, 0x23a1 },
+ { 0x08a8, 0x23a3 },
+ { 0x08a9, 0x23a4 },
+ { 0x08aa, 0x23a6 },
+ { 0x08af, 0x23a8 },
+ { 0x08b0, 0x23ac },
+ { 0x08a1, 0x23b7 },
+ { 0x09ef, 0x23ba },
+ { 0x09f0, 0x23bb },
+ { 0x09f2, 0x23bc },
+ { 0x09f3, 0x23bd },
+ { 0x09e2, 0x2409 },
+ { 0x09e5, 0x240a },
+ { 0x09e9, 0x240b },
+ { 0x09e3, 0x240c },
+ { 0x09e4, 0x240d },
+ { 0x09e8, 0x2424 },
+ { 0x09f1, 0x2500 },
+ { 0x09f8, 0x2502 },
+ { 0x09ec, 0x250c },
+ { 0x09eb, 0x2510 },
+ { 0x09ed, 0x2514 },
+ { 0x09ea, 0x2518 },
+ { 0x09f4, 0x251c },
+ { 0x09f5, 0x2524 },
+ { 0x09f7, 0x252c },
+ { 0x09f6, 0x2534 },
+ { 0x09ee, 0x253c },
+ { 0x09e1, 0x2592 },
+ { 0x0ae7, 0x25aa },
+ { 0x0ae1, 0x25ab },
+ { 0x0adb, 0x25ac },
+ { 0x0ae2, 0x25ad },
+ { 0x0adf, 0x25ae },
+ { 0x0acf, 0x25af },
+ { 0x0ae8, 0x25b2 },
+ { 0x0ae3, 0x25b3 },
+ { 0x0add, 0x25b6 },
+ { 0x0acd, 0x25b7 },
+ { 0x0ae9, 0x25bc },
+ { 0x0ae4, 0x25bd },
+ { 0x0adc, 0x25c0 },
+ { 0x0acc, 0x25c1 },
+ { 0x09e0, 0x25c6 },
+ { 0x0ace, 0x25cb },
+ { 0x0ade, 0x25cf },
+ { 0x0ae0, 0x25e6 },
+ { 0x0ae5, 0x2606 },
+ { 0x0af9, 0x260e },
+ { 0x0aca, 0x2613 },
+ { 0x0aea, 0x261c },
+ { 0x0aeb, 0x261e },
+ { 0x0af8, 0x2640 },
+ { 0x0af7, 0x2642 },
+ { 0x0aec, 0x2663 },
+ { 0x0aee, 0x2665 },
+ { 0x0aed, 0x2666 },
+ { 0x0af6, 0x266d },
+ { 0x0af5, 0x266f },
+ { 0x0af3, 0x2713 },
+ { 0x0af4, 0x2717 },
+ { 0x0ad9, 0x271d },
+ { 0x0af0, 0x2720 },
+ { 0x04a4, 0x3001 },
+ { 0x04a1, 0x3002 },
+ { 0x04a2, 0x300c },
+ { 0x04a3, 0x300d },
+ { 0x04de, 0x309b },
+ { 0x04df, 0x309c },
+ { 0x04a7, 0x30a1 },
+ { 0x04b1, 0x30a2 },
+ { 0x04a8, 0x30a3 },
+ { 0x04b2, 0x30a4 },
+ { 0x04a9, 0x30a5 },
+ { 0x04b3, 0x30a6 },
+ { 0x04aa, 0x30a7 },
+ { 0x04b4, 0x30a8 },
+ { 0x04ab, 0x30a9 },
+ { 0x04b5, 0x30aa },
+ { 0x04b6, 0x30ab },
+ { 0x04b7, 0x30ad },
+ { 0x04b8, 0x30af },
+ { 0x04b9, 0x30b1 },
+ { 0x04ba, 0x30b3 },
+ { 0x04bb, 0x30b5 },
+ { 0x04bc, 0x30b7 },
+ { 0x04bd, 0x30b9 },
+ { 0x04be, 0x30bb },
+ { 0x04bf, 0x30bd },
+ { 0x04c0, 0x30bf },
+ { 0x04c1, 0x30c1 },
+ { 0x04af, 0x30c3 },
+ { 0x04c2, 0x30c4 },
+ { 0x04c3, 0x30c6 },
+ { 0x04c4, 0x30c8 },
+ { 0x04c5, 0x30ca },
+ { 0x04c6, 0x30cb },
+ { 0x04c7, 0x30cc },
+ { 0x04c8, 0x30cd },
+ { 0x04c9, 0x30ce },
+ { 0x04ca, 0x30cf },
+ { 0x04cb, 0x30d2 },
+ { 0x04cc, 0x30d5 },
+ { 0x04cd, 0x30d8 },
+ { 0x04ce, 0x30db },
+ { 0x04cf, 0x30de },
+ { 0x04d0, 0x30df },
+ { 0x04d1, 0x30e0 },
+ { 0x04d2, 0x30e1 },
+ { 0x04d3, 0x30e2 },
+ { 0x04ac, 0x30e3 },
+ { 0x04d4, 0x30e4 },
+ { 0x04ad, 0x30e5 },
+ { 0x04d5, 0x30e6 },
+ { 0x04ae, 0x30e7 },
+ { 0x04d6, 0x30e8 },
+ { 0x04d7, 0x30e9 },
+ { 0x04d8, 0x30ea },
+ { 0x04d9, 0x30eb },
+ { 0x04da, 0x30ec },
+ { 0x04db, 0x30ed },
+ { 0x04dc, 0x30ef },
+ { 0x04a6, 0x30f2 },
+ { 0x04dd, 0x30f3 },
+ { 0x04a5, 0x30fb },
+ { 0x04b0, 0x30fc },
+ { 0x0ea1, 0x3131 },
+ { 0x0ea2, 0x3132 },
+ { 0x0ea3, 0x3133 },
+ { 0x0ea4, 0x3134 },
+ { 0x0ea5, 0x3135 },
+ { 0x0ea6, 0x3136 },
+ { 0x0ea7, 0x3137 },
+ { 0x0ea8, 0x3138 },
+ { 0x0ea9, 0x3139 },
+ { 0x0eaa, 0x313a },
+ { 0x0eab, 0x313b },
+ { 0x0eac, 0x313c },
+ { 0x0ead, 0x313d },
+ { 0x0eae, 0x313e },
+ { 0x0eaf, 0x313f },
+ { 0x0eb0, 0x3140 },
+ { 0x0eb1, 0x3141 },
+ { 0x0eb2, 0x3142 },
+ { 0x0eb3, 0x3143 },
+ { 0x0eb4, 0x3144 },
+ { 0x0eb5, 0x3145 },
+ { 0x0eb6, 0x3146 },
+ { 0x0eb7, 0x3147 },
+ { 0x0eb8, 0x3148 },
+ { 0x0eb9, 0x3149 },
+ { 0x0eba, 0x314a },
+ { 0x0ebb, 0x314b },
+ { 0x0ebc, 0x314c },
+ { 0x0ebd, 0x314d },
+ { 0x0ebe, 0x314e },
+ { 0x0ebf, 0x314f },
+ { 0x0ec0, 0x3150 },
+ { 0x0ec1, 0x3151 },
+ { 0x0ec2, 0x3152 },
+ { 0x0ec3, 0x3153 },
+ { 0x0ec4, 0x3154 },
+ { 0x0ec5, 0x3155 },
+ { 0x0ec6, 0x3156 },
+ { 0x0ec7, 0x3157 },
+ { 0x0ec8, 0x3158 },
+ { 0x0ec9, 0x3159 },
+ { 0x0eca, 0x315a },
+ { 0x0ecb, 0x315b },
+ { 0x0ecc, 0x315c },
+ { 0x0ecd, 0x315d },
+ { 0x0ece, 0x315e },
+ { 0x0ecf, 0x315f },
+ { 0x0ed0, 0x3160 },
+ { 0x0ed1, 0x3161 },
+ { 0x0ed2, 0x3162 },
+ { 0x0ed3, 0x3163 },
+ { 0x0eef, 0x316d },
+ { 0x0ef0, 0x3171 },
+ { 0x0ef1, 0x3178 },
+ { 0x0ef2, 0x317f },
+ { 0x0ef3, 0x3181 },
+ { 0x0ef4, 0x3184 },
+ { 0x0ef5, 0x3186 },
+ { 0x0ef6, 0x318d },
+ { 0x0ef7, 0x318e }
+ };
+
+ public static int translate(int unicode) {
+ if ((unicode >= 0x20 && unicode <= 0x7e) ||
+ (unicode >= 0xa0 && unicode <= 0xff))
+ return unicode;
+
+ int min = 0;
+ int max = table.length - 1;
+ int mid;
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (table[mid][1] < unicode)
+ min = mid + 1;
+ else if (table[mid][1] > unicode)
+ max = mid - 1;
+ else
+ return table[mid][0];
+ }
+
+ /* no matching Unicode value found */
+ return -1;
+ }
+}
diff --git a/java/src/com/tigervnc/rfb/UserMsgBox.java b/java/src/com/tigervnc/rfb/UserMsgBox.java
new file mode 100644
index 00000000..e83d9956
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/UserMsgBox.java
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// getUserPasswd() gets the username and password. This might involve a
+// dialog, getpass(), etc. The user buffer pointer can be null, in which case
+// no user name will be retrieved.
+
+package com.tigervnc.rfb;
+
+public interface UserMsgBox {
+ public boolean showMsgBox(int flags,String title, String text);
+}
diff --git a/java/src/com/tigervnc/rfb/UserPasswdGetter.java b/java/src/com/tigervnc/rfb/UserPasswdGetter.java
new file mode 100644
index 00000000..9796b66f
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/UserPasswdGetter.java
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// getUserPasswd() gets the username and password. This might involve a
+// dialog, getpass(), etc. The user buffer pointer can be null, in which case
+// no user name will be retrieved.
+
+package com.tigervnc.rfb;
+
+public interface UserPasswdGetter {
+ public boolean getUserPasswd(StringBuffer user, StringBuffer password);
+}
diff --git a/java/src/com/tigervnc/rfb/VncAuth.java b/java/src/com/tigervnc/rfb/VncAuth.java
new file mode 100644
index 00000000..cce8d81c
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/VncAuth.java
@@ -0,0 +1,67 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class VncAuth {
+
+ public static final int ok = 0;
+ public static final int failed = 1;
+ public static final int tooMany = 2; // deprecated
+
+ public static final int challengeSize = 16;
+
+ public static void encryptChallenge(byte[] challenge, String passwd) {
+ byte[] key = new byte[8];
+ for (int i = 0; i < 8 && i < passwd.length(); i++) {
+ key[i] = (byte)passwd.charAt(i);
+ }
+
+ DesCipher des = new DesCipher(key);
+
+ for (int j = 0; j < challengeSize; j += 8)
+ des.encrypt(challenge,j,challenge,j);
+ }
+
+ void obfuscatePasswd(String passwd, byte[] obfuscated) {
+ for (int i = 0; i < 8; i++) {
+ if (i < passwd.length())
+ obfuscated[i] = (byte)passwd.charAt(i);
+ else
+ obfuscated[i] = 0;
+ }
+ DesCipher des = new DesCipher(obfuscationKey);
+ des.encrypt(obfuscated,0,obfuscated,0);
+ }
+
+ String unobfuscatePasswd(byte[] obfuscated) {
+ DesCipher des = new DesCipher(obfuscationKey);
+ des.decrypt(obfuscated,0,obfuscated,0);
+ int len;
+ for (len = 0; len < 8; len++) {
+ if (obfuscated[len] == 0) break;
+ }
+ char[] plain = new char[len];
+ for (int i = 0; i < len; i++) {
+ plain[i] = (char)obfuscated[i];
+ }
+ return new String(plain);
+ }
+
+ static byte[] obfuscationKey = {23,82,107,6,35,78,88,7};
+}
diff --git a/java/src/com/tigervnc/rfb/VoidParameter.java b/java/src/com/tigervnc/rfb/VoidParameter.java
new file mode 100644
index 00000000..f41f4c84
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/VoidParameter.java
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+abstract public class VoidParameter {
+ public VoidParameter(String name_, String desc_) {
+ name = name_;
+ description = desc_;
+ next = Configuration.head;
+ Configuration.head = this;
+ }
+
+ final public String getName() { return name; }
+ final public String getDescription() { return description; }
+
+ abstract public boolean setParam(String value);
+ public boolean setParam() { return false; }
+ abstract public String getDefaultStr();
+ abstract public String getValueStr();
+ public boolean isBool() { return false; }
+
+ VoidParameter next;
+ protected String name;
+ protected String description;
+}
diff --git a/java/src/com/tigervnc/rfb/ZRLEDecoder.java b/java/src/com/tigervnc/rfb/ZRLEDecoder.java
new file mode 100644
index 00000000..4f740f9d
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/ZRLEDecoder.java
@@ -0,0 +1,166 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class ZRLEDecoder extends Decoder {
+
+ public ZRLEDecoder(CMsgReader reader_) {
+ reader = reader_;
+ zis = new ZlibInStream();
+ }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ InStream is = reader.getInStream();
+ int[] buf = reader.getImageBuf(64 * 64 * 4);
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+
+ int length = is.readU32();
+ zis.setUnderlying(is, length);
+ Rect t = new Rect();
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
+
+ t.br.y = Math.min(r.br.y, t.tl.y + 64);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
+
+ t.br.x = Math.min(r.br.x, t.tl.x + 64);
+
+ int mode = zis.readU8();
+ boolean rle = (mode & 128) != 0;
+ int palSize = mode & 127;
+ int[] palette = new int[128];
+
+ if (bytesPerPixel > 1) {
+ zis.readPixels(palette, palSize, 3, bigEndian);
+ } else {
+ for (int i = 0; i < palSize; i++) {
+ palette[i] = zis.readPixel(bytesPerPixel, bigEndian);
+ }
+ }
+
+ if (palSize == 1) {
+ int pix = palette[0];
+ handler.fillRect(t, pix);
+ continue;
+ }
+
+ if (!rle) {
+ if (palSize == 0) {
+
+ // raw
+
+ if (bytesPerPixel > 1) {
+ zis.readPixels(buf, t.area(), 3, bigEndian);
+ } else {
+ zis.readPixels(buf, t.area(), bytesPerPixel, bigEndian);
+ }
+
+ } else {
+
+ // packed pixels
+ int bppp = ((palSize > 16) ? 8 :
+ ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
+
+ int ptr = 0;
+
+ for (int i = 0; i < t.height(); i++) {
+ int eol = ptr + t.width();
+ int b = 0;
+ int nbits = 0;
+
+ while (ptr < eol) {
+ if (nbits == 0) {
+ b = zis.readU8();
+ nbits = 8;
+ }
+ nbits -= bppp;
+ int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
+ buf[ptr++] = palette[index];
+ }
+ }
+ }
+
+ } else {
+
+ if (palSize == 0) {
+
+ // plain RLE
+
+ int ptr = 0;
+ int end = ptr + t.area();
+ while (ptr < end) {
+ int pix = (bytesPerPixel > 1 ? zis.readPixel(3, bigEndian) :
+ zis.readPixel(bytesPerPixel, bigEndian));
+ int len = 1;
+ int b;
+ do {
+ b = zis.readU8();
+ len += b;
+ } while (b == 255);
+
+ if (!(len <= end - ptr))
+ throw new Exception("ZRLEDecoder: assertion (len <= end - ptr)"
+ +" failed");
+
+ while (len-- > 0) buf[ptr++] = pix;
+ }
+ } else {
+
+ // palette RLE
+
+ int ptr = 0;
+ int end = ptr + t.area();
+ while (ptr < end) {
+ int index = zis.readU8();
+ int len = 1;
+ if ((index & 128) != 0) {
+ int b;
+ do {
+ b = zis.readU8();
+ len += b;
+ } while (b == 255);
+
+ if (!(len <= end - ptr))
+ throw new Exception("ZRLEDecoder: assertion "
+ +"(len <= end - ptr) failed");
+ }
+
+ index &= 127;
+
+ int pix = palette[index];
+
+ while (len-- > 0) buf[ptr++] = pix;
+ }
+ }
+ }
+
+ handler.imageRect(t, buf);
+ }
+ }
+
+ zis.reset();
+ }
+
+ CMsgReader reader;
+ ZlibInStream zis;
+}
diff --git a/java/src/com/tigervnc/rfb/screenTypes.java b/java/src/com/tigervnc/rfb/screenTypes.java
new file mode 100644
index 00000000..d46741c6
--- /dev/null
+++ b/java/src/com/tigervnc/rfb/screenTypes.java
@@ -0,0 +1,36 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+public class screenTypes {
+
+ // Reasons
+ public static final int reasonServer = 0;
+ public static final int reasonClient = 1;
+ public static final int reasonOtherClient = 2;
+
+ // Result codes
+ public static final int resultSuccess = 0;
+ public static final int resultProhibited = 1;
+ public static final int resultNoResources = 2;
+ public static final int resultInvalid = 3;
+
+ public static final int resultUnsolicited = 0xffff; // internal code used for server changes
+
+}
diff --git a/java/src/com/tigervnc/vncviewer/AuthPanel.java b/java/src/com/tigervnc/vncviewer/AuthPanel.java
deleted file mode 100644
index a23758e4..00000000
--- a/java/src/com/tigervnc/vncviewer/AuthPanel.java
+++ /dev/null
@@ -1,125 +0,0 @@
-//
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-// Copyright (C) 2002-2006 Constantin Kaplinsky. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-//
-// The panel which implements the user authentication scheme
-//
-
-class AuthPanel extends Panel implements ActionListener {
-
- TextField passwordField;
- Button okButton;
- boolean AskPassword;
-
- //
- // Constructor.
- //
-
- public AuthPanel(VncViewer viewer, boolean askpassword)
- {
- AskPassword = askpassword;
- Label titleLabel = new Label("VNC Authentication", Label.CENTER);
- titleLabel.setFont(new Font("Helvetica", Font.BOLD, 18));
-
- Label promptLabel;
- if (AskPassword)
- promptLabel = new Label("Password:", Label.CENTER);
- else
- promptLabel = new Label("User:", Label.CENTER);
-
- passwordField = new TextField(10);
- passwordField.setForeground(Color.black);
- passwordField.setBackground(Color.white);
- if (AskPassword)
- passwordField.setEchoChar('*');
-
- okButton = new Button("OK");
-
- GridBagLayout gridbag = new GridBagLayout();
- GridBagConstraints gbc = new GridBagConstraints();
-
- setLayout(gridbag);
-
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.insets = new Insets(0,0,20,0);
- gridbag.setConstraints(titleLabel,gbc);
- add(titleLabel);
-
- gbc.fill = GridBagConstraints.NONE;
- gbc.gridwidth = 1;
- gbc.insets = new Insets(0,0,0,0);
- gridbag.setConstraints(promptLabel,gbc);
- add(promptLabel);
-
- gridbag.setConstraints(passwordField,gbc);
- add(passwordField);
- passwordField.addActionListener(this);
-
- // gbc.ipady = 10;
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.BOTH;
- gbc.insets = new Insets(0,20,0,0);
- gbc.ipadx = 30;
- gridbag.setConstraints(okButton,gbc);
- add(okButton);
- okButton.addActionListener(this);
- }
-
- //
- // Move keyboard focus to the default object, that is, the password
- // text field.
- //
-
- public void moveFocusToDefaultField()
- {
- passwordField.requestFocus();
- }
-
- //
- // This method is called when a button is pressed or return is
- // pressed in the password text field.
- //
-
- public synchronized void actionPerformed(ActionEvent evt)
- {
- if (evt.getSource() == passwordField || evt.getSource() == okButton) {
- passwordField.setEnabled(false);
- notify();
- }
- }
-
- //
- // Wait for user entering a password, and return it as String.
- //
-
- public synchronized String getPassword() throws Exception
- {
- try {
- wait();
- } catch (InterruptedException e) { }
- return passwordField.getText();
- }
-
-}
diff --git a/java/src/com/tigervnc/vncviewer/ButtonPanel.java b/java/src/com/tigervnc/vncviewer/ButtonPanel.java
deleted file mode 100644
index 1ef64124..00000000
--- a/java/src/com/tigervnc/vncviewer/ButtonPanel.java
+++ /dev/null
@@ -1,154 +0,0 @@
-//
-// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// ButtonPanel class implements panel with four buttons in the
-// VNCViewer desktop window.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-
-class ButtonPanel extends Panel implements ActionListener {
-
- VncViewer viewer;
- Button disconnectButton;
- Button optionsButton;
- Button recordButton;
- Button clipboardButton;
- Button ctrlAltDelButton;
- Button refreshButton;
-
- ButtonPanel(VncViewer v) {
- viewer = v;
-
- setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
- disconnectButton = new Button("Disconnect");
- disconnectButton.setEnabled(false);
- add(disconnectButton);
- disconnectButton.addActionListener(this);
- optionsButton = new Button("Options");
- add(optionsButton);
- optionsButton.addActionListener(this);
- clipboardButton = new Button("Clipboard");
- clipboardButton.setEnabled(false);
- add(clipboardButton);
- clipboardButton.addActionListener(this);
- if (viewer.rec != null) {
- recordButton = new Button("Record");
- add(recordButton);
- recordButton.addActionListener(this);
- }
- ctrlAltDelButton = new Button("Send Ctrl-Alt-Del");
- ctrlAltDelButton.setEnabled(false);
- add(ctrlAltDelButton);
- ctrlAltDelButton.addActionListener(this);
- refreshButton = new Button("Refresh");
- refreshButton.setEnabled(false);
- add(refreshButton);
- refreshButton.addActionListener(this);
- }
-
- //
- // Enable buttons on successful connection.
- //
-
- public void enableButtons() {
- disconnectButton.setEnabled(true);
- clipboardButton.setEnabled(true);
- refreshButton.setEnabled(true);
- }
-
- //
- // Disable all buttons on disconnect.
- //
-
- public void disableButtonsOnDisconnect() {
- remove(disconnectButton);
- disconnectButton = new Button("Hide desktop");
- disconnectButton.setEnabled(true);
- add(disconnectButton, 0);
- disconnectButton.addActionListener(this);
-
- optionsButton.setEnabled(false);
- clipboardButton.setEnabled(false);
- ctrlAltDelButton.setEnabled(false);
- refreshButton.setEnabled(false);
- }
-
- //
- // Enable/disable controls that should not be available in view-only
- // mode.
- //
-
- public void enableRemoteAccessControls(boolean enable) {
- ctrlAltDelButton.setEnabled(enable);
- }
-
- //
- // Event processing.
- //
-
- public void actionPerformed(ActionEvent evt) {
-
- viewer.moveFocusToDesktop();
-
- if (evt.getSource() == disconnectButton) {
- viewer.disconnect();
-
- } else if (evt.getSource() == optionsButton) {
- viewer.options.setVisible(!viewer.options.isVisible());
-
- } else if (evt.getSource() == recordButton) {
- viewer.rec.setVisible(!viewer.rec.isVisible());
-
- } else if (evt.getSource() == clipboardButton) {
- viewer.clipboard.setVisible(!viewer.clipboard.isVisible());
-
- } else if (evt.getSource() == ctrlAltDelButton) {
- try {
- final int modifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK;
-
- KeyEvent ctrlAltDelEvent =
- new KeyEvent(this, KeyEvent.KEY_PRESSED, 0, modifiers, 127);
- viewer.rfb.writeKeyEvent(ctrlAltDelEvent);
-
- ctrlAltDelEvent =
- new KeyEvent(this, KeyEvent.KEY_RELEASED, 0, modifiers, 127);
- viewer.rfb.writeKeyEvent(ctrlAltDelEvent);
-
- } catch (IOException e) {
- e.printStackTrace();
- }
- } else if (evt.getSource() == refreshButton) {
- try {
- RfbProto rfb = viewer.rfb;
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-}
-
diff --git a/java/src/com/tigervnc/vncviewer/CConn.java b/java/src/com/tigervnc/vncviewer/CConn.java
new file mode 100644
index 00000000..e4da1697
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/CConn.java
@@ -0,0 +1,1137 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// CConn
+//
+// Methods on CConn are called from both the GUI thread and the thread which
+// processes incoming RFB messages ("the RFB thread"). This means we need to
+// be careful with synchronization here.
+//
+// Any access to writer() must not only be synchronized, but we must also make
+// sure that the connection is in RFBSTATE_NORMAL. We are guaranteed this for
+// any code called after serverInit() has been called. Since the DesktopWindow
+// isn't created until then, any methods called only from DesktopWindow can
+// assume that we are in RFBSTATE_NORMAL.
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Frame;
+import java.awt.ScrollPane;
+
+import java.io.*;
+import javax.net.ssl.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.ImageIcon;
+import java.net.URL;
+import java.net.ServerSocket;
+import javax.swing.border.*;
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+import com.tigervnc.rfb.Point;
+import com.tigervnc.rfb.Rect;
+
+class ViewportFrame extends JFrame
+{
+ public ViewportFrame(String name, CConn cc_) {
+ cc = cc_;
+ setTitle("TigerVNC: "+name);
+ setFocusable(false);
+ setFocusTraversalKeysEnabled(false);
+ addWindowFocusListener(new WindowAdapter() {
+ public void windowGainedFocus(WindowEvent e) {
+ sp.getViewport().getView().requestFocusInWindow();
+ }
+ });
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ cc.close();
+ }
+ });
+ }
+
+ public void addChild(DesktopWindow child) {
+ sp = new JScrollPane(child);
+ child.setBackground(Color.BLACK);
+ child.setOpaque(true);
+ sp.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
+ getContentPane().add(sp);
+ }
+
+ public void setGeometry(int x, int y, int w, int h) {
+ pack();
+ if (cc.fullScreen) setSize(w, h);
+ setLocation(x, y);
+ setBackground(Color.BLACK);
+ }
+
+
+ CConn cc;
+ Graphics g;
+ JScrollPane sp;
+ static LogWriter vlog = new LogWriter("ViewportFrame");
+}
+
+public class CConn extends CConnection
+ implements UserPasswdGetter, UserMsgBox, OptionsDialogCallback
+{
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the RFB thread
+
+ public CConn(VncViewer viewer_, java.net.Socket sock_,
+ String vncServerName, boolean reverse)
+ {
+ serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_;
+ currentEncoding = Encodings.encodingTight; lastServerEncoding = -1;
+ fullColour = viewer.fullColour.getValue();
+ lowColourLevel = 2;
+ autoSelect = viewer.autoSelect.getValue();
+ shared = viewer.shared.getValue(); formatChange = false;
+ encodingChange = false; sameMachine = false;
+ fullScreen = viewer.fullScreen.getValue();
+ menuKey = Keysyms.F8;
+ options = new OptionsDialog(this);
+ clipboardDialog = new ClipboardDialog(this);
+ firstUpdate = true; pendingUpdate = false;
+
+ setShared(shared);
+ upg = this;
+ msg = this;
+
+ String encStr = viewer.preferredEncoding.getValue();
+ int encNum = Encodings.encodingNum(encStr);
+ if (encNum != -1) {
+ currentEncoding = encNum;
+ }
+ cp.supportsDesktopResize = true;
+ cp.supportsExtendedDesktopSize = true;
+ cp.supportsDesktopRename = true;
+ cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
+ cp.customCompressLevel = viewer.customCompressLevel.getValue();
+ cp.compressLevel = viewer.compressLevel.getValue();
+ cp.noJpeg = viewer.noJpeg.getValue();
+ cp.qualityLevel = viewer.qualityLevel.getValue();
+ initMenu();
+
+ if (sock != null) {
+ String name = sock.getRemoteSocketAddress()+"::"+sock.getPort();
+ vlog.info("Accepted connection from "+name);
+ } else {
+ if (vncServerName != null) {
+ serverHost = Hostname.getHost(vncServerName);
+ serverPort = Hostname.getPort(vncServerName);
+ } else {
+ ServerDialog dlg = new ServerDialog(options, vncServerName, this);
+ if (!dlg.showDialog() || dlg.server.getSelectedItem().equals("")) {
+ System.exit(1);
+ }
+ vncServerName = (String)dlg.server.getSelectedItem();
+ serverHost = Hostname.getHost(vncServerName);
+ serverPort = Hostname.getPort(vncServerName);
+ }
+
+ try {
+ sock = new java.net.Socket(serverHost, serverPort);
+ } catch (java.io.IOException e) {
+ throw new Exception(e.toString());
+ }
+ vlog.info("connected to host "+serverHost+" port "+serverPort);
+ }
+
+ sameMachine = (sock.getLocalSocketAddress() == sock.getRemoteSocketAddress());
+ try {
+ sock.setTcpNoDelay(true);
+ sock.setTrafficClass(0x10);
+ setServerName(serverHost);
+ jis = new JavaInStream(sock.getInputStream());
+ jos = new JavaOutStream(sock.getOutputStream());
+ } catch (java.net.SocketException e) {
+ throw new Exception(e.toString());
+ } catch (java.io.IOException e) {
+ throw new Exception(e.toString());
+ }
+ setStreams(jis, jos);
+ initialiseProtocol();
+ }
+
+ public boolean showMsgBox(int flags, String title, String text)
+ {
+ StringBuffer titleText = new StringBuffer("VNC Viewer: "+title);
+
+ return true;
+ }
+
+ // deleteWindow() is called when the user closes the desktop or menu windows.
+
+ void deleteWindow() {
+ if (viewport != null)
+ viewport.dispose();
+ viewport = null;
+ }
+
+ // getUserPasswd() is called by the CSecurity object when it needs us to read
+ // a password from the user.
+
+ public final boolean getUserPasswd(StringBuffer user, StringBuffer passwd) {
+ String title = ("VNC Authentication ["
+ +csecurity.description() + "]");
+ PasswdDialog dlg;
+ if (user == null) {
+ dlg = new PasswdDialog(title, (user == null), (passwd == null));
+ } else {
+ if ((passwd == null) && viewer.sendLocalUsername.getValue()) {
+ user.append((String)System.getProperties().get("user.name"));
+ return true;
+ }
+ dlg = new PasswdDialog(title, viewer.sendLocalUsername.getValue(),
+ (passwd == null));
+ }
+ if (!dlg.showDialog()) return false;
+ if (user != null) {
+ if (viewer.sendLocalUsername.getValue()) {
+ user.append((String)System.getProperties().get("user.name"));
+ } else {
+ user.append(dlg.userEntry.getText());
+ }
+ }
+ if (passwd != null)
+ passwd.append(dlg.passwdEntry.getText());
+ return true;
+ }
+
+ // CConnection callback methods
+
+ // serverInit() is called when the serverInit message has been received. At
+ // this point we create the desktop window and display it. We also tell the
+ // server the pixel format and encodings to use and request the first update.
+ public void serverInit() {
+ super.serverInit();
+
+ // If using AutoSelect with old servers, start in FullColor
+ // mode. See comment in autoSelectFormatAndEncoding.
+ if (cp.beforeVersion(3, 8) && autoSelect) {
+ fullColour = true;
+ }
+
+ serverPF = cp.pf();
+ desktop = new DesktopWindow(cp.width, cp.height, serverPF, this);
+ //desktopEventHandler = desktop.setEventHandler(this);
+ //desktop.addEventMask(KeyPressMask | KeyReleaseMask);
+ fullColourPF = desktop.getPF();
+ if (!serverPF.trueColour)
+ fullColour = true;
+ recreateViewport();
+ formatChange = true; encodingChange = true;
+ requestNewUpdate();
+ }
+
+ // setDesktopSize() is called when the desktop size changes (including when
+ // it is set initially).
+ public void setDesktopSize(int w, int h) {
+ super.setDesktopSize(w,h);
+ resizeFramebuffer();
+ }
+
+ // setExtendedDesktopSize() is a more advanced version of setDesktopSize()
+ public void setExtendedDesktopSize(int reason, int result, int w, int h,
+ ScreenSet layout) {
+ super.setExtendedDesktopSize(reason, result, w, h, layout);
+
+ if ((reason == screenTypes.reasonClient) &&
+ (result != screenTypes.resultSuccess)) {
+ vlog.error("SetDesktopSize failed: "+result);
+ return;
+ }
+
+ resizeFramebuffer();
+ }
+
+ // setName() is called when the desktop name changes
+ public void setName(String name) {
+ super.setName(name);
+
+ if (viewport != null) {
+ viewport.setTitle("TigerVNC: "+name);
+ }
+ }
+
+ // framebufferUpdateStart() is called at the beginning of an update.
+ // Here we try to send out a new framebuffer update request so that the
+ // next update can be sent out in parallel with us decoding the current
+ // one. We cannot do this if we're in the middle of a format change
+ // though.
+ public void framebufferUpdateStart() {
+ if (!formatChange) {
+ pendingUpdate = true;
+ requestNewUpdate();
+ } else
+ pendingUpdate = false;
+ }
+
+ // framebufferUpdateEnd() is called at the end of an update.
+ // For each rectangle, the FdInStream will have timed the speed
+ // of the connection, allowing us to select format and encoding
+ // appropriately, and then request another incremental update.
+ public void framebufferUpdateEnd() {
+ desktop.framebufferUpdateEnd();
+
+ if (firstUpdate) {
+ //int width = (int)viewer.desktopSize.getValue().split("x")[0];
+ //int height = (int)viewer.desktopSize.getValue().split("x")[1];
+
+/*
+ if (cp.supportsSetDesktopSize &&
+ ((width != 0) && (height != 0))) {
+ ScreenSet layout;
+
+ layout = cp.screenLayout;
+
+ if (layout.num_screens() == 0)
+ layout.add_screen(new Screen());
+ else if (layout.num_screens() != 1) {
+
+ while (true) {
+ Iterator iter = layout.screens.iterator();
+ iter.next();
+
+ if (!iter.hasNext())
+ break;
+
+ layout.remove_screen(iter.id);
+ }
+ }
+
+ layout.screens.iterator().dimensions.tl.x = 0;
+ layout.screens.iterator().dimensions.tl.y = 0;
+ layout.screens.iterator().dimensions.by.x = width;
+ layout.screens.iterator().dimensions.by.y = height;
+
+ writer().writeSetDesktopSize(width, height, layout);
+ }
+*/
+
+ firstUpdate = false;
+ }
+
+ // A format change prevented us from sending this before the update,
+ // so make sure to send it now.
+ if (formatChange && !pendingUpdate)
+ requestNewUpdate();
+
+ // Compute new settings based on updated bandwidth values
+ if (autoSelect)
+ autoSelectFormatAndEncoding();
+ }
+
+ // The rest of the callbacks are fairly self-explanatory...
+
+ public void setColourMapEntries(int firstColour, int nColours, int[] rgbs) {
+ desktop.setColourMapEntries(firstColour, nColours, rgbs);
+ }
+
+ public void bell() { desktop.getToolkit().beep(); }
+
+ public void serverCutText(String str, int len) {
+ if (viewer.acceptClipboard.getValue())
+ clipboardDialog.serverCutText(str, len);
+ }
+
+ // We start timing on beginRect and stop timing on endRect, to
+ // avoid skewing the bandwidth estimation as a result of the server
+ // being slow or the network having high latency
+ public void beginRect(Rect r, int encoding) {
+ ((JavaInStream)getInStream()).startTiming();
+ if (encoding != Encodings.encodingCopyRect) {
+ lastServerEncoding = encoding;
+ }
+ }
+
+ public void endRect(Rect r, int encoding) {
+ ((JavaInStream)getInStream()).stopTiming();
+ }
+
+ public void fillRect(Rect r, int p) {
+ desktop.fillRect(r.tl.x, r.tl.y, r.width(), r.height(), p);
+ }
+ public void imageRect(Rect r, int[] p) {
+ desktop.imageRect(r.tl.x, r.tl.y, r.width(), r.height(), p);
+ }
+ public void copyRect(Rect r, int sx, int sy) {
+ desktop.copyRect(r.tl.x, r.tl.y, r.width(), r.height(), sx, sy);
+ }
+
+ public void setCursor(int width, int height, Point hotspot,
+ int[] data, byte[] mask) {
+ desktop.setCursor(width, height, hotspot, data, mask);
+ }
+
+ private void resizeFramebuffer()
+ {
+ if (desktop == null)
+ return;
+ if ((desktop.width() == cp.width) && (desktop.height() == cp.height))
+ return;
+
+ desktop.resize();
+ recreateViewport();
+ }
+
+ // recreateViewport() recreates our top-level window. This seems to be
+ // better than attempting to resize the existing window, at least with
+ // various X window managers.
+
+ private void recreateViewport()
+ {
+ if (viewport != null) viewport.dispose();
+ viewport = new ViewportFrame(cp.name(), this);
+ viewport.setUndecorated(fullScreen);
+ ClassLoader loader = this.getClass().getClassLoader();
+ URL url = loader.getResource("tigervnc.ico");
+ ImageIcon icon = null;
+ if (url != null) {
+ icon = new ImageIcon(url);
+ viewport.setIconImage(icon.getImage());
+ }
+ viewport.addChild(desktop);
+ reconfigureViewport();
+ viewport.setVisible(true);
+ desktop.initGraphics();
+ desktop.requestFocusInWindow();
+ }
+
+ private void reconfigureViewport()
+ {
+ //viewport->setMaxSize(cp.width, cp.height);
+ int w = cp.width;
+ int h = cp.height;
+ Dimension dpySize = viewport.getToolkit().getScreenSize();
+ int wmDecorationWidth = 0;
+ int wmDecorationHeight = 24;
+ if (w + wmDecorationWidth >= dpySize.width)
+ w = dpySize.width - wmDecorationWidth;
+ if (h + wmDecorationHeight >= dpySize.height)
+ h = dpySize.height - wmDecorationHeight;
+
+ int x = (dpySize.width - w - wmDecorationWidth) / 2;
+ int y = (dpySize.height - h - wmDecorationHeight)/2;
+
+ if (fullScreen) {
+ viewport.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ viewport.setGeometry(0, 0, dpySize.width, dpySize.height);
+ } else {
+ viewport.setExtendedState(JFrame.NORMAL);
+ viewport.setGeometry(x, y, w, h);
+ }
+ }
+
+ // autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+ // to the connection speed:
+ //
+ // First we wait for at least one second of bandwidth measurement.
+ //
+ // Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,
+ // which should be perceptually lossless.
+ //
+ // If the bandwidth is below that, we choose a more lossy JPEG quality.
+ //
+ // If the bandwidth drops below 256 Kbps, we switch to palette mode.
+ //
+ // Note: The system here is fairly arbitrary and should be replaced
+ // with something more intelligent at the server end.
+ //
+ private void autoSelectFormatAndEncoding() {
+ long kbitsPerSecond = ((JavaInStream)getInStream()).kbitsPerSecond();
+ long timeWaited = ((JavaInStream)getInStream()).timeWaited();
+ boolean newFullColour = fullColour;
+ int newQualityLevel = cp.qualityLevel;
+
+ // Always use Tight
+ if (currentEncoding != Encodings.encodingTight) {
+ currentEncoding = Encodings.encodingTight;
+ encodingChange = true;
+ }
+
+ // Check that we have a decent bandwidth measurement
+ if ((kbitsPerSecond == 0) || (timeWaited < 10000))
+ return;
+
+ // Select appropriate quality level
+ if (!cp.noJpeg) {
+ if (kbitsPerSecond > 16000)
+ newQualityLevel = 8;
+ else
+ newQualityLevel = 6;
+
+ if (newQualityLevel != cp.qualityLevel) {
+ vlog.info("Throughput "+kbitsPerSecond+
+ " kbit/s - changing to quality "+newQualityLevel);
+ cp.qualityLevel = newQualityLevel;
+ viewer.qualityLevel.setParam(Integer.toString(newQualityLevel));
+ encodingChange = true;
+ }
+ }
+
+ if (cp.beforeVersion(3, 8)) {
+ // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+ // cursors "asynchronously". If this happens in the middle of a
+ // pixel format change, the server will encode the cursor with
+ // the old format, but the client will try to decode it
+ // according to the new format. This will lead to a
+ // crash. Therefore, we do not allow automatic format change for
+ // old servers.
+ return;
+ }
+
+ // Select best color level
+ newFullColour = (kbitsPerSecond > 256);
+ if (newFullColour != fullColour) {
+ vlog.info("Throughput "+kbitsPerSecond+
+ " kbit/s - full color is now "+
+ (newFullColour ? "enabled" : "disabled"));
+ fullColour = newFullColour;
+ formatChange = true;
+ }
+ }
+
+ // requestNewUpdate() requests an update from the server, having set the
+ // format and encoding appropriately.
+ private void requestNewUpdate()
+ {
+ if (formatChange) {
+ if (fullColour) {
+ desktop.setPF(fullColourPF);
+ } else {
+ if (lowColourLevel == 0) {
+ desktop.setPF(new PixelFormat(8,3,false,true,1,1,1,2,1,0));
+ } else if (lowColourLevel == 1) {
+ desktop.setPF(new PixelFormat(8,6,false,true,3,3,3,4,2,0));
+ } else {
+ desktop.setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+ }
+ }
+ String str = desktop.getPF().print();
+ vlog.info("Using pixel format "+str);
+ cp.setPF(desktop.getPF());
+ synchronized (this) {
+ writer().writeSetPixelFormat(cp.pf());
+ }
+ }
+ checkEncodings();
+ synchronized (this) {
+ writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),
+ !formatChange);
+ }
+ formatChange = false;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the GUI thread
+
+ // close() closes the socket, thus waking up the RFB thread.
+ public void close() {
+ try {
+ shuttingDown = true;
+ sock.close();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Menu callbacks. These are guaranteed only to be called after serverInit()
+ // has been called, since the menu is only accessible from the DesktopWindow
+
+ private void initMenu() {
+ menu = new F8Menu(this);
+ }
+
+ void showMenu(int x, int y) {
+ String os = System.getProperty("os.name");
+ if (os.startsWith("Windows"))
+ com.sun.java.swing.plaf.windows.WindowsLookAndFeel.setMnemonicHidden(false);
+ menu.show(desktop, x, y);
+ }
+
+ void showAbout() {
+ InputStream stream = cl.getResourceAsStream("manifest");
+ String pkgVersion = "";
+ String pkgDate = "";
+ String pkgTime = "";
+ try {
+ Manifest manifest = new Manifest(stream);
+ Attributes attributes = manifest.getMainAttributes();
+ pkgVersion = attributes.getValue("Package-Version");
+ pkgDate = attributes.getValue("Package-Date");
+ pkgTime = attributes.getValue("Package-Time");
+ } catch (IOException e) { }
+ JOptionPane.showMessageDialog((viewport != null ? viewport : null),
+ VncViewer.about1+"\n"
+ +"Built on "+pkgDate+" at "+pkgTime+"\n"
+ +VncViewer.about2+"\n"
+ +VncViewer.about3,
+ "About TigerVNC Viewer for Java",
+ JOptionPane.INFORMATION_MESSAGE,
+ logo);
+ }
+
+ void showInfo() {
+ JOptionPane.showMessageDialog(viewport,
+ "Desktop name: "+cp.name()+"\n"
+ +"Host: "+serverHost+":"+sock.getPort()+"\n"
+ +"Size: "+cp.width+"x"+cp.height+"\n"
+ +"Pixel format: "+desktop.getPF().print()+"\n"
+ +"(server default "+serverPF.print()+")\n"
+ +"Requested encoding: "+Encodings.encodingName(currentEncoding)+"\n"
+ +"Last used encoding: "+Encodings.encodingName(lastServerEncoding)+"\n"
+ +"Line speed estimate: "+((JavaInStream)getInStream()).kbitsPerSecond()+" kbit/s"+"\n"
+ +"Protocol version: "+cp.majorVersion+"."+cp.minorVersion+"\n"
+ +"Security method: "+Security.secTypeName(csecurity.getType())
+ +" ["+csecurity.description()+"]",
+ "VNC connection info",
+ JOptionPane.PLAIN_MESSAGE);
+ }
+
+ synchronized public void refresh() {
+ writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height), false);
+ }
+
+
+ // OptionsDialogCallback. setOptions() sets the options dialog's checkboxes
+ // etc to reflect our flags. getOptions() sets our flags according to the
+ // options dialog's checkboxes. They are both called from the GUI thread.
+ // Some of the flags are also accessed by the RFB thread. I believe that
+ // reading and writing boolean and int values in java is atomic, so there is
+ // no need for synchronization.
+
+ public void setOptions() {
+ int digit;
+ options.autoSelect.setSelected(autoSelect);
+ options.fullColour.setSelected(fullColour);
+ options.veryLowColour.setSelected(!fullColour && lowColourLevel == 0);
+ options.lowColour.setSelected(!fullColour && lowColourLevel == 1);
+ options.mediumColour.setSelected(!fullColour && lowColourLevel == 2);
+ options.tight.setSelected(currentEncoding == Encodings.encodingTight);
+ options.zrle.setSelected(currentEncoding == Encodings.encodingZRLE);
+ options.hextile.setSelected(currentEncoding == Encodings.encodingHextile);
+ options.raw.setSelected(currentEncoding == Encodings.encodingRaw);
+
+ options.customCompressLevel.setSelected(viewer.customCompressLevel.getValue());
+ digit = -1 + viewer.compressLevel.getValue();
+ options.compressLevel.setSelectedIndex(digit);
+ options.noJpeg.setSelected(!viewer.noJpeg.getValue());
+ digit = -1 + viewer.qualityLevel.getValue();
+ options.qualityLevel.setSelectedIndex(digit);
+
+ options.viewOnly.setSelected(viewer.viewOnly.getValue());
+ options.acceptClipboard.setSelected(viewer.acceptClipboard.getValue());
+ options.sendClipboard.setSelected(viewer.sendClipboard.getValue());
+ options.menuKey.setSelectedIndex(menuKey-0xFFBE);
+
+ if (state() == RFBSTATE_NORMAL) {
+ options.shared.setEnabled(false);
+ options.secVeNCrypt.setEnabled(false);
+ options.encNone.setEnabled(false);
+ options.encTLS.setEnabled(false);
+ options.encX509.setEnabled(false);
+ options.ca.setEnabled(false);
+ options.crl.setEnabled(false);
+ options.secManaged.setEnabled(false);
+ options.secNone.setEnabled(false);
+ options.secVnc.setEnabled(false);
+ options.secPlain.setEnabled(false);
+ options.sendLocalUsername.setEnabled(false);
+ } else {
+ options.shared.setSelected(shared);
+
+ /* Process non-VeNCrypt sectypes */
+ java.util.List<Integer> secTypes = new ArrayList<Integer>();
+ secTypes = security.GetEnabledSecTypes();
+ for (Iterator i = secTypes.iterator(); i.hasNext();) {
+ switch ((Integer)i.next()) {
+ case Security.secTypeVeNCrypt:
+ options.secVeNCrypt.setSelected(true);
+ break;
+ case Security.secTypeManaged:
+ options.encNone.setSelected(true);
+ options.secManaged.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeNone:
+ options.encNone.setSelected(true);
+ options.secNone.setSelected(true);
+ break;
+ case Security.secTypeVncAuth:
+ options.encNone.setSelected(true);
+ options.secVnc.setSelected(true);
+ break;
+ }
+ }
+
+ /* Process VeNCrypt subtypes */
+ if (options.secVeNCrypt.isSelected()) {
+ java.util.List<Integer> secTypesExt = new ArrayList<Integer>();
+ secTypesExt = security.GetEnabledExtSecTypes();
+ for (Iterator iext = secTypesExt.iterator(); iext.hasNext();) {
+ switch ((Integer)iext.next()) {
+ case Security.secTypePlain:
+ options.secPlain.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeTLSNone:
+ options.encTLS.setSelected(true);
+ options.secNone.setSelected(true);
+ break;
+ case Security.secTypeTLSVnc:
+ options.encTLS.setSelected(true);
+ options.secVnc.setSelected(true);
+ break;
+ case Security.secTypeTLSPlain:
+ options.encTLS.setSelected(true);
+ options.secPlain.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeX509None:
+ options.encX509.setSelected(true);
+ options.secNone.setSelected(true);
+ break;
+ case Security.secTypeX509Vnc:
+ options.encX509.setSelected(true);
+ options.secVnc.setSelected(true);
+ break;
+ case Security.secTypeX509Plain:
+ options.encX509.setSelected(true);
+ options.secPlain.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ }
+ }
+ }
+ options.sendLocalUsername.setEnabled(options.secPlain.isSelected()||
+ options.secManaged.isSelected());
+ }
+
+ options.fullScreen.setSelected(fullScreen);
+ options.useLocalCursor.setSelected(viewer.useLocalCursor.getValue());
+ options.fastCopyRect.setSelected(viewer.fastCopyRect.getValue());
+ }
+
+ public void getOptions() {
+ autoSelect = options.autoSelect.isSelected();
+ if (fullColour != options.fullColour.isSelected())
+ formatChange = true;
+ fullColour = options.fullColour.isSelected();
+ if (!fullColour) {
+ int newLowColourLevel = (options.veryLowColour.isSelected() ? 0 :
+ options.lowColour.isSelected() ? 1 : 2);
+ if (newLowColourLevel != lowColourLevel) {
+ lowColourLevel = newLowColourLevel;
+ formatChange = true;
+ }
+ }
+ int newEncoding = (options.zrle.isSelected() ? Encodings.encodingZRLE :
+ options.hextile.isSelected() ? Encodings.encodingHextile :
+ options.tight.isSelected() ? Encodings.encodingTight :
+ Encodings.encodingRaw);
+ if (newEncoding != currentEncoding) {
+ currentEncoding = newEncoding;
+ encodingChange = true;
+ }
+
+ viewer.customCompressLevel.setParam(options.customCompressLevel.isSelected());
+ if (cp.customCompressLevel != viewer.customCompressLevel.getValue()) {
+ cp.customCompressLevel = viewer.customCompressLevel.getValue();
+ encodingChange = true;
+ }
+ viewer.compressLevel.setParam(Integer.toString(options.compressLevel.getSelectedIndex()));
+ if (cp.compressLevel != viewer.compressLevel.getValue()) {
+ cp.compressLevel = viewer.compressLevel.getValue();
+ encodingChange = true;
+ }
+ viewer.noJpeg.setParam(!options.noJpeg.isSelected());
+ if (cp.noJpeg != viewer.noJpeg.getValue()) {
+ cp.noJpeg = viewer.noJpeg.getValue();
+ encodingChange = true;
+ }
+ viewer.qualityLevel.setParam(Integer.toString(options.qualityLevel.getSelectedIndex()));
+ if (cp.qualityLevel != viewer.qualityLevel.getValue()) {
+ cp.qualityLevel = viewer.qualityLevel.getValue();
+ encodingChange = true;
+ }
+ viewer.sendLocalUsername.setParam(options.sendLocalUsername.isSelected());
+
+ viewer.viewOnly.setParam(options.viewOnly.isSelected());
+ viewer.acceptClipboard.setParam(options.acceptClipboard.isSelected());
+ viewer.sendClipboard.setParam(options.sendClipboard.isSelected());
+ clipboardDialog.setSendingEnabled(viewer.sendClipboard.getValue());
+ menuKey = (int)(options.menuKey.getSelectedIndex()+0xFFBE);
+ F8Menu.f8.setLabel("Send F"+(menuKey-Keysyms.F1+1));
+
+ shared = options.shared.isSelected();
+ setShared(shared);
+ viewer.useLocalCursor.setParam(options.useLocalCursor.isSelected());
+ if (cp.supportsLocalCursor != viewer.useLocalCursor.getValue()) {
+ cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
+ encodingChange = true;
+ if (desktop != null)
+ desktop.resetLocalCursor();
+ }
+
+ checkEncodings();
+
+ if (state() != RFBSTATE_NORMAL) {
+ /* Process security types which don't use encryption */
+ if (options.encNone.isSelected()) {
+ if (options.secManaged.isSelected())
+ Security.EnableSecType(Security.secTypeManaged);
+ if (options.secNone.isSelected())
+ Security.EnableSecType(Security.secTypeNone);
+ if (options.secVnc.isSelected())
+ Security.EnableSecType(Security.secTypeVncAuth);
+ if (options.secPlain.isSelected())
+ Security.EnableSecType(Security.secTypePlain);
+ } else {
+ Security.DisableSecType(Security.secTypeManaged);
+ Security.DisableSecType(Security.secTypeNone);
+ Security.DisableSecType(Security.secTypeVncAuth);
+ Security.DisableSecType(Security.secTypePlain);
+ }
+
+ /* Process security types which use TLS encryption */
+ if (options.encTLS.isSelected()) {
+ if (options.secNone.isSelected())
+ Security.EnableSecType(Security.secTypeTLSNone);
+ if (options.secVnc.isSelected())
+ Security.EnableSecType(Security.secTypeTLSVnc);
+ if (options.secPlain.isSelected())
+ Security.EnableSecType(Security.secTypeTLSPlain);
+ } else {
+ Security.DisableSecType(Security.secTypeTLSNone);
+ Security.DisableSecType(Security.secTypeTLSVnc);
+ Security.DisableSecType(Security.secTypeTLSPlain);
+ }
+
+ /* Process security types which use X509 encryption */
+ if (options.encX509.isSelected()) {
+ if (options.secNone.isSelected())
+ Security.EnableSecType(Security.secTypeX509None);
+ if (options.secVnc.isSelected())
+ Security.EnableSecType(Security.secTypeX509Vnc);
+ if (options.secPlain.isSelected())
+ Security.EnableSecType(Security.secTypeX509Plain);
+ } else {
+ Security.DisableSecType(Security.secTypeX509None);
+ Security.DisableSecType(Security.secTypeX509Vnc);
+ Security.DisableSecType(Security.secTypeX509Plain);
+ }
+
+ /* Process *None security types */
+ if (options.secNone.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypeNone);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSNone);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509None);
+ } else {
+ Security.DisableSecType(Security.secTypeNone);
+ Security.DisableSecType(Security.secTypeTLSNone);
+ Security.DisableSecType(Security.secTypeX509None);
+ }
+
+ /* Process *Vnc security types */
+ if (options.secVnc.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypeVncAuth);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSVnc);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509Vnc);
+ } else {
+ Security.DisableSecType(Security.secTypeVncAuth);
+ Security.DisableSecType(Security.secTypeTLSVnc);
+ Security.DisableSecType(Security.secTypeX509Vnc);
+ }
+
+ /* Process *Plain security types */
+ if (options.secPlain.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypePlain);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSPlain);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509Plain);
+ } else {
+ Security.DisableSecType(Security.secTypePlain);
+ Security.DisableSecType(Security.secTypeTLSPlain);
+ Security.DisableSecType(Security.secTypeX509Plain);
+ }
+
+ CSecurityTLS.x509ca.setParam(options.ca.getText());
+ CSecurityTLS.x509crl.setParam(options.crl.getText());
+ }
+ }
+
+ public void toggleFullScreen() {
+ fullScreen = !fullScreen;
+ if (!fullScreen) menu.fullScreen.setSelected(false);
+ recreateViewport();
+ }
+
+ // writeClientCutText() is called from the clipboard dialog
+ synchronized public void writeClientCutText(String str, int len) {
+ if (state() != RFBSTATE_NORMAL) return;
+ writer().writeClientCutText(str,len);
+ }
+
+ synchronized public void writeKeyEvent(int keysym, boolean down) {
+ if (state() != RFBSTATE_NORMAL) return;
+ writer().writeKeyEvent(keysym, down);
+ }
+
+ synchronized public void writeKeyEvent(KeyEvent ev) {
+ if (ev.getID() != KeyEvent.KEY_PRESSED && !ev.isActionKey())
+ return;
+
+ int keysym;
+
+ if (!ev.isActionKey()) {
+ vlog.debug("key press "+ev.getKeyChar());
+ if (ev.getKeyChar() < 32) {
+ // if the ctrl modifier key is down, send the equivalent ASCII since we
+ // will send the ctrl modifier anyway
+
+ if ((ev.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
+ if ((ev.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
+ keysym = ev.getKeyChar() + 64;
+ if (keysym == -1)
+ return;
+ } else {
+ keysym = ev.getKeyChar() + 96;
+ if (keysym == 127) keysym = 95;
+ }
+ } else {
+ switch (ev.getKeyCode()) {
+ case KeyEvent.VK_BACK_SPACE: keysym = Keysyms.BackSpace; break;
+ case KeyEvent.VK_TAB: keysym = Keysyms.Tab; break;
+ case KeyEvent.VK_ENTER: keysym = Keysyms.Return; break;
+ case KeyEvent.VK_ESCAPE: keysym = Keysyms.Escape; break;
+ default: return;
+ }
+ }
+
+ } else if (ev.getKeyChar() == 127) {
+ keysym = Keysyms.Delete;
+
+ } else {
+ keysym = UnicodeToKeysym.translate(ev.getKeyChar());
+ if (keysym == -1)
+ return;
+ }
+
+ } else {
+ // KEY_ACTION
+ vlog.debug("key action "+ev.getKeyCode());
+ switch (ev.getKeyCode()) {
+ case KeyEvent.VK_HOME: keysym = Keysyms.Home; break;
+ case KeyEvent.VK_END: keysym = Keysyms.End; break;
+ case KeyEvent.VK_PAGE_UP: keysym = Keysyms.Page_Up; break;
+ case KeyEvent.VK_PAGE_DOWN: keysym = Keysyms.Page_Down; break;
+ case KeyEvent.VK_UP: keysym = Keysyms.Up; break;
+ case KeyEvent.VK_DOWN: keysym = Keysyms.Down; break;
+ case KeyEvent.VK_LEFT: keysym = Keysyms.Left; break;
+ case KeyEvent.VK_RIGHT: keysym = Keysyms.Right; break;
+ case KeyEvent.VK_F1: keysym = Keysyms.F1; break;
+ case KeyEvent.VK_F2: keysym = Keysyms.F2; break;
+ case KeyEvent.VK_F3: keysym = Keysyms.F3; break;
+ case KeyEvent.VK_F4: keysym = Keysyms.F4; break;
+ case KeyEvent.VK_F5: keysym = Keysyms.F5; break;
+ case KeyEvent.VK_F6: keysym = Keysyms.F6; break;
+ case KeyEvent.VK_F7: keysym = Keysyms.F7; break;
+ case KeyEvent.VK_F8: keysym = Keysyms.F8; break;
+ case KeyEvent.VK_F9: keysym = Keysyms.F9; break;
+ case KeyEvent.VK_F10: keysym = Keysyms.F10; break;
+ case KeyEvent.VK_F11: keysym = Keysyms.F11; break;
+ case KeyEvent.VK_F12: keysym = Keysyms.F12; break;
+ case KeyEvent.VK_PRINTSCREEN: keysym = Keysyms.Print; break;
+ case KeyEvent.VK_PAUSE: keysym = Keysyms.Pause; break;
+ case KeyEvent.VK_INSERT: keysym = Keysyms.Insert; break;
+ default: return;
+ }
+ }
+
+ writeModifiers(ev.getModifiers());
+ writeKeyEvent(keysym, true);
+ writeKeyEvent(keysym, false);
+ writeModifiers(0);
+ }
+
+
+ synchronized public void writePointerEvent(MouseEvent ev) {
+ if (state() != RFBSTATE_NORMAL) return;
+ int x, y;
+
+ switch (ev.getID()) {
+ case MouseEvent.MOUSE_PRESSED:
+ buttonMask = 1;
+ if ((ev.getModifiers() & KeyEvent.ALT_MASK) != 0) buttonMask = 2;
+ if ((ev.getModifiers() & KeyEvent.META_MASK) != 0) buttonMask = 4;
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ buttonMask = 0;
+ break;
+ }
+
+ writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
+
+ x = ev.getX();
+ y = ev.getY();
+ if (x < 0) x = 0;
+ if (x > cp.width-1) x = cp.width-1;
+ if (y < 0) y = 0;
+ if (y > cp.height-1) y = cp.height-1;
+
+ writer().writePointerEvent(new Point(x, y), buttonMask);
+
+ if (buttonMask == 0) writeModifiers(0);
+ }
+
+
+ synchronized public void writeWheelEvent(MouseWheelEvent ev) {
+ if (state() != RFBSTATE_NORMAL) return;
+ int x, y;
+ int clicks = ev.getWheelRotation();
+ if (clicks < 0) {
+ buttonMask = 8;
+ } else {
+ buttonMask = 16;
+ }
+ writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
+ for (int i=0;i<java.lang.Math.abs(clicks);i++) {
+ x = ev.getX();
+ y = ev.getY();
+ writer().writePointerEvent(new Point(x, y), buttonMask);
+ buttonMask = 0;
+ writer().writePointerEvent(new Point(x, y), buttonMask);
+ }
+ writeModifiers(0);
+
+ }
+
+
+ void writeModifiers(int m) {
+ if ((m & Event.SHIFT_MASK) != (pressedModifiers & Event.SHIFT_MASK))
+ writeKeyEvent(Keysyms.Shift_L, (m & Event.SHIFT_MASK) != 0);
+ if ((m & Event.CTRL_MASK) != (pressedModifiers & Event.CTRL_MASK))
+ writeKeyEvent(Keysyms.Control_L, (m & Event.CTRL_MASK) != 0);
+ if ((m & Event.ALT_MASK) != (pressedModifiers & Event.ALT_MASK))
+ writeKeyEvent(Keysyms.Alt_L, (m & Event.ALT_MASK) != 0);
+ if ((m & Event.META_MASK) != (pressedModifiers & Event.META_MASK))
+ writeKeyEvent(Keysyms.Meta_L, (m & Event.META_MASK) != 0);
+ pressedModifiers = m;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are called from both RFB and GUI threads
+
+ // checkEncodings() sends a setEncodings message if one is needed.
+ synchronized private void checkEncodings() {
+ if (encodingChange && state() == RFBSTATE_NORMAL) {
+ vlog.info("Using "+Encodings.encodingName(currentEncoding)+" encoding");
+ writer().writeSetEncodings(currentEncoding, true);
+ encodingChange = false;
+ }
+ }
+
+ // the following never change so need no synchronization:
+ JavaInStream jis;
+ JavaOutStream jos;
+
+
+ // viewer object is only ever accessed by the GUI thread so needs no
+ // synchronization (except for one test in DesktopWindow - see comment
+ // there).
+ VncViewer viewer;
+
+ // access to desktop by different threads is specified in DesktopWindow
+
+ // the following need no synchronization:
+
+ ClassLoader cl = this.getClass().getClassLoader();
+ ImageIcon logo = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.png"));
+ public static UserPasswdGetter upg;
+ public UserMsgBox msg;
+
+ // shuttingDown is set by the GUI thread and only ever tested by the RFB
+ // thread after the window has been destroyed.
+ boolean shuttingDown;
+
+ // reading and writing int and boolean is atomic in java, so no
+ // synchronization of the following flags is needed:
+ int currentEncoding, lastServerEncoding;
+
+ int lowColourLevel;
+
+
+ // All menu, options, about and info stuff is done in the GUI thread (apart
+ // from when constructed).
+ F8Menu menu;
+ OptionsDialog options;
+
+ // clipboard sync issues?
+ ClipboardDialog clipboardDialog;
+
+ // the following are only ever accessed by the GUI thread:
+ int buttonMask;
+ int pressedModifiers;
+
+ public String serverHost;
+ public int serverPort;
+ public int menuKey;
+ PixelFormat serverPF;
+ ViewportFrame viewport;
+ DesktopWindow desktop;
+ PixelFormat fullColourPF;
+ boolean fullColour;
+ boolean autoSelect;
+ boolean shared;
+ boolean formatChange;
+ boolean encodingChange;
+ boolean sameMachine;
+ boolean fullScreen;
+ boolean reverseConnection;
+ boolean firstUpdate;
+ boolean pendingUpdate;
+
+ static LogWriter vlog = new LogWriter("CConn");
+}
diff --git a/java/src/com/tigervnc/vncviewer/ClipboardDialog.java b/java/src/com/tigervnc/vncviewer/ClipboardDialog.java
new file mode 100644
index 00000000..9753b152
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/ClipboardDialog.java
@@ -0,0 +1,107 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import javax.swing.*;
+import com.tigervnc.rfb.LogWriter;
+
+class ClipboardDialog extends Dialog implements ActionListener {
+
+ public ClipboardDialog(CConn cc_) {
+ super(false);
+ cc = cc_;
+ setTitle("VNC clipboard");
+ textArea = new JTextArea(5,50);
+ getContentPane().add("Center", textArea);
+
+ JPanel pb = new JPanel();
+ clearButton = new JButton("Clear");
+ pb.add(clearButton);
+ clearButton.addActionListener(this);
+ sendButton = new JButton("Send to VNC server");
+ pb.add(sendButton);
+ sendButton.addActionListener(this);
+ cancelButton = new JButton("Cancel");
+ pb.add(cancelButton);
+ cancelButton.addActionListener(this);
+ getContentPane().add("South", pb);
+
+ pack();
+ }
+
+ static Clipboard systemClipboard;
+ static {
+ try {
+ systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ } catch (Exception e) { }
+ }
+
+ public void initDialog() {
+ textArea.setText(current);
+ textArea.selectAll();
+ }
+
+ public void setContents(String str) {
+ current = str;
+ textArea.setText(str);
+ textArea.selectAll();
+ }
+
+ public void serverCutText(String str, int len) {
+ setContents(str);
+ if (systemClipboard != null) {
+ StringSelection ss = new StringSelection(str);
+ try {
+ systemClipboard.setContents(ss, ss);
+ } catch(Exception e) {
+ vlog.debug(e.toString());
+ }
+ }
+ }
+
+ public void setSendingEnabled(boolean b) {
+ sendButton.setEnabled(b);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JButton && (JButton)s == clearButton) {
+ current = "";
+ textArea.setText(current);
+ } else if (s instanceof JButton && (JButton)s == sendButton) {
+ ok = true;
+ current = textArea.getText();
+ cc.writeClientCutText(current, current.length());
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == cancelButton) {
+ ok = false;
+ endDialog();
+ }
+ }
+
+ CConn cc;
+ String current;
+ JTextArea textArea;
+ JButton clearButton, sendButton, cancelButton;
+ static LogWriter vlog = new LogWriter("ClipboardDialog");
+}
diff --git a/java/src/com/tigervnc/vncviewer/ClipboardFrame.java b/java/src/com/tigervnc/vncviewer/ClipboardFrame.java
deleted file mode 100644
index a09519cd..00000000
--- a/java/src/com/tigervnc/vncviewer/ClipboardFrame.java
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// Clipboard frame.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-class ClipboardFrame extends Frame
- implements WindowListener, ActionListener {
-
- TextArea textArea;
- Button clearButton, closeButton;
- String selection;
- VncViewer viewer;
-
- //
- // Constructor.
- //
-
- ClipboardFrame(VncViewer v) {
- super("TigerVNC Clipboard");
-
- viewer = v;
-
- GridBagLayout gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.BOTH;
- gbc.weighty = 1.0;
-
- textArea = new TextArea(5, 40);
- gridbag.setConstraints(textArea, gbc);
- add(textArea);
-
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weightx = 1.0;
- gbc.weighty = 0.0;
- gbc.gridwidth = 1;
-
- clearButton = new Button("Clear");
- gridbag.setConstraints(clearButton, gbc);
- add(clearButton);
- clearButton.addActionListener(this);
-
- closeButton = new Button("Close");
- gridbag.setConstraints(closeButton, gbc);
- add(closeButton);
- closeButton.addActionListener(this);
-
- pack();
-
- addWindowListener(this);
- }
-
-
- //
- // Set the cut text from the RFB server.
- //
-
- void setCutText(String text) {
- selection = text;
- textArea.setText(text);
- if (isVisible()) {
- textArea.selectAll();
- }
- }
-
-
- //
- // When the focus leaves the window, see if we have new cut text and
- // if so send it to the RFB server.
- //
-
- public void windowDeactivated (WindowEvent evt) {
- if (selection != null && !selection.equals(textArea.getText())) {
- selection = textArea.getText();
- viewer.setCutText(selection);
- }
- }
-
- //
- // Close our window properly.
- //
-
- public void windowClosing(WindowEvent evt) {
- setVisible(false);
- }
-
- //
- // Ignore window events we're not interested in.
- //
-
- public void windowActivated(WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-
-
- //
- // Respond to button presses
- //
-
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == clearButton) {
- textArea.setText("");
- } else if (evt.getSource() == closeButton) {
- setVisible(false);
- }
- }
-}
diff --git a/java/src/com/tigervnc/vncviewer/DesktopWindow.java b/java/src/com/tigervnc/vncviewer/DesktopWindow.java
new file mode 100644
index 00000000..4fd80d31
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/DesktopWindow.java
@@ -0,0 +1,480 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// DesktopWindow is an AWT Canvas representing a VNC desktop.
+//
+// Methods on DesktopWindow are called from both the GUI thread and the thread
+// which processes incoming RFB messages ("the RFB thread"). This means we
+// need to be careful with synchronization here.
+//
+
+package com.tigervnc.vncviewer;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import javax.swing.*;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Cursor;
+import com.tigervnc.rfb.Exception;
+import com.tigervnc.rfb.Point;
+
+class DesktopWindow extends JPanel implements
+ Runnable,
+ MouseListener,
+ MouseMotionListener,
+ MouseWheelListener,
+ KeyListener
+{
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the RFB thread
+
+ public DesktopWindow(int width, int height, PixelFormat serverPF, CConn cc_) {
+ cc = cc_;
+ setSize(width, height);
+ im = new PixelBufferImage(width, height, cc, this);
+
+ cursor = new Cursor();
+ cursorBacking = new ManagedPixelBuffer();
+ addMouseListener(this);
+ addMouseWheelListener(this);
+ addMouseMotionListener(this);
+ addKeyListener(this);
+ addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ checkClipboard();
+ }
+ });
+ setFocusTraversalKeysEnabled(false);
+ setFocusable(true);
+ setDoubleBuffered(true);
+ }
+
+ public int width() {
+ return getWidth();
+ }
+
+ public int height() {
+ return getHeight();
+ }
+
+ // initGraphics() is needed because for some reason you can't call
+ // getGraphics() on a newly-created awt Component. It is called when the
+ // DesktopWindow has actually been made visible so that getGraphics() ought
+ // to work.
+
+ public void initGraphics() {
+ cc.viewport.g = cc.viewport.getGraphics();
+ graphics = getComponentGraphics(cc.viewport.g);
+ prepareImage(im.image, -1, -1, this);
+ }
+
+ final public PixelFormat getPF() { return im.getPF(); }
+
+ synchronized public void setPF(PixelFormat pf) {
+ im.setPF(pf);
+ }
+
+ // Methods called from the RFB thread - these need to be synchronized
+ // wherever they access data shared with the GUI thread.
+
+ public void setCursor(int w, int h, Point hotspot,
+ int[] data, byte[] mask) {
+ // strictly we should use a mutex around this test since useLocalCursor
+ // might be being altered by the GUI thread. However it's only a single
+ // boolean and it doesn't matter if we get the wrong value anyway.
+
+ synchronized(this) {
+ if (!cc.viewer.useLocalCursor.getValue()) return;
+
+ hideLocalCursor();
+
+ cursor.hotspot = hotspot;
+
+ Dimension bsc = tk.getBestCursorSize(w, h);
+
+ cursor.setSize(((int)bsc.getWidth() > w ? (int)bsc.getWidth() : w),
+ ((int)bsc.getHeight() > h ? (int)bsc.getHeight() : h));
+ cursor.setPF(getPF());
+
+ cursorBacking.setSize(cursor.width(), cursor.height());
+ cursorBacking.setPF(getPF());
+
+ cursor.data = new int[cursor.width() * cursor.height()];
+ cursor.mask = new byte[cursor.maskLen()];
+
+ // set the masked pixels of the cursor transparent by using an extra bit in
+ // the colormap. We'll OR this into the data based on the values in the mask.
+ if (cursor.getPF().bpp == 8) {
+ cursor.cm = new DirectColorModel(9, 7, (7 << 3), (3 << 6), (1 << 8));
+ }
+
+ int maskBytesPerRow = (w + 7) / 8;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int byte_ = y * maskBytesPerRow + x / 8;
+ int bit = 7 - x % 8;
+ if ((mask[byte_] & (1 << bit)) > 0) {
+ cursor.data[y * cursor.width() + x] = (cursor.getPF().bpp == 8) ?
+ data[y * w + x] | (1 << 8) : data[y * w + x];
+ }
+ }
+ System.arraycopy(mask, y * maskBytesPerRow, cursor.mask,
+ y * ((cursor.width() + 7) / 8), maskBytesPerRow);
+ }
+
+ MemoryImageSource bitmap =
+ new MemoryImageSource(cursor.width(), cursor.height(), cursor.cm,
+ cursor.data, 0, cursor.width());
+ softCursor =
+ tk.createCustomCursor(tk.createImage(bitmap), new java.awt.Point(hotspot.x,hotspot.y), "Cursor");
+ }
+
+ if (softCursor != null) {
+ setCursor(softCursor);
+ cursorAvailable = true;
+ return;
+ }
+
+ if (!cursorAvailable) {
+ cursorAvailable = true;
+ }
+
+ showLocalCursor();
+ return;
+ }
+
+ // setColourMapEntries() changes some of the entries in the colourmap.
+ // Unfortunately these messages are often sent one at a time, so we delay the
+ // settings taking effect unless the whole colourmap has changed. This is
+ // because getting java to recalculate its internal translation table and
+ // redraw the screen is expensive.
+
+ synchronized public void setColourMapEntries(int firstColour, int nColours,
+ int[] rgbs) {
+ im.setColourMapEntries(firstColour, nColours, rgbs);
+ if (nColours <= 256) {
+ im.updateColourMap();
+ im.put(0, 0, im.width(), im.height(), graphics);
+ } else {
+ if (setColourMapEntriesTimerThread == null) {
+ setColourMapEntriesTimerThread = new Thread(this);
+ setColourMapEntriesTimerThread.start();
+ }
+ }
+ }
+
+// Update the actual window with the changed parts of the framebuffer.
+
+ public void framebufferUpdateEnd()
+ {
+ drawInvalidRect();
+ }
+
+ // resize() is called when the desktop has changed size
+ synchronized public void resize() {
+ vlog.debug("DesktopWindow.resize() called");
+ int w = cc.cp.width;
+ int h = cc.cp.height;
+ hideLocalCursor();
+ setSize(w, h);
+ im.resize(w, h);
+ }
+
+ final void drawInvalidRect() {
+ if (!invalidRect) return;
+ int x = invalidLeft;
+ int w = invalidRight - x;
+ int y = invalidTop;
+ int h = invalidBottom - y;
+ invalidRect = false;
+
+ synchronized (this) {
+ im.put(x, y, w, h, graphics);
+ }
+ }
+
+ final void invalidate(int x, int y, int w, int h) {
+ if (invalidRect) {
+ if (x < invalidLeft) invalidLeft = x;
+ if (x + w > invalidRight) invalidRight = x + w;
+ if (y < invalidTop) invalidTop = y;
+ if (y + h > invalidBottom) invalidBottom = y + h;
+ } else {
+ invalidLeft = x;
+ invalidRight = x + w;
+ invalidTop = y;
+ invalidBottom = y + h;
+ invalidRect = true;
+ }
+
+ if ((invalidRight - invalidLeft) * (invalidBottom - invalidTop) > 100000)
+ drawInvalidRect();
+ }
+
+ public void beginRect(int x, int y, int w, int h, int encoding) {
+ invalidRect = false;
+ }
+
+ public void endRect(int x, int y, int w, int h, int encoding) {
+ drawInvalidRect();
+ }
+
+ synchronized final public void fillRect(int x, int y, int w, int h, int pix)
+ {
+ if (overlapsCursor(x, y, w, h)) hideLocalCursor();
+ im.fillRect(x, y, w, h, pix);
+ invalidate(x, y, w, h);
+ if (softCursor == null)
+ showLocalCursor();
+ }
+
+ synchronized final public void imageRect(int x, int y, int w, int h,
+ int[] pix) {
+ if (overlapsCursor(x, y, w, h)) hideLocalCursor();
+ im.imageRect(x, y, w, h, pix);
+ invalidate(x, y, w, h);
+ if (softCursor == null)
+ showLocalCursor();
+ }
+
+ synchronized final public void copyRect(int x, int y, int w, int h,
+ int srcX, int srcY) {
+ if (overlapsCursor(x, y, w, h) || overlapsCursor(srcX, srcY, w, h))
+ hideLocalCursor();
+ im.copyRect(x, y, w, h, srcX, srcY);
+ if (!cc.viewer.fastCopyRect.getValue()) {
+ invalidate(x, y, w, h);
+ }
+ }
+
+
+ // mutex MUST be held when overlapsCursor() is called
+ final boolean overlapsCursor(int x, int y, int w, int h) {
+ return (x < cursorBackingX + cursorBacking.width() &&
+ y < cursorBackingY + cursorBacking.height() &&
+ x+w > cursorBackingX && y+h > cursorBackingY);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the GUI thread
+
+ synchronized void resetLocalCursor() {
+ hideLocalCursor();
+ cursorAvailable = false;
+ }
+
+ synchronized public Dimension getPreferredSize() {
+ return new Dimension(im.width(), im.height());
+ }
+
+ synchronized public Dimension getMinimumSize() {
+ return new Dimension(im.width(), im.height());
+ }
+
+ public void update(Graphics g) {
+ //repaint();
+ }
+
+ synchronized public void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.drawImage(im.image, 0, 0, this);
+ }
+
+
+ String oldContents = "";
+
+ synchronized public void checkClipboard() {
+ if (ClipboardDialog.systemClipboard != null &&
+ cc.viewer.sendClipboard.getValue()) {
+ Transferable t = ClipboardDialog.systemClipboard.getContents(this);
+ if ((t != null) && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+ try {
+ String newContents = (String) t.getTransferData(DataFlavor.stringFlavor);
+ if (newContents != null && !newContents.equals(oldContents)) {
+ cc.writeClientCutText(newContents, newContents.length());
+ oldContents = newContents;
+ cc.clipboardDialog.setContents(newContents);
+ }
+ } catch (java.lang.Exception e) {
+ System.out.println("Exception getting clipboard data: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ /** Mouse-Motion callback function */
+ private void mouseMotionCB(MouseEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writePointerEvent(e);
+ // - If local cursor rendering is enabled then use it
+ synchronized(this) {
+ if (cursorAvailable) {
+ // - Render the cursor!
+ if (e.getX() != cursorPosX || e.getY() != cursorPosY) {
+ hideLocalCursor();
+ if (e.getX() >= 0 && e.getX() < im.width() &&
+ e.getY() >= 0 && e.getY() < im.height()) {
+ cursorPosX = e.getX();
+ cursorPosY = e.getY();
+ if (softCursor == null)
+ showLocalCursor();
+ }
+ }
+ }
+ }
+ lastX = e.getX();
+ lastY = e.getY();
+ }
+ public void mouseDragged(MouseEvent e) { mouseMotionCB(e);}
+ public void mouseMoved(MouseEvent e) { mouseMotionCB(e);}
+
+ /** Mouse callback function */
+ private void mouseCB(MouseEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writePointerEvent(e);
+ lastX = e.getX();
+ lastY = e.getY();
+ }
+ public void mouseReleased(MouseEvent e){ mouseCB(e);}
+ public void mousePressed(MouseEvent e) { mouseCB(e);}
+ public void mouseClicked(MouseEvent e){}
+ public void mouseEntered(MouseEvent e){}
+ public void mouseExited(MouseEvent e){}
+
+ /** MouseWheel callback function */
+ private void mouseWheelCB(MouseWheelEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writeWheelEvent(e);
+ }
+ public void mouseWheelMoved(MouseWheelEvent e){
+ mouseWheelCB(e);
+ }
+
+ /** Handle the key-typed event. */
+ public void keyTyped(KeyEvent e) {}
+ /** Handle the key-released event. */
+ public void keyReleased(KeyEvent e) {}
+ /** Handle the key-pressed event. */
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() ==
+ (KeyEvent.VK_F1+cc.menuKey-Keysyms.F1)) {
+ cc.showMenu(lastX, lastY);
+ return;
+ }
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writeKeyEvent(e);
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are called from both RFB and GUI threads
+
+ // Note that mutex MUST be held when hideLocalCursor() and showLocalCursor()
+ // are called.
+
+ private void hideLocalCursor() {
+ // - Blit the cursor backing store over the cursor
+ if (cursorVisible) {
+ cursorVisible = false;
+ im.imageRect(cursorBackingX, cursorBackingY, cursorBacking.width(),
+ cursorBacking.height(), cursorBacking.data);
+ im.put(cursorBackingX, cursorBackingY, cursorBacking.width(),
+ cursorBacking.height(), graphics);
+ }
+ }
+
+ private void showLocalCursor() {
+ if (cursorAvailable && !cursorVisible) {
+ if (!im.getPF().equal(cursor.getPF()) ||
+ cursor.width() == 0 || cursor.height() == 0) {
+ vlog.debug("attempting to render invalid local cursor");
+ cursorAvailable = false;
+ return;
+ }
+ cursorVisible = true;
+ if (softCursor != null) return;
+
+ int cursorLeft = (int)cursor.hotspot.x;
+ int cursorTop = (int)cursor.hotspot.y;
+ int cursorRight = cursorLeft + cursor.width();
+ int cursorBottom = cursorTop + cursor.height();
+
+ int x = (cursorLeft >= 0 ? cursorLeft : 0);
+ int y = (cursorTop >= 0 ? cursorTop : 0);
+ int w = ((cursorRight < im.width() ? cursorRight : im.width()) - x);
+ int h = ((cursorBottom < im.height() ? cursorBottom : im.height()) - y);
+
+ cursorBackingX = x;
+ cursorBackingY = y;
+ cursorBacking.setSize(w, h);
+
+ for (int j = 0; j < h; j++)
+ System.arraycopy(im.data, (y+j) * im.width() + x,
+ cursorBacking.data, j*w, w);
+
+ im.maskRect(cursorLeft, cursorTop, cursor.width(), cursor.height(),
+ cursor.data, cursor.mask);
+ im.put(x, y, w, h, graphics);
+ }
+ }
+
+
+ // run() is executed by the setColourMapEntriesTimerThread - it sleeps for
+ // 100ms before actually updating the colourmap.
+ public void run() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ synchronized (this) {
+ im.updateColourMap();
+ im.put(0, 0, im.width(), im.height(), graphics);
+ setColourMapEntriesTimerThread = null;
+ }
+ }
+
+ // access to cc by different threads is specified in CConn
+ CConn cc;
+
+ // access to the following must be synchronized:
+ PixelBufferImage im;
+ Graphics graphics;
+ Thread setColourMapEntriesTimerThread;
+
+ Cursor cursor;
+ boolean cursorVisible; // Is cursor currently rendered?
+ boolean cursorAvailable; // Is cursor available for rendering?
+ int cursorPosX, cursorPosY;
+ ManagedPixelBuffer cursorBacking;
+ int cursorBackingX, cursorBackingY;
+ java.awt.Cursor softCursor;
+ static Toolkit tk = Toolkit.getDefaultToolkit();
+
+ // the following are only ever accessed by the RFB thread:
+ boolean invalidRect;
+ int invalidLeft, invalidRight, invalidTop, invalidBottom;
+
+ // the following are only ever accessed by the GUI thread:
+ int lastX, lastY;
+
+ static LogWriter vlog = new LogWriter("DesktopWindow");
+}
diff --git a/java/src/com/tigervnc/vncviewer/Dialog.java b/java/src/com/tigervnc/vncviewer/Dialog.java
index 9572b9f1..6a11fb3a 100644
--- a/java/src/com/tigervnc/vncviewer/Dialog.java
+++ b/java/src/com/tigervnc/vncviewer/Dialog.java
@@ -1,5 +1,4 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2010 TigerVNC Team
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,6 +15,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
+
//
// This Dialog class implements a pop-up dialog. This is needed because
// apparently you can't use the standard AWT Dialog from within an applet. The
@@ -27,11 +27,24 @@
package com.tigervnc.vncviewer;
+import java.io.*;
+import java.net.*;
import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import javax.swing.*;
+import javax.swing.filechooser.*;
-class Dialog extends Frame {
+//class Dialog extends JFrame implements WindowListener {
+class Dialog extends JFrame {
- public Dialog(boolean modal_) { modal = modal_; }
+ protected boolean ok, done;
+ boolean modal;
+
+ public Dialog(boolean modal_) {
+ modal = modal_;
+ //addWindowListener(this);
+ }
public boolean showDialog() {
ok = false;
@@ -42,7 +55,14 @@ class Dialog extends Frame {
int x = (dpySize.width - mySize.width) / 2;
int y = (dpySize.height - mySize.height) / 2;
setLocation(x, y);
- show();
+ ClassLoader cl = this.getClass().getClassLoader();
+ ImageIcon icon = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.ico"));
+ setIconImage(icon.getImage());
+ //setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ //setFont(new Font("SansSerif", Font.PLAIN, 11));
+
+ setVisible(true);
+ setFocusable(true);
if (!modal) return true;
synchronized(this) {
try {
@@ -56,7 +76,8 @@ class Dialog extends Frame {
public void endDialog() {
done = true;
- hide();
+ setVisible(false);
+ setFocusable(false);
if (modal) {
synchronized (this) {
notify();
@@ -66,16 +87,57 @@ class Dialog extends Frame {
// initDialog() can be overridden in a derived class. Typically it is used
// to make sure that checkboxes have the right state, etc.
- public void initDialog() {}
-
- public boolean handleEvent(Event event) {
- if (event.id == Event.WINDOW_DESTROY) {
- ok = false;
- endDialog();
- }
- return super.handleEvent(event);
+ public void initDialog() {
+ }
+
+ //------------------------------------------------------------------
+ // implemented blank methods
+ //public void windowClosed(WindowEvent event){}
+ //public void windowDeiconified(WindowEvent event){}
+ //public void windowIconified(WindowEvent event){}
+ //public void windowActivated(WindowEvent event){}
+ //public void windowDeactivated(WindowEvent event){}
+ //public void windowOpened(WindowEvent event){}
+
+ //------------------------------------------------------------------
+
+ // method to check which window was closing
+ //public void windowClosing(WindowEvent event) {
+ // ok = false;
+ // endDialog();
+ //}
+
+ public void addGBComponent(JComponent c, JComponent cp,
+ int gx, int gy,
+ int gw, int gh,
+ int gipx, int gipy,
+ double gwx, double gwy,
+ int fill, int anchor,
+ Insets insets)
+ {
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = anchor;
+ gbc.fill = fill;
+ gbc.gridx = gx;
+ gbc.gridy = gy;
+ gbc.gridwidth = gw;
+ gbc.gridheight = gh;
+ gbc.insets = insets;
+ gbc.ipadx = gipx;
+ gbc.ipady = gipy;
+ gbc.weightx = gwx;
+ gbc.weighty = gwy;
+ cp.add(c, gbc);
+ }
+
+ final public String getFileSeperator() {
+ String seperator = System.getProperties().get("file.separator").toString();
+ return seperator;
+ }
+
+ final public String getUserName() {
+ String userName = (String)System.getProperties().get("user.name");
+ return userName;
}
- protected boolean ok, done;
- boolean modal;
}
diff --git a/java/src/com/tigervnc/vncviewer/F8Menu.java b/java/src/com/tigervnc/vncviewer/F8Menu.java
new file mode 100644
index 00000000..5838b38c
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/F8Menu.java
@@ -0,0 +1,133 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.awt.Cursor;
+import java.awt.event.*;
+import javax.swing.JFrame;
+import javax.swing.JPopupMenu;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JCheckBoxMenuItem;
+
+import com.tigervnc.rfb.*;
+
+public class F8Menu extends JPopupMenu implements ActionListener {
+ public F8Menu(CConn cc_) {
+ super("VNC Menu");
+ setLightWeightPopupEnabled(false);
+ cc = cc_;
+ restore = addMenuItem("Restore",KeyEvent.VK_R);
+ move = addMenuItem("Move");
+ move.setEnabled(false);
+ size = addMenuItem("Size");
+ size.setEnabled(false);
+ minimize = addMenuItem("Minimize", KeyEvent.VK_N);
+ maximize = addMenuItem("Maximize", KeyEvent.VK_X);
+ addSeparator();
+ exit = addMenuItem("Close Viewer", KeyEvent.VK_C);
+ addSeparator();
+ fullScreen = new JCheckBoxMenuItem("Full Screen");
+ fullScreen.setMnemonic(KeyEvent.VK_F);
+ fullScreen.addActionListener(this);
+ add(fullScreen);
+ addSeparator();
+ clipboard = addMenuItem("Clipboard...");
+ addSeparator();
+ f8 = addMenuItem("Send F"+(cc.menuKey-Keysyms.F1+1));
+ ctrlAltDel = addMenuItem("Send Ctrl-Alt-Del");
+ addSeparator();
+ refresh = addMenuItem("Refresh Screen", KeyEvent.VK_H);
+ addSeparator();
+ newConn = addMenuItem("New connection...", KeyEvent.VK_W);
+ options = addMenuItem("Options...", KeyEvent.VK_O);
+ info = addMenuItem("Connection info...", KeyEvent.VK_I);
+ about = addMenuItem("About VNCviewer...", KeyEvent.VK_A);
+ addSeparator();
+ dismiss = addMenuItem("Dismiss menu");
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ JMenuItem addMenuItem(String str, int mnemonic) {
+ JMenuItem item = new JMenuItem(str, mnemonic);
+ item.addActionListener(this);
+ add(item);
+ return item;
+ }
+
+ JMenuItem addMenuItem(String str) {
+ JMenuItem item = new JMenuItem(str);
+ item.addActionListener(this);
+ add(item);
+ return item;
+ }
+
+ boolean actionMatch(ActionEvent ev, JMenuItem item) {
+ return ev.getActionCommand().equals(item.getActionCommand());
+ }
+
+ public void actionPerformed(ActionEvent ev) {
+ if (actionMatch(ev, exit)) {
+ cc.close();
+ } else if (actionMatch(ev, fullScreen)) {
+ cc.toggleFullScreen();
+ } else if (actionMatch(ev, restore)) {
+ if (cc.fullScreen) cc.toggleFullScreen();
+ cc.viewport.setExtendedState(JFrame.NORMAL);
+ } else if (actionMatch(ev, minimize)) {
+ if (cc.fullScreen) cc.toggleFullScreen();
+ cc.viewport.setExtendedState(JFrame.ICONIFIED);
+ } else if (actionMatch(ev, maximize)) {
+ if (cc.fullScreen) cc.toggleFullScreen();
+ cc.viewport.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ } else if (actionMatch(ev, clipboard)) {
+ cc.clipboardDialog.showDialog();
+ } else if (actionMatch(ev, f8)) {
+ cc.writeKeyEvent(cc.menuKey, true);
+ cc.writeKeyEvent(cc.menuKey, false);
+ } else if (actionMatch(ev, ctrlAltDel)) {
+ cc.writeKeyEvent(Keysyms.Control_L, true);
+ cc.writeKeyEvent(Keysyms.Alt_L, true);
+ cc.writeKeyEvent(Keysyms.Delete, true);
+ cc.writeKeyEvent(Keysyms.Delete, false);
+ cc.writeKeyEvent(Keysyms.Alt_L, false);
+ cc.writeKeyEvent(Keysyms.Control_L, false);
+ } else if (actionMatch(ev, refresh)) {
+ cc.refresh();
+ } else if (actionMatch(ev, newConn)) {
+ VncViewer.newViewer(cc.viewer);
+ } else if (actionMatch(ev, options)) {
+ cc.options.showDialog();
+ } else if (actionMatch(ev, info)) {
+ cc.showInfo();
+ } else if (actionMatch(ev, about)) {
+ cc.showAbout();
+ } else if (actionMatch(ev, dismiss)) {
+ firePopupMenuCanceled();
+ }
+ }
+
+ CConn cc;
+ JMenuItem restore, move, size, minimize, maximize;
+ JMenuItem exit, clipboard, ctrlAltDel, refresh;
+ JMenuItem newConn, options, info, about, dismiss;
+ static JMenuItem f8;
+ JCheckBoxMenuItem fullScreen;
+ static LogWriter vlog = new LogWriter("F8Menu");
+}
diff --git a/java/src/com/tigervnc/vncviewer/HTTPConnectSocket.java b/java/src/com/tigervnc/vncviewer/HTTPConnectSocket.java
deleted file mode 100644
index 2a66b25d..00000000
--- a/java/src/com/tigervnc/vncviewer/HTTPConnectSocket.java
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// HTTPConnectSocket.java together with HTTPConnectSocketFactory.java
-// implement an alternate way to connect to VNC servers via one or two
-// HTTP proxies supporting the HTTP CONNECT method.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.net.*;
-import java.io.*;
-
-class HTTPConnectSocket extends Socket {
-
- public HTTPConnectSocket(String host, int port,
- String proxyHost, int proxyPort)
- throws IOException {
-
- // Connect to the specified HTTP proxy
- super(proxyHost, proxyPort);
-
- // Send the CONNECT request
- getOutputStream().write(("CONNECT " + host + ":" + port +
- " HTTP/1.0\r\n\r\n").getBytes());
-
- // Read the first line of the response
- DataInputStream is = new DataInputStream(getInputStream());
- String str = is.readLine();
-
- // Check the HTTP error code -- it should be "200" on success
- if (!str.startsWith("HTTP/1.0 200 ")) {
- if (str.startsWith("HTTP/1.0 "))
- str = str.substring(9);
- throw new IOException("Proxy reports \"" + str + "\"");
- }
-
- // Success -- skip remaining HTTP headers
- do {
- str = is.readLine();
- } while (str.length() != 0);
- }
-}
-
diff --git a/java/src/com/tigervnc/vncviewer/HTTPConnectSocketFactory.java b/java/src/com/tigervnc/vncviewer/HTTPConnectSocketFactory.java
deleted file mode 100644
index 56c8b97c..00000000
--- a/java/src/com/tigervnc/vncviewer/HTTPConnectSocketFactory.java
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// HTTPConnectSocketFactory.java together with HTTPConnectSocket.java
-// implement an alternate way to connect to VNC servers via one or two
-// HTTP proxies supporting the HTTP CONNECT method.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.applet.*;
-import java.net.*;
-import java.io.*;
-
-class HTTPConnectSocketFactory implements SocketFactory {
-
- public Socket createSocket(String host, int port, Applet applet)
- throws IOException {
-
- return createSocket(host, port,
- applet.getParameter("PROXYHOST1"),
- applet.getParameter("PROXYPORT1"));
- }
-
- public Socket createSocket(String host, int port, String[] args)
- throws IOException {
-
- return createSocket(host, port,
- readArg(args, "PROXYHOST1"),
- readArg(args, "PROXYPORT1"));
- }
-
- public Socket createSocket(String host, int port,
- String proxyHost, String proxyPortStr)
- throws IOException {
-
- int proxyPort = 0;
- if (proxyPortStr != null) {
- try {
- proxyPort = Integer.parseInt(proxyPortStr);
- } catch (NumberFormatException e) { }
- }
-
- if (proxyHost == null || proxyPort == 0) {
- System.out.println("Incomplete parameter list for HTTPConnectSocket");
- return new Socket(host, port);
- }
-
- System.out.println("HTTP CONNECT via proxy " + proxyHost +
- " port " + proxyPort);
- HTTPConnectSocket s =
- new HTTPConnectSocket(host, port, proxyHost, proxyPort);
-
- return (Socket)s;
- }
-
- private String readArg(String[] args, String name) {
-
- for (int i = 0; i < args.length; i += 2) {
- if (args[i].equalsIgnoreCase(name)) {
- try {
- return args[i+1];
- } catch (Exception e) {
- return null;
- }
- }
- }
- return null;
- }
-}
-
diff --git a/java/src/com/tigervnc/vncviewer/Makefile b/java/src/com/tigervnc/vncviewer/Makefile
index 39ccbb76..99c04ac4 100644
--- a/java/src/com/tigervnc/vncviewer/Makefile
+++ b/java/src/com/tigervnc/vncviewer/Makefile
@@ -11,25 +11,15 @@ MANIFEST = MANIFEST.MF
PAGES = index.vnc
INSTALL_DIR = /usr/local/vnc/classes
-CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \
- VncCanvas2.class \
- OptionsFrame.class ClipboardFrame.class ButtonPanel.class \
- DesCipher.class \
- RecordingFrame.class SessionRecorder.class \
- SocketFactory.class HTTPConnectSocketFactory.class \
- HTTPConnectSocket.class ReloginPanel.class \
- InStream.class MemInStream.class ZlibInStream.class \
- TLSTunnelBase.class TLSTunnel.class X509Tunnel.class Dialog.class MessageBox.class
-
-SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \
- VncCanvas2.java \
- OptionsFrame.java ClipboardFrame.java ButtonPanel.java \
- DesCipher.java \
- RecordingFrame.java SessionRecorder.java \
- SocketFactory.java HTTPConnectSocketFactory.java \
- HTTPConnectSocket.java ReloginPanel.java \
- InStream.java MemInStream.java ZlibInStream.java \
- TLSTunnelBase.java TLSTunnel.java X509Tunnel.java Dialog.java MessageBox.java
+CLASSES = CConn.class OptionsDialogCallback.class ClipboardDialog.class \
+ PasswdDialog.class DesktopWindow.class PixelBufferImage.class \
+ Dialog.class ServerDialog.class F8Menu.class UserPrefs.class \
+ OptionsDialog.class VncViewer.class
+
+SOURCES = CConn.java OptionsDialogCallback.java ClipboardDialog.java \
+ PasswdDialog.java DesktopWindow.java PixelBufferImage.java \
+ Dialog.java ServerDialog.java F8Menu.java UserPrefs.java \
+ OptionsDialog.java VncViewer.java
all: $(CLASSES) $(ARCHIVE)
@@ -41,8 +31,10 @@ $(ARCHIVE): $(CLASSES) $(MANIFEST)
$(JAR) cfm com/tigervnc/vncviewer/$(ARCHIVE) \
com/tigervnc/vncviewer/$(MANIFEST) \
com/tigervnc/vncviewer/*.class \
- com/tigervnc/decoder/*.class \
- com/tigervnc/decoder/common/*.class
+ com/tigervnc/rfb/*.class \
+ com/tigervnc/rdr/*.class \
+ com/tigervnc/vncviewer/tigervnc.png \
+ com/tigervnc/vncviewer/tigervnc.ico
install: $(CLASSES) $(ARCHIVE)
$(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
@@ -51,4 +43,4 @@ export:: $(CLASSES) $(ARCHIVE) $(PAGES)
@$(ExportJavaClasses)
clean::
- $(RM) *.class *.jar ../decoder/*.class ../decoder/common/*.class
+ $(RM) *.class *.jar ../rfb/*.class ../rdr/*.class
diff --git a/java/src/com/tigervnc/vncviewer/MessageBox.java b/java/src/com/tigervnc/vncviewer/MessageBox.java
deleted file mode 100644
index feac5ceb..00000000
--- a/java/src/com/tigervnc/vncviewer/MessageBox.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2010 TigerVNC Team
- *
- * This 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 software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-
-public class MessageBox extends com.tigervnc.vncviewer.Dialog {
-
- public static final int MB_OK = 0;
- public static final int MB_OKAYCANCEL = 1;
- public static final int MB_YESNO = 2;
-
- public MessageBox(String msg, int flags) {
- super(true);
- GridLayout g = new GridLayout(0,1);
- setLayout(g);
- while (true) {
- int i = msg.indexOf('\n');
- int j = (i==-1) ? msg.length() : i;
- add(new Label(msg.substring(0, j)));
- if (i==-1) break;
- msg = msg.substring(j+1);
- }
- Panel p2 = new Panel();
- switch (flags & 3) {
- case MB_OKAYCANCEL:
- cancelButton = new Button("Cancel");
- // No break
- case MB_OK:
- okButton = new Button("OK");
- break;
- case MB_YESNO:
- okButton = new Button("Yes");
- cancelButton = new Button("No");
- break;
- }
- if (okButton != null) p2.add(okButton);
- if (cancelButton != null) p2.add(cancelButton);
- add("South", p2);
- pack();
- showDialog();
- }
-
- public MessageBox(String msg) {
- this(msg, MB_OK);
- }
-
-
- public boolean action(Event event, Object arg) {
- if (event.target == okButton) {
- ok = true;
- endDialog();
- } else if (event.target == cancelButton) {
- ok = false;
- endDialog();
- }
- return true;
- }
-
- Button okButton, cancelButton;
-
- public boolean result() {
- return ok;
- }
-
-}
diff --git a/java/src/com/tigervnc/vncviewer/OptionsDialog.java b/java/src/com/tigervnc/vncviewer/OptionsDialog.java
new file mode 100644
index 00000000..7e1828e7
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/OptionsDialog.java
@@ -0,0 +1,380 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.filechooser.*;
+import javax.swing.ImageIcon;
+import java.net.URL;
+import java.io.IOException;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+class OptionsDialog extends Dialog implements
+ ActionListener,
+ ItemListener
+{
+
+ // Constants
+ // Static variables
+ static LogWriter vlog = new LogWriter("OptionsDialog");
+
+ OptionsDialogCallback cb;
+ JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel;
+ JCheckBox autoSelect, customCompressLevel, noJpeg;
+ JComboBox menuKey, compressLevel, qualityLevel ;
+ ButtonGroup encodingGroup, colourGroup;
+ JRadioButton zrle, hextile, tight, raw;
+ JRadioButton fullColour, mediumColour, lowColour, veryLowColour;
+ JCheckBox viewOnly, acceptClipboard, sendClipboard;
+ JCheckBox fullScreen, shared, useLocalCursor, fastCopyRect;
+ JCheckBox secVeNCrypt, encNone, encTLS, encX509;
+ JCheckBox secNone, secVnc, secPlain, secManaged, sendLocalUsername;
+ JButton okButton, cancelButton;
+ JButton ca, crl;
+ JButton defSaveButton;
+ boolean encryption = true;
+ UserPrefs defaults;
+
+ public OptionsDialog(OptionsDialogCallback cb_) {
+ super(false);
+ cb = cb_;
+ setResizable(false);
+ setTitle("VNC Viewer Options");
+ defaults = new UserPrefs("vncviewer");
+
+ getContentPane().setLayout(
+ new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
+
+ JTabbedPane tabPane = new JTabbedPane();
+
+ ButtonGroup encodingGroup = new ButtonGroup();
+ ButtonGroup colourGroup = new ButtonGroup();
+
+ // Colour & Encoding tab
+ FormatPanel=new JPanel(new GridBagLayout());
+
+ autoSelect = new JCheckBox("Auto Select");
+ autoSelect.addItemListener(this);
+
+ JPanel encodingPanel = new JPanel(new GridBagLayout());
+ encodingPanel.setBorder(BorderFactory.createTitledBorder("Preferred encoding"));
+ zrle = addRadioCheckbox("ZRLE", encodingGroup, encodingPanel);
+ hextile = addRadioCheckbox("Hextile", encodingGroup, encodingPanel);
+ tight = addRadioCheckbox("Tight", encodingGroup, encodingPanel);
+ raw = addRadioCheckbox("Raw", encodingGroup, encodingPanel);
+
+ JPanel tightPanel = new JPanel(new GridBagLayout());
+ customCompressLevel = new JCheckBox("Custom Compression Level");
+ customCompressLevel.addItemListener(this);
+ String[] compressionLevels = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+ compressLevel = new JComboBox(compressionLevels);
+ JLabel compressionLabel = new JLabel("Level (1=fast, 9=best)");
+ noJpeg = new JCheckBox("Allow JPEG Compression");
+ noJpeg.addItemListener(this);
+ String[] qualityLevels = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+ qualityLevel = new JComboBox(qualityLevels);
+ JLabel qualityLabel = new JLabel("Level (1=poor, 9=best)");
+ addGBComponent(customCompressLevel, tightPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+ addGBComponent(compressLevel, tightPanel, 0, 1, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));
+ addGBComponent(compressionLabel, tightPanel, 1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));
+ addGBComponent(noJpeg, tightPanel, 0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+ addGBComponent(qualityLevel, tightPanel, 0, 3, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));
+ addGBComponent(qualityLabel, tightPanel, 1, 3, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));
+
+
+ JPanel colourPanel = new JPanel(new GridBagLayout());
+ colourPanel.setBorder(BorderFactory.createTitledBorder("Colour level"));
+ fullColour = addRadioCheckbox("Full (all available colours)", colourGroup, colourPanel);
+ mediumColour = addRadioCheckbox("Medium (256 colours)", colourGroup, colourPanel);
+ lowColour = addRadioCheckbox("Low (64 colours)", colourGroup, colourPanel);
+ veryLowColour = addRadioCheckbox("Very low(8 colours)", colourGroup, colourPanel);
+
+ addGBComponent(autoSelect,FormatPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+ addGBComponent(encodingPanel,FormatPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,2,0,0));
+ addGBComponent(colourPanel,FormatPanel, 1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(0,2,0,0));
+ addGBComponent(tightPanel,FormatPanel, 0, 2, 2, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+
+ // Inputs tab
+ InputsPanel=new JPanel(new GridBagLayout());
+
+ viewOnly = new JCheckBox("View Only (ignore mouse & keyboard)");
+ viewOnly.addItemListener(this);
+ acceptClipboard = new JCheckBox("Accept clipboard from server");
+ acceptClipboard.addItemListener(this);
+ sendClipboard = new JCheckBox("Send clipboard to server");
+ sendClipboard.addItemListener(this);
+ JLabel menuKeyLabel = new JLabel("Menu Key");
+ String[] menuKeys =
+ { "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" };
+ menuKey = new JComboBox(menuKeys);
+ menuKey.addItemListener(this);
+ addGBComponent(viewOnly,InputsPanel, 0, 0, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(acceptClipboard,InputsPanel, 0, 1, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(sendClipboard,InputsPanel, 0, 2, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(menuKeyLabel,InputsPanel, 0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(8,10,0,4));
+ addGBComponent(menuKey,InputsPanel, 1, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,125));
+ //((javax.swing.plaf.basic.BasicComboBoxRenderer)menuKey.getRenderer()).setBorder(new EmptyBorder(0,3,0,3));
+
+ // Misc tab
+ MiscPanel=new JPanel(new GridBagLayout());
+
+ fullScreen = new JCheckBox("Full-screen mode");
+ fullScreen.addItemListener(this);
+ shared = new JCheckBox("Shared connection (do not disconnect other viewers)");
+ shared.addItemListener(this);
+ useLocalCursor = new JCheckBox("Render cursor locally");
+ useLocalCursor.addItemListener(this);
+ fastCopyRect = new JCheckBox("Fast CopyRect");
+ fastCopyRect.addItemListener(this);
+ addGBComponent(fullScreen,MiscPanel, 0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(shared,MiscPanel, 0, 1, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(useLocalCursor,MiscPanel, 0, 2, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(fastCopyRect,MiscPanel, 0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,4));
+
+ // load/save tab
+ DefaultsPanel=new JPanel(new GridBagLayout());
+
+ JPanel configPanel = new JPanel(new GridBagLayout());
+ configPanel.setBorder(BorderFactory.createTitledBorder("Configuration File"));
+ JButton cfReloadButton = new JButton("Reload");
+ cfReloadButton.addActionListener(this);
+ addGBComponent(cfReloadButton,configPanel, 0, 0, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ JButton cfSaveButton = new JButton("Save");
+ cfSaveButton.addActionListener(this);
+ addGBComponent(cfSaveButton,configPanel, 0, 1, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ JButton cfSaveAsButton = new JButton("Save As...");
+ cfSaveAsButton.addActionListener(this);
+ addGBComponent(cfSaveAsButton,configPanel, 0, 2, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ cfReloadButton.setEnabled(false);
+ cfSaveButton.setEnabled(false);
+
+ JPanel defaultsPanel = new JPanel(new GridBagLayout());
+ defaultsPanel.setBorder(BorderFactory.createTitledBorder("Defaults"));
+ JButton defReloadButton = new JButton("Reload");
+ defReloadButton.addActionListener(this);
+ addGBComponent(defReloadButton,defaultsPanel, 0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ defSaveButton = new JButton("Save");
+ defSaveButton.addActionListener(this);
+ addGBComponent(defSaveButton,defaultsPanel, 0, 1, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+
+ addGBComponent(configPanel,DefaultsPanel, 0, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));
+ addGBComponent(defaultsPanel,DefaultsPanel, 1, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));
+
+ // security tab
+ SecPanel=new JPanel(new GridBagLayout());
+
+ JPanel encryptionPanel = new JPanel(new GridBagLayout());
+ encryptionPanel.setBorder(BorderFactory.createTitledBorder("Session Encryption"));
+ encNone = addCheckbox("None", null, encryptionPanel);
+ encTLS = addCheckbox("Anonymous TLS", null, encryptionPanel);
+ encX509 = addJCheckBox("TLS with X.509 certificates", null, encryptionPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.REMAINDER,new Insets(0,0,0,60),0,0));
+
+ JPanel x509Panel = new JPanel(new GridBagLayout());
+ x509Panel.setBorder(BorderFactory.createTitledBorder("X.509 certificates"));
+ ca = new JButton("Load CA certificate");
+ ca.setPreferredSize(new Dimension(145,25));
+ ca.addActionListener(this);
+ crl = new JButton("Load CRL certificate");
+ crl.setPreferredSize(new Dimension(145,25));
+ crl.addActionListener(this);
+ addGBComponent(ca, x509Panel, 0, 0, 1, 1, 2, 2, 0, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));
+ addGBComponent(crl, x509Panel, 1, 0, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));
+
+ JPanel authPanel = new JPanel(new GridBagLayout());
+ authPanel.setBorder(BorderFactory.createTitledBorder("Authentication"));
+ secNone = addCheckbox("None", null, authPanel);
+ secVnc = addCheckbox("Standard VNC", null, authPanel);
+ secPlain = addJCheckBox("Plaintext", null, authPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+ secManaged = addJCheckBox("Managed", null, authPanel, new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+ sendLocalUsername = new JCheckBox("Send Local Username");
+ sendLocalUsername.addItemListener(this);
+ addGBComponent(sendLocalUsername, authPanel, 1, 2, 1, 2, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,20,0,0));
+
+ secVeNCrypt = new JCheckBox("Extended encryption and authentication methods (VeNCrypt)");
+ secVeNCrypt.addItemListener(this);
+ addGBComponent(secVeNCrypt,SecPanel, 0, 0, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,20));
+ addGBComponent(encryptionPanel,SecPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(0,4,2,4));
+ addGBComponent(x509Panel,SecPanel, 0, 2, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,4,2,4));
+ addGBComponent(authPanel,SecPanel, 0, 3, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(2,4,2,4));
+
+ tabPane.add(FormatPanel);
+ tabPane.add(InputsPanel);
+ tabPane.add(MiscPanel);
+ tabPane.add(DefaultsPanel);
+ tabPane.add(SecPanel);
+ tabPane.addTab("Colour & Encoding", FormatPanel);
+ tabPane.addTab("Inputs", InputsPanel);
+ tabPane.addTab("Misc", MiscPanel);
+ tabPane.addTab("Load / Save", DefaultsPanel);
+ tabPane.addTab("Security", SecPanel);
+ tabPane.setBorder(BorderFactory.createEmptyBorder(4,4,0,4));
+
+ okButton = new JButton("OK");
+ okButton.setPreferredSize(new Dimension(90,30));
+ okButton.addActionListener(this);
+ cancelButton = new JButton("Cancel");
+ cancelButton.setPreferredSize(new Dimension(90,30));
+ cancelButton.addActionListener(this);
+
+ JPanel buttonPane = new JPanel();
+ buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
+ buttonPane.setBorder(BorderFactory.createEmptyBorder(4,0,0,0));
+ buttonPane.add(Box.createHorizontalGlue());
+ buttonPane.add(okButton);
+ buttonPane.add(Box.createRigidArea(new Dimension(4,0)));
+ buttonPane.add(cancelButton);
+ buttonPane.add(Box.createRigidArea(new Dimension(4,0)));
+
+ this.getContentPane().add(tabPane);
+ this.getContentPane().add(buttonPane);
+
+ pack();
+
+ }
+
+ public void initDialog() {
+ if (cb != null) cb.setOptions();
+ zrle.setEnabled(!autoSelect.isSelected());
+ hextile.setEnabled(!autoSelect.isSelected());
+ tight.setEnabled(!autoSelect.isSelected());
+ raw.setEnabled(!autoSelect.isSelected());
+ fullColour.setEnabled(!autoSelect.isSelected());
+ mediumColour.setEnabled(!autoSelect.isSelected());
+ lowColour.setEnabled(!autoSelect.isSelected());
+ veryLowColour.setEnabled(!autoSelect.isSelected());
+ compressLevel.setEnabled(customCompressLevel.isSelected());
+ qualityLevel.setEnabled(noJpeg.isSelected());
+ sendLocalUsername.setEnabled(secVeNCrypt.isEnabled()&&
+ (secPlain.isSelected()||secManaged.isSelected()));
+ }
+
+ JRadioButton addRadioCheckbox(String str, ButtonGroup group, JPanel panel) {
+ JRadioButton c = new JRadioButton(str);
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.LINE_START;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.weightx = 1;
+ gbc.weighty = 1;
+ panel.add(c,gbc);
+ group.add(c);
+ c.addItemListener(this);
+ return c;
+ }
+
+ JCheckBox addCheckbox(String str, ButtonGroup group, JPanel panel) {
+ JCheckBox c = new JCheckBox(str);
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.LINE_START;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.weightx = 1;
+ gbc.weighty = 1;
+ panel.add(c,gbc);
+ if (group != null)
+ group.add(c);
+ c.addItemListener(this);
+ return c;
+ }
+
+ JCheckBox addJCheckBox(String str, ButtonGroup group, JPanel panel,
+ GridBagConstraints gbc) {
+ JCheckBox c = new JCheckBox(str);
+ panel.add(c,gbc);
+ if (group != null)
+ group.add(c);
+ c.addItemListener(this);
+
+ return c;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JButton && (JButton)s == okButton) {
+ ok = true;
+ if (cb != null) cb.getOptions();
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == cancelButton) {
+ ok = false;
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == defSaveButton) {
+ try {
+ defaults.Save();
+ } catch (java.lang.Exception x) { }
+ } else if (s instanceof JButton && (JButton)s == ca) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to X509 CA certificate");
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ CSecurityTLS.x509ca.setParam(fc.getSelectedFile().toString());
+ } else if (s instanceof JButton && (JButton)s == crl) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to X509 CRL file");
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ CSecurityTLS.x509crl.setParam(fc.getSelectedFile().toString());
+ }
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JCheckBox && (JCheckBox)s == autoSelect) {
+ zrle.setEnabled(!autoSelect.isSelected());
+ hextile.setEnabled(!autoSelect.isSelected());
+ tight.setEnabled(!autoSelect.isSelected());
+ raw.setEnabled(!autoSelect.isSelected());
+ fullColour.setEnabled(!autoSelect.isSelected());
+ mediumColour.setEnabled(!autoSelect.isSelected());
+ lowColour.setEnabled(!autoSelect.isSelected());
+ veryLowColour.setEnabled(!autoSelect.isSelected());
+ defaults.setPref("autoSelect",(autoSelect.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == customCompressLevel) {
+ compressLevel.setEnabled(customCompressLevel.isSelected());
+ defaults.setPref("customCompressLevel",(customCompressLevel.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == noJpeg) {
+ qualityLevel.setEnabled(noJpeg.isSelected());
+ defaults.setPref("noJpeg",(noJpeg.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == sendLocalUsername) {
+ defaults.setPref("sendLocalUsername",(sendLocalUsername.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == secVeNCrypt) {
+ encNone.setEnabled(secVeNCrypt.isSelected());
+ encTLS.setEnabled(secVeNCrypt.isSelected());
+ encX509.setEnabled(secVeNCrypt.isSelected());
+ ca.setEnabled(secVeNCrypt.isSelected());
+ crl.setEnabled(secVeNCrypt.isSelected());
+ secManaged.setEnabled(secVeNCrypt.isSelected());
+ secNone.setEnabled(secVeNCrypt.isSelected());
+ secVnc.setEnabled(secVeNCrypt.isSelected());
+ secPlain.setEnabled(secVeNCrypt.isSelected());
+ sendLocalUsername.setEnabled(secVeNCrypt.isSelected());
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == secManaged ||
+ s instanceof JCheckBox && (JCheckBox)s == secPlain) {
+ sendLocalUsername.setEnabled(secManaged.isSelected()||secPlain.isSelected());
+ }
+ }
+
+}
diff --git a/java/src/com/tigervnc/vncviewer/TLSTunnel.java b/java/src/com/tigervnc/vncviewer/OptionsDialogCallback.java
index 00cfb4ab..f6897e24 100644
--- a/java/src/com/tigervnc/vncviewer/TLSTunnel.java
+++ b/java/src/com/tigervnc/vncviewer/OptionsDialogCallback.java
@@ -1,18 +1,15 @@
-/*
- * Copyright (C) 2003 Sun Microsystems, Inc.
- * Copyright (C) 2003-2010 Martin Koegler
- * Copyright (C) 2006 OCCAM Financial Technology
- *
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
* This 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 software 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 software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
@@ -21,31 +18,7 @@
package com.tigervnc.vncviewer;
-import java.util.*;
-import java.net.*;
-import javax.net.ssl.*;
-
-public class TLSTunnel extends TLSTunnelBase
-{
-
- public TLSTunnel (Socket sock_)
- {
- super (sock_);
- }
-
-
- protected void setParam (SSLSocket sock)
- {
- String[]supported;
- ArrayList enabled = new ArrayList ();
-
- supported = sock.getSupportedCipherSuites ();
-
- for (int i = 0; i < supported.length; i++)
- if (supported[i].matches (".*DH_anon.*"))
- enabled.add (supported[i]);
-
- sock.setEnabledCipherSuites ((String[])enabled.toArray (new String[0]));
- }
-
+public interface OptionsDialogCallback {
+ public void setOptions();
+ public void getOptions();
}
diff --git a/java/src/com/tigervnc/vncviewer/OptionsFrame.java b/java/src/com/tigervnc/vncviewer/OptionsFrame.java
deleted file mode 100644
index 573f21d9..00000000
--- a/java/src/com/tigervnc/vncviewer/OptionsFrame.java
+++ /dev/null
@@ -1,441 +0,0 @@
-//
-// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// Options frame.
-//
-// This deals with all the options the user can play with.
-// It sets the encodings array and some booleans.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-
-class OptionsFrame extends Frame
- implements WindowListener, ActionListener, ItemListener {
-
- static String[] names = {
- "Encoding",
- "Compression level",
- "JPEG image quality",
- "Cursor shape updates",
- "Use CopyRect",
- "Restricted colors",
- "Mouse buttons 2 and 3",
- "View only",
- "Scaling factor",
- "Scale remote cursor",
- "Share desktop"
- };
-
- static String[][] values = {
- { "Auto", "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight", "ZRLE" },
- { "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
- { "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
- { "Enable", "Ignore", "Disable" },
- { "Yes", "No" },
- { "Yes", "No" },
- { "Normal", "Reversed" },
- { "Yes", "No" },
- { "Auto", "1%", "5%", "10%", "20%", "25%", "50%", "75%", "100%"},
- { "No", "50%", "75%", "125%", "150%" },
- { "Yes", "No" }
- };
-
- final int
- encodingIndex = 0,
- compressLevelIndex = 1,
- jpegQualityIndex = 2,
- cursorUpdatesIndex = 3,
- useCopyRectIndex = 4,
- eightBitColorsIndex = 5,
- mouseButtonIndex = 6,
- viewOnlyIndex = 7,
- scalingFactorIndex = 8,
- scaleCursorIndex = 9,
- shareDesktopIndex = 10;
-
- Label[] labels = new Label[names.length];
- Choice[] choices = new Choice[names.length];
- Button closeButton;
- VncViewer viewer;
-
-
- //
- // The actual data which other classes look at:
- //
-
- int preferredEncoding;
- int compressLevel;
- int jpegQuality;
- boolean useCopyRect;
- boolean requestCursorUpdates;
- boolean ignoreCursorUpdates;
-
- boolean eightBitColors;
-
- boolean reverseMouseButtons2And3;
- boolean shareDesktop;
- boolean viewOnly;
- int scaleCursor;
-
- boolean autoScale;
- int scalingFactor;
-
- //
- // Constructor. Set up the labels and choices from the names and values
- // arrays.
- //
-
- OptionsFrame(VncViewer v) {
- super("TigerVNC Options");
-
- viewer = v;
-
- GridBagLayout gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.fill = GridBagConstraints.BOTH;
-
- for (int i = 0; i < names.length; i++) {
- labels[i] = new Label(names[i]);
- gbc.gridwidth = 1;
- gridbag.setConstraints(labels[i],gbc);
- add(labels[i]);
-
- choices[i] = new Choice();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gridbag.setConstraints(choices[i],gbc);
- add(choices[i]);
- choices[i].addItemListener(this);
-
- for (int j = 0; j < values[i].length; j++) {
- choices[i].addItem(values[i][j]);
- }
- }
-
- closeButton = new Button("Close");
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gridbag.setConstraints(closeButton, gbc);
- add(closeButton);
- closeButton.addActionListener(this);
-
- pack();
-
- addWindowListener(this);
-
- // Set up defaults
-
- choices[encodingIndex].select("Auto");
- choices[compressLevelIndex].select("Default");
- choices[jpegQualityIndex].select("6");
- choices[cursorUpdatesIndex].select("Enable");
- choices[useCopyRectIndex].select("Yes");
- choices[eightBitColorsIndex].select("No");
- choices[mouseButtonIndex].select("Normal");
- choices[viewOnlyIndex].select("No");
- choices[scaleCursorIndex].select("No");
- choices[shareDesktopIndex].select("Yes");
-
- // But let them be overridden by parameters
-
- for (int i = 0; i < names.length; i++) {
- String s = viewer.readParameter(names[i], false);
- if (s != null) {
- for (int j = 0; j < values[i].length; j++) {
- if (s.equalsIgnoreCase(values[i][j])) {
- choices[i].select(j);
- }
- }
- }
- }
-
- // Get scaling factor from parameters and set it
- // to gui and class member scalingFactor
-
- String s = viewer.readParameter("Scaling Factor", false);
- if (s == null) s = "100%";
- setScalingFactor(s);
- if (autoScale) {
- choices[scalingFactorIndex].select("Auto");
- } else {
- choices[scalingFactorIndex].select(s);
- }
-
- // Make the booleans and encodings array correspond to the state of the GUI
-
- setEncodings();
- setColorFormat();
- setOtherOptions();
- }
-
- //
- // Set scaling factor class member value
- //
-
- void setScalingFactor(int sf) {
- setScalingFactor(((Integer)sf).toString());
- }
-
- void setScalingFactor(String s) {
- autoScale = false;
- scalingFactor = 100;
- if (s != null) {
- if (s.equalsIgnoreCase("Auto")) {
- autoScale = true;
- } else {
- // Remove the '%' char at the end of string if present.
- if (s.charAt(s.length() - 1) == '%') {
- s = s.substring(0, s.length() - 1);
- }
- // Convert to an integer.
- try {
- scalingFactor = Integer.parseInt(s);
- }
- catch (NumberFormatException e) {
- scalingFactor = 100;
- }
- // Make sure scalingFactor is in the range of [1..1000].
- if (scalingFactor < 1) {
- scalingFactor = 1;
- } else if (scalingFactor > 1000) {
- scalingFactor = 1000;
- }
- }
- }
- }
-
-
- //
- // Disable the shareDesktop option
- //
-
- void disableShareDesktop() {
- labels[shareDesktopIndex].setEnabled(false);
- choices[shareDesktopIndex].setEnabled(false);
- }
-
- //
- // setEncodings looks at the encoding, compression level, JPEG
- // quality level, cursor shape updates and copyRect choices and sets
- // corresponding variables properly. Then it calls the VncViewer's
- // setEncodings method to send a SetEncodings message to the RFB
- // server.
- //
-
- void setEncodings() {
- useCopyRect = choices[useCopyRectIndex].getSelectedItem().equals("Yes");
-
- preferredEncoding = RfbProto.EncodingRaw;
- boolean enableCompressLevel = false;
- boolean enableQualityLevel = false;
-
- if (choices[encodingIndex].getSelectedItem().equals("RRE")) {
- preferredEncoding = RfbProto.EncodingRRE;
- } else if (choices[encodingIndex].getSelectedItem().equals("CoRRE")) {
- preferredEncoding = RfbProto.EncodingCoRRE;
- } else if (choices[encodingIndex].getSelectedItem().equals("Hextile")) {
- preferredEncoding = RfbProto.EncodingHextile;
- } else if (choices[encodingIndex].getSelectedItem().equals("ZRLE")) {
- preferredEncoding = RfbProto.EncodingZRLE;
- } else if (choices[encodingIndex].getSelectedItem().equals("Zlib")) {
- preferredEncoding = RfbProto.EncodingZlib;
- enableCompressLevel = true;
- } else if (choices[encodingIndex].getSelectedItem().equals("Tight")) {
- preferredEncoding = RfbProto.EncodingTight;
- enableCompressLevel = true;
- enableQualityLevel = !eightBitColors;
- } else if (choices[encodingIndex].getSelectedItem().equals("Auto")) {
- preferredEncoding = -1;
- enableQualityLevel = !eightBitColors;
- }
-
- // Handle compression level setting.
-
- try {
- compressLevel =
- Integer.parseInt(choices[compressLevelIndex].getSelectedItem());
- }
- catch (NumberFormatException e) {
- compressLevel = -1;
- }
- if (compressLevel < 1 || compressLevel > 9) {
- compressLevel = -1;
- }
- labels[compressLevelIndex].setEnabled(enableCompressLevel);
- choices[compressLevelIndex].setEnabled(enableCompressLevel);
-
- // Handle JPEG quality setting.
-
- try {
- jpegQuality =
- Integer.parseInt(choices[jpegQualityIndex].getSelectedItem());
- }
- catch (NumberFormatException e) {
- jpegQuality = -1;
- }
- if (jpegQuality < 0 || jpegQuality > 9) {
- jpegQuality = -1;
- }
- labels[jpegQualityIndex].setEnabled(enableQualityLevel);
- choices[jpegQualityIndex].setEnabled(enableQualityLevel);
-
- // Request cursor shape updates if necessary.
-
- requestCursorUpdates =
- !choices[cursorUpdatesIndex].getSelectedItem().equals("Disable");
-
- if (requestCursorUpdates) {
- ignoreCursorUpdates =
- choices[cursorUpdatesIndex].getSelectedItem().equals("Ignore");
- }
-
- viewer.setEncodings();
- }
-
- //
- // setColorFormat sets eightBitColors variable depending on the GUI
- // setting, causing switches between 8-bit and 24-bit colors mode if
- // necessary.
- //
-
- void setColorFormat() {
-
- eightBitColors =
- choices[eightBitColorsIndex].getSelectedItem().equals("Yes");
-
- boolean enableJPEG = !eightBitColors &&
- (choices[encodingIndex].getSelectedItem().equals("Tight") ||
- choices[encodingIndex].getSelectedItem().equals("Auto"));
-
- labels[jpegQualityIndex].setEnabled(enableJPEG);
- choices[jpegQualityIndex].setEnabled(enableJPEG);
- }
-
- //
- // setOtherOptions looks at the "other" choices (ones that do not
- // cause sending any protocol messages) and sets the boolean flags
- // appropriately.
- //
-
- void setOtherOptions() {
-
- reverseMouseButtons2And3
- = choices[mouseButtonIndex].getSelectedItem().equals("Reversed");
-
- viewOnly
- = choices[viewOnlyIndex].getSelectedItem().equals("Yes");
- if (viewer.vc != null)
- viewer.vc.enableInput(!viewOnly);
-
- shareDesktop
- = choices[shareDesktopIndex].getSelectedItem().equals("Yes");
-
- String scaleString = choices[scaleCursorIndex].getSelectedItem();
- if (scaleString.endsWith("%"))
- scaleString = scaleString.substring(0, scaleString.length() - 1);
- try {
- scaleCursor = Integer.parseInt(scaleString);
- }
- catch (NumberFormatException e) {
- scaleCursor = 0;
- }
- if (scaleCursor < 10 || scaleCursor > 500) {
- scaleCursor = 0;
- }
- if (requestCursorUpdates && !ignoreCursorUpdates && !viewOnly) {
- labels[scaleCursorIndex].setEnabled(true);
- choices[scaleCursorIndex].setEnabled(true);
- } else {
- labels[scaleCursorIndex].setEnabled(false);
- choices[scaleCursorIndex].setEnabled(false);
- }
- if (viewer.vc != null)
- viewer.vc.createSoftCursor(); // update cursor scaling
- }
-
-
- //
- // Respond to actions on Choice controls
- //
-
- public void itemStateChanged(ItemEvent evt) {
- Object source = evt.getSource();
-
- if (source == choices[encodingIndex] ||
- source == choices[compressLevelIndex] ||
- source == choices[jpegQualityIndex] ||
- source == choices[cursorUpdatesIndex] ||
- source == choices[useCopyRectIndex]) {
-
- setEncodings();
-
- if (source == choices[cursorUpdatesIndex]) {
- setOtherOptions(); // update scaleCursor state
- }
-
- } else if (source == choices[eightBitColorsIndex]) {
-
- setColorFormat();
-
- } else if (source == choices[mouseButtonIndex] ||
- source == choices[shareDesktopIndex] ||
- source == choices[viewOnlyIndex] ||
- source == choices[scaleCursorIndex]) {
-
- setOtherOptions();
-
- } else if (source == choices[scalingFactorIndex]){
- // Tell VNC canvas that scaling factor has changed
- setScalingFactor(choices[scalingFactorIndex].getSelectedItem());
- if (viewer.vc != null)
- viewer.vc.setScalingFactor(scalingFactor);
- }
- }
-
- //
- // Respond to button press
- //
-
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == closeButton)
- setVisible(false);
- }
-
- //
- // Respond to window events
- //
-
- public void windowClosing(WindowEvent evt) {
- setVisible(false);
- }
-
- public void windowActivated(WindowEvent evt) {}
- public void windowDeactivated(WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-}
diff --git a/java/src/com/tigervnc/vncviewer/PasswdDialog.java b/java/src/com/tigervnc/vncviewer/PasswdDialog.java
new file mode 100644
index 00000000..eaace698
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/PasswdDialog.java
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.net.URL;
+
+class PasswdDialog extends Dialog implements KeyListener{
+
+ public PasswdDialog(String title, boolean userDisabled, boolean passwdDisabled) {
+ super(true);
+ setResizable(false);
+ setTitle(title);
+ setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+ JPanel p1 = new JPanel();
+ userLabel = new JLabel("Username:");
+ p1.add(userLabel);
+ userEntry = new JTextField(30);
+ userEntry.setEnabled(!userDisabled);
+ userLabel.setEnabled(!userDisabled);
+ p1.add(userEntry);
+ userEntry.addKeyListener(this);
+
+ JPanel p2 = new JPanel();
+ passwdLabel = new JLabel("Password:");
+ passwdLabel.setPreferredSize(userLabel.getPreferredSize());
+ p2.add(passwdLabel);
+ passwdEntry = new JPasswordField(30);
+ passwdEntry.setEnabled(!passwdDisabled);
+ passwdLabel.setEnabled(!passwdDisabled);
+ p2.add(passwdEntry);
+ passwdEntry.addKeyListener(this);
+
+ getContentPane().setLayout(new BoxLayout(getContentPane(),BoxLayout.Y_AXIS));
+ getContentPane().add(p1);
+ getContentPane().add(p2);
+ pack();
+ if (userEntry.isEnabled()) {
+ userEntry.requestFocus();
+ } else {
+ passwdEntry.requestFocus();
+ }
+ }
+
+ /** Handle the key-typed event. */
+ public void keyTyped(KeyEvent event) { }
+ /** Handle the key-released event. */
+ public void keyReleased(KeyEvent event) { }
+ /** Handle the key-pressed event. */
+ public void keyPressed(KeyEvent event) {
+ Object s = event.getSource();
+ if (s instanceof JTextField && (JTextField)s == userEntry) {
+ if (event.getKeyCode() == KeyEvent.VK_ENTER) {
+ ok = true;
+ endDialog();
+ }
+ } else if (s instanceof JPasswordField && (JPasswordField)s == passwdEntry) {
+ if (event.getKeyCode() == KeyEvent.VK_ENTER) {
+ ok = true;
+ endDialog();
+ }
+ }
+ }
+
+ JLabel userLabel;
+ JTextField userEntry;
+ JLabel passwdLabel;
+ JTextField passwdEntry;
+}
diff --git a/java/src/com/tigervnc/vncviewer/PixelBufferImage.java b/java/src/com/tigervnc/vncviewer/PixelBufferImage.java
new file mode 100644
index 00000000..7e5e7174
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/PixelBufferImage.java
@@ -0,0 +1,185 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// PixelBufferImage is an PixelBuffer which also acts as an ImageProducer.
+// Currently it only supports 8-bit colourmapped pixel format.
+//
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.nio.ByteOrder;
+import javax.swing.JScrollPane;
+
+import com.tigervnc.rfb.*;
+
+public class PixelBufferImage extends PixelBuffer implements ImageProducer
+{
+ public PixelBufferImage(int w, int h, CConn cc_, DesktopWindow desktop_) {
+ cc = cc_;
+ desktop = desktop_;
+ PixelFormat nativePF = getNativePF();
+ switch ((nativePF.depth > cc.serverPF.depth) ? cc.serverPF.depth : nativePF.depth) {
+ case 8:
+ setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+ break;
+ case 16:
+ setPF(new PixelFormat(16,16,false,true,0xF800,0x07C0,0x003E,0,0,0));
+ break;
+ case 24:
+ setPF(new PixelFormat(32,24,false,true,0xff,0xff,0xff,16,8,0));
+ break;
+ default:
+ setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+ vlog.debug("Unsupported native PF, defaulting to depth 8");
+ }
+ resize(w, h);
+ }
+
+ // resize() resizes the image, preserving the image data where possible.
+ public void resize(int w, int h) {
+ if (w == width() && h == height()) return;
+
+ int rowsToCopy = h < height() ? h : height();
+ int copyWidth = w < width() ? w : width();
+ int oldWidth = width();
+ int[] oldData = data;
+
+ width_ = w;
+ height_ = h;
+ image = desktop.createImage(this);
+ //image.setAccelerationPriority(1);
+
+ data = new int[width() * height()];
+
+ for (int i = 0; i < rowsToCopy; i++)
+ System.arraycopy(oldData, copyWidth * i,
+ data, width() * i, copyWidth);
+ }
+
+ private PixelFormat getNativePF() {
+ PixelFormat pf;
+ cm = java.awt.Toolkit.getDefaultToolkit().getColorModel();
+ if (cm.getColorSpace().getType() == java.awt.color.ColorSpace.TYPE_RGB) {
+ int depth = cm.getPixelSize();
+ int bpp = (depth > 16 ? 32 : (depth > 8 ? 16 : 8));
+ ByteOrder byteOrder = ByteOrder.nativeOrder();
+ boolean bigEndian = (byteOrder == ByteOrder.BIG_ENDIAN ? true : false);
+ boolean trueColour = (depth > 8 ? true : false);
+ int redShift = cm.getComponentSize()[0] + cm.getComponentSize()[1];
+ int greenShift = cm.getComponentSize()[0];
+ int blueShift = 0;
+ pf = new PixelFormat(bpp, depth, bigEndian, trueColour,
+ (depth > 8 ? 0xff : 0),
+ (depth > 8 ? 0xff : 0),
+ (depth > 8 ? 0xff : 0),
+ (depth > 8 ? redShift : 0),
+ (depth > 8 ? greenShift : 0),
+ (depth > 8 ? blueShift : 0));
+ } else {
+ pf = new PixelFormat(8, 8, false, false, 7, 7, 3, 0, 3, 6);
+ }
+ vlog.debug("Native pixel format is "+pf.print());
+ return pf;
+ }
+
+ // put() causes the given rectangle to be drawn using the given graphics
+ // context.
+ public void put(int x, int y, int w, int h, Graphics g) {
+ if (ic != null) {
+ ic.setPixels(x, y, w, h, cm, data, width() * y + x, width());
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+ }
+
+ // fillRect(), imageRect(), maskRect() are inherited from PixelBuffer. For
+ // copyRect() we also need to tell the ImageConsumer that the pixels have
+ // changed (this is done in the put() call for the others).
+
+ public void copyRect(int x, int y, int w, int h, int srcX, int srcY) {
+ super.copyRect(x, y, w, h, srcX, srcY);
+ if (ic == null) return;
+ ic.setPixels(x, y, w, h, cm, data, width() * y + x, width());
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+
+ // setColourMapEntries() changes some of the entries in the colourmap.
+ // However these settings won't take effect until updateColourMap() is
+ // called. This is because getting java to recalculate its internal
+ // translation table and redraw the screen is expensive.
+
+ public void setColourMapEntries(int firstColour, int nColours_,
+ int[] rgbs) {
+ nColours = nColours_;
+ reds = new byte[nColours];
+ blues = new byte[nColours];
+ greens = new byte[nColours];
+ for (int i = 0; i < nColours; i++) {
+ reds[firstColour+i] = (byte)(rgbs[i*3] >> 8);
+ greens[firstColour+i] = (byte)(rgbs[i*3+1] >> 8);
+ blues[firstColour+i] = (byte)(rgbs[i*3+2] >> 8);
+ }
+ }
+
+ // ImageProducer methods
+
+ public void updateColourMap() {
+ cm = new IndexColorModel(8, nColours, reds, greens, blues);
+ }
+
+ public void addConsumer(ImageConsumer c) {
+ if (ic == c) return;
+
+ vlog.debug("adding consumer "+c);
+
+ if (ic != null)
+ vlog.error("Only one ImageConsumer allowed - discarding old one");
+
+ ic = c;
+ ic.setDimensions(width(), height());
+ ic.setHints(ImageConsumer.RANDOMPIXELORDER);
+ // Calling ic.setColorModel(cm) seemed to help in some earlier versions of
+ // the JDK, but it shouldn't be necessary because we pass the ColorModel
+ // with each setPixels() call.
+ ic.setPixels(0, 0, width(), height(), cm, data, 0, width());
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+
+ public void removeConsumer(ImageConsumer c) {
+ System.err.println("removeConsumer "+c);
+ if (ic == c) ic = null;
+ }
+
+ public boolean isConsumer(ImageConsumer c) { return ic == c; }
+ public void requestTopDownLeftRightResend(ImageConsumer c) {}
+ public void startProduction(ImageConsumer c) { addConsumer(c); }
+
+ Image image;
+ ImageConsumer ic;
+
+ int nColours;
+ byte[] reds;
+ byte[] greens;
+ byte[] blues;
+
+ CConn cc;
+ DesktopWindow desktop;
+ static LogWriter vlog = new LogWriter("PixelBufferImage");
+}
diff --git a/java/src/com/tigervnc/vncviewer/README b/java/src/com/tigervnc/vncviewer/README
index 39ba825f..c6949d59 100644
--- a/java/src/com/tigervnc/vncviewer/README
+++ b/java/src/com/tigervnc/vncviewer/README
@@ -9,7 +9,7 @@ optimizations, major GUI improvements, and more.
Copyright (C) 1999 AT&T Laboratories Cambridge.
Copyright (C) 2000 Tridia Corp.
- Copyright (C) 2002-2003 RealVNC Ltd.
+ Copyright (C) 2002-2005 RealVNC Ltd.
Copyright (C) 2001-2004 HorizonLive.com, Inc.
Copyright (C) 2000-2007 Constantin Kaplinsky
Copyright (C) 2000-2007 TightVNC Group
diff --git a/java/src/com/tigervnc/vncviewer/RecordOutputStream.java b/java/src/com/tigervnc/vncviewer/RecordOutputStream.java
deleted file mode 100644
index 7f132492..00000000
--- a/java/src/com/tigervnc/vncviewer/RecordOutputStream.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.tigervnc.vncviewer;
-
-import java.io.DataOutput;
-import java.io.IOException;
-
-public class RecordOutputStream implements DataOutput {
-
- public RecordOutputStream(RfbProto rfbproto) {
- rfb = rfbproto;
- }
-
- private boolean canWrite() {
- return ((rfb != null) && (rfb.rec != null));
- }
-
- public void write(byte[] b) throws IOException {
- if (canWrite())
- rfb.rec.write(b);
- }
-
- public void write(byte[] b, int off, int len) throws IOException {
- if (canWrite())
- rfb.rec.write(b, off, len);
- }
-
- public void write(int b) throws IOException {
- if (canWrite())
- rfb.rec.writeIntBE(b);
- }
-
- public void writeBoolean(boolean v) { }
-
- public void writeByte(int v) throws IOException {
- if (canWrite()) {
- rfb.rec.writeByte(v);
- }
- }
-
- public void writeBytes(String s) { }
- public void writeChar(int v) { }
- public void writeChars(String s) { }
- public void writeDouble(double v) { }
- public void writeFloat(float v) { }
-
- public void writeInt(int v) throws IOException {
- if (canWrite())
- rfb.rec.writeIntBE(v);
- }
-
- public void writeLong(long v) { }
-
- public void writeShort(int v) throws IOException {
- if (canWrite())
- rfb.rec.writeShortBE(v);
- }
-
- public void writeUTF(String str) { }
-
- private RfbProto rfb = null;
-}
diff --git a/java/src/com/tigervnc/vncviewer/RecordingFrame.java b/java/src/com/tigervnc/vncviewer/RecordingFrame.java
deleted file mode 100644
index 6bf40ea0..00000000
--- a/java/src/com/tigervnc/vncviewer/RecordingFrame.java
+++ /dev/null
@@ -1,313 +0,0 @@
-//
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// Recording frame. It allows to control recording RFB sessions into
-// FBS (FrameBuffer Stream) files.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.io.*;
-import java.awt.*;
-import java.awt.event.*;
-
-class RecordingFrame extends Frame
- implements WindowListener, ActionListener {
-
- boolean recording;
-
- TextField fnameField;
- Button browseButton;
-
- Label statusLabel;
-
- Button recordButton, nextButton, closeButton;
- VncViewer viewer;
-
- //
- // Check if current security manager allows to create a
- // RecordingFrame object.
- //
-
- public static boolean checkSecurity() {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- try {
- security.checkPropertyAccess("user.dir");
- security.checkPropertyAccess("file.separator");
- // Work around (rare) checkPropertyAccess bug
- System.getProperty("user.dir");
- } catch (SecurityException e) {
- System.out.println("SecurityManager restricts session recording.");
- return false;
- }
- }
- return true;
- }
-
- //
- // Constructor.
- //
-
- RecordingFrame(VncViewer v) {
- super("TigerVNC Session Recording");
-
- viewer = v;
-
- // Determine initial filename for next saved session.
- // FIXME: Check SecurityManager.
-
- String fname = nextNewFilename(System.getProperty("user.dir") +
- System.getProperty("file.separator") +
- "vncsession.fbs");
-
- // Construct new panel with file name field and "Browse" button.
-
- Panel fnamePanel = new Panel();
- GridBagLayout fnameGridbag = new GridBagLayout();
- fnamePanel.setLayout(fnameGridbag);
-
- GridBagConstraints fnameConstraints = new GridBagConstraints();
- fnameConstraints.gridwidth = GridBagConstraints.RELATIVE;
- fnameConstraints.fill = GridBagConstraints.BOTH;
- fnameConstraints.weightx = 4.0;
-
- fnameField = new TextField(fname, 64);
- fnameGridbag.setConstraints(fnameField, fnameConstraints);
- fnamePanel.add(fnameField);
- fnameField.addActionListener(this);
-
- fnameConstraints.gridwidth = GridBagConstraints.REMAINDER;
- fnameConstraints.weightx = 1.0;
-
- browseButton = new Button("Browse");
- fnameGridbag.setConstraints(browseButton, fnameConstraints);
- fnamePanel.add(browseButton);
- browseButton.addActionListener(this);
-
- // Construct the frame.
-
- GridBagLayout gridbag = new GridBagLayout();
- setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.BOTH;
- gbc.weighty = 1.0;
- gbc.insets = new Insets(10, 0, 0, 0);
-
- Label helpLabel =
- new Label("File name to save next recorded session in:", Label.CENTER);
- gridbag.setConstraints(helpLabel, gbc);
- add(helpLabel);
-
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weighty = 0.0;
- gbc.insets = new Insets(0, 0, 0, 0);
-
- gridbag.setConstraints(fnamePanel, gbc);
- add(fnamePanel);
-
- gbc.fill = GridBagConstraints.BOTH;
- gbc.weighty = 1.0;
- gbc.insets = new Insets(10, 0, 10, 0);
-
- statusLabel = new Label("", Label.CENTER);
- gridbag.setConstraints(statusLabel, gbc);
- add(statusLabel);
-
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.weightx = 1.0;
- gbc.weighty = 0.0;
- gbc.gridwidth = 1;
- gbc.insets = new Insets(0, 0, 0, 0);
-
- recordButton = new Button("Record");
- gridbag.setConstraints(recordButton, gbc);
- add(recordButton);
- recordButton.addActionListener(this);
-
- nextButton = new Button("Next file");
- gridbag.setConstraints(nextButton, gbc);
- add(nextButton);
- nextButton.addActionListener(this);
-
- closeButton = new Button("Close");
- gridbag.setConstraints(closeButton, gbc);
- add(closeButton);
- closeButton.addActionListener(this);
-
- // Set correct text, font and color for the statusLabel.
- stopRecording();
-
- pack();
-
- addWindowListener(this);
- }
-
- //
- // If the given string ends with ".NNN" where NNN is a decimal
- // number, increase this number by one. Otherwise, append ".001"
- // to the given string.
- //
-
- protected String nextFilename(String fname) {
- int len = fname.length();
- int suffixPos = len;
- int suffixNum = 1;
-
- if (len > 4 && fname.charAt(len - 4) == '.') {
- try {
- suffixNum = Integer.parseInt(fname.substring(len - 3, len)) + 1;
- suffixPos = len - 4;
- } catch (NumberFormatException e) { }
- }
-
- char[] zeroes = {'0', '0', '0'};
- String suffix = String.valueOf(suffixNum);
- if (suffix.length() < 3) {
- suffix = new String(zeroes, 0, 3 - suffix.length()) + suffix;
- }
-
- return fname.substring(0, suffixPos) + '.' + suffix;
- }
-
- //
- // Find next name of a file which does not exist yet.
- //
-
- protected String nextNewFilename(String fname) {
- String newName = fname;
- File f;
- try {
- do {
- newName = nextFilename(newName);
- f = new File(newName);
- } while (f.exists());
- } catch (SecurityException e) { }
-
- return newName;
- }
-
- //
- // Let the user choose a file name showing a FileDialog.
- //
-
- protected boolean browseFile() {
- File currentFile = new File(fnameField.getText());
-
- FileDialog fd =
- new FileDialog(this, "Save next session as...", FileDialog.SAVE);
- fd.setDirectory(currentFile.getParent());
- fd.setVisible(true);
- if (fd.getFile() != null) {
- String newDir = fd.getDirectory();
- String sep = System.getProperty("file.separator");
- if (newDir.length() > 0) {
- if (!sep.equals(newDir.substring(newDir.length() - sep.length())))
- newDir += sep;
- }
- String newFname = newDir + fd.getFile();
- if (newFname.equals(fnameField.getText())) {
- fnameField.setText(newFname);
- return true;
- }
- }
- return false;
- }
-
- //
- // Start recording.
- //
-
- public void startRecording() {
- statusLabel.setText("Status: Recording...");
- statusLabel.setFont(new Font("Helvetica", Font.BOLD, 12));
- statusLabel.setForeground(Color.red);
- recordButton.setLabel("Stop recording");
-
- recording = true;
-
- viewer.setRecordingStatus(fnameField.getText());
- }
-
- //
- // Stop recording.
- //
-
- public void stopRecording() {
- statusLabel.setText("Status: Not recording.");
- statusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
- statusLabel.setForeground(Color.black);
- recordButton.setLabel("Record");
-
- recording = false;
-
- viewer.setRecordingStatus(null);
- }
-
- //
- // Close our window properly.
- //
-
- public void windowClosing(WindowEvent evt) {
- setVisible(false);
- }
-
- //
- // Ignore window events we're not interested in.
- //
-
- public void windowActivated(WindowEvent evt) {}
- public void windowDeactivated (WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
-
-
- //
- // Respond to button presses
- //
-
- public void actionPerformed(ActionEvent evt) {
- if (evt.getSource() == browseButton) {
- if (browseFile() && recording)
- startRecording();
-
- } else if (evt.getSource() == recordButton) {
- if (!recording) {
- startRecording();
- } else {
- stopRecording();
- fnameField.setText(nextNewFilename(fnameField.getText()));
- }
-
- } else if (evt.getSource() == nextButton) {
- fnameField.setText(nextNewFilename(fnameField.getText()));
- if (recording)
- startRecording();
-
- } else if (evt.getSource() == closeButton) {
- setVisible(false);
-
- }
- }
-}
diff --git a/java/src/com/tigervnc/vncviewer/ReloginPanel.java b/java/src/com/tigervnc/vncviewer/ReloginPanel.java
deleted file mode 100644
index 51d9d210..00000000
--- a/java/src/com/tigervnc/vncviewer/ReloginPanel.java
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (C) 2002 Cendio Systems. All Rights Reserved.
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// ReloginPanel class implements panel with a button for logging in again,
-// after fatal errors or disconnect
-//
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.applet.*;
-
-//
-// The panel which implements the Relogin button
-//
-
-class ReloginPanel extends Panel implements ActionListener {
- Button reloginButton;
- Button closeButton;
- VncViewer viewer;
-
- //
- // Constructor.
- //
- public ReloginPanel(VncViewer v) {
- viewer = v;
- setLayout(new FlowLayout(FlowLayout.CENTER));
- reloginButton = new Button("Login again");
- add(reloginButton);
- reloginButton.addActionListener(this);
- if (viewer.inSeparateFrame) {
- closeButton = new Button("Close window");
- add(closeButton);
- closeButton.addActionListener(this);
- }
- }
-
- //
- // This method is called when a button is pressed.
- //
- public synchronized void actionPerformed(ActionEvent evt) {
- if (viewer.inSeparateFrame)
- viewer.vncFrame.dispose();
- if (evt.getSource() == reloginButton)
- viewer.getAppletContext().showDocument(viewer.getDocumentBase());
- }
-}
diff --git a/java/src/com/tigervnc/vncviewer/RfbInputStream.java b/java/src/com/tigervnc/vncviewer/RfbInputStream.java
deleted file mode 100644
index cac3ec77..00000000
--- a/java/src/com/tigervnc/vncviewer/RfbInputStream.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.tigervnc.vncviewer;
-
-import java.io.IOException;
-
-//
-// This class is layer between data of private RfbProto class
-// and classes in other packages.
-//
-// For now this class is used by com.tigervnc.decoder.RawDecoder
-//
-public class RfbInputStream {
- RfbInputStream(RfbProto rfbProto) {
- rfb = rfbProto;
- }
-
- //
- // Read data methods
- //
-
- public void readFully(byte b[]) throws IOException {
- readFully(b, 0, b.length);
- }
-
- public void readFully(byte b[], int off, int len) throws IOException {
- rfb.readFully(b, off, len);
- }
-
- public int readU32() throws IOException {
- return rfb.readU32();
- }
-
- public int readU8() throws IOException {
- return rfb.readU8();
- }
-
- public int readCompactLen() throws IOException {
- return rfb.readCompactLen();
- }
-
- public int readU16() throws IOException {
- return rfb.readU16();
- }
-
- private RfbProto rfb = null;
-}
diff --git a/java/src/com/tigervnc/vncviewer/RfbProto.java b/java/src/com/tigervnc/vncviewer/RfbProto.java
deleted file mode 100644
index da54c56b..00000000
--- a/java/src/com/tigervnc/vncviewer/RfbProto.java
+++ /dev/null
@@ -1,1202 +0,0 @@
-//
-// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2001-2006 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// RfbProto.java
-//
-
-package com.tigervnc.vncviewer;
-
-import java.io.*;
-import java.awt.*;
-import java.awt.event.*;
-import java.net.Socket;
-import java.util.zip.*;
-
-class RfbProto {
-
- final static String
- versionMsg_3_3 = "RFB 003.003\n",
- versionMsg_3_7 = "RFB 003.007\n",
- versionMsg_3_8 = "RFB 003.008\n";
-
- // Security types
- final static int
- SecTypeInvalid = 0,
- SecTypeNone = 1,
- SecTypeVncAuth = 2,
- SecTypeTight = 16,
- SecTypeVeNCrypt = 19,
- SecTypePlain = 256,
- SecTypeTLSNone = 257,
- SecTypeTLSVnc = 258,
- SecTypeTLSPlain = 259,
- SecTypeX509None = 260,
- SecTypeX509Vnc = 261,
- SecTypeX509Plain = 262;
-
- // VNC authentication results
- final static int
- VncAuthOK = 0,
- VncAuthFailed = 1,
- VncAuthTooMany = 2;
-
- // Standard server-to-client messages
- final static int
- FramebufferUpdate = 0,
- SetColourMapEntries = 1,
- Bell = 2,
- ServerCutText = 3;
-
- // Standard client-to-server messages
- final static int
- SetPixelFormat = 0,
- FixColourMapEntries = 1,
- SetEncodings = 2,
- FramebufferUpdateRequest = 3,
- KeyboardEvent = 4,
- PointerEvent = 5,
- ClientCutText = 6;
-
- // Supported encodings and pseudo-encodings
- final static int
- EncodingRaw = 0,
- EncodingCopyRect = 1,
- EncodingRRE = 2,
- EncodingCoRRE = 4,
- EncodingHextile = 5,
- EncodingZlib = 6,
- EncodingTight = 7,
- EncodingZRLE = 16,
- EncodingCompressLevel0 = 0xFFFFFF00,
- EncodingQualityLevel0 = 0xFFFFFFE0,
- EncodingXCursor = 0xFFFFFF10,
- EncodingRichCursor = 0xFFFFFF11,
- EncodingPointerPos = 0xFFFFFF18,
- EncodingLastRect = 0xFFFFFF20,
- EncodingNewFBSize = 0xFFFFFF21;
-
- final static int MaxNormalEncoding = 255;
-
- // Contstants used in the Hextile decoder
- final static int
- HextileRaw = 1,
- HextileBackgroundSpecified = 2,
- HextileForegroundSpecified = 4,
- HextileAnySubrects = 8,
- HextileSubrectsColoured = 16;
-
- // Contstants used in the Tight decoder
- final static int TightMinToCompress = 12;
- final static int
- TightExplicitFilter = 0x04,
- TightFill = 0x08,
- TightJpeg = 0x09,
- TightMaxSubencoding = 0x09,
- TightFilterCopy = 0x00,
- TightFilterPalette = 0x01,
- TightFilterGradient = 0x02;
-
-
- String host;
- int port;
- Socket sock;
- OutputStream os;
- SessionRecorder rec;
- boolean inNormalProtocol = false;
- VncViewer viewer;
-
- // Input stream is declared private to make sure it can be accessed
- // only via RfbProto methods. We have to do this because we want to
- // count how many bytes were read.
- private DataInputStream is;
- private long numBytesRead = 0;
- public long getNumBytesRead() { return numBytesRead; }
-
- // Java on UNIX does not call keyPressed() on some keys, for example
- // swedish keys To prevent our workaround to produce duplicate
- // keypresses on JVMs that actually works, keep track of if
- // keyPressed() for a "broken" key was called or not.
- boolean brokenKeyPressed = false;
-
- // This will be set to true on the first framebuffer update
- // containing Zlib-, ZRLE- or Tight-encoded data.
- boolean wereZlibUpdates = false;
-
- // This fields are needed to show warnings about inefficiently saved
- // sessions only once per each saved session file.
- boolean zlibWarningShown;
- boolean tightWarningShown;
-
- // Before starting to record each saved session, we set this field
- // to 0, and increment on each framebuffer update. We don't flush
- // the SessionRecorder data into the file before the second update.
- // This allows us to write initial framebuffer update with zero
- // timestamp, to let the player show initial desktop before
- // playback.
- int numUpdatesInSession;
-
- // Measuring network throughput.
- boolean timing;
- long timeWaitedIn100us;
- long timedKbits;
-
- // Protocol version and TightVNC-specific protocol options.
- int serverMajor, serverMinor;
- int clientMajor, clientMinor;
-
- // If true, informs that the RFB socket was closed.
- private boolean closed;
-
- //
- // Constructor. Make TCP connection to RFB server.
- //
-
- RfbProto(String h, int p, VncViewer v) throws IOException {
- viewer = v;
- host = h;
- port = p;
-
- if (viewer.socketFactory == null) {
- sock = new Socket(host, port);
- sock.setTcpNoDelay(true);
- } else {
- try {
- Class factoryClass = Class.forName(viewer.socketFactory);
- SocketFactory factory = (SocketFactory)factoryClass.newInstance();
- if (viewer.inAnApplet)
- sock = factory.createSocket(host, port, viewer);
- else
- sock = factory.createSocket(host, port, viewer.mainArgs);
- } catch(Exception e) {
- e.printStackTrace();
- throw new IOException(e.getMessage());
- }
- }
- is = new DataInputStream(new BufferedInputStream(sock.getInputStream(),
- 16384));
- os = sock.getOutputStream();
-
- timing = false;
- timeWaitedIn100us = 5;
- timedKbits = 0;
- }
-
-
- synchronized void close() {
- try {
- sock.close();
- closed = true;
- System.out.println("RFB socket closed");
- if (rec != null) {
- rec.close();
- rec = null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- synchronized boolean closed() {
- return closed;
- }
-
- //
- // Read server's protocol version message
- //
-
- void readVersionMsg() throws Exception {
-
- byte[] b = new byte[12];
-
- readFully(b);
-
- if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ')
- || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9')
- || (b[6] < '0') || (b[6] > '9') || (b[7] != '.')
- || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9')
- || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
- {
- throw new Exception("Host " + host + " port " + port +
- " is not an RFB server");
- }
-
- serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
- serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
-
- if (serverMajor < 3) {
- throw new Exception("RFB server does not support protocol version 3");
- }
- }
-
-
- //
- // Write our protocol version message
- //
-
- void writeVersionMsg() throws IOException {
- clientMajor = 3;
- if (serverMajor > 3 || serverMinor >= 8) {
- clientMinor = 8;
- os.write(versionMsg_3_8.getBytes());
- } else if (serverMinor >= 7) {
- clientMinor = 7;
- os.write(versionMsg_3_7.getBytes());
- } else {
- clientMinor = 3;
- os.write(versionMsg_3_3.getBytes());
- }
- }
-
-
- //
- // Negotiate the authentication scheme.
- //
-
- int negotiateSecurity() throws Exception {
- return (clientMinor >= 7) ?
- selectSecurityType() : readSecurityType();
- }
-
- //
- // Read security type from the server (protocol version 3.3).
- //
-
- int readSecurityType() throws Exception {
- int secType = readU32();
-
- switch (secType) {
- case SecTypeInvalid:
- readConnFailedReason();
- return SecTypeInvalid; // should never be executed
- case SecTypeNone:
- case SecTypeVncAuth:
- return secType;
- default:
- throw new Exception("Unknown security type from RFB server: " + secType);
- }
- }
-
- //
- // Select security type from the server's list (protocol versions 3.7/3.8).
- //
-
- int selectSecurityType() throws Exception {
- int secType = SecTypeInvalid;
-
- // Read the list of secutiry types.
- int nSecTypes = readU8();
- if (nSecTypes == 0) {
- readConnFailedReason();
- return SecTypeInvalid; // should never be executed
- }
- byte[] secTypes = new byte[nSecTypes];
- readFully(secTypes);
-
- // Find first supported security type.
- for (int i = 0; i < nSecTypes; i++) {
- if (secTypes[i] == SecTypeNone || secTypes[i] == SecTypeVncAuth
- || secTypes[i] == SecTypeVeNCrypt) {
- secType = secTypes[i];
- break;
- }
- }
-
- if (secType == SecTypeInvalid) {
- throw new Exception("Server did not offer supported security type");
- } else {
- os.write(secType);
- }
-
- return secType;
- }
-
- int authenticateVeNCrypt() throws Exception {
- int majorVersion = readU8();
- int minorVersion = readU8();
- int Version = (majorVersion << 8) | minorVersion;
- if (Version < 0x0002) {
- os.write(0);
- os.write(0);
- throw new Exception("Server reported an unsupported VeNCrypt version");
- }
- os.write(0);
- os.write(2);
- if (readU8() != 0)
- throw new Exception("Server reported it could not support the VeNCrypt version");
- int nSecTypes = readU8();
- int[] secTypes = new int[nSecTypes];
- for(int i = 0; i < nSecTypes; i++)
- secTypes[i] = readU32();
-
- for(int i = 0; i < nSecTypes; i++)
- switch(secTypes[i])
- {
- case SecTypeNone:
- case SecTypeVncAuth:
- case SecTypePlain:
- case SecTypeTLSNone:
- case SecTypeTLSVnc:
- case SecTypeTLSPlain:
- case SecTypeX509None:
- case SecTypeX509Vnc:
- case SecTypeX509Plain:
- writeInt(secTypes[i]);
- return secTypes[i];
- }
-
- throw new Exception("No valid VeNCrypt sub-type");
- }
-
- //
- // Perform "no authentication".
- //
-
- void authenticateNone() throws Exception {
- if (clientMinor >= 8)
- readSecurityResult("No authentication");
- }
-
- //
- // Perform standard VNC Authentication.
- //
-
- void authenticateVNC(String pw) throws Exception {
- byte[] challenge = new byte[16];
- readFully(challenge);
-
- if (pw.length() > 8)
- pw = pw.substring(0, 8); // Truncate to 8 chars
-
- // Truncate password on the first zero byte.
- int firstZero = pw.indexOf(0);
- if (firstZero != -1)
- pw = pw.substring(0, firstZero);
-
- byte[] key = {0, 0, 0, 0, 0, 0, 0, 0};
- System.arraycopy(pw.getBytes(), 0, key, 0, pw.length());
-
- DesCipher des = new DesCipher(key);
-
- des.encrypt(challenge, 0, challenge, 0);
- des.encrypt(challenge, 8, challenge, 8);
-
- os.write(challenge);
-
- readSecurityResult("VNC authentication");
- }
-
- void authenticateTLS() throws Exception {
- TLSTunnel tunnel = new TLSTunnel(sock);
- tunnel.setup (this);
- }
-
- void authenticateX509() throws Exception {
- X509Tunnel tunnel = new X509Tunnel(sock);
- tunnel.setup (this);
- }
-
- void authenticatePlain(String User, String Password) throws Exception {
- byte[] user=User.getBytes();
- byte[] password=Password.getBytes();
- writeInt(user.length);
- writeInt(password.length);
- os.write(user);
- os.write(password);
-
- readSecurityResult("Plain authentication");
- }
-
- //
- // Read security result.
- // Throws an exception on authentication failure.
- //
-
- void readSecurityResult(String authType) throws Exception {
- int securityResult = readU32();
-
- switch (securityResult) {
- case VncAuthOK:
- System.out.println(authType + ": success");
- break;
- case VncAuthFailed:
- if (clientMinor >= 8)
- readConnFailedReason();
- throw new Exception(authType + ": failed");
- case VncAuthTooMany:
- throw new Exception(authType + ": failed, too many tries");
- default:
- throw new Exception(authType + ": unknown result " + securityResult);
- }
- }
-
- //
- // Read the string describing the reason for a connection failure,
- // and throw an exception.
- //
-
- void readConnFailedReason() throws Exception {
- int reasonLen = readU32();
- byte[] reason = new byte[reasonLen];
- readFully(reason);
- throw new Exception(new String(reason));
- }
-
- //
- // Write a 32-bit integer into the output stream.
- //
-
- void writeInt(int value) throws IOException {
- byte[] b = new byte[4];
- b[0] = (byte) ((value >> 24) & 0xff);
- b[1] = (byte) ((value >> 16) & 0xff);
- b[2] = (byte) ((value >> 8) & 0xff);
- b[3] = (byte) (value & 0xff);
- os.write(b);
- }
-
- //
- // Write the client initialisation message
- //
-
- void writeClientInit() throws IOException {
- if (viewer.options.shareDesktop) {
- os.write(1);
- } else {
- os.write(0);
- }
- viewer.options.disableShareDesktop();
- }
-
-
- //
- // Read the server initialisation message
- //
-
- String desktopName;
- int framebufferWidth, framebufferHeight;
- int bitsPerPixel, depth;
- boolean bigEndian, trueColour;
- int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
-
- void readServerInit() throws IOException {
- framebufferWidth = readU16();
- framebufferHeight = readU16();
- bitsPerPixel = readU8();
- depth = readU8();
- bigEndian = (readU8() != 0);
- trueColour = (readU8() != 0);
- redMax = readU16();
- greenMax = readU16();
- blueMax = readU16();
- redShift = readU8();
- greenShift = readU8();
- blueShift = readU8();
- byte[] pad = new byte[3];
- readFully(pad);
- int nameLength = readU32();
- byte[] name = new byte[nameLength];
- readFully(name);
- desktopName = new String(name);
- inNormalProtocol = true;
- }
-
-
- //
- // Create session file and write initial protocol messages into it.
- //
-
- void startSession(String fname) throws IOException {
- rec = new SessionRecorder(fname);
- rec.writeHeader();
- rec.write(versionMsg_3_3.getBytes());
- rec.writeIntBE(SecTypeNone);
- rec.writeShortBE(framebufferWidth);
- rec.writeShortBE(framebufferHeight);
- byte[] fbsServerInitMsg = {
- 32, 24, 0, 1, 0,
- (byte)0xFF, 0, (byte)0xFF, 0, (byte)0xFF,
- 16, 8, 0, 0, 0, 0
- };
- rec.write(fbsServerInitMsg);
- rec.writeIntBE(desktopName.length());
- rec.write(desktopName.getBytes());
- numUpdatesInSession = 0;
-
- // FIXME: If there were e.g. ZRLE updates only, that should not
- // affect recording of Zlib and Tight updates. So, actually
- // we should maintain separate flags for Zlib, ZRLE and
- // Tight, instead of one ``wereZlibUpdates'' variable.
- //
-
- zlibWarningShown = false;
- tightWarningShown = false;
- }
-
- //
- // Close session file.
- //
-
- void closeSession() throws IOException {
- if (rec != null) {
- rec.close();
- rec = null;
- }
- }
-
-
- //
- // Set new framebuffer size
- //
-
- void setFramebufferSize(int width, int height) {
- framebufferWidth = width;
- framebufferHeight = height;
- }
-
-
- //
- // Read the server message type
- //
-
- int readServerMessageType() throws IOException {
- int msgType = readU8();
-
- // If the session is being recorded:
- if (rec != null) {
- if (msgType == Bell) { // Save Bell messages in session files.
- rec.writeByte(msgType);
- if (numUpdatesInSession > 0)
- rec.flush();
- }
- }
-
- return msgType;
- }
-
-
- //
- // Read a FramebufferUpdate message
- //
-
- int updateNRects;
-
- void readFramebufferUpdate() throws IOException {
- skipBytes(1);
- updateNRects = readU16();
-
- // If the session is being recorded:
- if (rec != null) {
- rec.writeByte(FramebufferUpdate);
- rec.writeByte(0);
- rec.writeShortBE(updateNRects);
- }
-
- numUpdatesInSession++;
- }
-
- //
- // Returns true if encoding is not pseudo
- //
- // FIXME: Find better way to differ pseudo and real encodings
- //
-
- boolean isRealDecoderEncoding(int encoding) {
- if ((encoding >= 1) && (encoding <= 16)) {
- return true;
- }
- return false;
- }
-
- // Read a FramebufferUpdate rectangle header
-
- int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
-
- void readFramebufferUpdateRectHdr() throws Exception {
- updateRectX = readU16();
- updateRectY = readU16();
- updateRectW = readU16();
- updateRectH = readU16();
- updateRectEncoding = readU32();
-
- if (updateRectEncoding == EncodingZlib ||
- updateRectEncoding == EncodingZRLE ||
- updateRectEncoding == EncodingTight)
- wereZlibUpdates = true;
-
- // If the session is being recorded:
- if (rec != null) {
- if (numUpdatesInSession > 1)
- rec.flush(); // Flush the output on each rectangle.
- rec.writeShortBE(updateRectX);
- rec.writeShortBE(updateRectY);
- rec.writeShortBE(updateRectW);
- rec.writeShortBE(updateRectH);
-
- //
- // If this is pseudo encoding or CopyRect that write encoding ID
- // in this place. All real encoding ID will be written to record stream
- // in decoder classes.
-
- if (((!isRealDecoderEncoding(updateRectEncoding))) && (rec != null)) {
- rec.writeIntBE(updateRectEncoding);
- }
- }
-
- if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
- return;
-
- if (updateRectX + updateRectW > framebufferWidth ||
- updateRectY + updateRectH > framebufferHeight) {
- throw new Exception("Framebuffer update rectangle too large: " +
- updateRectW + "x" + updateRectH + " at (" +
- updateRectX + "," + updateRectY + ")");
- }
- }
-
- //
- // Read a ServerCutText message
- //
-
- String readServerCutText() throws IOException {
- skipBytes(3);
- int len = readU32();
- byte[] text = new byte[len];
- readFully(text);
- return new String(text);
- }
-
-
- //
- // Read an integer in compact representation (1..3 bytes).
- // Such format is used as a part of the Tight encoding.
- // Also, this method records data if session recording is active and
- // the viewer's recordFromBeginning variable is set to true.
- //
-
- int readCompactLen() throws IOException {
- int[] portion = new int[3];
- portion[0] = readU8();
- int byteCount = 1;
- int len = portion[0] & 0x7F;
- if ((portion[0] & 0x80) != 0) {
- portion[1] = readU8();
- byteCount++;
- len |= (portion[1] & 0x7F) << 7;
- if ((portion[1] & 0x80) != 0) {
- portion[2] = readU8();
- byteCount++;
- len |= (portion[2] & 0xFF) << 14;
- }
- }
-
- return len;
- }
-
-
- //
- // Write a FramebufferUpdateRequest message
- //
-
- void writeFramebufferUpdateRequest(int x, int y, int w, int h,
- boolean incremental)
- throws IOException
- {
- byte[] b = new byte[10];
-
- b[0] = (byte) FramebufferUpdateRequest;
- b[1] = (byte) (incremental ? 1 : 0);
- b[2] = (byte) ((x >> 8) & 0xff);
- b[3] = (byte) (x & 0xff);
- b[4] = (byte) ((y >> 8) & 0xff);
- b[5] = (byte) (y & 0xff);
- b[6] = (byte) ((w >> 8) & 0xff);
- b[7] = (byte) (w & 0xff);
- b[8] = (byte) ((h >> 8) & 0xff);
- b[9] = (byte) (h & 0xff);
-
- os.write(b);
- }
-
-
- //
- // Write a SetPixelFormat message
- //
-
- void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian,
- boolean trueColour,
- int redMax, int greenMax, int blueMax,
- int redShift, int greenShift, int blueShift)
- throws IOException
- {
- byte[] b = new byte[20];
-
- b[0] = (byte) SetPixelFormat;
- b[4] = (byte) bitsPerPixel;
- b[5] = (byte) depth;
- b[6] = (byte) (bigEndian ? 1 : 0);
- b[7] = (byte) (trueColour ? 1 : 0);
- b[8] = (byte) ((redMax >> 8) & 0xff);
- b[9] = (byte) (redMax & 0xff);
- b[10] = (byte) ((greenMax >> 8) & 0xff);
- b[11] = (byte) (greenMax & 0xff);
- b[12] = (byte) ((blueMax >> 8) & 0xff);
- b[13] = (byte) (blueMax & 0xff);
- b[14] = (byte) redShift;
- b[15] = (byte) greenShift;
- b[16] = (byte) blueShift;
-
- os.write(b);
- }
-
-
- //
- // Write a FixColourMapEntries message. The values in the red, green and
- // blue arrays are from 0 to 65535.
- //
-
- void writeFixColourMapEntries(int firstColour, int nColours,
- int[] red, int[] green, int[] blue)
- throws IOException
- {
- byte[] b = new byte[6 + nColours * 6];
-
- b[0] = (byte) FixColourMapEntries;
- b[2] = (byte) ((firstColour >> 8) & 0xff);
- b[3] = (byte) (firstColour & 0xff);
- b[4] = (byte) ((nColours >> 8) & 0xff);
- b[5] = (byte) (nColours & 0xff);
-
- for (int i = 0; i < nColours; i++) {
- b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
- b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
- b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
- b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
- b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
- b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
- }
-
- os.write(b);
- }
-
-
- //
- // Write a SetEncodings message
- //
-
- void writeSetEncodings(int[] encs, int len) throws IOException {
- byte[] b = new byte[4 + 4 * len];
-
- b[0] = (byte) SetEncodings;
- b[2] = (byte) ((len >> 8) & 0xff);
- b[3] = (byte) (len & 0xff);
-
- for (int i = 0; i < len; i++) {
- b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
- b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
- b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
- b[7 + 4 * i] = (byte) (encs[i] & 0xff);
- }
-
- os.write(b);
- }
-
-
- //
- // Write a ClientCutText message
- //
-
- void writeClientCutText(String text) throws IOException {
- byte[] b = new byte[8 + text.length()];
-
- b[0] = (byte) ClientCutText;
- b[4] = (byte) ((text.length() >> 24) & 0xff);
- b[5] = (byte) ((text.length() >> 16) & 0xff);
- b[6] = (byte) ((text.length() >> 8) & 0xff);
- b[7] = (byte) (text.length() & 0xff);
-
- System.arraycopy(text.getBytes(), 0, b, 8, text.length());
-
- os.write(b);
- }
-
-
- //
- // A buffer for putting pointer and keyboard events before being sent. This
- // is to ensure that multiple RFB events generated from a single Java Event
- // will all be sent in a single network packet. The maximum possible
- // length is 4 modifier down events, a single key event followed by 4
- // modifier up events i.e. 9 key events or 72 bytes.
- //
-
- byte[] eventBuf = new byte[72];
- int eventBufLen;
-
-
- // Useful shortcuts for modifier masks.
-
- final static int CTRL_MASK = InputEvent.CTRL_MASK;
- final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
- final static int META_MASK = InputEvent.META_MASK;
- final static int ALT_MASK = InputEvent.ALT_MASK;
-
-
- //
- // Write a pointer event message. We may need to send modifier key events
- // around it to set the correct modifier state.
- //
-
- int pointerMask = 0;
-
- void writePointerEvent(MouseEvent evt) throws IOException {
- int modifiers = evt.getModifiers();
-
- int mask2 = 2;
- int mask3 = 4;
- if (viewer.options.reverseMouseButtons2And3) {
- mask2 = 4;
- mask3 = 2;
- }
-
- // Note: For some reason, AWT does not set BUTTON1_MASK on left
- // button presses. Here we think that it was the left button if
- // modifiers do not include BUTTON2_MASK or BUTTON3_MASK.
-
- if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
- if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- pointerMask = mask2;
- modifiers &= ~ALT_MASK;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- pointerMask = mask3;
- modifiers &= ~META_MASK;
- } else {
- pointerMask = 1;
- }
- } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
- pointerMask = 0;
- if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
- modifiers &= ~ALT_MASK;
- } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
- modifiers &= ~META_MASK;
- }
- }
-
- eventBufLen = 0;
- writeModifierKeyEvents(modifiers);
-
- int x = evt.getX();
- int y = evt.getY();
-
- if (x < 0) x = 0;
- if (y < 0) y = 0;
-
- eventBuf[eventBufLen++] = (byte) PointerEvent;
- eventBuf[eventBufLen++] = (byte) pointerMask;
- eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (x & 0xff);
- eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (y & 0xff);
-
- //
- // Always release all modifiers after an "up" event
- //
-
- if (pointerMask == 0) {
- writeModifierKeyEvents(0);
- }
-
- os.write(eventBuf, 0, eventBufLen);
- }
-
-
- //
- // Write a key event message. We may need to send modifier key events
- // around it to set the correct modifier state. Also we need to translate
- // from the Java key values to the X keysym values used by the RFB protocol.
- //
-
- void writeKeyEvent(KeyEvent evt) throws IOException {
-
- int keyChar = evt.getKeyChar();
-
- //
- // Ignore event if only modifiers were pressed.
- //
-
- // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar().
- if (keyChar == 0)
- keyChar = KeyEvent.CHAR_UNDEFINED;
-
- if (keyChar == KeyEvent.CHAR_UNDEFINED) {
- int code = evt.getKeyCode();
- if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT ||
- code == KeyEvent.VK_META || code == KeyEvent.VK_ALT)
- return;
- }
-
- //
- // Key press or key release?
- //
-
- boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
-
- int key;
- if (evt.isActionKey()) {
-
- //
- // An action key should be one of the following.
- // If not then just ignore the event.
- //
-
- switch(evt.getKeyCode()) {
- case KeyEvent.VK_HOME: key = 0xff50; break;
- case KeyEvent.VK_LEFT: key = 0xff51; break;
- case KeyEvent.VK_UP: key = 0xff52; break;
- case KeyEvent.VK_RIGHT: key = 0xff53; break;
- case KeyEvent.VK_DOWN: key = 0xff54; break;
- case KeyEvent.VK_PAGE_UP: key = 0xff55; break;
- case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break;
- case KeyEvent.VK_END: key = 0xff57; break;
- case KeyEvent.VK_INSERT: key = 0xff63; break;
- case KeyEvent.VK_F1: key = 0xffbe; break;
- case KeyEvent.VK_F2: key = 0xffbf; break;
- case KeyEvent.VK_F3: key = 0xffc0; break;
- case KeyEvent.VK_F4: key = 0xffc1; break;
- case KeyEvent.VK_F5: key = 0xffc2; break;
- case KeyEvent.VK_F6: key = 0xffc3; break;
- case KeyEvent.VK_F7: key = 0xffc4; break;
- case KeyEvent.VK_F8: key = 0xffc5; break;
- case KeyEvent.VK_F9: key = 0xffc6; break;
- case KeyEvent.VK_F10: key = 0xffc7; break;
- case KeyEvent.VK_F11: key = 0xffc8; break;
- case KeyEvent.VK_F12: key = 0xffc9; break;
- default:
- return;
- }
-
- } else {
-
- //
- // A "normal" key press. Ordinary ASCII characters go straight through.
- // For CTRL-<letter>, CTRL is sent separately so just send <letter>.
- // Backspace, tab, return, escape and delete have special keysyms.
- // Anything else we ignore.
- //
-
- key = keyChar;
-
- if (key < 0x20) {
- if (evt.isControlDown()) {
- key += 0x60;
- } else {
- switch(key) {
- case KeyEvent.VK_BACK_SPACE: key = 0xff08; break;
- case KeyEvent.VK_TAB: key = 0xff09; break;
- case KeyEvent.VK_ENTER: key = 0xff0d; break;
- case KeyEvent.VK_ESCAPE: key = 0xff1b; break;
- }
- }
- } else if (key == 0x7f) {
- // Delete
- key = 0xffff;
- } else if (key > 0xff) {
- // JDK1.1 on X incorrectly passes some keysyms straight through,
- // so we do too. JDK1.1.4 seems to have fixed this.
- // The keysyms passed are 0xff00 .. XK_BackSpace .. XK_Delete
- // Also, we pass through foreign currency keysyms (0x20a0..0x20af).
- if ((key < 0xff00 || key > 0xffff) &&
- !(key >= 0x20a0 && key <= 0x20af))
- return;
- }
- }
-
- // Fake keyPresses for keys that only generates keyRelease events
- if ((key == 0xe5) || (key == 0xc5) || // XK_aring / XK_Aring
- (key == 0xe4) || (key == 0xc4) || // XK_adiaeresis / XK_Adiaeresis
- (key == 0xf6) || (key == 0xd6) || // XK_odiaeresis / XK_Odiaeresis
- (key == 0xa7) || (key == 0xbd) || // XK_section / XK_onehalf
- (key == 0xa3)) { // XK_sterling
- // Make sure we do not send keypress events twice on platforms
- // with correct JVMs (those that actually report KeyPress for all
- // keys)
- if (down)
- brokenKeyPressed = true;
-
- if (!down && !brokenKeyPressed) {
- // We've got a release event for this key, but haven't received
- // a press. Fake it.
- eventBufLen = 0;
- writeModifierKeyEvents(evt.getModifiers());
- writeKeyEvent(key, true);
- os.write(eventBuf, 0, eventBufLen);
- }
-
- if (!down)
- brokenKeyPressed = false;
- }
-
- eventBufLen = 0;
- writeModifierKeyEvents(evt.getModifiers());
- writeKeyEvent(key, down);
-
- // Always release all modifiers after an "up" event
- if (!down)
- writeModifierKeyEvents(0);
-
- os.write(eventBuf, 0, eventBufLen);
- }
-
-
- //
- // Add a raw key event with the given X keysym to eventBuf.
- //
-
- void writeKeyEvent(int keysym, boolean down) {
- eventBuf[eventBufLen++] = (byte) KeyboardEvent;
- eventBuf[eventBufLen++] = (byte) (down ? 1 : 0);
- eventBuf[eventBufLen++] = (byte) 0;
- eventBuf[eventBufLen++] = (byte) 0;
- eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff);
- eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff);
- eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff);
- eventBuf[eventBufLen++] = (byte) (keysym & 0xff);
- }
-
-
- //
- // Write key events to set the correct modifier state.
- //
-
- int oldModifiers = 0;
-
- void writeModifierKeyEvents(int newModifiers) {
- if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
- writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
-
- if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK))
- writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0);
-
- if ((newModifiers & META_MASK) != (oldModifiers & META_MASK))
- writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0);
-
- if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK))
- writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0);
-
- oldModifiers = newModifiers;
- }
-
-
- public void startTiming() {
- timing = true;
-
- // Carry over up to 1s worth of previous rate for smoothing.
-
- if (timeWaitedIn100us > 10000) {
- timedKbits = timedKbits * 10000 / timeWaitedIn100us;
- timeWaitedIn100us = 10000;
- }
- }
-
- public void stopTiming() {
- timing = false;
- if (timeWaitedIn100us < timedKbits/2)
- timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
- }
-
- public long kbitsPerSecond() {
- return timedKbits * 10000 / timeWaitedIn100us;
- }
-
- public long timeWaited() {
- return timeWaitedIn100us;
- }
-
- //
- // Methods for reading data via our DataInputStream member variable (is).
- //
- // In addition to reading data, the readFully() methods updates variables
- // used to estimate data throughput.
- //
-
- public void readFully(byte b[]) throws IOException {
- readFully(b, 0, b.length);
- }
-
- public void readFully(byte b[], int off, int len) throws IOException {
- long before = 0;
- if (timing)
- before = System.currentTimeMillis();
-
- is.readFully(b, off, len);
-
- if (timing) {
- long after = System.currentTimeMillis();
- long newTimeWaited = (after - before) * 10;
- int newKbits = len * 8 / 1000;
-
- // limit rate to between 10kbit/s and 40Mbit/s
-
- if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
- if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
-
- timeWaitedIn100us += newTimeWaited;
- timedKbits += newKbits;
- }
-
- numBytesRead += len;
- }
-
- final int available() throws IOException {
- return is.available();
- }
-
- // FIXME: DataInputStream::skipBytes() is not guaranteed to skip
- // exactly n bytes. Probably we don't want to use this method.
- final int skipBytes(int n) throws IOException {
- int r = is.skipBytes(n);
- numBytesRead += r;
- return r;
- }
-
- final int readU8() throws IOException {
- int r = is.readUnsignedByte();
- numBytesRead++;
- return r;
- }
-
- final int readU16() throws IOException {
- int r = is.readUnsignedShort();
- numBytesRead += 2;
- return r;
- }
-
- final int readU32() throws IOException {
- int r = is.readInt();
- numBytesRead += 4;
- return r;
- }
-
- public void setStreams(InputStream is_, OutputStream os_) {
- is = new DataInputStream(is_);
- os = os_;
- }
-}
diff --git a/java/src/com/tigervnc/vncviewer/ServerDialog.java b/java/src/com/tigervnc/vncviewer/ServerDialog.java
new file mode 100644
index 00000000..86160f80
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/ServerDialog.java
@@ -0,0 +1,178 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.net.URL;
+import java.io.File;
+import java.util.*;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+class ServerDialog extends Dialog implements
+ ActionListener,
+ ItemListener
+{
+
+ public ServerDialog(OptionsDialog options_,
+ String defaultServerName, CConn cc_) {
+
+ super(true);
+ cc = cc_;
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ setSize(new Dimension(340, 135));
+ setTitle("VNC Viewer : Connection Details");
+
+ options = options_;
+ getContentPane().setLayout(new GridBagLayout());
+
+ JLabel serverLabel = new JLabel("Server:", JLabel.RIGHT);
+ if (options.defaults.getString("server") != null) {
+ server = new JComboBox(options.defaults.getString("server").split(","));
+ } else {
+ server = new JComboBox();
+ }
+
+ // Hack to set the left inset on editable JComboBox
+ if (UIManager.getLookAndFeel().getID() == "Windows") {
+ server.setBorder(BorderFactory.createCompoundBorder(server.getBorder(),
+ BorderFactory.createEmptyBorder(0,2,0,0)));
+ } else {
+ ComboBoxEditor editor = server.getEditor();
+ JTextField jtf = (JTextField)editor.getEditorComponent();
+ jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));
+ }
+
+ server.setEditable(true);
+ editor = server.getEditor();
+ JLabel encryptionLabel = new JLabel("Encryption:");
+ encryption = new JComboBox();
+ serverLabel.setPreferredSize(encryptionLabel.getPreferredSize());
+
+ JPanel topPanel = new JPanel(new GridBagLayout());
+
+ addGBComponent(new JLabel(cc.logo),topPanel, 0, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(5,5,5,15));
+ addGBComponent(serverLabel,topPanel, 1, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(10,0,5,5));
+ addGBComponent(server,topPanel, 2, 0, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(10,0,5,40));
+
+ optionsButton = new JButton("Options...");
+ aboutButton = new JButton("About...");
+ okButton = new JButton("OK");
+ cancelButton = new JButton("Cancel");
+ JPanel buttonPanel = new JPanel(new GridBagLayout());
+ buttonPanel.setPreferredSize(new Dimension(340, 40));
+ addGBComponent(aboutButton,buttonPanel, 0, 3, 1, 1, 0, 0, 0.2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+ addGBComponent(optionsButton,buttonPanel, 1, 3, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+ addGBComponent(okButton,buttonPanel, 2, 3, 1, 1, 0, 0, 0.8, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+ addGBComponent(cancelButton,buttonPanel, 3, 3, 1, 1, 0, 0, 0.5, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.LINE_START;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.gridheight = 1;
+ gbc.insets = new Insets(0,0,0,0);
+ gbc.ipadx = 0;
+ gbc.ipady = 0;
+ gbc.weightx = 1;
+ gbc.weighty = 1;
+ getContentPane().add(topPanel,gbc);
+ getContentPane().add(buttonPanel);
+
+ server.addActionListener(this);
+ optionsButton.addActionListener(this);
+ aboutButton.addActionListener(this);
+ okButton.addActionListener(this);
+ cancelButton.addActionListener(this);
+
+ pack();
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JComboBox && (JComboBox)s == encryption) {
+ options.encryption=(encryption.getSelectedIndex()==1) ? false : true;
+ }
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JButton && (JButton)s == okButton) {
+ ok = true;
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == cancelButton) {
+ ok = false;
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == optionsButton) {
+ options.showDialog();
+ } else if (s instanceof JButton && (JButton)s == aboutButton) {
+ cc.showAbout();
+ } else if (s instanceof JComboBox && (JComboBox)s == server) {
+ if (e.getActionCommand().equals("comboBoxEdited")) {
+ server.insertItemAt(editor.getItem(), 0);
+ server.setSelectedIndex(0);
+ ok = true;
+ endDialog();
+ }
+ }
+ }
+
+ public void endDialog() {
+ if (ok) {
+ options.defaults.setPref("encryption",(encryption.getSelectedIndex()==1) ? "off" : "on");
+ if (!server.getSelectedItem().toString().equals("")) {
+ String t = (options.defaults.getString("server")==null) ? "" : options.defaults.getString("server");
+ StringTokenizer st = new StringTokenizer(t, ",");
+ StringBuffer sb = new StringBuffer().append((String)server.getSelectedItem());
+ while (st.hasMoreTokens()) {
+ String s = st.nextToken();
+ if (!s.equals((String)server.getSelectedItem()) && !s.equals("")) {
+ sb.append(',');
+ sb.append(s);
+ }
+ }
+ options.defaults.setPref("server", sb.toString());
+ }
+ try {
+ options.defaults.Save();
+ } catch (java.lang.Exception x) { }
+ }
+ done = true;
+ if (modal) {
+ synchronized (this) {
+ notify();
+ }
+ }
+ this.dispose();
+ }
+
+ CConn cc;
+ JComboBox encryption, server;
+ ComboBoxEditor editor;
+ JButton aboutButton, optionsButton, okButton, cancelButton;
+ OptionsDialog options;
+ static LogWriter vlog = new LogWriter("ServerDialog");
+
+}
diff --git a/java/src/com/tigervnc/vncviewer/SessionRecorder.java b/java/src/com/tigervnc/vncviewer/SessionRecorder.java
deleted file mode 100644
index 2ae70798..00000000
--- a/java/src/com/tigervnc/vncviewer/SessionRecorder.java
+++ /dev/null
@@ -1,195 +0,0 @@
-//
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// SessionRecorder is a class to write FBS (FrameBuffer Stream) files.
-// FBS files are used to save RFB sessions for later playback.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.io.*;
-
-class SessionRecorder {
-
- protected FileOutputStream f;
- protected DataOutputStream df;
- protected long startTime, lastTimeOffset;
-
- protected byte[] buffer;
- protected int bufferSize;
- protected int bufferBytes;
-
- public SessionRecorder(String name, int bufsize) throws IOException {
- f = new FileOutputStream(name);
- df = new DataOutputStream(f);
- startTime = System.currentTimeMillis();
- lastTimeOffset = 0;
-
- bufferSize = bufsize;
- bufferBytes = 0;
- buffer = new byte[bufferSize];
- }
-
- public SessionRecorder(String name) throws IOException {
- this(name, 65536);
- }
-
- //
- // Close the file, free resources.
- //
-
- public void close() throws IOException {
- try {
- flush();
- } catch (IOException e) {
- }
-
- df = null;
- f.close();
- f = null;
- buffer = null;
- }
-
- //
- // Write the FBS file header as defined in the rfbproxy utility.
- //
-
- public void writeHeader() throws IOException {
- df.write("FBS 001.000\n".getBytes());
- }
-
- //
- // Write one byte.
- //
-
- public void writeByte(int b) throws IOException {
- prepareWriting();
- buffer[bufferBytes++] = (byte)b;
- }
-
- //
- // Write 16-bit value, big-endian.
- //
-
- public void writeShortBE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes++] = (byte)(v >> 8);
- buffer[bufferBytes++] = (byte)v;
- }
-
- //
- // Write 32-bit value, big-endian.
- //
-
- public void writeIntBE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes] = (byte)(v >> 24);
- buffer[bufferBytes + 1] = (byte)(v >> 16);
- buffer[bufferBytes + 2] = (byte)(v >> 8);
- buffer[bufferBytes + 3] = (byte)v;
- bufferBytes += 4;
- }
-
- //
- // Write 16-bit value, little-endian.
- //
-
- public void writeShortLE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes++] = (byte)v;
- buffer[bufferBytes++] = (byte)(v >> 8);
- }
-
- //
- // Write 32-bit value, little-endian.
- //
-
- public void writeIntLE(int v) throws IOException {
- prepareWriting();
- buffer[bufferBytes] = (byte)v;
- buffer[bufferBytes + 1] = (byte)(v >> 8);
- buffer[bufferBytes + 2] = (byte)(v >> 16);
- buffer[bufferBytes + 3] = (byte)(v >> 24);
- bufferBytes += 4;
- }
-
- //
- // Write byte arrays.
- //
-
- public void write(byte b[], int off, int len) throws IOException {
- prepareWriting();
- while (len > 0) {
- if (bufferBytes > bufferSize - 4)
- flush(false);
-
- int partLen;
- if (bufferBytes + len > bufferSize) {
- partLen = bufferSize - bufferBytes;
- } else {
- partLen = len;
- }
- System.arraycopy(b, off, buffer, bufferBytes, partLen);
- bufferBytes += partLen;
- off += partLen;
- len -= partLen;
- }
- }
-
- public void write(byte b[]) throws IOException {
- write(b, 0, b.length);
- }
-
- //
- // Flush the output. This method saves buffered data in the
- // underlying file object adding data sizes and timestamps. If the
- // updateTimeOffset is set to false, then the current time offset
- // will not be changed for next write operation.
- //
-
- public void flush(boolean updateTimeOffset) throws IOException {
- if (bufferBytes > 0) {
- df.writeInt(bufferBytes);
- df.write(buffer, 0, (bufferBytes + 3) & 0x7FFFFFFC);
- df.writeInt((int)lastTimeOffset);
- bufferBytes = 0;
- if (updateTimeOffset)
- lastTimeOffset = -1;
- }
- }
-
- public void flush() throws IOException {
- flush(true);
- }
-
- //
- // Before writing any data, remember time offset and flush the
- // buffer before it becomes full.
- //
-
- protected void prepareWriting() throws IOException {
- if (lastTimeOffset == -1)
- lastTimeOffset = System.currentTimeMillis() - startTime;
- if (bufferBytes > bufferSize - 4)
- flush(false);
- }
-
-}
-
diff --git a/java/src/com/tigervnc/vncviewer/SocketFactory.java b/java/src/com/tigervnc/vncviewer/SocketFactory.java
deleted file mode 100644
index 30460dce..00000000
--- a/java/src/com/tigervnc/vncviewer/SocketFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-//
-// SocketFactory.java describes an interface used to substitute the
-// standard Socket class by its alternative implementations.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.applet.*;
-import java.net.*;
-import java.io.*;
-
-public interface SocketFactory {
-
- public Socket createSocket(String host, int port, Applet applet)
- throws IOException;
-
- public Socket createSocket(String host, int port, String[] args)
- throws IOException;
-}
diff --git a/java/src/com/tigervnc/vncviewer/TLSTunnelBase.java b/java/src/com/tigervnc/vncviewer/TLSTunnelBase.java
deleted file mode 100644
index 922e8374..00000000
--- a/java/src/com/tigervnc/vncviewer/TLSTunnelBase.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2003 Sun Microsystems, Inc.
- * Copyright (C) 2003-2010 Martin Koegler
- *
- * This 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 software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-package com.tigervnc.vncviewer;
-
-import java.util.ArrayList;
-import java.net.*;
-import javax.net.ssl.*;
-
-public abstract class TLSTunnelBase
-{
-
- public TLSTunnelBase (Socket sock_)
- {
- sock = sock_;
- }
-
- protected void initContext (SSLContext sc) throws java.security.
- GeneralSecurityException
- {
- sc.init (null, null, null);
- }
-
- public void setup (RfbProto cc) throws Exception
- {
- if (cc.readU8 () == 0)
- throw new Exception("Setup on the server failed");
- try
- {
- SSLSocketFactory sslfactory;
- SSLSocket sslsock;
- SSLContext sc = SSLContext.getInstance ("TLS");
- System.out.println("Generating TLS context");
- initContext (sc);
- System.out.println("Doing TLS handshake");
- sslfactory = sc.getSocketFactory ();
- sslsock = (SSLSocket) sslfactory.createSocket (sock,
- sock.getInetAddress ().
- getHostName (),
- sock.getPort (), true);
-
- setParam (sslsock);
-
- /* Not neccessary - just ensures that we know what cipher
- * suite we are using for the output of toString()
- */
- sslsock.startHandshake ();
-
- System.out.println("TLS done");
-
- cc.setStreams (sslsock.getInputStream (),
- sslsock.getOutputStream ());
- }
- catch (java.io.IOException e)
- {
- throw new Exception("TLS handshake failed " + e.toString ());
- }
- catch (java.security.GeneralSecurityException e)
- {
- throw new Exception("TLS handshake failed " + e.toString ());
- }
- }
-
-
- protected abstract void setParam (SSLSocket sock);
-
- Socket sock;
-
-}
diff --git a/java/src/com/tigervnc/vncviewer/UserPrefs.java b/java/src/com/tigervnc/vncviewer/UserPrefs.java
new file mode 100644
index 00000000..51b8b904
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/UserPrefs.java
@@ -0,0 +1,258 @@
+/* Copyright (C) 2011 TigerVNC Team. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+package com.tigervnc.vncviewer;
+
+import java.util.Properties;
+import java.io.FileOutputStream;
+import javax.swing.filechooser.*;
+
+/**
+ * Simple, generic class to load up or save properties for an application.
+ * (eg user preferences)
+ *
+ * While reading in values, it will automatically convert from string format,
+ * to your choice of int or boolean, if desired.
+ *
+ * We assume that you want properties stored in a file named
+ * $HOME/.yourappname, where $HOME represents the users "home directory"
+ *
+ * Feel free to email comments or suggestions to the author
+ *
+ * @version 1.0, 09/16/1997
+ * @author Philip Brown phil@bolthole.com
+ */
+
+public class UserPrefs extends Properties {
+ String userhome=null; //This will have fileseperator on end if it
+ String prefFile;
+ String appName;
+
+ Properties systemprops;
+
+
+ /**
+ * We try to read in a preferences file, from the user's "HOME"
+ * directory. We base the name of the file, on the name of the
+ * application we are in.
+ * Use the getHomeDir() call if you want to know what directory
+ * this is in.
+ *
+ * @param appName_ name of application calling this class
+ */
+ public UserPrefs(String appName_) {
+ appName = appName_;
+
+ systemprops=System.getProperties();
+ // This is guaranteed as always being some valid directory,
+ // according to spec.
+ prefFile= getHomeDir()+getFileSeperator()+
+ "."+appName;
+ try {
+ load(new java.io.FileInputStream(prefFile));
+ } catch (Exception err) {
+ if(err instanceof java.io.FileNotFoundException) {
+ try {
+ store(new FileOutputStream(prefFile), appName+" preferences");
+ } catch (Exception e) { /* FIXME */ }
+ } else {
+ // FIXME - should be a dialog
+ System.out.println("Error opening prefs file:"+err.getMessage());
+ }
+ }
+
+ }
+
+ // Strip off any comments
+ String trimValue(String prop) {
+ if(prop==null)
+ return null;
+
+ int lastpos;
+ lastpos=prop.indexOf('#');
+ if(lastpos==-1)
+ lastpos=prop.length()-1;
+ while((prop.charAt(lastpos)==' ') ||
+ (prop.charAt(lastpos)=='\t')) {
+ lastpos--;
+ if(lastpos==0)
+ break;
+ }
+
+ return prop.substring(0, lastpos+1);
+ }
+
+ /**
+ * The java spec guarantees that a "home" directory be
+ * specified. We look it up for our own uses at initialization
+ * If you want to do other things in the user's home dir,
+ * this routine is an easy way to find out where it is.
+ *
+ * This returns string that will have trailing fileseparator, eg "/")
+ * so you can slap together a filename directly after it, and
+ * not worry about that sort of junk.
+ */
+ final public static String getHomeDir() {
+ String homeDir = null;
+ String os = System.getProperty("os.name");
+ try {
+ if (os.startsWith("Windows")) {
+ // JRE prior to 1.5 cannot reliably determine USERPROFILE
+ // return user.home and hope it's right...
+ if (Integer.parseInt(System.getProperty("java.version").split("\\.")[1]) < 5) {
+ homeDir = System.getProperty("user.home");
+ } else {
+ homeDir = System.getenv("USERPROFILE");
+ }
+ } else {
+ homeDir = FileSystemView.getFileSystemView().
+ getDefaultDirectory().getCanonicalPath();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return homeDir;
+ }
+
+ final private String getUserName() {
+ String userName = (String) System.getProperties().get("user.name");
+ return userName;
+ }
+
+ final public static String getFileSeperator() {
+ String seperator = System.getProperties().get("file.separator").toString();
+ return seperator;
+ }
+
+ /**
+ * way to directly set a preference. You'll have to
+ * do your own type conversion.
+ * @param prefname name of property
+ * @param value string value of property
+ */
+ public void setPref(String prefname, String value) {
+ setProperty(prefname, value);
+ }
+
+ public void setPref(String prefname, int value) {
+ systemprops.put(prefname, java.lang.Integer.toString(value));
+ }
+
+ public void setPref(String prefname, boolean value) {
+ put(prefname, (value ? "true" : "false"));
+ }
+
+ /**
+ * Gets named resource, as a string value.
+ * returns null if no such resource defined.
+ * @param name name of property
+ */
+ public String getString(String name) {
+ return trimValue(getProperty(name));
+ }
+ /**
+ * Gets named resource, as a string value.
+ *
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public String getString(String name, String defstr) {
+ String val = trimValue(getProperty(name));
+ if(val==null) {
+ setPref(name, defstr);
+ return defstr;
+ }
+ return val;
+ }
+
+ /**
+ * look up property that is an int value
+ * @param name name of property
+ */
+ public int getInt(String name) {
+ String strint = trimValue(getProperty(name));
+ int val=0;
+ try {
+ val = Integer.parseInt(strint);
+ } catch (NumberFormatException err) {
+ //we dont care
+ }
+ return val;
+ }
+
+ /**
+ * look up property that is an int value
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public int getInt(String name, int defval) {
+ String strint = trimValue(getProperty(name));
+ if(strint==null) {
+ setPref(name, String.valueOf(defval));
+ return defval;
+ }
+ int val=0;
+ try {
+ val = Integer.parseInt(strint);
+ } catch (NumberFormatException err) {
+ //we dont care
+ }
+ return val;
+ }
+
+ /**
+ * look up property that is a boolean value
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public boolean getBool(String name) {
+ String strval = trimValue(getProperty(name));
+ if(strval.equals("true"))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public boolean getBool(String name, boolean defval) {
+ String strval = trimValue(getProperty(name));
+ if(strval==null) {
+ setPref(name, String.valueOf(defval));
+ return defval;
+ }
+
+ if(strval.equals("true"))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * save user preferences to default file. Duh.
+ */
+ public void Save() throws java.io.IOException {
+ store(new FileOutputStream(prefFile), appName+" preferences");
+ }
+}
diff --git a/java/src/com/tigervnc/vncviewer/VncCanvas.java b/java/src/com/tigervnc/vncviewer/VncCanvas.java
deleted file mode 100644
index b7764819..00000000
--- a/java/src/com/tigervnc/vncviewer/VncCanvas.java
+++ /dev/null
@@ -1,1092 +0,0 @@
-//
-// Copyright (C) 2004 Horizon Wimba. All Rights Reserved.
-// Copyright (C) 2001-2003 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tigervnc.vncviewer;
-
-import com.tigervnc.decoder.CoRREDecoder;
-import com.tigervnc.decoder.CopyRectDecoder;
-import com.tigervnc.decoder.HextileDecoder;
-import com.tigervnc.decoder.RREDecoder;
-import com.tigervnc.decoder.RawDecoder;
-import com.tigervnc.decoder.TightDecoder;
-import com.tigervnc.decoder.ZRLEDecoder;
-import com.tigervnc.decoder.ZlibDecoder;
-import com.tigervnc.decoder.common.Repaintable;
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.image.*;
-import java.io.*;
-import java.lang.*;
-import java.util.zip.*;
-
-
-//
-// VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
-//
-
-class VncCanvas extends Canvas
- implements KeyListener, MouseListener, MouseMotionListener, Repaintable, Runnable {
-
- VncViewer viewer;
- RfbProto rfb;
- ColorModel cm8, cm24;
- int bytesPixel;
-
- int maxWidth = 0, maxHeight = 0;
- int scalingFactor;
- int scaledWidth, scaledHeight;
-
- Image memImage;
- Graphics memGraphics;
-
- //
- // Decoders
- //
-
- RawDecoder rawDecoder;
- RREDecoder rreDecoder;
- CoRREDecoder correDecoder;
- ZlibDecoder zlibDecoder;
- HextileDecoder hextileDecoder;
- ZRLEDecoder zrleDecoder;
- TightDecoder tightDecoder;
- CopyRectDecoder copyRectDecoder;
-
- // Base decoder decoders array
- RawDecoder []decoders = null;
-
- // Update statistics.
- long statStartTime; // time on first framebufferUpdateRequest
- long statNumUpdates; // counter for FramebufferUpdate messages
- long statNumTotalRects; // rectangles in FramebufferUpdate messages
- long statNumPixelRects; // the same, but excluding pseudo-rectangles
- long statNumRectsTight; // Tight-encoded rectangles (including JPEG)
- long statNumRectsTightJPEG; // JPEG-compressed Tight-encoded rectangles
- long statNumRectsZRLE; // ZRLE-encoded rectangles
- long statNumRectsHextile; // Hextile-encoded rectangles
- long statNumRectsRaw; // Raw-encoded rectangles
- long statNumRectsCopy; // CopyRect rectangles
- long statNumBytesEncoded; // number of bytes in updates, as received
- long statNumBytesDecoded; // number of bytes, as if Raw encoding was used
-
- // True if we process keyboard and mouse events.
- boolean inputEnabled;
-
- // True if was no one auto resize of canvas
- boolean isFirstSizeAutoUpdate = true;
-
- // Members for limiting sending mouse events to server
- long lastMouseEventSendTime = System.currentTimeMillis();
- long mouseMaxFreq = 20;
-
- //
- // The constructors.
- //
-
- public VncCanvas(VncViewer v, int maxWidth_, int maxHeight_)
- throws IOException {
-
- viewer = v;
- maxWidth = maxWidth_;
- maxHeight = maxHeight_;
-
- rfb = viewer.rfb;
- scalingFactor = viewer.options.scalingFactor;
-
- cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
- cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
-
- //
- // Create decoders
- //
-
- // Input stream for decoders
- RfbInputStream rfbis = new RfbInputStream(rfb);
- // Create output stream for session recording
- RecordOutputStream ros = new RecordOutputStream(rfb);
-
- rawDecoder = new RawDecoder(memGraphics, rfbis);
- rreDecoder = new RREDecoder(memGraphics, rfbis);
- correDecoder = new CoRREDecoder(memGraphics, rfbis);
- hextileDecoder = new HextileDecoder(memGraphics, rfbis);
- tightDecoder = new TightDecoder(memGraphics, rfbis);
- zlibDecoder = new ZlibDecoder(memGraphics, rfbis);
- zrleDecoder = new ZRLEDecoder(memGraphics, rfbis);
- copyRectDecoder = new CopyRectDecoder(memGraphics, rfbis);
-
- //
- // Set data for decoders that needs extra parameters
- //
-
- hextileDecoder.setRepainableControl(this);
- tightDecoder.setRepainableControl(this);
-
- //
- // Create array that contains our decoders
- //
-
- decoders = new RawDecoder[8];
- decoders[0] = rawDecoder;
- decoders[1] = rreDecoder;
- decoders[2] = correDecoder;
- decoders[3] = hextileDecoder;
- decoders[4] = zlibDecoder;
- decoders[5] = tightDecoder;
- decoders[6] = zrleDecoder;
- decoders[7] = copyRectDecoder;
-
- //
- // Set session recorder for decoders
- //
-
- for (int i = 0; i < decoders.length; i++) {
- decoders[i].setDataOutputStream(ros);
- }
-
- setPixelFormat();
-
- inputEnabled = false;
- if (!viewer.options.viewOnly)
- enableInput(true);
-
- // Enable mouse and keyboard event listeners.
- addKeyListener(this);
- addMouseListener(this);
- addMouseMotionListener(this);
-
- // Create thread, that will send mouse movement events
- // to VNC server.
- Thread mouseThread = new Thread(this);
- mouseThread.start();
- }
-
- public VncCanvas(VncViewer v) throws IOException {
- this(v, 0, 0);
- }
-
- //
- // Callback methods to determine geometry of our Component.
- //
-
- public Dimension getPreferredSize() {
- return new Dimension(scaledWidth, scaledHeight);
- }
-
- public Dimension getMinimumSize() {
- return new Dimension(scaledWidth, scaledHeight);
- }
-
- public Dimension getMaximumSize() {
- return new Dimension(scaledWidth, scaledHeight);
- }
-
- //
- // All painting is performed here.
- //
-
- public void update(Graphics g) {
- paint(g);
- }
-
- public void paint(Graphics g) {
- synchronized(memImage) {
- if (rfb.framebufferWidth == scaledWidth) {
- g.drawImage(memImage, 0, 0, null);
- } else {
- paintScaledFrameBuffer(g);
- }
- }
- if (showSoftCursor) {
- int x0 = cursorX - hotX, y0 = cursorY - hotY;
- Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight);
- if (r.intersects(g.getClipBounds())) {
- g.drawImage(softCursor, x0, y0, null);
- }
- }
- }
-
- public void paintScaledFrameBuffer(Graphics g) {
- g.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null);
- }
-
- //
- // Start/stop receiving mouse events. Keyboard events are received
- // even in view-only mode, because we want to map the 'r' key to the
- // screen refreshing function.
- //
-
- public synchronized void enableInput(boolean enable) {
- if (enable && !inputEnabled) {
- inputEnabled = true;
- if (viewer.showControls) {
- viewer.buttonPanel.enableRemoteAccessControls(true);
- }
- createSoftCursor(); // scaled cursor
- } else if (!enable && inputEnabled) {
- inputEnabled = false;
- if (viewer.showControls) {
- viewer.buttonPanel.enableRemoteAccessControls(false);
- }
- createSoftCursor(); // non-scaled cursor
- }
- }
-
- public void setPixelFormat() throws IOException {
- if (viewer.options.eightBitColors) {
- rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6);
- bytesPixel = 1;
- } else {
- rfb.writeSetPixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0);
- bytesPixel = 4;
- }
- updateFramebufferSize();
- }
-
- void setScalingFactor(int sf) {
- scalingFactor = sf;
- updateFramebufferSize();
- invalidate();
- }
-
- void updateFramebufferSize() {
-
- // Useful shortcuts.
- int fbWidth = rfb.framebufferWidth;
- int fbHeight = rfb.framebufferHeight;
-
- // FIXME: This part of code must be in VncViewer i think
- if (viewer.options.autoScale) {
- if (viewer.inAnApplet) {
- maxWidth = viewer.getWidth();
- maxHeight = viewer.getHeight();
- } else {
- if (viewer.vncFrame != null) {
- if (isFirstSizeAutoUpdate) {
- isFirstSizeAutoUpdate = false;
- Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
- maxWidth = (int)screenSize.getWidth() - 100;
- maxHeight = (int)screenSize.getHeight() - 100;
- viewer.vncFrame.setSize(maxWidth, maxHeight);
- } else {
- viewer.desktopScrollPane.doLayout();
- maxWidth = viewer.desktopScrollPane.getWidth();
- maxHeight = viewer.desktopScrollPane.getHeight();
- }
- } else {
- maxWidth = fbWidth;
- maxHeight = fbHeight;
- }
- }
- int f1 = maxWidth * 100 / fbWidth;
- int f2 = maxHeight * 100 / fbHeight;
- scalingFactor = Math.min(f1, f2);
- if (scalingFactor > 100)
- scalingFactor = 100;
- System.out.println("Scaling desktop at " + scalingFactor + "%");
- }
-
- // Update scaled framebuffer geometry.
- scaledWidth = (fbWidth * scalingFactor + 50) / 100;
- scaledHeight = (fbHeight * scalingFactor + 50) / 100;
-
- // Create new off-screen image either if it does not exist, or if
- // its geometry should be changed. It's not necessary to replace
- // existing image if only pixel format should be changed.
- if (memImage == null) {
- memImage = viewer.vncContainer.createImage(fbWidth, fbHeight);
- memGraphics = memImage.getGraphics();
- } else if (memImage.getWidth(null) != fbWidth ||
- memImage.getHeight(null) != fbHeight) {
- synchronized(memImage) {
- memImage = viewer.vncContainer.createImage(fbWidth, fbHeight);
- memGraphics = memImage.getGraphics();
- }
- }
-
- //
- // Update decoders
- //
-
- //
- // FIXME: Why decoders can be null here?
- //
-
- if (decoders != null) {
- for (int i = 0; i < decoders.length; i++) {
- //
- // Set changes to every decoder that we can use
- //
-
- decoders[i].setBPP(bytesPixel);
- decoders[i].setFrameBufferSize(fbWidth, fbHeight);
- decoders[i].setGraphics(memGraphics);
-
- //
- // Update decoder
- //
-
- decoders[i].update();
- }
- }
-
- // FIXME: This part of code must be in VncViewer i think
- // Update the size of desktop containers.
- if (viewer.inSeparateFrame) {
- if (viewer.desktopScrollPane != null) {
- if (!viewer.options.autoScale) {
- resizeDesktopFrame();
- } else {
- setSize(scaledWidth, scaledHeight);
- viewer.desktopScrollPane.setSize(maxWidth + 200,
- maxHeight + 200);
- }
- }
- } else {
- setSize(scaledWidth, scaledHeight);
- }
- viewer.moveFocusToDesktop();
- }
-
- void resizeDesktopFrame() {
- setSize(scaledWidth, scaledHeight);
-
- // FIXME: Find a better way to determine correct size of a
- // ScrollPane. -- const
- Insets insets = viewer.desktopScrollPane.getInsets();
- viewer.desktopScrollPane.setSize(scaledWidth +
- 2 * Math.min(insets.left, insets.right),
- scaledHeight +
- 2 * Math.min(insets.top, insets.bottom));
-
- viewer.vncFrame.pack();
-
- // Try to limit the frame size to the screen size.
-
- Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize();
- Dimension frameSize = viewer.vncFrame.getSize();
- Dimension newSize = frameSize;
-
- // Reduce Screen Size by 30 pixels in each direction;
- // This is a (poor) attempt to account for
- // 1) Menu bar on Macintosh (should really also account for
- // Dock on OSX). Usually 22px on top of screen.
- // 2) Taxkbar on Windows (usually about 28 px on bottom)
- // 3) Other obstructions.
-
- screenSize.height -= 30;
- screenSize.width -= 30;
-
- boolean needToResizeFrame = false;
- if (frameSize.height > screenSize.height) {
- newSize.height = screenSize.height;
- needToResizeFrame = true;
- }
- if (frameSize.width > screenSize.width) {
- newSize.width = screenSize.width;
- needToResizeFrame = true;
- }
- if (needToResizeFrame) {
- viewer.vncFrame.setSize(newSize);
- }
-
- viewer.desktopScrollPane.doLayout();
- }
-
- //
- // processNormalProtocol() - executed by the rfbThread to deal with the
- // RFB socket.
- //
-
- public void processNormalProtocol() throws Exception {
-
- // Start/stop session recording if necessary.
- viewer.checkRecordingStatus();
-
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
-
- resetStats();
- boolean statsRestarted = false;
-
- //
- // main dispatch loop
- //
-
- while (true) {
-
- // Read message type from the server.
- int msgType = rfb.readServerMessageType();
-
- // Process the message depending on its type.
- switch (msgType) {
- case RfbProto.FramebufferUpdate:
-
- if (statNumUpdates == viewer.debugStatsExcludeUpdates &&
- !statsRestarted) {
- resetStats();
- statsRestarted = true;
- } else if (statNumUpdates == viewer.debugStatsMeasureUpdates &&
- statsRestarted) {
- viewer.disconnect();
- }
-
- rfb.readFramebufferUpdate();
- statNumUpdates++;
-
- boolean cursorPosReceived = false;
-
- for (int i = 0; i < rfb.updateNRects; i++) {
-
- rfb.readFramebufferUpdateRectHdr();
- statNumTotalRects++;
- int rx = rfb.updateRectX, ry = rfb.updateRectY;
- int rw = rfb.updateRectW, rh = rfb.updateRectH;
-
- if (rfb.updateRectEncoding == rfb.EncodingLastRect)
- break;
-
- if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) {
- rfb.setFramebufferSize(rw, rh);
- updateFramebufferSize();
- break;
- }
-
- if (rfb.updateRectEncoding == rfb.EncodingXCursor ||
- rfb.updateRectEncoding == rfb.EncodingRichCursor) {
- handleCursorShapeUpdate(rfb.updateRectEncoding, rx, ry, rw, rh);
- continue;
- }
-
- if (rfb.updateRectEncoding == rfb.EncodingPointerPos) {
- softCursorMove(rx, ry);
- cursorPosReceived = true;
- continue;
- }
-
- long numBytesReadBefore = rfb.getNumBytesRead();
-
- rfb.startTiming();
-
- switch (rfb.updateRectEncoding) {
- case RfbProto.EncodingRaw:
- statNumRectsRaw++;
- handleRawRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingCopyRect:
- statNumRectsCopy++;
- handleCopyRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingRRE:
- handleRRERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingCoRRE:
- handleCoRRERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingHextile:
- statNumRectsHextile++;
- handleHextileRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingZRLE:
- statNumRectsZRLE++;
- handleZRLERect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingZlib:
- handleZlibRect(rx, ry, rw, rh);
- break;
- case RfbProto.EncodingTight:
- if (tightDecoder != null) {
- statNumRectsTightJPEG = tightDecoder.getNumJPEGRects();
- //statNumRectsTight = tightDecoder.getNumTightRects();
- }
- statNumRectsTight++;
- handleTightRect(rx, ry, rw, rh);
- break;
- default:
- throw new Exception("Unknown RFB rectangle encoding " +
- rfb.updateRectEncoding);
- }
-
- rfb.stopTiming();
-
- statNumPixelRects++;
- statNumBytesDecoded += rw * rh * bytesPixel;
- statNumBytesEncoded +=
- (int)(rfb.getNumBytesRead() - numBytesReadBefore);
- }
-
- boolean fullUpdateNeeded = false;
-
- // Start/stop session recording if necessary. Request full
- // update if a new session file was opened.
- if (viewer.checkRecordingStatus())
- fullUpdateNeeded = true;
-
- // Defer framebuffer update request if necessary. But wake up
- // immediately on keyboard or mouse event. Also, don't sleep
- // if there is some data to receive, or if the last update
- // included a PointerPos message.
- if (viewer.deferUpdateRequests > 0 &&
- rfb.available() == 0 && !cursorPosReceived) {
- synchronized(rfb) {
- try {
- rfb.wait(viewer.deferUpdateRequests);
- } catch (InterruptedException e) {
- }
- }
- }
-
- viewer.autoSelectEncodings();
-
- // Before requesting framebuffer update, check if the pixel
- // format should be changed.
- if (viewer.options.eightBitColors != (bytesPixel == 1)) {
- // Pixel format should be changed.
- setPixelFormat();
- fullUpdateNeeded = true;
- }
-
- // Finally, request framebuffer update if needed.
- if (fullUpdateNeeded) {
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
- } else {
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, true);
- }
-
- break;
-
- case RfbProto.SetColourMapEntries:
- throw new Exception("Can't handle SetColourMapEntries message");
-
- case RfbProto.Bell:
- Toolkit.getDefaultToolkit().beep();
- break;
-
- case RfbProto.ServerCutText:
- String s = rfb.readServerCutText();
- viewer.clipboard.setCutText(s);
- break;
-
- default:
- throw new Exception("Unknown RFB message type " + msgType);
- }
- }
- }
-
- //
- // Handle a raw rectangle. The second form with paint==false is used
- // by the Hextile decoder for raw-encoded tiles.
- //
-
- void handleRawRect(int x, int y, int w, int h) throws IOException, Exception {
- handleRawRect(x, y, w, h, true);
- }
-
- void handleRawRect(int x, int y, int w, int h, boolean paint)
- throws IOException , Exception{
- rawDecoder.handleRect(x, y, w, h);
- if (paint)
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a CopyRect rectangle.
- //
-
- void handleCopyRect(int x, int y, int w, int h) throws IOException {
- copyRectDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle an RRE-encoded rectangle.
- //
-
- void handleRRERect(int x, int y, int w, int h) throws IOException {
- rreDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a CoRRE-encoded rectangle.
- //
-
- void handleCoRRERect(int x, int y, int w, int h) throws IOException {
- correDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Hextile-encoded rectangle.
- //
-
- void handleHextileRect(int x, int y, int w, int h) throws IOException,
- Exception {
- hextileDecoder.handleRect(x, y, w, h);
- }
-
- //
- // Handle a ZRLE-encoded rectangle.
- //
- // FIXME: Currently, session recording is not fully supported for ZRLE.
- //
-
- void handleZRLERect(int x, int y, int w, int h) throws Exception {
- zrleDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Zlib-encoded rectangle.
- //
-
- void handleZlibRect(int x, int y, int w, int h) throws Exception {
- zlibDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Handle a Tight-encoded rectangle.
- //
-
- void handleTightRect(int x, int y, int w, int h) throws Exception {
- tightDecoder.handleRect(x, y, w, h);
- scheduleRepaint(x, y, w, h);
- }
-
- //
- // Tell JVM to repaint specified desktop area.
- //
-
- public void scheduleRepaint(int x, int y, int w, int h) {
- // Request repaint, deferred if necessary.
- if (rfb.framebufferWidth == scaledWidth) {
- repaint(viewer.deferScreenUpdates, x, y, w, h);
- } else {
- int sx = x * scalingFactor / 100;
- int sy = y * scalingFactor / 100;
- int sw = ((x + w) * scalingFactor + 49) / 100 - sx + 1;
- int sh = ((y + h) * scalingFactor + 49) / 100 - sy + 1;
- repaint(viewer.deferScreenUpdates, sx, sy, sw, sh);
- }
- }
-
- //
- // Handle events.
- //
-
- public void keyPressed(KeyEvent evt) {
- processLocalKeyEvent(evt);
- }
- public void keyReleased(KeyEvent evt) {
- processLocalKeyEvent(evt);
- }
- public void keyTyped(KeyEvent evt) {
- evt.consume();
- }
-
- public void mousePressed(MouseEvent evt) {
- processLocalMouseEvent(evt, false);
- }
- public void mouseReleased(MouseEvent evt) {
- processLocalMouseEvent(evt, false);
- }
- public void mouseMoved(MouseEvent evt) {
- processLocalMouseEvent(evt, true);
- }
- public void mouseDragged(MouseEvent evt) {
- processLocalMouseEvent(evt, true);
- }
-
- private synchronized void trySendPointerEvent() {
- if ((needToSendMouseEvent) && (mouseEvent!=null)) {
- sendMouseEvent(mouseEvent, false);
- needToSendMouseEvent = false;
- lastMouseEventSendTime = System.currentTimeMillis();
- }
- }
-
- public void run() {
- while (true) {
- // Send mouse movement if we have it
- trySendPointerEvent();
- // Sleep for some time
- try {
- Thread.sleep(1000 / mouseMaxFreq);
- } catch (InterruptedException ex) {
- }
- }
- }
-
- //
- // Ignored events.
- //
-
- public void mouseClicked(MouseEvent evt) {}
- public void mouseEntered(MouseEvent evt) {}
- public void mouseExited(MouseEvent evt) {}
-
- //
- // Actual event processing.
- //
-
- private void processLocalKeyEvent(KeyEvent evt) {
- if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (!inputEnabled) {
- if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R') &&
- evt.getID() == KeyEvent.KEY_PRESSED ) {
- // Request screen update.
- try {
- rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth,
- rfb.framebufferHeight, false);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- } else {
- // Input enabled.
- synchronized(rfb) {
- try {
- rfb.writeKeyEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
- }
- }
- }
- // Don't ever pass keyboard events to AWT for default processing.
- // Otherwise, pressing Tab would switch focus to ButtonPanel etc.
- evt.consume();
- }
-
- private void processLocalMouseEvent(MouseEvent evt, boolean moved) {
- if (viewer.rfb != null && rfb.inNormalProtocol) {
- if (inputEnabled) {
- // If mouse not moved, but it's click event then
- // send it to server immideanlty.
- // Else, it's mouse movement - we can send it in
- // our thread later.
- if (!moved) {
- sendMouseEvent(evt, moved);
- } else {
- mouseEvent = evt;
- needToSendMouseEvent = true;
- }
- }
- }
- }
-
- private void sendMouseEvent(MouseEvent evt, boolean moved) {
- if (moved) {
- softCursorMove(evt.getX(), evt.getY());
- }
- if (rfb.framebufferWidth != scaledWidth) {
- int sx = (evt.getX() * 100 + scalingFactor/2) / scalingFactor;
- int sy = (evt.getY() * 100 + scalingFactor/2) / scalingFactor;
- evt.translatePoint(sx - evt.getX(), sy - evt.getY());
- }
- synchronized(rfb) {
- try {
- rfb.writePointerEvent(evt);
- } catch (Exception e) {
- e.printStackTrace();
- }
- rfb.notify();
- lastMouseEventSendTime = System.currentTimeMillis();
- }
- }
-
- //
- // Reset update statistics.
- //
-
- void resetStats() {
- statStartTime = System.currentTimeMillis();
- statNumUpdates = 0;
- statNumTotalRects = 0;
- statNumPixelRects = 0;
- statNumRectsTight = 0;
- statNumRectsTightJPEG = 0;
- statNumRectsZRLE = 0;
- statNumRectsHextile = 0;
- statNumRectsRaw = 0;
- statNumRectsCopy = 0;
- statNumBytesEncoded = 0;
- statNumBytesDecoded = 0;
- if (tightDecoder != null) {
- tightDecoder.setNumJPEGRects(0);
- tightDecoder.setNumTightRects(0);
- }
- }
-
- //////////////////////////////////////////////////////////////////
- //
- // Handle cursor shape updates (XCursor and RichCursor encodings).
- //
-
- boolean showSoftCursor = false;
-
- MemoryImageSource softCursorSource;
- Image softCursor;
- MouseEvent mouseEvent = null;
- boolean needToSendMouseEvent = false;
- int cursorX = 0, cursorY = 0;
- int cursorWidth, cursorHeight;
- int origCursorWidth, origCursorHeight;
- int hotX, hotY;
- int origHotX, origHotY;
-
- //
- // Handle cursor shape update (XCursor and RichCursor encodings).
- //
-
- synchronized void
- handleCursorShapeUpdate(int encodingType,
- int xhot, int yhot, int width, int height)
- throws IOException {
-
- softCursorFree();
-
- if (width * height == 0)
- return;
-
- // Ignore cursor shape data if requested by user.
- if (viewer.options.ignoreCursorUpdates) {
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
-
- if (encodingType == rfb.EncodingXCursor) {
- rfb.skipBytes(6 + bytesMaskData * 2);
- } else {
- // rfb.EncodingRichCursor
- rfb.skipBytes(width * height + bytesMaskData);
- }
- return;
- }
-
- // Decode cursor pixel data.
- softCursorSource = decodeCursorShape(encodingType, width, height);
-
- // Set original (non-scaled) cursor dimensions.
- origCursorWidth = width;
- origCursorHeight = height;
- origHotX = xhot;
- origHotY = yhot;
-
- // Create off-screen cursor image.
- createSoftCursor();
-
- // Show the cursor.
- showSoftCursor = true;
- repaint(viewer.deferCursorUpdates,
- cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
- }
-
- //
- // decodeCursorShape(). Decode cursor pixel data and return
- // corresponding MemoryImageSource instance.
- //
-
- synchronized MemoryImageSource
- decodeCursorShape(int encodingType, int width, int height)
- throws IOException {
-
- int bytesPerRow = (width + 7) / 8;
- int bytesMaskData = bytesPerRow * height;
-
- int[] softCursorPixels = new int[width * height];
-
- if (encodingType == rfb.EncodingXCursor) {
-
- // Read foreground and background colors of the cursor.
- byte[] rgb = new byte[6];
- rfb.readFully(rgb);
- int[] colors = { (0xFF000000 | (rgb[3] & 0xFF) << 16 |
- (rgb[4] & 0xFF) << 8 | (rgb[5] & 0xFF)),
- (0xFF000000 | (rgb[0] & 0xFF) << 16 |
- (rgb[1] & 0xFF) << 8 | (rgb[2] & 0xFF)) };
-
- // Read pixel and mask data.
- byte[] pixBuf = new byte[bytesMaskData];
- rfb.readFully(pixBuf);
- byte[] maskBuf = new byte[bytesMaskData];
- rfb.readFully(maskBuf);
-
- // Decode pixel data into softCursorPixels[].
- byte pixByte, maskByte;
- int x, y, n, result;
- int i = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width / 8; x++) {
- pixByte = pixBuf[y * bytesPerRow + x];
- maskByte = maskBuf[y * bytesPerRow + x];
- for (n = 7; n >= 0; n--) {
- if ((maskByte >> n & 1) != 0) {
- result = colors[pixByte >> n & 1];
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- for (n = 7; n >= 8 - width % 8; n--) {
- if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
- result = colors[pixBuf[y * bytesPerRow + x] >> n & 1];
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
-
- } else {
- // encodingType == rfb.EncodingRichCursor
-
- // Read pixel and mask data.
- byte[] pixBuf = new byte[width * height * bytesPixel];
- rfb.readFully(pixBuf);
- byte[] maskBuf = new byte[bytesMaskData];
- rfb.readFully(maskBuf);
-
- // Decode pixel data into softCursorPixels[].
- byte maskByte;
- int x, y, n, result;
- int i = 0;
- for (y = 0; y < height; y++) {
- for (x = 0; x < width / 8; x++) {
- maskByte = maskBuf[y * bytesPerRow + x];
- for (n = 7; n >= 0; n--) {
- if ((maskByte >> n & 1) != 0) {
- if (bytesPixel == 1) {
- result = cm8.getRGB(pixBuf[i]);
- } else {
- result = 0xFF000000 |
- (pixBuf[i * 4 + 2] & 0xFF) << 16 |
- (pixBuf[i * 4 + 1] & 0xFF) << 8 |
- (pixBuf[i * 4] & 0xFF);
- }
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
- for (n = 7; n >= 8 - width % 8; n--) {
- if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) {
- if (bytesPixel == 1) {
- result = cm8.getRGB(pixBuf[i]);
- } else {
- result = 0xFF000000 |
- (pixBuf[i * 4 + 2] & 0xFF) << 16 |
- (pixBuf[i * 4 + 1] & 0xFF) << 8 |
- (pixBuf[i * 4] & 0xFF);
- }
- } else {
- result = 0; // Transparent pixel
- }
- softCursorPixels[i++] = result;
- }
- }
-
- }
-
- return new MemoryImageSource(width, height, softCursorPixels, 0, width);
- }
-
- //
- // createSoftCursor(). Assign softCursor new Image (scaled if necessary).
- // Uses softCursorSource as a source for new cursor image.
- //
-
- synchronized void
- createSoftCursor() {
-
- if (softCursorSource == null)
- return;
-
- int scaleCursor = viewer.options.scaleCursor;
- if (scaleCursor == 0 || !inputEnabled)
- scaleCursor = 100;
-
- // Save original cursor coordinates.
- int x = cursorX - hotX;
- int y = cursorY - hotY;
- int w = cursorWidth;
- int h = cursorHeight;
-
- cursorWidth = (origCursorWidth * scaleCursor + 50) / 100;
- cursorHeight = (origCursorHeight * scaleCursor + 50) / 100;
- hotX = (origHotX * scaleCursor + 50) / 100;
- hotY = (origHotY * scaleCursor + 50) / 100;
- softCursor = Toolkit.getDefaultToolkit().createImage(softCursorSource);
-
- if (scaleCursor != 100) {
- softCursor = softCursor.getScaledInstance(cursorWidth, cursorHeight,
- Image.SCALE_SMOOTH);
- }
-
- if (showSoftCursor) {
- // Compute screen area to update.
- x = Math.min(x, cursorX - hotX);
- y = Math.min(y, cursorY - hotY);
- w = Math.max(w, cursorWidth);
- h = Math.max(h, cursorHeight);
-
- repaint(viewer.deferCursorUpdates, x, y, w, h);
- }
- }
-
- //
- // softCursorMove(). Moves soft cursor into a particular location.
- //
-
- synchronized void softCursorMove(int x, int y) {
- int oldX = cursorX;
- int oldY = cursorY;
- cursorX = x;
- cursorY = y;
- if (showSoftCursor) {
- repaint(viewer.deferCursorUpdates,
- oldX - hotX, oldY - hotY, cursorWidth, cursorHeight);
- repaint(viewer.deferCursorUpdates,
- cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
- }
- }
-
- //
- // softCursorFree(). Remove soft cursor, dispose resources.
- //
-
- synchronized void softCursorFree() {
- if (showSoftCursor) {
- showSoftCursor = false;
- softCursor = null;
- softCursorSource = null;
-
- repaint(viewer.deferCursorUpdates,
- cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight);
- }
- }
-}
diff --git a/java/src/com/tigervnc/vncviewer/VncCanvas2.java b/java/src/com/tigervnc/vncviewer/VncCanvas2.java
deleted file mode 100644
index c39d4a52..00000000
--- a/java/src/com/tigervnc/vncviewer/VncCanvas2.java
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
-
-package com.tigervnc.vncviewer;
-
-import java.awt.*;
-import java.io.*;
-
-//
-// VncCanvas2 is a special version of VncCanvas which may use Java 2 API.
-//
-
-class VncCanvas2 extends VncCanvas {
-
- public VncCanvas2(VncViewer v) throws IOException {
- super(v);
- disableFocusTraversalKeys();
- }
-
- public VncCanvas2(VncViewer v, int maxWidth_, int maxHeight_)
- throws IOException {
-
- super(v, maxWidth_, maxHeight_);
- disableFocusTraversalKeys();
- }
-
- public void paintScaledFrameBuffer(Graphics g) {
- Graphics2D g2d = (Graphics2D)g;
- g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
- RenderingHints.VALUE_RENDER_QUALITY);
- g2d.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null);
- }
-
- //
- // Try to disable focus traversal keys (JVMs 1.4 and higher).
- //
-
- private void disableFocusTraversalKeys() {
- try {
- Class[] argClasses = { Boolean.TYPE };
- java.lang.reflect.Method method =
- getClass().getMethod("setFocusTraversalKeysEnabled", argClasses);
- Object[] argObjects = { new Boolean(false) };
- method.invoke(this, argObjects);
- } catch (Exception e) {}
- }
-
-}
-
diff --git a/java/src/com/tigervnc/vncviewer/VncViewer.java b/java/src/com/tigervnc/vncviewer/VncViewer.java
index 3a9f4c62..ba549186 100644
--- a/java/src/com/tigervnc/vncviewer/VncViewer.java
+++ b/java/src/com/tigervnc/vncviewer/VncViewer.java
@@ -1,1106 +1,268 @@
-//
-// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
-// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
-// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
-//
-// This 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 software 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 software; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
-//
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This 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 software 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 software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
//
-// VncViewer.java - the VNC viewer applet. This class mainly just sets up the
-// user interface, leaving it to the VncCanvas to do the actual rendering of
-// a VNC desktop.
+// VncViewer - the VNC viewer applet. It can also be run from the
+// command-line, when it behaves as much as possibly like the windows and unix
+// viewers.
//
+// Unfortunately, because of the way Java classes are loaded on demand, only
+// configuration parameters defined in this file can be set from the command
+// line or in applet parameters.
package com.tigervnc.vncviewer;
import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-import java.net.*;
-
-public class VncViewer extends java.applet.Applet
- implements java.lang.Runnable, WindowListener, ComponentListener {
-
- boolean inAnApplet = true;
- boolean inSeparateFrame = false;
-
- //
- // main() is called when run as a java program from the command line.
- // It simply runs the applet inside a newly-created frame.
- //
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.*;
+import java.awt.Label;
+import javax.swing.*;
+import java.net.URL;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+public class VncViewer extends java.applet.Applet implements Runnable
+{
+ public static final String version = "1.0.90";
+ public static final String about1 = "TigerVNC Viewer for Java "+version;
+ public static final String about2 = "Copyright (C) 1998-2010 "+
+ "[many holders]";
+ public static final String about3 = "Visit www.tigervnc.org "+
+ "for information on TigerVNC.";
public static void main(String[] argv) {
- VncViewer v = new VncViewer();
- v.mainArgs = argv;
- v.inAnApplet = false;
- v.inSeparateFrame = true;
-
- v.init();
- v.start();
- }
-
- String[] mainArgs;
-
- RfbProto rfb;
- Thread rfbThread;
-
- Frame vncFrame;
- Container vncContainer;
- ScrollPane desktopScrollPane;
- GridBagLayout gridbag;
- ButtonPanel buttonPanel;
- Label connStatusLabel;
- VncCanvas vc;
- OptionsFrame options;
- ClipboardFrame clipboard;
- RecordingFrame rec;
-
- // Control session recording.
- Object recordingSync;
- String sessionFileName;
- boolean recordingActive;
- boolean recordingStatusChanged;
- String cursorUpdatesDef;
- String eightBitColorsDef;
-
- // Variables read from parameter values.
- String socketFactory;
- String host;
- int port;
- String passwordParam;
- boolean showControls;
- boolean offerRelogin;
- boolean showOfflineDesktop;
- int deferScreenUpdates;
- int deferCursorUpdates;
- int deferUpdateRequests;
- int debugStatsExcludeUpdates;
- int debugStatsMeasureUpdates;
-
- // Reference to this applet for inter-applet communication.
- public static java.applet.Applet refApplet;
-
- //
- // init()
- //
-
- public void init() {
-
- readParameters();
-
- refApplet = this;
-
- if (inSeparateFrame) {
- vncFrame = new Frame("TigerVNC");
- if (!inAnApplet) {
- vncFrame.add("Center", this);
- }
- vncContainer = vncFrame;
- } else {
- vncContainer = this;
- }
-
- recordingSync = new Object();
-
- options = new OptionsFrame(this);
- clipboard = new ClipboardFrame(this);
- if (RecordingFrame.checkSecurity())
- rec = new RecordingFrame(this);
-
- sessionFileName = null;
- recordingActive = false;
- recordingStatusChanged = false;
- cursorUpdatesDef = null;
- eightBitColorsDef = null;
-
- if (inSeparateFrame) {
- vncFrame.addWindowListener(this);
- vncFrame.addComponentListener(this);
- }
-
- rfbThread = new Thread(this);
- rfbThread.start();
- }
-
- public void update(Graphics g) {
- }
-
- //
- // run() - executed by the rfbThread to deal with the RFB socket.
- //
-
- public void run() {
-
- gridbag = new GridBagLayout();
- vncContainer.setLayout(gridbag);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.anchor = GridBagConstraints.NORTHWEST;
-
- if (showControls) {
- buttonPanel = new ButtonPanel(this);
- gridbag.setConstraints(buttonPanel, gbc);
- vncContainer.add(buttonPanel);
- }
-
try {
- connectAndAuthenticate();
- doProtocolInitialisation();
-
- // FIXME: Use auto-scaling not only in a separate frame.
- if (options.autoScale && inSeparateFrame) {
- Dimension screenSize;
- try {
- screenSize = vncContainer.getToolkit().getScreenSize();
- } catch (Exception e) {
- screenSize = new Dimension(0, 0);
- }
- createCanvas(screenSize.width - 32, screenSize.height - 32);
+ String os = System.getProperty("os.name");
+ if (os.startsWith("Windows")) {
+ String laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+ UIManager.setLookAndFeel(laf);
} else {
- createCanvas(0, 0);
- }
-
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
-
- if (inSeparateFrame) {
-
- // Create a panel which itself is resizeable and can hold
- // non-resizeable VncCanvas component at the top left corner.
- Panel canvasPanel = new Panel();
- canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
- canvasPanel.add(vc);
-
- // Create a ScrollPane which will hold a panel with VncCanvas
- // inside.
- desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
- gbc.fill = GridBagConstraints.BOTH;
- gridbag.setConstraints(desktopScrollPane, gbc);
- desktopScrollPane.add(canvasPanel);
- // If auto scale is not enabled we don't need to set first frame
- // size to fullscreen
- if (!options.autoScale) {
- vc.isFirstSizeAutoUpdate = false;
+ UIManager.put("swing.boldMetal", Boolean.FALSE);
+ javax.swing.plaf.FontUIResource f = new
+ javax.swing.plaf.FontUIResource("SansSerif", Font.PLAIN, 11);
+ java.util.Enumeration keys = UIManager.getDefaults().keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ Object value = UIManager.get (key);
+ if (value instanceof javax.swing.plaf.FontUIResource)
+ UIManager.put(key, f);
}
-
- // Finally, add our ScrollPane to the Frame window.
- vncFrame.add(desktopScrollPane);
- vncFrame.setTitle(rfb.desktopName);
- vncFrame.pack();
- vc.resizeDesktopFrame();
-
- } else {
- // Just add the VncCanvas component to the Applet.
- gridbag.setConstraints(vc, gbc);
- add(vc);
- validate();
- }
-
- if (showControls) {
- buttonPanel.enableButtons();
- }
-
- moveFocusToDesktop();
- processNormalProtocol();
-
- } catch (NoRouteToHostException e) {
- fatalError("Network error: no route to server: " + host, e);
- } catch (UnknownHostException e) {
- fatalError("Network error: server name unknown: " + host, e);
- } catch (ConnectException e) {
- fatalError("Network error: could not connect to server: " +
- host + ":" + port, e);
- } catch (EOFException e) {
- if (showOfflineDesktop) {
- e.printStackTrace();
- System.out.println("Network error: remote side closed connection");
- if (vc != null) {
- vc.enableInput(false);
- }
- if (inSeparateFrame) {
- vncFrame.setTitle(rfb.desktopName + " [disconnected]");
- }
- if (rfb != null && !rfb.closed())
- rfb.close();
- if (showControls && buttonPanel != null) {
- buttonPanel.disableButtonsOnDisconnect();
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
- }
- } else {
- fatalError("Network error: remote side closed connection", e);
- }
- } catch (IOException e) {
- String str = e.getMessage();
- if (str != null && str.length() != 0) {
- fatalError("Network Error: " + str, e);
- } else {
- fatalError(e.toString(), e);
- }
- } catch (Exception e) {
- String str = e.getMessage();
- if (str != null && str.length() != 0) {
- fatalError("Error: " + str, e);
- } else {
- fatalError(e.toString(), e);
- }
- }
-
- }
-
- //
- // Create a VncCanvas instance.
- //
-
- void createCanvas(int maxWidth, int maxHeight) throws IOException {
- // Determine if Java 2D API is available and use a special
- // version of VncCanvas if it is present.
- vc = null;
- try {
- // This throws ClassNotFoundException if there is no Java 2D API.
- Class cl = Class.forName("java.awt.Graphics2D");
- // If we could load Graphics2D class, then we can use VncCanvas2D.
- cl = Class.forName("com.tigervnc.vncviewer.VncCanvas2");
- Class[] argClasses = { this.getClass(), Integer.TYPE, Integer.TYPE };
- java.lang.reflect.Constructor cstr = cl.getConstructor(argClasses);
- Object[] argObjects =
- { this, new Integer(maxWidth), new Integer(maxHeight) };
- vc = (VncCanvas)cstr.newInstance(argObjects);
- } catch (Exception e) {
- System.out.println("Warning: Java 2D API is not available");
- }
-
- // If we failed to create VncCanvas2D, use old VncCanvas.
- if (vc == null)
- vc = new VncCanvas(this, maxWidth, maxHeight);
- }
-
-
- //
- // Process RFB socket messages.
- // If the rfbThread is being stopped, ignore any exceptions,
- // otherwise rethrow the exception so it can be handled.
- //
-
- void processNormalProtocol() throws Exception {
- try {
- vc.processNormalProtocol();
- } catch (Exception e) {
- if (rfbThread == null) {
- System.out.println("Ignoring RFB socket exceptions" +
- " because applet is stopping");
- } else {
- throw e;
- }
- }
- }
-
-
- //
- // Connect to the RFB server and authenticate the user.
- //
-
- void connectAndAuthenticate() throws Exception
- {
- showConnectionStatus("Initializing...");
- if (inSeparateFrame) {
- vncFrame.pack();
- vncFrame.show();
- } else {
- validate();
- }
-
- showConnectionStatus("Connecting to " + host + ", port " + port + "...");
-
- rfb = new RfbProto(host, port, this);
- showConnectionStatus("Connected to server");
-
- rfb.readVersionMsg();
- showConnectionStatus("RFB server supports protocol version " +
- rfb.serverMajor + "." + rfb.serverMinor);
-
- rfb.writeVersionMsg();
- showConnectionStatus("Using RFB protocol version " +
- rfb.clientMajor + "." + rfb.clientMinor);
-
- int secType = rfb.negotiateSecurity();
- doAuthentification(secType);
- }
-
- void doAuthentification(int secType) throws Exception {
- switch (secType) {
- case RfbProto.SecTypeNone:
- showConnectionStatus("No authentication needed");
- rfb.authenticateNone();
- break;
- case RfbProto.SecTypeVncAuth:
- showConnectionStatus("Performing standard VNC authentication");
- if (passwordParam != null) {
- rfb.authenticateVNC(passwordParam);
- } else {
- String pw = askPassword();
- rfb.authenticateVNC(pw);
- }
- break;
- case RfbProto.SecTypeVeNCrypt:
- showConnectionStatus("VeNCrypt chooser");
- secType = rfb.authenticateVeNCrypt();
- doAuthentification(secType);
- break;
- case RfbProto.SecTypePlain:
- showConnectionStatus("Plain authentication");
- {
- String user = askUser();
- String pw = askPassword();
- rfb.authenticatePlain(user,pw);
- }
- break;
- case RfbProto.SecTypeTLSNone:
- showConnectionStatus("TLSNone");
- rfb.authenticateTLS();
- rfb.authenticateNone();
- break;
- case RfbProto.SecTypeTLSVnc:
- showConnectionStatus("TLSVnc");
- rfb.authenticateTLS();
- doAuthentification(RfbProto.SecTypeVncAuth);
- break;
- case RfbProto.SecTypeTLSPlain:
- showConnectionStatus("TLSPlain");
- rfb.authenticateTLS();
- doAuthentification(RfbProto.SecTypePlain);
- break;
- case RfbProto.SecTypeX509None:
- showConnectionStatus("X509None");
- rfb.authenticateX509();
- rfb.authenticateNone();
- break;
- case RfbProto.SecTypeX509Vnc:
- showConnectionStatus("X509Vnc");
- rfb.authenticateX509();
- doAuthentification(RfbProto.SecTypeVncAuth);
- break;
- case RfbProto.SecTypeX509Plain:
- showConnectionStatus("X509Plain");
- rfb.authenticateX509();
- doAuthentification(RfbProto.SecTypePlain);
- break;
- default:
- throw new Exception("Unknown authentication scheme " + secType);
- }
- }
-
-
- //
- // Show a message describing the connection status.
- // To hide the connection status label, use (msg == null).
- //
-
- void showConnectionStatus(String msg)
- {
- if (msg == null) {
- if (vncContainer.isAncestorOf(connStatusLabel)) {
- vncContainer.remove(connStatusLabel);
}
- return;
- }
-
- System.out.println(msg);
-
- if (connStatusLabel == null) {
- connStatusLabel = new Label("Status: " + msg);
- connStatusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
- } else {
- connStatusLabel.setText("Status: " + msg);
- }
-
- if (!vncContainer.isAncestorOf(connStatusLabel)) {
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.fill = GridBagConstraints.HORIZONTAL;
- gbc.anchor = GridBagConstraints.NORTHWEST;
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
- gbc.insets = new Insets(20, 30, 20, 30);
- gridbag.setConstraints(connStatusLabel, gbc);
- vncContainer.add(connStatusLabel);
- }
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
+ UIManager.put("TitledBorder.titleColor",Color.blue);
+ } catch (java.lang.Exception exc) { }
+ VncViewer viewer = new VncViewer(argv);
+ viewer.start();
}
-
- //
- // Show an authentication panel.
- //
-
- String askUser() throws Exception
- {
- showConnectionStatus(null);
-
- AuthPanel authPanel = new AuthPanel(this, false);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.anchor = GridBagConstraints.NORTHWEST;
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
- gbc.ipadx = 100;
- gbc.ipady = 50;
- gridbag.setConstraints(authPanel, gbc);
- vncContainer.add(authPanel);
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
-
- authPanel.moveFocusToDefaultField();
- String pw = authPanel.getPassword();
- vncContainer.remove(authPanel);
-
- return pw;
- }
-
- String askPassword() throws Exception
- {
- showConnectionStatus(null);
-
- AuthPanel authPanel = new AuthPanel(this, true);
-
- GridBagConstraints gbc = new GridBagConstraints();
- gbc.gridwidth = GridBagConstraints.REMAINDER;
- gbc.anchor = GridBagConstraints.NORTHWEST;
- gbc.weightx = 1.0;
- gbc.weighty = 1.0;
- gbc.ipadx = 100;
- gbc.ipady = 50;
- gridbag.setConstraints(authPanel, gbc);
- vncContainer.add(authPanel);
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
-
- authPanel.moveFocusToDefaultField();
- String pw = authPanel.getPassword();
- vncContainer.remove(authPanel);
-
- return pw;
- }
-
-
- //
- // Do the rest of the protocol initialisation.
- //
-
- void doProtocolInitialisation() throws IOException
- {
- rfb.writeClientInit();
- rfb.readServerInit();
-
- System.out.println("Desktop name is " + rfb.desktopName);
- System.out.println("Desktop size is " + rfb.framebufferWidth + " x " +
- rfb.framebufferHeight);
-
- setEncodings();
-
- showConnectionStatus(null);
- }
-
-
- //
- // Send current encoding list to the RFB server.
- //
-
- int[] encodingsSaved;
- int nEncodingsSaved;
-
- void setEncodings() { setEncodings(false); }
- void autoSelectEncodings() { setEncodings(true); }
-
- void setEncodings(boolean autoSelectOnly) {
- if (options == null || rfb == null || !rfb.inNormalProtocol)
- return;
-
- int preferredEncoding = options.preferredEncoding;
- if (preferredEncoding == -1) {
- long kbitsPerSecond = rfb.kbitsPerSecond();
- if (nEncodingsSaved < 1) {
- // Choose Tight or ZRLE encoding for the very first update.
- System.out.println("Using Tight/ZRLE encodings");
- preferredEncoding = RfbProto.EncodingTight;
- } else if (kbitsPerSecond > 2000 &&
- encodingsSaved[0] != RfbProto.EncodingHextile) {
- // Switch to Hextile if the connection speed is above 2Mbps.
- System.out.println("Throughput " + kbitsPerSecond +
- " kbit/s - changing to Hextile encoding");
- preferredEncoding = RfbProto.EncodingHextile;
- } else if (kbitsPerSecond < 1000 &&
- encodingsSaved[0] != RfbProto.EncodingTight) {
- // Switch to Tight/ZRLE if the connection speed is below 1Mbps.
- System.out.println("Throughput " + kbitsPerSecond +
- " kbit/s - changing to Tight/ZRLE encodings");
- preferredEncoding = RfbProto.EncodingTight;
- } else {
- // Don't change the encoder.
- if (autoSelectOnly)
- return;
- preferredEncoding = encodingsSaved[0];
+
+ public VncViewer(String[] argv) {
+ applet = false;
+
+ // Override defaults with command-line options
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].equalsIgnoreCase("-log")) {
+ if (++i >= argv.length) usage();
+ System.err.println("Log setting: "+argv[i]);
+ LogWriter.setLogParams(argv[i]);
+ continue;
}
- } else {
- // Auto encoder selection is not enabled.
- if (autoSelectOnly)
- return;
- }
- int[] encodings = new int[20];
- int nEncodings = 0;
+ if (Configuration.setParam(argv[i]))
+ continue;
- encodings[nEncodings++] = preferredEncoding;
- if (options.useCopyRect) {
- encodings[nEncodings++] = RfbProto.EncodingCopyRect;
- }
-
- if (preferredEncoding != RfbProto.EncodingTight) {
- encodings[nEncodings++] = RfbProto.EncodingTight;
- }
- if (preferredEncoding != RfbProto.EncodingZRLE) {
- encodings[nEncodings++] = RfbProto.EncodingZRLE;
- }
- if (preferredEncoding != RfbProto.EncodingHextile) {
- encodings[nEncodings++] = RfbProto.EncodingHextile;
- }
- if (preferredEncoding != RfbProto.EncodingZlib) {
- encodings[nEncodings++] = RfbProto.EncodingZlib;
- }
- if (preferredEncoding != RfbProto.EncodingCoRRE) {
- encodings[nEncodings++] = RfbProto.EncodingCoRRE;
- }
- if (preferredEncoding != RfbProto.EncodingRRE) {
- encodings[nEncodings++] = RfbProto.EncodingRRE;
- }
-
- if (options.compressLevel >= 0 && options.compressLevel <= 9) {
- encodings[nEncodings++] =
- RfbProto.EncodingCompressLevel0 + options.compressLevel;
- }
- if (options.jpegQuality >= 0 && options.jpegQuality <= 9) {
- encodings[nEncodings++] =
- RfbProto.EncodingQualityLevel0 + options.jpegQuality;
- }
-
- if (options.requestCursorUpdates) {
- encodings[nEncodings++] = RfbProto.EncodingXCursor;
- encodings[nEncodings++] = RfbProto.EncodingRichCursor;
- if (!options.ignoreCursorUpdates)
- encodings[nEncodings++] = RfbProto.EncodingPointerPos;
- }
-
- encodings[nEncodings++] = RfbProto.EncodingLastRect;
- encodings[nEncodings++] = RfbProto.EncodingNewFBSize;
-
- boolean encodingsWereChanged = false;
- if (nEncodings != nEncodingsSaved) {
- encodingsWereChanged = true;
- } else {
- for (int i = 0; i < nEncodings; i++) {
- if (encodings[i] != encodingsSaved[i]) {
- encodingsWereChanged = true;
- break;
+ if (argv[i].charAt(0) == '-') {
+ if (i+1 < argv.length) {
+ if (Configuration.setParam(argv[i].substring(1), argv[i+1])) {
+ i++;
+ continue;
+ }
}
+ usage();
}
- }
- if (encodingsWereChanged) {
- try {
- rfb.writeSetEncodings(encodings, nEncodings);
- if (vc != null) {
- vc.softCursorFree();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- encodingsSaved = encodings;
- nEncodingsSaved = nEncodings;
+ if (vncServerName.getValue() != null)
+ usage();
+ vncServerName.setParam(argv[i]);
}
}
-
- //
- // setCutText() - send the given cut text to the RFB server.
- //
-
- void setCutText(String text) {
- try {
- if (rfb != null && rfb.inNormalProtocol) {
- rfb.writeClientCutText(text);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
+ public static void usage() {
+ String usage = ("\nusage: vncviewer [options/parameters] "+
+ "[host:displayNum] [options/parameters]\n"+
+ //" vncviewer [options/parameters] -listen [port] "+
+ //"[options/parameters]\n"+
+ "\n"+
+ "Options:\n"+
+ " -log <level> configure logging level\n"+
+ "\n"+
+ "Parameters can be turned on with -<param> or off with "+
+ "-<param>=0\n"+
+ "Parameters which take a value can be specified as "+
+ "-<param> <value>\n"+
+ "Other valid forms are <param>=<value> -<param>=<value> "+
+ "--<param>=<value>\n"+
+ "Parameter names are case-insensitive. The parameters "+
+ "are:\n\n"+
+ Configuration.listParams());
+ System.err.print(usage);
+ System.exit(1);
}
-
- //
- // Order change in session recording status. To stop recording, pass
- // null in place of the fname argument.
- //
-
- void setRecordingStatus(String fname) {
- synchronized(recordingSync) {
- sessionFileName = fname;
- recordingStatusChanged = true;
- }
+ public VncViewer() {
+ applet = true;
+ firstApplet = true;
}
- //
- // Start or stop session recording. Returns true if this method call
- // causes recording of a new session.
- //
-
- boolean checkRecordingStatus() throws IOException {
- synchronized(recordingSync) {
- if (recordingStatusChanged) {
- recordingStatusChanged = false;
- if (sessionFileName != null) {
- startRecording();
- return true;
- } else {
- stopRecording();
- }
- }
- }
- return false;
+ public static void newViewer(VncViewer oldViewer) {
+ VncViewer viewer = new VncViewer();
+ viewer.applet = oldViewer.applet;
+ viewer.firstApplet = false;
+ viewer.start();
}
- //
- // Start session recording.
- //
-
- protected void startRecording() throws IOException {
- synchronized(recordingSync) {
- if (!recordingActive) {
- // Save settings to restore them after recording the session.
- cursorUpdatesDef =
- options.choices[options.cursorUpdatesIndex].getSelectedItem();
- eightBitColorsDef =
- options.choices[options.eightBitColorsIndex].getSelectedItem();
- // Set options to values suitable for recording.
- options.choices[options.cursorUpdatesIndex].select("Disable");
- options.choices[options.cursorUpdatesIndex].setEnabled(false);
- options.setEncodings();
- options.choices[options.eightBitColorsIndex].select("No");
- options.choices[options.eightBitColorsIndex].setEnabled(false);
- options.setColorFormat();
- } else {
- rfb.closeSession();
- }
-
- System.out.println("Recording the session in " + sessionFileName);
- rfb.startSession(sessionFileName);
- recordingActive = true;
- }
- }
-
- //
- // Stop session recording.
- //
-
- protected void stopRecording() throws IOException {
- synchronized(recordingSync) {
- if (recordingActive) {
- // Restore options.
- options.choices[options.cursorUpdatesIndex].select(cursorUpdatesDef);
- options.choices[options.cursorUpdatesIndex].setEnabled(true);
- options.setEncodings();
- options.choices[options.eightBitColorsIndex].select(eightBitColorsDef);
- options.choices[options.eightBitColorsIndex].setEnabled(true);
- options.setColorFormat();
-
- rfb.closeSession();
- System.out.println("Session recording stopped.");
- }
- sessionFileName = null;
- recordingActive = false;
- }
- }
-
-
- //
- // readParameters() - read parameters from the html source or from the
- // command line. On the command line, the arguments are just a sequence of
- // param_name/param_value pairs where the names and values correspond to
- // those expected in the html applet tag source.
- //
-
- void readParameters() {
- host = readParameter("HOST", !inAnApplet);
- if (host == null) {
- host = getCodeBase().getHost();
- if (host.equals("")) {
- fatalError("HOST parameter not specified");
- }
- }
-
- port = readIntParameter("PORT", 5900);
-
- // Read "ENCPASSWORD" or "PASSWORD" parameter if specified.
- readPasswordParameters();
-
- String str;
- if (inAnApplet) {
- str = readParameter("Open New Window", false);
- if (str != null && str.equalsIgnoreCase("Yes"))
- inSeparateFrame = true;
- }
-
- // "Show Controls" set to "No" disables button panel.
- showControls = true;
- str = readParameter("Show Controls", false);
- if (str != null && str.equalsIgnoreCase("No"))
- showControls = false;
-
- // "Offer Relogin" set to "No" disables "Login again" and "Close
- // window" buttons under error messages in applet mode.
- offerRelogin = true;
- str = readParameter("Offer Relogin", false);
- if (str != null && str.equalsIgnoreCase("No"))
- offerRelogin = false;
-
- // Do we continue showing desktop on remote disconnect?
- showOfflineDesktop = false;
- str = readParameter("Show Offline Desktop", false);
- if (str != null && str.equalsIgnoreCase("Yes"))
- showOfflineDesktop = true;
-
- // Fine tuning options.
- deferScreenUpdates = readIntParameter("Defer screen updates", 20);
- deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
- deferUpdateRequests = readIntParameter("Defer update requests", 0);
-
- // Debugging options.
- debugStatsExcludeUpdates = readIntParameter("DEBUG_XU", 0);
- debugStatsMeasureUpdates = readIntParameter("DEBUG_CU", 0);
-
- // SocketFactory.
- socketFactory = readParameter("SocketFactory", false);
- }
-
- //
- // Read password parameters. If an "ENCPASSWORD" parameter is set,
- // then decrypt the password into the passwordParam string. Otherwise,
- // try to read the "PASSWORD" parameter directly to passwordParam.
- //
-
- private void readPasswordParameters() {
- String encPasswordParam = readParameter("ENCPASSWORD", false);
- if (encPasswordParam == null) {
- passwordParam = readParameter("PASSWORD", false);
- } else {
- // ENCPASSWORD is hexascii-encoded. Decode.
- byte[] pw = {0, 0, 0, 0, 0, 0, 0, 0};
- int len = encPasswordParam.length() / 2;
- if (len > 8)
- len = 8;
- for (int i = 0; i < len; i++) {
- String hex = encPasswordParam.substring(i*2, i*2+2);
- Integer x = new Integer(Integer.parseInt(hex, 16));
- pw[i] = x.byteValue();
- }
- // Decrypt the password.
- byte[] key = {23, 82, 107, 6, 35, 78, 88, 7};
- DesCipher des = new DesCipher(key);
- des.decrypt(pw, 0, pw, 0);
- passwordParam = new String(pw);
- }
- }
-
- public String readParameter(String name, boolean required) {
- if (inAnApplet) {
- String s = getParameter(name);
- if ((s == null) && required) {
- fatalError(name + " parameter not specified");
- }
- return s;
- }
- for (int i = 0; i < mainArgs.length; i += 2) {
- if (mainArgs[i].equalsIgnoreCase(name)) {
- try {
- return mainArgs[i+1];
- } catch (Exception e) {
- if (required) {
- fatalError(name + " parameter not specified");
- }
- return null;
- }
- }
- }
- if (required) {
- fatalError(name + " parameter not specified");
- }
- return null;
- }
-
- int readIntParameter(String name, int defaultValue) {
- String str = readParameter(name, false);
- int result = defaultValue;
- if (str != null) {
- try {
- result = Integer.parseInt(str);
- } catch (NumberFormatException e) { }
- }
- return result;
- }
-
- //
- // moveFocusToDesktop() - move keyboard focus either to VncCanvas.
- //
-
- void moveFocusToDesktop() {
- if (vncContainer != null) {
- if (vc != null && vncContainer.isAncestorOf(vc))
- vc.requestFocus();
- }
+ public void init() {
+ vlog.debug("init called");
+ setBackground(Color.white);
+ logo = getImage(getDocumentBase(), "logo150x150.gif");
}
- //
- // disconnect() - close connection to server.
- //
-
- synchronized public void disconnect() {
- System.out.println("Disconnecting");
-
- if (vc != null) {
- double sec = (System.currentTimeMillis() - vc.statStartTime) / 1000.0;
- double rate = Math.round(vc.statNumUpdates / sec * 100) / 100.0;
- long nRealRects = vc.statNumPixelRects;
- long nPseudoRects = vc.statNumTotalRects - vc.statNumPixelRects;
- System.out.println("Updates received: " + vc.statNumUpdates + " (" +
- nRealRects + " rectangles + " + nPseudoRects +
- " pseudo), " + rate + " updates/sec");
- long numRectsOther = nRealRects - vc.statNumRectsTight
- - vc.statNumRectsZRLE - vc.statNumRectsHextile
- - vc.statNumRectsRaw - vc.statNumRectsCopy;
- System.out.println("Rectangles:" +
- " Tight=" + vc.statNumRectsTight +
- "(JPEG=" + vc.statNumRectsTightJPEG +
- ") ZRLE=" + vc.statNumRectsZRLE +
- " Hextile=" + vc.statNumRectsHextile +
- " Raw=" + vc.statNumRectsRaw +
- " CopyRect=" + vc.statNumRectsCopy +
- " other=" + numRectsOther);
-
- long raw = vc.statNumBytesDecoded;
- long compressed = vc.statNumBytesEncoded;
- if (compressed > 0) {
- double ratio = Math.round((double)raw / compressed * 1000) / 1000.0;
- System.out.println("Pixel data: " + vc.statNumBytesDecoded +
- " bytes, " + vc.statNumBytesEncoded +
- " compressed, ratio " + ratio);
+ public void start() {
+ vlog.debug("start called");
+ nViewers++;
+ if (firstApplet) {
+ alwaysShowServerDialog.setParam(true);
+ Configuration.readAppletParams(this);
+ String host = getCodeBase().getHost();
+ if (vncServerName.getValue() == null && vncServerPort.getValue() != 0) {
+ int port = vncServerPort.getValue();
+ vncServerName.setParam(host + ((port >= 5900 && port <= 5999)
+ ? (":"+(port-5900))
+ : ("::"+port)));
}
}
-
- if (rfb != null && !rfb.closed())
- rfb.close();
- options.dispose();
- clipboard.dispose();
- if (rec != null)
- rec.dispose();
-
- if (inAnApplet) {
- showMessage("Disconnected");
- } else {
- System.exit(0);
- }
- }
-
- //
- // fatalError() - print out a fatal error message.
- // FIXME: Do we really need two versions of the fatalError() method?
- //
-
- synchronized public void fatalError(String str) {
- System.out.println(str);
-
- if (inAnApplet) {
- // vncContainer null, applet not inited,
- // can not present the error to the user.
- Thread.currentThread().stop();
- } else {
- System.exit(1);
- }
- }
-
- synchronized public void fatalError(String str, Exception e) {
-
- if (rfb != null && rfb.closed()) {
- // Not necessary to show error message if the error was caused
- // by I/O problems after the rfb.close() method call.
- System.out.println("RFB thread finished");
- return;
- }
-
- System.out.println(str);
- e.printStackTrace();
-
- if (rfb != null)
- rfb.close();
-
- if (inAnApplet) {
- showMessage(str);
- } else {
- System.exit(1);
- }
- }
-
- //
- // Show message text and optionally "Relogin" and "Close" buttons.
- //
-
- void showMessage(String msg) {
- vncContainer.removeAll();
-
- Label errLabel = new Label(msg, Label.CENTER);
- errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
-
- if (offerRelogin) {
-
- Panel gridPanel = new Panel(new GridLayout(0, 1));
- Panel outerPanel = new Panel(new FlowLayout(FlowLayout.LEFT));
- outerPanel.add(gridPanel);
- vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 16));
- vncContainer.add(outerPanel);
- Panel textPanel = new Panel(new FlowLayout(FlowLayout.CENTER));
- textPanel.add(errLabel);
- gridPanel.add(textPanel);
- gridPanel.add(new ReloginPanel(this));
-
- } else {
-
- vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
- vncContainer.add(errLabel);
-
- }
-
- if (inSeparateFrame) {
- vncFrame.pack();
- } else {
- validate();
- }
+ thread = new Thread(this);
+ thread.start();
}
- //
- // Stop the applet.
- // Main applet thread will terminate on first exception
- // after seeing that rfbThread has been set to null.
- //
-
- public void stop() {
- System.out.println("Stopping applet");
- rfbThread = null;
- }
-
- //
- // This method is called before the applet is destroyed.
- //
-
- public void destroy() {
- System.out.println("Destroying applet");
-
- vncContainer.removeAll();
- options.dispose();
- clipboard.dispose();
- if (rec != null)
- rec.dispose();
- if (rfb != null && !rfb.closed())
- rfb.close();
- if (inSeparateFrame)
- vncFrame.dispose();
- }
-
- //
- // Start/stop receiving mouse events.
- //
-
- public void enableInput(boolean enable) {
- vc.enableInput(enable);
- }
-
- //
- // Resize framebuffer if autoScale is enabled.
- //
-
- public void componentResized(ComponentEvent e) {
- if (e.getComponent() == vncFrame) {
- if (options.autoScale) {
- if (vc != null) {
- if (!vc.isFirstSizeAutoUpdate) {
- vc.updateFramebufferSize();
- }
- }
+ public void run() {
+ CConn cc = null;
+ try {
+ cc = new CConn(this, null, vncServerName.getValue(), false);
+ while (true)
+ cc.processMsg();
+ } catch (EndOfStream e) {
+ vlog.info(e.toString());
+ } catch (java.lang.Exception e) {
+ if (cc != null) cc.deleteWindow();
+ if (cc == null || !cc.shuttingDown) {
+ e.printStackTrace();
+ JOptionPane.showMessageDialog(null,
+ e.toString(),
+ "VNC Viewer : Error",
+ JOptionPane.ERROR_MESSAGE);
}
}
- }
-
- //
- // Ignore component events we're not interested in.
- //
-
- public void componentShown(ComponentEvent e) { }
- public void componentMoved(ComponentEvent e) { }
- public void componentHidden(ComponentEvent e) { }
-
- //
- // Close application properly on window close event.
- //
-
- public void windowClosing(WindowEvent evt) {
- System.out.println("Closing window");
- if (rfb != null)
- disconnect();
-
- vncContainer.hide();
-
- if (!inAnApplet) {
+ if (cc != null) cc.deleteWindow();
+ nViewers--;
+ if (!applet && nViewers == 0) {
System.exit(0);
}
}
- //
- // Ignore window events we're not interested in.
- //
-
- public void windowActivated(WindowEvent evt) {}
- public void windowDeactivated (WindowEvent evt) {}
- public void windowOpened(WindowEvent evt) {}
- public void windowClosed(WindowEvent evt) {}
- public void windowIconified(WindowEvent evt) {}
- public void windowDeiconified(WindowEvent evt) {}
+ BoolParameter fastCopyRect
+ = new BoolParameter("FastCopyRect",
+ "Use fast CopyRect - turn this off if you get "+
+ "screen corruption when copying from off-screen",
+ true);
+ BoolParameter useLocalCursor
+ = new BoolParameter("UseLocalCursor",
+ "Render the mouse cursor locally", true);
+ BoolParameter sendLocalUsername
+ = new BoolParameter("SendLocalUsername",
+ "Send the local username for SecurityTypes "+
+ "such as Plain rather than prompting", true);
+ BoolParameter autoSelect
+ = new BoolParameter("AutoSelect",
+ "Auto select pixel format and encoding", true);
+ BoolParameter fullColour
+ = new BoolParameter("FullColour",
+ "Use full colour - otherwise 6-bit colour is used "+
+ "until AutoSelect decides the link is fast enough",
+ true);
+ AliasParameter fullColor
+ = new AliasParameter("FullColor", "Alias for FullColour", fullColour);
+ StringParameter preferredEncoding
+ = new StringParameter("PreferredEncoding",
+ "Preferred encoding to use (Tight, ZRLE, hextile or"+
+ " raw) - implies AutoSelect=0", "Tight");
+ BoolParameter viewOnly
+ = new BoolParameter("ViewOnly", "Don't send any mouse or keyboard "+
+ "events to the server", false);
+ BoolParameter shared
+ = new BoolParameter("Shared", "Don't disconnect other viewers upon "+
+ "connection - share the desktop instead", false);
+ BoolParameter fullScreen
+ = new BoolParameter("FullScreen", "Full Screen Mode", false);
+ BoolParameter acceptClipboard
+ = new BoolParameter("AcceptClipboard",
+ "Accept clipboard changes from the server", true);
+ BoolParameter sendClipboard
+ = new BoolParameter("SendClipboard",
+ "Send clipboard changes to the server", true);
+ BoolParameter alwaysShowServerDialog
+ = new BoolParameter("AlwaysShowServerDialog",
+ "Always show the server dialog even if a server "+
+ "has been specified in an applet parameter or on "+
+ "the command line", false);
+ StringParameter vncServerName
+ = new StringParameter("Server",
+ "The VNC server <host>[:<dpyNum>] or "+
+ "<host>::<port>", null);
+ IntParameter vncServerPort
+ = new IntParameter("Port",
+ "The VNC server's port number, assuming it is on "+
+ "the host from which the applet was downloaded", 0);
+ BoolParameter customCompressLevel
+ = new BoolParameter("CustomCompressLevel",
+ "Use custom compression level. "+
+ "Default if CompressLevel is specified.", false);
+ IntParameter compressLevel
+ = new IntParameter("CompressLevel",
+ "Use specified compression level "+
+ "0 = Low, 9 = High",
+ 6);
+ BoolParameter noJpeg
+ = new BoolParameter("NoJPEG",
+ "Disable lossy JPEG compression in Tight encoding.", false);
+ IntParameter qualityLevel
+ = new IntParameter("QualityLevel",
+ "JPEG quality level. "+
+ "0 = Low, 9 = High",
+ 8);
+
+ Thread thread;
+ boolean applet, firstApplet;
+ Image logo;
+ static int nViewers;
+ static LogWriter vlog = new LogWriter("main");
}
diff --git a/java/src/com/tigervnc/vncviewer/X509Tunnel.java b/java/src/com/tigervnc/vncviewer/X509Tunnel.java
deleted file mode 100644
index ddc3f82a..00000000
--- a/java/src/com/tigervnc/vncviewer/X509Tunnel.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2003 Sun Microsystems, Inc.
- * Copyright (C) 2003-2010 Martin Koegler
- * Copyright (C) 2006 OCCAM Financial Technology
- *
- * This 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 software 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 software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-package com.tigervnc.vncviewer;
-
-import java.util.*;
-import java.net.*;
-import javax.net.ssl.*;
-import java.security.*;
-import java.security.cert.*;
-
-public class X509Tunnel extends TLSTunnelBase
-{
-
- public X509Tunnel (Socket sock_)
- {
- super (sock_);
- }
-
- protected void setParam (SSLSocket sock)
- {
- String[]supported;
- ArrayList enabled = new ArrayList ();
-
- supported = sock.getSupportedCipherSuites ();
-
- for (int i = 0; i < supported.length; i++)
- if (!supported[i].matches (".*DH_anon.*"))
- enabled.add (supported[i]);
-
- sock.setEnabledCipherSuites ((String[])enabled.toArray (new String[0]));
- }
-
- protected void initContext (SSLContext sc) throws java.security.
- GeneralSecurityException
- {
- TrustManager[] myTM = new TrustManager[]
- {
- new MyX509TrustManager ()};
- sc.init (null, myTM, null);
- }
-
-
- class MyX509TrustManager implements X509TrustManager
- {
-
- X509TrustManager tm;
-
- MyX509TrustManager () throws java.security.GeneralSecurityException
- {
- TrustManagerFactory tmf =
- TrustManagerFactory.getInstance ("SunX509", "SunJSSE");
- KeyStore ks = KeyStore.getInstance ("JKS");
- tmf.init (ks);
- tm = (X509TrustManager) tmf.getTrustManagers ()[0];
- }
- public void checkClientTrusted (X509Certificate[]chain,
- String authType) throws
- CertificateException
- {
- tm.checkClientTrusted (chain, authType);
- }
-
- public void checkServerTrusted (X509Certificate[]chain,
- String authType)
- throws CertificateException
- {
- try
- {
- tm.checkServerTrusted (chain, authType);
- } catch (CertificateException e)
- {
- MessageBox m =
- new MessageBox (e.toString (), MessageBox.MB_OKAYCANCEL);
- if (!m.result ())
- throw e;
- }
- }
-
- public X509Certificate[] getAcceptedIssuers ()
- {
- return tm.getAcceptedIssuers ();
- }
- }
-}
diff --git a/java/src/com/tigervnc/vncviewer/tigervnc.ico b/java/src/com/tigervnc/vncviewer/tigervnc.ico
new file mode 100644
index 00000000..50b90f00
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/tigervnc.ico
Binary files differ
diff --git a/java/src/com/tigervnc/vncviewer/tigervnc.png b/java/src/com/tigervnc/vncviewer/tigervnc.png
new file mode 100644
index 00000000..8ac883ef
--- /dev/null
+++ b/java/src/com/tigervnc/vncviewer/tigervnc.png
Binary files differ