}
}
- 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 {
}
- 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);
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);
public class Exception extends RuntimeException {
public Exception(String s) {
super(s);
+ System.out.println(s);
}
}
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;
}
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.
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) {}
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");
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();
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;
}
/* 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
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();
+ }
}
/* 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
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();
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 &&
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;
public boolean supportsExtendedDesktopSize;
public boolean supportsDesktopRename;
public boolean supportsClientRedirect;
+ public boolean supportsFence;
+ public boolean supportsContinuousUpdates;
public boolean supportsLastRect;
public boolean supportsSetDesktopSize;
public int compressLevel;
public boolean noJpeg;
public int qualityLevel;
+ public int fineQualityLevel;
+ public String subsampling;
private PixelFormat pf_;
private String name_;
/* 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
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;
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;
--- /dev/null
+/* 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";
+ }
+ }
+}
/* 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
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;
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;
}
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));
--- /dev/null
+/* 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);
+}
/* 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
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;
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);
// 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
// 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) {
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)
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;
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;
}
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>();
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();
}
- synchronized public void writeWheelEvent(MouseWheelEvent ev) {
+ public void writeWheelEvent(MouseWheelEvent ev) {
if (state() != RFBSTATE_NORMAL) return;
int x, y;
int clicks = ev.getWheelRotation();
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);
// 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;
}
}
// reading and writing int and boolean is atomic in java, so no
// synchronization of the following flags is needed:
- int currentEncoding, lastServerEncoding;
int lowColourLevel;
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");
}
-/* 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.
return;
}
+ public void setServerPF(PixelFormat pf) {
+ im.setPF(pf);
+ }
+
public PixelFormat getPreferredPF() {
return im.getNativePF();
}
}
}
-// 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();
}
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();
/* 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
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);
}
}
try {
- cc = new CConn(this, sock, vncServerName.getValue(), false);
+ cc = new CConn(this, sock, vncServerName.getValue());
while (true)
cc.processMsg();
} catch (EndOfStream e) {