corrected all inconsistent eol-styles and set eol-style:native on *.java.  Also set svn:ignore on *.class

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4574 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/java/src/com/tigervnc/rfb/CSecurityTLS.java b/java/src/com/tigervnc/rfb/CSecurityTLS.java
index 977987e..355d08f 100644
--- a/java/src/com/tigervnc/rfb/CSecurityTLS.java
+++ b/java/src/com/tigervnc/rfb/CSecurityTLS.java
@@ -1,251 +1,251 @@
-/*

- * Copyright (C) 2003 Sun Microsystems, Inc.

- *

- * 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.

- */

-

+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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;
-

-import javax.net.ssl.*;

-import java.security.*;

-import java.security.cert.*;

-import java.security.KeyStore;

-import java.io.File;

-import java.io.InputStream;

-import java.io.FileInputStream;

-import java.util.ArrayList;

-import java.util.Collection;

-import javax.swing.JOptionPane;

-

-import com.tigervnc.vncviewer.UserPrefs;

-import com.tigervnc.rdr.*;

-

-public class CSecurityTLS extends CSecurity {

-

-  public static StringParameter x509ca

-  = new StringParameter("x509ca",

-                        "X509 CA certificate", "");

-  public static StringParameter x509crl

-  = new StringParameter("x509crl",

-                        "X509 CRL file", "");

-

-  private void initGlobal() 

-  {

-    try {

-      SSLSocketFactory sslfactory;

-      SSLContext ctx = SSLContext.getInstance("TLS");

-      if (anon) {

-        ctx.init(null, null, null);

-      } else {

-        TrustManager[] myTM = new TrustManager[] { 

-          new MyX509TrustManager() 

-        };

-        ctx.init (null, myTM, null);

-      }

-      sslfactory = ctx.getSocketFactory();

-      try {

-        ssl = (SSLSocket)sslfactory.createSocket(cc.sock,

-						  cc.sock.getInetAddress().getHostName(),

-						  cc.sock.getPort(), true);

-      } catch (java.io.IOException e) { 

-        throw new Exception(e.toString());

-      }

-

-      if (anon) {

-        String[] supported;

-        ArrayList enabled = new ArrayList();

-

-        supported = ssl.getSupportedCipherSuites();

-

-        for (int i = 0; i < supported.length; i++)

-          if (supported[i].matches("TLS_DH_anon.*"))

-	          enabled.add(supported[i]);

-

-        ssl.setEnabledCipherSuites((String[])enabled.toArray(new String[0]));

-      } else {

-        ssl.setEnabledCipherSuites(ssl.getSupportedCipherSuites());

-      }

-

-      ssl.setEnabledProtocols(new String[]{"SSLv3","TLSv1"});

-      ssl.addHandshakeCompletedListener(new MyHandshakeListener());

-    }

-    catch (java.security.GeneralSecurityException e)

-    {

-      vlog.error ("TLS handshake failed " + e.toString ());

-      return;

-    }

-  }

-

-  public CSecurityTLS(boolean _anon) 

-  {

-    anon = _anon;

-    setDefaults();

-    cafile = x509ca.getData(); 

-    crlfile = x509crl.getData(); 

-  }

-

-  public static void setDefaults()

-  {

-    String homeDir = null;

-    

-    if ((homeDir=UserPrefs.getHomeDir()) == null) {

-      vlog.error("Could not obtain VNC home directory path");

-      return;

-    }

-

-    String vnchomedir = homeDir+UserPrefs.getFileSeperator()+".vnc"+

-                        UserPrefs.getFileSeperator();

-    String caDefault = new String(vnchomedir+"x509_ca.pem");

-    String crlDefault = new String(vnchomedir+"x509_crl.pem");

-

-    if (new File(caDefault).exists())

-      x509ca.setDefaultStr(caDefault);

-    if (new File(crlDefault).exists())

-      x509crl.setDefaultStr(crlDefault);

-  }

-

-  public boolean processMsg(CConnection cc) {

-    is = cc.getInStream();

-    os = cc.getOutStream();

-

-    initGlobal();

-

-    if (!is.checkNoWait(1))

-      return false;

-

-    if (is.readU8() == 0) {

-      int result = is.readU32();

-      String reason;

-      if (result == Security.secResultFailed ||

-          result == Security.secResultTooMany)

-        reason = is.readString();

-      else

-        reason = new String("Authentication failure (protocol error)");

-      throw new AuthFailureException(reason);

-    }

-

-    // SSLSocket.getSession blocks until the handshake is complete

-    session = ssl.getSession();

-    if (!session.isValid())

-      throw new Exception("TLS Handshake failed!");

-

-    try {

-      cc.setStreams(new JavaInStream(ssl.getInputStream()),

-		                new JavaOutStream(ssl.getOutputStream()));

-    } catch (java.io.IOException e) { 

-      throw new Exception("Failed to set streams");

-    }

-

-    return true;

-  }

-

-  class MyHandshakeListener implements HandshakeCompletedListener {

-   public void handshakeCompleted(HandshakeCompletedEvent e) {

-     vlog.info("Handshake succesful!");

-     vlog.info("Using cipher suite: " + e.getCipherSuite());

-   }

-  }

-

-  class MyX509TrustManager implements X509TrustManager

-  {

-

-    X509TrustManager tm;

-

-    MyX509TrustManager() throws java.security.GeneralSecurityException

-    {

-      TrustManagerFactory tmf =

-        TrustManagerFactory.getInstance("PKIX");

-      KeyStore ks = KeyStore.getInstance("JKS");

-      CertificateFactory cf = CertificateFactory.getInstance("X.509");

-      try {

-        ks.load(null, null);

-        File cacert = new File(cafile);

-        if (!cacert.exists() || !cacert.canRead())

-          return;

-        InputStream caStream = new FileInputStream(cafile);

-        X509Certificate ca = (X509Certificate)cf.generateCertificate(caStream);

-        ks.setCertificateEntry("CA", ca);

-        PKIXBuilderParameters params = new PKIXBuilderParameters(ks, new X509CertSelector());

-        File crlcert = new File(crlfile);

-        if (!crlcert.exists() || !crlcert.canRead()) {

-          params.setRevocationEnabled(false);

-        } else {

-          InputStream crlStream = new FileInputStream(crlfile);

-          Collection<? extends CRL> crls = cf.generateCRLs(crlStream);

-          CertStoreParameters csp = new CollectionCertStoreParameters(crls);

-          CertStore store = CertStore.getInstance("Collection", csp);

-          params.addCertStore(store);

-          params.setRevocationEnabled(true);

-        }

-        tmf.init(new CertPathTrustManagerParameters(params));

-      } catch (java.io.FileNotFoundException e) { 

-        vlog.error(e.toString());

-      } catch (java.io.IOException e) {

-        vlog.error(e.toString());

-      }

-      tm = (X509TrustManager)tmf.getTrustManagers()[0];

-    }

-

-    public void checkClientTrusted(X509Certificate[] chain, String authType) 

-      throws CertificateException

-    {

-      tm.checkClientTrusted(chain, authType);

-    }

-

-    public void checkServerTrusted(X509Certificate[] chain, String authType)

-      throws CertificateException

-    {

-      try {

-	      tm.checkServerTrusted(chain, authType);

-      } catch (CertificateException e) {

-        Object[] answer = {"Proceed", "Exit"};

-        int ret = JOptionPane.showOptionDialog(null,

-          e.getCause().getLocalizedMessage()+"\n"+

-          "Continue connecting to this host?",

-          "Confirm certificate exception?",

-          JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,

-          null, answer, answer[0]);

-        if (ret == JOptionPane.NO_OPTION)

-          System.exit(1);

-      } catch (java.lang.Exception e) {

-        throw new Exception(e.toString());

-      }

-    }

-

-    public X509Certificate[] getAcceptedIssuers ()

-    {

-      return tm.getAcceptedIssuers();

-    }

-  }

-

-  public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; }

-  public final String description() 

-    { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }

-

-

-  //protected void setParam();

-  //protected void checkSession();

-  protected CConnection cc;

-

-  private boolean anon;

-  private SSLSession session;

-  private String cafile, crlfile;

-  private InStream is;

-  private OutStream os;

-  private SSLSocket ssl;

-

-  static LogWriter vlog = new LogWriter("CSecurityTLS");

-}

+
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.KeyStore;
+import java.io.File;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import com.tigervnc.vncviewer.UserPrefs;
+import com.tigervnc.rdr.*;
+
+public class CSecurityTLS extends CSecurity {
+
+  public static StringParameter x509ca
+  = new StringParameter("x509ca",
+                        "X509 CA certificate", "");
+  public static StringParameter x509crl
+  = new StringParameter("x509crl",
+                        "X509 CRL file", "");
+
+  private void initGlobal() 
+  {
+    try {
+      SSLSocketFactory sslfactory;
+      SSLContext ctx = SSLContext.getInstance("TLS");
+      if (anon) {
+        ctx.init(null, null, null);
+      } else {
+        TrustManager[] myTM = new TrustManager[] { 
+          new MyX509TrustManager() 
+        };
+        ctx.init (null, myTM, null);
+      }
+      sslfactory = ctx.getSocketFactory();
+      try {
+        ssl = (SSLSocket)sslfactory.createSocket(cc.sock,
+						  cc.sock.getInetAddress().getHostName(),
+						  cc.sock.getPort(), true);
+      } catch (java.io.IOException e) { 
+        throw new Exception(e.toString());
+      }
+
+      if (anon) {
+        String[] supported;
+        ArrayList enabled = new ArrayList();
+
+        supported = ssl.getSupportedCipherSuites();
+
+        for (int i = 0; i < supported.length; i++)
+          if (supported[i].matches("TLS_DH_anon.*"))
+	          enabled.add(supported[i]);
+
+        ssl.setEnabledCipherSuites((String[])enabled.toArray(new String[0]));
+      } else {
+        ssl.setEnabledCipherSuites(ssl.getSupportedCipherSuites());
+      }
+
+      ssl.setEnabledProtocols(new String[]{"SSLv3","TLSv1"});
+      ssl.addHandshakeCompletedListener(new MyHandshakeListener());
+    }
+    catch (java.security.GeneralSecurityException e)
+    {
+      vlog.error ("TLS handshake failed " + e.toString ());
+      return;
+    }
+  }
+
+  public CSecurityTLS(boolean _anon) 
+  {
+    anon = _anon;
+    setDefaults();
+    cafile = x509ca.getData(); 
+    crlfile = x509crl.getData(); 
+  }
+
+  public static void setDefaults()
+  {
+    String homeDir = null;
+    
+    if ((homeDir=UserPrefs.getHomeDir()) == null) {
+      vlog.error("Could not obtain VNC home directory path");
+      return;
+    }
+
+    String vnchomedir = homeDir+UserPrefs.getFileSeperator()+".vnc"+
+                        UserPrefs.getFileSeperator();
+    String caDefault = new String(vnchomedir+"x509_ca.pem");
+    String crlDefault = new String(vnchomedir+"x509_crl.pem");
+
+    if (new File(caDefault).exists())
+      x509ca.setDefaultStr(caDefault);
+    if (new File(crlDefault).exists())
+      x509crl.setDefaultStr(crlDefault);
+  }
+
+  public boolean processMsg(CConnection cc) {
+    is = cc.getInStream();
+    os = cc.getOutStream();
+
+    initGlobal();
+
+    if (!is.checkNoWait(1))
+      return false;
+
+    if (is.readU8() == 0) {
+      int result = is.readU32();
+      String reason;
+      if (result == Security.secResultFailed ||
+          result == Security.secResultTooMany)
+        reason = is.readString();
+      else
+        reason = new String("Authentication failure (protocol error)");
+      throw new AuthFailureException(reason);
+    }
+
+    // SSLSocket.getSession blocks until the handshake is complete
+    session = ssl.getSession();
+    if (!session.isValid())
+      throw new Exception("TLS Handshake failed!");
+
+    try {
+      cc.setStreams(new JavaInStream(ssl.getInputStream()),
+		                new JavaOutStream(ssl.getOutputStream()));
+    } catch (java.io.IOException e) { 
+      throw new Exception("Failed to set streams");
+    }
+
+    return true;
+  }
+
+  class MyHandshakeListener implements HandshakeCompletedListener {
+   public void handshakeCompleted(HandshakeCompletedEvent e) {
+     vlog.info("Handshake succesful!");
+     vlog.info("Using cipher suite: " + e.getCipherSuite());
+   }
+  }
+
+  class MyX509TrustManager implements X509TrustManager
+  {
+
+    X509TrustManager tm;
+
+    MyX509TrustManager() throws java.security.GeneralSecurityException
+    {
+      TrustManagerFactory tmf =
+        TrustManagerFactory.getInstance("PKIX");
+      KeyStore ks = KeyStore.getInstance("JKS");
+      CertificateFactory cf = CertificateFactory.getInstance("X.509");
+      try {
+        ks.load(null, null);
+        File cacert = new File(cafile);
+        if (!cacert.exists() || !cacert.canRead())
+          return;
+        InputStream caStream = new FileInputStream(cafile);
+        X509Certificate ca = (X509Certificate)cf.generateCertificate(caStream);
+        ks.setCertificateEntry("CA", ca);
+        PKIXBuilderParameters params = new PKIXBuilderParameters(ks, new X509CertSelector());
+        File crlcert = new File(crlfile);
+        if (!crlcert.exists() || !crlcert.canRead()) {
+          params.setRevocationEnabled(false);
+        } else {
+          InputStream crlStream = new FileInputStream(crlfile);
+          Collection<? extends CRL> crls = cf.generateCRLs(crlStream);
+          CertStoreParameters csp = new CollectionCertStoreParameters(crls);
+          CertStore store = CertStore.getInstance("Collection", csp);
+          params.addCertStore(store);
+          params.setRevocationEnabled(true);
+        }
+        tmf.init(new CertPathTrustManagerParameters(params));
+      } catch (java.io.FileNotFoundException e) { 
+        vlog.error(e.toString());
+      } catch (java.io.IOException e) {
+        vlog.error(e.toString());
+      }
+      tm = (X509TrustManager)tmf.getTrustManagers()[0];
+    }
+
+    public void checkClientTrusted(X509Certificate[] chain, String authType) 
+      throws CertificateException
+    {
+      tm.checkClientTrusted(chain, authType);
+    }
+
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+      throws CertificateException
+    {
+      try {
+	      tm.checkServerTrusted(chain, authType);
+      } catch (CertificateException e) {
+        Object[] answer = {"Proceed", "Exit"};
+        int ret = JOptionPane.showOptionDialog(null,
+          e.getCause().getLocalizedMessage()+"\n"+
+          "Continue connecting to this host?",
+          "Confirm certificate exception?",
+          JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+          null, answer, answer[0]);
+        if (ret == JOptionPane.NO_OPTION)
+          System.exit(1);
+      } catch (java.lang.Exception e) {
+        throw new Exception(e.toString());
+      }
+    }
+
+    public X509Certificate[] getAcceptedIssuers ()
+    {
+      return tm.getAcceptedIssuers();
+    }
+  }
+
+  public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; }
+  public final String description() 
+    { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
+
+
+  //protected void setParam();
+  //protected void checkSession();
+  protected CConnection cc;
+
+  private boolean anon;
+  private SSLSession session;
+  private String cafile, crlfile;
+  private InStream is;
+  private OutStream os;
+  private SSLSocket ssl;
+
+  static LogWriter vlog = new LogWriter("CSecurityTLS");
+}
diff --git a/java/src/com/tigervnc/rfb/CSecurityVncAuth.java b/java/src/com/tigervnc/rfb/CSecurityVncAuth.java
index 75673d5..405e79f 100644
--- a/java/src/com/tigervnc/rfb/CSecurityVncAuth.java
+++ b/java/src/com/tigervnc/rfb/CSecurityVncAuth.java
@@ -1,66 +1,66 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  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.

- */

-

+/* Copyright (C) 2002-2005 RealVNC Ltd.  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;
-

-import com.tigervnc.rdr.*;

+
+import com.tigervnc.rdr.*;
 import com.tigervnc.vncviewer.*;
-

-public class CSecurityVncAuth extends CSecurity {

-

-  public CSecurityVncAuth() { }

-

-  private static final int vncAuthChallengeSize = 16;

-

-  public boolean processMsg(CConnection cc) 

-  {

-    InStream is = cc.getInStream();

-    OutStream os = cc.getOutStream();

-

-    // Read the challenge & obtain the user's password

-    byte[] challenge = new byte[vncAuthChallengeSize];

-    is.readBytes(challenge, 0, vncAuthChallengeSize);

-    StringBuffer passwd = new StringBuffer();

-    CConn.upg.getUserPasswd(null, passwd);

-

-    // Calculate the correct response

-    byte[] key = new byte[8];

-    int pwdLen = passwd.length();

+
+public class CSecurityVncAuth extends CSecurity {
+
+  public CSecurityVncAuth() { }
+
+  private static final int vncAuthChallengeSize = 16;
+
+  public boolean processMsg(CConnection cc) 
+  {
+    InStream is = cc.getInStream();
+    OutStream os = cc.getOutStream();
+
+    // Read the challenge & obtain the user's password
+    byte[] challenge = new byte[vncAuthChallengeSize];
+    is.readBytes(challenge, 0, vncAuthChallengeSize);
+    StringBuffer passwd = new StringBuffer();
+    CConn.upg.getUserPasswd(null, passwd);
+
+    // Calculate the correct response
+    byte[] key = new byte[8];
+    int pwdLen = passwd.length();
     byte[] utf8str = new byte[pwdLen];
     try {
       utf8str = passwd.toString().getBytes("UTF8");
     } catch(java.io.UnsupportedEncodingException e) {
       e.printStackTrace();
     }
-    for (int i=0; i<8; i++)

-      key[i] = i<pwdLen ? utf8str[i] : 0;

-    DesCipher des = new DesCipher(key);

-    for (int j = 0; j < vncAuthChallengeSize; j += 8)

-      des.encrypt(challenge,j,challenge,j);

-

-    // Return the response to the server

-    os.writeBytes(challenge, 0, vncAuthChallengeSize);

-    os.flush();

-    return true;

-  }

-

-  public int getType() { return Security.secTypeVncAuth; }

-  public String description() { return "No Encryption"; }

-

-  static LogWriter vlog = new LogWriter("VncAuth");

-}

+    for (int i=0; i<8; i++)
+      key[i] = i<pwdLen ? utf8str[i] : 0;
+    DesCipher des = new DesCipher(key);
+    for (int j = 0; j < vncAuthChallengeSize; j += 8)
+      des.encrypt(challenge,j,challenge,j);
+
+    // Return the response to the server
+    os.writeBytes(challenge, 0, vncAuthChallengeSize);
+    os.flush();
+    return true;
+  }
+
+  public int getType() { return Security.secTypeVncAuth; }
+  public String description() { return "No Encryption"; }
+
+  static LogWriter vlog = new LogWriter("VncAuth");
+}
diff --git a/java/src/com/tigervnc/rfb/StringParameter.java b/java/src/com/tigervnc/rfb/StringParameter.java
index 4f704d9..d7fd1a5 100644
--- a/java/src/com/tigervnc/rfb/StringParameter.java
+++ b/java/src/com/tigervnc/rfb/StringParameter.java
@@ -1,46 +1,46 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  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.

- */

-

+/* Copyright (C) 2002-2005 RealVNC Ltd.  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 StringParameter extends VoidParameter {

-  public StringParameter(String name_, String desc_, String v) {

-    super(name_, desc_);

-    value = v;

-    defValue = v;

-  }

-

-  public boolean setParam(String v) {

-    value = v;

-    return value != null;

-  }

-

-  public boolean setDefaultStr(String v) {

-    value = defValue = v;

-    return defValue != null;

-  }

-

-  public String getDefaultStr() { return defValue; }

-  public String getValueStr() { return value; }

-

-  public String getValue() { return value; }

-  public String getData() { return value; }

-

-  protected String value;

-  protected String defValue;

-}

+
+public class StringParameter extends VoidParameter {
+  public StringParameter(String name_, String desc_, String v) {
+    super(name_, desc_);
+    value = v;
+    defValue = v;
+  }
+
+  public boolean setParam(String v) {
+    value = v;
+    return value != null;
+  }
+
+  public boolean setDefaultStr(String v) {
+    value = defValue = v;
+    return defValue != null;
+  }
+
+  public String getDefaultStr() { return defValue; }
+  public String getValueStr() { return value; }
+
+  public String getValue() { return value; }
+  public String getData() { return value; }
+
+  protected String value;
+  protected String defValue;
+}
diff --git a/java/src/com/tigervnc/vncviewer/CConn.java b/java/src/com/tigervnc/vncviewer/CConn.java
index 9224aa1..9ce75fc 100644
--- a/java/src/com/tigervnc/vncviewer/CConn.java
+++ b/java/src/com/tigervnc/vncviewer/CConn.java
@@ -1,287 +1,287 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  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.

- */

+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
 
-//

-// CConn

-//

-// Methods on CConn are called from both the GUI thread and the thread which

-// processes incoming RFB messages ("the RFB thread").  This means we need to

-// be careful with synchronization here.

-//

-// Any access to writer() must not only be synchronized, but we must also make

-// sure that the connection is in RFBSTATE_NORMAL.  We are guaranteed this for

-// any code called after serverInit() has been called.  Since the DesktopWindow

-// isn't created until then, any methods called only from DesktopWindow can

-// assume that we are in RFBSTATE_NORMAL.

-

-package com.tigervnc.vncviewer;

-

+//
+// CConn
+//
+// Methods on CConn are called from both the GUI thread and the thread which
+// processes incoming RFB messages ("the RFB thread").  This means we need to
+// be careful with synchronization here.
+//
+// Any access to writer() must not only be synchronized, but we must also make
+// sure that the connection is in RFBSTATE_NORMAL.  We are guaranteed this for
+// any code called after serverInit() has been called.  Since the DesktopWindow
+// isn't created until then, any methods called only from DesktopWindow can
+// assume that we are in RFBSTATE_NORMAL.
+
+package com.tigervnc.vncviewer;
+
 import java.awt.Color;
 import java.awt.Graphics;
-import java.awt.event.*;

-import java.awt.Component;

-import java.awt.Dimension;

-import java.awt.Event;

-import java.awt.Frame;

-import java.awt.ScrollPane;

-

-import java.io.*;

-import javax.net.ssl.*;

-import java.io.IOException;

-import java.io.InputStream;

-import java.io.OutputStream;

-import java.io.File;

-import java.util.jar.Attributes;

-import java.util.jar.Manifest;

-import javax.swing.*;

-import javax.swing.filechooser.*;

-import javax.swing.ImageIcon;

-import java.net.URL;

-import java.net.ServerSocket;

-import javax.swing.border.*;

-import java.util.*;

+import java.awt.event.*;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Frame;
+import java.awt.ScrollPane;
+
+import java.io.*;
+import javax.net.ssl.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.ImageIcon;
+import java.net.URL;
+import java.net.ServerSocket;
+import javax.swing.border.*;
+import java.util.*;
 
 import com.tigervnc.rdr.*;
 import com.tigervnc.rfb.*;
 import com.tigervnc.rfb.Exception;
 import com.tigervnc.rfb.Point;
 import com.tigervnc.rfb.Rect;
