]> source.dussan.org Git - tigervnc.git/commitdiff
Adds support for fence & continuous updates extensions to java viewer. Adds low...
authorBrian Hinz <bphinz@users.sourceforge.net>
Sun, 12 Feb 2012 20:44:29 +0000 (20:44 +0000)
committerBrian Hinz <bphinz@users.sourceforge.net>
Sun, 12 Feb 2012 20:44:29 +0000 (20:44 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4847 3789f03b-4d11-0410-bbf8-ca57d06f2519

18 files changed:
java/com/tigervnc/network/SocketDescriptor.java
java/com/tigervnc/rdr/Exception.java
java/com/tigervnc/rdr/MemInStream.java
java/com/tigervnc/rdr/MemOutStream.java
java/com/tigervnc/rfb/CMsgHandler.java
java/com/tigervnc/rfb/CMsgReaderV3.java
java/com/tigervnc/rfb/CMsgWriter.java
java/com/tigervnc/rfb/CMsgWriterV3.java
java/com/tigervnc/rfb/ConnParams.java
java/com/tigervnc/rfb/Encodings.java
java/com/tigervnc/rfb/JpegCompressor.java [new file with mode: 0644]
java/com/tigervnc/rfb/MsgTypes.java
java/com/tigervnc/rfb/PixelBuffer.java
java/com/tigervnc/rfb/fenceTypes.java [new file with mode: 0644]
java/com/tigervnc/vncviewer/CConn.java
java/com/tigervnc/vncviewer/DesktopWindow.java
java/com/tigervnc/vncviewer/PixelBufferImage.java
java/com/tigervnc/vncviewer/VncViewer.java

index 1998ca5b246d8efc7df2da043588721f1713ae13..d4970c61deedb5eb183c646e268e83122bbf0365 100644 (file)
@@ -49,7 +49,7 @@ public class SocketDescriptor extends SocketChannel
     }
   }
 
