}
}
- 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();
ptr = end = start;
}
+ public void removeUnderlying()
+ {
+ ptr = end = start;
+ if (underlying == null) return;
+
+ while (bytesIn > 0) {
+ decompress(true);
+ end = start; // throw away any data
+ }
+ underlying = null;
+ }
+
public int pos()
{
return offset + ptr - start;
package com.tigervnc.rfb;
+import java.awt.color.*;
+import java.awt.image.*;
+import java.nio.*;
import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
import com.tigervnc.network.*;
import com.tigervnc.rdr.*;
public CConnection()
{
- csecurity = null; is = null; os = null; reader_ = null;
- writer_ = null; shared = false;
+ super();
+ csecurity = null; is = null; os = null; reader_ = null; writer_ = null;
+ shared = false;
state_ = RFBSTATE_UNINITIALISED; useProtocol3_3 = false;
+ framebuffer = null; decoder = new DecodeManager(this);
security = new SecurityClient();
}
- // deleteReaderAndWriter() deletes the reader and writer associated with
- // this connection. This may be useful if you want to delete the streams
- // before deleting the SConnection to make sure that no attempt by the
- // SConnection is made to read or write.
- // XXX Do we really need this at all???
- public void deleteReaderAndWriter()
+ // 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 final void setServerName(String name) {
+ serverName = name;
+ }
+
+ // setShared sets the value of the shared flag which will be sent to the
+ // server upon initialisation.
+ public final void setShared(boolean s) { shared = s; }
+
+ // setProtocol3_3 configures whether or not the CConnection should
+ // only ever support protocol version 3.3
+ public final void setProtocol3_3(boolean s) { useProtocol3_3 = s; }
+
+ // 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 final void setStreams(InStream is_, OutStream os_)
+ {
+ is = is_;
+ os = os_;
+ }
+
+ // setFramebuffer configures the PixelBuffer that the CConnection
+ // should render all pixel data in to. Note that the CConnection
+ // takes ownership of the PixelBuffer and it must not be deleted by
+ // anyone else. Call setFramebuffer again with NULL or a different
+ // PixelBuffer to delete the previous one.
+ public void setFramebuffer(ModifiablePixelBuffer fb)
{
- reader_ = null;
- writer_ = null;
+ decoder.flush();
+
+ if ((framebuffer != null) && (fb != null)) {
+ Rect rect = new Rect();
+
+ Raster data;
+
+ byte[] black = new byte[4];
+
+ // Copy still valid area
+
+ rect.setXYWH(0, 0,
+ Math.min(fb.width(), framebuffer.width()),
+ Math.min(fb.height(), framebuffer.height()));
+ data = framebuffer.getBuffer(rect);
+ fb.imageRect(framebuffer.getPF(), rect, data);
+
+ // Black out any new areas
+
+ if (fb.width() > framebuffer.width()) {
+ rect.setXYWH(framebuffer.width(), 0,
+ fb.width() - framebuffer.width(),
+ fb.height());
+ fb.fillRect(rect, black);
+ }
+
+ if (fb.height() > framebuffer.height()) {
+ rect.setXYWH(0, framebuffer.height(),
+ fb.width(),
+ fb.height() - framebuffer.height());
+ fb.fillRect(rect, black);
+ }
+ }
+
+ framebuffer = fb;
}
// initialiseProtocol() should be called once the streams and security
private void processVersionMsg()
{
vlog.debug("reading protocol version");
- if (!cp.readVersion(is)) {
+ AtomicBoolean done = new AtomicBoolean();
+ if (!cp.readVersion(is, done)) {
state_ = RFBSTATE_INVALID;
throw new Exception("reading version failed: not an RFB server?");
}
- if (!cp.done) return;
+ if (!done.get()) return;
vlog.info("Server supports RFB protocol version "
+cp.majorVersion+"."+ cp.minorVersion);
private void securityCompleted() {
state_ = RFBSTATE_INITIALISATION;
- reader_ = new CMsgReaderV3(this, is);
- writer_ = new CMsgWriterV3(cp, os);
+ reader_ = new CMsgReader(this, is);
+ writer_ = new CMsgWriter(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 final void setServerName(String name) {
- serverName = name;
- }
-
- // 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 final void setStreams(InStream is_, OutStream os_)
- {
- is = is_;
- os = os_;
- }
+ // Methods to be overridden in a derived class
- // setShared sets the value of the shared flag which will be sent to the
- // server upon initialisation.
- public final void setShared(boolean s) { shared = s; }
+ // Note: These must be called by any deriving classes
- // setProtocol3_3 configures whether or not the CConnection should
- // only ever support protocol version 3.3
- public final void setProtocol3_3(boolean s) { useProtocol3_3 = s; }
+ public void setDesktopSize(int w, int h) {
+ decoder.flush();
- public void setServerPort(int port) {
- serverPort = port;
+ super.setDesktopSize(w,h);
}
- public void initSecTypes() {
- nSecTypes = 0;
- }
+ public void setExtendedDesktopSize(int reason,
+ int result, int w, int h,
+ ScreenSet layout) {
+ decoder.flush();
- // Methods to be overridden in a derived class
+ super.setExtendedDesktopSize(reason, result, w, h, layout);
+ }
// getIdVerifier() returns the identity verifier associated with the connection.
// Ownership of the IdentityVerifier is retained by the CConnection instance.
public void framebufferUpdateEnd()
{
+ decoder.flush();
+
super.framebufferUpdateEnd();
}
+ public void dataRect(Rect r, int encoding)
+ {
+ decoder.decodeRect(r, encoding, framebuffer);
+ }
+
// authSuccess() is called when authentication has succeeded.
- public void authSuccess() {}
+ public void authSuccess()
+ {
+ }
// serverInit() is called when the ServerInit message is received. The
// derived class must call on to CConnection::serverInit().
vlog.debug("initialisation done");
}
- // 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;
- }
-
// Other methods
- public CMsgReaderV3 reader() { return reader_; }
- public CMsgWriterV3 writer() { return writer_; }
+ public CMsgReader reader() { return reader_; }
+ public CMsgWriter writer() { return writer_; }
public InStream getInStream() { return is; }
public OutStream getOutStream() { return os; }
+ // Access method used by SSecurity implementations that can verify servers'
+ // Identities, to determine the unique(ish) name of the server.
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 int state() { return state_; }
- protected final void setState(int s) { state_ = s; }
+ public int getServerPort() { return serverPort; }
+ public void setServerPort(int port) {
+ serverPort = port;
+ }
+
+ protected void setState(int s) { state_ = s; }
+
+ protected void setReader(CMsgReader r) { reader_ = r; }
+ protected void setWriter(CMsgWriter w) { writer_ = w; }
+
+ protected ModifiablePixelBuffer getFramebuffer() { return framebuffer; }
public void fence(int flags, int len, byte[] data)
{
throw new AuthFailureException(reason);
}
- InStream is;
- OutStream os;
- CMsgReaderV3 reader_;
- CMsgWriterV3 writer_;
- boolean shared;
+ private InStream is;
+ private OutStream os;
+ private CMsgReader reader_;
+ private CMsgWriter writer_;
+ private boolean deleteStreamsWhenDone;
+ private boolean shared;
+ private int state_ = RFBSTATE_UNINITIALISED;
+
+ private String serverName;
+
+ private boolean useProtocol3_3;
+
+ protected ModifiablePixelBuffer framebuffer;
+ private DecodeManager decoder;
+
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;
boolean clientSecTypeOrder;
static LogWriter vlog = new LogWriter("CConnection");
String x509subject) {}
public void setCursor(int width, int height, Point hotspot,
- int[] data, byte[] mask) {}
+ byte[] 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 dataRect(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, Object pixels) {}
- public void copyRect(Rect r, int srcX, int srcY) {}
-
- abstract public PixelFormat getPreferredPF();
-
public ConnParams cp;
static LogWriter vlog = new LogWriter("CMsgHandler");
import java.nio.charset.Charset;
import com.tigervnc.rdr.*;
-abstract public class CMsgReader {
+public class CMsgReader {
protected CMsgReader(CMsgHandler handler_, InStream is_)
{
is = is_;
imageBuf = null;
imageBufSize = 0;
- decoders = new Decoder[Encodings.encodingMax+1];
+ 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.msgTypeSetColourMapEntries:
+ readSetColourMapEntries();
+ break;
+ case MsgTypes.msgTypeBell:
+ readBell();
+ break;
+ case MsgTypes.msgTypeServerCutText:
+ readServerCutText();
+ break;
+ case MsgTypes.msgTypeFramebufferUpdate:
+ readFramebufferUpdate();
+ break;
+ case MsgTypes.msgTypeServerFence:
+ readFence();
+ break;
+ case MsgTypes.msgTypeEndOfContinuousUpdates:
+ readEndOfContinuousUpdates();
+ break;
+ default:
+ //fprintf(stderr, "unknown message type %d\n", 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.readS32();
+
+ switch (encoding) {
+ case Encodings.pseudoEncodingLastRect:
+ nUpdateRectsLeft = 1; // this rectangle is the last one
+ break;
+ case Encodings.pseudoEncodingCursor:
+ readSetCursor(w, h, new Point(x,y));
+ break;
+ case Encodings.pseudoEncodingDesktopName:
+ readSetDesktopName(x, y, w, h);
+ break;
+ case Encodings.pseudoEncodingDesktopSize:
+ handler.setDesktopSize(w, h);
+ break;
+ case Encodings.pseudoEncodingExtendedDesktopSize:
+ readExtendedDesktopSize(x, y, w, h);
+ break;
+ default:
+ readRect(new Rect(x, y, x+w, y+h), encoding);
+ break;
+ };
+
+ nUpdateRectsLeft--;
+ if (nUpdateRectsLeft == 0)
+ handler.framebufferUpdateEnd();
+ }
}
protected void readSetColourMapEntries()
handler.serverCutText(chars.toString(), len);
}
+ protected void readFence()
+ {
+ int flags;
+ int len;
+ byte[] data = new byte[64];
+
+ is.skip(3);
+
+ flags = is.readU32();
+
+ len = is.readU8();
+ if (len > data.length) {
+ System.out.println("Ignoring fence with too large payload\n");
+ is.skip(len);
+ return;
+ }
+
+ is.readBytes(data, 0, len);
+
+ handler.fence(flags, len, data);
+ }
+
+ protected void readEndOfContinuousUpdates()
+ {
+ handler.endOfContinuousUpdates();
+ }
+
+ protected void readFramebufferUpdate()
+ {
+ is.skip(1);
+ nUpdateRectsLeft = is.readU16();
+ handler.framebufferUpdateStart();
+ }
+
+
+
+ /*
protected void readFramebufferUpdateStart()
{
handler.framebufferUpdateStart();
{
handler.framebufferUpdateEnd();
}
+ */
protected void readRect(Rect r, int encoding)
{
if (r.is_empty())
vlog.error("Ignoring zero size rect");
- handler.beginRect(r, encoding);
+ handler.dataRect(r, encoding);
+ }
- if (encoding == Encodings.encodingCopyRect) {
- readCopyRect(r);
- } else {
+ protected void readSetCursor(int width, int height, Point hotspot)
+ {
+ int data_len = width * height * (handler.cp.pf().bpp/8);
+ int mask_len = ((width+7)/8) * height;
+ byte[] data = new byte[data_len];
+ byte[] mask = new byte[mask_len];
- 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);
- }
+ is.readBytes(data, 0, data_len);
+ is.readBytes(mask, 0, mask_len);
- handler.endRect(r, encoding);
+ handler.setCursor(width, height, hotspot, data, mask);
}
- protected void readCopyRect(Rect r)
+ protected void readSetDesktopName(int x, int y, int w, int h)
{
- int srcX = is.readU16();
- int srcY = is.readU16();
- handler.copyRect(r, srcX, srcY);
+ 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);
+ }
+
}
- protected void readSetCursor(int width, int height, Point hotspot)
+ protected void readExtendedDesktopSize(int x, int y, int w, int h)
{
- int data_len = width * height;
- int mask_len = ((width+7)/8) * height;
- int[] data = new int[data_len];
- byte[] mask = new byte[mask_len];
+ int screens, i;
+ int id, flags;
+ int sx, sy, sw, sh;
+ ScreenSet layout = new ScreenSet();
- is.readPixels(data, data_len, (handler.cp.pf().bpp/8), handler.cp.pf().bigEndian);
- is.readBytes(mask, 0, mask_len);
+ screens = is.readU8();
+ is.skip(3);
- handler.setCursor(width, height, hotspot, data, mask);
+ 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);
}
public int[] getImageBuf(int required) { return getImageBuf(required, 0, 0); }
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 nUpdateRectsLeft;
protected int[] imageBuf;
protected int imageBufSize;
package com.tigervnc.rfb;
+import com.tigervnc.rdr.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
-import com.tigervnc.rdr.*;
+import java.util.Iterator;
-abstract public class CMsgWriter {
+public class CMsgWriter {
- abstract public void writeClientInit(boolean shared);
+ protected CMsgWriter(ConnParams cp_, OutStream os_)
+ {
+ cp = cp_;
+ os = os_;
+ }
+
+ synchronized public void writeClientInit(boolean shared) {
+ os.writeU8(shared?1:0);
+ endMsg();
+ }
synchronized public void writeSetPixelFormat(PixelFormat pf)
{
{
int nEncodings = 0;
int[] encodings = new int[Encodings.encodingMax+3];
+
if (cp.supportsLocalCursor)
encodings[nEncodings++] = Encodings.pseudoEncodingCursor;
if (cp.supportsDesktopResize)
encodings[nEncodings++] = Encodings.pseudoEncodingContinuousUpdates;
encodings[nEncodings++] = Encodings.pseudoEncodingFence;
-
if (Decoder.supported(preferredEncoding)) {
encodings[nEncodings++] = preferredEncoding;
}
// Remaining encodings
for (int i = Encodings.encodingMax; i >= 0; i--) {
switch (i) {
+ case Encodings.encodingCopyRect:
case Encodings.encodingTight:
case Encodings.encodingZRLE:
case Encodings.encodingHextile:
+ /* These have already been sent earlier */
break;
default:
if ((i != preferredEncoding) && Decoder.supported(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;
+ if (cp.compressLevel >= 0 && cp.compressLevel <= 9)
+ encodings[nEncodings++] =
+ Encodings.pseudoEncodingCompressLevel0 + cp.compressLevel;
+ if (cp.qualityLevel >= 0 && cp.qualityLevel <= 9)
+ encodings[nEncodings++] =
+ Encodings.pseudoEncodingQualityLevel0 + cp.qualityLevel;
writeSetEncodings(nEncodings, encodings);
}
+ synchronized public void writeSetDesktopSize(int width, int height,
+ ScreenSet layout)
+ {
+ if (!cp.supportsSetDesktopSize)
+ throw new Exception("Server does not support SetDesktopSize");
+
+ startMsg(MsgTypes.msgTypeSetDesktopSize);
+ os.pad(1);
+
+ os.writeU16(width);
+ os.writeU16(height);
+
+ os.writeU8(layout.num_screens());
+ os.pad(1);
+
+ for (Iterator<Screen> iter = layout.screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ os.writeU32(refScreen.id);
+ os.writeU16(refScreen.dimensions.tl.x);
+ os.writeU16(refScreen.dimensions.tl.y);
+ os.writeU16(refScreen.dimensions.width());
+ os.writeU16(refScreen.dimensions.height());
+ os.writeU32(refScreen.flags);
+ }
+
+ endMsg();
+ }
+
synchronized public void writeFramebufferUpdateRequest(Rect r, boolean incremental)
{
startMsg(MsgTypes.msgTypeFramebufferUpdateRequest);
endMsg();
}
+ synchronized public void writeEnableContinuousUpdates(boolean enable,
+ int x, int y, int w, int h)
+ {
+ if (!cp.supportsContinuousUpdates)
+ throw new Exception("Server does not support continuous updates");
+
+ startMsg(MsgTypes.msgTypeEnableContinuousUpdates);
+
+ os.writeU8((enable?1:0));
+
+ os.writeU16(x);
+ os.writeU16(y);
+ os.writeU16(w);
+ os.writeU16(h);
+
+ endMsg();
+ }
+
+ synchronized public void writeFence(int flags, int len, byte[] data)
+ {
+ if (!cp.supportsFence)
+ throw new Exception("Server does not support fences");
+ if (len > 64)
+ throw new Exception("Too large fence payload");
+ if ((flags & ~fenceTypes.fenceFlagsSupported) != 0)
+ throw new Exception("Unknown fence flags");
+
+ startMsg(MsgTypes.msgTypeClientFence);
+ os.pad(3);
+
+ os.writeU32(flags);
+
+ os.writeU8(len);
+ os.writeBytes(data, 0, len);
+
+ endMsg();
+ }
+
synchronized public void writeKeyEvent(int key, boolean down)
{
startMsg(MsgTypes.msgTypeKeyEvent);
endMsg();
}
- abstract public void startMsg(int type);
- abstract public void endMsg();
-
- synchronized public void setOutStream(OutStream os_) { os = os_; }
-
- ConnParams getConnParams() { return cp; }
- OutStream getOutStream() { return os; }
+ synchronized public void startMsg(int type) {
+ os.writeU8(type);
+ }
- protected CMsgWriter(ConnParams cp_, OutStream os_) {cp = cp_; os = os_;}
+ synchronized public void endMsg() {
+ os.flush();
+ }
ConnParams cp;
OutStream os;
- static LogWriter vlog = new LogWriter("CMsgWriter");
}
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2011 D. R. Commander. All Rights Reserved.
- * Copyright (C) 2012 Brian P. Hinz
+ * Copyright (C) 2012-2016 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
package com.tigervnc.rfb;
import com.tigervnc.rdr.*;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
public class ConnParams {
- static LogWriter vlog = new LogWriter("ConnParams");
- public ConnParams() {
+ private static final int subsampleUndefined = -1;
+ private static final int subsampleNone = 0;
+ private static final int subsampleGray = 1;
+ private static final int subsample2X = 2;
+ private static final int subsample4X = 3;
+ private static final int subsample8X = 4;
+ private static final int subsample16X = 5;
+
+ public ConnParams()
+ {
majorVersion = 0; minorVersion = 0;
width = 0; height = 0; useCopyRect = false;
supportsLocalCursor = false; supportsLocalXCursor = false;
supportsSetDesktopSize = false; supportsFence = false;
supportsContinuousUpdates = false;
supportsClientRedirect = false;
- customCompressLevel = false; compressLevel = 6;
- noJpeg = false; qualityLevel = -1; fineQualityLevel = -1;
- subsampling = "SUBSAMP_UNDEFINED";
- name_ = null; nEncodings_ = 0; encodings_ = null;
- currentEncoding_ = Encodings.encodingRaw; verStrPos = 0;
+ compressLevel = 6; qualityLevel = -1; fineQualityLevel = -1;
+ subsampling = subsampleUndefined; name_ = null; verStrPos = 0;
+
+ encodings_ = new ArrayList();
screenLayout = new ScreenSet();
setName("");
}
- public boolean readVersion(InStream is)
+ public boolean readVersion(InStream is, AtomicBoolean done)
{
- done = false;
if (verStrPos >= 12) return false;
verStr = new StringBuilder(13);
while (is.checkNoWait(1) && verStrPos < 12) {
}
if (verStrPos < 12) {
- done = false;
+ done.set(false);
return true;
}
- done = true;
+ done.set(true);
verStr.insert(12,'0');
verStrPos = 0;
if (verStr.toString().matches("RFB \\d{3}\\.\\d{3}\\n0")) {
return false;
}
- public void writeVersion(OutStream os) {
+ public void writeVersion(OutStream os)
+ {
String str = String.format("RFB %03d.%03d\n", majorVersion, minorVersion);
os.writeBytes(str.getBytes(), 0, 12);
os.flush();
public PixelFormat pf() { return pf_; }
public void setPF(PixelFormat pf) {
+
pf_ = pf;
- if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) {
+
+ 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_; }
name_ = name;
}
- public int currentEncoding() { return currentEncoding_; }
- public int nEncodings() { return nEncodings_; }
- public int[] encodings() { return encodings_; }
+ public boolean supportsEncoding(int encoding)
+ {
+ return encodings_.indexOf(encoding) != -1;
+ }
+
public void setEncodings(int nEncodings, int[] encodings)
{
- if (nEncodings > nEncodings_) {
- encodings_ = new int[nEncodings];
- }
- nEncodings_ = nEncodings;
useCopyRect = false;
supportsLocalCursor = false;
supportsDesktopResize = false;
supportsExtendedDesktopSize = false;
supportsLocalXCursor = false;
supportsLastRect = false;
- customCompressLevel = false;
compressLevel = -1;
- noJpeg = true;
qualityLevel = -1;
fineQualityLevel = -1;
- subsampling = "SUBSAMP_UNDEFINED";
- currentEncoding_ = Encodings.encodingRaw;
+ subsampling = subsampleUndefined;
- for (int i = nEncodings-1; i >= 0; i--) {
- encodings_[i] = encodings[i];
+ encodings_.clear();
+ encodings_.add(Encodings.encodingRaw);
- if (encodings[i] == Encodings.encodingCopyRect)
+ for (int i = nEncodings-1; i >= 0; i--) {
+ switch (encodings[i]) {
+ case Encodings.encodingCopyRect:
useCopyRect = true;
- else if (encodings[i] == Encodings.pseudoEncodingCursor)
+ break;
+ case Encodings.pseudoEncodingCursor:
supportsLocalCursor = true;
- else if (encodings[i] == Encodings.pseudoEncodingXCursor)
+ break;
+ case Encodings.pseudoEncodingXCursor:
supportsLocalXCursor = true;
- else if (encodings[i] == Encodings.pseudoEncodingDesktopSize)
+ break;
+ case Encodings.pseudoEncodingDesktopSize:
supportsDesktopResize = true;
- else if (encodings[i] == Encodings.pseudoEncodingExtendedDesktopSize)
+ break;
+ case Encodings.pseudoEncodingExtendedDesktopSize:
supportsExtendedDesktopSize = true;
- else if (encodings[i] == Encodings.pseudoEncodingDesktopName)
+ break;
+ case Encodings.pseudoEncodingDesktopName:
supportsDesktopRename = true;
- else if (encodings[i] == Encodings.pseudoEncodingLastRect)
+ break;
+ case Encodings.pseudoEncodingLastRect:
supportsLastRect = true;
- else if (encodings[i] == Encodings.pseudoEncodingFence)
+ break;
+ case Encodings.pseudoEncodingFence:
supportsFence = true;
- else if (encodings[i] == Encodings.pseudoEncodingContinuousUpdates)
+ break;
+ case Encodings.pseudoEncodingContinuousUpdates:
supportsContinuousUpdates = true;
- else if (encodings[i] == Encodings.pseudoEncodingClientRedirect)
+ break;
+ case Encodings.pseudoEncodingClientRedirect:
supportsClientRedirect = true;
- else if (encodings[i] >= Encodings.pseudoEncodingCompressLevel0 &&
- encodings[i] <= Encodings.pseudoEncodingCompressLevel9) {
- customCompressLevel = true;
+ break;
+ case Encodings.pseudoEncodingSubsamp1X:
+ subsampling = subsampleNone;
+ break;
+ case Encodings.pseudoEncodingSubsampGray:
+ subsampling = subsampleGray;
+ break;
+ case Encodings.pseudoEncodingSubsamp2X:
+ subsampling = subsample2X;
+ break;
+ case Encodings.pseudoEncodingSubsamp4X:
+ subsampling = subsample4X;
+ break;
+ case Encodings.pseudoEncodingSubsamp8X:
+ subsampling = subsample8X;
+ break;
+ case Encodings.pseudoEncodingSubsamp16X:
+ subsampling = subsample16X;
+ break;
+ }
+
+ if (encodings[i] >= Encodings.pseudoEncodingCompressLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingCompressLevel9)
compressLevel = encodings[i] - Encodings.pseudoEncodingCompressLevel0;
- } else if (encodings[i] >= Encodings.pseudoEncodingQualityLevel0 &&
- encodings[i] <= Encodings.pseudoEncodingQualityLevel9) {
- noJpeg = false;
+
+ if (encodings[i] >= Encodings.pseudoEncodingQualityLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingQualityLevel9)
qualityLevel = encodings[i] - Encodings.pseudoEncodingQualityLevel0;
- } else if (encodings[i] <= Encodings.encodingMax &&
- Encoder.supported(encodings[i]))
- currentEncoding_ = encodings[i];
- }
- // If the TurboVNC fine quality/subsampling encodings exist, let them
- // override the coarse TightVNC quality level
- for (int i = nEncodings-1; i >= 0; i--) {
- if (encodings[i] >= Encodings.pseudoEncodingFineQualityLevel0 + 1 &&
- encodings[i] <= Encodings.pseudoEncodingFineQualityLevel100) {
- noJpeg = false;
+ if (encodings[i] >= Encodings.pseudoEncodingFineQualityLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingFineQualityLevel100)
fineQualityLevel = encodings[i] - Encodings.pseudoEncodingFineQualityLevel0;
- } else if (encodings[i] >= Encodings.pseudoEncodingSubsamp1X &&
- encodings[i] <= Encodings.pseudoEncodingSubsampGray) {
- noJpeg = false;
- subsampling = JpegCompressor.subsamplingName(encodings[i] - Encodings.pseudoEncodingSubsamp1X);
- }
+
+ if (encodings[i] > 0)
+ encodings_.add(encodings[i]);
}
}
- public boolean done;
+
public boolean useCopyRect;
public boolean supportsLocalCursor;
public boolean supportsDesktopResize;
public boolean supportsExtendedDesktopSize;
public boolean supportsDesktopRename;
- public boolean supportsClientRedirect;
- public boolean supportsFence;
- public boolean supportsContinuousUpdates;
public boolean supportsLastRect;
+ public boolean supportsClientRedirect;
public boolean supportsSetDesktopSize;
+ public boolean supportsFence;
+ public boolean supportsContinuousUpdates;
- public boolean customCompressLevel;
public int compressLevel;
- public boolean noJpeg;
public int qualityLevel;
public int fineQualityLevel;
- public String subsampling;
+ public int subsampling;
private PixelFormat pf_;
private String name_;
- private int nEncodings_;
- private int[] encodings_;
- private int currentEncoding_;
+ private Cursor cursor_;
+ private ArrayList encodings_;
private StringBuilder verStr;
private int verStrPos;
}
screens = new ArrayList<Screen>();
}
+ public final ListIterator<Screen> begin() { return screens.listIterator(0); }
+ public final ListIterator<Screen> end() {
+ return screens.listIterator(screens.size());
+ }
public final int num_screens() { return screens.size(); }
public final void add_screen(Screen screen) { screens.add(screen); }
public final void remove_screen(int id) {
- for (Iterator<Screen> iter = screens.iterator(); iter.hasNext(); ) {
- Screen refScreen = (Screen)iter.next();
- if (refScreen.id == id)
+ ListIterator iter, nextiter;
+ for (iter = begin(); iter != end(); iter = nextiter) {
+ nextiter = iter; nextiter.next();
+ if (((Screen)iter.next()).id == id)
iter.remove();
}
}
}
public final void debug_print() {
+ vlog.debug(num_screens()+" screen(s)");
for (Iterator<Screen> iter = screens.iterator(); iter.hasNext(); ) {
Screen refScreen = (Screen)iter.next();
- vlog.error(" "+refScreen.id+" (0x"+refScreen.id+"): "+
+ vlog.debug(" "+refScreen.id+" (0x"+refScreen.id+"): "+
refScreen.dimensions.width()+"x"+refScreen.dimensions.height()+
"+"+refScreen.dimensions.tl.x+"+"+refScreen.dimensions.tl.y+
" (flags 0x"+refScreen.flags+")");