-

-class ViewportFrame extends JFrame 

-{

-  public ViewportFrame(String name, CConn cc_) {

-    cc = cc_;

-    setTitle("TigerVNC: "+name);

-    setFocusable(false);

-    setFocusTraversalKeysEnabled(false);

-    addWindowFocusListener(new WindowAdapter() {

-      public void windowGainedFocus(WindowEvent e) {

-        sp.getViewport().getView().requestFocusInWindow();

-      }

-    });

-    addWindowListener(new WindowAdapter() {

-      public void windowClosing(WindowEvent e) {

-        cc.close();

-      }

-    });

-  }

-

-  public void addChild(DesktopWindow child) {

-    sp = new JScrollPane(child);

-    child.setBackground(Color.BLACK);

-    child.setOpaque(true);

-    sp.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));

-    getContentPane().add(sp);

-  }

-

-  public void setChild(DesktopWindow child) {

+
+class ViewportFrame extends JFrame 
+{
+  public ViewportFrame(String name, CConn cc_) {
+    cc = cc_;
+    setTitle("TigerVNC: "+name);
+    setFocusable(false);
+    setFocusTraversalKeysEnabled(false);
+    addWindowFocusListener(new WindowAdapter() {
+      public void windowGainedFocus(WindowEvent e) {
+        sp.getViewport().getView().requestFocusInWindow();
+      }
+    });
+    addWindowListener(new WindowAdapter() {
+      public void windowClosing(WindowEvent e) {
+        cc.close();
+      }
+    });
+  }
+
+  public void addChild(DesktopWindow child) {
+    sp = new JScrollPane(child);
+    child.setBackground(Color.BLACK);
+    child.setOpaque(true);
+    sp.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
+    getContentPane().add(sp);
+  }
+
+  public void setChild(DesktopWindow child) {
     getContentPane().removeAll();
     addChild(child);
-  }

-

-  public void setGeometry(int x, int y, int w, int h) {

-    pack();

-    if (cc.fullScreen) setSize(w, h);

-    setLocation(x, y);

-    setBackground(Color.BLACK);

-  }

-

-

-  CConn cc;

-  Graphics g;

-  JScrollPane sp;

-  static LogWriter vlog = new LogWriter("ViewportFrame");

-}

-

-public class CConn extends CConnection

-  implements UserPasswdGetter, UserMsgBox, OptionsDialogCallback

-{

-  ////////////////////////////////////////////////////////////////////

-  // The following methods are all called from the RFB thread

-

-  public CConn(VncViewer viewer_, java.net.Socket sock_, 

-               String vncServerName, boolean reverse) 

-  {

-    serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_; 

-    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;

-    fullScreen = viewer.fullScreen.getValue();

-    menuKey = Keysyms.F8;

-    options = new OptionsDialog(this);

-    clipboardDialog = new ClipboardDialog(this);

-    firstUpdate = true; pendingUpdate = false;

-

-    setShared(shared);

-    upg = this;

-    msg = this;

-

-    String encStr = viewer.preferredEncoding.getValue();

-    int encNum = Encodings.encodingNum(encStr);

-    if (encNum != -1) {

-      currentEncoding = encNum;

-    }

-    cp.supportsDesktopResize = true;

-    cp.supportsExtendedDesktopSize = true;

-    cp.supportsDesktopRename = true;

-    cp.supportsLocalCursor = viewer.useLocalCursor.getValue();

-    cp.customCompressLevel = viewer.customCompressLevel.getValue();

-    cp.compressLevel = viewer.compressLevel.getValue();

-    cp.noJpeg = viewer.noJpeg.getValue();

-    cp.qualityLevel = viewer.qualityLevel.getValue();

-    initMenu();

-

-    if (sock != null) {

-      String name = sock.getRemoteSocketAddress()+"::"+sock.getPort();

-      vlog.info("Accepted connection from "+name);

-    } else {

-      if (vncServerName != null) {

-        serverHost = Hostname.getHost(vncServerName);

-        serverPort = Hostname.getPort(vncServerName);

-      } else {

-        ServerDialog dlg = new ServerDialog(options, vncServerName, this);

-        if (!dlg.showDialog() || dlg.server.getSelectedItem().equals("")) {

-          System.exit(1);

-        }

-        vncServerName = (String)dlg.server.getSelectedItem();

-        serverHost = Hostname.getHost(vncServerName);

-        serverPort = Hostname.getPort(vncServerName);

-      }

-

-      try {

-        sock = new java.net.Socket(serverHost, serverPort);

-      } catch (java.io.IOException e) { 

-        throw new Exception(e.toString());

-      }

-      vlog.info("connected to host "+serverHost+" port "+serverPort);

-    }

-

-    sameMachine = (sock.getLocalSocketAddress() == sock.getRemoteSocketAddress());

-    try {

-      sock.setTcpNoDelay(true);

-      sock.setTrafficClass(0x10);

-      setServerName(serverHost);

-      jis = new JavaInStream(sock.getInputStream());

-      jos = new JavaOutStream(sock.getOutputStream());

-    } catch (java.net.SocketException e) {

-      throw new Exception(e.toString());

-    } catch (java.io.IOException e) { 

-      throw new Exception(e.toString());

-    }

-    setStreams(jis, jos);

-    initialiseProtocol();

-  }

-

-  public boolean showMsgBox(int flags, String title, String text)

-  {

-    StringBuffer titleText = new StringBuffer("VNC Viewer: "+title);

-

-    return true;

-  }

-

-  // deleteWindow() is called when the user closes the desktop or menu windows.

-

-  void deleteWindow() {

-    if (viewport != null)

-      viewport.dispose();

-    viewport = null;

-  } 

-

-  // getUserPasswd() is called by the CSecurity object when it needs us to read

-  // a password from the user.

-

-  public final boolean getUserPasswd(StringBuffer user, StringBuffer passwd) {

-    String title = ("VNC Authentication ["

-                    +csecurity.description() + "]");

-    PasswdDialog dlg;    

-    if (user == null) {

-      dlg = new PasswdDialog(title, (user == null), (passwd == null));

-    } else {

-      if ((passwd == null) && viewer.sendLocalUsername.getValue()) {

-         user.append((String)System.getProperties().get("user.name"));

-         return true;

-      }

-      dlg = new PasswdDialog(title, viewer.sendLocalUsername.getValue(), 

-         (passwd == null));

-    }

-    if (!dlg.showDialog()) return false;

-    if (user != null) {

-      if (viewer.sendLocalUsername.getValue()) {

-         user.append((String)System.getProperties().get("user.name"));

-      } else {

-         user.append(dlg.userEntry.getText());

-      }

-    }

-    if (passwd != null)

-      passwd.append(dlg.passwdEntry.getText());

-    return true;

-  }

-

-  // CConnection callback methods

-

-  // serverInit() is called when the serverInit message has been received.  At

-  // this point we create the desktop window and display it.  We also tell the

-  // server the pixel format and encodings to use and request the first update.

-  public void serverInit() {

-    super.serverInit();

-

-    // If using AutoSelect with old servers, start in FullColor

-    // mode. See comment in autoSelectFormatAndEncoding. 

-    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.getPF();

-    if (!serverPF.trueColour)

-      fullColour = true;

-    recreateViewport();

-    formatChange = true; encodingChange = true;

-    requestNewUpdate();

-  }

-

-  // setDesktopSize() is called when the desktop size changes (including when

-  // it is set initially).

-  public void setDesktopSize(int w, int h) {

-    super.setDesktopSize(w,h);

-    resizeFramebuffer();

-  }

-

-  // setExtendedDesktopSize() is a more advanced version of setDesktopSize()

-  public void setExtendedDesktopSize(int reason, int result, int w, int h,

-                                     ScreenSet layout) {

-    super.setExtendedDesktopSize(reason, result, w, h, layout);

+  }
 
-    if ((reason == screenTypes.reasonClient) &&

-        (result != screenTypes.resultSuccess)) {

-      vlog.error("SetDesktopSize failed: "+result);

-      return;

-    }

-

+  public void setGeometry(int x, int y, int w, int h) {
+    pack();
+    if (cc.fullScreen) setSize(w, h);
+    setLocation(x, y);
+    setBackground(Color.BLACK);
+  }
+
+
+  CConn cc;
+  Graphics g;
+  JScrollPane sp;
+  static LogWriter vlog = new LogWriter("ViewportFrame");
+}
+
+public class CConn extends CConnection
+  implements UserPasswdGetter, UserMsgBox, OptionsDialogCallback
+{
+  ////////////////////////////////////////////////////////////////////
+  // The following methods are all called from the RFB thread
+
+  public CConn(VncViewer viewer_, java.net.Socket sock_, 
+               String vncServerName, boolean reverse) 
+  {
+    serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_; 
+    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;
+    fullScreen = viewer.fullScreen.getValue();
+    menuKey = Keysyms.F8;
+    options = new OptionsDialog(this);
+    clipboardDialog = new ClipboardDialog(this);
+    firstUpdate = true; pendingUpdate = false;
+
+    setShared(shared);
+    upg = this;
+    msg = this;
+
+    String encStr = viewer.preferredEncoding.getValue();
+    int encNum = Encodings.encodingNum(encStr);
+    if (encNum != -1) {
+      currentEncoding = encNum;
+    }
+    cp.supportsDesktopResize = true;
+    cp.supportsExtendedDesktopSize = true;
+    cp.supportsDesktopRename = true;
+    cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
+    cp.customCompressLevel = viewer.customCompressLevel.getValue();
+    cp.compressLevel = viewer.compressLevel.getValue();
+    cp.noJpeg = viewer.noJpeg.getValue();
+    cp.qualityLevel = viewer.qualityLevel.getValue();
+    initMenu();
+
+    if (sock != null) {
+      String name = sock.getRemoteSocketAddress()+"::"+sock.getPort();
+      vlog.info("Accepted connection from "+name);
+    } else {
+      if (vncServerName != null) {
+        serverHost = Hostname.getHost(vncServerName);
+        serverPort = Hostname.getPort(vncServerName);
+      } else {
+        ServerDialog dlg = new ServerDialog(options, vncServerName, this);
+        if (!dlg.showDialog() || dlg.server.getSelectedItem().equals("")) {
+          System.exit(1);
+        }
+        vncServerName = (String)dlg.server.getSelectedItem();
+        serverHost = Hostname.getHost(vncServerName);
+        serverPort = Hostname.getPort(vncServerName);
+      }
+
+      try {
+        sock = new java.net.Socket(serverHost, serverPort);
+      } catch (java.io.IOException e) { 
+        throw new Exception(e.toString());
+      }
+      vlog.info("connected to host "+serverHost+" port "+serverPort);
+    }
+
+    sameMachine = (sock.getLocalSocketAddress() == sock.getRemoteSocketAddress());
+    try {
+      sock.setTcpNoDelay(true);
+      sock.setTrafficClass(0x10);
+      setServerName(serverHost);
+      jis = new JavaInStream(sock.getInputStream());
+      jos = new JavaOutStream(sock.getOutputStream());
+    } catch (java.net.SocketException e) {
+      throw new Exception(e.toString());
+    } catch (java.io.IOException e) { 
+      throw new Exception(e.toString());
+    }
+    setStreams(jis, jos);
+    initialiseProtocol();
+  }
+
+  public boolean showMsgBox(int flags, String title, String text)
+  {
+    StringBuffer titleText = new StringBuffer("VNC Viewer: "+title);
+
+    return true;
+  }
+
+  // deleteWindow() is called when the user closes the desktop or menu windows.
+
+  void deleteWindow() {
+    if (viewport != null)
+      viewport.dispose();
+    viewport = null;
+  } 
+
+  // getUserPasswd() is called by the CSecurity object when it needs us to read
+  // a password from the user.
+
+  public final boolean getUserPasswd(StringBuffer user, StringBuffer passwd) {
+    String title = ("VNC Authentication ["
+                    +csecurity.description() + "]");
+    PasswdDialog dlg;    
+    if (user == null) {
+      dlg = new PasswdDialog(title, (user == null), (passwd == null));
+    } else {
+      if ((passwd == null) && viewer.sendLocalUsername.getValue()) {
+         user.append((String)System.getProperties().get("user.name"));
+         return true;
+      }
+      dlg = new PasswdDialog(title, viewer.sendLocalUsername.getValue(), 
+         (passwd == null));
+    }
+    if (!dlg.showDialog()) return false;
+    if (user != null) {
+      if (viewer.sendLocalUsername.getValue()) {
+         user.append((String)System.getProperties().get("user.name"));
+      } else {
+         user.append(dlg.userEntry.getText());
+      }
+    }
+    if (passwd != null)
+      passwd.append(dlg.passwdEntry.getText());
+    return true;
+  }
+
+  // CConnection callback methods
+
+  // serverInit() is called when the serverInit message has been received.  At
+  // this point we create the desktop window and display it.  We also tell the
+  // server the pixel format and encodings to use and request the first update.
+  public void serverInit() {
+    super.serverInit();
+
+    // If using AutoSelect with old servers, start in FullColor
+    // mode. See comment in autoSelectFormatAndEncoding. 
+    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.getPF();
+    if (!serverPF.trueColour)
+      fullColour = true;
+    recreateViewport();
+    formatChange = true; encodingChange = true;
+    requestNewUpdate();
+  }
+
+  // setDesktopSize() is called when the desktop size changes (including when
+  // it is set initially).
+  public void setDesktopSize(int w, int h) {
+    super.setDesktopSize(w,h);
     resizeFramebuffer();
-  }

-

+  }
+
+  // setExtendedDesktopSize() is a more advanced version of setDesktopSize()
+  public void setExtendedDesktopSize(int reason, int result, int w, int h,
+                                     ScreenSet layout) {
+    super.setExtendedDesktopSize(reason, result, w, h, layout);
+
+    if ((reason == screenTypes.reasonClient) &&
+        (result != screenTypes.resultSuccess)) {
+      vlog.error("SetDesktopSize failed: "+result);
+      return;
+    }
+
+    resizeFramebuffer();
+  }
+
   // clientRedirect() migrates the client to another host/port
   public void clientRedirect(int port, String host, 
                              String x509subject) {
@@ -301,899 +301,899 @@
     }
   }
 
-  // setName() is called when the desktop name changes

-  public void setName(String name) {

-    super.setName(name);

-  

-    if (viewport != null) {

-      viewport.setTitle("TigerVNC: "+name);

-    }

-  }

-

-  // 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;

-  }

-

-  // 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();

-

-    if (firstUpdate) {

-      int width, height;

-      

-      if (cp.supportsSetDesktopSize &&

-          viewer.desktopSize.getValue() != null &&

-          viewer.desktopSize.getValue().split("x").length == 2) {

-        width = Integer.parseInt(viewer.desktopSize.getValue().split("x")[0]);

-        height = Integer.parseInt(viewer.desktopSize.getValue().split("x")[1]);

-        ScreenSet layout;

-

-        layout = cp.screenLayout;

-

-        if (layout.num_screens() == 0)

-          layout.add_screen(new Screen());

-        else if (layout.num_screens() != 1) {

-

-          while (true) {

-            Iterator iter = layout.screens.iterator(); 

-            Screen screen = (Screen)iter.next();

-        

-            if (!iter.hasNext())

-              break;

-

-            layout.remove_screen(screen.id);

-          }

-        }

-

-        Screen screen0 = (Screen)layout.screens.iterator().next();

-        screen0.dimensions.tl.x = 0;

-        screen0.dimensions.tl.y = 0;

-        screen0.dimensions.br.x = width;

-        screen0.dimensions.br.y = height;

-

-        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();

-

-    // Compute new settings based on updated bandwidth values

-    if (autoSelect)

-      autoSelectFormatAndEncoding();

-  }

-

-  // The rest of the callbacks are fairly self-explanatory...

-

-  public void setColourMapEntries(int firstColour, int nColours, int[] rgbs) {

-    desktop.setColourMapEntries(firstColour, nColours, rgbs);

-  }

-

-  public void bell() { desktop.getToolkit().beep(); }

-

-  public void serverCutText(String str, int len) {

-    if (viewer.acceptClipboard.getValue())

-      clipboardDialog.serverCutText(str, len);

-  }

-

-  // We start timing on beginRect and stop timing on endRect, to

-  // avoid skewing the bandwidth estimation as a result of the server

-  // being slow or the network having high latency

-  public void beginRect(Rect r, int encoding) {

-    ((JavaInStream)getInStream()).startTiming();

-    if (encoding != Encodings.encodingCopyRect) {

-      lastServerEncoding = encoding;

-    }

-  }

-

-  public void endRect(Rect r, int encoding) {

-    ((JavaInStream)getInStream()).stopTiming();

-  }

-

-  public void fillRect(Rect r, int p) {

-    desktop.fillRect(r.tl.x, r.tl.y, r.width(), r.height(), p);

-  }

-  public void imageRect(Rect r, int[] p) {

-    desktop.imageRect(r.tl.x, r.tl.y, r.width(), r.height(), p);

-  }

-  public void copyRect(Rect r, int sx, int sy) {

-    desktop.copyRect(r.tl.x, r.tl.y, r.width(), r.height(), sx, sy);

-  }

-

-  public void setCursor(int width, int height, Point hotspot,

-                        int[] data, byte[] mask) {

-    desktop.setCursor(width, height, hotspot, data, mask);

-  }

-

-  private void resizeFramebuffer()

-  {

-    if ((cp.width == 0) && (cp.height == 0))

-      return;

-    if (desktop == null)

-      return;

-    if ((desktop.width() == cp.width) && (desktop.height() == cp.height))

-      return;

-    

-    desktop.resize();

-    recreateViewport();

-  }

-

-  // recreateViewport() recreates our top-level window.  This seems to be

-  // better than attempting to resize the existing window, at least with

-  // various X window managers.

-

-  private void recreateViewport()

-  {

-    if (viewport != null) viewport.dispose();

-    viewport = new ViewportFrame(cp.name(), this);

-    viewport.setUndecorated(fullScreen);

+  // setName() is called when the desktop name changes
+  public void setName(String name) {
+    super.setName(name);
+  
+    if (viewport != null) {
+      viewport.setTitle("TigerVNC: "+name);
+    }
+  }
+
+  // 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;
+  }
+
+  // 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();
+
+    if (firstUpdate) {
+      int width, height;
+      
+      if (cp.supportsSetDesktopSize &&
+          viewer.desktopSize.getValue() != null &&
+          viewer.desktopSize.getValue().split("x").length == 2) {
+        width = Integer.parseInt(viewer.desktopSize.getValue().split("x")[0]);
+        height = Integer.parseInt(viewer.desktopSize.getValue().split("x")[1]);
+        ScreenSet layout;
+
+        layout = cp.screenLayout;
+
+        if (layout.num_screens() == 0)
+          layout.add_screen(new Screen());
+        else if (layout.num_screens() != 1) {
+
+          while (true) {
+            Iterator iter = layout.screens.iterator(); 
+            Screen screen = (Screen)iter.next();
+        
+            if (!iter.hasNext())
+              break;
+
+            layout.remove_screen(screen.id);
+          }
+        }
+
+        Screen screen0 = (Screen)layout.screens.iterator().next();
+        screen0.dimensions.tl.x = 0;
+        screen0.dimensions.tl.y = 0;
+        screen0.dimensions.br.x = width;
+        screen0.dimensions.br.y = height;
+
+        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();
+
+    // Compute new settings based on updated bandwidth values
+    if (autoSelect)
+      autoSelectFormatAndEncoding();
+  }
+
+  // The rest of the callbacks are fairly self-explanatory...
+
+  public void setColourMapEntries(int firstColour, int nColours, int[] rgbs) {
+    desktop.setColourMapEntries(firstColour, nColours, rgbs);
+  }
+
+  public void bell() { desktop.getToolkit().beep(); }
+
+  public void serverCutText(String str, int len) {
+    if (viewer.acceptClipboard.getValue())
+      clipboardDialog.serverCutText(str, len);
+  }
+
+  // We start timing on beginRect and stop timing on endRect, to
+  // avoid skewing the bandwidth estimation as a result of the server
+  // being slow or the network having high latency
+  public void beginRect(Rect r, int encoding) {
+    ((JavaInStream)getInStream()).startTiming();
+    if (encoding != Encodings.encodingCopyRect) {
+      lastServerEncoding = encoding;
+    }
+  }
+
+  public void endRect(Rect r, int encoding) {
+    ((JavaInStream)getInStream()).stopTiming();
+  }
+
+  public void fillRect(Rect r, int p) {
+    desktop.fillRect(r.tl.x, r.tl.y, r.width(), r.height(), p);
+  }
+  public void imageRect(Rect r, int[] p) {
+    desktop.imageRect(r.tl.x, r.tl.y, r.width(), r.height(), p);
+  }
+  public void copyRect(Rect r, int sx, int sy) {
+    desktop.copyRect(r.tl.x, r.tl.y, r.width(), r.height(), sx, sy);
+  }
+
+  public void setCursor(int width, int height, Point hotspot,
+                        int[] data, byte[] mask) {
+    desktop.setCursor(width, height, hotspot, data, mask);
+  }
+
+  private void resizeFramebuffer()
+  {
+    if ((cp.width == 0) && (cp.height == 0))
+      return;
+    if (desktop == null)
+      return;
+    if ((desktop.width() == cp.width) && (desktop.height() == cp.height))
+      return;
+    
+    desktop.resize();
+    recreateViewport();
+  }
+
+  // recreateViewport() recreates our top-level window.  This seems to be
+  // better than attempting to resize the existing window, at least with
+  // various X window managers.
+
+  private void recreateViewport()
+  {
+    if (viewport != null) viewport.dispose();
+    viewport = new ViewportFrame(cp.name(), this);
+    viewport.setUndecorated(fullScreen);
     desktop.setViewport(viewport);
-    ClassLoader loader = this.getClass().getClassLoader();

-    URL url = loader.getResource("com/tigervnc/vncviewer/tigervnc.ico");

-    ImageIcon icon = null;

-    if (url != null) {

-      icon = new ImageIcon(url);

-      viewport.setIconImage(icon.getImage());

-    }

-    viewport.addChild(desktop);

-    reconfigureViewport();

-    viewport.setVisible(true);

-    desktop.initGraphics();

-    desktop.requestFocusInWindow();

-  }

-

-  private void reconfigureViewport()

-  {

-    //viewport->setMaxSize(cp.width, cp.height);

-    if (fullScreen) {

-      Dimension dpySize = viewport.getToolkit().getScreenSize();

-      viewport.setExtendedState(JFrame.MAXIMIZED_BOTH);

-      viewport.setGeometry(0, 0, dpySize.width, dpySize.height);

-    } else {

-      int w = cp.width;

-      int h = cp.height;

-      Dimension dpySize = viewport.getToolkit().getScreenSize();

-      int wmDecorationWidth = 0;

-      int wmDecorationHeight = 24;

-      if (w + wmDecorationWidth >= dpySize.width)

-        w = dpySize.width - wmDecorationWidth;

-      if (h + wmDecorationHeight >= dpySize.height)

-        h = dpySize.height - wmDecorationHeight;

-

-      int x = (dpySize.width - w - wmDecorationWidth) / 2;

-      int y = (dpySize.height - h - wmDecorationHeight)/2;

-

-      viewport.setExtendedState(JFrame.NORMAL);

-      viewport.setGeometry(x, y, w, h);

-    }

-  }

-

-  // autoSelectFormatAndEncoding() chooses the format and encoding appropriate

-  // to the connection speed:

-  //

-  //   First we wait for at least one second of bandwidth measurement.

-  //

-  //   Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,

-  //   which should be perceptually lossless.

-  //

-  //   If the bandwidth is below that, we choose a more lossy JPEG quality.

-  //

-  //   If the bandwidth drops below 256 Kbps, we switch to palette mode.

-  //

-  //   Note: The system here is fairly arbitrary and should be replaced

-  //         with something more intelligent at the server end.

-  //

-  private void autoSelectFormatAndEncoding() {

-    long kbitsPerSecond = ((JavaInStream)getInStream()).kbitsPerSecond();

-    long timeWaited = ((JavaInStream)getInStream()).timeWaited();

-    boolean newFullColour = fullColour;

-    int newQualityLevel = cp.qualityLevel;

-

-    // Always use Tight

-    if (currentEncoding != Encodings.encodingTight) {

-      currentEncoding = Encodings.encodingTight;

-      encodingChange = true;

-    }

-

-    // Check that we have a decent bandwidth measurement

-    if ((kbitsPerSecond == 0) || (timeWaited < 10000))

-      return;

-  

-    // Select appropriate quality level

-    if (!cp.noJpeg) {

-      if (kbitsPerSecond > 16000)

-        newQualityLevel = 8;

-      else

-        newQualityLevel = 6;

-  

-      if (newQualityLevel != cp.qualityLevel) {

-        vlog.info("Throughput "+kbitsPerSecond+

-                  " kbit/s - changing to quality "+newQualityLevel);

-        cp.qualityLevel = newQualityLevel;

-        viewer.qualityLevel.setParam(Integer.toString(newQualityLevel));

-        encodingChange = true;

-      }

-    }

-

-    if (cp.beforeVersion(3, 8)) {

-      // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with

-      // cursors "asynchronously". If this happens in the middle of a

-      // pixel format change, the server will encode the cursor with

-      // the old format, but the client will try to decode it

-      // according to the new format. This will lead to a

-      // crash. Therefore, we do not allow automatic format change for

-      // old servers.

-      return;

-    }

-    

-    // Select best color level

-    newFullColour = (kbitsPerSecond > 256);

-    if (newFullColour != fullColour) {

-      vlog.info("Throughput "+kbitsPerSecond+

-                " kbit/s - full color is now "+ 

-  	            (newFullColour ? "enabled" : "disabled"));

-      fullColour = newFullColour;

-      formatChange = true;

-    } 

-  }

-

-  // requestNewUpdate() requests an update from the server, having set the

-  // format and encoding appropriately.

-  private void requestNewUpdate()

-  {

-    if (formatChange) {

+    ClassLoader loader = this.getClass().getClassLoader();
+    URL url = loader.getResource("com/tigervnc/vncviewer/tigervnc.ico");
+    ImageIcon icon = null;
+    if (url != null) {
+      icon = new ImageIcon(url);
+      viewport.setIconImage(icon.getImage());
+    }
+    viewport.addChild(desktop);
+    reconfigureViewport();
+    viewport.setVisible(true);
+    desktop.initGraphics();
+    desktop.requestFocusInWindow();
+  }
+
+  private void reconfigureViewport()
+  {
+    //viewport->setMaxSize(cp.width, cp.height);
+    if (fullScreen) {
+      Dimension dpySize = viewport.getToolkit().getScreenSize();
+      viewport.setExtendedState(JFrame.MAXIMIZED_BOTH);
+      viewport.setGeometry(0, 0, dpySize.width, dpySize.height);
+    } else {
+      int w = cp.width;
+      int h = cp.height;
+      Dimension dpySize = viewport.getToolkit().getScreenSize();
+      int wmDecorationWidth = 0;
+      int wmDecorationHeight = 24;
+      if (w + wmDecorationWidth >= dpySize.width)
+        w = dpySize.width - wmDecorationWidth;
+      if (h + wmDecorationHeight >= dpySize.height)
+        h = dpySize.height - wmDecorationHeight;
+
+      int x = (dpySize.width - w - wmDecorationWidth) / 2;
+      int y = (dpySize.height - h - wmDecorationHeight)/2;
+
+      viewport.setExtendedState(JFrame.NORMAL);
+      viewport.setGeometry(x, y, w, h);
+    }
+  }
+
+  // autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+  // to the connection speed:
+  //
+  //   First we wait for at least one second of bandwidth measurement.
+  //
+  //   Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,
+  //   which should be perceptually lossless.
+  //
+  //   If the bandwidth is below that, we choose a more lossy JPEG quality.
+  //
+  //   If the bandwidth drops below 256 Kbps, we switch to palette mode.
+  //
+  //   Note: The system here is fairly arbitrary and should be replaced
+  //         with something more intelligent at the server end.
+  //
+  private void autoSelectFormatAndEncoding() {
+    long kbitsPerSecond = ((JavaInStream)getInStream()).kbitsPerSecond();
+    long timeWaited = ((JavaInStream)getInStream()).timeWaited();
+    boolean newFullColour = fullColour;
+    int newQualityLevel = cp.qualityLevel;
+
+    // Always use Tight
+    if (currentEncoding != Encodings.encodingTight) {
+      currentEncoding = Encodings.encodingTight;
+      encodingChange = true;
+    }
+
+    // Check that we have a decent bandwidth measurement
+    if ((kbitsPerSecond == 0) || (timeWaited < 10000))
+      return;
+  
+    // Select appropriate quality level
+    if (!cp.noJpeg) {
+      if (kbitsPerSecond > 16000)
+        newQualityLevel = 8;
+      else
+        newQualityLevel = 6;
+  
+      if (newQualityLevel != cp.qualityLevel) {
+        vlog.info("Throughput "+kbitsPerSecond+
+                  " kbit/s - changing to quality "+newQualityLevel);
+        cp.qualityLevel = newQualityLevel;
+        viewer.qualityLevel.setParam(Integer.toString(newQualityLevel));
+        encodingChange = true;
+      }
+    }
+
+    if (cp.beforeVersion(3, 8)) {
+      // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+      // cursors "asynchronously". If this happens in the middle of a
+      // pixel format change, the server will encode the cursor with
+      // the old format, but the client will try to decode it
+      // according to the new format. This will lead to a
+      // crash. Therefore, we do not allow automatic format change for
+      // old servers.
+      return;
+    }
+    
+    // Select best color level
+    newFullColour = (kbitsPerSecond > 256);
+    if (newFullColour != fullColour) {
+      vlog.info("Throughput "+kbitsPerSecond+
+                " kbit/s - full color is now "+ 
+  	            (newFullColour ? "enabled" : "disabled"));
+      fullColour = newFullColour;
+      formatChange = true;
+    } 
+  }
+
+  // requestNewUpdate() requests an update from the server, having set the
+  // format and encoding appropriately.
+  private void requestNewUpdate()
+  {
+    if (formatChange) {
 
       /* Catch incorrect requestNewUpdate calls */
       assert(pendingUpdate == false);
 
-      if (fullColour) {

-        desktop.setPF(fullColourPF);

-      } else {

-        if (lowColourLevel == 0) {

-          desktop.setPF(new PixelFormat(8,3,false,true,1,1,1,2,1,0));

-        } else if (lowColourLevel == 1) {

-          desktop.setPF(new PixelFormat(8,6,false,true,3,3,3,4,2,0));

-        } else {

-          desktop.setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));

-        }

-      }

-      String str = desktop.getPF().print();

-      vlog.info("Using pixel format "+str);

-      cp.setPF(desktop.getPF());

-      synchronized (this) {

-        writer().writeSetPixelFormat(cp.pf());

-      }

-    }

-    checkEncodings();

-    synchronized (this) {

-      writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),

-                                             !formatChange);

-    }

