]> source.dussan.org Git - tigervnc.git/commitdiff
RFB refactoring to sync with native client
authorBrian P. Hinz <bphinz@users.sf.net>
Fri, 22 Nov 2019 01:00:49 +0000 (20:00 -0500)
committerBrian P. Hinz <bphinz@users.sf.net>
Fri, 22 Nov 2019 01:04:10 +0000 (20:04 -0500)
21 files changed:
java/com/tigervnc/rfb/AuthFailureException.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/ConnFailedException.java
java/com/tigervnc/rfb/ConnParams.java [deleted file]
java/com/tigervnc/rfb/CopyRectDecoder.java
java/com/tigervnc/rfb/DecodeManager.java
java/com/tigervnc/rfb/Decoder.java
java/com/tigervnc/rfb/HextileDecoder.java
java/com/tigervnc/rfb/RREDecoder.java
java/com/tigervnc/rfb/RawDecoder.java
java/com/tigervnc/rfb/ScreenSet.java
java/com/tigervnc/rfb/ServerParams.java [new file with mode: 0644]
java/com/tigervnc/rfb/TightDecoder.java
java/com/tigervnc/rfb/ZRLEDecoder.java
java/com/tigervnc/vncviewer/CConn.java
java/com/tigervnc/vncviewer/DesktopWindow.java
java/com/tigervnc/vncviewer/OptionsDialog.java
java/com/tigervnc/vncviewer/Viewport.java

index 542270cb8abf26f3aca3013383decfea86985c1e..39dcd78621be470e1f7f648a1ff57dda7fee535b 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2019 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
@@ -19,5 +20,8 @@
 package com.tigervnc.rfb;
 
 public class AuthFailureException extends Exception {
-  public AuthFailureException(String s) { super(s); }
+  public AuthFailureException() { super("Authentication failure"); }
+  public AuthFailureException(String reason) {
+    super("Authentication failure: "+reason);
+  }
 }
index 17c47521bebf7865ac5ca44bd47fbd89b2640572..aaa2f49041e9f63603daaa3a3320a509d95a23b7 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011-2012 Brian P. Hinz
+ * Copyright (C) 2011-2019 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
@@ -30,12 +30,24 @@ import com.tigervnc.rdr.*;
 
 abstract public class CConnection extends CMsgHandler {
 
+  static LogWriter vlog = new LogWriter("CConnection");
+
+  private static final String osName = 
+    System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
+
   public CConnection()
   {
     super();
-    csecurity = null; is = null; os = null; reader_ = null; writer_ = null;
+    csecurity = null;
+    supportsLocalCursor = false; supportsDesktopResize = false;
+    is = null; os = null; reader_ = null; writer_ = null;
     shared = false;
-    state_ = RFBSTATE_UNINITIALISED;
+    state_ = stateEnum.RFBSTATE_UNINITIALISED;
+    pendingPFChange = false; preferredEncoding = Encodings.encodingTight;
+    compressLevel = 2; qualityLevel = -1;
+    formatChange = false; encodingChange = false;
+    firstUpdate = true; pendingUpdate = false; continuousUpdates = false;
+    forceNonincremental = true;
     framebuffer = null; decoder = new DecodeManager(this);
     security = new SecurityClient();
   }
@@ -46,13 +58,9 @@ abstract public class CConnection extends CMsgHandler {
   // 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;
-  }
+  public 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; }
+  public void setServerPort(int port_) { serverPort = port_; }
 
   // setStreams() sets the streams to be used for the connection.  These must
   // be set before initialiseProtocol() and processMsg() are called.  The
@@ -66,6 +74,10 @@ abstract public class CConnection extends CMsgHandler {
     os = os_;
   }
 
+  // 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; }
+
   // 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
