Merge pull request #80 from bphinz/buildfixes
More RPM spec file cleanup
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1dcfd9e..3091d7b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,10 +18,10 @@
include(CMakeMacroLibtoolFile)
project(tigervnc)
-set(VERSION 1.3.80)
+set(VERSION 1.4.80)
# The RC version must always be four comma-separated numbers
-set(RCVERSION 1,3,80,0)
+set(RCVERSION 1,4,80,0)
# Installation paths
set(BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin")
@@ -321,6 +321,12 @@
set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
endif()
check_function_exists(inet_aton HAVE_INET_ATON)
+# This might give a false positive on Windows as it is also guarded by
+# a version check that we do not satisfy (requires Vista, but we target
+# Windows 2000).
+if(NOT WIN32)
+check_function_exists(inet_pton HAVE_INET_PTON)
+endif()
check_function_exists(getaddrinfo HAVE_GETADDRINFO)
set(CMAKE_EXTRA_INCLUDE_FILES)
set(CMAKE_REQUIRED_LIBRARIES)
diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx
index d9e9376..0db6ff6 100644
--- a/common/network/TcpSocket.cxx
+++ b/common/network/TcpSocket.cxx
@@ -239,27 +239,66 @@
}
char* TcpSocket::getPeerAddress() {
- struct sockaddr_in info;
- struct in_addr addr;
- socklen_t info_size = sizeof(info);
+ vnc_sockaddr_t sa;
+ socklen_t sa_size = sizeof(sa);
- getpeername(getFd(), (struct sockaddr *)&info, &info_size);
- memcpy(&addr, &info.sin_addr, sizeof(addr));
-
- char* name = inet_ntoa(addr);
- if (name) {
- return rfb::strDup(name);
- } else {
+ if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
+ vlog.error("unable to get peer name for socket");
return rfb::strDup("");
}
+
+#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON)
+ if (sa.u.sa.sa_family == AF_INET6) {
+ char buffer[INET6_ADDRSTRLEN + 2];
+ const char *name;
+
+ buffer[0] = '[';
+
+ name = inet_ntop(sa.u.sa.sa_family, &sa.u.sin6.sin6_addr,
+ buffer + 1, sizeof(buffer) - 2);
+ if (name == NULL) {
+ vlog.error("unable to convert peer name to a string");
+ return rfb::strDup("");
+ }
+
+ strcat(buffer, "]");
+
+ return rfb::strDup(buffer);
+ }
+#endif
+
+ if (sa.u.sa.sa_family == AF_INET) {
+ char *name;
+
+ name = inet_ntoa(sa.u.sin.sin_addr);
+ if (name == NULL) {
+ vlog.error("unable to convert peer name to a string");
+ return rfb::strDup("");
+ }
+
+ return rfb::strDup(name);
+ }
+
+ vlog.error("unknown address family for socket");
+ return rfb::strDup("");
}
int TcpSocket::getPeerPort() {
- struct sockaddr_in info;
- socklen_t info_size = sizeof(info);
+ vnc_sockaddr_t sa;
+ socklen_t sa_size = sizeof(sa);
- getpeername(getFd(), (struct sockaddr *)&info, &info_size);
- return ntohs(info.sin_port);
+ getpeername(getFd(), &sa.u.sa, &sa_size);
+
+ switch (sa.u.sa.sa_family) {
+#ifdef HAVE_GETADDRINFO
+ case AF_INET6:
+ return ntohs(sa.u.sin6.sin6_port);
+#endif /* HAVE_GETADDRINFO */
+ case AF_INET:
+ return ntohs(sa.u.sin.sin_port);
+ default:
+ return 0;
+ }
}
char* TcpSocket::getPeerEndpoint() {
@@ -293,7 +332,11 @@
&myaddr.u.sin6.sin6_addr);
#endif
- return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
+ if (peeraddr.u.sa.sa_family == AF_INET)
+ return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
+
+ // No idea what this is. Assume we're on different machines.
+ return false;
}
void TcpSocket::shutdown()
@@ -326,25 +369,34 @@
bool TcpSocket::isSocket(int sock)
{
- struct sockaddr_in info;
- socklen_t info_size = sizeof(info);
- return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
+ vnc_sockaddr_t sa;
+ socklen_t sa_size = sizeof(sa);
+ return getsockname(sock, &sa.u.sa, &sa_size) >= 0;
}
bool TcpSocket::isConnected(int sock)
{
- struct sockaddr_in info;
- socklen_t info_size = sizeof(info);
- return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
+ vnc_sockaddr_t sa;
+ socklen_t sa_size = sizeof(sa);
+ return getpeername(sock, &sa.u.sa, &sa_size) >= 0;
}
int TcpSocket::getSockPort(int sock)
{
- struct sockaddr_in info;
- socklen_t info_size = sizeof(info);
- if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
+ vnc_sockaddr_t sa;
+ socklen_t sa_size = sizeof(sa);
+ if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
return 0;
- return ntohs(info.sin_port);
+
+ switch (sa.u.sa.sa_family) {
+#ifdef HAVE_GETADDRINFO
+ case AF_INET6:
+ return ntohs(sa.u.sin6.sin6_port);
+#endif /* HAVE_GETADDRINFO */
+
+ default:
+ return ntohs(sa.u.sin.sin_port);
+ }
}
@@ -356,9 +408,40 @@
return;
}
+ bool use_ipv6;
+ int af;
+#ifdef HAVE_GETADDRINFO
+ use_ipv6 = true;
+ af = AF_INET6;
+#else
+ use_ipv6 = false;
+ af = AF_INET;
+#endif
+
initSockets();
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- throw SocketException("unable to create listening socket", errorNumber);
+ if ((fd = socket(af, SOCK_STREAM, 0)) < 0) {
+ // - Socket creation failed
+ if (use_ipv6) {
+ // - Trying to make an IPv6-capable socket failed - try again, IPv4-only
+ use_ipv6 = false;
+ af = AF_INET;
+ fd = socket(af, SOCK_STREAM, 0);
+ }
+ if (fd < 0)
+ throw SocketException("unable to create listening socket", errorNumber);
+ } else {
+ // - Socket creation succeeded
+ if (use_ipv6) {
+#ifdef IPV6_V6ONLY
+ // - We made an IPv6-capable socket, and we need it to do IPv4 too
+ int opt = 0;
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof(opt));
+#else
+ vlog.error("IPV6_V6ONLY support is missing. "
+ "IPv4 clients may not be able to connect.");
+#endif
+ }
+ }
#ifndef WIN32
// - By default, close the socket on exec()
@@ -375,27 +458,62 @@
// - Bind it to the desired port
struct sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
-
- if (localhostOnly) {
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- } else if (listenaddr != NULL) {
-#ifdef HAVE_INET_ATON
- if (inet_aton(listenaddr, &addr.sin_addr) == 0)
-#else
- /* Some systems (e.g. Windows) do not have inet_aton, sigh */
- if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE)
+#ifdef HAVE_GETADDRINFO
+ struct sockaddr_in6 addr6;
#endif
- {
- closesocket(fd);
- throw Exception("invalid network interface address: %s", listenaddr);
+ struct sockaddr *sa;
+ int sa_len;
+
+#ifdef HAVE_GETADDRINFO
+ if (use_ipv6) {
+ memset(&addr6, 0, (sa_len = sizeof(addr6)));
+ addr6.sin6_family = af;
+ addr6.sin6_port = htons(port);
+
+ if (localhostOnly)
+ addr6.sin6_addr = in6addr_loopback;
+ else if (listenaddr != NULL) {
+#ifdef HAVE_INET_PTON
+ if (inet_pton(AF_INET6, listenaddr, &addr6.sin6_addr) != 1)
+ use_ipv6 = false;
+#else
+ // Unable to parse without inet_pton
+ use_ipv6 = false;
+#endif
}
- } else
- addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to 0.0.0.0 by default. */
+
+ if (use_ipv6)
+ sa = (struct sockaddr *)&addr6;
+ }
+#endif
+
+ if (!use_ipv6) {
+ memset(&addr, 0, (sa_len = sizeof(addr)));
+ addr.sin_family = af;
+ addr.sin_port = htons(port);
+
+ if (localhostOnly) {
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ } else if (listenaddr != NULL) {
+#ifdef HAVE_INET_ATON
+ if (inet_aton(listenaddr, &addr.sin_addr) == 0)
+#else
+ /* Some systems (e.g. Windows) do not have inet_aton, sigh */
+ if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE)
+#endif
+ {
+ closesocket(fd);
+ throw Exception("invalid network interface address: %s", listenaddr);
+ }
+ } else
+ /* Bind to 0.0.0.0 by default. */
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ sa = (struct sockaddr *)&addr;
+ }
addr.sin_port = htons(port);
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (bind(fd, sa, sa_len) < 0) {
int e = errorNumber;
closesocket(fd);
throw SocketException("unable to bind listening socket", e);
@@ -449,6 +567,30 @@
}
void TcpListener::getMyAddresses(std::list<char*>* result) {
+#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON)
+ vnc_sockaddr_t sa;
+ struct addrinfo *ai, *current, hints;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if ((getaddrinfo(NULL, NULL, &hints, &ai)) != 0)
+ return;
+
+ for (current= ai; current != NULL; current = current->ai_next) {
+ if (current->ai_family != AF_INET && current->ai_family != AF_INET6)
+ continue;
+
+ char *addr = new char[INET6_ADDRSTRLEN];
+ inet_ntop(current->ai_family, current->ai_addr, addr, INET6_ADDRSTRLEN);
+ result->push_back(addr);
+ }
+ freeaddrinfo(ai);
+#else
const hostent* addrs = gethostbyname(0);
if (addrs == 0)
throw rdr::SystemException("gethostbyname", errorNumber);
@@ -460,6 +602,7 @@
strcpy(addr, addrC);
result->push_back(addr);
}
+#endif /* defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) */
}
int TcpListener::getMyPort() {
@@ -493,6 +636,15 @@
TcpFilter::verifyConnection(Socket* s) {
rfb::CharArray name;
+#ifdef HAVE_GETADDRINFO
+ vnc_sockaddr_t sa;
+ socklen_t sa_size = sizeof(sa);
+ if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0 ||
+ sa.u.sa.sa_family != AF_INET)
+ /* Matching only works for IPv4 */
+ return false;
+#endif /* HAVE_GETADDRINFO */
+
name.buf = s->getPeerAddress();
std::list<TcpFilter::Pattern>::iterator i;
for (i=filter.begin(); i!=filter.end(); i++) {
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx
index 1695c3a..e0a23b5 100644
--- a/common/rfb/CConnection.cxx
+++ b/common/rfb/CConnection.cxx
@@ -181,7 +181,7 @@
if (secType != secTypeInvalid) {
os->writeU8(secType);
os->flush();
- vlog.debug("Choosing security type %s(%d)",secTypeName(secType),secType);
+ vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
}
}
diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx
index 77eeef9..a15da4a 100644
--- a/common/rfb/CSecurityVeNCrypt.cxx
+++ b/common/rfb/CSecurityVeNCrypt.cxx
@@ -164,7 +164,7 @@
break;
}
- vlog.debug("Choosing security type %s (%d)", secTypeName(chosenType),
+ vlog.info("Choosing security type %s (%d)", secTypeName(chosenType),
chosenType);
/* Set up the stack according to the chosen type: */
diff --git a/common/rfb/SSecurityVeNCrypt.cxx b/common/rfb/SSecurityVeNCrypt.cxx
index 9e4260f..39647f6 100644
--- a/common/rfb/SSecurityVeNCrypt.cxx
+++ b/common/rfb/SSecurityVeNCrypt.cxx
@@ -157,7 +157,7 @@
if (!haveChosenType)
chosenType = secTypeInvalid;
- vlog.debug("Choosing security type %s (%d)", secTypeName(chosenType),
+ vlog.info("Client requests security type %s (%d)", secTypeName(chosenType),
chosenType);
/* Set up the stack according to the chosen type */
diff --git a/common/rfb/SecurityServer.cxx b/common/rfb/SecurityServer.cxx
index 5bd7b2c..e0aee13 100644
--- a/common/rfb/SecurityServer.cxx
+++ b/common/rfb/SecurityServer.cxx
@@ -43,7 +43,7 @@
#endif
")",
#ifdef HAVE_GNUTLS
- "VncAuth,TLSVnc",
+ "TLSVnc,VncAuth",
#else
"VncAuth",
#endif
diff --git a/config.h.in b/config.h.in
index a50e723..490d7f6 100644
--- a/config.h.in
+++ b/config.h.in
@@ -2,6 +2,7 @@
#define PACKAGE_VERSION "@VERSION@"
#cmakedefine HAVE_INET_ATON
+#cmakedefine HAVE_INET_PTON
#cmakedefine HAVE_GETADDRINFO
#cmakedefine HAVE_GNUTLS_SET_GLOBAL_ERRNO
#cmakedefine HAVE_GNUTLS_SET_ERRNO
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index c98c69c..bf1cffb 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -2,7 +2,7 @@
project(tigervnc-java Java)
if(NOT VERSION)
- set(VERSION 1.3.80)
+ set(VERSION 1.4.80)
endif()
find_package(Java)
diff --git a/java/com/tigervnc/network/SSLEngineManager.java b/java/com/tigervnc/network/SSLEngineManager.java
index cb1f7c4..c011099 100644
--- a/java/com/tigervnc/network/SSLEngineManager.java
+++ b/java/com/tigervnc/network/SSLEngineManager.java
@@ -41,14 +41,14 @@
private ByteBuffer peerNetData;
private Executor executor;
- private FdInStream inStream;
- private FdOutStream outStream;
+ private FdInStream in;
+ private FdOutStream os;
- public SSLEngineManager(SSLEngine sslEngine, FdInStream is,
- FdOutStream os) throws IOException {
+ public SSLEngineManager(SSLEngine sslEngine, FdInStream is_,
+ FdOutStream os_) throws IOException {
- inStream = is;
- outStream = os;
+ in = is_;
+ os = os_;
engine = sslEngine;
executor = Executors.newSingleThreadExecutor();
@@ -56,7 +56,8 @@
pktBufSize = engine.getSession().getPacketBufferSize();
appBufSize = engine.getSession().getApplicationBufferSize();
- myAppData = ByteBuffer.allocate(appBufSize);
+ myAppData =
+ ByteBuffer.allocate(Math.max(appBufSize, os.getBufSize()));
myNetData = ByteBuffer.allocate(pktBufSize);
peerAppData = ByteBuffer.allocate(appBufSize);
peerNetData = ByteBuffer.allocate(pktBufSize);
@@ -80,13 +81,14 @@
SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
hs = res.getHandshakeStatus();
+ // Check status
switch (res.getStatus()) {
case BUFFER_UNDERFLOW:
- int len = Math.min(peerNetData.remaining(), inStream.getBufSize());
- int m = inStream.check(1, len, false);
- byte[] buf = new byte[m];
- inStream.readBytes(buf, 0, m);
- peerNetData.put(buf, 0, m);
+ int max = Math.min(peerNetData.remaining(), in.getBufSize());
+ int m = in.check(1, max, true);
+ int pos = peerNetData.position();
+ in.readBytes(peerNetData.array(), pos, m);
+ peerNetData.position(pos+m);
peerNetData.flip();
peerNetData.compact();
break;
@@ -102,7 +104,7 @@
}
break;
- case NEED_WRAP :
+ case NEED_WRAP:
// Empty the local network packet buffer.
myNetData.clear();
@@ -112,20 +114,17 @@
// Check status
switch (res.getStatus()) {
- case OK :
+ case OK:
myAppData.compact();
myNetData.flip();
- int n = myNetData.remaining();
- byte[] b = new byte[n];
- myNetData.get(b);
+ os.writeBytes(myNetData.array(), 0, myNetData.remaining());
+ os.flush();
myNetData.clear();
- outStream.writeBytes(b, 0, n);
- outStream.flush();
break;
case BUFFER_OVERFLOW:
// FIXME: How much larger should the buffer be?
- // fallthrough
+ break;
case CLOSED:
engine.closeOutbound();
@@ -133,7 +132,8 @@
}
break;
- case NEED_TASK :
+
+ case NEED_TASK:
// Handle blocking tasks
executeTasks();
break;
@@ -151,29 +151,28 @@
public int read(byte[] data, int dataPtr, int length) throws IOException {
// Read SSL/TLS encoded data from peer
- int len = Math.min(pktBufSize,inStream.getBufSize());
- int bytesRead = inStream.check(1,len,false);
- byte[] buf = new byte[bytesRead];
- inStream.readBytes(buf, 0, bytesRead);
- if (peerNetData.remaining() < bytesRead) {
- peerNetData.flip();
- ByteBuffer b = ByteBuffer.allocate(peerNetData.remaining() + bytesRead);
- b.put(peerNetData);
- peerNetData = b;
- }
- peerNetData.put(buf);
+ int bytesRead = 0;
peerNetData.flip();
SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
switch (res.getStatus()) {
case OK :
+ bytesRead = Math.min(length, res.bytesProduced());
peerAppData.flip();
- peerAppData.get(data, dataPtr, res.bytesProduced());
+ peerAppData.get(data, dataPtr, bytesRead);
peerAppData.compact();
break;
case BUFFER_UNDERFLOW:
- // normal (need more net data)
+ // need more net data
+ int pos = peerNetData.position();
+ // attempt to drain the underlying buffer first
+ int need = peerNetData.remaining();
+ int avail = in.check(1, in.getBufSize(), false);
+ if (avail < need)
+ avail = in.check(1, Math.min(need, in.getBufSize()), true);
+ in.readBytes(peerNetData.array(), pos, Math.min(need, avail));
+ peerNetData.position(pos+Math.min(need, avail));
break;
case CLOSED:
@@ -181,24 +180,28 @@
break;
}
- return res.bytesProduced();
+ return bytesRead;
}
public int write(byte[] data, int dataPtr, int length) throws IOException {
int n = 0;
- // FIXME: resize myAppData if necessary
myAppData.put(data, dataPtr, length);
myAppData.flip();
while (myAppData.hasRemaining()) {
SSLEngineResult res = engine.wrap(myAppData, myNetData);
n += res.bytesConsumed();
switch (res.getStatus()) {
- case BUFFER_OVERFLOW:
- ByteBuffer b = ByteBuffer.allocate(myNetData.capacity() + myAppData.remaining());
- myNetData.flip();
- b.put(myNetData);
- myNetData = b;
+ case OK:
break;
+
+ case BUFFER_OVERFLOW:
+ // Make room in the buffer by flushing the outstream
+ myNetData.flip();
+ os.writeBytes(myNetData.array(), 0, myNetData.remaining());
+ os.flush();
+ myNetData.clear();
+ break;
+
case CLOSED:
engine.closeOutbound();
break;
@@ -206,12 +209,9 @@
}
myAppData.clear();
myNetData.flip();
- int len = myNetData.remaining();
- byte[] buf = new byte[len];
- myNetData.get(buf);
+ os.writeBytes(myNetData.array(), 0, myNetData.remaining());
+ os.flush();
myNetData.clear();
- outStream.writeBytes(buf, 0, len);
- outStream.flush();
return n;
}
diff --git a/java/com/tigervnc/network/Socket.java b/java/com/tigervnc/network/Socket.java
index bcc920d..651dc05 100644
--- a/java/com/tigervnc/network/Socket.java
+++ b/java/com/tigervnc/network/Socket.java
@@ -58,7 +58,6 @@
// Is the remote end on the same machine?
abstract public boolean sameMachine();
- // Was there a "?" in the ConnectionFilter used to accept this Socket?
public void setRequiresQuery() {queryConnection = true;}
public final boolean requiresQuery() {return queryConnection;}
@@ -78,29 +77,3 @@
boolean isShutdown_;
boolean queryConnection;
}
-
-/*
-abstract class ConnectionFilter {
- public abstract boolean verifyConnection(Socket s);
-};
-
-abstract class SocketListener {
- public SocketListener() {
- fd = null; filter = null;
- }
-
- // shutdown() stops the socket from accepting further connections
- public abstract void shutdown();
-
- // accept() returns a new Socket object if there is a connection
- // attempt in progress AND if the connection passes the filter
- // if one is installed. Otherwise, returns 0.
- public abstract Socket accept();
-
- // setFilter() applies the specified filter to all new connections
- public void setFilter(ConnectionFilter f) {filter = f;}
- //public SocketDescriptor getFd() {return fd;}
- protected FileDescriptor fd;
- protected ConnectionFilter filter;
-};
-*/
diff --git a/java/com/tigervnc/network/SocketListener.java b/java/com/tigervnc/network/SocketListener.java
index a1b2c12..a1f5ea1 100644
--- a/java/com/tigervnc/network/SocketListener.java
+++ b/java/com/tigervnc/network/SocketListener.java
@@ -29,18 +29,15 @@
public SocketListener() {}
// shutdown() stops the socket from accepting further connections
- abstract public void shutdown();
+ abstract public void shutdown() throws Exception;
// accept() returns a new Socket object if there is a connection
// attempt in progress AND if the connection passes the filter
// if one is installed. Otherwise, returns 0.
abstract public Socket accept();
- // setFilter() applies the specified filter to all new connections
- //public void setFilter(ConnectionFilter* f) {filter = f;}
public FileDescriptor getFd() {return fd;}
protected FileDescriptor fd;
- //protected ConnectionFilter* filter;
}
diff --git a/java/com/tigervnc/network/TcpListener.java b/java/com/tigervnc/network/TcpListener.java
index bab9e4c..45ee8a4 100644
--- a/java/com/tigervnc/network/TcpListener.java
+++ b/java/com/tigervnc/network/TcpListener.java
@@ -84,12 +84,21 @@
this(listenaddr, port, false, null, true);
}
-// TcpListener::~TcpListener() {
-// if (closeFd) closesocket(fd);
-// }
+ protected void finalize() throws Exception {
+ if (closeFd)
+ try {
+ ((SocketDescriptor)getFd()).close();
+ } catch (IOException e) {
+ throw new Exception(e.getMessage());
+ }
+ }
- public void shutdown() {
- //shutdown(getFd(), 2);
+ public void shutdown() throws Exception {
+ try {
+ ((SocketDescriptor)getFd()).shutdown();
+ } catch (IOException e) {
+ throw new Exception(e.getMessage());
+ }
}
public TcpSocket accept() {
@@ -132,32 +141,12 @@
}
fd.setChannel(new_sock);
TcpSocket s = new TcpSocket(fd);
- //if (filter && !filter->verifyConnection(s)) {
- // delete s;
- // return 0;
- //}
return s;
}
-/*
-void TcpListener::getMyAddresses(std::list<char*>* result) {
- const hostent* addrs = gethostbyname(0);
- if (addrs == 0)
- throw rdr::SystemException("gethostbyname", errorNumber);
- if (addrs->h_addrtype != AF_INET)
- throw rdr::Exception("getMyAddresses: bad family");
- for (int i=0; addrs->h_addr_list[i] != 0; i++) {
- const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
- char* addr = new char[strlen(addrC)+1];
- strcpy(addr, addrC);
- result->push_back(addr);
+ public int getMyPort() {
+ return ((SocketDescriptor)getFd()).socket().getLocalPort();
}
-}
- */
-
- //public int getMyPort() {
- // return TcpSocket.getSockPort();
- //}
private boolean closeFd;
private ServerSocketChannel channel;
diff --git a/java/com/tigervnc/network/TcpSocket.java b/java/com/tigervnc/network/TcpSocket.java
index 051a9d8..43787e4 100644
--- a/java/com/tigervnc/network/TcpSocket.java
+++ b/java/com/tigervnc/network/TcpSocket.java
@@ -113,8 +113,7 @@
}
public int getMyPort() {
- SocketAddress address = ((SocketDescriptor)getFd()).socket().getLocalSocketAddress();
- return ((InetSocketAddress)address).getPort();
+ return getSockPort();
}
public String getPeerAddress() {
@@ -184,7 +183,7 @@
}
public int getSockPort() {
- return ((InetSocketAddress)((SocketDescriptor)getFd()).socket().getRemoteSocketAddress()).getPort();
+ return ((SocketDescriptor)getFd()).socket().getLocalPort();
}
/* Tunnelling support. */
diff --git a/java/com/tigervnc/vncviewer/ClipboardDialog.java b/java/com/tigervnc/vncviewer/ClipboardDialog.java
index d4cde6e..e7aa7e9 100644
--- a/java/com/tigervnc/vncviewer/ClipboardDialog.java
+++ b/java/com/tigervnc/vncviewer/ClipboardDialog.java
@@ -1,5 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2011 Brian P. Hinz
+ * Copyright (C) 2011-2014 Brian P. Hinz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,27 +21,91 @@
import java.awt.*;
import java.awt.event.*;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.*;
+import java.io.*;
+import java.nio.*;
import javax.swing.*;
import javax.swing.border.*;
+import javax.swing.text.*;
+
import com.tigervnc.rfb.LogWriter;
class ClipboardDialog extends Dialog implements ActionListener {
+ private class VncTransferHandler extends TransferHandler {
+ // Custom TransferHandler designed to limit the size of outbound
+ // clipboard transfers to VncViewer.maxCutText.getValue() bytes.
+ private LogWriter vlog = new LogWriter("VncTransferHandler");
+
+ public void exportToClipboard(JComponent c, Clipboard clip, int a)
+ throws IllegalStateException {
+ if (!(c instanceof JTextComponent)) return;
+ StringSelection selection =
+ new StringSelection(((JTextComponent)c).getText());
+ clip.setContents(selection, null);
+ }
+
+ public boolean importData(JComponent c, Transferable t) {
+ if (canImport(c, t.getTransferDataFlavors())) {
+ try {
+ DataFlavor VncFlavor = null;
+ for (DataFlavor f : t.getTransferDataFlavors())
+ if (f.isFlavorTextType() && f.isRepresentationClassInputStream())
+ VncFlavor = f;
+ if (VncFlavor == null) return false;
+ Reader reader = (Reader)VncFlavor.getReaderForText(t);
+ CharBuffer cbuf =
+ CharBuffer.allocate(VncViewer.maxCutText.getValue());
+ cbuf.limit(reader.read(cbuf.array(), 0, cbuf.length()));
+ reader.close();
+ if (c instanceof JTextComponent)
+ ((JTextComponent)c).setText(cbuf.toString());
+ return true;
+ } catch (OutOfMemoryError oome) {
+ vlog.error("ERROR: Too much data on local clipboard!");
+ } catch (UnsupportedFlavorException ufe) {
+ // Skip import
+ vlog.info(ufe.toString());
+ } catch (IOException ioe) {
+ // Skip import
+ vlog.info(ioe.toString());
+ }
+ }
+ return false;
+ }
+
+ public boolean canImport(JComponent c, DataFlavor[] flavors) {
+ for (DataFlavor f : flavors)
+ if (f.isFlavorTextType() && f.isRepresentationClassReader())
+ return true;
+ return false;
+ }
+ }
+
public ClipboardDialog(CConn cc_) {
super(false);
+ setTitle("VNC Clipboard Viewer");
+ setPreferredSize(new Dimension(640, 480));
+ addWindowFocusListener(new WindowAdapter() {
+ // Necessary to ensure that updates from the system clipboard
+ // still occur when the ClipboardDialog has the focus.
+ public void WindowGainedFocus(WindowEvent e) {
+ clientCutText();
+ }
+ });
cc = cc_;
- setTitle("VNC clipboard");
- JPanel pt = new JPanel();
- textArea = new JTextArea(5,50);
- textArea.setBorder(BorderFactory.createLineBorder(Color.gray));
- textArea.setLineWrap(true);
+ textArea = new JTextArea();
+ textArea.setTransferHandler(new VncTransferHandler());
+ // If the textArea can receive the focus, then text within the textArea
+ // can be selected. On platforms that don't support separate selection
+ // and clipboard buffers, this triggers a replacement of the textAra's
+ // contents with the selected text.
+ textArea.setFocusable(false);
+ textArea.setLineWrap(false);
textArea.setWrapStyleWord(true);
JScrollPane sp = new JScrollPane(textArea);
- pt.add(sp, BorderLayout.CENTER);
- getContentPane().add("North", pt);
-
+ getContentPane().add(sp, BorderLayout.CENTER);
+ // button panel placed below the scrollpane
JPanel pb = new JPanel();
clearButton = new JButton("Clear");
pb.add(clearButton);
@@ -53,40 +117,22 @@
pb.add(cancelButton);
cancelButton.addActionListener(this);
getContentPane().add("South", pb);
-
pack();
}
- public boolean compareContentsTo(String str) {
- return str.equals(textArea.getText());
-
- }
-
- public void setContents(String str) {
- textArea.setText(str);
- }
-
- public String getContents() {
- return textArea.getText();
- }
-
public void serverCutText(String str, int len) {
- setContents(str);
- SecurityManager sm = System.getSecurityManager();
- try {
- if (sm != null) sm.checkSystemClipboardAccess();
- Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
- if (cb != null) {
- StringSelection ss = new StringSelection(str);
- try {
- cb.setContents(ss, null);
- } catch(Exception e) {
- vlog.debug(e.getMessage());
- }
- }
- } catch(SecurityException e) {
- vlog.debug("Cannot access the system clipboard: "+e.getMessage());
- }
+ textArea.setText(str);
+ textArea.copy();
+ }
+
+ public void clientCutText() {
+ int hc = textArea.getText().hashCode();
+ textArea.paste();
+ textArea.setCaretPosition(0);
+ String text = textArea.getText();
+ if (cc.viewer.sendClipboard.getValue())
+ if (hc != text.hashCode())
+ cc.writeClientCutText(text, text.length());
}
public void setSendingEnabled(boolean b) {
@@ -98,7 +144,8 @@
if (s instanceof JButton && (JButton)s == clearButton) {
serverCutText(new String(""), 0);
} else if (s instanceof JButton && (JButton)s == sendButton) {
- cc.writeClientCutText(textArea.getText(), textArea.getText().length());
+ String text = textArea.getText();
+ cc.writeClientCutText(text, text.length());
endDialog();
} else if (s instanceof JButton && (JButton)s == cancelButton) {
endDialog();
diff --git a/java/com/tigervnc/vncviewer/DesktopWindow.java b/java/com/tigervnc/vncviewer/DesktopWindow.java
index e78ee27..10d158c 100644
--- a/java/com/tigervnc/vncviewer/DesktopWindow.java
+++ b/java/com/tigervnc/vncviewer/DesktopWindow.java
@@ -85,7 +85,7 @@
addKeyListener(this);
addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
- checkClipboard();
+ cc.clipboardDialog.clientCutText();
}
public void focusLost(FocusEvent e) {
cc.releaseDownKeys();
@@ -359,36 +359,6 @@
g2.dispose();
}
- public synchronized void checkClipboard() {
- SecurityManager sm = System.getSecurityManager();
- try {
- if (sm != null) sm.checkSystemClipboardAccess();
- Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
- if (cb != null) {
- Transferable t = cb.getContents(null);
- if (t == null) return;
- DataFlavor flavor =
- DataFlavor.selectBestTextFlavor(t.getTransferDataFlavors());
- if (flavor == null) return;
- BufferedReader br = new BufferedReader(flavor.getReaderForText(t));
- CharBuffer cbuf =
- CharBuffer.allocate(VncViewer.maxCutText.getValue());
- br.read(cbuf);
- cbuf.flip();
- String newContents = cbuf.toString();
- if (!cc.clipboardDialog.compareContentsTo(newContents)) {
- cc.clipboardDialog.setContents(newContents);
- if (cc.viewer.sendClipboard.getValue())
- cc.writeClientCutText(newContents, newContents.length());
- }
- br.close();
- System.gc();
- }
- } catch(java.lang.Exception e) {
- vlog.debug("Exception getting clipboard data: " + e.getMessage());
- }
- }
-
// Mouse-Motion callback function
private void mouseMotionCB(MouseEvent e) {
if (!cc.viewer.viewOnly.getValue() &&
diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java
index 0df39c8..1e0f223 100644
--- a/java/com/tigervnc/vncviewer/VncViewer.java
+++ b/java/com/tigervnc/vncviewer/VncViewer.java
@@ -457,7 +457,7 @@
while (true) {
Socket new_sock = listener.accept();
if (new_sock != null)
- newViewer(this, new_sock);
+ newViewer(this, new_sock, true);
}
}
diff --git a/po/tigervnc.pot b/po/tigervnc.pot
index 5df3639..5a91804 100644
--- a/po/tigervnc.pot
+++ b/po/tigervnc.pot
@@ -8,7 +8,7 @@
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: tigervnc-devel@googlegroups.com\n"
-"POT-Creation-Date: 2014-09-22 11:15+0000\n"
+"POT-Creation-Date: 2014-11-19 12:46+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -30,7 +30,7 @@
msgid "About TigerVNC Viewer"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1086
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1097
msgid "About TigerVNC viewer..."
msgstr ""
@@ -50,7 +50,7 @@
msgid "Allow JPEG compression:"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1070
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1081
msgid "Alt"
msgstr ""
@@ -71,7 +71,7 @@
msgid "Bad Name/Value pair on line: %d in file: %s"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:92
+#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:91
msgid "BitBlt failed"
msgstr ""
@@ -101,7 +101,7 @@
msgid "Connect"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1085
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1096
msgid "Connection info..."
msgstr ""
@@ -144,6 +144,18 @@
msgid "Could not create VNC home directory: can't obtain home directory path."
msgstr ""
+#: /home/ossman/devel/tigervnc/vncviewer/OSXPixelBuffer.cxx:58
+msgid "Could not create framebuffer bitmap"
+msgstr ""
+
+#: /home/ossman/devel/tigervnc/vncviewer/OSXPixelBuffer.cxx:52
+msgid "Could not create framebuffer device"
+msgstr ""
+
+#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:107
+msgid "Could not create framebuffer image"
+msgstr ""
+
#: /home/ossman/devel/tigervnc/vncviewer/parameters.cxx:310
#, c-format
msgid "Could not encode the parameter-value %s when writing to the Registry."
@@ -156,11 +168,15 @@
"small."
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:80
+#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:68
+msgid "Couldn't find suitable pixmap format"
+msgstr ""
+
+#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:79
msgid "CreateCompatibleDC failed"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1068
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1079
msgid "Ctrl"
msgstr ""
@@ -179,10 +195,14 @@
msgid "Desktop name: %.80s"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1088
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1099
msgid "Dismiss menu"
msgstr ""
+#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:59
+msgid "Display lacks pixmap format for default depth"
+msgstr ""
+
#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:778
msgid "Enable full-screen mode over all monitors"
msgstr ""
@@ -252,24 +272,7 @@
msgid "Error(%d) writing %s(REG_SZ) to Registry."
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/OSXPixelBuffer.cxx:50
-#: /home/ossman/devel/tigervnc/vncviewer/FLTKPixelBuffer.cxx:33
-msgid "Error: Not enough memory for framebuffer"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:69
-msgid "Error: couldn't find suitable pixmap format"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:60
-msgid "Error: display lacks pixmap format for default depth"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:78
-msgid "Error: only true colour displays supported"
-msgstr ""
-
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1056
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1067
msgid "Exit viewer"
msgstr ""
@@ -310,7 +313,7 @@
msgid "Full (all available colors)"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1059
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1070
msgid "Full screen"
msgstr ""
@@ -352,7 +355,7 @@
msgid "Invalid parameter name on line: %d in file: %s"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:797
+#: /home/ossman/devel/tigervnc/vncviewer/DesktopWindow.cxx:805
msgid "Invalid screen layout computed for resize request!"
msgstr ""
@@ -399,7 +402,7 @@
msgid "Misc."
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1026
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1037
#, c-format
msgid "Multiple characters given for key code %d (0x%04x): '%s'"
msgstr ""
@@ -408,32 +411,32 @@
msgid "No"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:688
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:691
#, c-format
msgid "No scan code for extended virtual key 0x%02x"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:690
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:693
#, c-format
msgid "No scan code for virtual key 0x%02x"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:701
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:710
#, c-format
msgid "No symbol for extended virtual key 0x%02x"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:765
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:776
#, c-format
msgid "No symbol for key code %d (in the current state)"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:739
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:750
#, c-format
msgid "No symbol for key code 0x%02x (in the current state)"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:703
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:712
#, c-format
msgid "No symbol for virtual key 0x%02x"
msgstr ""
@@ -444,16 +447,26 @@
msgid "None"
msgstr ""
+#: /home/ossman/devel/tigervnc/vncviewer/OSXPixelBuffer.cxx:48
+#: /home/ossman/devel/tigervnc/vncviewer/FLTKPixelBuffer.cxx:33
+#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:111
+msgid "Not enough memory for framebuffer"
+msgstr ""
+
#: /home/ossman/devel/tigervnc/vncviewer/vncviewer.cxx:220
#: /home/ossman/devel/tigervnc/vncviewer/OptionsDialog.cxx:88
msgid "OK"
msgstr ""
+#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:77
+msgid "Only true colour displays supported"
+msgstr ""
+
#: /home/ossman/devel/tigervnc/vncviewer/UserDialog.cxx:74
msgid "Opening password file failed"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1084
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1095
#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:64
msgid "Options..."
msgstr ""
@@ -498,7 +511,7 @@
msgid "Quit"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1082
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1093
msgid "Refresh screen"
msgstr ""
@@ -515,7 +528,7 @@
msgid "Resize remote session to the local window"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1062
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1073
msgid "Resize window to session"
msgstr ""
@@ -536,16 +549,16 @@
msgid "Security method: %s"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:83
+#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:82
msgid "SelectObject failed"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1075
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1086
#, c-format
msgid "Send %s"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1080
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1091
msgid "Send Ctrl-Alt-Del"
msgstr ""
@@ -632,12 +645,17 @@
"See http://www.tigervnc.org for information on TigerVNC."
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1004
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:456
+#, c-format
+msgid "Unable to create platform specific framebuffer: %s"
+msgstr ""
+
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1015
#, c-format
msgid "Unknown FLTK key code %d (0x%04x)"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:878
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:889
#, c-format
msgid "Unknown decimal separator: '%s'"
msgstr ""
@@ -671,7 +689,7 @@
msgid "Using %s encoding"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:80
+#: /home/ossman/devel/tigervnc/vncviewer/X11PixelBuffer.cxx:79
#, c-format
msgid "Using default colormap and visual, %sdepth %d."
msgstr ""
@@ -681,6 +699,10 @@
msgid "Using pixel format %s"
msgstr ""
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:457
+msgid "Using platform independent framebuffer"
+msgstr ""
+
#: /home/ossman/devel/tigervnc/vncviewer/ServerDialog.cxx:42
msgid "VNC Viewer: Connection Details"
msgstr ""
@@ -694,7 +716,7 @@
msgid "VNC authentication"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1176
+#: /home/ossman/devel/tigervnc/vncviewer/Viewport.cxx:1187
msgid "VNC connection info"
msgstr ""
@@ -736,6 +758,6 @@
msgid "quality (0=poor, 9=best)"
msgstr ""
-#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:63
+#: /home/ossman/devel/tigervnc/vncviewer/Win32PixelBuffer.cxx:62
msgid "unable to create DIB section"
msgstr ""
diff --git a/unix/xserver/hw/vnc/xvnc.cc b/unix/xserver/hw/vnc/xvnc.cc
index 2ef888d..0fd7b0c 100644
--- a/unix/xserver/hw/vnc/xvnc.cc
+++ b/unix/xserver/hw/vnc/xvnc.cc
@@ -98,7 +98,7 @@
#define Xfree free
#endif
-#define XVNCVERSION "TigerVNC 1.3.80"
+#define XVNCVERSION "TigerVNC 1.4.80"
#define XVNCCOPYRIGHT ("Copyright (C) 1999-2013 TigerVNC Team and many others (see README.txt)\n" \
"See http://www.tigervnc.org for information on TigerVNC.\n")
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 3579618..423d2df 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -658,12 +658,20 @@
void DesktopWindow::handleDesktopSize()
{
- int width, height;
+ if (desktopSize.hasBeenSet()) {
+ int width, height;
- if (sscanf(desktopSize.getValueStr(), "%dx%d", &width, &height) != 2)
- return;
+ // An explicit size has been requested
- remoteResize(width, height);
+ if (sscanf(desktopSize.getValueStr(), "%dx%d", &width, &height) != 2)
+ return;
+
+ remoteResize(width, height);
+ } else if (::remoteResize) {
+ // No explicit size, but remote resizing is on so make sure it
+ // matches whatever size the window ended up being
+ remoteResize(w(), h());
+ }
}
diff --git a/vncviewer/FLTKPixelBuffer.cxx b/vncviewer/FLTKPixelBuffer.cxx
index 1eafe10..ab116d1 100644
--- a/vncviewer/FLTKPixelBuffer.cxx
+++ b/vncviewer/FLTKPixelBuffer.cxx
@@ -30,7 +30,7 @@
{
data = new rdr::U8[width * height * format.bpp/8];
if (data == NULL)
- throw rfb::Exception(_("Error: Not enough memory for framebuffer"));
+ throw rfb::Exception(_("Not enough memory for framebuffer"));
}
FLTKPixelBuffer::~FLTKPixelBuffer()