-    formatChange = false;

-  }

-

-

-  ////////////////////////////////////////////////////////////////////

-  // The following methods are all called from the GUI thread

-

-  // close() closes the socket, thus waking up the RFB thread.

-  public void close() {

-    try {

-      shuttingDown = true;

-      sock.close();

-    } catch (java.io.IOException e) {

-      e.printStackTrace();

-    }

-  }

-

-  // Menu callbacks.  These are guaranteed only to be called after serverInit()

-  // has been called, since the menu is only accessible from the DesktopWindow

-

-  private void initMenu() {

-    menu = new F8Menu(this);

-  }

-

-  void showMenu(int x, int y) {

-    String os = System.getProperty("os.name");

-    if (os.startsWith("Windows"))

-      com.sun.java.swing.plaf.windows.WindowsLookAndFeel.setMnemonicHidden(false);

-    menu.show(desktop, x, y);

-  }

-

-  void showAbout() {

-    InputStream stream = cl.getResourceAsStream("com/tigervnc/vncviewer/timestamp");

-    String pkgDate = "";

-    String pkgTime = "";

-    try {

-      Manifest manifest = new Manifest(stream);

-      Attributes attributes = manifest.getMainAttributes();

-      pkgDate = attributes.getValue("Package-Date");

-      pkgTime = attributes.getValue("Package-Time");

-    } catch (IOException e) { }

-    JOptionPane.showMessageDialog((viewport != null ? viewport : null),

-      VncViewer.about1+"\n"

-      +"Built on "+pkgDate+" at "+pkgTime+"\n"

-      +VncViewer.about2+"\n"

-      +VncViewer.about3,

-      "About TigerVNC Viewer for Java",

-      JOptionPane.INFORMATION_MESSAGE,

-      logo);

-  }

-

-  void showInfo() {

-    JOptionPane.showMessageDialog(viewport,

-      "Desktop name: "+cp.name()+"\n"

-      +"Host: "+serverHost+":"+sock.getPort()+"\n"

-      +"Size: "+cp.width+"x"+cp.height+"\n"

-      +"Pixel format: "+desktop.getPF().print()+"\n"

-      +"(server default "+serverPF.print()+")\n"

-      +"Requested encoding: "+Encodings.encodingName(currentEncoding)+"\n"

-      +"Last used encoding: "+Encodings.encodingName(lastServerEncoding)+"\n"

-      +"Line speed estimate: "+((JavaInStream)getInStream()).kbitsPerSecond()+" kbit/s"+"\n"

-      +"Protocol version: "+cp.majorVersion+"."+cp.minorVersion+"\n"

-      +"Security method: "+Security.secTypeName(csecurity.getType())

-       +" ["+csecurity.description()+"]",

-      "VNC connection info",

-      JOptionPane.PLAIN_MESSAGE);

-  }

-

-  synchronized public void refresh() {

-    writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height), false);

+      if (fullColour) {
+        desktop.setPF(fullColourPF);
+      } else {
+        if (lowColourLevel == 0) {
+          desktop.setPF(new PixelFormat(8,3,false,true,1,1,1,2,1,0));
+        } else if (lowColourLevel == 1) {
+          desktop.setPF(new PixelFormat(8,6,false,true,3,3,3,4,2,0));
+        } else {
+          desktop.setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+        }
+      }
+      String str = desktop.getPF().print();
+      vlog.info("Using pixel format "+str);
+      cp.setPF(desktop.getPF());
+      synchronized (this) {
+        writer().writeSetPixelFormat(cp.pf());
+      }
+    }
+    checkEncodings();
+    synchronized (this) {
+      writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),
+                                             !formatChange);
+    }
+    formatChange = false;
+  }
+
+
+  ////////////////////////////////////////////////////////////////////
+  // The following methods are all called from the GUI thread
+
+  // close() closes the socket, thus waking up the RFB thread.
+  public void close() {
+    try {
+      shuttingDown = true;
+      sock.close();
+    } catch (java.io.IOException e) {
+      e.printStackTrace();
+    }
+  }
+
+  // Menu callbacks.  These are guaranteed only to be called after serverInit()
+  // has been called, since the menu is only accessible from the DesktopWindow
+
+  private void initMenu() {
+    menu = new F8Menu(this);
+  }
+
+  void showMenu(int x, int y) {
+    String os = System.getProperty("os.name");
+    if (os.startsWith("Windows"))
+      com.sun.java.swing.plaf.windows.WindowsLookAndFeel.setMnemonicHidden(false);
+    menu.show(desktop, x, y);
+  }
+
+  void showAbout() {
+    InputStream stream = cl.getResourceAsStream("com/tigervnc/vncviewer/timestamp");
+    String pkgDate = "";
+    String pkgTime = "";
+    try {
+      Manifest manifest = new Manifest(stream);
+      Attributes attributes = manifest.getMainAttributes();
+      pkgDate = attributes.getValue("Package-Date");
+      pkgTime = attributes.getValue("Package-Time");
+    } catch (IOException e) { }
+    JOptionPane.showMessageDialog((viewport != null ? viewport : null),
+      VncViewer.about1+"\n"
+      +"Built on "+pkgDate+" at "+pkgTime+"\n"
+      +VncViewer.about2+"\n"
+      +VncViewer.about3,
+      "About TigerVNC Viewer for Java",
+      JOptionPane.INFORMATION_MESSAGE,
+      logo);
+  }
+
+  void showInfo() {
+    JOptionPane.showMessageDialog(viewport,
+      "Desktop name: "+cp.name()+"\n"
+      +"Host: "+serverHost+":"+sock.getPort()+"\n"
+      +"Size: "+cp.width+"x"+cp.height+"\n"
+      +"Pixel format: "+desktop.getPF().print()+"\n"
+      +"(server default "+serverPF.print()+")\n"
+      +"Requested encoding: "+Encodings.encodingName(currentEncoding)+"\n"
+      +"Last used encoding: "+Encodings.encodingName(lastServerEncoding)+"\n"
+      +"Line speed estimate: "+((JavaInStream)getInStream()).kbitsPerSecond()+" kbit/s"+"\n"
+      +"Protocol version: "+cp.majorVersion+"."+cp.minorVersion+"\n"
+      +"Security method: "+Security.secTypeName(csecurity.getType())
+       +" ["+csecurity.description()+"]",
+      "VNC connection info",
+      JOptionPane.PLAIN_MESSAGE);
+  }
+
+  synchronized public void refresh() {
+    writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height), false);
     pendingUpdate = true;
-  }

-

-

-  // OptionsDialogCallback.  setOptions() sets the options dialog's checkboxes

-  // etc to reflect our flags.  getOptions() sets our flags according to the

-  // options dialog's checkboxes.  They are both called from the GUI thread.

-  // Some of the flags are also accessed by the RFB thread.  I believe that

-  // reading and writing boolean and int values in java is atomic, so there is

-  // no need for synchronization.

-

-  public void setOptions() {

-    int digit;

-    options.autoSelect.setSelected(autoSelect);

-    options.fullColour.setSelected(fullColour);

-    options.veryLowColour.setSelected(!fullColour && lowColourLevel == 0);

-    options.lowColour.setSelected(!fullColour && lowColourLevel == 1);

-    options.mediumColour.setSelected(!fullColour && lowColourLevel == 2);

-    options.tight.setSelected(currentEncoding == Encodings.encodingTight);

-    options.zrle.setSelected(currentEncoding == Encodings.encodingZRLE);

-    options.hextile.setSelected(currentEncoding == Encodings.encodingHextile);

-    options.raw.setSelected(currentEncoding == Encodings.encodingRaw);

-

-    options.customCompressLevel.setSelected(viewer.customCompressLevel.getValue());

-    digit = 0 + viewer.compressLevel.getValue();

-    options.compressLevel.setSelectedItem(digit);

-    options.noJpeg.setSelected(!viewer.noJpeg.getValue());

-    digit = 0 + viewer.qualityLevel.getValue();

-    options.qualityLevel.setSelectedItem(digit);

-

-    options.viewOnly.setSelected(viewer.viewOnly.getValue());

-    options.acceptClipboard.setSelected(viewer.acceptClipboard.getValue());

-    options.sendClipboard.setSelected(viewer.sendClipboard.getValue());

-    options.menuKey.setSelectedIndex(menuKey-0xFFBE);

-

-    if (state() == RFBSTATE_NORMAL) {

-      options.shared.setEnabled(false);

-      options.secVeNCrypt.setEnabled(false);

-      options.encNone.setEnabled(false);

-      options.encTLS.setEnabled(false);

-      options.encX509.setEnabled(false);

-      options.ca.setEnabled(false);

-      options.crl.setEnabled(false);

-      options.secIdent.setEnabled(false);

-      options.secNone.setEnabled(false);

-      options.secVnc.setEnabled(false);

-      options.secPlain.setEnabled(false);

-      options.sendLocalUsername.setEnabled(false);

-    } else {

-      options.shared.setSelected(shared);

-

-      /* Process non-VeNCrypt sectypes */

-      java.util.List<Integer> secTypes = new ArrayList<Integer>();

-      secTypes = security.GetEnabledSecTypes();

-      for (Iterator i = secTypes.iterator(); i.hasNext();) {

-        switch ((Integer)i.next()) {

-        case Security.secTypeVeNCrypt:

-          options.secVeNCrypt.setSelected(true);

-          break;

-        case Security.secTypeNone:

-          options.encNone.setSelected(true);

-          options.secNone.setSelected(true);

-          break;

-        case Security.secTypeVncAuth:

-          options.encNone.setSelected(true);

-          options.secVnc.setSelected(true);

-          break;

-        }

-      }

-

-      /* Process VeNCrypt subtypes */

-      if (options.secVeNCrypt.isSelected()) {

-        java.util.List<Integer> secTypesExt = new ArrayList<Integer>();

-        secTypesExt = security.GetEnabledExtSecTypes();

-        for (Iterator iext = secTypesExt.iterator(); iext.hasNext();) {

-          switch ((Integer)iext.next()) {

-          case Security.secTypePlain:

-            options.secPlain.setSelected(true);

-            options.sendLocalUsername.setSelected(true);

-            break;

-          case Security.secTypeIdent:

-            options.secIdent.setSelected(true);

-            options.sendLocalUsername.setSelected(true);

-            break;

-          case Security.secTypeTLSNone:

-            options.encTLS.setSelected(true);

-            options.secNone.setSelected(true);

-            break;

-          case Security.secTypeTLSVnc:

-            options.encTLS.setSelected(true);

-            options.secVnc.setSelected(true);

-            break;

-          case Security.secTypeTLSPlain:

-            options.encTLS.setSelected(true);

-            options.secPlain.setSelected(true);

-            options.sendLocalUsername.setSelected(true);

-            break;

-          case Security.secTypeTLSIdent:

-            options.encTLS.setSelected(true);

-            options.secIdent.setSelected(true);

-            options.sendLocalUsername.setSelected(true);

-            break;

-          case Security.secTypeX509None:

-            options.encX509.setSelected(true);

-            options.secNone.setSelected(true);

-            break;

-          case Security.secTypeX509Vnc:

-            options.encX509.setSelected(true);

-            options.secVnc.setSelected(true);

-            break;

-          case Security.secTypeX509Plain:

-            options.encX509.setSelected(true);

-            options.secPlain.setSelected(true);

-            options.sendLocalUsername.setSelected(true);

-            break;

-          case Security.secTypeX509Ident:

-            options.encX509.setSelected(true);

-            options.secIdent.setSelected(true);

-            options.sendLocalUsername.setSelected(true);

-            break;

-          }

-        }

-      }

-      options.sendLocalUsername.setEnabled(options.secPlain.isSelected()||

-        options.secIdent.isSelected());

-    }

-

-    options.fullScreen.setSelected(fullScreen);

-    options.useLocalCursor.setSelected(viewer.useLocalCursor.getValue());

-    options.fastCopyRect.setSelected(viewer.fastCopyRect.getValue());

-  }

-