@@ -75,6 +87,11 @@ abstract public class CConnection extends CMsgHandler {
   {
     decoder.flush();
 
+    if (fb != null) {
+      assert(fb.width() == server.width());
+      assert(fb.height() == server.height());
+    }
+
     if ((framebuffer != null) && (fb != null)) {
       Rect rect = new Rect();
 
@@ -115,7 +132,7 @@ abstract public class CConnection extends CMsgHandler {
   // there is data to read on the InStream.
   public final void initialiseProtocol()
   {
-    state_ = RFBSTATE_PROTOCOL_VERSION;
+    state_ = stateEnum.RFBSTATE_PROTOCOL_VERSION;
   }
 
   // processMsg() should be called whenever there is data to read on the
@@ -139,35 +156,55 @@ abstract public class CConnection extends CMsgHandler {
 
   private void processVersionMsg()
   {
+    ByteBuffer verStr = ByteBuffer.allocate(12);
+    int majorVersion;
+    int minorVersion;
+
     vlog.debug("reading protocol version");
-    AtomicBoolean done = new AtomicBoolean();
-    if (!cp.readVersion(is, done)) {
-      state_ = RFBSTATE_INVALID;
+
+    if (!is.checkNoWait(12))
+      return;
+
+    is.readBytes(verStr, 12);
+
+    if ((new String(verStr.array())).matches("RFB \\d{3}\\.\\d{3}\\n")) {
+      majorVersion =
+        Integer.parseInt((new String(verStr.array())).substring(4,7));
+      minorVersion =
+        Integer.parseInt((new String(verStr.array())).substring(8,11));
+    } else {
+      state_ = stateEnum.RFBSTATE_INVALID;
       throw new Exception("reading version failed: not an RFB server?");
     }
-    if (!done.get()) return;
+
+    server.setVersion(majorVersion, minorVersion);
 
     vlog.info("Server supports RFB protocol version "
-              +cp.majorVersion+"."+ cp.minorVersion);
+              +server.majorVersion+"."+ server.minorVersion);
 
     // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
-    if (cp.beforeVersion(3,3)) {
+    if (server.beforeVersion(3,3)) {
       String msg = ("Server gave unsupported RFB protocol version "+
-                    cp.majorVersion+"."+cp.minorVersion);
+                    server.majorVersion+"."+server.minorVersion);
       vlog.error(msg);
-      state_ = RFBSTATE_INVALID;
+      state_ = stateEnum.RFBSTATE_INVALID;
       throw new Exception(msg);
-    } else if (cp.beforeVersion(3,7)) {
-      cp.setVersion(3,3);
-    } else if (cp.afterVersion(3,8)) {
-      cp.setVersion(3,8);
+    } else if (server.beforeVersion(3,7)) {
+      server.setVersion(3,3);
+    } else if (server.afterVersion(3,8)) {
+      server.setVersion(3,8);
     }
 
-    cp.writeVersion(os);
-    state_ = RFBSTATE_SECURITY_TYPES;
+    verStr.clear();
+    verStr.put(String.format("RFB %03d.%03d\n",
+               majorVersion, minorVersion).getBytes()).flip();
+    os.writeBytes(verStr.array(), 0, 12);
+    os.flush();
+
+    state_ = stateEnum.RFBSTATE_SECURITY_TYPES;
 
     vlog.info("Using RFB protocol version "+
-              cp.majorVersion+"."+cp.minorVersion);
+              server.majorVersion+"."+server.minorVersion);
   }
 
   private void processSecurityTypesMsg()
@@ -179,7 +216,7 @@ abstract public class CConnection extends CMsgHandler {
     List<Integer> secTypes = new ArrayList<Integer>();
     secTypes = security.GetEnabledSecTypes();
 
-    if (cp.isVersion(3,3)) {
+    if (server.isVersion(3,3)) {
 
       // legacy 3.3 server may only offer "vnc authentication" or "none"
 
@@ -244,12 +281,12 @@ abstract public class CConnection extends CMsgHandler {
     }
 
     if (secType == Security.secTypeInvalid) {
-      state_ = RFBSTATE_INVALID;
+      state_ = stateEnum.RFBSTATE_INVALID;
       vlog.error("No matching security types");
       throw new Exception("No matching security types");
     }
 
-    state_ = RFBSTATE_SECURITY;
+    state_ = stateEnum.RFBSTATE_SECURITY;
     csecurity = security.GetCSecurity(secType);
     processSecurityMsg();
   }
@@ -257,7 +294,7 @@ abstract public class CConnection extends CMsgHandler {
   private void processSecurityMsg() {
     vlog.debug("processing security message");
     if (csecurity.processMsg(this)) {
-      state_ = RFBSTATE_SECURITY_RESULT;
+      state_ = stateEnum.RFBSTATE_SECURITY_RESULT;
       processSecurityResultMsg();
     }
   }
@@ -265,7 +302,7 @@ abstract public class CConnection extends CMsgHandler {
   private void processSecurityResultMsg() {
     vlog.debug("processing security result message");
     int result;
-    if (cp.beforeVersion(3,8) && csecurity.getType() == Security.secTypeNone) {
+    if (server.beforeVersion(3,8) && csecurity.getType() == Security.secTypeNone) {
       result = Security.secResultOK;
     } else {
       if (!is.checkNoWait(1)) return;
@@ -284,12 +321,10 @@ abstract public class CConnection extends CMsgHandler {
     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;
+    state_ = stateEnum.RFBSTATE_INVALID;
+    if (server.beforeVersion(3,8))
+      throw new AuthFailureException();
+    String reason = is.readString();
     throw new AuthFailureException(reason);
   }
 
@@ -299,22 +334,22 @@ abstract public class CConnection extends CMsgHandler {
   }
 
   private void throwConnFailedException() {
-    state_ = RFBSTATE_INVALID;
+    state_ = stateEnum.RFBSTATE_INVALID;
     String reason;
     reason = is.readString();
     throw new ConnFailedException(reason);
   }
 
   private void securityCompleted() {
-    state_ = RFBSTATE_INITIALISATION;
+    state_ = stateEnum.RFBSTATE_INITIALISATION;
     reader_ = new CMsgReader(this, is);
-    writer_ = new CMsgWriter(cp, os);
+    writer_ = new CMsgWriter(server, os);
     vlog.debug("Authentication success!");
     authSuccess();
     writer_.writeClientInit(shared);
   }
 
-  // Methods to be overridden in a derived class
+  // Methods overridden from CMsgHandler
 
   // Note: These must be called by any deriving classes
 
@@ -322,14 +357,79 @@ abstract public class CConnection extends CMsgHandler {
     decoder.flush();
 
     super.setDesktopSize(w,h);
+
+    if (continuousUpdates)
+      writer().writeEnableContinuousUpdates(true, 0, 0,
+                                            server.width(),
+                                            server.height());
+
+    resizeFramebuffer();
+    assert(framebuffer != null);
+    assert(framebuffer.width() == server.width());
+    assert(framebuffer.height() == server.height());
   }
 
   public void setExtendedDesktopSize(int reason,
-                                     int result, int w, int h,
+                                     int result,
+                                     int w, int h,
                                      ScreenSet layout) {
     decoder.flush();
 
     super.setExtendedDesktopSize(reason, result, w, h, layout);
+
+    if (continuousUpdates)
+      writer().writeEnableContinuousUpdates(true, 0, 0,
+                                            server.width(),
+                                            server.height());
+
+    resizeFramebuffer();
+    assert(framebuffer != null);
+    assert(framebuffer.width() == server.width());
+    assert(framebuffer.height() == server.height());
+  }
+
+  public void endOfContinuousUpdates()
+  {
+    super.endOfContinuousUpdates();
+
+    // We've gotten the marker for a format change, so make the pending
+    // one active
+    if (pendingPFChange) {
+      server.setPF(pendingPF);
+      pendingPFChange = false;
+
+      // We might have another change pending
+      if (formatChange)
+        requestNewUpdate();
+    }
+  }
+  // serverInit() is called when the ServerInit message is received.  The
+  // derived class must call on to CConnection::serverInit().
+  public void serverInit(int width, int height,
+                         PixelFormat pf, String name)
+  {
+    super.serverInit(width, height, pf, name);
+    
+    state_ = stateEnum.RFBSTATE_NORMAL;
+    vlog.debug("initialisation done");
+
+    initDone();
+    assert(framebuffer != null);
+    // FIXME: even if the client is scaling?
+    assert(framebuffer.width() == server.width());
+    assert(framebuffer.height() == server.height());
+
+    // We want to make sure we call SetEncodings at least once
+    encodingChange = true;
+
+    requestNewUpdate();
+
+    // This initial update request is a bit of a corner case, so we need
+    // to help out setting the correct format here.
+    if (pendingPFChange) {
+      server.setPF(pendingPF);
+      pendingPFChange = false;
+    }
   }
 
   public void readAndDecodeRect(Rect r, int encoding,
@@ -339,13 +439,16 @@ abstract public class CConnection extends CMsgHandler {
     decoder.flush();
   }
 
-  // getIdVerifier() returns the identity verifier associated with the connection.
-  // Ownership of the IdentityVerifier is retained by the CConnection instance.
-  //public IdentityVerifier getIdentityVerifier() { return 0; }
-
   public void framebufferUpdateStart()
   {
     super.framebufferUpdateStart();
+
+    assert(framebuffer != null);
+
+    // Note: This might not be true if continuous updates are supported
+    pendingUpdate = false;
+
+    requestNewUpdate();
   }
 
   public void framebufferUpdateEnd()
@@ -353,6 +456,25 @@ abstract public class CConnection extends CMsgHandler {
     decoder.flush();
 
     super.framebufferUpdateEnd();
+
+    // A format change has been scheduled and we are now past the update
+    // with the old format. Time to active the new one.
+    if (pendingPFChange && !continuousUpdates) {
+      server.setPF(pendingPF);
+      pendingPFChange = false;
+    }
+
+    if (firstUpdate) {
+      if (server.supportsContinuousUpdates) {
+        vlog.info("Enabling continuous updates");
+        continuousUpdates = true;
+        writer().writeEnableContinuousUpdates(true, 0, 0,
+                                              server.width(),
+                                              server.height());
+      }
+
+      firstUpdate = false;
+    }
   }
 
   public void dataRect(Rect r, int encoding)
@@ -360,20 +482,87 @@ abstract public class CConnection extends CMsgHandler {
     decoder.decodeRect(r, encoding, framebuffer);
   }
 
+  // Methods to be overridden in a derived class
+
   // authSuccess() is called when authentication has succeeded.
-  public void authSuccess()
+  public void authSuccess() { }
+
+  // initDone() is called when the connection is fully established
+  // and standard messages can be sent. This is called before the
+  // initial FramebufferUpdateRequest giving a derived class the
+  // chance to modify pixel format and settings. The derived class
+  // must also make sure it has provided a valid framebuffer before
+  // returning.
+  public void initDone() { }
+
+  // resizeFramebuffer() is called whenever the framebuffer
+  // dimensions or the screen layout changes. A subclass must make
+  // sure the pixel buffer has been updated once this call returns.
+  public void resizeFramebuffer()
   {
+    assert(false);
   }
 
-  // serverInit() is called when the ServerInit message is received.  The
-  // derived class must call on to CConnection::serverInit().
-  public void serverInit()
+  // refreshFramebuffer() forces a complete refresh of the entire
+  // framebuffer
+  public void refreshFramebuffer()
   {
-    state_ = RFBSTATE_NORMAL;
-    vlog.debug("initialisation done");
+    forceNonincremental = true;
+
+    // Without fences, we cannot safely trigger an update request directly
+    // but must wait for the next update to arrive.
+    if (continuousUpdates)
+      requestNewUpdate();
   }
 
-  // Other methods
+  // setPreferredEncoding()/getPreferredEncoding() adjusts which
+  // encoding is listed first as a hint to the server that it is the
+  // preferred one
+  public void setPreferredEncoding(int encoding)
+  {
+    if (preferredEncoding == encoding)
+      return;
+  
+    preferredEncoding = encoding;
+    encodingChange = true;
+  }
+  
+  public int getPreferredEncoding()
+  {
+    return preferredEncoding;
+  }
+  
+  // setCompressLevel()/setQualityLevel() controls the encoding hints
+  // sent to the server
+  public void setCompressLevel(int level)
+  {
+    if (compressLevel == level)
+      return;
+  
+    compressLevel = level;
+    encodingChange = true;
+  }
+  
+  public void setQualityLevel(int level)
+  {
+    if (qualityLevel == level)
+      return;
+  
+    qualityLevel = level;
+    encodingChange = true;
+  }
+
+  // setPF() controls the pixel format requested from the server.
+  // server.pf() will automatically be adjusted once the new format
+  // is active.
+  public void setPF(PixelFormat pf)
+  {
+    if (server.pf().equal(pf) && !formatChange)
+      return;
+
+    nextPF = pf;
+    formatChange = true;
+  }
 
   public CMsgReader reader() { return reader_; }
   public CMsgWriter writer() { return writer_; }
@@ -384,26 +573,24 @@ abstract public class CConnection extends CMsgHandler {
   // 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 boolean isSecure() { return csecurity != null ? csecurity.isSecure() : false; }
-
-  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;
+  boolean isSecure() { return csecurity != null ? csecurity.isSecure() : false; }
 
-  public int state() { return state_; }
+  public enum stateEnum {
+    RFBSTATE_UNINITIALISED,
+    RFBSTATE_PROTOCOL_VERSION,
+    RFBSTATE_SECURITY_TYPES,
+    RFBSTATE_SECURITY,
+    RFBSTATE_SECURITY_RESULT,
+    RFBSTATE_INITIALISATION,
+    RFBSTATE_NORMAL,
+    RFBSTATE_INVALID
+  };
 
-  public int getServerPort() { return serverPort; }
-  public void setServerPort(int port) {
-    serverPort = port;
-  }
+  public stateEnum state() { return state_; }
 
-  protected void setState(int s) { state_ = s; }
+  protected void setState(stateEnum s) { state_ = s; }
 
   protected void setReader(CMsgReader r) { reader_ = r; }
   protected void setWriter(CMsgWriter w) { writer_ = w; }
@@ -420,44 +607,147 @@ abstract public class CConnection extends CMsgHandler {
     // We cannot guarantee any synchronisation at this level
     flags = 0;
 
-    synchronized(this) {
-      writer().writeFence(flags, len, data);
+    writer().writeFence(flags, len, data);
+  }
+
+  // requestNewUpdate() requests an update from the server, having set the
+  // format and encoding appropriately.
+  private void requestNewUpdate()
+  {
+    if (formatChange && !pendingPFChange) {
+      /* Catch incorrect requestNewUpdate calls */
+      assert(!pendingUpdate || continuousUpdates);
+
+      // We have to make sure we switch the internal format at a safe
+      // time. For continuous updates we temporarily disable updates and
+      // look for a EndOfContinuousUpdates message to see when to switch.
+      // For classical updates we just got a new update right before this
+      // function was called, so we need to make sure we finish that
+      // update before we can switch.
+
+      pendingPFChange = true;
+      pendingPF = nextPF;
+
+      if (continuousUpdates)
+        writer().writeEnableContinuousUpdates(false, 0, 0, 0, 0);
+
+      writer().writeSetPixelFormat(pendingPF);
+
+      if (continuousUpdates)
+        writer().writeEnableContinuousUpdates(true, 0, 0,
+                                              server.width(),
+                                              server.height());
+      formatChange = false;
+    }
+
+    if (encodingChange) {
+      updateEncodings();
+      encodingChange = false;
+    }
+
+    if (forceNonincremental || !continuousUpdates) {
+      pendingUpdate = true;
+      writer().writeFramebufferUpdateRequest(new Rect(0, 0,
+                                                      server.width(),
+                                                      server.height()),
+                                             !forceNonincremental);
     }
+
+    forceNonincremental = false;
+  }
+
+  // Ask for encodings based on which decoders are supported.  Assumes higher
+  // encoding numbers are more desirable.
+
+  private void updateEncodings()
+  {
+    List<Integer> encodings = new ArrayList<Integer>();
+
+    if (server.supportsLocalCursor) {
+      // JRE on Windows does not support alpha cursor
+      if (!osName.contains("windows"))
+        encodings.add(Encodings.pseudoEncodingCursorWithAlpha);
+      encodings.add(Encodings.pseudoEncodingCursor);
+      encodings.add(Encodings.pseudoEncodingXCursor);
+    }
+    if (server.supportsDesktopResize) {
+      encodings.add(Encodings.pseudoEncodingDesktopSize);
+      encodings.add(Encodings.pseudoEncodingExtendedDesktopSize);
+    }
+    if (server.supportsClientRedirect)
+      encodings.add(Encodings.pseudoEncodingClientRedirect);
+
+    encodings.add(Encodings.pseudoEncodingDesktopName);
+    encodings.add(Encodings.pseudoEncodingLastRect);
+    encodings.add(Encodings.pseudoEncodingContinuousUpdates);
+    encodings.add(Encodings.pseudoEncodingFence);
+
+    if (Decoder.supported(preferredEncoding)) {
+      encodings.add(preferredEncoding);
+    }
+
+    encodings.add(Encodings.encodingCopyRect);
+
+    for (int i = Encodings.encodingMax; i >= 0; i--) {
+      if ((i != preferredEncoding) && Decoder.supported(i))
+        encodings.add(i);
+    }
+
+    if (compressLevel >= 0 && compressLevel <= 9)
+      encodings.add(Encodings.pseudoEncodingCompressLevel0 + compressLevel);
+    if (qualityLevel >= 0 && qualityLevel <= 9)
+      encodings.add(Encodings.pseudoEncodingQualityLevel0 + qualityLevel);
+
+    writer().writeSetEncodings(encodings);
   }
 
   private void throwAuthFailureException() {
     String reason;
-    vlog.debug("state="+state()+", ver="+cp.majorVersion+"."+cp.minorVersion);
-    if (state() == RFBSTATE_SECURITY_RESULT && !cp.beforeVersion(3,8)) {
+    vlog.debug("state="+state()+", ver="+server.majorVersion+"."+server.minorVersion);
+    if (state() == stateEnum.RFBSTATE_SECURITY_RESULT && !server.beforeVersion(3,8)) {
       reason = is.readString();
     } else {
       reason = "Authentication failure";
     }
-    state_ = RFBSTATE_INVALID;
+    state_ = stateEnum.RFBSTATE_INVALID;
     vlog.error(reason);
     throw new AuthFailureException(reason);
   }
 
+  public CSecurity csecurity;
+  public SecurityClient security;
+
+  protected boolean supportsLocalCursor;
+  protected boolean supportsDesktopResize;
+
   private InStream is;
   private OutStream os;
   private CMsgReader reader_;
   private CMsgWriter writer_;
   private boolean deleteStreamsWhenDone;
   private boolean shared;
-  private int state_ = RFBSTATE_UNINITIALISED;
+  private stateEnum state_;
 
   private String serverName;
+  private int serverPort;
 
-  protected ModifiablePixelBuffer framebuffer;
-  private DecodeManager decoder;
+  private boolean pendingPFChange;
+  private PixelFormat pendingPF;
 
-  public CSecurity csecurity;
-  public SecurityClient security;
-  public static final int maxSecTypes = 8;
-  int nSecTypes;
-  int[] secTypes;
-  int serverPort;
-  boolean clientSecTypeOrder;
+  private int preferredEncoding;
+  private int compressLevel;
+  private int qualityLevel;
 
-  static LogWriter vlog = new LogWriter("CConnection");
+  private boolean formatChange;
+  private PixelFormat nextPF;
+  private boolean encodingChange;
+
+  private boolean firstUpdate;
+  private boolean pendingUpdate;
+  private boolean continuousUpdates;
+
+  private boolean forceNonincremental;
+
+  protected ModifiablePixelBuffer framebuffer;
+  private DecodeManager decoder;
 }
index 2f3151b7cd262ac1d26f6f0a8358e24056680248..5b62f961ba535fc4917e4cb1bd53749bc723208f 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2009-2011 Pierre Ossman for Cendio AB
  * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
- * Copyright (C) 2011 Brian P. Hinz
+ * Copyright (C) 2011-2019 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
@@ -27,59 +27,62 @@ package com.tigervnc.rfb;
 
 abstract public class CMsgHandler {
 
+  static LogWriter vlog = new LogWriter("CMsgHandler");
+
   public CMsgHandler() {
-    cp = new ConnParams();
+    server = new ServerParams();
   }
 
   public void setDesktopSize(int width, int height)
   {
-    cp.width = width;
-    cp.height = height;
+    server.setDimensions(width, height);
   }
 
   public void setExtendedDesktopSize(int reason, int result,
                                      int width, int height,
                                      ScreenSet layout)
   {
-    cp.supportsSetDesktopSize = true;
+    server.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;
+    server.setDimensions(width, height, layout);
   }
 
+  abstract public void setCursor(int width, int height, Point hotspot,
+                                 byte[] data);
+
   public void setPixelFormat(PixelFormat pf)
   {
-    cp.setPF(pf);
+    server.setPF(pf);
   }
 
   public void setName(String name)
   {
-    cp.setName(name);
+    server.setName(name);
   }
 
   public void fence(int flags, int len, byte[] data)
   {
-    cp.supportsFence = true;
+    server.supportsFence = true;
   }
 
   public void endOfContinuousUpdates()
   {
-    cp.supportsContinuousUpdates = true;
+    server.supportsContinuousUpdates = true;
   }
 
   abstract public void clientRedirect(int port, String host,
                                       String x509subject);
 
-  abstract public void setCursor(int width, int height, Point hotspot,
-                                 byte[] data);
-  abstract public void serverInit();
+  public void serverInit(int width, int height,
+                         PixelFormat pf, String name)
+  {
+    server.setDimensions(width, height);
+    server.setPF(pf);
+    server.setName(name);
+  }
 
   abstract public void readAndDecodeRect(Rect r, int encoding,
                                          ModifiablePixelBuffer pb);
@@ -93,7 +96,5 @@ abstract public class CMsgHandler {
   abstract public void bell();
   abstract public void serverCutText(String str, int len);
 
-  public ConnParams cp;
-
-  static LogWriter vlog = new LogWriter("CMsgHandler");
+  public ServerParams server;
 }
index e65db8c67a942c2399aa4f733c8d69f479ff1768..56b761e47de26910b4d89360064851d031e34f0a 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011-2017 Brian P. Hinz
+ * Copyright (C) 2011-2019 Brian P. Hinz
  * Copyright (C) 2017 Pierre Ossman for Cendio AB
  *
  * This is free software; you can redistribute it and/or modify
@@ -34,27 +34,26 @@ import com.tigervnc.rdr.*;
 
 public class CMsgReader {
 
+  static LogWriter vlog = new LogWriter("CMsgReader");
+
   protected CMsgReader(CMsgHandler handler_, InStream is_)
   {
     imageBufIdealSize = 0;
     handler = handler_;
     is = is_;
+    nUpdateRectsLeft = 0;
     imageBuf = null;
     imageBufSize = 0;
-    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();
+    handler.serverInit(width, height, pf, name);
   }
 
   public void readMsg()
@@ -82,6 +81,7 @@ public class CMsgReader {
         readEndOfContinuousUpdates();
         break;
       default:
+        vlog.error("unknown message type "+type);
         throw new Exception("unknown message type");
       }
     } else {
@@ -148,11 +148,13 @@ public class CMsgReader {
   {
     is.skip(3);
     int len = is.readU32();
+
     if (len > 256*1024) {
       is.skip(len);
       vlog.error("cut text too long ("+len+" bytes) - ignoring");
       return;
     }
+
     ByteBuffer buf = ByteBuffer.allocate(len);
     is.readBytes(buf, len);
     Charset latin1 = Charset.forName("ISO-8859-1");
@@ -196,10 +198,10 @@ public class CMsgReader {
 
   protected void readRect(Rect r, int encoding)
   {
-    if ((r.br.x > handler.cp.width) || (r.br.y > handler.cp.height)) {
+    if ((r.br.x > handler.server.width()) || (r.br.y > handler.server.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);
+                  r.tl.x+","+r.tl.y+" exceeds "+handler.server.width()+"x"+
+                  handler.server.height());
       throw new Exception("Rect too big");
     }
 
@@ -268,7 +270,7 @@ public class CMsgReader {
 
   protected void readSetCursor(int width, int height, Point hotspot)
   {
-    int data_len = width * height * (handler.cp.pf().bpp/8);
+    int data_len = width * height * (handler.server.pf().bpp/8);
     int mask_len = ((width+7)/8) * height;
     ByteBuffer data = ByteBuffer.allocate(data_len);
     ByteBuffer mask = ByteBuffer.allocate(mask_len);
@@ -295,9 +297,9 @@ public class CMsgReader {
         else
           out.put((byte)0);
 
-        handler.cp.pf().rgbFromBuffer(out.duplicate(), in.duplicate(), 1);
+        handler.server.pf().rgbFromBuffer(out.duplicate(), in.duplicate(), 1);
 
-        in.position(in.position() + handler.cp.pf().bpp/8);
+        in.position(in.position() + handler.server.pf().bpp/8);
         out.position(out.position() + 3);
       }
     }
@@ -320,10 +322,10 @@ public class CMsgReader {
 
     encoding = is.readS32();
 
-    origPF = handler.cp.pf();
-    handler.cp.setPF(rgbaPF);
+    origPF = handler.server.pf();
+    handler.server.setPF(rgbaPF);
     handler.readAndDecodeRect(pb.getRect(), encoding, pb);
-    handler.cp.setPF(origPF);
+    handler.server.setPF(origPF);
 
     // ARGB with pre-multiplied alpha works best for BufferedImage
     if (pb.area() > 0) {
@@ -412,7 +414,7 @@ public class CMsgReader {
       imageBuf = new int[imageBufSize];
     }
     if (nPixels != 0)
-      nPixels = imageBufSize / (handler.cp.pf().bpp / 8);
+      nPixels = imageBufSize / (handler.server.pf().bpp / 8);
     return imageBuf;
   }
 
@@ -425,6 +427,4 @@ public class CMsgReader {
   protected int nUpdateRectsLeft;
   protected int[] imageBuf;
   protected int imageBufSize;
-
-  static LogWriter vlog = new LogWriter("CMsgReader");
 }
index 164fa293467d95290f2ff7302b165e955c093f77..f89e40d4b0a496e23629c463af90487edbdff5cd 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2009-2011 Pierre Ossman for Cendio AB
- * Copyright (C) 2011 Brian P. Hinz
+ * Copyright (C) 2011-2019 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
@@ -23,13 +23,13 @@ package com.tigervnc.rfb;
 import com.tigervnc.rdr.*;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
-import java.util.Iterator;
+import java.util.*;
 
 public class CMsgWriter {
 
-  protected CMsgWriter(ConnParams cp_, OutStream os_)
+  protected CMsgWriter(ServerParams server_, OutStream os_)
   {
-    cp = cp_;
+    server = server_;
     os = os_;
   }
 
@@ -46,98 +46,20 @@ public class CMsgWriter {
     endMsg();
   }
 
-  synchronized public void writeSetEncodings(int nEncodings, int[] encodings)
+  synchronized public void writeSetEncodings(List<Integer> encodings)
   {
     startMsg(MsgTypes.msgTypeSetEncodings);
     os.skip(1);
-    os.writeU16(nEncodings);
-    for (int i = 0; i < nEncodings; i++)
-      os.writeU32(encodings[i]);
+    os.writeU16(encodings.size());
+    for (Iterator<Integer> i = encodings.iterator(); i.hasNext();)
+      os.writeU32(i.next());
     endMsg();
   }
 
-  // Ask for encodings based on which decoders are supported.  Assumes higher
-  // encoding numbers are more desirable.
-
-  synchronized public void writeSetEncodings(int preferredEncoding, boolean useCopyRect)
-  {
-    int nEncodings = 0;
-    int[] encodings = new int[Encodings.encodingMax+3];
-
-    if (cp.supportsLocalCursor) {
-      if (cp.supportsLocalCursorWithAlpha)
-        encodings[nEncodings++] = Encodings.pseudoEncodingCursorWithAlpha;
-      encodings[nEncodings++] = Encodings.pseudoEncodingCursor;
-      encodings[nEncodings++] = Encodings.pseudoEncodingXCursor;
-    }
-    if (cp.supportsDesktopResize)
-      encodings[nEncodings++] = Encodings.pseudoEncodingDesktopSize;
-    if (cp.supportsExtendedDesktopSize)
-      encodings[nEncodings++] = Encodings.pseudoEncodingExtendedDesktopSize;
-    if (cp.supportsDesktopRename)
-      encodings[nEncodings++] = Encodings.pseudoEncodingDesktopName;
-    if (cp.supportsClientRedirect)
-      encodings[nEncodings++] = Encodings.pseudoEncodingClientRedirect;
-
-    encodings[nEncodings++] = Encodings.pseudoEncodingLastRect;
-    encodings[nEncodings++] = Encodings.pseudoEncodingContinuousUpdates;
-    encodings[nEncodings++] = Encodings.pseudoEncodingFence;
-
-    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.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++] = i;
-      }
-    }
-
-    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)
+         if (!server.supportsSetDesktopSize)
            throw new Exception("Server does not support SetDesktopSize");
 
          startMsg(MsgTypes.msgTypeSetDesktopSize);
@@ -176,7 +98,7 @@ public class CMsgWriter {
   synchronized public void writeEnableContinuousUpdates(boolean enable,
                                            int x, int y, int w, int h)
   {
-    if (!cp.supportsContinuousUpdates)
+    if (!server.supportsContinuousUpdates)
       throw new Exception("Server does not support continuous updates");
 
     startMsg(MsgTypes.msgTypeEnableContinuousUpdates);
@@ -193,7 +115,7 @@ public class CMsgWriter {
 
   synchronized public void writeFence(int flags, int len, byte[] data)
   {
-    if (!cp.supportsFence)
+    if (!server.supportsFence)
       throw new Exception("Server does not support fences");
     if (len > 64)
       throw new Exception("Too large fence payload");
@@ -211,7 +133,7 @@ public class CMsgWriter {
     endMsg();
   }
 
-  synchronized public void keyEvent(int keysym, boolean down)
+  synchronized public void writeKeyEvent(int keysym, boolean down)
   {
     startMsg(MsgTypes.msgTypeKeyEvent);
     os.writeU8(down?1:0);
@@ -220,13 +142,13 @@ public class CMsgWriter {
     endMsg();
   }
 
-  synchronized public void pointerEvent(Point pos, int buttonMask)
+  synchronized 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;
+    if (p.x >= server.width()) p.x = server.width() - 1;
+    if (p.y >= server.height()) p.y = server.height() - 1;
 
     startMsg(MsgTypes.msgTypePointerEvent);
     os.writeU8(buttonMask);
@@ -246,14 +168,14 @@ public class CMsgWriter {
     endMsg();
   }
 
-  synchronized public void startMsg(int type) {
+  synchronized protected void startMsg(int type) {
     os.writeU8(type);
   }
 
-  synchronized public void endMsg() {
+  synchronized protected void endMsg() {
     os.flush();
   }
 
-  ConnParams cp;
-  OutStream os;
+  protected ServerParams server;
+  protected OutStream os;
 }
index 7c3291464e01dbef6c91aa491c891a15587ab317..518ff9af95577c3f0e831bb8a88c5dab64af4e3f 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2019 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
@@ -19,5 +20,8 @@
 package com.tigervnc.rfb;
 
 public class ConnFailedException extends Exception {
-  public ConnFailedException(String s) { super(s); }
+  public ConnFailedException() { super("Connection failed"); }
+  public ConnFailedException(String reason) {
+    super("Connection faied: "+reason);
+  }
 }
diff --git a/java/com/tigervnc/rfb/ConnParams.java b/java/com/tigervnc/rfb/ConnParams.java
deleted file mode 100644 (file)
index ce3af71..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
- * 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
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-package com.tigervnc.rfb;
-
-import com.tigervnc.rdr.*;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class 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;
-    supportsLocalCursorWithAlpha = false;
-    supportsDesktopResize = false; supportsExtendedDesktopSize = false;
-    supportsDesktopRename = false; supportsLastRect = false;
-    supportsSetDesktopSize = false; supportsFence = false;
-    supportsContinuousUpdates = false;
-    supportsClientRedirect = false;
-    compressLevel = 6; qualityLevel = -1; fineQualityLevel = -1;
-    subsampling = subsampleUndefined; name_ = null; verStrPos = 0;
-
-    encodings_ = new ArrayList();
-    screenLayout = new ScreenSet();
-
-    setName("");
-  }
-
-  public boolean readVersion(InStream is, AtomicBoolean done)
-  {
-    if (verStrPos >= 12) return false;
-    verStr = new StringBuilder(13);
-    while (is.checkNoWait(1) && verStrPos < 12) {
-      verStr.insert(verStrPos++,(char)is.readU8());
-    }
-
-    if (verStrPos < 12) {
-      done.set(false);
-      return true;
-    }
-    done.set(true);
-    verStr.insert(12,'0');
-    verStrPos = 0;
-    if (verStr.toString().matches("RFB \\d{3}\\.\\d{3}\\n0")) {
-      majorVersion = Integer.parseInt(verStr.substring(4,7));
-      minorVersion = Integer.parseInt(verStr.substring(8,11));
-      return true;
-    }
-    return false;
-  }
-
-  public void writeVersion(OutStream os)
-  {
-    String str = String.format("RFB %03d.%03d\n", majorVersion, minorVersion);
-    os.writeBytes(str.getBytes(), 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 boolean supportsEncoding(int encoding)
-  {
-    return encodings_.indexOf(encoding) != -1;
-  }
-
-  public void setEncodings(int nEncodings, int[] encodings)
-  {
-    useCopyRect = false;
-    supportsLocalCursor = false;
-    supportsLocalCursorWithAlpha = false;
-    supportsDesktopResize = false;
-    supportsExtendedDesktopSize = false;
-    supportsLocalXCursor = false;
-    supportsLastRect = false;
-    compressLevel = -1;
-    qualityLevel = -1;
-    fineQualityLevel = -1;
-    subsampling = subsampleUndefined;
-
-    encodings_.clear();
-    encodings_.add(Encodings.encodingRaw);
-
-    for (int i = nEncodings-1; i >= 0; i--) {
-      switch (encodings[i]) {
-      case Encodings.encodingCopyRect:
-        useCopyRect = true;
-        break;
-      case Encodings.pseudoEncodingCursor:
-        supportsLocalCursor = true;
-        break;
-      case Encodings.pseudoEncodingXCursor:
-        supportsLocalXCursor = true;
-        break;
-      case Encodings.pseudoEncodingCursorWithAlpha:
-        supportsLocalCursorWithAlpha = true;
-        break;
-      case Encodings.pseudoEncodingDesktopSize:
-        supportsDesktopResize = true;
-        break;
-      case Encodings.pseudoEncodingExtendedDesktopSize:
-        supportsExtendedDesktopSize = true;
-        break;
-      case Encodings.pseudoEncodingDesktopName:
-        supportsDesktopRename = true;
-        break;
-      case Encodings.pseudoEncodingLastRect:
-        supportsLastRect = true;
-        break;
-      case Encodings.pseudoEncodingFence:
-        supportsFence = true;
-        break;
-      case Encodings.pseudoEncodingContinuousUpdates:
-        supportsContinuousUpdates = true;
-        break;
-      case Encodings.pseudoEncodingClientRedirect:
-        supportsClientRedirect = 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;
-
-      if (encodings[i] >= Encodings.pseudoEncodingQualityLevel0 &&
-          encodings[i] <= Encodings.pseudoEncodingQualityLevel9)
-        qualityLevel = encodings[i] - Encodings.pseudoEncodingQualityLevel0;
-
-      if (encodings[i] >= Encodings.pseudoEncodingFineQualityLevel0 &&
-          encodings[i] <= Encodings.pseudoEncodingFineQualityLevel100)
-        fineQualityLevel = encodings[i] - Encodings.pseudoEncodingFineQualityLevel0;
-
-      if (encodings[i] > 0)
-        encodings_.add(encodings[i]);
-    }
-  }
-
-  public boolean useCopyRect;
-
-  public boolean supportsLocalCursor;
-  public boolean supportsLocalXCursor;
-  public boolean supportsLocalCursorWithAlpha;
-  public boolean supportsDesktopResize;
-  public boolean supportsExtendedDesktopSize;
-  public boolean supportsDesktopRename;
-  public boolean supportsLastRect;
-  public boolean supportsClientRedirect;
-
-  public boolean supportsSetDesktopSize;
-  public boolean supportsFence;
-  public boolean supportsContinuousUpdates;
-
-  public int compressLevel;
-  public int qualityLevel;
-  public int fineQualityLevel;
-  public int subsampling;
-
-  private PixelFormat pf_;
-  private String name_;
-  private Cursor cursor_;
-  private ArrayList encodings_;
-  private StringBuilder verStr;
-  private int verStrPos;
-}
index 40452e21a9bffa3a8f7e2daf97ff2cc121c3f7ee..47861f9cbf1ade0757fe9da8c42ce4fec7765acf 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright 2014 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright 2016 Brian P. Hinz
+ * Copyright 2016-2019 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
@@ -26,27 +26,27 @@ public class CopyRectDecoder extends Decoder {
   public CopyRectDecoder() { super(DecoderFlags.DecoderPlain); }
 
   public void readRect(Rect r, InStream is,
-                       ConnParams cp, OutStream os)
+                       ServerParams server, OutStream os)
   {
     os.copyBytes(is, 4);
   }
 
   public void getAffectedRegion(Rect rect, Object buffer,
-                                int buflen, ConnParams cp,
+                                int buflen, ServerParams server,
                                 Region region)
   {
     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
     int srcX = is.readU16();
     int srcY = is.readU16();
 
-    super.getAffectedRegion(rect, buffer, buflen, cp, region);
+    super.getAffectedRegion(rect, buffer, buflen, server, region);
 
     region.assign_union(new Region(rect.translate(new Point(srcX-rect.tl.x,
                                                             srcY-rect.tl.y))));
   }
 
   public void decodeRect(Rect r, Object buffer,
-                         int buflen, ConnParams cp,
+                         int buflen, ServerParams server,
                          ModifiablePixelBuffer pb)
   {
     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
index d849444615a6138901d086815c342ae617946c3e..d117a0b350e851210efe95415204ea4c0460501c 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright 2015 Pierre Ossman for Cendio AB
- * Copyright 2016 Brian P. Hinz
+ * Copyright 2016-2019 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
@@ -107,9 +107,9 @@ public class DecodeManager {
     if (threads.size() == 1) {
       bufferStream = freeBuffers.getFirst();
       bufferStream.clear();
-      decoder.readRect(r, conn.getInStream(), conn.cp, bufferStream);
+      decoder.readRect(r, conn.getInStream(), conn.server, bufferStream);
       decoder.decodeRect(r, (Object)bufferStream.data(), bufferStream.length(),
-                         conn.cp, pb);
+                         conn.server, pb);
       return;
     }
 
@@ -134,7 +134,7 @@ public class DecodeManager {
 
     // Read the rect
     bufferStream.clear();
-    decoder.readRect(r, conn.getInStream(), conn.cp, bufferStream);
+    decoder.readRect(r, conn.getInStream(), conn.server, bufferStream);
 
     // Then try to put it on the queue
     entry = new QueueEntry();
@@ -143,12 +143,12 @@ public class DecodeManager {
     entry.rect = r;
     entry.encoding = encoding;
     entry.decoder = decoder;
-    entry.cp = conn.cp;
+    entry.server = conn.server;
     entry.pb = pb;
     entry.bufferStream = bufferStream;
 
     decoder.getAffectedRegion(r, bufferStream.data(),
-                              bufferStream.length(), conn.cp,
+                              bufferStream.length(), conn.server,
                               entry.affectedRegion);
 
     queueMutex.lock();
@@ -228,7 +228,7 @@ public class DecodeManager {
     public Rect rect;
     public int encoding;
     public Decoder decoder;
-    public ConnParams cp;
+    public ServerParams server;
     public ModifiablePixelBuffer pb;
     public MemOutStream bufferStream;
     public Region affectedRegion;
@@ -289,7 +289,7 @@ public class DecodeManager {
         try {
           entry.decoder.decodeRect(entry.rect, entry.bufferStream.data(),
                                    entry.bufferStream.length(),
-                                   entry.cp, entry.pb);
+                                   entry.server, entry.pb);
         } catch (com.tigervnc.rdr.Exception e) {
           manager.setThreadException(e);
         } catch(java.lang.Exception e) {
@@ -363,7 +363,7 @@ public class DecodeManager {
                                               entry2.rect,
                                               entry2.bufferStream.data(),
                                               entry2.bufferStream.length(),
-                                              entry.cp))
+                                              entry.server))
               lockedRegion.assign_union(entry.affectedRegion);
               continue next;
           }
index 6bbed85e832a867734a395b6b41478d030becc3e..0216176d554f8e53baa665a88383512d8cc45e00 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2019 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
@@ -38,14 +39,14 @@ abstract public class Decoder {
   }
 
   abstract public void readRect(Rect r, InStream is,
-                                ConnParams cp, OutStream os);
+                                ServerParams server, OutStream os);
 
   abstract public void decodeRect(Rect r, Object buffer,
-                                  int buflen, ConnParams cp,
+                                  int buflen, ServerParams server,
                                   ModifiablePixelBuffer pb);
 
   public void getAffectedRegion(Rect rect, Object buffer,
-                                int buflen, ConnParams cp,
+                                int buflen, ServerParams server,
                                 Region region)
   {
     region.reset(rect);
@@ -54,7 +55,7 @@ abstract public class Decoder {
   public boolean doRectsConflict(Rect rectA, Object bufferA,
                                  int buflenA, Rect rectB,
                                  Object bufferB, int buflenB,
-                                 ConnParams cp)
+                                 ServerParams server)
   {
     return false;
   }
index 4c99deebe33ee2fbbbd5eaea28570419a011c39e..c5717782179b9e131b86fae1257a3ff29b944cfe 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2019 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
@@ -35,12 +36,12 @@ public class HextileDecoder extends Decoder {
   public HextileDecoder() { super(DecoderFlags.DecoderPlain); }
 
   public void readRect(Rect r, InStream is,
-                       ConnParams cp, OutStream os)
+                       ServerParams server, OutStream os)
   {
     Rect t = new Rect();
     int bytesPerPixel;
 
-    bytesPerPixel = cp.pf().bpp/8;
+    bytesPerPixel = server.pf().bpp/8;
 
     for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
@@ -81,11 +82,11 @@ public class HextileDecoder extends Decoder {
   }
 
   public void decodeRect(Rect r, Object buffer,
-                         int buflen, ConnParams cp,
+                         int buflen, ServerParams server,
                          ModifiablePixelBuffer pb)
   {
     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
-    PixelFormat pf = cp.pf();
+    PixelFormat pf = server.pf();
     switch (pf.bpp) {
     case 8:  hextileDecode8(r, is, pf, pb); break;
     case 16: hextileDecode16(r, is, pf, pb); break;
index c73c7a948937451b60b77af39e1cb056303db341..2fa98d0cad6c400b3c53227b1faf6bf23d51ad3a 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2016 Brian P. Hinz
+ * Copyright 2016-2019 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
@@ -28,22 +28,22 @@ public class RREDecoder extends Decoder {
   public RREDecoder() { super(DecoderFlags.DecoderPlain); }
 
   public void readRect(Rect r, InStream is,
-                       ConnParams cp, OutStream os)
+                       ServerParams server, OutStream os)
   {
     int numRects;
 
     numRects = is.readU32();
     os.writeU32(numRects);
 
-    os.copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8));
+    os.copyBytes(is, server.pf().bpp/8 + numRects * (server.pf().bpp/8 + 8));
   }
 
   public void decodeRect(Rect r, Object buffer,
-                         int buflen, ConnParams cp,
+                         int buflen, ServerParams server,
                          ModifiablePixelBuffer pb)
   {
     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
-    PixelFormat pf = cp.pf();
+    PixelFormat pf = server.pf();
     switch (pf.bpp) {
     case 8:  rreDecode8 (r, is, pf, pb); break;
     case 16: rreDecode16(r, is, pf, pb); break;
index 71b79607917a712773ee0336ef988dea4f1044eb..386845ed43a8d1f8f19dc796a4143ce1a46b0134 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2019 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
@@ -25,18 +26,18 @@ public class RawDecoder extends Decoder {
   public RawDecoder() { super(DecoderFlags.DecoderPlain); }
 
   public void readRect(Rect r, InStream is,
-                       ConnParams cp, OutStream os)
+                       ServerParams server, OutStream os)
   {
-    os.copyBytes(is, r.area() * cp.pf().bpp/8);
+    os.copyBytes(is, r.area() * server.pf().bpp/8);
   }
 
   static LogWriter vlog = new LogWriter("RawDecoder");
   public void decodeRect(Rect r, Object buffer,
-                         int buflen, ConnParams cp,
+                         int buflen, ServerParams server,
                          ModifiablePixelBuffer pb)
   {
-    assert(buflen >= r.area() * cp.pf().bpp/8);
-    pb.imageRect(cp.pf(), r, (byte[])buffer);
+    assert(buflen >= r.area() * server.pf().bpp/8);
+    pb.imageRect(server.pf(), r, (byte[])buffer);
   }
 
 }
index 92437da1a98a4a9f890e54bb27618ae1bcba877e..4c4e543eae4358156b968cd10cf100f5ad3e5f95 100644 (file)
@@ -83,10 +83,6 @@ public class ScreenSet {
     }
   }
 
-  // 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 ArrayList<Screen> screens;
 
   static LogWriter vlog = new LogWriter("ScreenSet");
diff --git a/java/com/tigervnc/rfb/ServerParams.java b/java/com/tigervnc/rfb/ServerParams.java
new file mode 100644 (file)
index 0000000..1ed6418
--- /dev/null
@@ -0,0 +1,234 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
+ * Copyright (C) 2012-2019 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
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class ServerParams {
+
+  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 ServerParams()
+  {
+    majorVersion = 0; minorVersion = 0;
+    width_ = 0; height_ = 0; useCopyRect = false;
+    supportsLocalCursor = false; supportsLocalXCursor = false;
+    supportsLocalCursorWithAlpha = false;
+    supportsDesktopResize = false; supportsExtendedDesktopSize = false;
+    supportsDesktopRename = false; supportsLastRect = false;
+    supportsSetDesktopSize = false; supportsFence = false;
+    supportsContinuousUpdates = false;
+    supportsClientRedirect = false;
+    compressLevel = 6; qualityLevel = -1; fineQualityLevel = -1;
+    subsampling = subsampleUndefined; name_ = null; verStrPos = 0;
+
+    encodings_ = new ArrayList();
+    screenLayout_ = new ScreenSet();
+
+    setName("");
+  }
+
+  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() { return width_; }
+  public int height() { return height_; }
+  public ScreenSet screenLayout() { return screenLayout_; }
+
+  public void setDimensions(int width, int height)
+  {
+    ScreenSet layout = new ScreenSet();
+    layout.add_screen(new Screen(0, 0, 0, width, height, 0));
+    setDimensions(width, height, layout);
+  }
+
+  public void setDimensions(int width, int height, ScreenSet layout)
+  {
+    if (!layout.validate(width, height))
+      throw new Exception("Attempted to configure an invalid screen layout");
+
+    width_ = width;
+    height_ = height;
+    screenLayout_ = layout;
+  }
+
+  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 boolean supportsEncoding(int encoding)
+  {
+    return encodings_.indexOf(encoding) != -1;
+  }
+
+  public void setEncodings(int nEncodings, int[] encodings)
+  {
+    useCopyRect = false;
+    supportsLocalCursor = false;
+    supportsLocalCursorWithAlpha = false;
+    supportsDesktopResize = false;
+    supportsExtendedDesktopSize = false;
+    supportsLocalXCursor = false;
+    supportsLastRect = false;
+    compressLevel = -1;
+    qualityLevel = -1;
+    fineQualityLevel = -1;
+    subsampling = subsampleUndefined;
+
+    encodings_.clear();
+    encodings_.add(Encodings.encodingRaw);
+
+    for (int i = nEncodings-1; i >= 0; i--) {
+      switch (encodings[i]) {
+      case Encodings.encodingCopyRect:
+        useCopyRect = true;
+        break;
+      case Encodings.pseudoEncodingCursor:
+        supportsLocalCursor = true;
+        break;
+      case Encodings.pseudoEncodingXCursor:
+        supportsLocalXCursor = true;
+        break;
+      case Encodings.pseudoEncodingCursorWithAlpha:
+        supportsLocalCursorWithAlpha = true;
+        break;
+      case Encodings.pseudoEncodingDesktopSize:
+        supportsDesktopResize = true;
+        break;
+      case Encodings.pseudoEncodingExtendedDesktopSize:
+        supportsExtendedDesktopSize = true;
+        break;
+      case Encodings.pseudoEncodingDesktopName:
+        supportsDesktopRename = true;
+        break;
+      case Encodings.pseudoEncodingLastRect:
+        supportsLastRect = true;
+        break;
+      case Encodings.pseudoEncodingFence:
+        supportsFence = true;
+        break;
+      case Encodings.pseudoEncodingContinuousUpdates:
+        supportsContinuousUpdates = true;
+        break;
+      case Encodings.pseudoEncodingClientRedirect:
+        supportsClientRedirect = 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;
+
+      if (encodings[i] >= Encodings.pseudoEncodingQualityLevel0 &&
+          encodings[i] <= Encodings.pseudoEncodingQualityLevel9)
+        qualityLevel = encodings[i] - Encodings.pseudoEncodingQualityLevel0;
+
+      if (encodings[i] >= Encodings.pseudoEncodingFineQualityLevel0 &&
+          encodings[i] <= Encodings.pseudoEncodingFineQualityLevel100)
+        fineQualityLevel = encodings[i] - Encodings.pseudoEncodingFineQualityLevel0;
+
+      if (encodings[i] > 0)
+        encodings_.add(encodings[i]);
+    }
+  }
+
+  public boolean useCopyRect;
+
+  public boolean supportsLocalCursor;
+  public boolean supportsLocalXCursor;
+  public boolean supportsLocalCursorWithAlpha;
+  public boolean supportsDesktopResize;
+  public boolean supportsExtendedDesktopSize;
+  public boolean supportsDesktopRename;
+  public boolean supportsLastRect;
+  public boolean supportsClientRedirect;
+
+  public boolean supportsSetDesktopSize;
+  public boolean supportsFence;
+  public boolean supportsContinuousUpdates;
+
+  public int compressLevel;
+  public int qualityLevel;
+  public int fineQualityLevel;
+  public int subsampling;
+
+  private int width_;
+  private int height_;
+  private ScreenSet screenLayout_;
+
+  private PixelFormat pf_;
+  private String name_;
+  private Cursor cursor_;
+  private ArrayList encodings_;
+  private StringBuilder verStr;
+  private int verStrPos;
+}
index 262fcc342c1f5367f423a8c77a600bab602fd974..f8cd23c3d2a37c8a04bf80970257a473bce12eab 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2000-2003 Constantin Kaplinsky.  All Rights Reserved.
  * Copyright 2004-2005 Cendio AB.
  * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
- * Copyright (C) 2011-2012 Brian P. Hinz
+ * Copyright (C) 2011-2019 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
@@ -59,7 +59,7 @@ public class TightDecoder extends Decoder {
   }
 
   public void readRect(Rect r, InStream is,
-                       ConnParams cp, OutStream os)
+                       ServerParams server, OutStream os)
   {
     int comp_ctl;
 
@@ -70,10 +70,10 @@ public class TightDecoder extends Decoder {
 
     // "Fill" compression type.
     if (comp_ctl == tightFill) {
-      if (cp.pf().is888())
+      if (server.pf().is888())
         os.copyBytes(is, 3);
       else
-        os.copyBytes(is, cp.pf().bpp/8);
+        os.copyBytes(is, server.pf().bpp/8);
       return;
     }
 
@@ -110,13 +110,13 @@ public class TightDecoder extends Decoder {
         palSize = is.readU8() + 1;
         os.writeU32(palSize - 1);
 
-        if (cp.pf().is888())
+        if (server.pf().is888())
           os.copyBytes(is, palSize * 3);
         else
-          os.copyBytes(is, palSize * cp.pf().bpp/8);
+          os.copyBytes(is, palSize * server.pf().bpp/8);
         break;
       case tightFilterGradient:
-        if (cp.pf().bpp == 8)
+        if (server.pf().bpp == 8)
           throw new Exception("TightDecoder: invalid BPP for gradient filter");
         break;
       case tightFilterCopy:
@@ -133,10 +133,10 @@ public class TightDecoder extends Decoder {
         rowSize = (r.width() + 7) / 8;
       else
         rowSize = r.width();
-    } else if (cp.pf().is888()) {
+    } else if (server.pf().is888()) {
       rowSize = r.width() * 3;
     } else {
-      rowSize = r.width() * cp.pf().bpp/8;
+      rowSize = r.width() * server.pf().bpp/8;
     }
 
     dataSize = r.height() * rowSize;
@@ -158,7 +158,7 @@ public class TightDecoder extends Decoder {
                                  Rect rectB,
                                  Object bufferB,
                                  int buflenB,
-                                 ConnParams cp)
+                                 ServerParams server)
   {
     byte comp_ctl_a, comp_ctl_b;
 
@@ -181,11 +181,11 @@ public class TightDecoder extends Decoder {
   }
 
   public void decodeRect(Rect r, Object buffer,
-                         int buflen, ConnParams cp,
+                         int buflen, ServerParams server,
                          ModifiablePixelBuffer pb)
   {
     ByteBuffer bufptr;
-    PixelFormat pf = cp.pf();
+    PixelFormat pf = server.pf();
 
     int comp_ctl;
 
index 03692b96771a514d300c889f4df5b07fd2004c3e..bd49ab43b5db4b97b7e73e15274cee50595bf7e5 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2019 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
@@ -52,7 +53,7 @@ public class ZRLEDecoder extends Decoder {
   }
 
   public void readRect(Rect r, InStream is,
-                      ConnParams cp, OutStream os)
+                      ServerParams server, OutStream os)
   {
     int len;
 
@@ -62,11 +63,11 @@ public class ZRLEDecoder extends Decoder {
   }
 
   public void decodeRect(Rect r, Object buffer,
-                         int buflen, ConnParams cp,
+                         int buflen, ServerParams server,
                          ModifiablePixelBuffer pb)
   {
     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
-    PixelFormat pf = cp.pf();
+    PixelFormat pf = server.pf();
     switch (pf.bpp) {
     case 8:  zrleDecode8(r, is, zis, pf, pb); break;
     case 16: zrleDecode16(r, is, zis, pf, pb); break;
index 75f6b74b9cfb75ff0ebe615bb2d0d8dbfc4099be..08a82b32da021984952275bf8115eb9ab1cf5082 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
  * Copyright 2009-2013 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2011-2013 D. R. Commander.  All Rights Reserved.
- * Copyright (C) 2011-2017 Brian P. Hinz
+ * Copyright (C) 2011-2019 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
@@ -83,42 +83,21 @@ public class CConn extends CConnection implements
   public CConn(String vncServerName, Socket socket)
   {
     serverHost = null; serverPort = 0; desktop = null;
-    pendingPFChange = false;
-    currentEncoding = Encodings.encodingTight; lastServerEncoding = -1;
-    formatChange = false; encodingChange = false;
-    firstUpdate = true; pendingUpdate = false; continuousUpdates = false;
-    forceNonincremental = true; supportsSyncFence = false;
+    updateCount = 0; pixelCount = 0;
+    lastServerEncoding = -1;
 
     setShared(shared.getValue());
     sock = socket;
 
-    int encNum = Encodings.encodingNum(preferredEncoding.getValue());
-    if (encNum != -1)
-      currentEncoding = encNum;
-
-    cp.supportsLocalCursor = true;
-    if (VncViewer.os.contains("windows"))
-      // JRE on Windows does not support alpha cursor
-      cp.supportsLocalCursorWithAlpha = false;
-    else
-      cp.supportsLocalCursorWithAlpha = true;
-
-    cp.supportsDesktopResize = true;
-    cp.supportsExtendedDesktopSize = true;
-    cp.supportsDesktopRename = true;
-
-    cp.supportsSetDesktopSize = false;
-    cp.supportsClientRedirect = true;
+    server.supportsLocalCursor = true;
+    server.supportsDesktopResize = true;
+    server.supportsClientRedirect = true;
 
     if (customCompressLevel.getValue())
-      cp.compressLevel = compressLevel.getValue();
-    else
-      cp.compressLevel = -1;
+      setCompressLevel(compressLevel.getValue());
 
     if (!noJpeg.getValue())
-      cp.qualityLevel = qualityLevel.getValue();
-    else
-      cp.qualityLevel = -1;
+      setQualityLevel(qualityLevel.getValue());
 
     if (sock == null) {
       setServerName(Hostname.getHost(vncServerName));
@@ -160,16 +139,6 @@ public class CConn extends CConnection implements
     OptionsDialog.addCallback("handleOptions", this);
   }
 
-  public void refreshFramebuffer()
-  {
-    forceNonincremental = true;
-
-    // Without fences, we cannot safely trigger an update request directly
-    // but must wait for the next update to arrive.
-    if (supportsSyncFence)
-      requestNewUpdate();
-  }
-
   public String connectionInfo() {
     String info = new String("Desktop name: %s%n"+
                              "Host: %s:%d%n"+
@@ -182,21 +151,31 @@ public class CConn extends CConnection implements
                              "Protocol version: %d.%d%n"+
                              "Security method: %s [%s]%n");
     String infoText =
-      String.format(info, cp.name(),
+      String.format(info, server.name(),
                     sock.getPeerName(), sock.getPeerPort(),
-                    cp.width, cp.height,
-                    cp.pf().print(),
+                    server.width(), server.height(),
+                    server.pf().print(),
                     serverPF.print(),
-                    Encodings.encodingName(currentEncoding),
+                    Encodings.encodingName(getPreferredEncoding()),
                     Encodings.encodingName(lastServerEncoding),
                     sock.inStream().kbitsPerSecond(),
-                    cp.majorVersion, cp.minorVersion,
+                    server.majorVersion, server.minorVersion,
                     Security.secTypeName(csecurity.getType()),
                     csecurity.description());
 
     return infoText;
   }
 
+  public int getUpdateCount()
+  {
+    return updateCount;
+  }
+
+  public int getPixelCount()
+  {
+    return pixelCount;
+  }
+
   // The RFB core is not properly asynchronous, so it calls this callback
   // whenever it needs to block to wait for more data. Since FLTK is
   // monitoring the socket, we just make sure FLTK gets to run.
@@ -216,31 +195,24 @@ public class CConn extends CConnection implements
   // 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()
+  public void initDone()
   {
-    super.serverInit();
-
     // If using AutoSelect with old servers, start in FullColor
     // mode. See comment in autoSelectFormatAndEncoding.
-    if (cp.beforeVersion(3, 8) && autoSelect.getValue())
+    if (server.beforeVersion(3, 8) && autoSelect.getValue())
       fullColor.setParam(true);
 
-    serverPF = cp.pf();
+    serverPF = server.pf();
 
-    desktop = new DesktopWindow(cp.width, cp.height, cp.name(), serverPF, this);
+    desktop = new DesktopWindow(server.width(), server.height(),
+                                server.name(), serverPF, this);
     fullColorPF = desktop.getPreferredPF();
 
     // Force a switch to the format and encoding we'd like
-    formatChange = true; encodingChange = true;
-
-    // And kick off the update cycle
-    requestNewUpdate();
-
-    // This initial update request is a bit of a corner case, so we need
-    // to help out setting the correct format here.
-    assert(pendingPFChange);
-    cp.setPF(pendingPF);
-    pendingPFChange = false;
+    updatePixelFormat();
+    int encNum = Encodings.encodingNum(preferredEncoding.getValue());
+    if (encNum != -1)
+      setPreferredEncoding(encNum);
   }
 
   // setDesktopSize() is called when the desktop size changes (including when
@@ -252,8 +224,8 @@ public class CConn extends CConnection implements
   }
 
   // setExtendedDesktopSize() is a more advanced version of setDesktopSize()
-  public void setExtendedDesktopSize(int reason, int result, int w, int h,
-                                     ScreenSet layout)
+  public void setExtendedDesktopSize(int reason, int result,
+                                     int w, int h, ScreenSet layout)
   {
     super.setExtendedDesktopSize(reason, result, w, h, layout);
 
@@ -299,23 +271,9 @@ public class CConn extends CConnection implements
   // one.
   public void framebufferUpdateStart()
   {
-    ModifiablePixelBuffer pb;
-    PlatformPixelBuffer ppb;
 
     super.framebufferUpdateStart();
 
-    // Note: This might not be true if sync fences are supported
-    pendingUpdate = false;
-
-    requestNewUpdate();
-
-    // We might still be rendering the previous update
-    pb = getFramebuffer();
-    assert(pb != null);
-    ppb = (PlatformPixelBuffer)pb;
-    assert(ppb != null);
-
-    //FIXME
   }
 
   // framebufferUpdateEnd() is called at the end of an update.
@@ -326,23 +284,9 @@ public class CConn extends CConnection implements
   {
     super.framebufferUpdateEnd();
 
-    desktop.updateWindow();
-
-    if (firstUpdate) {
-      // We need fences to make extra update requests and continuous
-      // updates "safe". See fence() for the next step.
-      if (cp.supportsFence)
-        writer().writeFence(fenceTypes.fenceFlagRequest | fenceTypes.fenceFlagSyncNext, 0, null);
+    updateCount++;
 
-      firstUpdate = false;
-    }
-
-    // A format change has been scheduled and we are now past the update
-    // with the old format. Time to active the new one.
-    if (pendingPFChange) {
-      cp.setPF(pendingPF);
-      pendingPFChange = false;
-    }
+    desktop.updateWindow();
 
     // Compute new settings based on updated bandwidth values
     if (autoSelect.getValue())
@@ -382,6 +326,8 @@ public class CConn extends CConnection implements
     super.dataRect(r, encoding);
 
     sock.inStream().stopTiming();
+
+    pixelCount += r.area();
   }
 
   public void setCursor(int width, int height, Point hotspot,
@@ -393,7 +339,7 @@ public class CConn extends CConnection implements
   public void fence(int flags, int len, byte[] data)
   {
     // can't call super.super.fence(flags, len, data);
-    cp.supportsFence = true;
+    server.supportsFence = true;
 
     if ((flags & fenceTypes.fenceFlagRequest) != 0) {
       // We handle everything synchronously so we trivially honor these modes
@@ -402,39 +348,15 @@ public class CConn extends CConnection implements
       writer().writeFence(flags, len, data);
       return;
     }
-
-    if (len == 0) {
-      // Initial probe
-      if ((flags & fenceTypes.fenceFlagSyncNext) != 0) {
-        supportsSyncFence = true;
-
-        if (cp.supportsContinuousUpdates) {
-          vlog.info("Enabling continuous updates");
-          continuousUpdates = true;
-          writer().writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);
-        }
-      }
-    } else {
-      // Pixel format change
-      MemInStream memStream = new MemInStream(data, 0, len);
-      PixelFormat pf = new PixelFormat();
-
-      pf.read(memStream);
-
-      cp.setPF(pf);
-    }
   }
 
   ////////////////////// Internal methods //////////////////////
-  private void resizeFramebuffer()
+  public void resizeFramebuffer()
   {
     if (desktop == null)
       return;
 
-    if (continuousUpdates)
-      writer().writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);
-
-    desktop.resizeFramebuffer(cp.width, cp.height);
+    desktop.resizeFramebuffer(server.width(), server.height());
   }
 
   // autoSelectFormatAndEncoding() chooses the format and encoding appropriate
@@ -456,14 +378,11 @@ public class CConn extends CConnection implements
   {
     long kbitsPerSecond = sock.inStream().kbitsPerSecond();
     long timeWaited = sock.inStream().timeWaited();
-    boolean newFullColor = fullColor.getValue();
+    boolean newFullColour = fullColor.getValue();
     int newQualityLevel = qualityLevel.getValue();
 
     // Always use Tight
-    if (currentEncoding != Encodings.encodingTight) {
-      currentEncoding = Encodings.encodingTight;
-      encodingChange = true;
-    }
+    setPreferredEncoding(Encodings.encodingTight);
 
     // Check that we have a decent bandwidth measurement
     if ((kbitsPerSecond == 0) || (timeWaited < 100))
@@ -479,13 +398,12 @@ public class CConn extends CConnection implements
       if (newQualityLevel != qualityLevel.getValue()) {
         vlog.info("Throughput "+kbitsPerSecond+
                   " kbit/s - changing to quality "+newQualityLevel);
-        cp.qualityLevel = newQualityLevel;
         qualityLevel.setParam(newQualityLevel);
-        encodingChange = true;
+        setQualityLevel(newQualityLevel);
       }
     }
 
-    if (cp.beforeVersion(3, 8)) {
+    if (server.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
@@ -497,83 +415,38 @@ public class CConn extends CConnection implements
     }
 
     // Select best color level
-    newFullColor = (kbitsPerSecond > 256);
-    if (newFullColor != fullColor.getValue()) {
-      vlog.info("Throughput "+kbitsPerSecond+
-                " kbit/s - full color is now "+
-                (newFullColor ? "enabled" : "disabled"));
-      fullColor.setParam(newFullColor);
-      formatChange = true;
-    }
-  }
-
-  // checkEncodings() sends a setEncodings message if one is needed.
-  private void checkEncodings()
-  {
-    if (encodingChange && (writer() != null)) {
-      vlog.info("Using " + Encodings.encodingName(currentEncoding) +
-        " encoding");
-      writer().writeSetEncodings(currentEncoding, true);
-      encodingChange = false;
+    newFullColour = (kbitsPerSecond > 256);
+    if (newFullColour != fullColor.getValue()) {
+      if (newFullColour)
+        vlog.info("Throughput "+kbitsPerSecond+ " kbit/s - full color is now enabled");
+      else
+        vlog.info("Throughput "+kbitsPerSecond+ " kbit/s - full color is now disabled");
+      fullColor.setParam(newFullColour);
+      updatePixelFormat();
     }
   }
 
-  // requestNewUpdate() requests an update from the server, having set the
+  // updatePixelFormat() requests an update from the server, having set the
   // format and encoding appropriately.
-  private void requestNewUpdate()
+  private void updatePixelFormat()
   {
-    if (formatChange) {
-      PixelFormat pf;
-
-      /* Catch incorrect requestNewUpdate calls */
-      assert(!pendingUpdate || supportsSyncFence);
-
-      if (fullColor.getValue()) {
-        pf = fullColorPF;
-      } else {
-        if (lowColorLevel.getValue() == 0) {
-          pf = verylowColorPF;
-        } else if (lowColorLevel.getValue() == 1) {
-          pf = lowColorPF;
-        } else {
-          pf = mediumColorPF;
-        }
-      }
-
-      if (supportsSyncFence) {
-        // We let the fence carry the pixel format and switch once we
-        // get the response back. That way we will be synchronised with
-        // when the server switches.
-        MemOutStream memStream = new MemOutStream();
-
-        pf.write(memStream);
+    PixelFormat pf;
 
-        writer().writeFence(fenceTypes.fenceFlagRequest | fenceTypes.fenceFlagSyncNext,
-                            memStream.length(), (byte[])memStream.data());
+    if (fullColor.getValue()) {
+      pf = fullColorPF;
+    } else {
+      if (lowColorLevel.getValue() == 0) {
+        pf = verylowColorPF;
+      } else if (lowColorLevel.getValue() == 1) {
+        pf = lowColorPF;
       } else {
-        // New requests are sent out at the start of processing the last
-        // one, so we cannot switch our internal format right now (doing so
-        // would mean misdecoding the current update).
-        pendingPFChange = true;
-        pendingPF = pf;
+        pf = mediumColorPF;
       }
-
-      String str = pf.print();
-      vlog.info("Using pixel format " + str);
-      writer().writeSetPixelFormat(pf);
-
-      formatChange = false;
-    }
-
-    checkEncodings();
-
-    if (forceNonincremental || !continuousUpdates) {
-      pendingUpdate = true;
-      writer().writeFramebufferUpdateRequest(new Rect(0, 0, cp.width, cp.height),
-                                                 !forceNonincremental);
     }
 
-    forceNonincremental = false;
+    String str = pf.print();
+    vlog.info("Using pixel format " + str);
+    setPF(pf);
   }
 
   public void handleOptions()
@@ -587,48 +460,20 @@ public class CConn extends CConnection implements
       int encNum = Encodings.encodingNum(preferredEncoding.getValue());
 
       if (encNum != -1)
-        this.currentEncoding = encNum;
+        this.setPreferredEncoding(encNum);
     }
 
-    this.cp.supportsLocalCursor = true;
-
     if (customCompressLevel.getValue())
-      this.cp.compressLevel = compressLevel.getValue();
+      this.setCompressLevel(compressLevel.getValue());
     else
-      this.cp.compressLevel = -1;
+      this.setCompressLevel(-1);
 
     if (!noJpeg.getValue() && !autoSelect.getValue())
-      this.cp.qualityLevel = qualityLevel.getValue();
+      this.setQualityLevel(qualityLevel.getValue());
     else
-      this.cp.qualityLevel = -1;
-
-    this.encodingChange = true;
-
-    // Format changes refreshes the entire screen though and are therefore
-    // very costly. It's probably worth the effort to see if it is necessary
-    // here.
-    PixelFormat pf;
-
-    if (fullColor.getValue()) {
-      pf = fullColorPF;
-    } else {
-      if (lowColorLevel.getValue() == 0)
-        pf = verylowColorPF;
-      else if (lowColorLevel.getValue() == 1)
-        pf = lowColorPF;
-      else
-        pf = mediumColorPF;
-    }
-
-    if (!pf.equal(this.cp.pf())) {
-      this.formatChange = true;
-
-      // Without fences, we cannot safely trigger an update request directly
-      // but must wait for the next update to arrive.
-      if (this.supportsSyncFence)
-        this.requestNewUpdate();
-    }
+      this.setQualityLevel(-1);
 
+    this.updatePixelFormat();
   }
 
   ////////////////////////////////////////////////////////////////////
@@ -654,7 +499,7 @@ public class CConn extends CConnection implements
 
   // writeClientCutText() is called from the clipboard dialog
   public void writeClientCutText(String str, int len) {
-    if (state() != RFBSTATE_NORMAL || shuttingDown)
+    if ((state() != stateEnum.RFBSTATE_NORMAL) || shuttingDown)
       return;
     writer().writeClientCutText(str, len);
   }
@@ -698,24 +543,13 @@ public class CConn extends CConnection implements
 
   protected DesktopWindow desktop;
 
+  private int updateCount;
+  private int pixelCount;
+
   private PixelFormat serverPF;
   private PixelFormat fullColorPF;
 
-  private boolean pendingPFChange;
-  private PixelFormat pendingPF;
-
-  private int currentEncoding, lastServerEncoding;
-
-  private boolean formatChange;
-  private boolean encodingChange;
-
-  private boolean firstUpdate;
-  private boolean pendingUpdate;
-  private boolean continuousUpdates;
-
-  private boolean forceNonincremental;
-
-  private boolean supportsSyncFence;
+  private int lastServerEncoding;
 
   public ActionListener closeListener = null;
 
index 42ecad8a0c313fa30414be1c22cd33e128516a87..416031f28d0433be5573eaa848408080dbbae093 100644 (file)
@@ -129,7 +129,7 @@ public class DesktopWindow extends JFrame
             // c) We're not still waiting for a chance to handle DesktopSize
             // d) We're not still waiting for startup fullscreen to kick in
             if (!firstUpdate && !delayedFullscreen &&
-                remoteResize.getValue() && cc.cp.supportsSetDesktopSize)
+                remoteResize.getValue() && cc.server.supportsSetDesktopSize)
               timer.start();
         } else {
           String scaleString = scalingFactor.getValue();
@@ -233,7 +233,7 @@ public class DesktopWindow extends JFrame
           setExtendedState(JFrame.MAXIMIZED_BOTH);
       }
 
-      if (cc.cp.supportsSetDesktopSize && !desktopSize.getValue().equals("")) {
+      if (cc.server.supportsSetDesktopSize && !desktopSize.getValue().equals("")) {
         // Hack: Wait until we're in the proper mode and position until
         // resizing things, otherwise we might send the wrong thing.
         if (delayedFullscreen)
@@ -354,7 +354,7 @@ public class DesktopWindow extends JFrame
       // to scroll) we just report a single virtual screen that covers
       // the entire framebuffer.
 
-      layout = cc.cp.screenLayout;
+      layout = cc.server.screenLayout();
 
       // Not sure why we have no screens, but adding a new one should be
       // safe as there is nothing to conflict with...
@@ -418,8 +418,8 @@ public class DesktopWindow extends JFrame
           sy -= viewport_rect.tl.y;
 
           // Look for perfectly matching existing screen...
-          for (iter = cc.cp.screenLayout.begin();
-              iter != cc.cp.screenLayout.end(); iter.next()) {
+          for (iter = cc.server.screenLayout().begin();
+              iter != cc.server.screenLayout().end(); iter.next()) {
             Screen screen = iter.next(); iter.previous();
             if ((screen.dimensions.tl.x == sx) &&
                 (screen.dimensions.tl.y == sy) &&
@@ -429,7 +429,7 @@ public class DesktopWindow extends JFrame
           }
 
           // Found it?
-          if (iter != cc.cp.screenLayout.end()) {
+          if (iter != cc.server.screenLayout().end()) {
             layout.add_screen(iter.next());
             continue;
           }
@@ -438,14 +438,14 @@ public class DesktopWindow extends JFrame
           Random rng = new Random();
           while (true) {
             id = rng.nextInt();
-            for (iter = cc.cp.screenLayout.begin();
-                iter != cc.cp.screenLayout.end(); iter.next()) {
+            for (iter = cc.server.screenLayout().begin();
+                iter != cc.server.screenLayout().end(); iter.next()) {
               Screen screen = iter.next(); iter.previous();
               if (screen.id == id)
                 break;
             }
 
-            if (iter == cc.cp.screenLayout.end())
+            if (iter == cc.server.screenLayout().end())
               break;
           }
 
@@ -460,14 +460,14 @@ public class DesktopWindow extends JFrame
     }
 
     // Do we actually change anything?
-    if ((width == cc.cp.width) &&
-        (height == cc.cp.height) &&
-        (layout == cc.cp.screenLayout))
+    if ((width == cc.server.width()) &&
+        (height == cc.server.height()) &&
+        (layout == cc.server.screenLayout()))
       return;
 
     String buffer;
     vlog.debug(String.format("Requesting framebuffer resize from %dx%d to %dx%d",
-               cc.cp.width, cc.cp.height, width, height));
+               cc.server.width(), cc.server.height(), width, height));
     layout.debug_print();
 
     if (!layout.validate(width, height)) {
@@ -592,7 +592,7 @@ public class DesktopWindow extends JFrame
         if (scaleString.matches("^[0-9]+$")) {
           scroll.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
           scroll.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
-          viewport.setScaledSize(cc.cp.width, cc.cp.height);
+          viewport.setScaledSize(cc.server.width(), cc.server.height());
         } else {
           scroll.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
           scroll.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
index c2847a86030c637f34cdd532334195d30d96ecaf..f0d4cb00bc1624296ec75282c597144cb5bd50c9 100644 (file)
@@ -1606,7 +1606,7 @@ class OptionsDialog extends Dialog {
   private void handleRfbState()
   {
     CConn cc = VncViewer.cc;
-    if (cc != null && cc.state() == CConnection.RFBSTATE_NORMAL) {
+    if (cc != null && cc.state() == CConnection.stateEnum.RFBSTATE_NORMAL) {
       JComponent[] components = {
           encNoneCheckbox, encTLSCheckbox, encX509Checkbox, authNoneCheckbox,
           authVncCheckbox, authVncCheckbox, authIdentCheckbox, authPlainCheckbox,
index 1ce411c5fd6c0d155fee672f2849da3471dc944e..1f21beef9e204eaa248587086467e2e128ee5102 100644 (file)
@@ -135,8 +135,8 @@ class Viewport extends JPanel implements ActionListener {
   public void updateWindow() {
     Rect r = frameBuffer.getDamage();
     if (!r.is_empty()) {
-      if (cc.cp.width != scaledWidth ||
-          cc.cp.height != scaledHeight) {
+      if (cc.server.width() != scaledWidth ||
+          cc.server.height() != scaledHeight) {
         AffineTransform t = new AffineTransform(); 
         t.scale((double)scaleRatioX, (double)scaleRatioY);
         Rectangle s = new Rectangle(r.tl.x, r.tl.y, r.width(), r.height());
@@ -309,8 +309,8 @@ class Viewport extends JPanel implements ActionListener {
   public void paintComponent(Graphics g) {
     Graphics2D g2 = (Graphics2D)g;
     synchronized(frameBuffer.getImage()) {
-      if (cc.cp.width != scaledWidth ||
-          cc.cp.height != scaledHeight) {
+      if (cc.server.width() != scaledWidth ||
+          cc.server.height() != scaledHeight) {
         g2.setRenderingHint(RenderingHints.KEY_RENDERING,
                             RenderingHints.VALUE_RENDER_QUALITY);
         g2.drawImage(frameBuffer.getImage(), 0, 0,
@@ -342,14 +342,14 @@ class Viewport extends JPanel implements ActionListener {
         scaledWidth = width;
         scaledHeight = height;
       } else {
-        float widthRatio = (float)width / (float)cc.cp.width;
-        float heightRatio = (float)height / (float)cc.cp.height;
+        float widthRatio = (float)width / (float)cc.server.width();
+        float heightRatio = (float)height / (float)cc.server.height();
         float ratio = Math.min(widthRatio, heightRatio);
-        scaledWidth = (int)Math.floor(cc.cp.width * ratio);
-        scaledHeight = (int)Math.floor(cc.cp.height * ratio);
+        scaledWidth = (int)Math.floor(cc.server.width() * ratio);
+        scaledHeight = (int)Math.floor(cc.server.height() * ratio);
       }
-      scaleRatioX = (float)scaledWidth / (float)cc.cp.width;
-      scaleRatioY = (float)scaledHeight / (float)cc.cp.height;
+      scaleRatioX = (float)scaledWidth / (float)cc.server.width();
+      scaleRatioY = (float)scaledHeight / (float)cc.server.height();
     }
     if (scaledWidth != getWidth() || scaledHeight != getHeight())
       setSize(new Dimension(scaledWidth, scaledHeight));
@@ -360,15 +360,15 @@ class Viewport extends JPanel implements ActionListener {
     if (!viewOnly.getValue()) {
       if (buttonMask != lastButtonMask || !pos.equals(lastPointerPos)) {
         try {
-          if (cc.cp.width != scaledWidth ||
-              cc.cp.height != scaledHeight) {
+          if (cc.server.width() != scaledWidth ||
+              cc.server.height() != scaledHeight) {
             int sx = (scaleRatioX == 1.00) ?
               pos.x : (int)Math.floor(pos.x / scaleRatioX);
             int sy = (scaleRatioY == 1.00) ?
               pos.y : (int)Math.floor(pos.y / scaleRatioY);
             pos = pos.translate(new Point(sx - pos.x, sy - pos.y));
           }
-          cc.writer().pointerEvent(pos, buttonMask);
+          cc.writer().writePointerEvent(pos, buttonMask);
         } catch (Exception e) {
           vlog.error("%s", e.getMessage());
           cc.close();
@@ -430,8 +430,8 @@ class Viewport extends JPanel implements ActionListener {
           downKeySym.containsValue(XK_Alt_R)) {
         vlog.debug("Faking release of AltGr (Ctrl_L+Alt_R)");
         try {
-          cc.writer().keyEvent(XK_Control_L, false);
-          cc.writer().keyEvent(XK_Alt_R, false);
+          cc.writer().writeKeyEvent(XK_Control_L, false);
+          cc.writer().writeKeyEvent(XK_Alt_R, false);
         } catch (Exception e) {
           vlog.error("%s", e.getMessage());
           cc.close();
@@ -450,9 +450,9 @@ class Viewport extends JPanel implements ActionListener {
     try {
       // Fake keycode?
       if (keyCode > 0xffff)
-        cc.writer().keyEvent(keySym, true);
+        cc.writer().writeKeyEvent(keySym, true);
       else
-        cc.writer().keyEvent(keySym, true);
+        cc.writer().writeKeyEvent(keySym, true);
     } catch (Exception e) {
       vlog.error("%s", e.getMessage());
       cc.close();
@@ -464,8 +464,8 @@ class Viewport extends JPanel implements ActionListener {
           downKeySym.containsValue(XK_Alt_R)) {
         vlog.debug("Restoring AltGr state");
         try {
-          cc.writer().keyEvent(XK_Control_L, true);
-          cc.writer().keyEvent(XK_Alt_R, true);
+          cc.writer().writeKeyEvent(XK_Control_L, true);
+          cc.writer().writeKeyEvent(XK_Alt_R, true);
         } catch (Exception e) {
           vlog.error("%s", e.getMessage());
           cc.close();
@@ -493,9 +493,9 @@ class Viewport extends JPanel implements ActionListener {
 
     try {
       if (keyCode > 0xffff)
-        cc.writer().keyEvent(iter, false);
+        cc.writer().writeKeyEvent(iter, false);
       else
-        cc.writer().keyEvent(iter, false);
+        cc.writer().writeKeyEvent(iter, false);
     } catch (Exception e) {
       vlog.error("%s", e.getMessage());
       cc.close();
@@ -773,7 +773,7 @@ class Viewport extends JPanel implements ActionListener {
   {
     setMenuKey();
     /*
-    setScaledSize(cc.cp.width, cc.cp.height);
+    setScaledSize(cc.server.width(), cc.server.height());
     if (!oldSize.equals(new Dimension(scaledWidth, scaledHeight))) {
     // Re-layout the DesktopWindow when the scaled size changes.
     // Ideally we'd do this with a ComponentListener, but unfortunately