Revision: 4847 http://tigervnc.svn.sourceforge.net/tigervnc/?rev=4847&view=rev Author: bphinz Date: 2012-02-12 20:44:29 +0000 (Sun, 12 Feb 2012) Log Message: ----------- Adds support for fence & continuous updates extensions to java viewer. Adds low level hooks for TurboVNC fine grained quality controls.
Modified Paths: -------------- trunk/java/com/tigervnc/network/SocketDescriptor.java trunk/java/com/tigervnc/rdr/Exception.java trunk/java/com/tigervnc/rdr/MemInStream.java trunk/java/com/tigervnc/rdr/MemOutStream.java trunk/java/com/tigervnc/rfb/CMsgHandler.java trunk/java/com/tigervnc/rfb/CMsgReaderV3.java trunk/java/com/tigervnc/rfb/CMsgWriter.java trunk/java/com/tigervnc/rfb/CMsgWriterV3.java trunk/java/com/tigervnc/rfb/ConnParams.java trunk/java/com/tigervnc/rfb/Encodings.java trunk/java/com/tigervnc/rfb/MsgTypes.java trunk/java/com/tigervnc/rfb/PixelBuffer.java trunk/java/com/tigervnc/vncviewer/CConn.java trunk/java/com/tigervnc/vncviewer/DesktopWindow.java trunk/java/com/tigervnc/vncviewer/PixelBufferImage.java trunk/java/com/tigervnc/vncviewer/VncViewer.java Added Paths: ----------- trunk/java/com/tigervnc/rfb/JpegCompressor.java trunk/java/com/tigervnc/rfb/fenceTypes.java Modified: trunk/java/com/tigervnc/network/SocketDescriptor.java =================================================================== --- trunk/java/com/tigervnc/network/SocketDescriptor.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/network/SocketDescriptor.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -49,7 +49,7 @@ } } - 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 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 @@ 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); Modified: trunk/java/com/tigervnc/rdr/Exception.java =================================================================== --- trunk/java/com/tigervnc/rdr/Exception.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rdr/Exception.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -21,6 +21,7 @@ public class Exception extends RuntimeException { public Exception(String s) { super(s); + System.out.println(s); } } Modified: trunk/java/com/tigervnc/rdr/MemInStream.java =================================================================== --- trunk/java/com/tigervnc/rdr/MemInStream.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rdr/MemInStream.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -22,13 +22,17 @@ 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; } Modified: trunk/java/com/tigervnc/rdr/MemOutStream.java =================================================================== --- trunk/java/com/tigervnc/rdr/MemOutStream.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rdr/MemOutStream.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -35,6 +35,10 @@ 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. Modified: trunk/java/com/tigervnc/rfb/CMsgHandler.java =================================================================== --- trunk/java/com/tigervnc/rfb/CMsgHandler.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/CMsgHandler.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -61,6 +61,16 @@ 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) {} Modified: trunk/java/com/tigervnc/rfb/CMsgReaderV3.java =================================================================== --- trunk/java/com/tigervnc/rfb/CMsgReaderV3.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/CMsgReaderV3.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -51,6 +51,8 @@ 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 @@ 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(); Modified: trunk/java/com/tigervnc/rfb/CMsgWriter.java =================================================================== --- trunk/java/com/tigervnc/rfb/CMsgWriter.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/CMsgWriter.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -59,9 +59,16 @@ 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; } Modified: trunk/java/com/tigervnc/rfb/CMsgWriterV3.java =================================================================== --- trunk/java/com/tigervnc/rfb/CMsgWriterV3.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/CMsgWriterV3.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 @@ 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(); + } } Modified: trunk/java/com/tigervnc/rfb/ConnParams.java =================================================================== --- trunk/java/com/tigervnc/rfb/ConnParams.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/ConnParams.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 @@ 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 @@ 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 @@ 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 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 int compressLevel; public boolean noJpeg; public int qualityLevel; + public int fineQualityLevel; + public String subsampling; private PixelFormat pf_; private String name_; Modified: trunk/java/com/tigervnc/rfb/Encodings.java =================================================================== --- trunk/java/com/tigervnc/rfb/Encodings.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/Encodings.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 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 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; Added: trunk/java/com/tigervnc/rfb/JpegCompressor.java =================================================================== --- trunk/java/com/tigervnc/rfb/JpegCompressor.java (rev 0) +++ trunk/java/com/tigervnc/rfb/JpegCompressor.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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"; + } + } +} Modified: trunk/java/com/tigervnc/rfb/MsgTypes.java =================================================================== --- trunk/java/com/tigervnc/rfb/MsgTypes.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/MsgTypes.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 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 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; } Modified: trunk/java/com/tigervnc/rfb/PixelBuffer.java =================================================================== --- trunk/java/com/tigervnc/rfb/PixelBuffer.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/rfb/PixelBuffer.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -36,9 +36,17 @@ 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)); Added: trunk/java/com/tigervnc/rfb/fenceTypes.java =================================================================== --- trunk/java/com/tigervnc/rfb/fenceTypes.java (rev 0) +++ trunk/java/com/tigervnc/rfb/fenceTypes.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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); +} Modified: trunk/java/com/tigervnc/vncviewer/CConn.java =================================================================== --- trunk/java/com/tigervnc/vncviewer/CConn.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/vncviewer/CConn.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 @@ 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 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ 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); } + public void fence(int flags, int len, byte[] data) + { + 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 == null) - return; if ((desktop.width() == cp.width) && (desktop.height() == cp.height)) return; @@ -639,34 +722,63 @@ 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 @@ 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 @@ 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 @@ } - 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 @@ 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 @@ // 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 @@ // 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 @@ 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"); } Modified: trunk/java/com/tigervnc/vncviewer/DesktopWindow.java =================================================================== --- trunk/java/com/tigervnc/vncviewer/DesktopWindow.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/vncviewer/DesktopWindow.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 @@ return; } + public void setServerPF(PixelFormat pf) { + im.setPF(pf); + } + public PixelFormat getPreferredPF() { return im.getNativePF(); } @@ -202,9 +207,8 @@ } } -// 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 @@ 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(); Modified: trunk/java/com/tigervnc/vncviewer/PixelBufferImage.java =================================================================== --- trunk/java/com/tigervnc/vncviewer/PixelBufferImage.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/vncviewer/PixelBufferImage.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -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 @@ 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); } Modified: trunk/java/com/tigervnc/vncviewer/VncViewer.java =================================================================== --- trunk/java/com/tigervnc/vncviewer/VncViewer.java 2012-02-08 04:21:43 UTC (rev 4846) +++ trunk/java/com/tigervnc/vncviewer/VncViewer.java 2012-02-12 20:44:29 UTC (rev 4847) @@ -219,7 +219,7 @@ } try { - cc = new CConn(this, sock, vncServerName.getValue(), false); + cc = new CConn(this, sock, vncServerName.getValue()); while (true) cc.processMsg(); } catch (EndOfStream e) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Virtualization & Cloud Management Using Capacity Planning Cloud computing makes use of virtualization - but cloud computing also focuses on allowing computing to be delivered as a service. http://www.accelacomm.com/jaw/sfnl/114/51521223/ _______________________________________________ Tigervnc-commits mailing list Tigervnc-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tigervnc-commits