-  public void getOptions() {

-    autoSelect = options.autoSelect.isSelected();

-    if (fullColour != options.fullColour.isSelected())

-      formatChange = true;

-    fullColour = options.fullColour.isSelected();

-    if (!fullColour) {

-      int newLowColourLevel = (options.veryLowColour.isSelected() ? 0 :

-                               options.lowColour.isSelected() ? 1 : 2);

-      if (newLowColourLevel != lowColourLevel) {

-        lowColourLevel = newLowColourLevel;

-        formatChange = true;

-      }

-    }

-    int newEncoding = (options.zrle.isSelected() ?  Encodings.encodingZRLE :

-                       options.hextile.isSelected() ?  Encodings.encodingHextile :

-                       options.tight.isSelected() ?  Encodings.encodingTight :

-                       Encodings.encodingRaw);

-    if (newEncoding != currentEncoding) {

-      currentEncoding = newEncoding;

-      encodingChange = true;

-    }

-

-    viewer.customCompressLevel.setParam(options.customCompressLevel.isSelected());

-    if (cp.customCompressLevel != viewer.customCompressLevel.getValue()) {

-      cp.customCompressLevel = viewer.customCompressLevel.getValue();

-      encodingChange = true;

-    }

-    viewer.compressLevel.setParam(options.compressLevel.getSelectedItem().toString());

-    if (cp.compressLevel != viewer.compressLevel.getValue()) {

-      cp.compressLevel = viewer.compressLevel.getValue();

-      encodingChange = true;

-    }

-    viewer.noJpeg.setParam(!options.noJpeg.isSelected());

-    if (cp.noJpeg != viewer.noJpeg.getValue()) {

-      cp.noJpeg = viewer.noJpeg.getValue();

-      encodingChange = true;

-    }

-    viewer.qualityLevel.setParam(options.qualityLevel.getSelectedItem().toString());

-    if (cp.qualityLevel != viewer.qualityLevel.getValue()) {

-      cp.qualityLevel = viewer.qualityLevel.getValue();

-      encodingChange = true;

-    }

-    viewer.sendLocalUsername.setParam(options.sendLocalUsername.isSelected());

-

-    viewer.viewOnly.setParam(options.viewOnly.isSelected());

-    viewer.acceptClipboard.setParam(options.acceptClipboard.isSelected());

-    viewer.sendClipboard.setParam(options.sendClipboard.isSelected());

-    clipboardDialog.setSendingEnabled(viewer.sendClipboard.getValue());

-    menuKey = (int)(options.menuKey.getSelectedIndex()+0xFFBE);

-    F8Menu.f8.setLabel("Send F"+(menuKey-Keysyms.F1+1));

-

-    shared = options.shared.isSelected();

-    setShared(shared);

-    viewer.useLocalCursor.setParam(options.useLocalCursor.isSelected());

-    if (cp.supportsLocalCursor != viewer.useLocalCursor.getValue()) {

-      cp.supportsLocalCursor = viewer.useLocalCursor.getValue();

-      encodingChange = true;

-      if (desktop != null)

-        desktop.resetLocalCursor();

-    }

-    

-    checkEncodings();

-  

-    if (state() != RFBSTATE_NORMAL) {

-      /* Process security types which don't use encryption */

-      if (options.encNone.isSelected()) {

-        if (options.secNone.isSelected())

-          Security.EnableSecType(Security.secTypeNone);

-        if (options.secVnc.isSelected())

-          Security.EnableSecType(Security.secTypeVncAuth);

-        if (options.secPlain.isSelected())

-          Security.EnableSecType(Security.secTypePlain);

-        if (options.secIdent.isSelected())

-          Security.EnableSecType(Security.secTypeIdent);

-      } else {

-        Security.DisableSecType(Security.secTypeNone);

-        Security.DisableSecType(Security.secTypeVncAuth);

-        Security.DisableSecType(Security.secTypePlain);

-        Security.DisableSecType(Security.secTypeIdent);

-      }

-

-      /* Process security types which use TLS encryption */

-      if (options.encTLS.isSelected()) {

-        if (options.secNone.isSelected())

-          Security.EnableSecType(Security.secTypeTLSNone);

-        if (options.secVnc.isSelected())

-          Security.EnableSecType(Security.secTypeTLSVnc);

-        if (options.secPlain.isSelected())

-          Security.EnableSecType(Security.secTypeTLSPlain);

-        if (options.secIdent.isSelected())

-          Security.EnableSecType(Security.secTypeTLSIdent);

-      } else {

-        Security.DisableSecType(Security.secTypeTLSNone);

-        Security.DisableSecType(Security.secTypeTLSVnc);

-        Security.DisableSecType(Security.secTypeTLSPlain);

-        Security.DisableSecType(Security.secTypeTLSIdent);

-      }

-  

-      /* Process security types which use X509 encryption */

-      if (options.encX509.isSelected()) {

-        if (options.secNone.isSelected())

-          Security.EnableSecType(Security.secTypeX509None);

-        if (options.secVnc.isSelected())

-          Security.EnableSecType(Security.secTypeX509Vnc);

-        if (options.secPlain.isSelected())

-          Security.EnableSecType(Security.secTypeX509Plain);

-        if (options.secIdent.isSelected())

-          Security.EnableSecType(Security.secTypeX509Ident);

-      } else {

-        Security.DisableSecType(Security.secTypeX509None);

-        Security.DisableSecType(Security.secTypeX509Vnc);

-        Security.DisableSecType(Security.secTypeX509Plain);

-        Security.DisableSecType(Security.secTypeX509Ident);

-      }

-  

-      /* Process *None security types */

-      if (options.secNone.isSelected()) {

-        if (options.encNone.isSelected())

-          Security.EnableSecType(Security.secTypeNone);

-        if (options.encTLS.isSelected())

-          Security.EnableSecType(Security.secTypeTLSNone);

-        if (options.encX509.isSelected())

-          Security.EnableSecType(Security.secTypeX509None);

-      } else {

-        Security.DisableSecType(Security.secTypeNone);

-        Security.DisableSecType(Security.secTypeTLSNone);

-        Security.DisableSecType(Security.secTypeX509None);

-      }

-  

-      /* Process *Vnc security types */

-      if (options.secVnc.isSelected()) {

-        if (options.encNone.isSelected())

-          Security.EnableSecType(Security.secTypeVncAuth);

-        if (options.encTLS.isSelected())

-          Security.EnableSecType(Security.secTypeTLSVnc);

-        if (options.encX509.isSelected())

-          Security.EnableSecType(Security.secTypeX509Vnc);

-      } else {

-        Security.DisableSecType(Security.secTypeVncAuth);

-        Security.DisableSecType(Security.secTypeTLSVnc);

-        Security.DisableSecType(Security.secTypeX509Vnc);

-      }

-  

-      /* Process *Plain security types */

-      if (options.secPlain.isSelected()) {

-        if (options.encNone.isSelected())

-          Security.EnableSecType(Security.secTypePlain);

-        if (options.encTLS.isSelected())

-          Security.EnableSecType(Security.secTypeTLSPlain);

-        if (options.encX509.isSelected())

-          Security.EnableSecType(Security.secTypeX509Plain);

-      } else {

-        Security.DisableSecType(Security.secTypePlain);

-        Security.DisableSecType(Security.secTypeTLSPlain);

-        Security.DisableSecType(Security.secTypeX509Plain);

-      }

-  

-      /* Process *Ident security types */

-      if (options.secIdent.isSelected()) {

-        if (options.encNone.isSelected())

-          Security.EnableSecType(Security.secTypeIdent);

-        if (options.encTLS.isSelected())

-          Security.EnableSecType(Security.secTypeTLSIdent);

-        if (options.encX509.isSelected())

-          Security.EnableSecType(Security.secTypeX509Ident);

-      } else {

-        Security.DisableSecType(Security.secTypeIdent);

-        Security.DisableSecType(Security.secTypeTLSIdent);

-        Security.DisableSecType(Security.secTypeX509Ident);

-      }

-  

-      CSecurityTLS.x509ca.setParam(options.ca.getText());

-      CSecurityTLS.x509crl.setParam(options.crl.getText());

-    }

-  }

-

-  public void toggleFullScreen() {

-    fullScreen = !fullScreen;

-    if (!fullScreen) menu.fullScreen.setSelected(false);

-    recreateViewport();

-  }

-

-  // writeClientCutText() is called from the clipboard dialog

-  synchronized public void writeClientCutText(String str, int len) {

-    if (state() != RFBSTATE_NORMAL) return;

-    writer().writeClientCutText(str,len);

-  }

-

-  synchronized public void writeKeyEvent(int keysym, boolean down) {

-    if (state() != RFBSTATE_NORMAL) return;

-    writer().writeKeyEvent(keysym, down);

-  }

-

-  synchronized public void writeKeyEvent(KeyEvent ev) {

-    if (ev.getID() != KeyEvent.KEY_PRESSED && !ev.isActionKey())

-      return;

-

-    int keysym;

-

-    if (!ev.isActionKey()) {

-      vlog.debug("key press "+ev.getKeyChar());

-      if (ev.getKeyChar() < 32) {

-        // if the ctrl modifier key is down, send the equivalent ASCII since we

-        // will send the ctrl modifier anyway

-

-        if ((ev.getModifiers() & KeyEvent.CTRL_MASK) != 0) {

-          if ((ev.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {

-            keysym = ev.getKeyChar() + 64;

-            if (keysym == -1)

-              return;

-          } else { 

-            keysym = ev.getKeyChar() + 96;

-            if (keysym == 127) keysym = 95;

-          }

-        } else {

-          switch (ev.getKeyCode()) {

-          case KeyEvent.VK_BACK_SPACE: keysym = Keysyms.BackSpace; break;

-          case KeyEvent.VK_TAB:        keysym = Keysyms.Tab; break;

-          case KeyEvent.VK_ENTER:      keysym = Keysyms.Return; break;

-          case KeyEvent.VK_ESCAPE:     keysym = Keysyms.Escape; break;

-          default: return;

-          }

-        }

-

-      } else if (ev.getKeyChar() == 127) {

-        keysym = Keysyms.Delete;

-

-      } else {

-        keysym = UnicodeToKeysym.translate(ev.getKeyChar());

-        if (keysym == -1)

-          return;

-      }

-

-    } else {

-      // KEY_ACTION

-      vlog.debug("key action "+ev.getKeyCode());

-      switch (ev.getKeyCode()) {

-      case KeyEvent.VK_HOME:         keysym = Keysyms.Home; break;

-      case KeyEvent.VK_END:          keysym = Keysyms.End; break;

-      case KeyEvent.VK_PAGE_UP:      keysym = Keysyms.Page_Up; break;

-      case KeyEvent.VK_PAGE_DOWN:    keysym = Keysyms.Page_Down; break;

-      case KeyEvent.VK_UP:           keysym = Keysyms.Up; break;

-      case KeyEvent.VK_DOWN:         keysym = Keysyms.Down; break;

-      case KeyEvent.VK_LEFT:         keysym = Keysyms.Left; break;

-      case KeyEvent.VK_RIGHT:        keysym = Keysyms.Right; break;

-      case KeyEvent.VK_F1:           keysym = Keysyms.F1; break;

-      case KeyEvent.VK_F2:           keysym = Keysyms.F2; break;

-      case KeyEvent.VK_F3:           keysym = Keysyms.F3; break;

-      case KeyEvent.VK_F4:           keysym = Keysyms.F4; break;

-      case KeyEvent.VK_F5:           keysym = Keysyms.F5; break;

-      case KeyEvent.VK_F6:           keysym = Keysyms.F6; break;

-      case KeyEvent.VK_F7:           keysym = Keysyms.F7; break;

-      case KeyEvent.VK_F8:           keysym = Keysyms.F8; break;

-      case KeyEvent.VK_F9:           keysym = Keysyms.F9; break;

-      case KeyEvent.VK_F10:          keysym = Keysyms.F10; break;

-      case KeyEvent.VK_F11:          keysym = Keysyms.F11; break;

-      case KeyEvent.VK_F12:          keysym = Keysyms.F12; break;

-      case KeyEvent.VK_PRINTSCREEN:  keysym = Keysyms.Print; break;

-      case KeyEvent.VK_PAUSE:        keysym = Keysyms.Pause; break;

-      case KeyEvent.VK_INSERT:       keysym = Keysyms.Insert; break;

-      default: return;

-      }

-    }

-

-    writeModifiers(ev.getModifiers());

-    writeKeyEvent(keysym, true);

-    writeKeyEvent(keysym, false);

-    writeModifiers(0);

-  }

-

-

-  synchronized public void writePointerEvent(MouseEvent ev) {

-    if (state() != RFBSTATE_NORMAL) return;

-    int x, y;

-

-    switch (ev.getID()) {

-    case MouseEvent.MOUSE_PRESSED:

-      buttonMask = 1;

-      if ((ev.getModifiers() & KeyEvent.ALT_MASK) != 0) buttonMask = 2;

-      if ((ev.getModifiers() & KeyEvent.META_MASK) != 0) buttonMask = 4;

-      break;

-    case MouseEvent.MOUSE_RELEASED:

-      buttonMask = 0;

-      break;

-    }

-

-    writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);

-

-    x = ev.getX();

-    y = ev.getY();

-    if (x < 0) x = 0;

-    if (x > cp.width-1) x = cp.width-1;

-    if (y < 0) y = 0;

-    if (y > cp.height-1) y = cp.height-1;

-

-    writer().writePointerEvent(new Point(x, y), buttonMask);

-

-    if (buttonMask == 0) writeModifiers(0);

-  }

-

-

-  synchronized public void writeWheelEvent(MouseWheelEvent ev) {

-    if (state() != RFBSTATE_NORMAL) return;

-    int x, y;

-    int clicks = ev.getWheelRotation();

-    if (clicks < 0) {

-      buttonMask = 8;

-    } else {

-      buttonMask = 16;

-    }

-    writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);

-    for (int i=0;i<java.lang.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);

-    }

-    writeModifiers(0);

-

-  }

-

-

-  void writeModifiers(int m) {

-    if ((m & Event.SHIFT_MASK) != (pressedModifiers & Event.SHIFT_MASK))

-      writeKeyEvent(Keysyms.Shift_L, (m & Event.SHIFT_MASK) != 0);

-    if ((m & Event.CTRL_MASK) != (pressedModifiers & Event.CTRL_MASK))

-      writeKeyEvent(Keysyms.Control_L, (m & Event.CTRL_MASK) != 0);

-    if ((m & Event.ALT_MASK) != (pressedModifiers & Event.ALT_MASK))

-      writeKeyEvent(Keysyms.Alt_L, (m & Event.ALT_MASK) != 0);

-    if ((m & Event.META_MASK) != (pressedModifiers & Event.META_MASK))

-      writeKeyEvent(Keysyms.Meta_L, (m & Event.META_MASK) != 0);

-    pressedModifiers = m;

-  }

-

-

-  ////////////////////////////////////////////////////////////////////

-  // 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) {

-      vlog.info("Using "+Encodings.encodingName(currentEncoding)+" encoding");

-      writer().writeSetEncodings(currentEncoding, true);

-      encodingChange = false;

-    }

-  }

-

-  // the following never change so need no synchronization:

-  JavaInStream jis;

-  JavaOutStream jos;

-

-

-  // viewer object is only ever accessed by the GUI thread so needs no

-  // synchronization (except for one test in DesktopWindow - see comment

-  // there).

-  VncViewer viewer;

-

-  // access to desktop by different threads is specified in DesktopWindow

-

-  // the following need no synchronization:

-

-  ClassLoader cl = this.getClass().getClassLoader();

-  ImageIcon logo = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.png"));

-  public static UserPasswdGetter upg;

-  public UserMsgBox msg;

-

-  // shuttingDown is set by the GUI thread and only ever tested by the RFB

-  // thread after the window has been destroyed.

-  boolean shuttingDown;

-

-  // reading and writing int and boolean is atomic in java, so no

-  // synchronization of the following flags is needed:

-  int currentEncoding, lastServerEncoding;

-  

-  int lowColourLevel;

-

-

-  // All menu, options, about and info stuff is done in the GUI thread (apart

-  // from when constructed).

-  F8Menu menu;

-  OptionsDialog options;

-

-  // clipboard sync issues?

-  ClipboardDialog clipboardDialog;

-

-  // the following are only ever accessed by the GUI thread:

-  int buttonMask;

-  int pressedModifiers;

-

-  public String serverHost;

-  public int serverPort;

-  public int menuKey;

-  PixelFormat serverPF;

-  ViewportFrame viewport;

-  DesktopWindow desktop;

-  PixelFormat fullColourPF;

-  boolean fullColour;

-  boolean autoSelect;

-  boolean shared;

-  boolean formatChange;

-  boolean encodingChange;

-  boolean sameMachine;

-  boolean fullScreen;

-  boolean reverseConnection;

-  boolean firstUpdate;

-  boolean pendingUpdate;

-  

-  static LogWriter vlog = new LogWriter("CConn");

-}