-  public int read(byte[] buf, int bufPtr, int length) throws Exception {
+  synchronized public int read(byte[] buf, int bufPtr, int length) throws Exception {
     int n;
     ByteBuffer b = ByteBuffer.allocate(length);
     try {
@@ -66,7 +66,7 @@ public class SocketDescriptor extends SocketChannel
 
   }
 
-  public int write(byte[] buf, int bufPtr, int length) throws Exception {
+  synchronized public int write(byte[] buf, int bufPtr, int length) throws Exception {
     int n;
     ByteBuffer b = ByteBuffer.allocate(length);
     b.put(buf, bufPtr, length);
@@ -80,7 +80,7 @@ public class SocketDescriptor extends SocketChannel
     return n;
   }
 
-  public int select(int interestOps, int timeout) throws Exception {
+  synchronized public int select(int interestOps, int timeout) throws Exception {
     int n;
     try {
       n = selector.select(timeout);
index a2f8833d364b7db9dec802694ad270c4a53e8031..2187685ea9d45aed511abdbe387deaad60d0cb81 100644 (file)
@@ -21,6 +21,7 @@ package com.tigervnc.rdr;
 public class Exception extends RuntimeException {
   public Exception(String s) {
     super(s);
+    System.out.println(s);
   }
 }
 
index 32911a3a78690a57fc7f080b59f119a2cce3b11e..6a768aad3c16934418dcf723c130d217b8c4a3b8 100644 (file)
@@ -22,13 +22,17 @@ public class MemInStream extends InStream {
 
   public MemInStream(byte[] data, int offset, int len) {
     b = data;
-    ptr = offset;
-    end = offset + len;
+    start = offset;    
+    ptr = start;
+    end = start + len;
   }
 
   public int pos() { return ptr; }
+  public void reposition(int pos) { ptr = start + pos; }
 
   protected int overrun(int itemSize, int nItems, boolean wait) {
     throw new EndOfStream();
   }
+
+  int start;
 }
index b30407931969220c2369922e0c60816d9f40bd07..4d654a2bed06f1677b26be45503b03aab8c79e14 100644 (file)
@@ -35,6 +35,10 @@ public class MemOutStream extends OutStream {
   public void clear() { ptr = 0; };
   public void reposition(int pos) { ptr = pos; }
 
+  // data() returns a pointer to the buffer.
+
+  public final byte[] data() { return b; }
+
   // overrun() either doubles the buffer or adds enough space for nItems of
   // size itemSize bytes.
 
index 311820035307f81a42e893f93378a75001bfc77d..533bfbc2aec037287393d828c2f14e85771f22a7 100644 (file)
@@ -61,6 +61,16 @@ abstract public class CMsgHandler {
     cp.setName(name);
   }
 
+  public void fence(int flags, int len, byte[] data) 
+  {
+    cp.supportsFence = true;
+  }
+
+  public void endOfContinuousUpdates() 
+  {
+    cp.supportsContinuousUpdates = true;
+  }
+
   public void clientRedirect(int port, String host, 
                              String x509subject) {}
 
index 6d9e254b4d66d332aa01a1dcc6b1d031dfe2e3d8..915b1e01965f06fceaf782ecfdad10c74c37be6b 100644 (file)
@@ -51,6 +51,8 @@ public class CMsgReaderV3 extends CMsgReader {
       case MsgTypes.msgTypeSetColourMapEntries: readSetColourMapEntries(); break;
       case MsgTypes.msgTypeBell:                readBell(); break;
       case MsgTypes.msgTypeServerCutText:       readServerCutText(); break;
+      case MsgTypes.msgTypeServerFence:         readFence(); break;
+      case MsgTypes.msgTypeEndOfContinuousUpdates:  readEndOfContinuousUpdates(); break;
       default:
         vlog.error("unknown message type "+type);
         throw new Exception("unknown message type");
@@ -136,6 +138,33 @@ public class CMsgReaderV3 extends CMsgReader {
     handler.setExtendedDesktopSize(x, y, w, h, layout);
   }
 
+  void readFence()
+  {
+    int flags;
+    int len;
+    byte[] data = new byte[64];
+  
+    is.skip(3);
+  
+    flags = is.readU32();
+  
+    len = is.readU8();
+    if (len > data.length) {
+      System.out.println("Ignoring fence with too large payload\n");
+      is.skip(len);
+      return;
+    }
+  
+    is.readBytes(data, 0, len);
+    
+    handler.fence(flags, len, data);
+  }
+  
+  void readEndOfContinuousUpdates()
+  {
+    handler.endOfContinuousUpdates();
+  }
+
   void readClientRedirect(int x, int y, int w, int h) 
   {
     int port = is.readU16();
index 7cafddde17097daf9e311a8f9d6b6f269b29aa79..c4f43554d17ae358df942f4940f30c7ec7f65b1e 100644 (file)
@@ -59,9 +59,16 @@ abstract public class CMsgWriter {
       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;
     }
index ec30a826b63c4cc618ccffc4a79c51ab77bd3e7d..430c374689d1cffb85a1f80ef44ada35027da5fa 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2009-2011 Pierre Ossman for Cendio AB
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -65,4 +66,42 @@ public class CMsgWriterV3 extends CMsgWriter {
        
          endMsg();
        }
+
+  public void writeFence(int flags, int len, byte[] data)
+  {
+    if (!cp.supportsFence)
+      throw new Exception("Server does not support fences");
+    if (len > 64)
+      throw new Exception("Too large fence payload");
+    if ((flags & ~fenceTypes.fenceFlagsSupported) != 0)
+      throw new Exception("Unknown fence flags");
+  
+    startMsg(MsgTypes.msgTypeClientFence);
+    os.pad(3);
+  
+    os.writeU32(flags);
+  
+    os.writeU8(len);
+    os.writeBytes(data, 0, len);
+  
+    endMsg();
+  }
+  
+  public void writeEnableContinuousUpdates(boolean enable,
+                                           int x, int y, int w, int h)
+  {
+    if (!cp.supportsContinuousUpdates)
+      throw new Exception("Server does not support continuous updates");
+  
+    startMsg(MsgTypes.msgTypeEnableContinuousUpdates);
+  
+    os.writeU8((enable?1:0));
+  
+    os.writeU16(x);
+    os.writeU16(y);
+    os.writeU16(w);
+    os.writeU16(h);
+  
+    endMsg();
+  }
 }
index 70d6114f925260cc62e4d9a955b19b1168b39016..7fac12608e73842fa66133a0248f22be3a07832c 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2012 TigerVNC Team.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,9 +30,12 @@ public class ConnParams {
     supportsLocalCursor = false; supportsLocalXCursor = false;
     supportsDesktopResize = false; supportsExtendedDesktopSize = false;
     supportsDesktopRename = false; supportsLastRect = false;
-    supportsSetDesktopSize = false; supportsClientRedirect = false;
+    supportsSetDesktopSize = false; supportsFence = false;
+    supportsContinuousUpdates = false;
+    supportsClientRedirect = false;
     customCompressLevel = false; compressLevel = 6;
-    noJpeg = false; qualityLevel = -1; 
+    noJpeg = false; qualityLevel = -1; fineQualityLevel = -1;
+    subsampling = "SUBSAMP_UNDEFINED";
     name_ = null; nEncodings_ = 0; encodings_ = null;
     currentEncoding_ = Encodings.encodingRaw; verStrPos = 0;
     screenLayout = new ScreenSet();
@@ -115,20 +119,38 @@ public class ConnParams {
     useCopyRect = false;
     supportsLocalCursor = false;
     supportsDesktopResize = false;
+    supportsExtendedDesktopSize = false;
+    supportsLocalXCursor = false;
+    supportsLastRect = false;
     customCompressLevel = false;
     compressLevel = -1;
     noJpeg = true;
     qualityLevel = -1;
+    fineQualityLevel = -1;
+    subsampling = "SUBSAMP_UNDEFINED";
     currentEncoding_ = Encodings.encodingRaw;
 
     for (int i = nEncodings-1; i >= 0; i--) {
       encodings_[i] = encodings[i];
+
       if (encodings[i] == Encodings.encodingCopyRect)
         useCopyRect = true;
       else if (encodings[i] == Encodings.pseudoEncodingCursor)
         supportsLocalCursor = true;
+      else if (encodings[i] == Encodings.pseudoEncodingXCursor)
+        supportsLocalXCursor = true;
       else if (encodings[i] == Encodings.pseudoEncodingDesktopSize)
         supportsDesktopResize = true;
+      else if (encodings[i] == Encodings.pseudoEncodingExtendedDesktopSize)
+        supportsExtendedDesktopSize = true;
+      else if (encodings[i] == Encodings.pseudoEncodingDesktopName)
+        supportsDesktopRename = true;
+      else if (encodings[i] == Encodings.pseudoEncodingLastRect)
+        supportsLastRect = true;
+      else if (encodings[i] == Encodings.pseudoEncodingFence)
+        supportsFence = true;
+      else if (encodings[i] == Encodings.pseudoEncodingContinuousUpdates)
+        supportsContinuousUpdates = true;
       else if (encodings[i] == Encodings.pseudoEncodingClientRedirect)
         supportsClientRedirect = true;
       else if (encodings[i] >= Encodings.pseudoEncodingCompressLevel0 &&
@@ -143,6 +165,20 @@ public class ConnParams {
                Encoder.supported(encodings[i]))
         currentEncoding_ = encodings[i];
     }
+
+    // If the TurboVNC fine quality/subsampling encodings exist, let them
+    // override the coarse TightVNC quality level
+    for (int i = nEncodings-1; i >= 0; i--) {
+      if (encodings[i] >= Encodings.pseudoEncodingFineQualityLevel0 + 1 &&
+          encodings[i] <= Encodings.pseudoEncodingFineQualityLevel100) {
+        noJpeg = false;
+        fineQualityLevel = encodings[i] - Encodings.pseudoEncodingFineQualityLevel0;
+      } else if (encodings[i] >= Encodings.pseudoEncodingSubsamp1X &&
+                 encodings[i] <= Encodings.pseudoEncodingSubsampGray) {
+        noJpeg = false;
+        subsampling = JpegCompressor.subsamplingName(encodings[i] - Encodings.pseudoEncodingSubsamp1X);
+      }
+    }
   }
   public boolean useCopyRect;
 
@@ -152,6 +188,8 @@ public class ConnParams {
   public boolean supportsExtendedDesktopSize;
   public boolean supportsDesktopRename;
   public boolean supportsClientRedirect;
+  public boolean supportsFence;
+  public boolean supportsContinuousUpdates;
   public boolean supportsLastRect;
 
   public boolean supportsSetDesktopSize;
@@ -160,6 +198,8 @@ public class ConnParams {
   public int compressLevel;
   public boolean noJpeg;
   public int qualityLevel;
+  public int fineQualityLevel;
+  public String subsampling;
 
   private PixelFormat pf_;
   private String name_;
index 493d54880cb50329728bac217bba8784763d06f9..4dc129f4de0df5b3d8a8835c8f33b8b1f7c7796e 100644 (file)
@@ -1,4 +1,6 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
+ * Copyright (C) 2012 TigerVNC Team.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,6 +38,8 @@ public class Encodings {
   public static final int pseudoEncodingExtendedDesktopSize = -308;
   public static final int pseudoEncodingDesktopName = -307;
   public static final int pseudoEncodingClientRedirect = -311;
+  public static final int pseudoEncodingFence = -312;
+  public static final int pseudoEncodingContinuousUpdates = -313;
 
   // TightVNC-specific
   public static final int pseudoEncodingLastRect = -224;
@@ -44,6 +48,16 @@ public class Encodings {
   public static final int pseudoEncodingCompressLevel0 = -256;
   public static final int pseudoEncodingCompressLevel9 = -247;
 
+  // TurboVNC-specific
+  public static final int pseudoEncodingFineQualityLevel0 = -512;
+  public static final int pseudoEncodingFineQualityLevel100 = -412;
+  public static final int pseudoEncodingSubsamp1X = -768;
+  public static final int pseudoEncodingSubsamp4X = -767;
+  public static final int pseudoEncodingSubsamp2X = -766;
+  public static final int pseudoEncodingSubsampGray = -765;
+  public static final int pseudoEncodingSubsamp8X = -764;
+  public static final int pseudoEncodingSubsamp16X = -763;
+
   public static int encodingNum(String name) {
     if (name.equalsIgnoreCase("raw"))      return encodingRaw;
     if (name.equalsIgnoreCase("copyRect")) return encodingCopyRect;
diff --git a/java/com/tigervnc/rfb/JpegCompressor.java b/java/com/tigervnc/rfb/JpegCompressor.java
new file mode 100644 (file)
index 0000000..929aa4e
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011 D. R. Commander.  All Rights Reserved.
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+package com.tigervnc.rfb;
+
+public class JpegCompressor {
+  
+  public static final int SUBSAMP_UNDEFINED = -1;
+  public static final int SUBSAMP_NONE = 0;
+  public static final int SUBSAMP_420 = 1;
+  public static final int SUBSAMP_422 = 2;
+  public static final int SUBSAMP_GRAY = 3;
+  
+  public static int subsamplingNum(String name) {
+    if (name.equalsIgnoreCase("SUBSAMP_UNDEFINED")) return SUBSAMP_UNDEFINED;
+    if (name.equalsIgnoreCase("SUBSAMP_NONE"))      return SUBSAMP_NONE;
+    if (name.equalsIgnoreCase("SUBSAMP_420"))       return SUBSAMP_420;
+    if (name.equalsIgnoreCase("SUBSAMP_422"))       return SUBSAMP_422;
+    if (name.equalsIgnoreCase("SUBSAMP_GRAY"))      return SUBSAMP_GRAY;
+    return SUBSAMP_UNDEFINED;
+  }
+
+  public static String subsamplingName(int num) {
+    switch (num) {
+    case SUBSAMP_UNDEFINED: return "SUBSAMP_UNDEFINED";
+    case SUBSAMP_NONE:      return "SUBSAMP_NONE";
+    case SUBSAMP_420:       return "SUBSAMP_420";
+    case SUBSAMP_422:       return "SUBSAMP_422";
+    case SUBSAMP_GRAY:      return "SUBSAMP_GRAY";
+    default:                return "SUBSAMP_UNDEFINED";
+    }
+  }
+}
index a009b39649f3975fffcb4f2deb8af608e1542155..2d452c81dca51203330d2a0524e0ecd6862c9072 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2012 TigerVNC Team.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,6 +27,10 @@ public class MsgTypes {
   public static final int msgTypeBell = 2;
   public static final int msgTypeServerCutText = 3;
 
+  public static final int msgTypeEndOfContinuousUpdates = 150;
+
+  public static final int msgTypeServerFence = 248;
+
   // client to server
 
   public static final int msgTypeSetPixelFormat = 0;
@@ -36,5 +41,9 @@ public class MsgTypes {
   public static final int msgTypePointerEvent = 5;
   public static final int msgTypeClientCutText = 6;
 
+  public static final int msgTypeEnableContinuousUpdates = 150;
+
+  public static final int msgTypeClientFence = 248;
+
   public static final int msgTypeSetDesktopSize = 251;
 }
index 2712ba94411418c7d863ac0abaec19fe447c493c..43713550ed1944a67431dbba6a0d61db75e8119d 100644 (file)
@@ -36,9 +36,17 @@ public class PixelBuffer {
       throw new Exception("Internal error: bpp must be 8, 16, or 32 in PixelBuffer ("+pf.bpp+")");
     format = pf;
     switch (pf.depth) {
+    case  3: 
+      // Fall-through to depth 8
+    case  6: 
+      // Fall-through to depth 8
     case  8: 
-      //cm = new IndexColorModel(8, 256, new byte[256], new byte[256], new byte[256]);
-      cm = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
+      int rmask = pf.redMax << pf.redShift;
+      int gmask = pf.greenMax << pf.greenShift;
+      int bmask = pf.blueMax << pf.blueShift;
+      cm = new DirectColorModel(8, rmask, gmask, bmask);
+      if (pf.depth == 8 && !pf.trueColour)
+        cm = new IndexColorModel(8, 256, new byte[256], new byte[256], new byte[256]);
       break;
     case 16: 
       cm = new DirectColorModel(32, 0xF800, 0x07C0, 0x003E, (0xff << 24));
diff --git a/java/com/tigervnc/rfb/fenceTypes.java b/java/com/tigervnc/rfb/fenceTypes.java
new file mode 100644 (file)
index 0000000..a8e32d3
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright 2011 Pierre Ossman for Cendio AB
+ * 
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ * USA.
+ */
+package com.tigervnc.rfb;
+
+public class fenceTypes {
+  public static final int fenceFlagBlockBefore = 1<<0;
+  public static final int fenceFlagBlockAfter  = 1<<1;
+  public static final int fenceFlagSyncNext    = 1<<2;
+
+  public static final int fenceFlagRequest     = 1<<31;
+
+  public static final int fenceFlagsSupported  = (fenceFlagBlockBefore |
+                                                  fenceFlagBlockAfter |
+                                                  fenceFlagSyncNext |
+                                                  fenceFlagRequest);
+}
index fd8bb624fb64ddb81d1e8130efb16e02bcc26ddc..8c45ecd8e3de66e5feb95a7b7aa9e74e804c65e0 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2012 TigerVNC Team
+ * Copyright (C) 2011-2012 TigerVNC Team
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -147,27 +147,38 @@ class ViewportFrame extends JFrame
 public class CConn extends CConnection
   implements UserPasswdGetter, UserMsgBox, OptionsDialogCallback, FdInStreamBlockCallback
 {
+
+  public final PixelFormat getPreferredPF() { return fullColourPF; }
+  static final PixelFormat verylowColourPF = 
+    new PixelFormat(8, 3, false, true, 1, 1, 1, 2, 1, 0);
+  static final PixelFormat lowColourPF = 
+    new PixelFormat(8, 6, false, true, 3, 3, 3, 4, 2, 0);
+  static final PixelFormat mediumColourPF = 
+    new PixelFormat(8, 8, false, false, 7, 7, 3, 0, 3, 6);
+
   ////////////////////////////////////////////////////////////////////
   // The following methods are all called from the RFB thread
 
   public CConn(VncViewer viewer_, Socket sock_, 
-               String vncServerName, boolean reverse
+               String vncServerName) 
   {
     serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_; 
+    pendingPFChange = false;
     currentEncoding = Encodings.encodingTight; lastServerEncoding = -1;
     fullColour = viewer.fullColour.getValue();
     lowColourLevel = 2;
     autoSelect = viewer.autoSelect.getValue();
-    shared = viewer.shared.getValue(); formatChange = false;
-    encodingChange = false; sameMachine = false;
+    formatChange = false; encodingChange = false;
     fullScreen = viewer.fullScreen.getValue();
     menuKey = Keysyms.F8;
     options = new OptionsDialog(this);
     options.initDialog();
     clipboardDialog = new ClipboardDialog(this);
-    firstUpdate = true; pendingUpdate = false;
+    firstUpdate = true; pendingUpdate = false; continuousUpdates = false; 
+    forceNonincremental = true; supportsSyncFence = false;
+    
 
-    setShared(shared);
+    setShared(viewer.shared.getValue());
     upg = this;
     msg = this;
 
@@ -212,13 +223,23 @@ public class CConn extends CConnection
       vlog.info("connected to host "+serverHost+" port "+serverPort);
     }
 
-    sameMachine = sock.sameMachine();
     sock.inStream().setBlockCallback(this);
     setServerName(serverHost);
     setStreams(sock.inStream(), sock.outStream());
     initialiseProtocol();
   }
 
+  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 boolean showMsgBox(int flags, String title, String text)
   {
     //StringBuffer titleText = new StringBuffer("VNC Viewer: "+title);
@@ -308,20 +329,28 @@ public class CConn extends CConnection
 
     // If using AutoSelect with old servers, start in FullColor
     // mode. See comment in autoSelectFormatAndEncoding. 
-    if (cp.beforeVersion(3, 8) && autoSelect) {
+    if (cp.beforeVersion(3, 8) && autoSelect)
       fullColour = true;
-    }
 
     serverPF = cp.pf();
+
     desktop = new DesktopWindow(cp.width, cp.height, serverPF, this);
-    //desktopEventHandler = desktop.setEventHandler(this);
-    //desktop.addEventMask(KeyPressMask | KeyReleaseMask);
     fullColourPF = desktop.getPreferredPF();
-    if (!serverPF.trueColour)
-      fullColour = true;
-    recreateViewport();
+
+    // 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);
+    desktop.setServerPF(pendingPF);
+    cp.setPF(pendingPF);
+    pendingPFChange = false;
+
+    recreateViewport();
   }
 
   // setDesktopSize() is called when the desktop size changes (including when
@@ -372,26 +401,34 @@ public class CConn extends CConnection
   // framebufferUpdateStart() is called at the beginning of an update.
   // Here we try to send out a new framebuffer update request so that the
   // next update can be sent out in parallel with us decoding the current
-  // one. We cannot do this if we're in the middle of a format change
-  // though.
-  public void framebufferUpdateStart() {
-    if (!formatChange) {
-      pendingUpdate = true;
-      requestNewUpdate();
-    } else 
-      pendingUpdate = false;
+  // one. 
+  public void framebufferUpdateStart() 
+  {
+    // Note: This might not be true if sync fences are supported
+    pendingUpdate = false;
+
+    requestNewUpdate();
   }
 
   // framebufferUpdateEnd() is called at the end of an update.
   // For each rectangle, the FdInStream will have timed the speed
   // of the connection, allowing us to select format and encoding
   // appropriately, and then request another incremental update.
-  public void framebufferUpdateEnd() {
-    desktop.framebufferUpdateEnd();
+  public void framebufferUpdateEnd() 
+  {
+
+    desktop.updateWindow();
 
     if (firstUpdate) {
       int width, height;
       
+      // We need fences to make extra update requests and continuous
+      // updates "safe". See fence() for the next step.
+      if (cp.supportsFence)
+        synchronized(this) {
+          writer().writeFence(fenceTypes.fenceFlagRequest | fenceTypes.fenceFlagSyncNext, 0, null);
+        }
+
       if (cp.supportsSetDesktopSize &&
           viewer.desktopSize.getValue() != null &&
           viewer.desktopSize.getValue().split("x").length == 2) {
@@ -422,16 +459,21 @@ public class CConn extends CConnection
         screen0.dimensions.br.x = width;
         screen0.dimensions.br.y = height;
 
-        writer().writeSetDesktopSize(width, height, layout);
+        synchronized(this) {
+          writer().writeSetDesktopSize(width, height, layout);
+        }
       }
 
       firstUpdate = false;
     }
 
-    // A format change prevented us from sending this before the update,
-    // so make sure to send it now.
-    if (formatChange && !pendingUpdate)
-      requestNewUpdate();
+    // 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) {
+      desktop.setServerPF(pendingPF);
+      cp.setPF(pendingPF);
+      pendingPFChange = false;
+    }
 
     // Compute new settings based on updated bandwidth values
     if (autoSelect)
@@ -480,21 +522,62 @@ public class CConn extends CConnection
     desktop.copyRect(r.tl.x, r.tl.y, r.width(), r.height(), sx, sy);
   }
 
-  public PixelFormat getPreferredPF() {
-    return fullColourPF;
-  }
-
   public void setCursor(int width, int height, Point hotspot,
                         int[] data, byte[] mask) {
     desktop.setCursor(width, height, hotspot, data, mask);
   }
 
-  private void resizeFramebuffer()
+  public void fence(int flags, int len, byte[] data)
   {
-    if ((cp.width == 0) && (cp.height == 0))
+    super.fence(flags, len, data);
+  
+    if ((flags & fenceTypes.fenceFlagRequest) != 0) {
+      // We handle everything synchronously so we trivially honor these modes
+      flags = flags & (fenceTypes.fenceFlagBlockBefore | fenceTypes.fenceFlagBlockAfter);
+  
+      synchronized(this) {
+        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;
+          synchronized(this) {
+            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);
+  
+      desktop.setServerPF(pf);
+      cp.setPF(pf);
+    }
+  }
+
+  private void resizeFramebuffer()
+  {
     if (desktop == null)
       return;
+
+    if (continuousUpdates)
+      synchronized(this) {
+        writer().writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height);
+      }
+
+    if ((cp.width == 0) && (cp.height == 0))
+      return;
     if ((desktop.width() == cp.width) && (desktop.height() == cp.height))
       return;
     
@@ -639,34 +722,63 @@ public class CConn extends CConnection
   private void requestNewUpdate()
   {
     if (formatChange) {
+      PixelFormat pf;
 
       /* Catch incorrect requestNewUpdate calls */
-      assert(pendingUpdate == false);
+      assert(!pendingUpdate || supportsSyncFence);
 
       if (fullColour) {
-        desktop.setPF(fullColourPF);
+        pf = fullColourPF;
       } else {
         if (lowColourLevel == 0) {
-          desktop.setPF(new PixelFormat(8,3,false,true,1,1,1,2,1,0));
+          pf = verylowColourPF;
         } else if (lowColourLevel == 1) {
-          desktop.setPF(new PixelFormat(8,6,false,true,3,3,3,4,2,0));
+          pf = lowColourPF;
         } else {
-          desktop.setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+          pf = mediumColourPF;
         }
       }
-      String str = desktop.getPF().print();
+
+      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);
+  
+        synchronized(this) {
+          writer().writeFence(fenceTypes.fenceFlagRequest | fenceTypes.fenceFlagSyncNext,
+                              memStream.length(), (byte[])memStream.data());
+        }
+      } 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;
+      }
+
+      String str = pf.print();
       vlog.info("Using pixel format "+str);
-      cp.setPF(desktop.getPF());
       synchronized (this) {
-        writer().writeSetPixelFormat(cp.pf());
+        writer().writeSetPixelFormat(pf);
       }
+
+      formatChange = false;
     }
+
     checkEncodings();
-    synchronized (this) {
-      writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),
-                                             !formatChange);
+
+    if (forceNonincremental || !continuousUpdates) {
+      pendingUpdate = true;
+      synchronized (this) {
+        writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),
+                                                   !formatChange);
+      }
     }
-    formatChange = false;
+
+    forceNonincremental = false;
   }
 
 
@@ -791,7 +903,7 @@ public class CConn extends CConnection
       options.secPlain.setEnabled(false);
       options.sendLocalUsername.setEnabled(false);
     } else {
-      options.shared.setSelected(shared);
+      options.shared.setSelected(viewer.shared.getValue());
 
       /* Process non-VeNCrypt sectypes */
       java.util.List<Integer> secTypes = new ArrayList<Integer>();
@@ -971,8 +1083,7 @@ public class CConn extends CConnection
     menuKey = (options.menuKey.getSelectedIndex()+0xFFBE);
     F8Menu.f8.setText("Send F"+(menuKey-Keysyms.F1+1));
 
-    shared = options.shared.isSelected();
-    setShared(shared);
+    setShared(options.shared.isSelected());
     viewer.useLocalCursor.setParam(options.useLocalCursor.isSelected());
     if (cp.supportsLocalCursor != viewer.useLocalCursor.getValue()) {
       cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
@@ -1226,7 +1337,7 @@ public class CConn extends CConnection
   }
 
 
-  synchronized public void writeWheelEvent(MouseWheelEvent ev) {
+  public void writeWheelEvent(MouseWheelEvent ev) {
     if (state() != RFBSTATE_NORMAL) return;
     int x, y;
     int clicks = ev.getWheelRotation();
@@ -1239,9 +1350,11 @@ public class CConn extends CConnection
     for (int i=0;i<Math.abs(clicks);i++) {
       x = ev.getX();
       y = ev.getY();
-      writer().writePointerEvent(new Point(x, y), buttonMask);
-      buttonMask = 0;
-      writer().writePointerEvent(new Point(x, y), buttonMask);
+      synchronized(this) {
+        writer().writePointerEvent(new Point(x, y), buttonMask);
+        buttonMask = 0;
+        writer().writePointerEvent(new Point(x, y), buttonMask);
+      }
     }
     writeModifiers(0);
 
@@ -1265,10 +1378,12 @@ public class CConn extends CConnection
   // The following methods are called from both RFB and GUI threads
 
   // checkEncodings() sends a setEncodings message if one is needed.
-  synchronized private void checkEncodings() {
-    if (encodingChange && state() == RFBSTATE_NORMAL) {
+  private void checkEncodings() {
+    if (encodingChange && (writer() != null)) {
       vlog.info("Using "+Encodings.encodingName(currentEncoding)+" encoding");
-      writer().writeSetEncodings(currentEncoding, true);
+      synchronized(this) {
+        writer().writeSetEncodings(currentEncoding, true);
+      }
       encodingChange = false;
     }
   }
@@ -1296,7 +1411,6 @@ public class CConn extends CConnection
 
   // reading and writing int and boolean is atomic in java, so no
   // synchronization of the following flags is needed:
-  int currentEncoding, lastServerEncoding;
   
   int lowColourLevel;
 
@@ -1313,24 +1427,37 @@ public class CConn extends CConnection
   int buttonMask;
   int pressedModifiers;
 
-  public String serverHost;
-  public int serverPort;
-  public Socket sock;
+  private String serverHost;
+  private int serverPort;
+  private Socket sock;
+
+  protected DesktopWindow desktop;
+
+  // FIXME: should be private
+  public PixelFormat serverPF;
+  private PixelFormat fullColourPF;
+
+  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;
+
   public int menuKey;
-  PixelFormat serverPF;
   ViewportFrame viewport;
-  DesktopWindow desktop;
-  PixelFormat fullColourPF;
-  boolean fullColour;
-  boolean autoSelect;
-  boolean shared;
-  boolean formatChange;
-  boolean encodingChange;
-  boolean sameMachine;
+  private boolean fullColour;
+  private boolean autoSelect;
   boolean fullScreen;
-  boolean reverseConnection;
-  boolean firstUpdate;
-  boolean pendingUpdate;
   
   static LogWriter vlog = new LogWriter("CConn");
 }
index 53d2980c457549a837b30aabcd0607d838a89e4c..814b9d067c2e5293c2d818f5805a22da683f40fc 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 2010 D. R. Commander.  All Rights Reserved.
+/* Copyright (C) 2011-2012 TigerVNC Team.
+ * Copyright (C) 2010 D. R. Commander.  All Rights Reserved.
  * Copyright (C) 2009 Paul Donohue.  All Rights Reserved.
  * Copyright (C) 2006 Constantin Kaplinsky.  All Rights Reserved.
  * Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
@@ -178,6 +179,10 @@ class DesktopWindow extends JPanel implements
     return;
   }
 
+  public void setServerPF(PixelFormat pf) {
+    im.setPF(pf);
+  }
+
   public PixelFormat getPreferredPF() {
     return im.getNativePF();
   }
@@ -202,9 +207,8 @@ class DesktopWindow extends JPanel implements
     }
   }
 
-// Update the actual window with the changed parts of the framebuffer.
-
-  public void framebufferUpdateEnd()
+  // Update the actual window with the changed parts of the framebuffer.
+  public void updateWindow()
   {
     drawInvalidRect();
   }
@@ -246,19 +250,12 @@ class DesktopWindow extends JPanel implements
       invalidBottom = y + h;
       invalidRect = true;
     }
-
-    if ((invalidRight - invalidLeft) * (invalidBottom - invalidTop) > 100000)
-      drawInvalidRect();
   }
 
   public void beginRect(int x, int y, int w, int h, int encoding) {
     invalidRect = false;
   }
 
-  public void endRect(int x, int y, int w, int h, int encoding) {
-    drawInvalidRect();
-  }
-
   final public void fillRect(int x, int y, int w, int h, int pix)
   {
     if (overlapsCursor(x, y, w, h)) hideLocalCursor();
index 9e34c8ab13aadf9817e49a9418c3a9e1f96c77c6..0efc3c1dca589664160261f2ac6f621e84ed4e74 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright (C) 2011-2012 TigerVNC Team.
  * 
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,19 +36,10 @@ public class PixelBufferImage extends PixelBuffer implements ImageProducer
     cc = cc_;
     desktop = desktop_;
     PixelFormat nativePF = getNativePF();
-    switch ((nativePF.depth > cc.serverPF.depth) ? cc.serverPF.depth : nativePF.depth) {
-    case  8: 
-      setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
-      break;
-    case 16: 
-      setPF(new PixelFormat(16,16,false,true,0xF800,0x07C0,0x003E,0,0,0));
-      break;
-    case 24: 
-      setPF(new PixelFormat(32,24,false,true,0xff,0xff,0xff,16,8,0));
-      break;
-    default:
-      setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
-      vlog.debug("Unsupported native PF, defaulting to depth 8");
+    if (nativePF.depth > cc.serverPF.depth) {
+      setPF(cc.serverPF);
+    } else {
+      setPF(nativePF);
     }
     resize(w, h);
   }
index c080f98c38cce08fcfbd69af2626cdd220ba0b1d..91504d2c101258898cd388c0288a389f821eaaa8 100644 (file)
@@ -219,7 +219,7 @@ public class VncViewer extends java.applet.Applet implements Runnable
     }
 
     try {
-      cc = new CConn(this, sock, vncServerName.getValue(), false);
+      cc = new CConn(this, sock, vncServerName.getValue());
       while (true)
         cc.processMsg();
     } catch (EndOfStream e) {