]> source.dussan.org Git - tigervnc.git/commitdiff
Method cleanup.
authorBrian P. Hinz <bphinz@users.sf.net>
Sun, 11 Dec 2016 00:14:55 +0000 (19:14 -0500)
committerBrian P. Hinz <bphinz@users.sf.net>
Sun, 11 Dec 2016 00:14:55 +0000 (19:14 -0500)
Sync various methods and filenames with C++ versions

java/com/tigervnc/rdr/InStream.java
java/com/tigervnc/rdr/ZlibInStream.java
java/com/tigervnc/rfb/CConnection.java
java/com/tigervnc/rfb/CMsgHandler.java
java/com/tigervnc/rfb/CMsgReader.java
java/com/tigervnc/rfb/CMsgWriter.java
java/com/tigervnc/rfb/ConnParams.java
java/com/tigervnc/rfb/ScreenSet.java

index f713d7383a6b1f45a86932e693b426eb3b27f338..0906d326e812799321a3a60add48676ba7882e11 100644 (file)
@@ -159,20 +159,6 @@ abstract public class InStream {
     }
   }
 
-  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();
index 103bb646ae893cfe5bbcbd72d40ca41a5e031330..151633ecca87bac53c41e4718451be88c663f69c 100644 (file)
@@ -62,6 +62,18 @@ public class ZlibInStream extends InStream {
     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;
index 483d1f8434d57fccb25b18ccfda869447ef1f738..0b38aeaf3508d1fd5a2245de17c6f3341b12531d 100644 (file)
 
 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.*;
@@ -28,21 +32,86 @@ abstract public class CConnection extends CMsgHandler {
 
   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
@@ -75,11 +144,12 @@ abstract public class CConnection extends CMsgHandler {
   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);
@@ -241,52 +311,30 @@ abstract public class CConnection extends CMsgHandler {
 
   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.
@@ -299,11 +347,20 @@ abstract public class CConnection extends CMsgHandler {
 
   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().
@@ -313,34 +370,17 @@ abstract public class CConnection extends CMsgHandler {
     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;
@@ -353,7 +393,17 @@ abstract public class CConnection extends CMsgHandler {
 
   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)
   {
@@ -383,20 +433,27 @@ abstract public class CConnection extends CMsgHandler {
     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");
index dd9767e12238f0b15f27bd2e8f1c7400acd887f8..99405983b0bcce19bd5610f30b429fe27d84a41b 100644 (file)
@@ -78,25 +78,18 @@ abstract public class CMsgHandler {
                              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");
index a93324cad4f09654838e35c51b47e26ba055adc8..e7b4deb80c242a07a1718affa17fa85968c461d1 100644 (file)
@@ -28,7 +28,7 @@ import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import com.tigervnc.rdr.*;
 
-abstract public class CMsgReader {
+public class CMsgReader {
 
   protected CMsgReader(CMsgHandler handler_, InStream is_)
   {
@@ -37,7 +37,82 @@ abstract public class CMsgReader {
     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()
@@ -72,6 +147,43 @@ abstract public class CMsgReader {
     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();
@@ -81,6 +193,7 @@ abstract public class CMsgReader {
   {
     handler.framebufferUpdateEnd();
   }
+  */
 
   protected void readRect(Rect r, int encoding)
   {
@@ -94,43 +207,56 @@ abstract public class CMsgReader {
     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); }
@@ -154,23 +280,13 @@ abstract public class CMsgReader {
     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;
 
index 0d3dccf9facf40aab645694dd39bd1ee53e398de..bdf50c28f18389420c887da2ccc614b029af7f56 100644 (file)
 
 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)
   {
@@ -53,6 +63,7 @@ abstract public class CMsgWriter {
   {
     int nEncodings = 0;
     int[] encodings = new int[Encodings.encodingMax+3];
+
     if (cp.supportsLocalCursor)
       encodings[nEncodings++] = Encodings.pseudoEncodingCursor;
     if (cp.supportsDesktopResize)
@@ -68,7 +79,6 @@ abstract public class CMsgWriter {
     encodings[nEncodings++] = Encodings.pseudoEncodingContinuousUpdates;
     encodings[nEncodings++] = Encodings.pseudoEncodingFence;
 
-
     if (Decoder.supported(preferredEncoding)) {
       encodings[nEncodings++] = preferredEncoding;
     }
@@ -98,9 +108,11 @@ abstract public class CMsgWriter {
     // 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))
@@ -108,15 +120,44 @@ abstract public class CMsgWriter {
       }
     }
 
-    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);
@@ -128,6 +169,44 @@ abstract public class CMsgWriter {
     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);
@@ -163,17 +242,14 @@ abstract public class CMsgWriter {
     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");
 }
index f1f53958068250c9227d57acd91d7b48e0e6727a..fe52770fcfb3e08d4bb1c501252621f7dd7d52e0 100644 (file)
@@ -1,6 +1,6 @@
 /* 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;
@@ -34,19 +44,17 @@ public class ConnParams {
     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) {
@@ -54,10 +62,10 @@ public class ConnParams {
     }
 
     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")) {
@@ -68,7 +76,8 @@ public class ConnParams {
     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();
@@ -97,10 +106,11 @@ public class ConnParams {
 
   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_; }
@@ -109,80 +119,96 @@ public class ConnParams {
     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;
@@ -190,25 +216,22 @@ public class ConnParams {
   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;
 }
index a14f561d1af9d08ffba85bc020718e844d546a4b..173dd101f4a7bb960d89d84c5723b0b43860fc04 100644 (file)
@@ -31,13 +31,18 @@ public class ScreenSet {
     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();
     }
   }
@@ -68,9 +73,10 @@ public class ScreenSet {
   }
 
   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+")");