+  }
+
+
+  // OptionsDialogCallback.  setOptions() sets the options dialog's checkboxes
+  // etc to reflect our flags.  getOptions() sets our flags according to the
+  // options dialog's checkboxes.  They are both called from the GUI thread.
+  // Some of the flags are also accessed by the RFB thread.  I believe that
+  // reading and writing boolean and int values in java is atomic, so there is
+  // no need for synchronization.
+
+  public void setOptions() {
+    int digit;
+    options.autoSelect.setSelected(autoSelect);
+    options.fullColour.setSelected(fullColour);
+    options.veryLowColour.setSelected(!fullColour && lowColourLevel == 0);
+    options.lowColour.setSelected(!fullColour && lowColourLevel == 1);
+    options.mediumColour.setSelected(!fullColour && lowColourLevel == 2);
+    options.tight.setSelected(currentEncoding == Encodings.encodingTight);
+    options.zrle.setSelected(currentEncoding == Encodings.encodingZRLE);
+    options.hextile.setSelected(currentEncoding == Encodings.encodingHextile);
+    options.raw.setSelected(currentEncoding == Encodings.encodingRaw);
+
+    options.customCompressLevel.setSelected(viewer.customCompressLevel.getValue());
+    digit = 0 + viewer.compressLevel.getValue();
+    options.compressLevel.setSelectedItem(digit);
+    options.noJpeg.setSelected(!viewer.noJpeg.getValue());
+    digit = 0 + viewer.qualityLevel.getValue();
+    options.qualityLevel.setSelectedItem(digit);
+
+    options.viewOnly.setSelected(viewer.viewOnly.getValue());
+    options.acceptClipboard.setSelected(viewer.acceptClipboard.getValue());
+    options.sendClipboard.setSelected(viewer.sendClipboard.getValue());
+    options.menuKey.setSelectedIndex(menuKey-0xFFBE);
+
+    if (state() == RFBSTATE_NORMAL) {
+      options.shared.setEnabled(false);
+      options.secVeNCrypt.setEnabled(false);
+      options.encNone.setEnabled(false);
+      options.encTLS.setEnabled(false);
+      options.encX509.setEnabled(false);
+      options.ca.setEnabled(false);
+      options.crl.setEnabled(false);
+      options.secIdent.setEnabled(false);
+      options.secNone.setEnabled(false);
+      options.secVnc.setEnabled(false);
+      options.secPlain.setEnabled(false);
+      options.sendLocalUsername.setEnabled(false);
+    } else {
+      options.shared.setSelected(shared);
+
+      /* Process non-VeNCrypt sectypes */
+      java.util.List<Integer> secTypes = new ArrayList<Integer>();
+      secTypes = security.GetEnabledSecTypes();
+      for (Iterator i = secTypes.iterator(); i.hasNext();) {
+        switch ((Integer)i.next()) {
+        case Security.secTypeVeNCrypt:
+          options.secVeNCrypt.setSelected(true);
+          break;
+        case Security.secTypeNone:
+          options.encNone.setSelected(true);
+          options.secNone.setSelected(true);
+          break;
+        case Security.secTypeVncAuth:
+          options.encNone.setSelected(true);
+          options.secVnc.setSelected(true);
+          break;
+        }
+      }
+
+      /* Process VeNCrypt subtypes */
+      if (options.secVeNCrypt.isSelected()) {
+        java.util.List<Integer> secTypesExt = new ArrayList<Integer>();
+        secTypesExt = security.GetEnabledExtSecTypes();
+        for (Iterator iext = secTypesExt.iterator(); iext.hasNext();) {
+          switch ((Integer)iext.next()) {
+          case Security.secTypePlain:
+            options.secPlain.setSelected(true);
+            options.sendLocalUsername.setSelected(true);
+            break;
+          case Security.secTypeIdent:
+            options.secIdent.setSelected(true);
+            options.sendLocalUsername.setSelected(true);
+            break;
+          case Security.secTypeTLSNone:
+            options.encTLS.setSelected(true);
+            options.secNone.setSelected(true);
+            break;
+          case Security.secTypeTLSVnc:
+            options.encTLS.setSelected(true);
+            options.secVnc.setSelected(true);
+            break;
+          case Security.secTypeTLSPlain:
+            options.encTLS.setSelected(true);
+            options.secPlain.setSelected(true);
+            options.sendLocalUsername.setSelected(true);
+            break;
+          case Security.secTypeTLSIdent:
+            options.encTLS.setSelected(true);
+            options.secIdent.setSelected(true);
+            options.sendLocalUsername.setSelected(true);
+            break;
+          case Security.secTypeX509None:
+            options.encX509.setSelected(true);
+            options.secNone.setSelected(true);
+            break;
+          case Security.secTypeX509Vnc:
+            options.encX509.setSelected(true);
+            options.secVnc.setSelected(true);
+            break;
+          case Security.secTypeX509Plain:
+            options.encX509.setSelected(true);
+            options.secPlain.setSelected(true);
+            options.sendLocalUsername.setSelected(true);
+            break;
+          case Security.secTypeX509Ident:
+            options.encX509.setSelected(true);
+            options.secIdent.setSelected(true);
+            options.sendLocalUsername.setSelected(true);
+            break;
+          }
+        }
+      }
+      options.sendLocalUsername.setEnabled(options.secPlain.isSelected()||
+        options.secIdent.isSelected());
+    }
+
+    options.fullScreen.setSelected(fullScreen);
+    options.useLocalCursor.setSelected(viewer.useLocalCursor.getValue());
+    options.fastCopyRect.setSelected(viewer.fastCopyRect.getValue());
+  }
+
+  public void getOptions() {
+    autoSelect = options.autoSelect.isSelected();
+    if (fullColour != options.fullColour.isSelected())
+      formatChange = true;
+    fullColour = options.fullColour.isSelected();
+    if (!fullColour) {
+      int newLowColourLevel = (options.veryLowColour.isSelected() ? 0 :
+                               options.lowColour.isSelected() ? 1 : 2);
+      if (newLowColourLevel != lowColourLevel) {
+        lowColourLevel = newLowColourLevel;
+        formatChange = true;
+      }
+    }
+    int newEncoding = (options.zrle.isSelected() ?  Encodings.encodingZRLE :
+                       options.hextile.isSelected() ?  Encodings.encodingHextile :
+                       options.tight.isSelected() ?  Encodings.encodingTight :
+                       Encodings.encodingRaw);
+    if (newEncoding != currentEncoding) {
+      currentEncoding = newEncoding;
+      encodingChange = true;
+    }
+
+    viewer.customCompressLevel.setParam(options.customCompressLevel.isSelected());
+    if (cp.customCompressLevel != viewer.customCompressLevel.getValue()) {
+      cp.customCompressLevel = viewer.customCompressLevel.getValue();
+      encodingChange = true;
+    }
+    viewer.compressLevel.setParam(options.compressLevel.getSelectedItem().toString());
+    if (cp.compressLevel != viewer.compressLevel.getValue()) {
+      cp.compressLevel = viewer.compressLevel.getValue();
+      encodingChange = true;
+    }
+    viewer.noJpeg.setParam(!options.noJpeg.isSelected());
+    if (cp.noJpeg != viewer.noJpeg.getValue()) {
+      cp.noJpeg = viewer.noJpeg.getValue();
+      encodingChange = true;
+    }
+    viewer.qualityLevel.setParam(options.qualityLevel.getSelectedItem().toString());
+    if (cp.qualityLevel != viewer.qualityLevel.getValue()) {
+      cp.qualityLevel = viewer.qualityLevel.getValue();
+      encodingChange = true;
+    }
+    viewer.sendLocalUsername.setParam(options.sendLocalUsername.isSelected());
+
+    viewer.viewOnly.setParam(options.viewOnly.isSelected());
+    viewer.acceptClipboard.setParam(options.acceptClipboard.isSelected());
+    viewer.sendClipboard.setParam(options.sendClipboard.isSelected());
+    clipboardDialog.setSendingEnabled(viewer.sendClipboard.getValue());
+    menuKey = (int)(options.menuKey.getSelectedIndex()+0xFFBE);
+    F8Menu.f8.setLabel("Send F"+(menuKey-Keysyms.F1+1));
+
+    shared = options.shared.isSelected();
+    setShared(shared);
+    viewer.useLocalCursor.setParam(options.useLocalCursor.isSelected());
+    if (cp.supportsLocalCursor != viewer.useLocalCursor.getValue()) {
+      cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
+      encodingChange = true;
+      if (desktop != null)
+        desktop.resetLocalCursor();
+    }
+    
+    checkEncodings();
+  
+    if (state() != RFBSTATE_NORMAL) {
+      /* Process security types which don't use encryption */
+      if (options.encNone.isSelected()) {
+        if (options.secNone.isSelected())
+          Security.EnableSecType(Security.secTypeNone);
+        if (options.secVnc.isSelected())
+          Security.EnableSecType(Security.secTypeVncAuth);
+        if (options.secPlain.isSelected())
+          Security.EnableSecType(Security.secTypePlain);
+        if (options.secIdent.isSelected())
+          Security.EnableSecType(Security.secTypeIdent);
+      } else {
+        Security.DisableSecType(Security.secTypeNone);
+        Security.DisableSecType(Security.secTypeVncAuth);
+        Security.DisableSecType(Security.secTypePlain);
+        Security.DisableSecType(Security.secTypeIdent);
+      }
+
+      /* Process security types which use TLS encryption */
+      if (options.encTLS.isSelected()) {
+        if (options.secNone.isSelected())
+          Security.EnableSecType(Security.secTypeTLSNone);
+        if (options.secVnc.isSelected())
+          Security.EnableSecType(Security.secTypeTLSVnc);
+        if (options.secPlain.isSelected())
+          Security.EnableSecType(Security.secTypeTLSPlain);
+        if (options.secIdent.isSelected())
+          Security.EnableSecType(Security.secTypeTLSIdent);
+      } else {
+        Security.DisableSecType(Security.secTypeTLSNone);
+        Security.DisableSecType(Security.secTypeTLSVnc);
+        Security.DisableSecType(Security.secTypeTLSPlain);
+        Security.DisableSecType(Security.secTypeTLSIdent);
+      }
+  
+      /* Process security types which use X509 encryption */
+      if (options.encX509.isSelected()) {
+        if (options.secNone.isSelected())
+          Security.EnableSecType(Security.secTypeX509None);
+        if (options.secVnc.isSelected())
+          Security.EnableSecType(Security.secTypeX509Vnc);
+        if (options.secPlain.isSelected())
+          Security.EnableSecType(Security.secTypeX509Plain);
+        if (options.secIdent.isSelected())
+          Security.EnableSecType(Security.secTypeX509Ident);
+      } else {
+        Security.DisableSecType(Security.secTypeX509None);
+        Security.DisableSecType(Security.secTypeX509Vnc);
+        Security.DisableSecType(Security.secTypeX509Plain);
+        Security.DisableSecType(Security.secTypeX509Ident);
+      }
+  
+      /* Process *None security types */
+      if (options.secNone.isSelected()) {
+        if (options.encNone.isSelected())
+          Security.EnableSecType(Security.secTypeNone);
+        if (options.encTLS.isSelected())
+          Security.EnableSecType(Security.secTypeTLSNone);
+        if (options.encX509.isSelected())
+          Security.EnableSecType(Security.secTypeX509None);
+      } else {
+        Security.DisableSecType(Security.secTypeNone);
+        Security.DisableSecType(Security.secTypeTLSNone);
+        Security.DisableSecType(Security.secTypeX509None);
+      }
+  
+      /* Process *Vnc security types */
+      if (options.secVnc.isSelected()) {
+        if (options.encNone.isSelected())
+          Security.EnableSecType(Security.secTypeVncAuth);
+        if (options.encTLS.isSelected())
+          Security.EnableSecType(Security.secTypeTLSVnc);
+        if (options.encX509.isSelected())
+          Security.EnableSecType(Security.secTypeX509Vnc);
+      } else {
+        Security.DisableSecType(Security.secTypeVncAuth);
+        Security.DisableSecType(Security.secTypeTLSVnc);
+        Security.DisableSecType(Security.secTypeX509Vnc);
+      }
+  
+      /* Process *Plain security types */
+      if (options.secPlain.isSelected()) {
+        if (options.encNone.isSelected())
+          Security.EnableSecType(Security.secTypePlain);
+        if (options.encTLS.isSelected())
+          Security.EnableSecType(Security.secTypeTLSPlain);
+        if (options.encX509.isSelected())
+          Security.EnableSecType(Security.secTypeX509Plain);
+      } else {
+        Security.DisableSecType(Security.secTypePlain);
+        Security.DisableSecType(Security.secTypeTLSPlain);
+        Security.DisableSecType(Security.secTypeX509Plain);
+      }
+  
+      /* Process *Ident security types */
+      if (options.secIdent.isSelected()) {
+        if (options.encNone.isSelected())
+          Security.EnableSecType(Security.secTypeIdent);
+        if (options.encTLS.isSelected())
+          Security.EnableSecType(Security.secTypeTLSIdent);
+        if (options.encX509.isSelected())
+          Security.EnableSecType(Security.secTypeX509Ident);
+      } else {
+        Security.DisableSecType(Security.secTypeIdent);
+        Security.DisableSecType(Security.secTypeTLSIdent);
+        Security.DisableSecType(Security.secTypeX509Ident);
+      }
+  
+      CSecurityTLS.x509ca.setParam(options.ca.getText());
+      CSecurityTLS.x509crl.setParam(options.crl.getText());
+    }
+  }
+
+  public void toggleFullScreen() {
+    fullScreen = !fullScreen;
+    if (!fullScreen) menu.fullScreen.setSelected(false);
+    recreateViewport();
+  }
+
+  // writeClientCutText() is called from the clipboard dialog
+  synchronized public void writeClientCutText(String str, int len) {
+    if (state() != RFBSTATE_NORMAL) return;
+    writer().writeClientCutText(str,len);
+  }
+
+  synchronized public void writeKeyEvent(int keysym, boolean down) {
+    if (state() != RFBSTATE_NORMAL) return;
+    writer().writeKeyEvent(keysym, down);
+  }
+
+  synchronized public void writeKeyEvent(KeyEvent ev) {
+    if (ev.getID() != KeyEvent.KEY_PRESSED && !ev.isActionKey())
+      return;
+
+    int keysym;
+
+    if (!ev.isActionKey()) {
+      vlog.debug("key press "+ev.getKeyChar());
+      if (ev.getKeyChar() < 32) {
+        // if the ctrl modifier key is down, send the equivalent ASCII since we
+        // will send the ctrl modifier anyway
+
+        if ((ev.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
+          if ((ev.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
+            keysym = ev.getKeyChar() + 64;
+            if (keysym == -1)
+              return;
+          } else { 
+            keysym = ev.getKeyChar() + 96;
+            if (keysym == 127) keysym = 95;
+          }
+        } else {
+          switch (ev.getKeyCode()) {
+          case KeyEvent.VK_BACK_SPACE: keysym = Keysyms.BackSpace; break;
+          case KeyEvent.VK_TAB:        keysym = Keysyms.Tab; break;
+          case KeyEvent.VK_ENTER:      keysym = Keysyms.Return; break;
+          case KeyEvent.VK_ESCAPE:     keysym = Keysyms.Escape; break;
+          default: return;
+          }
+        }
+
+      } else if (ev.getKeyChar() == 127) {
+        keysym = Keysyms.Delete;
+
+      } else {
+        keysym = UnicodeToKeysym.translate(ev.getKeyChar());
+        if (keysym == -1)
+          return;
+      }
+
+    } else {
+      // KEY_ACTION
+      vlog.debug("key action "+ev.getKeyCode());
+      switch (ev.getKeyCode()) {
+      case KeyEvent.VK_HOME:         keysym = Keysyms.Home; break;
+      case KeyEvent.VK_END:          keysym = Keysyms.End; break;
+      case KeyEvent.VK_PAGE_UP:      keysym = Keysyms.Page_Up; break;
+      case KeyEvent.VK_PAGE_DOWN:    keysym = Keysyms.Page_Down; break;
+      case KeyEvent.VK_UP:           keysym = Keysyms.Up; break;
+      case KeyEvent.VK_DOWN:         keysym = Keysyms.Down; break;
+      case KeyEvent.VK_LEFT:         keysym = Keysyms.Left; break;
+      case KeyEvent.VK_RIGHT:        keysym = Keysyms.Right; break;
+      case KeyEvent.VK_F1:           keysym = Keysyms.F1; break;
+      case KeyEvent.VK_F2:           keysym = Keysyms.F2; break;
+      case KeyEvent.VK_F3:           keysym = Keysyms.F3; break;
+      case KeyEvent.VK_F4:           keysym = Keysyms.F4; break;
+      case KeyEvent.VK_F5:           keysym = Keysyms.F5; break;
+      case KeyEvent.VK_F6:           keysym = Keysyms.F6; break;
+      case KeyEvent.VK_F7:           keysym = Keysyms.F7; break;
+      case KeyEvent.VK_F8:           keysym = Keysyms.F8; break;
+      case KeyEvent.VK_F9:           keysym = Keysyms.F9; break;
+      case KeyEvent.VK_F10:          keysym = Keysyms.F10; break;
+      case KeyEvent.VK_F11:          keysym = Keysyms.F11; break;
+      case KeyEvent.VK_F12:          keysym = Keysyms.F12; break;
+      case KeyEvent.VK_PRINTSCREEN:  keysym = Keysyms.Print; break;
+      case KeyEvent.VK_PAUSE:        keysym = Keysyms.Pause; break;
+      case KeyEvent.VK_INSERT:       keysym = Keysyms.Insert; break;
+      default: return;
+      }
+    }
+
+    writeModifiers(ev.getModifiers());
+    writeKeyEvent(keysym, true);
+    writeKeyEvent(keysym, false);
+    writeModifiers(0);
+  }
+
+
+  synchronized public void writePointerEvent(MouseEvent ev) {
+    if (state() != RFBSTATE_NORMAL) return;
+    int x, y;
+
+    switch (ev.getID()) {
+    case MouseEvent.MOUSE_PRESSED:
+      buttonMask = 1;
+      if ((ev.getModifiers() & KeyEvent.ALT_MASK) != 0) buttonMask = 2;
+      if ((ev.getModifiers() & KeyEvent.META_MASK) != 0) buttonMask = 4;
+      break;
+    case MouseEvent.MOUSE_RELEASED:
+      buttonMask = 0;
+      break;
+    }
+
+    writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
+
+    x = ev.getX();
+    y = ev.getY();
+    if (x < 0) x = 0;
+    if (x > cp.width-1) x = cp.width-1;
+    if (y < 0) y = 0;
+    if (y > cp.height-1) y = cp.height-1;
+
+    writer().writePointerEvent(new Point(x, y), buttonMask);
+
+    if (buttonMask == 0) writeModifiers(0);
+  }
+
+
+  synchronized public void writeWheelEvent(MouseWheelEvent ev) {
+    if (state() != RFBSTATE_NORMAL) return;
+    int x, y;
+    int clicks = ev.getWheelRotation();
+    if (clicks < 0) {
+      buttonMask = 8;
+    } else {
+      buttonMask = 16;
+    }
+    writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
+    for (int i=0;i<java.lang.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);
+    }
+    writeModifiers(0);
+
+  }
+
+
+  void writeModifiers(int m) {
+    if ((m & Event.SHIFT_MASK) != (pressedModifiers & Event.SHIFT_MASK))
+      writeKeyEvent(Keysyms.Shift_L, (m & Event.SHIFT_MASK) != 0);
+    if ((m & Event.CTRL_MASK) != (pressedModifiers & Event.CTRL_MASK))
+      writeKeyEvent(Keysyms.Control_L, (m & Event.CTRL_MASK) != 0);
+    if ((m & Event.ALT_MASK) != (pressedModifiers & Event.ALT_MASK))
+      writeKeyEvent(Keysyms.Alt_L, (m & Event.ALT_MASK) != 0);
+    if ((m & Event.META_MASK) != (pressedModifiers & Event.META_MASK))
+      writeKeyEvent(Keysyms.Meta_L, (m & Event.META_MASK) != 0);
+    pressedModifiers = m;
+  }
+
+
+  ////////////////////////////////////////////////////////////////////
+  // 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) {
+      vlog.info("Using "+Encodings.encodingName(currentEncoding)+" encoding");
+      writer().writeSetEncodings(currentEncoding, true);
+      encodingChange = false;
+    }
+  }
+
+  // the following never change so need no synchronization:
+  JavaInStream jis;
+  JavaOutStream jos;
+
+
+  // viewer object is only ever accessed by the GUI thread so needs no
+  // synchronization (except for one test in DesktopWindow - see comment
+  // there).
+  VncViewer viewer;
+
+  // access to desktop by different threads is specified in DesktopWindow
+
+  // the following need no synchronization:
+
+  ClassLoader cl = this.getClass().getClassLoader();
+  ImageIcon logo = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.png"));
+  public static UserPasswdGetter upg;
+  public UserMsgBox msg;
+
+  // shuttingDown is set by the GUI thread and only ever tested by the RFB
+  // thread after the window has been destroyed.
+  boolean shuttingDown;
+
+  // reading and writing int and boolean is atomic in java, so no
+  // synchronization of the following flags is needed:
+  int currentEncoding, lastServerEncoding;
+  
+  int lowColourLevel;
+
+
+  // All menu, options, about and info stuff is done in the GUI thread (apart
+  // from when constructed).
+  F8Menu menu;
+  OptionsDialog options;
+
+  // clipboard sync issues?
+  ClipboardDialog clipboardDialog;
+
+  // the following are only ever accessed by the GUI thread:
+  int buttonMask;
+  int pressedModifiers;
+
+  public String serverHost;
+  public int serverPort;
+  public int menuKey;
+  PixelFormat serverPF;
+  ViewportFrame viewport;
+  DesktopWindow desktop;
+  PixelFormat fullColourPF;
+  boolean fullColour;
+  boolean autoSelect;
+  boolean shared;
+  boolean formatChange;
+  boolean encodingChange;
+  boolean sameMachine;
+  boolean fullScreen;
+  boolean reverseConnection;
+  boolean firstUpdate;
+  boolean pendingUpdate;
+  
+  static LogWriter vlog = new LogWriter("CConn");
+}
diff --git a/java/src/com/tigervnc/vncviewer/DesktopWindow.java b/java/src/com/tigervnc/vncviewer/DesktopWindow.java
index 7a8cda8..5e2764b 100644
--- a/java/src/com/tigervnc/vncviewer/DesktopWindow.java
+++ b/java/src/com/tigervnc/vncviewer/DesktopWindow.java
@@ -1,485 +1,485 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  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.

- */

+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.
+ */
 
-//

-// DesktopWindow is an AWT Canvas representing a VNC desktop.

-//

-// Methods on DesktopWindow are called from both the GUI thread and the thread

-// which processes incoming RFB messages ("the RFB thread").  This means we

-// need to be careful with synchronization here.

-//

-

-package com.tigervnc.vncviewer;

-import java.awt.*;

-import java.awt.event.*;

-import java.awt.image.*;

-import java.awt.datatransfer.DataFlavor;

-import java.awt.datatransfer.Transferable;

+//
+// DesktopWindow is an AWT Canvas representing a VNC desktop.
+//
+// Methods on DesktopWindow are called from both the GUI thread and the thread
+// which processes incoming RFB messages ("the RFB thread").  This means we
+// need to be careful with synchronization here.
+//
+
+package com.tigervnc.vncviewer;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
 import java.awt.datatransfer.Clipboard;
 import javax.swing.*;
-

+
 import com.tigervnc.rfb.*;
-import com.tigervnc.rfb.Cursor;

+import com.tigervnc.rfb.Cursor;
 import com.tigervnc.rfb.Exception;
 import com.tigervnc.rfb.Point;
-

-class DesktopWindow extends JPanel implements

-                                   Runnable,

-                                   MouseListener,

-                                   MouseMotionListener,

-                                   MouseWheelListener,

-                                   KeyListener

-{

-

-  ////////////////////////////////////////////////////////////////////

-  // The following methods are all called from the RFB thread

-

-  public DesktopWindow(int width, int height, PixelFormat serverPF, CConn cc_) {

-    cc = cc_;

-    setSize(width, height);

-    im = new PixelBufferImage(width, height, cc, this);

-

-    cursor = new Cursor();

-    cursorBacking = new ManagedPixelBuffer();

-    addMouseListener(this);

-    addMouseWheelListener(this);

-    addMouseMotionListener(this);

-    addKeyListener(this);

-    addFocusListener(new FocusAdapter() {

-      public void focusGained(FocusEvent e) {

-        checkClipboard();

-      }

-    });

-    setFocusTraversalKeysEnabled(false);

-    setFocusable(true);

-    setDoubleBuffered(true);

-  }

-  

-  public int width() {

-    return getWidth();

-  }

-

-  public int height() {

-    return getHeight();

-  }

-

-  // initGraphics() is needed because for some reason you can't call

-  // getGraphics() on a newly-created awt Component.  It is called when the

-  // DesktopWindow has actually been made visible so that getGraphics() ought

-  // to work.

-

-  public void initGraphics() { 

-    cc.viewport.g = cc.viewport.getGraphics(); 

-    graphics = getComponentGraphics(cc.viewport.g);

-    prepareImage(im.image, -1, -1, this);

-  }

-

-  final public PixelFormat getPF() { return im.getPF(); }

-

-  synchronized public void setPF(PixelFormat pf) { 

-    im.setPF(pf); 

-  }

-

+
+class DesktopWindow extends JPanel implements
+                                   Runnable,
+                                   MouseListener,
+                                   MouseMotionListener,
+                                   MouseWheelListener,
+                                   KeyListener
+{
+
+  ////////////////////////////////////////////////////////////////////
+  // The following methods are all called from the RFB thread
+
+  public DesktopWindow(int width, int height, PixelFormat serverPF, CConn cc_) {
+    cc = cc_;
+    setSize(width, height);
+    im = new PixelBufferImage(width, height, cc, this);
+
+    cursor = new Cursor();
+    cursorBacking = new ManagedPixelBuffer();
+    addMouseListener(this);
+    addMouseWheelListener(this);
+    addMouseMotionListener(this);
+    addKeyListener(this);
+    addFocusListener(new FocusAdapter() {
+      public void focusGained(FocusEvent e) {
+        checkClipboard();
+      }
+    });
+    setFocusTraversalKeysEnabled(false);
+    setFocusable(true);
+    setDoubleBuffered(true);
+  }
+  
+  public int width() {
+    return getWidth();
+  }
+
+  public int height() {
+    return getHeight();
+  }
+
+  // initGraphics() is needed because for some reason you can't call
+  // getGraphics() on a newly-created awt Component.  It is called when the
+  // DesktopWindow has actually been made visible so that getGraphics() ought
+  // to work.
+
+  public void initGraphics() { 
+    cc.viewport.g = cc.viewport.getGraphics(); 
+    graphics = getComponentGraphics(cc.viewport.g);
+    prepareImage(im.image, -1, -1, this);
+  }
+
+  final public PixelFormat getPF() { return im.getPF(); }
+
+  synchronized public void setPF(PixelFormat pf) { 
+    im.setPF(pf); 
+  }
+
   public void setViewport(ViewportFrame viewport)
   {
     viewport.setChild(this);
   }
 
-  // Methods called from the RFB thread - these need to be synchronized

-  // wherever they access data shared with the GUI thread.

-

-  public void setCursor(int w, int h, Point hotspot,

-                                     int[] data, byte[] mask) {

-    // strictly we should use a mutex around this test since useLocalCursor

-    // might be being altered by the GUI thread.  However it's only a single

-    // boolean and it doesn't matter if we get the wrong value anyway.

-

-    synchronized(this) {

-    if (!cc.viewer.useLocalCursor.getValue()) return;

-

-    hideLocalCursor();

-

-    cursor.hotspot = hotspot;

-

-    Dimension bsc = tk.getBestCursorSize(w, h);

-

-    cursor.setSize(((int)bsc.getWidth() > w ? (int)bsc.getWidth() : w),

-                   ((int)bsc.getHeight() > h ? (int)bsc.getHeight() : h));

-    cursor.setPF(getPF());

-

-    cursorBacking.setSize(cursor.width(), cursor.height());

-    cursorBacking.setPF(getPF());

-

-    cursor.data = new int[cursor.width() * cursor.height()];

-    cursor.mask = new byte[cursor.maskLen()];

-

-    // set the masked pixels of the cursor transparent by using an extra bit in

-    // the colormap.  We'll OR this into the data based on the values in the mask.

-    if (cursor.getPF().bpp == 8) {

-      cursor.cm = new DirectColorModel(9, 7, (7 << 3), (3 << 6), (1 << 8));

-    }

-

-    int maskBytesPerRow = (w + 7) / 8;

-    for (int y = 0; y < h; y++) {

-      for (int x = 0; x < w; x++) {

-        int byte_ = y * maskBytesPerRow + x / 8;

-        int bit = 7 - x % 8;

-        if ((mask[byte_] & (1 << bit)) > 0) {

-          cursor.data[y * cursor.width() + x] = (cursor.getPF().bpp == 8) ?

-            data[y * w + x] | (1 << 8) : data[y * w + x];

-        }

-      }

-      System.arraycopy(mask, y * maskBytesPerRow, cursor.mask, 

-        y * ((cursor.width() + 7) / 8), maskBytesPerRow);

-    }

-

-    MemoryImageSource bitmap = 

-      new MemoryImageSource(cursor.width(), cursor.height(), cursor.cm,

-                            cursor.data, 0, cursor.width());

-    softCursor = 

-      tk.createCustomCursor(tk.createImage(bitmap), new java.awt.Point(hotspot.x,hotspot.y), "Cursor");

-    }

-

-    if (softCursor != null) {

-      setCursor(softCursor); 

-      cursorAvailable = true;

-      return;

-    }

-

-    if (!cursorAvailable) {

-      cursorAvailable = true;

-    }

-

-    showLocalCursor();

-    return;

-  }

-

-  // setColourMapEntries() changes some of the entries in the colourmap.

-  // Unfortunately these messages are often sent one at a time, so we delay the

-  // settings taking effect unless the whole colourmap has changed.  This is

-  // because getting java to recalculate its internal translation table and

-  // redraw the screen is expensive.

-

-  synchronized public void setColourMapEntries(int firstColour, int nColours,

-                                               int[] rgbs) {

-    im.setColourMapEntries(firstColour, nColours, rgbs);

-    if (nColours <= 256) {

-      im.updateColourMap();

-      im.put(0, 0, im.width(), im.height(), graphics);

-    } else {

-      if (setColourMapEntriesTimerThread == null) {

-        setColourMapEntriesTimerThread = new Thread(this);

-        setColourMapEntriesTimerThread.start();

-      }

-    }

-  }

-

-// Update the actual window with the changed parts of the framebuffer.

-

-  public void framebufferUpdateEnd()

-  {

-    drawInvalidRect();

-  }

-

-  // resize() is called when the desktop has changed size

-  synchronized public void resize() {

-    int w = cc.cp.width;

-    int h = cc.cp.height;

-    hideLocalCursor();

-    setSize(w, h);

-    im.resize(w, h);

-  }

-

-  final void drawInvalidRect() {

-    if (!invalidRect) return;

-    int x = invalidLeft;

-    int w = invalidRight - x;

-    int y = invalidTop;

-    int h = invalidBottom - y;

-    invalidRect = false;

-

-    synchronized (this) {

-      im.put(x, y, w, h, graphics);

-    }

-  }

-

-  final void invalidate(int x, int y, int w, int h) {

-    if (invalidRect) {

-      if (x < invalidLeft) invalidLeft = x;

-      if (x + w > invalidRight) invalidRight = x + w;

-      if (y < invalidTop) invalidTop = y;

-      if (y + h > invalidBottom) invalidBottom = y + h;

-    } else {

-      invalidLeft = x;

-      invalidRight = x + w;

-      invalidTop = y;

-      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();

-  }

-

-  synchronized final public void fillRect(int x, int y, int w, int h, int pix)

-  {

-    if (overlapsCursor(x, y, w, h)) hideLocalCursor();

-    im.fillRect(x, y, w, h, pix);

-    invalidate(x, y, w, h);

-    if (softCursor == null)

-      showLocalCursor();

-  }

-

-  synchronized final public void imageRect(int x, int y, int w, int h,

-                                           int[] pix) {

-    if (overlapsCursor(x, y, w, h)) hideLocalCursor();

-    im.imageRect(x, y, w, h, pix);

-    invalidate(x, y, w, h);

-    if (softCursor == null)

-      showLocalCursor();

-  }

-

-  synchronized final public void copyRect(int x, int y, int w, int h,

-                                          int srcX, int srcY) {

-    if (overlapsCursor(x, y, w, h) || overlapsCursor(srcX, srcY, w, h))

-      hideLocalCursor();

-    im.copyRect(x, y, w, h, srcX, srcY);

-    if (!cc.viewer.fastCopyRect.getValue()) {

-      invalidate(x, y, w, h);

-    }

-  }

-

-

-  // mutex MUST be held when overlapsCursor() is called

-  final boolean overlapsCursor(int x, int y, int w, int h) {

-    return (x < cursorBackingX + cursorBacking.width() &&

-            y < cursorBackingY + cursorBacking.height() &&

-            x+w > cursorBackingX && y+h > cursorBackingY);

-  }

-

-

-  ////////////////////////////////////////////////////////////////////

-  // The following methods are all called from the GUI thread

-

-  synchronized void resetLocalCursor() {

-    hideLocalCursor();

-    cursorAvailable = false;

-  }

-

-  synchronized public Dimension getPreferredSize() {

-    return new Dimension(im.width(), im.height());

-  }

-

-  synchronized public Dimension getMinimumSize() {

-    return new Dimension(im.width(), im.height());

-  }

-

-  public void update(Graphics g) {

-    //repaint();

-  }

-

-  synchronized public void paintComponent(Graphics g) {

-    Graphics2D g2 = (Graphics2D) g;

-    g2.drawImage(im.image, 0, 0, this);

-  }

-

-

-  String oldContents = "";

-  

-  synchronized public void checkClipboard() {

+  // Methods called from the RFB thread - these need to be synchronized
+  // wherever they access data shared with the GUI thread.
+
+  public void setCursor(int w, int h, Point hotspot,
+                                     int[] data, byte[] mask) {
+    // strictly we should use a mutex around this test since useLocalCursor
+    // might be being altered by the GUI thread.  However it's only a single
+    // boolean and it doesn't matter if we get the wrong value anyway.
+
+    synchronized(this) {
+    if (!cc.viewer.useLocalCursor.getValue()) return;
+
+    hideLocalCursor();
+
+    cursor.hotspot = hotspot;
+
+    Dimension bsc = tk.getBestCursorSize(w, h);
+
+    cursor.setSize(((int)bsc.getWidth() > w ? (int)bsc.getWidth() : w),
+                   ((int)bsc.getHeight() > h ? (int)bsc.getHeight() : h));
+    cursor.setPF(getPF());
+
+    cursorBacking.setSize(cursor.width(), cursor.height());
+    cursorBacking.setPF(getPF());
+
+    cursor.data = new int[cursor.width() * cursor.height()];
+    cursor.mask = new byte[cursor.maskLen()];
+
+    // set the masked pixels of the cursor transparent by using an extra bit in
+    // the colormap.  We'll OR this into the data based on the values in the mask.
+    if (cursor.getPF().bpp == 8) {
+      cursor.cm = new DirectColorModel(9, 7, (7 << 3), (3 << 6), (1 << 8));
+    }
+
+    int maskBytesPerRow = (w + 7) / 8;
+    for (int y = 0; y < h; y++) {
+      for (int x = 0; x < w; x++) {
+        int byte_ = y * maskBytesPerRow + x / 8;
+        int bit = 7 - x % 8;
+        if ((mask[byte_] & (1 << bit)) > 0) {
+          cursor.data[y * cursor.width() + x] = (cursor.getPF().bpp == 8) ?
+            data[y * w + x] | (1 << 8) : data[y * w + x];
+        }
+      }
+      System.arraycopy(mask, y * maskBytesPerRow, cursor.mask, 
+        y * ((cursor.width() + 7) / 8), maskBytesPerRow);
+    }
+
+    MemoryImageSource bitmap = 
+      new MemoryImageSource(cursor.width(), cursor.height(), cursor.cm,
+                            cursor.data, 0, cursor.width());
+    softCursor = 
+      tk.createCustomCursor(tk.createImage(bitmap), new java.awt.Point(hotspot.x,hotspot.y), "Cursor");
+    }
+
+    if (softCursor != null) {
+      setCursor(softCursor); 
+      cursorAvailable = true;
+      return;
+    }
+
+    if (!cursorAvailable) {
+      cursorAvailable = true;
+    }
+
+    showLocalCursor();
+    return;
+  }
+
+  // setColourMapEntries() changes some of the entries in the colourmap.
+  // Unfortunately these messages are often sent one at a time, so we delay the
+  // settings taking effect unless the whole colourmap has changed.  This is
+  // because getting java to recalculate its internal translation table and
+  // redraw the screen is expensive.
+
+  synchronized public void setColourMapEntries(int firstColour, int nColours,
+                                               int[] rgbs) {
+    im.setColourMapEntries(firstColour, nColours, rgbs);
+    if (nColours <= 256) {
+      im.updateColourMap();
+      im.put(0, 0, im.width(), im.height(), graphics);
+    } else {
+      if (setColourMapEntriesTimerThread == null) {
+        setColourMapEntriesTimerThread = new Thread(this);
+        setColourMapEntriesTimerThread.start();
+      }
+    }
+  }
+
+// Update the actual window with the changed parts of the framebuffer.
+
+  public void framebufferUpdateEnd()
+  {
+    drawInvalidRect();
+  }
+
+  // resize() is called when the desktop has changed size
+  synchronized public void resize() {
+    int w = cc.cp.width;
+    int h = cc.cp.height;
+    hideLocalCursor();
+    setSize(w, h);
+    im.resize(w, h);
+  }
+
+  final void drawInvalidRect() {
+    if (!invalidRect) return;
+    int x = invalidLeft;
+    int w = invalidRight - x;
+    int y = invalidTop;
+    int h = invalidBottom - y;
+    invalidRect = false;
+
+    synchronized (this) {
+      im.put(x, y, w, h, graphics);
+    }
+  }
+
+  final void invalidate(int x, int y, int w, int h) {
+    if (invalidRect) {
+      if (x < invalidLeft) invalidLeft = x;
+      if (x + w > invalidRight) invalidRight = x + w;
+      if (y < invalidTop) invalidTop = y;
+      if (y + h > invalidBottom) invalidBottom = y + h;
+    } else {
+      invalidLeft = x;
+      invalidRight = x + w;
+      invalidTop = y;
+      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();
+  }
+
+  synchronized final public void fillRect(int x, int y, int w, int h, int pix)
+  {
+    if (overlapsCursor(x, y, w, h)) hideLocalCursor();
+    im.fillRect(x, y, w, h, pix);
+    invalidate(x, y, w, h);
+    if (softCursor == null)
+      showLocalCursor();
+  }
+
+  synchronized final public void imageRect(int x, int y, int w, int h,
+                                           int[] pix) {
+    if (overlapsCursor(x, y, w, h)) hideLocalCursor();
+    im.imageRect(x, y, w, h, pix);
+    invalidate(x, y, w, h);
+    if (softCursor == null)
+      showLocalCursor();
+  }
+
+  synchronized final public void copyRect(int x, int y, int w, int h,
+                                          int srcX, int srcY) {
+    if (overlapsCursor(x, y, w, h) || overlapsCursor(srcX, srcY, w, h))
+      hideLocalCursor();
+    im.copyRect(x, y, w, h, srcX, srcY);
+    if (!cc.viewer.fastCopyRect.getValue()) {
+      invalidate(x, y, w, h);
+    }
+  }
+
+
+  // mutex MUST be held when overlapsCursor() is called
+  final boolean overlapsCursor(int x, int y, int w, int h) {
+    return (x < cursorBackingX + cursorBacking.width() &&
+            y < cursorBackingY + cursorBacking.height() &&
+            x+w > cursorBackingX && y+h > cursorBackingY);
+  }
+
+
+  ////////////////////////////////////////////////////////////////////
+  // The following methods are all called from the GUI thread
+
+  synchronized void resetLocalCursor() {
+    hideLocalCursor();
+    cursorAvailable = false;
+  }
+
+  synchronized public Dimension getPreferredSize() {
+    return new Dimension(im.width(), im.height());
+  }
+
+  synchronized public Dimension getMinimumSize() {
+    return new Dimension(im.width(), im.height());
+  }
+
+  public void update(Graphics g) {
+    //repaint();
+  }
+
+  synchronized public void paintComponent(Graphics g) {
+    Graphics2D g2 = (Graphics2D) g;
+    g2.drawImage(im.image, 0, 0, this);
+  }
+
+
+  String oldContents = "";
+  
+  synchronized public void checkClipboard() {
     Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
-    if (cb != null && cc.viewer.sendClipboard.getValue()) {

-      Transferable t = cb.getContents(null);

-      if ((t != null) && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {

-        try {

-          String newContents = (String)t.getTransferData(DataFlavor.stringFlavor);

-          if (newContents != null && !newContents.equals(oldContents)) {

-            cc.writeClientCutText(newContents, newContents.length());

-            oldContents = newContents;

-            cc.clipboardDialog.setContents(newContents);

-          }

-        } catch (java.lang.Exception e) {

-          System.out.println("Exception getting clipboard data: " + e.getMessage());

-        }

-      }

-    }

-  }

-

-  /** Mouse-Motion callback function */

-  private void mouseMotionCB(MouseEvent e) {

-    if (!cc.viewer.viewOnly.getValue())

-      cc.writePointerEvent(e);

-    // - If local cursor rendering is enabled then use it

-    synchronized(this) {

-      if (cursorAvailable) {

-        // - Render the cursor!

-        if (e.getX() != cursorPosX || e.getY() != cursorPosY) {

-          hideLocalCursor();

-          if (e.getX() >= 0 && e.getX() < im.width() &&

-              e.getY() >= 0 && e.getY() < im.height()) {

-            cursorPosX = e.getX();

-            cursorPosY = e.getY();

-            if (softCursor == null)

-              showLocalCursor();

-          }

-        }

-      }

-    }

-    lastX = e.getX();

-    lastY = e.getY();      

-  }

-  public void mouseDragged(MouseEvent e) { mouseMotionCB(e);}

-  public void mouseMoved(MouseEvent e) { mouseMotionCB(e);}

-

-  /** Mouse callback function */

-  private void mouseCB(MouseEvent e) {

-    if (!cc.viewer.viewOnly.getValue())

-      cc.writePointerEvent(e);

-    lastX = e.getX();

-    lastY = e.getY();

-  }

-  public void mouseReleased(MouseEvent e){ mouseCB(e);}

-  public void mousePressed(MouseEvent e) { mouseCB(e);}

-  public void mouseClicked(MouseEvent e){}

-  public void mouseEntered(MouseEvent e){}

-  public void mouseExited(MouseEvent e){}  

-  

-  /** MouseWheel callback function */

-  private void mouseWheelCB(MouseWheelEvent e) {

-    if (!cc.viewer.viewOnly.getValue())

-      cc.writeWheelEvent(e);

-  }

-  public void mouseWheelMoved(MouseWheelEvent e){ 

-    mouseWheelCB(e);

-  }

-

-  /** Handle the key-typed event. */

-  public void keyTyped(KeyEvent e) {}

-  /** Handle the key-released event. */

-  public void keyReleased(KeyEvent e) {}

-  /** Handle the key-pressed event. */

-  public void keyPressed(KeyEvent e) {

-    if (e.getKeyCode() == 

-        (KeyEvent.VK_F1+cc.menuKey-Keysyms.F1)) {

-      cc.showMenu(lastX, lastY);

-      return;

-    }

-    if (!cc.viewer.viewOnly.getValue())

-      cc.writeKeyEvent(e);

-  }

-

-  ////////////////////////////////////////////////////////////////////

-  // The following methods are called from both RFB and GUI threads

-

-  // Note that mutex MUST be held when hideLocalCursor() and showLocalCursor()

-  // are called.

-

-  private void hideLocalCursor() {

-    // - Blit the cursor backing store over the cursor

-    if (cursorVisible) {

-      cursorVisible = false;

-      im.imageRect(cursorBackingX, cursorBackingY, cursorBacking.width(),

-                   cursorBacking.height(), cursorBacking.data);

-      im.put(cursorBackingX, cursorBackingY, cursorBacking.width(),

-             cursorBacking.height(), graphics);

-    }

-  }

-

-  private void showLocalCursor() {

-    if (cursorAvailable && !cursorVisible) {

-      if (!im.getPF().equal(cursor.getPF()) ||

-          cursor.width() == 0 || cursor.height() == 0) {

-        vlog.debug("attempting to render invalid local cursor");

-        cursorAvailable = false;

-        return;

-      }

-      cursorVisible = true;

-      if (softCursor != null) return;

-

-      int cursorLeft = (int)cursor.hotspot.x;

-      int cursorTop = (int)cursor.hotspot.y;

-      int cursorRight = cursorLeft + cursor.width();

-      int cursorBottom = cursorTop + cursor.height();

-

-      int x = (cursorLeft >= 0 ? cursorLeft : 0);

-      int y = (cursorTop >= 0 ? cursorTop : 0);

-      int w = ((cursorRight < im.width() ? cursorRight : im.width()) - x);

-      int h = ((cursorBottom < im.height() ? cursorBottom : im.height()) - y);

-

-      cursorBackingX = x;

-      cursorBackingY = y;

-      cursorBacking.setSize(w, h);

-      

-      for (int j = 0; j < h; j++)

-        System.arraycopy(im.data, (y+j) * im.width() + x,

-                         cursorBacking.data, j*w, w);

-

-      im.maskRect(cursorLeft, cursorTop, cursor.width(), cursor.height(),

-                  cursor.data, cursor.mask);

-      im.put(x, y, w, h, graphics);

-    }

-  }

-

-

-  // run() is executed by the setColourMapEntriesTimerThread - it sleeps for

-  // 100ms before actually updating the colourmap.

-  public void run() {

-    try {

-      Thread.sleep(100);

-    } catch (InterruptedException e) {}

-    synchronized (this) {

-      im.updateColourMap();

-      im.put(0, 0, im.width(), im.height(), graphics);

-      setColourMapEntriesTimerThread = null;

-    }

-  }

-

-  // access to cc by different threads is specified in CConn

-  CConn cc;

-

-  // access to the following must be synchronized:

-  PixelBufferImage im;

-  Graphics graphics;

-  Thread setColourMapEntriesTimerThread;

-

-  Cursor cursor;

-  boolean cursorVisible;     // Is cursor currently rendered?

-  boolean cursorAvailable;   // Is cursor available for rendering?

-  int cursorPosX, cursorPosY;

-  ManagedPixelBuffer cursorBacking;

-  int cursorBackingX, cursorBackingY;

-  java.awt.Cursor softCursor;

-  static Toolkit tk = Toolkit.getDefaultToolkit();

-

-  // the following are only ever accessed by the RFB thread:

-  boolean invalidRect;

-  int invalidLeft, invalidRight, invalidTop, invalidBottom;

-

-  // the following are only ever accessed by the GUI thread:

-  int lastX, lastY;

-

-  static LogWriter vlog = new LogWriter("DesktopWindow");

-}

+    if (cb != null && cc.viewer.sendClipboard.getValue()) {
+      Transferable t = cb.getContents(null);
+      if ((t != null) && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+        try {
+          String newContents = (String)t.getTransferData(DataFlavor.stringFlavor);
+          if (newContents != null && !newContents.equals(oldContents)) {
+            cc.writeClientCutText(newContents, newContents.length());
+            oldContents = newContents;
+            cc.clipboardDialog.setContents(newContents);
+          }
+        } catch (java.lang.Exception e) {
+          System.out.println("Exception getting clipboard data: " + e.getMessage());
+        }
+      }
+    }
+  }
+
+  /** Mouse-Motion callback function */
+  private void mouseMotionCB(MouseEvent e) {
+    if (!cc.viewer.viewOnly.getValue())
+      cc.writePointerEvent(e);
+    // - If local cursor rendering is enabled then use it
+    synchronized(this) {
+      if (cursorAvailable) {
+        // - Render the cursor!
+        if (e.getX() != cursorPosX || e.getY() != cursorPosY) {
+          hideLocalCursor();
+          if (e.getX() >= 0 && e.getX() < im.width() &&
+              e.getY() >= 0 && e.getY() < im.height()) {
+            cursorPosX = e.getX();
+            cursorPosY = e.getY();
+            if (softCursor == null)
+              showLocalCursor();
+          }
+        }
+      }
+    }
+    lastX = e.getX();
+    lastY = e.getY();      
+  }
+  public void mouseDragged(MouseEvent e) { mouseMotionCB(e);}
+  public void mouseMoved(MouseEvent e) { mouseMotionCB(e);}
+
+  /** Mouse callback function */
+  private void mouseCB(MouseEvent e) {
+    if (!cc.viewer.viewOnly.getValue())
+      cc.writePointerEvent(e);
+    lastX = e.getX();
+    lastY = e.getY();
+  }
+  public void mouseReleased(MouseEvent e){ mouseCB(e);}
+  public void mousePressed(MouseEvent e) { mouseCB(e);}
+  public void mouseClicked(MouseEvent e){}
+  public void mouseEntered(MouseEvent e){}
+  public void mouseExited(MouseEvent e){}  
+  
+  /** MouseWheel callback function */
+  private void mouseWheelCB(MouseWheelEvent e) {
+    if (!cc.viewer.viewOnly.getValue())
+      cc.writeWheelEvent(e);
+  }
+  public void mouseWheelMoved(MouseWheelEvent e){ 
+    mouseWheelCB(e);
+  }
+
+  /** Handle the key-typed event. */
+  public void keyTyped(KeyEvent e) {}
+  /** Handle the key-released event. */
+  public void keyReleased(KeyEvent e) {}
+  /** Handle the key-pressed event. */
+  public void keyPressed(KeyEvent e) {
+    if (e.getKeyCode() == 
+        (KeyEvent.VK_F1+cc.menuKey-Keysyms.F1)) {
+      cc.showMenu(lastX, lastY);
+      return;
+    }
+    if (!cc.viewer.viewOnly.getValue())
+      cc.writeKeyEvent(e);
+  }
+
+  ////////////////////////////////////////////////////////////////////
+  // The following methods are called from both RFB and GUI threads
+
+  // Note that mutex MUST be held when hideLocalCursor() and showLocalCursor()
+  // are called.
+
+  private void hideLocalCursor() {
+    // - Blit the cursor backing store over the cursor
+    if (cursorVisible) {
+      cursorVisible = false;
+      im.imageRect(cursorBackingX, cursorBackingY, cursorBacking.width(),
+                   cursorBacking.height(), cursorBacking.data);
+      im.put(cursorBackingX, cursorBackingY, cursorBacking.width(),
+             cursorBacking.height(), graphics);
+    }
+  }
+
+  private void showLocalCursor() {
+    if (cursorAvailable && !cursorVisible) {
+      if (!im.getPF().equal(cursor.getPF()) ||
+          cursor.width() == 0 || cursor.height() == 0) {
+        vlog.debug("attempting to render invalid local cursor");
+        cursorAvailable = false;
+        return;
+      }
+      cursorVisible = true;
+      if (softCursor != null) return;
+
+      int cursorLeft = (int)cursor.hotspot.x;
+      int cursorTop = (int)cursor.hotspot.y;
+      int cursorRight = cursorLeft + cursor.width();
+      int cursorBottom = cursorTop + cursor.height();
+
+      int x = (cursorLeft >= 0 ? cursorLeft : 0);
+      int y = (cursorTop >= 0 ? cursorTop : 0);
+      int w = ((cursorRight < im.width() ? cursorRight : im.width()) - x);
+      int h = ((cursorBottom < im.height() ? cursorBottom : im.height()) - y);
+
+      cursorBackingX = x;
+      cursorBackingY = y;
+      cursorBacking.setSize(w, h);
+      
+      for (int j = 0; j < h; j++)
+        System.arraycopy(im.data, (y+j) * im.width() + x,
+                         cursorBacking.data, j*w, w);
+
+      im.maskRect(cursorLeft, cursorTop, cursor.width(), cursor.height(),
+                  cursor.data, cursor.mask);
+      im.put(x, y, w, h, graphics);
+    }
+  }
+
+
+  // run() is executed by the setColourMapEntriesTimerThread - it sleeps for
+  // 100ms before actually updating the colourmap.
+  public void run() {
+    try {
+      Thread.sleep(100);
+    } catch (InterruptedException e) {}
+    synchronized (this) {
+      im.updateColourMap();
+      im.put(0, 0, im.width(), im.height(), graphics);
+      setColourMapEntriesTimerThread = null;
+    }
+  }
+
+  // access to cc by different threads is specified in CConn
+  CConn cc;
+
+  // access to the following must be synchronized:
+  PixelBufferImage im;
+  Graphics graphics;
+  Thread setColourMapEntriesTimerThread;
+
+  Cursor cursor;
+  boolean cursorVisible;     // Is cursor currently rendered?
+  boolean cursorAvailable;   // Is cursor available for rendering?
+  int cursorPosX, cursorPosY;
+  ManagedPixelBuffer cursorBacking;
+  int cursorBackingX, cursorBackingY;
+  java.awt.Cursor softCursor;
+  static Toolkit tk = Toolkit.getDefaultToolkit();
+
+  // the following are only ever accessed by the RFB thread:
+  boolean invalidRect;
+  int invalidLeft, invalidRight, invalidTop, invalidBottom;
+
+  // the following are only ever accessed by the GUI thread:
+  int lastX, lastY;
+
+  static LogWriter vlog = new LogWriter("DesktopWindow");
+}
diff --git a/java/src/com/tigervnc/vncviewer/OptionsDialog.java b/java/src/com/tigervnc/vncviewer/OptionsDialog.java
index 9819815..f38a1e6 100644
--- a/java/src/com/tigervnc/vncviewer/OptionsDialog.java
+++ b/java/src/com/tigervnc/vncviewer/OptionsDialog.java
@@ -1,380 +1,380 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  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.

- */

-

+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.vncviewer;
-

-import java.awt.*;

-import java.awt.event.*;

-import javax.swing.*;

-import javax.swing.border.*;

-import javax.swing.filechooser.*;

-import javax.swing.ImageIcon;

-import java.net.URL;

-import java.io.IOException;

+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.filechooser.*;
+import javax.swing.ImageIcon;
+import java.net.URL;
+import java.io.IOException;
 
 import com.tigervnc.rfb.*;
 import com.tigervnc.rfb.Exception;
-

-class OptionsDialog extends Dialog implements

-                            ActionListener,

-                            ItemListener

-{

-

-  // Constants

-  // Static variables

-  static LogWriter vlog = new LogWriter("OptionsDialog");

-

-  OptionsDialogCallback cb;

-  JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel;

-  JCheckBox autoSelect, customCompressLevel, noJpeg;

-  JComboBox menuKey, compressLevel, qualityLevel ;

-  ButtonGroup encodingGroup, colourGroup;

-  JRadioButton zrle, hextile, tight, raw;

-  JRadioButton fullColour, mediumColour, lowColour, veryLowColour;

-  JCheckBox viewOnly, acceptClipboard, sendClipboard;

-  JCheckBox fullScreen, shared, useLocalCursor, fastCopyRect;

-  JCheckBox secVeNCrypt, encNone, encTLS, encX509;

-  JCheckBox secNone, secVnc, secPlain, secIdent, sendLocalUsername;

-  JButton okButton, cancelButton;

-  JButton ca, crl;

-  JButton defSaveButton;

-  boolean encryption = true; 

-  UserPrefs defaults;

-

-  public OptionsDialog(OptionsDialogCallback cb_) { 

-    super(false);

-    cb = cb_;

-    setResizable(false);

-    setTitle("VNC Viewer Options");

-    defaults = new UserPrefs("vncviewer");

-

-    getContentPane().setLayout(

-      new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));

-	

-    JTabbedPane tabPane = new JTabbedPane();

-

-    ButtonGroup encodingGroup = new ButtonGroup();

-    ButtonGroup colourGroup = new ButtonGroup();

-

-    // Colour & Encoding tab

-    FormatPanel=new JPanel(new GridBagLayout());

-

-    autoSelect = new JCheckBox("Auto Select");

-    autoSelect.addItemListener(this);

-

-    JPanel encodingPanel = new JPanel(new GridBagLayout());

-    encodingPanel.setBorder(BorderFactory.createTitledBorder("Preferred encoding"));

-    zrle = addRadioCheckbox("ZRLE", encodingGroup, encodingPanel);

-    hextile = addRadioCheckbox("Hextile", encodingGroup, encodingPanel);

-    tight = addRadioCheckbox("Tight", encodingGroup, encodingPanel);

-    raw = addRadioCheckbox("Raw", encodingGroup, encodingPanel);

-

-    JPanel tightPanel = new JPanel(new GridBagLayout());

-    customCompressLevel = new JCheckBox("Custom Compression Level");

-    customCompressLevel.addItemListener(this);

-    Object[] compressionLevels = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

-    compressLevel  = new JComboBox(compressionLevels);

-    JLabel compressionLabel = new JLabel("Level (1=fast, 9=best)");

-    noJpeg = new JCheckBox("Allow JPEG Compression");

-    noJpeg.addItemListener(this);

-    Object[] qualityLevels = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

-    qualityLevel  = new JComboBox(qualityLevels);

-    JLabel qualityLabel = new JLabel("Level (1=poor, 9=best)");

-    addGBComponent(customCompressLevel, tightPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));

-    addGBComponent(compressLevel, tightPanel,       0, 1, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));

-    addGBComponent(compressionLabel, tightPanel,    1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));

-    addGBComponent(noJpeg, tightPanel,              0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));

-    addGBComponent(qualityLevel, tightPanel,        0, 3, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));

-    addGBComponent(qualityLabel, tightPanel,        1, 3, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));

-

-

-    JPanel colourPanel = new JPanel(new GridBagLayout());

-    colourPanel.setBorder(BorderFactory.createTitledBorder("Colour level"));

-    fullColour = addRadioCheckbox("Full (all available colours)", colourGroup, colourPanel);

-    mediumColour = addRadioCheckbox("Medium (256 colours)", colourGroup, colourPanel);

-    lowColour = addRadioCheckbox("Low (64 colours)", colourGroup, colourPanel);

-    veryLowColour = addRadioCheckbox("Very low(8 colours)", colourGroup, colourPanel);

-

-    addGBComponent(autoSelect,FormatPanel,    0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));

-    addGBComponent(encodingPanel,FormatPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,2,0,0));

-    addGBComponent(colourPanel,FormatPanel,   1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(0,2,0,0));

-    addGBComponent(tightPanel,FormatPanel,    0, 2, 2, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));

-

-    // Inputs tab

-    InputsPanel=new JPanel(new GridBagLayout());

-

-    viewOnly = new JCheckBox("View Only (ignore mouse & keyboard)");

-    viewOnly.addItemListener(this);

-    acceptClipboard = new JCheckBox("Accept clipboard from server");

-    acceptClipboard.addItemListener(this);

-    sendClipboard = new JCheckBox("Send clipboard to server");

-    sendClipboard.addItemListener(this);

-    JLabel menuKeyLabel = new JLabel("Menu Key");

-    String[] menuKeys = 

-      { "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" };

-    menuKey  = new JComboBox(menuKeys);

-    menuKey.addItemListener(this);

-    addGBComponent(viewOnly,InputsPanel,        0, 0, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));

-    addGBComponent(acceptClipboard,InputsPanel, 0, 1, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));

-    addGBComponent(sendClipboard,InputsPanel,   0, 2, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));

-    addGBComponent(menuKeyLabel,InputsPanel,    0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(8,10,0,4));

-    addGBComponent(menuKey,InputsPanel,         1, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,125));

-    //((javax.swing.plaf.basic.BasicComboBoxRenderer)menuKey.getRenderer()).setBorder(new EmptyBorder(0,3,0,3));

-

-    // Misc tab

-    MiscPanel=new JPanel(new GridBagLayout());

-

-    fullScreen = new JCheckBox("Full-screen mode");

-    fullScreen.addItemListener(this);

-    shared = new JCheckBox("Shared connection (do not disconnect other viewers)");

-    shared.addItemListener(this);

-    useLocalCursor = new JCheckBox("Render cursor locally");

-    useLocalCursor.addItemListener(this);

-    fastCopyRect = new JCheckBox("Fast CopyRect");

-    fastCopyRect.addItemListener(this);

-    addGBComponent(fullScreen,MiscPanel,     0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));

-    addGBComponent(shared,MiscPanel,         0, 1, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));

-    addGBComponent(useLocalCursor,MiscPanel, 0, 2, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));

-    addGBComponent(fastCopyRect,MiscPanel,   0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,4));

-

-    // load/save tab

-    DefaultsPanel=new JPanel(new GridBagLayout());

-

-    JPanel configPanel = new JPanel(new GridBagLayout());

-    configPanel.setBorder(BorderFactory.createTitledBorder("Configuration File"));

-    JButton cfReloadButton = new JButton("Reload");

-    cfReloadButton.addActionListener(this);

-    addGBComponent(cfReloadButton,configPanel, 0, 0, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));

-    JButton cfSaveButton = new JButton("Save");

-    cfSaveButton.addActionListener(this);

-    addGBComponent(cfSaveButton,configPanel, 0, 1, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));

-    JButton cfSaveAsButton = new JButton("Save As...");

-    cfSaveAsButton.addActionListener(this);

-    addGBComponent(cfSaveAsButton,configPanel, 0, 2, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));

-    cfReloadButton.setEnabled(false);

-    cfSaveButton.setEnabled(false);

-

-    JPanel defaultsPanel = new JPanel(new GridBagLayout());

-    defaultsPanel.setBorder(BorderFactory.createTitledBorder("Defaults"));

-    JButton defReloadButton = new JButton("Reload");

-    defReloadButton.addActionListener(this);

-    addGBComponent(defReloadButton,defaultsPanel, 0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));

-    defSaveButton = new JButton("Save");

-    defSaveButton.addActionListener(this);

-    addGBComponent(defSaveButton,defaultsPanel, 0, 1, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));

-

-    addGBComponent(configPanel,DefaultsPanel, 0, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));

-    addGBComponent(defaultsPanel,DefaultsPanel, 1, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));

-

-    // security tab

-    SecPanel=new JPanel(new GridBagLayout());

-

-    JPanel encryptionPanel = new JPanel(new GridBagLayout());

-    encryptionPanel.setBorder(BorderFactory.createTitledBorder("Session Encryption"));

-    encNone = addCheckbox("None", null, encryptionPanel);

-    encTLS = addCheckbox("Anonymous TLS", null, encryptionPanel);

-    encX509 = addJCheckBox("TLS with X.509 certificates", null, encryptionPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.REMAINDER,new Insets(0,0,0,60),0,0));

-

-    JPanel x509Panel = new JPanel(new GridBagLayout());

-    x509Panel.setBorder(BorderFactory.createTitledBorder("X.509 certificates"));

-    ca = new JButton("Load CA certificate");

-    ca.setPreferredSize(new Dimension(145,25));

-    ca.addActionListener(this);

-    crl = new JButton("Load CRL certificate");

-    crl.setPreferredSize(new Dimension(145,25));

-    crl.addActionListener(this);

-    addGBComponent(ca, x509Panel,  0, 0, 1, 1, 2, 2, 0, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));

-    addGBComponent(crl, x509Panel, 1, 0, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));

-

-    JPanel authPanel = new JPanel(new GridBagLayout());

-    authPanel.setBorder(BorderFactory.createTitledBorder("Authentication"));

-    secNone = addCheckbox("None", null, authPanel);

-    secVnc = addCheckbox("Standard VNC", null, authPanel);

-    secPlain = addJCheckBox("Plaintext", null, authPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));

-    secIdent = addJCheckBox("Ident", null, authPanel, new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));

-    sendLocalUsername = new JCheckBox("Send Local Username");

-    sendLocalUsername.addItemListener(this);

-    addGBComponent(sendLocalUsername, authPanel, 1, 2, 1, 2, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,20,0,0));

-

-    secVeNCrypt = new JCheckBox("Extended encryption and authentication methods (VeNCrypt)");

-    secVeNCrypt.addItemListener(this);

-    addGBComponent(secVeNCrypt,SecPanel,        0, 0, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,20));

-    addGBComponent(encryptionPanel,SecPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(0,4,2,4));

-    addGBComponent(x509Panel,SecPanel,       0, 2, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,4,2,4));

-    addGBComponent(authPanel,SecPanel,       0, 3, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(2,4,2,4));

-

-    tabPane.add(FormatPanel);

-    tabPane.add(InputsPanel);

-    tabPane.add(MiscPanel);

-    tabPane.add(DefaultsPanel);

-    tabPane.add(SecPanel);

-    tabPane.addTab("Colour & Encoding", FormatPanel);

-    tabPane.addTab("Inputs", InputsPanel);

-    tabPane.addTab("Misc", MiscPanel);

-    tabPane.addTab("Load / Save", DefaultsPanel);

-    tabPane.addTab("Security", SecPanel);

-    tabPane.setBorder(BorderFactory.createEmptyBorder(4,4,0,4));

-

-    okButton = new JButton("OK");

-    okButton.setPreferredSize(new Dimension(90,30));

-    okButton.addActionListener(this);

-    cancelButton = new JButton("Cancel");

-    cancelButton.setPreferredSize(new Dimension(90,30));

-    cancelButton.addActionListener(this);

-

-    JPanel buttonPane = new JPanel();

-    buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));

-    buttonPane.setBorder(BorderFactory.createEmptyBorder(4,0,0,0));

-    buttonPane.add(Box.createHorizontalGlue());

-    buttonPane.add(okButton);

-    buttonPane.add(Box.createRigidArea(new Dimension(4,0)));

-    buttonPane.add(cancelButton);

-    buttonPane.add(Box.createRigidArea(new Dimension(4,0)));

-

-    this.getContentPane().add(tabPane);

-    this.getContentPane().add(buttonPane);

-

-    pack();

-	

-  }

-

-  public void initDialog() {

-    if (cb != null) cb.setOptions();

-    zrle.setEnabled(!autoSelect.isSelected());

-    hextile.setEnabled(!autoSelect.isSelected());

-    tight.setEnabled(!autoSelect.isSelected());

-    raw.setEnabled(!autoSelect.isSelected());

-    fullColour.setEnabled(!autoSelect.isSelected());

-    mediumColour.setEnabled(!autoSelect.isSelected());

-    lowColour.setEnabled(!autoSelect.isSelected());

-    veryLowColour.setEnabled(!autoSelect.isSelected());

-    compressLevel.setEnabled(customCompressLevel.isSelected());

-    qualityLevel.setEnabled(noJpeg.isSelected());

-    sendLocalUsername.setEnabled(secVeNCrypt.isEnabled()&&

-      (secPlain.isSelected()||secIdent.isSelected()));

-  }

-

-  JRadioButton addRadioCheckbox(String str, ButtonGroup group, JPanel panel) {

-    JRadioButton c = new JRadioButton(str);

-    GridBagConstraints gbc = new GridBagConstraints();

-    gbc.anchor = GridBagConstraints.LINE_START;

-    gbc.gridwidth = GridBagConstraints.REMAINDER;

-    gbc.weightx = 1;

-    gbc.weighty = 1;

-    panel.add(c,gbc);

-    group.add(c);

-    c.addItemListener(this);

-    return c;

-  }

-

-  JCheckBox addCheckbox(String str, ButtonGroup group, JPanel panel) {

-    JCheckBox c = new JCheckBox(str);

-    GridBagConstraints gbc = new GridBagConstraints();

-    gbc.anchor = GridBagConstraints.LINE_START;

-    gbc.gridwidth = GridBagConstraints.REMAINDER;

-    gbc.weightx = 1;

-    gbc.weighty = 1;

-    panel.add(c,gbc);

-    if (group != null)

-      group.add(c);

-    c.addItemListener(this);

-    return c;

-  }

-

-  JCheckBox addJCheckBox(String str, ButtonGroup group, JPanel panel,

-      GridBagConstraints gbc) {

-    JCheckBox c = new JCheckBox(str);

-    panel.add(c,gbc);

-    if (group != null)

-      group.add(c);

-    c.addItemListener(this);

-    

-    return c;

-  }

-

-  public void actionPerformed(ActionEvent e) {

-    Object s = e.getSource();

-    if (s instanceof JButton && (JButton)s == okButton) {

-      ok = true;

-      if (cb != null) cb.getOptions();

-      endDialog();

-    } else if (s instanceof JButton && (JButton)s == cancelButton) {

-      ok = false;

-      endDialog();

-    } else if (s instanceof JButton && (JButton)s == defSaveButton) {

-      try {

-        defaults.Save();

-      } catch (java.lang.Exception x) { }

-    } else if (s instanceof JButton && (JButton)s == ca) {

-      JFileChooser fc = new JFileChooser();

-      fc.setDialogTitle("Path to X509 CA certificate");

-      int ret = fc.showOpenDialog(this);

-      if (ret == JFileChooser.APPROVE_OPTION)

-        CSecurityTLS.x509ca.setParam(fc.getSelectedFile().toString());

-    } else if (s instanceof JButton && (JButton)s == crl) {

-      JFileChooser fc = new JFileChooser();

-      fc.setDialogTitle("Path to X509 CRL file");

-      int ret = fc.showOpenDialog(this);

-      if (ret == JFileChooser.APPROVE_OPTION)

-        CSecurityTLS.x509crl.setParam(fc.getSelectedFile().toString());

-    }

-  }

-

-  public void itemStateChanged(ItemEvent e) {

-    Object s = e.getSource();

-    if (s instanceof JCheckBox && (JCheckBox)s == autoSelect) {

-      zrle.setEnabled(!autoSelect.isSelected());

-      hextile.setEnabled(!autoSelect.isSelected());

-      tight.setEnabled(!autoSelect.isSelected());

-      raw.setEnabled(!autoSelect.isSelected());

-      fullColour.setEnabled(!autoSelect.isSelected());

-      mediumColour.setEnabled(!autoSelect.isSelected());

-      lowColour.setEnabled(!autoSelect.isSelected());

-      veryLowColour.setEnabled(!autoSelect.isSelected());

-      defaults.setPref("autoSelect",(autoSelect.isSelected()) ? "on" : "off");

-    } 

-    if (s instanceof JCheckBox && (JCheckBox)s == customCompressLevel) {

-      compressLevel.setEnabled(customCompressLevel.isSelected());

-      defaults.setPref("customCompressLevel",(customCompressLevel.isSelected()) ? "on" : "off");

-    }

-    if (s instanceof JCheckBox && (JCheckBox)s == noJpeg) {

-      qualityLevel.setEnabled(noJpeg.isSelected());

-      defaults.setPref("noJpeg",(noJpeg.isSelected()) ? "on" : "off");

-    }

-    if (s instanceof JCheckBox && (JCheckBox)s == sendLocalUsername) {

-      defaults.setPref("sendLocalUsername",(sendLocalUsername.isSelected()) ? "on" : "off");

-    }

-    if (s instanceof JCheckBox && (JCheckBox)s == secVeNCrypt) {

-      encNone.setEnabled(secVeNCrypt.isSelected());

-      encTLS.setEnabled(secVeNCrypt.isSelected());

-      encX509.setEnabled(secVeNCrypt.isSelected());

-      ca.setEnabled(secVeNCrypt.isSelected());

-      crl.setEnabled(secVeNCrypt.isSelected());

-      secIdent.setEnabled(secVeNCrypt.isSelected());

-      secNone.setEnabled(secVeNCrypt.isSelected());

-      secVnc.setEnabled(secVeNCrypt.isSelected());

-      secPlain.setEnabled(secVeNCrypt.isSelected());

-      sendLocalUsername.setEnabled(secVeNCrypt.isSelected());

-    }

-    if (s instanceof JCheckBox && (JCheckBox)s == secIdent ||

-        s instanceof JCheckBox && (JCheckBox)s == secPlain) {

-      sendLocalUsername.setEnabled(secIdent.isSelected()||secPlain.isSelected());

-    }

-  }

-

-}

+
+class OptionsDialog extends Dialog implements
+                            ActionListener,
+                            ItemListener
+{
+
+  // Constants
+  // Static variables
+  static LogWriter vlog = new LogWriter("OptionsDialog");
+
+  OptionsDialogCallback cb;
+  JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel;
+  JCheckBox autoSelect, customCompressLevel, noJpeg;
+  JComboBox menuKey, compressLevel, qualityLevel ;
+  ButtonGroup encodingGroup, colourGroup;
+  JRadioButton zrle, hextile, tight, raw;
+  JRadioButton fullColour, mediumColour, lowColour, veryLowColour;
+  JCheckBox viewOnly, acceptClipboard, sendClipboard;
+  JCheckBox fullScreen, shared, useLocalCursor, fastCopyRect;
+  JCheckBox secVeNCrypt, encNone, encTLS, encX509;
+  JCheckBox secNone, secVnc, secPlain, secIdent, sendLocalUsername;
+  JButton okButton, cancelButton;
+  JButton ca, crl;
+  JButton defSaveButton;
+  boolean encryption = true; 
+  UserPrefs defaults;
+
+  public OptionsDialog(OptionsDialogCallback cb_) { 
+    super(false);
+    cb = cb_;
+    setResizable(false);
+    setTitle("VNC Viewer Options");
+    defaults = new UserPrefs("vncviewer");
+
+    getContentPane().setLayout(
+      new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
+	
+    JTabbedPane tabPane = new JTabbedPane();
+
+    ButtonGroup encodingGroup = new ButtonGroup();
+    ButtonGroup colourGroup = new ButtonGroup();
+
+    // Colour & Encoding tab
+    FormatPanel=new JPanel(new GridBagLayout());
+
+    autoSelect = new JCheckBox("Auto Select");
+    autoSelect.addItemListener(this);
+
+    JPanel encodingPanel = new JPanel(new GridBagLayout());
+    encodingPanel.setBorder(BorderFactory.createTitledBorder("Preferred encoding"));
+    zrle = addRadioCheckbox("ZRLE", encodingGroup, encodingPanel);
+    hextile = addRadioCheckbox("Hextile", encodingGroup, encodingPanel);
+    tight = addRadioCheckbox("Tight", encodingGroup, encodingPanel);
+    raw = addRadioCheckbox("Raw", encodingGroup, encodingPanel);
+
+    JPanel tightPanel = new JPanel(new GridBagLayout());
+    customCompressLevel = new JCheckBox("Custom Compression Level");
+    customCompressLevel.addItemListener(this);
+    Object[] compressionLevels = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    compressLevel  = new JComboBox(compressionLevels);
+    JLabel compressionLabel = new JLabel("Level (1=fast, 9=best)");
+    noJpeg = new JCheckBox("Allow JPEG Compression");
+    noJpeg.addItemListener(this);
+    Object[] qualityLevels = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    qualityLevel  = new JComboBox(qualityLevels);
+    JLabel qualityLabel = new JLabel("Level (1=poor, 9=best)");
+    addGBComponent(customCompressLevel, tightPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+    addGBComponent(compressLevel, tightPanel,       0, 1, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));
+    addGBComponent(compressionLabel, tightPanel,    1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));
+    addGBComponent(noJpeg, tightPanel,              0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+    addGBComponent(qualityLevel, tightPanel,        0, 3, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));
+    addGBComponent(qualityLabel, tightPanel,        1, 3, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));
+
+
+    JPanel colourPanel = new JPanel(new GridBagLayout());
+    colourPanel.setBorder(BorderFactory.createTitledBorder("Colour level"));
+    fullColour = addRadioCheckbox("Full (all available colours)", colourGroup, colourPanel);
+    mediumColour = addRadioCheckbox("Medium (256 colours)", colourGroup, colourPanel);
+    lowColour = addRadioCheckbox("Low (64 colours)", colourGroup, colourPanel);
+    veryLowColour = addRadioCheckbox("Very low(8 colours)", colourGroup, colourPanel);
+
+    addGBComponent(autoSelect,FormatPanel,    0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+    addGBComponent(encodingPanel,FormatPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,2,0,0));
+    addGBComponent(colourPanel,FormatPanel,   1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(0,2,0,0));
+    addGBComponent(tightPanel,FormatPanel,    0, 2, 2, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+
+    // Inputs tab
+    InputsPanel=new JPanel(new GridBagLayout());
+
+    viewOnly = new JCheckBox("View Only (ignore mouse & keyboard)");
+    viewOnly.addItemListener(this);
+    acceptClipboard = new JCheckBox("Accept clipboard from server");
+    acceptClipboard.addItemListener(this);
+    sendClipboard = new JCheckBox("Send clipboard to server");
+    sendClipboard.addItemListener(this);
+    JLabel menuKeyLabel = new JLabel("Menu Key");
+    String[] menuKeys = 
+      { "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" };
+    menuKey  = new JComboBox(menuKeys);
+    menuKey.addItemListener(this);
+    addGBComponent(viewOnly,InputsPanel,        0, 0, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+    addGBComponent(acceptClipboard,InputsPanel, 0, 1, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+    addGBComponent(sendClipboard,InputsPanel,   0, 2, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+    addGBComponent(menuKeyLabel,InputsPanel,    0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(8,10,0,4));
+    addGBComponent(menuKey,InputsPanel,         1, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,125));
+    //((javax.swing.plaf.basic.BasicComboBoxRenderer)menuKey.getRenderer()).setBorder(new EmptyBorder(0,3,0,3));
+
+    // Misc tab
+    MiscPanel=new JPanel(new GridBagLayout());
+
+    fullScreen = new JCheckBox("Full-screen mode");
+    fullScreen.addItemListener(this);
+    shared = new JCheckBox("Shared connection (do not disconnect other viewers)");
+    shared.addItemListener(this);
+    useLocalCursor = new JCheckBox("Render cursor locally");
+    useLocalCursor.addItemListener(this);
+    fastCopyRect = new JCheckBox("Fast CopyRect");
+    fastCopyRect.addItemListener(this);
+    addGBComponent(fullScreen,MiscPanel,     0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+    addGBComponent(shared,MiscPanel,         0, 1, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+    addGBComponent(useLocalCursor,MiscPanel, 0, 2, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+    addGBComponent(fastCopyRect,MiscPanel,   0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,4));
+
+    // load/save tab
+    DefaultsPanel=new JPanel(new GridBagLayout());
+
+    JPanel configPanel = new JPanel(new GridBagLayout());
+    configPanel.setBorder(BorderFactory.createTitledBorder("Configuration File"));
+    JButton cfReloadButton = new JButton("Reload");
+    cfReloadButton.addActionListener(this);
+    addGBComponent(cfReloadButton,configPanel, 0, 0, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+    JButton cfSaveButton = new JButton("Save");
+    cfSaveButton.addActionListener(this);
+    addGBComponent(cfSaveButton,configPanel, 0, 1, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+    JButton cfSaveAsButton = new JButton("Save As...");
+    cfSaveAsButton.addActionListener(this);
+    addGBComponent(cfSaveAsButton,configPanel, 0, 2, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+    cfReloadButton.setEnabled(false);
+    cfSaveButton.setEnabled(false);
+
+    JPanel defaultsPanel = new JPanel(new GridBagLayout());
+    defaultsPanel.setBorder(BorderFactory.createTitledBorder("Defaults"));
+    JButton defReloadButton = new JButton("Reload");
+    defReloadButton.addActionListener(this);
+    addGBComponent(defReloadButton,defaultsPanel, 0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+    defSaveButton = new JButton("Save");
+    defSaveButton.addActionListener(this);
+    addGBComponent(defSaveButton,defaultsPanel, 0, 1, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+
+    addGBComponent(configPanel,DefaultsPanel, 0, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));
+    addGBComponent(defaultsPanel,DefaultsPanel, 1, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));
+
+    // security tab
+    SecPanel=new JPanel(new GridBagLayout());
+
+    JPanel encryptionPanel = new JPanel(new GridBagLayout());
+    encryptionPanel.setBorder(BorderFactory.createTitledBorder("Session Encryption"));
+    encNone = addCheckbox("None", null, encryptionPanel);
+    encTLS = addCheckbox("Anonymous TLS", null, encryptionPanel);
+    encX509 = addJCheckBox("TLS with X.509 certificates", null, encryptionPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.REMAINDER,new Insets(0,0,0,60),0,0));
+
+    JPanel x509Panel = new JPanel(new GridBagLayout());
+    x509Panel.setBorder(BorderFactory.createTitledBorder("X.509 certificates"));
+    ca = new JButton("Load CA certificate");
+    ca.setPreferredSize(new Dimension(145,25));
+    ca.addActionListener(this);
+    crl = new JButton("Load CRL certificate");
+    crl.setPreferredSize(new Dimension(145,25));
+    crl.addActionListener(this);
+    addGBComponent(ca, x509Panel,  0, 0, 1, 1, 2, 2, 0, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));
+    addGBComponent(crl, x509Panel, 1, 0, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));
+
+    JPanel authPanel = new JPanel(new GridBagLayout());
+    authPanel.setBorder(BorderFactory.createTitledBorder("Authentication"));
+    secNone = addCheckbox("None", null, authPanel);
+    secVnc = addCheckbox("Standard VNC", null, authPanel);
+    secPlain = addJCheckBox("Plaintext", null, authPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+    secIdent = addJCheckBox("Ident", null, authPanel, new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+    sendLocalUsername = new JCheckBox("Send Local Username");
+    sendLocalUsername.addItemListener(this);
+    addGBComponent(sendLocalUsername, authPanel, 1, 2, 1, 2, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,20,0,0));
+
+    secVeNCrypt = new JCheckBox("Extended encryption and authentication methods (VeNCrypt)");
+    secVeNCrypt.addItemListener(this);
+    addGBComponent(secVeNCrypt,SecPanel,        0, 0, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,20));
+    addGBComponent(encryptionPanel,SecPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(0,4,2,4));
+    addGBComponent(x509Panel,SecPanel,       0, 2, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,4,2,4));
+    addGBComponent(authPanel,SecPanel,       0, 3, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(2,4,2,4));
+
+    tabPane.add(FormatPanel);
+    tabPane.add(InputsPanel);
+    tabPane.add(MiscPanel);
+    tabPane.add(DefaultsPanel);
+    tabPane.add(SecPanel);
+    tabPane.addTab("Colour & Encoding", FormatPanel);
+    tabPane.addTab("Inputs", InputsPanel);
+    tabPane.addTab("Misc", MiscPanel);
+    tabPane.addTab("Load / Save", DefaultsPanel);
+    tabPane.addTab("Security", SecPanel);
+    tabPane.setBorder(BorderFactory.createEmptyBorder(4,4,0,4));
+
+    okButton = new JButton("OK");
+    okButton.setPreferredSize(new Dimension(90,30));
+    okButton.addActionListener(this);
+    cancelButton = new JButton("Cancel");
+    cancelButton.setPreferredSize(new Dimension(90,30));
+    cancelButton.addActionListener(this);
+
+    JPanel buttonPane = new JPanel();
+    buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
+    buttonPane.setBorder(BorderFactory.createEmptyBorder(4,0,0,0));
+    buttonPane.add(Box.createHorizontalGlue());
+    buttonPane.add(okButton);
+    buttonPane.add(Box.createRigidArea(new Dimension(4,0)));
+    buttonPane.add(cancelButton);
+    buttonPane.add(Box.createRigidArea(new Dimension(4,0)));
+
+    this.getContentPane().add(tabPane);
+    this.getContentPane().add(buttonPane);
+
+    pack();
+	
+  }
+
+  public void initDialog() {
+    if (cb != null) cb.setOptions();
+    zrle.setEnabled(!autoSelect.isSelected());
+    hextile.setEnabled(!autoSelect.isSelected());
+    tight.setEnabled(!autoSelect.isSelected());
+    raw.setEnabled(!autoSelect.isSelected());
+    fullColour.setEnabled(!autoSelect.isSelected());
+    mediumColour.setEnabled(!autoSelect.isSelected());
+    lowColour.setEnabled(!autoSelect.isSelected());
+    veryLowColour.setEnabled(!autoSelect.isSelected());
+    compressLevel.setEnabled(customCompressLevel.isSelected());
+    qualityLevel.setEnabled(noJpeg.isSelected());
+    sendLocalUsername.setEnabled(secVeNCrypt.isEnabled()&&
+      (secPlain.isSelected()||secIdent.isSelected()));
+  }
+
+  JRadioButton addRadioCheckbox(String str, ButtonGroup group, JPanel panel) {
+    JRadioButton c = new JRadioButton(str);
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.anchor = GridBagConstraints.LINE_START;
+    gbc.gridwidth = GridBagConstraints.REMAINDER;
+    gbc.weightx = 1;
+    gbc.weighty = 1;
+    panel.add(c,gbc);
+    group.add(c);
+    c.addItemListener(this);
+    return c;
+  }
+
+  JCheckBox addCheckbox(String str, ButtonGroup group, JPanel panel) {
+    JCheckBox c = new JCheckBox(str);
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.anchor = GridBagConstraints.LINE_START;
+    gbc.gridwidth = GridBagConstraints.REMAINDER;
+    gbc.weightx = 1;
+    gbc.weighty = 1;
+    panel.add(c,gbc);
+    if (group != null)
+      group.add(c);
+    c.addItemListener(this);
+    return c;
+  }
+
+  JCheckBox addJCheckBox(String str, ButtonGroup group, JPanel panel,
+      GridBagConstraints gbc) {
+    JCheckBox c = new JCheckBox(str);
+    panel.add(c,gbc);
+    if (group != null)
+      group.add(c);
+    c.addItemListener(this);
+    
+    return c;
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    Object s = e.getSource();
+    if (s instanceof JButton && (JButton)s == okButton) {
+      ok = true;
+      if (cb != null) cb.getOptions();
+      endDialog();
+    } else if (s instanceof JButton && (JButton)s == cancelButton) {
+      ok = false;
+      endDialog();
+    } else if (s instanceof JButton && (JButton)s == defSaveButton) {
+      try {
+        defaults.Save();
+      } catch (java.lang.Exception x) { }
+    } else if (s instanceof JButton && (JButton)s == ca) {
+      JFileChooser fc = new JFileChooser();
+      fc.setDialogTitle("Path to X509 CA certificate");
+      int ret = fc.showOpenDialog(this);
+      if (ret == JFileChooser.APPROVE_OPTION)
+        CSecurityTLS.x509ca.setParam(fc.getSelectedFile().toString());
+    } else if (s instanceof JButton && (JButton)s == crl) {
+      JFileChooser fc = new JFileChooser();
+      fc.setDialogTitle("Path to X509 CRL file");
+      int ret = fc.showOpenDialog(this);
+      if (ret == JFileChooser.APPROVE_OPTION)
+        CSecurityTLS.x509crl.setParam(fc.getSelectedFile().toString());
+    }
+  }
+
+  public void itemStateChanged(ItemEvent e) {
+    Object s = e.getSource();
+    if (s instanceof JCheckBox && (JCheckBox)s == autoSelect) {
+      zrle.setEnabled(!autoSelect.isSelected());
+      hextile.setEnabled(!autoSelect.isSelected());
+      tight.setEnabled(!autoSelect.isSelected());
+      raw.setEnabled(!autoSelect.isSelected());
+      fullColour.setEnabled(!autoSelect.isSelected());
+      mediumColour.setEnabled(!autoSelect.isSelected());
+      lowColour.setEnabled(!autoSelect.isSelected());
+      veryLowColour.setEnabled(!autoSelect.isSelected());
+      defaults.setPref("autoSelect",(autoSelect.isSelected()) ? "on" : "off");
+    } 
+    if (s instanceof JCheckBox && (JCheckBox)s == customCompressLevel) {
+      compressLevel.setEnabled(customCompressLevel.isSelected());
+      defaults.setPref("customCompressLevel",(customCompressLevel.isSelected()) ? "on" : "off");
+    }
+    if (s instanceof JCheckBox && (JCheckBox)s == noJpeg) {
+      qualityLevel.setEnabled(noJpeg.isSelected());
+      defaults.setPref("noJpeg",(noJpeg.isSelected()) ? "on" : "off");
+    }
+    if (s instanceof JCheckBox && (JCheckBox)s == sendLocalUsername) {
+      defaults.setPref("sendLocalUsername",(sendLocalUsername.isSelected()) ? "on" : "off");
+    }
+    if (s instanceof JCheckBox && (JCheckBox)s == secVeNCrypt) {
+      encNone.setEnabled(secVeNCrypt.isSelected());
+      encTLS.setEnabled(secVeNCrypt.isSelected());
+      encX509.setEnabled(secVeNCrypt.isSelected());
+      ca.setEnabled(secVeNCrypt.isSelected());
+      crl.setEnabled(secVeNCrypt.isSelected());
+      secIdent.setEnabled(secVeNCrypt.isSelected());
+      secNone.setEnabled(secVeNCrypt.isSelected());
+      secVnc.setEnabled(secVeNCrypt.isSelected());
+      secPlain.setEnabled(secVeNCrypt.isSelected());
+      sendLocalUsername.setEnabled(secVeNCrypt.isSelected());
+    }
+    if (s instanceof JCheckBox && (JCheckBox)s == secIdent ||
+        s instanceof JCheckBox && (JCheckBox)s == secPlain) {
+      sendLocalUsername.setEnabled(secIdent.isSelected()||secPlain.isSelected());
+    }
+  }
+
+}
diff --git a/java/src/com/tigervnc/vncviewer/ServerDialog.java b/java/src/com/tigervnc/vncviewer/ServerDialog.java
index 86160f8..e38085a 100644
--- a/java/src/com/tigervnc/vncviewer/ServerDialog.java
+++ b/java/src/com/tigervnc/vncviewer/ServerDialog.java
@@ -1,178 +1,178 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  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.

- */

-

+/* Copyright (C) 2002-2005 RealVNC Ltd.  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.vncviewer;
-

-import java.awt.*;

-import java.awt.image.*;

-import java.awt.event.*;

-import javax.swing.*;

-import javax.swing.border.*;

-import java.net.URL;

-import java.io.File;

-import java.util.*;

+
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.net.URL;
+import java.io.File;
+import java.util.*;
 
 import com.tigervnc.rfb.*;
 import com.tigervnc.rfb.Exception;
-

-class ServerDialog extends Dialog implements

-                           ActionListener,

-                           ItemListener

-{

-

-  public ServerDialog(OptionsDialog options_,

-                      String defaultServerName, CConn cc_) {

-    

-    super(true);

-    cc = cc_;

-    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

-    setResizable(false);

-    setSize(new Dimension(340, 135));

-    setTitle("VNC Viewer : Connection Details");

-

-    options = options_;

-    getContentPane().setLayout(new GridBagLayout());

-

-    JLabel serverLabel = new JLabel("Server:", JLabel.RIGHT);

-    if (options.defaults.getString("server") != null) {

-      server = new JComboBox(options.defaults.getString("server").split(","));

-    } else {

-      server = new JComboBox();

-    }

-

-    // Hack to set the left inset on editable JComboBox

-    if (UIManager.getLookAndFeel().getID() == "Windows") {

-      server.setBorder(BorderFactory.createCompoundBorder(server.getBorder(),

-        BorderFactory.createEmptyBorder(0,2,0,0)));

-    } else {

-      ComboBoxEditor editor = server.getEditor();

-      JTextField jtf = (JTextField)editor.getEditorComponent();

-      jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));

-    }

-

-    server.setEditable(true);

-    editor = server.getEditor();

-    JLabel encryptionLabel = new JLabel("Encryption:");

-    encryption = new JComboBox();

-    serverLabel.setPreferredSize(encryptionLabel.getPreferredSize());

-

-    JPanel topPanel = new JPanel(new GridBagLayout());

-

-    addGBComponent(new JLabel(cc.logo),topPanel, 0, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(5,5,5,15));

-    addGBComponent(serverLabel,topPanel, 1, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(10,0,5,5));

-    addGBComponent(server,topPanel, 2, 0, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(10,0,5,40));

-

-    optionsButton = new JButton("Options...");

-    aboutButton = new JButton("About...");

-    okButton = new JButton("OK");

-    cancelButton = new JButton("Cancel");

-    JPanel buttonPanel = new JPanel(new GridBagLayout());

-    buttonPanel.setPreferredSize(new Dimension(340, 40));

-    addGBComponent(aboutButton,buttonPanel, 0, 3, 1, 1, 0, 0, 0.2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));

-    addGBComponent(optionsButton,buttonPanel, 1, 3, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));

-    addGBComponent(okButton,buttonPanel, 2, 3, 1, 1, 0, 0, 0.8, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));

-    addGBComponent(cancelButton,buttonPanel, 3, 3, 1, 1, 0, 0, 0.5, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));

-

-    GridBagConstraints gbc = new GridBagConstraints();

-    gbc.anchor = GridBagConstraints.LINE_START;

-    gbc.fill = GridBagConstraints.BOTH;

-    gbc.gridwidth = GridBagConstraints.REMAINDER;

-    gbc.gridheight = 1;

-    gbc.insets = new Insets(0,0,0,0);

-    gbc.ipadx = 0;

-    gbc.ipady = 0;

-    gbc.weightx = 1;

-    gbc.weighty = 1;

-    getContentPane().add(topPanel,gbc);

-    getContentPane().add(buttonPanel);

-

-    server.addActionListener(this);

-    optionsButton.addActionListener(this);

-    aboutButton.addActionListener(this);

-    okButton.addActionListener(this);

-    cancelButton.addActionListener(this);

-    

-    pack();

-  }

-

-  public void itemStateChanged(ItemEvent e) {

-    Object s = e.getSource();

-    if (s instanceof JComboBox && (JComboBox)s == encryption) {

-      options.encryption=(encryption.getSelectedIndex()==1) ? false : true;

-    }

-  }

-

-  public void actionPerformed(ActionEvent e) {

-    Object s = e.getSource();

-    if (s instanceof JButton && (JButton)s == okButton) {

-      ok = true;

-      endDialog();

-    } else if (s instanceof JButton && (JButton)s == cancelButton) {

-      ok = false;

-      endDialog();

-    } else if (s instanceof JButton && (JButton)s == optionsButton) {

-      options.showDialog();

-    } else if (s instanceof JButton && (JButton)s == aboutButton) {

-      cc.showAbout();

-    } else if (s instanceof JComboBox && (JComboBox)s == server) {

-      if (e.getActionCommand().equals("comboBoxEdited")) {

-        server.insertItemAt(editor.getItem(), 0);

-        server.setSelectedIndex(0);

-        ok = true;

-        endDialog();

-      }

-    }

-  }

-  

-  public void endDialog() {

-    if (ok) {

-      options.defaults.setPref("encryption",(encryption.getSelectedIndex()==1) ? "off" : "on");

-      if (!server.getSelectedItem().toString().equals("")) {

-        String t = (options.defaults.getString("server")==null) ? "" : options.defaults.getString("server");

-        StringTokenizer st = new StringTokenizer(t, ",");

-        StringBuffer sb = new StringBuffer().append((String)server.getSelectedItem());

-        while (st.hasMoreTokens()) {

-          String s = st.nextToken();

-          if (!s.equals((String)server.getSelectedItem()) && !s.equals("")) {

-            sb.append(',');

-            sb.append(s);

-          }

-        }

-        options.defaults.setPref("server", sb.toString());

-      }

-      try {

-        options.defaults.Save();

-      } catch (java.lang.Exception x) { }

-    }

-    done = true;

-    if (modal) {

-      synchronized (this) {

-        notify();

-      }

-    }

-    this.dispose();

-  }

-

-  CConn cc;

-  JComboBox encryption, server;

-  ComboBoxEditor editor;

-  JButton aboutButton, optionsButton, okButton, cancelButton;

-  OptionsDialog options;

-  static LogWriter vlog = new LogWriter("ServerDialog");

-

-}

+
+class ServerDialog extends Dialog implements
+                           ActionListener,
+                           ItemListener
+{
+
+  public ServerDialog(OptionsDialog options_,
+                      String defaultServerName, CConn cc_) {
+    
+    super(true);
+    cc = cc_;
+    setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+    setResizable(false);
+    setSize(new Dimension(340, 135));
+    setTitle("VNC Viewer : Connection Details");
+
+    options = options_;
+    getContentPane().setLayout(new GridBagLayout());
+
+    JLabel serverLabel = new JLabel("Server:", JLabel.RIGHT);
+    if (options.defaults.getString("server") != null) {
+      server = new JComboBox(options.defaults.getString("server").split(","));
+    } else {
+      server = new JComboBox();
+    }
+
+    // Hack to set the left inset on editable JComboBox
+    if (UIManager.getLookAndFeel().getID() == "Windows") {
+      server.setBorder(BorderFactory.createCompoundBorder(server.getBorder(),
+        BorderFactory.createEmptyBorder(0,2,0,0)));
+    } else {
+      ComboBoxEditor editor = server.getEditor();
+      JTextField jtf = (JTextField)editor.getEditorComponent();
+      jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));
+    }
+
+    server.setEditable(true);
+    editor = server.getEditor();
+    JLabel encryptionLabel = new JLabel("Encryption:");
+    encryption = new JComboBox();
+    serverLabel.setPreferredSize(encryptionLabel.getPreferredSize());
+
+    JPanel topPanel = new JPanel(new GridBagLayout());
+
+    addGBComponent(new JLabel(cc.logo),topPanel, 0, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(5,5,5,15));
+    addGBComponent(serverLabel,topPanel, 1, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(10,0,5,5));
+    addGBComponent(server,topPanel, 2, 0, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(10,0,5,40));
+
+    optionsButton = new JButton("Options...");
+    aboutButton = new JButton("About...");
+    okButton = new JButton("OK");
+    cancelButton = new JButton("Cancel");
+    JPanel buttonPanel = new JPanel(new GridBagLayout());
+    buttonPanel.setPreferredSize(new Dimension(340, 40));
+    addGBComponent(aboutButton,buttonPanel, 0, 3, 1, 1, 0, 0, 0.2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+    addGBComponent(optionsButton,buttonPanel, 1, 3, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+    addGBComponent(okButton,buttonPanel, 2, 3, 1, 1, 0, 0, 0.8, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+    addGBComponent(cancelButton,buttonPanel, 3, 3, 1, 1, 0, 0, 0.5, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+
+    GridBagConstraints gbc = new GridBagConstraints();
+    gbc.anchor = GridBagConstraints.LINE_START;
+    gbc.fill = GridBagConstraints.BOTH;
+    gbc.gridwidth = GridBagConstraints.REMAINDER;
+    gbc.gridheight = 1;
+    gbc.insets = new Insets(0,0,0,0);
+    gbc.ipadx = 0;
+    gbc.ipady = 0;
+    gbc.weightx = 1;
+    gbc.weighty = 1;
+    getContentPane().add(topPanel,gbc);
+    getContentPane().add(buttonPanel);
+
+    server.addActionListener(this);
+    optionsButton.addActionListener(this);
+    aboutButton.addActionListener(this);
+    okButton.addActionListener(this);
+    cancelButton.addActionListener(this);
+    
+    pack();
+  }
+
+  public void itemStateChanged(ItemEvent e) {
+    Object s = e.getSource();
+    if (s instanceof JComboBox && (JComboBox)s == encryption) {
+      options.encryption=(encryption.getSelectedIndex()==1) ? false : true;
+    }
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    Object s = e.getSource();
+    if (s instanceof JButton && (JButton)s == okButton) {
+      ok = true;
+      endDialog();
+    } else if (s instanceof JButton && (JButton)s == cancelButton) {
+      ok = false;
+      endDialog();
+    } else if (s instanceof JButton && (JButton)s == optionsButton) {
+      options.showDialog();
+    } else if (s instanceof JButton && (JButton)s == aboutButton) {
+      cc.showAbout();
+    } else if (s instanceof JComboBox && (JComboBox)s == server) {
+      if (e.getActionCommand().equals("comboBoxEdited")) {
+        server.insertItemAt(editor.getItem(), 0);
+        server.setSelectedIndex(0);
+        ok = true;
+        endDialog();
+      }
+    }
+  }
+  
+  public void endDialog() {
+    if (ok) {
+      options.defaults.setPref("encryption",(encryption.getSelectedIndex()==1) ? "off" : "on");
+      if (!server.getSelectedItem().toString().equals("")) {
+        String t = (options.defaults.getString("server")==null) ? "" : options.defaults.getString("server");
+        StringTokenizer st = new StringTokenizer(t, ",");
+        StringBuffer sb = new StringBuffer().append((String)server.getSelectedItem());
+        while (st.hasMoreTokens()) {
+          String s = st.nextToken();
+          if (!s.equals((String)server.getSelectedItem()) && !s.equals("")) {
+            sb.append(',');
+            sb.append(s);
+          }
+        }
+        options.defaults.setPref("server", sb.toString());
+      }
+      try {
+        options.defaults.Save();
+      } catch (java.lang.Exception x) { }
+    }
+    done = true;
+    if (modal) {
+      synchronized (this) {
+        notify();
+      }
+    }
+    this.dispose();
+  }
+
+  CConn cc;
+  JComboBox encryption, server;
+  ComboBoxEditor editor;
+  JButton aboutButton, optionsButton, okButton, cancelButton;
+  OptionsDialog options;
+  static LogWriter vlog = new LogWriter("ServerDialog");
+
+}