Merge pull request #279 from bphinz/ui-fixes

Various fixes for Java viewer UI
diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java
index 9128b21..dbb2a29 100644
--- a/java/com/tigervnc/vncviewer/CConn.java
+++ b/java/com/tigervnc/vncviewer/CConn.java
@@ -39,6 +39,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.util.jar.Attributes;
@@ -191,7 +192,7 @@
     String passwordFileStr = viewer.passwordFile.getValue();
     PasswdDialog dlg;
 
-    if (user == null && passwordFileStr != "") {
+    if (user == null && !passwordFileStr.equals("")) {
       InputStream fp = null;
       try {
         fp = new FileInputStream(passwordFileStr);
@@ -884,8 +885,10 @@
       options.encNone.setEnabled(false);
       options.encTLS.setEnabled(false);
       options.encX509.setEnabled(false);
-      options.ca.setEnabled(false);
-      options.crl.setEnabled(false);
+      options.x509ca.setEnabled(false);
+      options.caButton.setEnabled(false);
+      options.x509crl.setEnabled(false);
+      options.crlButton.setEnabled(false);
       options.secIdent.setEnabled(false);
       options.secNone.setEnabled(false);
       options.secVnc.setEnabled(false);
@@ -966,11 +969,23 @@
           }
         }
       }
+      File caFile = new File(viewer.x509ca.getValue());
+      if (caFile.exists() && caFile.canRead())
+        options.x509ca.setText(caFile.getAbsolutePath());
+      File crlFile = new File(viewer.x509crl.getValue());
+      if (crlFile.exists() && crlFile.canRead())
+        options.x509crl.setText(crlFile.getAbsolutePath());
       options.encNone.setEnabled(options.secVeNCrypt.isSelected());
       options.encTLS.setEnabled(options.secVeNCrypt.isSelected());
       options.encX509.setEnabled(options.secVeNCrypt.isSelected());
-      options.ca.setEnabled(options.secVeNCrypt.isSelected());
-      options.crl.setEnabled(options.secVeNCrypt.isSelected());
+      options.x509ca.setEnabled(options.secVeNCrypt.isSelected() &&
+                                options.encX509.isSelected());
+      options.caButton.setEnabled(options.secVeNCrypt.isSelected() &&
+                                  options.encX509.isSelected());
+      options.x509crl.setEnabled(options.secVeNCrypt.isSelected() &&
+                                 options.encX509.isSelected());
+      options.crlButton.setEnabled(options.secVeNCrypt.isSelected() &&
+                                   options.encX509.isSelected());
       options.secIdent.setEnabled(options.secVeNCrypt.isSelected());
       options.secPlain.setEnabled(options.secVeNCrypt.isSelected());
       options.sendLocalUsername.setEnabled(options.secPlain.isSelected()||
@@ -1057,6 +1072,10 @@
       cp.qualityLevel = viewer.qualityLevel.getValue();
       encodingChange = true;
     }
+    if (!options.x509ca.getText().equals(""))
+        CSecurityTLS.x509ca.setParam(options.x509ca.getText());
+    if (!options.x509crl.getText().equals(""))
+        CSecurityTLS.x509crl.setParam(options.x509crl.getText());
     viewer.sendLocalUsername.setParam(options.sendLocalUsername.isSelected());
 
     viewer.viewOnly.setParam(options.viewOnly.isSelected());
diff --git a/java/com/tigervnc/vncviewer/ClipboardDialog.java b/java/com/tigervnc/vncviewer/ClipboardDialog.java
index e7aa7e9..441846c 100644
--- a/java/com/tigervnc/vncviewer/ClipboardDialog.java
+++ b/java/com/tigervnc/vncviewer/ClipboardDialog.java
@@ -30,7 +30,7 @@
 
 import com.tigervnc.rfb.LogWriter;
 
-class ClipboardDialog extends Dialog implements ActionListener {
+class ClipboardDialog extends Dialog {
 
   private class VncTransferHandler extends TransferHandler {
     // Custom TransferHandler designed to limit the size of outbound
@@ -109,14 +109,12 @@
     JPanel pb = new JPanel();
     clearButton = new JButton("Clear");
     pb.add(clearButton);
-    clearButton.addActionListener(this);
     sendButton = new JButton("Send to VNC server");
     pb.add(sendButton);
-    sendButton.addActionListener(this);
     cancelButton = new JButton("Cancel");
     pb.add(cancelButton);
-    cancelButton.addActionListener(this);
     getContentPane().add("South", pb);
+    addListeners(this);
     pack();
   }
 
diff --git a/java/com/tigervnc/vncviewer/Dialog.java b/java/com/tigervnc/vncviewer/Dialog.java
index 4b82eb9..3d24619 100644
--- a/java/com/tigervnc/vncviewer/Dialog.java
+++ b/java/com/tigervnc/vncviewer/Dialog.java
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011-2014 Brian P. Hinz
+ * Copyright (C) 2011-2016 Brian P. Hinz
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,9 +30,18 @@
 
 import java.awt.*;
 import java.awt.Dialog.*;
+import java.awt.event.*;
 import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.text.*;
 
-class Dialog extends JDialog {
+class Dialog extends JDialog implements ActionListener,
+                                        ItemListener,
+                                        KeyListener {
+
+  // GridBag weights
+  static double HEAVY = 1.0;
+  static double LIGHT = 0.0;
 
   public Dialog(boolean modal) {
     setIconImage(VncViewer.frameIcon);
@@ -78,30 +87,98 @@
 
   // initDialog() can be overridden in a derived class.  Typically it is used
   // to make sure that checkboxes have the right state, etc.
-  public void initDialog() {
+  public void initDialog() { }
+
+  public void actionPerformed(ActionEvent e) { }
+  public void itemStateChanged(ItemEvent e) { }
+  public void keyTyped(KeyEvent event) { }
+  public void keyReleased(KeyEvent event) { }
+  public void keyPressed(KeyEvent event) { }
+
+  protected void addListeners(Container c) {
+    for (Component ch : c.getComponents()) {
+      if (ch instanceof JCheckBox)
+        ((JCheckBox)ch).addItemListener(this);
+      else if (ch instanceof JButton)
+        ((JButton)ch).addActionListener(this);
+      else if (ch instanceof JComboBox)
+        ((JComboBox)ch).addActionListener(this);
+      else if (ch instanceof JTextField)
+        ((JTextField)ch).addKeyListener(this);
+      else if (ch instanceof Container)
+        addListeners((Container)ch);
+    }
   }
 
-  public void addGBComponent(JComponent c, JComponent cp,
-                             int gx, int gy,
-                             int gw, int gh,
-                             int gipx, int gipy,
-                             double gwx, double gwy,
-                             int fill, int anchor,
-                             Insets insets)
-  {
-      GridBagConstraints gbc = new GridBagConstraints();
-      gbc.anchor = anchor;
-      gbc.fill = fill;
-      gbc.gridx = gx;
-      gbc.gridy = gy;
-      gbc.gridwidth = gw;
-      gbc.gridheight = gh;
-      gbc.insets = insets;
-      gbc.ipadx = gipx;
-      gbc.ipady = gipy;
-      gbc.weightx = gwx;
-      gbc.weighty = gwy;
-      cp.add(c, gbc);
+  public int getButtonLabelInset(AbstractButton b) {
+    // Aligning components vertically to the label of
+    // a JCheckbox is absurdly difficult.  JCheckBox's
+    // getIcon() method generally returns null, so we 
+    // have to resort to querying the UIManager in 
+    // order to determine the width of the checkbox.
+    // The default values are based on Nimbus.
+    int width = 18;
+    int gap = 4;
+
+    Icon ico = b.getIcon();
+    if (ico == null) {
+      if (b instanceof JCheckBox)
+        ico = (Icon)UIManager.get("CheckBox.icon");
+      else if (b instanceof JRadioButton)
+        ico = (Icon)UIManager.get("RadioButton.icon");
+    }
+    if (ico != null)
+      width = Math.max(width, ico.getIconWidth());
+    if (b != null)
+      gap = Math.max(gap, b.getIconTextGap());
+
+    return width + gap;
+  }
+
+  protected class GroupedJRadioButton extends JRadioButton {
+    public GroupedJRadioButton(String l, ButtonGroup g, JComponent c) {
+      super(l);
+      c.add(this);
+      if (g != null)
+        g.add(this);
+    }
+  }
+
+  protected class MyJComboBox extends JComboBox {
+    public MyJComboBox(Object[] items) {
+      super(items);
+      // Hack to set the left inset on editable JComboBox
+      if (UIManager.getLookAndFeel().getID().equals("Windows")) {
+        this.setBorder(BorderFactory.createCompoundBorder(this.getBorder(),
+          BorderFactory.createEmptyBorder(0,1,0,0)));
+      } else if (UIManager.getLookAndFeel().getID().equals("Metal")) {
+        ComboBoxEditor editor = this.getEditor();
+        JTextField jtf = (JTextField)editor.getEditorComponent();
+        jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));
+      }
+    }
+
+    public MyJComboBox() {
+      new MyJComboBox(null);
+    }
+
+    @Override
+    public void setPrototypeDisplayValue(Object prototypeDisplayValue) {
+      // Even with setPrototypeDisplayValue set JComboxBox resizes 
+      // itself when setEditable(true) is called.
+      super.setPrototypeDisplayValue(prototypeDisplayValue);
+      boolean e = isEditable();
+      setEditable(false);
+      Dimension d = getPreferredSize();
+      setPreferredSize(d);
+      setEditable(e);
+    }
+
+    public void setDocument(PlainDocument doc) {
+      ComboBoxEditor editor = this.getEditor();
+      JTextField jtf = (JTextField)editor.getEditorComponent();
+      jtf.setDocument(doc);
+    }
   }
 
   private Window fullScreenWindow;
diff --git a/java/com/tigervnc/vncviewer/MenuKey.java b/java/com/tigervnc/vncviewer/MenuKey.java
index 63b6380..071c004 100644
--- a/java/com/tigervnc/vncviewer/MenuKey.java
+++ b/java/com/tigervnc/vncviewer/MenuKey.java
@@ -70,6 +70,13 @@
     return menuSymbols;
   }
 
+  public static String getKeyText(MenuKeySymbol sym) {
+    if (VncViewer.os.startsWith("mac os x"))
+      return sym.name.replace("_", " ");
+    else
+      return KeyEvent.getKeyText(sym.keycode);
+  }
+
   public static String getMenuKeyValueStr() {
     String s = "";
     for (int i = 0; i < getMenuKeySymbolCount(); i++) {
diff --git a/java/com/tigervnc/vncviewer/OptionsDialog.java b/java/com/tigervnc/vncviewer/OptionsDialog.java
index e2cd7c8..1681518 100644
--- a/java/com/tigervnc/vncviewer/OptionsDialog.java
+++ b/java/com/tigervnc/vncviewer/OptionsDialog.java
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011-2015 Brian P. Hinz
+ * Copyright (C) 2011-2016 Brian P. Hinz
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,18 +26,58 @@
 import java.text.NumberFormat;
 import javax.swing.*;
 import javax.swing.border.*;
+import javax.swing.UIManager.*;
+import javax.swing.text.*;
+import java.util.*;
+import java.util.Map.Entry;
+
 
 import com.tigervnc.rfb.*;
 
-class OptionsDialog extends Dialog implements
-                            ActionListener,
-                            ItemListener
-{
+import static java.awt.GridBagConstraints.BOTH;
+import static java.awt.GridBagConstraints.CENTER;
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.LINE_END;
+import static java.awt.GridBagConstraints.LINE_START;
+import static java.awt.GridBagConstraints.PAGE_START;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.RELATIVE;
+import static java.awt.GridBagConstraints.REMAINDER;
+import static java.awt.GridBagConstraints.VERTICAL;
+
+class OptionsDialog extends Dialog {
+
+  private class IntegerDocument extends PlainDocument {
+    private int limit;
+
+    IntegerDocument(int limit) {
+      super();
+      this.limit = limit;
+    }
+
+    public void insertString(int offset, String  str, AttributeSet a)
+          throws BadLocationException {
+      if (str == null || !str.matches("^[0-9]+$")) return;
+      if ((getLength() + str.length()) > limit)
+        java.awt.Toolkit.getDefaultToolkit().beep();
+      else
+        super.insertString(offset, str, a);
+    }
+  }
 
   private class IntegerTextField extends JFormattedTextField {
-    public IntegerTextField(Format format) {
-      super(format);
+    public IntegerTextField(int digits) {
+      super();
+      this.setDocument(new IntegerDocument(digits));
+      Font f = getFont();
+      String template = String.format("%0"+digits+"d", 0);
+      int w = getFontMetrics(f).stringWidth(template) +
+              getMargin().left + getMargin().right + 
+              getInsets().left + getInsets().right;
+      int h = getPreferredSize().height;
+      setPreferredSize(new Dimension(w, h));
     }
+
     @Override
     protected void processFocusEvent(final FocusEvent e) {
       if (e.isTemporary())
@@ -50,277 +90,603 @@
   }
 
   // Constants
-  // Static variables
   static LogWriter vlog = new LogWriter("OptionsDialog");
 
   CConn cc;
-  JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel, ScreenPanel;
-  JCheckBox autoSelect, customCompressLevel, noJpeg;
   @SuppressWarnings({"rawtypes"})
   JComboBox menuKey, compressLevel, qualityLevel, scalingFactor;
   ButtonGroup encodingGroup, colourGroup;
-  JRadioButton zrle, hextile, tight, raw;
-  JRadioButton fullColour, mediumColour, lowColour, veryLowColour;
-  JCheckBox viewOnly, acceptClipboard, sendClipboard, acceptBell;
-  JCheckBox desktopSize, fullScreen, fullScreenAllMonitors, shared, useLocalCursor;
-  JCheckBox secVeNCrypt, encNone, encTLS, encX509;
-  JCheckBox secNone, secVnc, secPlain, secIdent, sendLocalUsername;
-  JButton okButton, cancelButton;
-  JButton ca, crl;
-  JButton cfLoadButton, cfSaveAsButton, defSaveButton, defReloadButton, defClearButton;
-  JTextField desktopWidth, desktopHeight;
+  JRadioButton zrle, hextile, tight, raw, fullColour, mediumColour,
+               lowColour, veryLowColour;
+  JCheckBox autoSelect, customCompressLevel, noJpeg, viewOnly,
+            acceptClipboard, sendClipboard, acceptBell, desktopSize,
+            fullScreen, fullScreenAllMonitors, shared, useLocalCursor,
+            secVeNCrypt, encNone, encTLS, encX509, secNone, secVnc,
+            secPlain, secIdent, sendLocalUsername;
+  JButton okButton, cancelButton, caButton, crlButton, cfLoadButton,
+          cfSaveAsButton, defSaveButton, defReloadButton, defClearButton;
+  JTextField desktopWidth, desktopHeight, x509ca, x509crl;
+  JTabbedPane tabPane;
 
   @SuppressWarnings({"rawtypes","unchecked"})
   public OptionsDialog(CConn cc_) {
     super(true);
     cc = cc_;
-    setResizable(false);
     setTitle("VNC Viewer Options");
+    setResizable(false);
 
     getContentPane().setLayout(
       new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
 
-    JTabbedPane tabPane = new JTabbedPane();
+    tabPane = new JTabbedPane();
     tabPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
 
-    ButtonGroup encodingGroup = new ButtonGroup();
-    ButtonGroup colourGroup = new ButtonGroup();
+    encodingGroup = new ButtonGroup();
+    colourGroup = new ButtonGroup();
+    int indent = 0;
 
     // Compression tab
-    FormatPanel=new JPanel(new GridBagLayout());
+    JPanel FormatPanel = new JPanel();
+    FormatPanel.setLayout(new BoxLayout(FormatPanel,
+                                        BoxLayout.PAGE_AXIS));
+    FormatPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
 
+    JPanel autoSelectPane = new JPanel();
+    autoSelectPane.setLayout(new BoxLayout(autoSelectPane,
+                                           BoxLayout.LINE_AXIS));
+    autoSelectPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
     autoSelect = new JCheckBox("Auto Select");
-    autoSelect.addItemListener(this);
+    autoSelectPane.add(autoSelect);
+    autoSelectPane.add(Box.createHorizontalGlue());
 
-    JPanel encodingPanel = new JPanel(new GridBagLayout());
-    encodingPanel.setBorder(BorderFactory.createTitledBorder("Preferred encoding"));
-    tight = addRadioCheckbox("Tight", encodingGroup, encodingPanel);
-    zrle = addRadioCheckbox("ZRLE", encodingGroup, encodingPanel);
-    hextile = addRadioCheckbox("Hextile", encodingGroup, encodingPanel);
-    raw = addRadioCheckbox("Raw", encodingGroup, encodingPanel);
+    JPanel encodingPanel = new JPanel(new GridLayout(4, 1));
+    encodingPanel.
+      setBorder(BorderFactory.createTitledBorder("Preferred encoding"));
+    tight = new GroupedJRadioButton("Tight",
+                                    encodingGroup, encodingPanel);
+    zrle = new GroupedJRadioButton("ZRLE",
+                                    encodingGroup, encodingPanel);
+    hextile = new GroupedJRadioButton("Hextile",
+                                      encodingGroup, encodingPanel);
+    raw = new GroupedJRadioButton("Raw", encodingGroup, encodingPanel);
+
+    JPanel colourPanel = new JPanel(new GridLayout(4, 1));
+    colourPanel.setBorder(BorderFactory.createTitledBorder("Color level"));
+    fullColour = new GroupedJRadioButton("Full (all available colors)",
+                                          colourGroup, colourPanel);
+    mediumColour = new GroupedJRadioButton("Medium (256 colors)",
+                                            colourGroup, colourPanel);
+    lowColour = new GroupedJRadioButton("Low (64 colours)",
+                                        colourGroup, colourPanel);
+    veryLowColour = new GroupedJRadioButton("Very low(8 colors)",
+                                            colourGroup, colourPanel);
+
+    JPanel encodingPane = new JPanel(new GridLayout(1, 2, 5, 0));
+    encodingPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
+    encodingPane.add(encodingPanel);
+    encodingPane.add(colourPanel);
 
     JPanel tightPanel = new JPanel(new GridBagLayout());
     customCompressLevel = new JCheckBox("Custom Compression Level");
-    customCompressLevel.addItemListener(this);
     Object[] compressionLevels = { 1, 2, 3, 4, 5, 6 };
-    compressLevel  = new JComboBox(compressionLevels);
-    JLabel compressionLabel = new JLabel("Level (1=fast, 6=best [4-6 are rarely useful])");
-    noJpeg = new JCheckBox("Allow JPEG Compression");
-    noJpeg.addItemListener(this);
-    Object[] qualityLevels = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-    qualityLevel  = new JComboBox(qualityLevels);
-    JLabel qualityLabel = new JLabel("Quality (0=poor, 9=best)");
-    // Hack to set the left inset on editable JComboBox
-    if (UIManager.getLookAndFeel().getID() == "Windows") {
-      compressLevel.setBorder(BorderFactory.createCompoundBorder(compressLevel.getBorder(),
-        BorderFactory.createEmptyBorder(0,1,0,0)));
-    } else if (UIManager.getLookAndFeel().getID() == "Metal") {
-      ComboBoxEditor editor = compressLevel.getEditor();
-      JTextField jtf = (JTextField)editor.getEditorComponent();
-      jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));
-    }
-    Dimension size = compressLevel.getPreferredSize();
+    compressLevel  = new MyJComboBox(compressionLevels);
+    ((MyJComboBox)compressLevel).setDocument(new IntegerDocument(1));
+    compressLevel.setPrototypeDisplayValue("0.");
     compressLevel.setEditable(true);
-    compressLevel.setPreferredSize(size);
-    addGBComponent(customCompressLevel, tightPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,0,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(4,0,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));
+    JLabel compressionLabel =
+      new JLabel("Level (1=fast, 6=best [4-6 are rarely useful])");
+    noJpeg = new JCheckBox("Allow JPEG Compression");
+    Object[] qualityLevels = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+    qualityLevel  = new MyJComboBox(qualityLevels);
+    qualityLevel.setPrototypeDisplayValue("0.");
+    JLabel qualityLabel = new JLabel("Quality (0=poor, 9=best)");
 
+    tightPanel.add(customCompressLevel,
+                   new GridBagConstraints(0, 0,
+                                          REMAINDER, 1,
+                                          LIGHT, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, 0, 0, 0),
+                                          NONE, NONE));
+    indent = getButtonLabelInset(customCompressLevel);
+    tightPanel.add(compressLevel,
+                   new GridBagConstraints(0, 1,
+                                          1, 1,
+                                          LIGHT, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, indent, 0, 0),
+                                          NONE, NONE));
+    tightPanel.add(compressionLabel,
+                   new GridBagConstraints(1, 1,
+                                          1, 1,
+                                          HEAVY, LIGHT,
+                                          LINE_START, HORIZONTAL,
+                                          new Insets(0, 5, 0, 0),
+                                          NONE, NONE));
+    tightPanel.add(noJpeg,
+                   new GridBagConstraints(0, 2,
+                                          REMAINDER, 1,
+                                          LIGHT, LIGHT, 
+                                          LINE_START, NONE,
+                                          new Insets(5, 0, 0, 0),
+                                          NONE, NONE));
+    indent = getButtonLabelInset(noJpeg);
+    tightPanel.add(qualityLevel,
+                   new GridBagConstraints(0, 3,
+                                          1, 1,
+                                          LIGHT, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, indent, 0, 0),
+                                          NONE, NONE));
+    tightPanel.add(qualityLabel,
+                   new GridBagConstraints(1, 3,
+                                          1, 1,
+                                          HEAVY, NONE,
+                                          LINE_START, HORIZONTAL,
+                                          new Insets(0, 5, 0, 0),
+                                          NONE, NONE));
+    tightPanel.add(Box.createRigidArea(new Dimension(5,0)),
+                   new GridBagConstraints(0, 4,
+                                          REMAINDER, REMAINDER,
+                                          HEAVY, HEAVY,
+                                          LINE_START, BOTH,
+                                          new Insets(0, 0, 0, 0),
+                                          NONE, NONE));
+    FormatPanel.add(autoSelectPane);
+    FormatPanel.add(encodingPane);
+    FormatPanel.add(tightPanel);
 
-    JPanel colourPanel = new JPanel(new GridBagLayout());
-    colourPanel.setBorder(BorderFactory.createTitledBorder("Color level"));
-    fullColour = addRadioCheckbox("Full (all available colors)", colourGroup, colourPanel);
-    mediumColour = addRadioCheckbox("Medium (256 colors)", colourGroup, colourPanel);
-    lowColour = addRadioCheckbox("Low (64 colours)", colourGroup, colourPanel);
-    veryLowColour = addRadioCheckbox("Very low(8 colors)", colourGroup, colourPanel);
+    // security tab
+    JPanel SecPanel = new JPanel();
+    SecPanel.setLayout(new BoxLayout(SecPanel,
+                                     BoxLayout.PAGE_AXIS));
+    SecPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
 
-    addGBComponent(autoSelect,FormatPanel,    0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,5,0,5));
-    addGBComponent(encodingPanel,FormatPanel, 0, 1, 1, 1, 2, 2, 3, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,5));
-    addGBComponent(colourPanel,FormatPanel,   1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(0,0,0,5));
-    addGBComponent(tightPanel,FormatPanel,    0, 2, 2, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,5,0,5));
+    JPanel vencryptPane = new JPanel();
+    vencryptPane.setLayout(new BoxLayout(vencryptPane,
+                                         BoxLayout.LINE_AXIS));
+    vencryptPane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+    secVeNCrypt = new JCheckBox("Extended encryption and "+
+                                "authentication methods (VeNCrypt)");
+    vencryptPane.add(secVeNCrypt);
+    vencryptPane.add(Box.createHorizontalGlue());
+
+    JPanel encrPanel = new JPanel(new GridBagLayout());
+    encrPanel.setBorder(BorderFactory.createTitledBorder("Encryption"));
+    encNone = new JCheckBox("None");
+    encTLS = new JCheckBox("Anonymous TLS");
+    encX509 = new JCheckBox("TLS with X.509 certificates");
+    JLabel caLabel = new JLabel("X.509 CA Certificate");
+    x509ca = new JTextField();
+    x509ca.setName(Configuration.getParam("x509ca").getName());
+    caButton = new JButton("Browse");
+    JLabel crlLabel = new JLabel("X.509 CRL file");
+    x509crl = new JTextField();
+    x509crl.setName(Configuration.getParam("x509crl").getName());
+    crlButton = new JButton("Browse");
+    encrPanel.add(encNone,
+                  new GridBagConstraints(0, 0,
+                                         REMAINDER, 1,
+                                         HEAVY, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    encrPanel.add(encTLS,
+                  new GridBagConstraints(0, 1,
+                                         REMAINDER, 1,
+                                         HEAVY, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    encrPanel.add(encX509,
+                  new GridBagConstraints(0, 2,
+                                         3, 1,
+                                         HEAVY, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 0, 0),
+                                         NONE, NONE));
+    indent = getButtonLabelInset(encX509);
+    encrPanel.add(caLabel,
+                  new GridBagConstraints(0, 3,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_END, NONE,
+                                         new Insets(0, indent, 5, 0),
+                                         0, 0));
+    encrPanel.add(x509ca,
+                  new GridBagConstraints(1, 3,
+                                         1, 1,
+                                         HEAVY, LIGHT,
+                                         LINE_START, HORIZONTAL,
+                                         new Insets(0, 5, 5, 0),
+                                         0, 0));
+    encrPanel.add(caButton,
+                  new GridBagConstraints(2, 3,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, VERTICAL,
+                                         new Insets(0, 5, 5, 0),
+                                         0, 0));
+    encrPanel.add(crlLabel,
+                  new GridBagConstraints(0, 4,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_END, NONE,
+                                         new Insets(0, indent, 0, 0),
+                                         0, 0));
+    encrPanel.add(x509crl,
+                  new GridBagConstraints(1, 4,
+                                         1, 1,
+                                         HEAVY, LIGHT,
+                                         LINE_START, HORIZONTAL,
+                                         new Insets(0, 5, 0, 0),
+                                         0, 0));
+    encrPanel.add(crlButton,
+                  new GridBagConstraints(2, 4,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, VERTICAL,
+                                         new Insets(0, 5, 0, 0),
+                                         0, 0));
+
+    JPanel authPanel = new JPanel(new GridBagLayout());
+    authPanel.setBorder(BorderFactory.createTitledBorder("Authentication"));
+
+    secNone = new JCheckBox("None");
+    secVnc = new JCheckBox("Standard VNC");
+    secPlain = new JCheckBox("Plaintext");
+    secIdent = new JCheckBox("Ident");
+    sendLocalUsername = new JCheckBox("Send Local Username");
+    authPanel.add(secNone,
+                  new GridBagConstraints(0, 0,
+                                         REMAINDER, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    authPanel.add(secVnc,
+                  new GridBagConstraints(0, 1,
+                                         REMAINDER, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    authPanel.add(secPlain,
+                  new GridBagConstraints(0, 2,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 2, 0),
+                                         NONE, NONE));
+    authPanel.add(secIdent,
+                  new GridBagConstraints(0, 3,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(2, 0, 0, 0),
+                                         NONE, NONE));
+    authPanel.add(sendLocalUsername,
+                  new GridBagConstraints(1, 2,
+                                         1, 2,
+                                         HEAVY, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(2, 20, 2, 0),
+                                         NONE, NONE));
+
+    SecPanel.add(vencryptPane,
+                 new GridBagConstraints(0, 0,
+                                        REMAINDER, 1,
+                                        LIGHT, LIGHT,
+                                        LINE_START, HORIZONTAL,
+                                        new Insets(0, 0, 4, 0),
+                                        NONE, NONE));
+    SecPanel.add(encrPanel,
+                 new GridBagConstraints(0, 1,
+                                        REMAINDER, 1,
+                                        LIGHT, LIGHT,
+                                        LINE_START, HORIZONTAL,
+                                        new Insets(0, 0, 4, 0),
+                                        NONE, NONE));
+    SecPanel.add(authPanel,
+                 new GridBagConstraints(0, 2,
+                                        REMAINDER, 1,
+                                        LIGHT, LIGHT,
+                                        LINE_START, HORIZONTAL,
+                                        new Insets(0, 0, 4, 0),
+                                        NONE, NONE));
+    SecPanel.add(Box.createRigidArea(new Dimension(0,0)),
+                 new GridBagConstraints(0, RELATIVE,
+                                        REMAINDER, REMAINDER,
+                                        HEAVY, HEAVY,
+                                        LINE_START, BOTH,
+                                        new Insets(0, 0, 0, 0),
+                                        NONE, NONE));
 
     // Input tab
-    InputsPanel=new JPanel(new GridBagLayout());
+    JPanel inputPanel = new JPanel(new GridBagLayout());
+    inputPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
 
     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 = new String[MenuKey.getMenuKeySymbolCount()];
     for (int i = 0; i < MenuKey.getMenuKeySymbolCount(); i++)
-      menuKeys[i] = KeyEvent.getKeyText(MenuKey.getMenuKeySymbols()[i].keycode);
+      menuKeys[i] = MenuKey.getKeyText(MenuKey.getMenuKeySymbols()[i]);
     menuKey  = new JComboBox(menuKeys);
-    menuKey.addItemListener(this);
-    addGBComponent(viewOnly,InputsPanel,        0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
-    addGBComponent(acceptClipboard,InputsPanel, 0, 1, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
-    addGBComponent(sendClipboard,InputsPanel,   0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
-    addGBComponent(menuKeyLabel,InputsPanel,    0, 3, 1, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(8,8,0,5));
-    addGBComponent(menuKey,InputsPanel,         1, 3, 1, GridBagConstraints.REMAINDER, 2, 2, 25, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(4,5,0,5));
+
+    inputPanel.add(viewOnly,
+                   new GridBagConstraints(0, 0,
+                                          REMAINDER, 1,
+                                          HEAVY, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, 0, 4, 0),
+                                          NONE, NONE));
+    inputPanel.add(acceptClipboard,
+                   new GridBagConstraints(0, 1,
+                                          REMAINDER, 1,
+                                          HEAVY, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, 0, 4, 0),
+                                          NONE, NONE));
+    inputPanel.add(sendClipboard,
+                   new GridBagConstraints(0, 2,
+                                          REMAINDER, 1,
+                                          HEAVY, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, 0, 4, 0),
+                                          NONE, NONE));
+    inputPanel.add(menuKeyLabel,
+                   new GridBagConstraints(0, 3,
+                                          1, 1,
+                                          LIGHT, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, 0, 0, 0),
+                                          NONE, NONE));
+    inputPanel.add(menuKey,
+                   new GridBagConstraints(1, 3,
+                                          1, 1,
+                                          HEAVY, LIGHT,
+                                          LINE_START, NONE,
+                                          new Insets(0, 5, 0, 0),
+                                          NONE, NONE));
+    inputPanel.add(Box.createRigidArea(new Dimension(5, 0)),
+                   new GridBagConstraints(0, 4,
+                                          REMAINDER, REMAINDER,
+                                          HEAVY, HEAVY,
+                                          LINE_START, BOTH,
+                                          new Insets(0, 0, 0, 0),
+                                          NONE, NONE));
 
     // Screen tab
-    ScreenPanel=new JPanel(new GridBagLayout());
+    JPanel ScreenPanel = new JPanel(new GridBagLayout());
+    ScreenPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
     desktopSize = new JCheckBox("Resize remote session on connect");
-    desktopSize.addItemListener(this);
     desktopSize.setEnabled(!cc.viewer.embed.getValue() &&
                            (cc.viewer.desktopSize.getValue() != null));
-    NumberFormat format = NumberFormat.getIntegerInstance();
-    format.setMaximumIntegerDigits(5);
-    format.setMinimumIntegerDigits(0);
-    format.setGroupingUsed(false);
-    desktopWidth = new IntegerTextField(format);
-    desktopWidth.setColumns(4);
+    desktopWidth = new IntegerTextField(5);
     desktopWidth.setEnabled(desktopSize.isSelected());
-    desktopHeight = new IntegerTextField(format);
-    desktopHeight.setColumns(4);
+    desktopHeight = new IntegerTextField(5);
     desktopHeight.setEnabled(desktopSize.isSelected());
-    JPanel desktopSizePanel = new JPanel();
+    JPanel desktopSizePanel =
+      new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
     desktopSizePanel.add(desktopWidth);
-    desktopSizePanel.add(new JLabel("x"));
+    desktopSizePanel.add(new JLabel(" x "));
     desktopSizePanel.add(desktopHeight);
     fullScreen = new JCheckBox("Full-screen mode");
-    fullScreen.addItemListener(this);
     fullScreen.setEnabled(!cc.viewer.embed.getValue());
-    fullScreenAllMonitors = new JCheckBox("Enable full-screen mode over all monitors");
-    fullScreenAllMonitors.addItemListener(this);
+    fullScreenAllMonitors =
+      new JCheckBox("Enable full-screen mode over all monitors");
     fullScreenAllMonitors.setEnabled(!cc.viewer.embed.getValue());
     JLabel scalingFactorLabel = new JLabel("Scaling Factor");
     Object[] scalingFactors = {
       "Auto", "Fixed Aspect Ratio", "50%", "75%", "95%", "100%", "105%",
       "125%", "150%", "175%", "200%", "250%", "300%", "350%", "400%" };
-    scalingFactor = new JComboBox(scalingFactors);
-    // Hack to set the left inset on editable JComboBox
-    if (UIManager.getLookAndFeel().getID() == "Windows") {
-      scalingFactor.setBorder(BorderFactory.createCompoundBorder(scalingFactor.getBorder(),
-        BorderFactory.createEmptyBorder(0,1,0,0)));
-    } else if (UIManager.getLookAndFeel().getID() == "Metal") {
-      ComboBoxEditor sfe = scalingFactor.getEditor();
-      JTextField sfeTextField = (JTextField)sfe.getEditorComponent();
-      sfeTextField.setBorder(new CompoundBorder(sfeTextField.getBorder(),
-                                                new EmptyBorder(0,2,0,0)));
-    }
+    scalingFactor = new MyJComboBox(scalingFactors);
     scalingFactor.setEditable(true);
-    scalingFactor.addItemListener(this);
     scalingFactor.setEnabled(!cc.viewer.embed.getValue());
-    addGBComponent(desktopSize,ScreenPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
-    addGBComponent(desktopSizePanel,ScreenPanel, 0, 1, 2, 1, 2, 2, 1, 0, GridBagConstraints.REMAINDER, GridBagConstraints.LINE_START, new Insets(0,20,0,0));
-    addGBComponent(fullScreen,ScreenPanel, 0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,5));
-    addGBComponent(fullScreenAllMonitors,ScreenPanel, 0, 3, 4, 1, 2, 2, 1, 0, GridBagConstraints.REMAINDER, GridBagConstraints.LINE_START, new Insets(4,25,0,5));
-    addGBComponent(scalingFactorLabel,ScreenPanel, 0, 4, 1, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(8,8,0,5));
-    addGBComponent(scalingFactor,ScreenPanel, 1, 4, 1, GridBagConstraints.REMAINDER, 2, 2, 25, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(4,5,0,5));
+    ScreenPanel.add(desktopSize,
+                    new GridBagConstraints(0, 0,
+                                           REMAINDER, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(0, 0, 0, 0),
+                                           NONE, NONE));
+    indent = getButtonLabelInset(desktopSize);
+    ScreenPanel.add(desktopSizePanel,
+                    new GridBagConstraints(0, 1,
+                                           REMAINDER, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(0, indent, 0, 0),
+                                           NONE, NONE));
+    ScreenPanel.add(fullScreen,
+                    new GridBagConstraints(0, 2,
+                                           REMAINDER, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(0, 0, 4, 0),
+                                           NONE, NONE));
+    indent = getButtonLabelInset(fullScreen);
+    ScreenPanel.add(fullScreenAllMonitors,
+                    new GridBagConstraints(0, 3,
+                                           REMAINDER, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(0, indent, 4, 0),
+                                           NONE, NONE));
+    ScreenPanel.add(scalingFactorLabel,
+                    new GridBagConstraints(0, 4,
+                                           1, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(0, 0, 4, 0),
+                                           NONE, NONE));
+    ScreenPanel.add(scalingFactor,
+                    new GridBagConstraints(1, 4,
+                                           1, 1,
+                                           HEAVY, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(0, 5, 4, 0),
+                                           NONE, NONE));
+    ScreenPanel.add(Box.createRigidArea(new Dimension(5, 0)),
+                    new GridBagConstraints(0, 5,
+                                           REMAINDER, REMAINDER,
+                                           HEAVY, HEAVY,
+                                           LINE_START, BOTH,
+                                           new Insets(0, 0, 0, 0),
+                                           NONE, NONE));
 
     // Misc tab
-    MiscPanel=new JPanel(new GridBagLayout());
-
-    shared = new JCheckBox("Shared connection (do not disconnect other viewers)");
-    shared.addItemListener(this);
+    JPanel MiscPanel = new JPanel(new GridBagLayout());
+    MiscPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
+    shared =
+      new JCheckBox("Shared connection (do not disconnect other viewers)");
     useLocalCursor = new JCheckBox("Render cursor locally");
-    useLocalCursor.addItemListener(this);
     acceptBell = new JCheckBox("Beep when requested by the server");
-    acceptBell.addItemListener(this);
-    addGBComponent(shared,MiscPanel,         0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
-    addGBComponent(useLocalCursor,MiscPanel, 0, 1, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,5,0,5));
-    addGBComponent(acceptBell,MiscPanel,     0, 2, 2, 1, 2, 2, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,5,0,5));
+    MiscPanel.add(shared,
+                  new GridBagConstraints(0, 0,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    MiscPanel.add(useLocalCursor,
+                  new GridBagConstraints(0, 1,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    MiscPanel.add(acceptBell,
+                  new GridBagConstraints(0, 2,
+                                         1, 1,
+                                         LIGHT, LIGHT,
+                                         LINE_START, NONE,
+                                         new Insets(0, 0, 4, 0),
+                                         NONE, NONE));
+    MiscPanel.add(Box.createRigidArea(new Dimension(5, 0)),
+                  new GridBagConstraints(0, 3,
+                                         REMAINDER, REMAINDER,
+                                         HEAVY, HEAVY,
+                                         LINE_START, BOTH,
+                                         new Insets(0, 0, 0, 0),
+                                         NONE, NONE));
+
 
     // load/save tab
-    DefaultsPanel=new JPanel(new GridBagLayout());
-
+    JPanel loadSavePanel = new JPanel(new GridBagLayout());
+    loadSavePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
     JPanel configPanel = new JPanel(new GridBagLayout());
-    configPanel.setBorder(BorderFactory.createTitledBorder("Configuration File"));
+    configPanel.
+      setBorder(BorderFactory.createTitledBorder("Configuration File"));
     cfLoadButton = new JButton("Load");
-    cfLoadButton.addActionListener(this);
-    addGBComponent(cfLoadButton,configPanel, 0, 0, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
     cfSaveAsButton = new JButton("Save As...");
-    cfSaveAsButton.addActionListener(this);
-    addGBComponent(cfSaveAsButton,configPanel, 0, 1, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+    configPanel.add(cfLoadButton,
+                    new GridBagConstraints(0, 0,
+                                           1, 1,
+                                           HEAVY, LIGHT,
+                                           CENTER, HORIZONTAL,
+                                           new Insets(0, 0, 5, 0),
+                                           NONE, NONE));
+    configPanel.add(cfSaveAsButton,
+                    new GridBagConstraints(0, 1,
+                                           1, 1,
+                                           HEAVY, HEAVY,
+                                           CENTER, HORIZONTAL,
+                                           new Insets(0, 0, 0, 0),
+                                           NONE, NONE));
 
     JPanel defaultsPanel = new JPanel(new GridBagLayout());
     defaultsPanel.setBorder(BorderFactory.createTitledBorder("Defaults"));
     defClearButton = new JButton("Clear");
-    defClearButton.addActionListener(this);
-    addGBComponent(defClearButton,defaultsPanel, 0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
     defReloadButton = new JButton("Reload");
-    defReloadButton.addActionListener(this);
-    addGBComponent(defReloadButton,defaultsPanel, 0, 1, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
     defSaveButton = new JButton("Save");
-    defSaveButton.addActionListener(this);
-    addGBComponent(defSaveButton,defaultsPanel, 0, 2, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+    defaultsPanel.add(defClearButton,
+                      new GridBagConstraints(0, 0,
+                                             1, 1,
+                                             HEAVY, LIGHT,
+                                             CENTER, HORIZONTAL,
+                                             new Insets(0, 0, 5, 0),
+                                             NONE, NONE));
+    defaultsPanel.add(defReloadButton,
+                      new GridBagConstraints(0, 1,
+                                             1, 1,
+                                             HEAVY, LIGHT,
+                                             CENTER, HORIZONTAL,
+                                             new Insets(0, 0, 5, 0),
+                                             NONE, NONE));
+    defaultsPanel.add(defSaveButton,
+                      new GridBagConstraints(0, 2,
+                                             1, 1,
+                                             HEAVY, HEAVY,
+                                             CENTER, HORIZONTAL,
+                                             new Insets(0, 0, 0, 0),
+                                             NONE, NONE));
 
-    addGBComponent(configPanel,DefaultsPanel, 0, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,5,4,5));
-    addGBComponent(defaultsPanel,DefaultsPanel, 1, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,0,4,5));
+    loadSavePanel.add(configPanel,
+                      new GridBagConstraints(0, 0,
+                                             1, 1,
+                                             HEAVY, LIGHT,
+                                             PAGE_START, HORIZONTAL,
+                                             new Insets(0, 0, 0, 0),
+                                             NONE, NONE));
+    loadSavePanel.add(Box.createRigidArea(new Dimension(5, 0)),
+                      new GridBagConstraints(1, 1,
+                                             1, 1,
+                                             LIGHT, LIGHT,
+                                             LINE_START, NONE,
+                                             new Insets(0, 0, 0, 0),
+                                             NONE, NONE));
+    loadSavePanel.add(defaultsPanel,
+                      new GridBagConstraints(2, 0,
+                                             1, 1,
+                                             HEAVY, LIGHT,
+                                             PAGE_START, HORIZONTAL,
+                                             new Insets(0, 0, 0, 0),
+                                             NONE, NONE));
+    loadSavePanel.add(Box.createRigidArea(new Dimension(5, 0)),
+                      new GridBagConstraints(0, 1,
+                                             REMAINDER, REMAINDER,
+                                             HEAVY, HEAVY,
+                                             LINE_START, BOTH,
+                                             new Insets(0, 0, 0, 0),
+                                             NONE, NONE));
 
-    // security tab
-    SecPanel=new JPanel(new GridBagLayout());
-
-    JPanel encryptionPanel = new JPanel(new GridBagLayout());
-    encryptionPanel.setBorder(BorderFactory.createTitledBorder("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,3,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.REMAINDER,new Insets(0,0,0,0),0,0));
-
-    ca = new JButton("Load CA certificate");
-    ca.addActionListener(this);
-    crl = new JButton("Load CRL certificate");
-    crl.addActionListener(this);
-    addGBComponent(ca, encryptionPanel,  0, 3, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,20,2,2));
-    addGBComponent(crl, encryptionPanel, 1, 3, 1, 1, 2, 2, 1, 0, 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(4,5,0,30));
-    addGBComponent(encryptionPanel,SecPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(0,10,2,5));
-    addGBComponent(authPanel,SecPanel,       0, 3, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(2,10,2,5));
-
-    tabPane.add(FormatPanel);
-    tabPane.add(ScreenPanel);
-    tabPane.add(InputsPanel);
-    tabPane.add(MiscPanel);
-    tabPane.add(DefaultsPanel);
-    tabPane.add(SecPanel);
+    // tabPane
     tabPane.addTab("Compression", FormatPanel);
     tabPane.addTab("Security", SecPanel);
-    tabPane.addTab("Input", InputsPanel);
+    tabPane.addTab("Input", inputPanel);
     tabPane.addTab("Screen", ScreenPanel);
     tabPane.addTab("Misc", MiscPanel);
-    tabPane.addTab("Load / Save", DefaultsPanel);
-    tabPane.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
+    tabPane.addTab("Load / Save", loadSavePanel);
+    tabPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+    // Resize the tabPane if necessary to prevent scrolling
+    Insets tpi =
+      (Insets)UIManager.get("TabbedPane:TabbedPaneTabArea.contentMargins");
+    int minWidth = tpi.left + tpi.right;
+    for (int i = 0; i < tabPane.getTabCount(); i++)
+      minWidth += tabPane.getBoundsAt(i).width;
+    int minHeight = tabPane.getPreferredSize().height;
+    if (tabPane.getPreferredSize().width < minWidth)
+      tabPane.setPreferredSize(new Dimension(minWidth, minHeight));
 
+    // button pane
     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(5,5,5,5));
-    buttonPane.add(Box.createHorizontalGlue());
+    JPanel buttonPane = new JPanel(new GridLayout(1, 5, 10, 10));
+    buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));
+    buttonPane.add(Box.createRigidArea(new Dimension()));
+    buttonPane.add(Box.createRigidArea(new Dimension()));
+    buttonPane.add(Box.createRigidArea(new Dimension()));
     buttonPane.add(okButton);
-    buttonPane.add(Box.createRigidArea(new Dimension(5,0)));
     buttonPane.add(cancelButton);
-    buttonPane.add(Box.createRigidArea(new Dimension(5,0)));
 
-    this.getContentPane().add(tabPane);
-    this.getContentPane().add(buttonPane);
-
+    this.add(tabPane);
+    this.add(buttonPane);
+    addListeners(this);
     pack();
-
   }
 
   public void initDialog() {
@@ -367,21 +733,29 @@
       }
     }
     UserPreferences.set("global", "NoJPEG", !noJpeg.isSelected());
-    UserPreferences.set("global", "QualityLevel", (Integer)qualityLevel.getSelectedItem());
-    UserPreferences.set("global", "CustomCompressLevel", customCompressLevel.isSelected());
-    UserPreferences.set("global", "CompressLevel", (Integer)compressLevel.getSelectedItem());
+    UserPreferences.set("global",
+            "QualityLevel", (Integer)qualityLevel.getSelectedItem());
+    UserPreferences.set("global",
+            "CustomCompressLevel", customCompressLevel.isSelected());
+    UserPreferences.set("global",
+            "CompressLevel", (Integer)compressLevel.getSelectedItem());
     UserPreferences.set("global", "ViewOnly", viewOnly.isSelected());
-    UserPreferences.set("global", "AcceptClipboard", acceptClipboard.isSelected());
+    UserPreferences.set("global",
+            "AcceptClipboard", acceptClipboard.isSelected());
     UserPreferences.set("global", "SendClipboard", sendClipboard.isSelected());
-    String menuKeyStr = MenuKey.getMenuKeySymbols()[menuKey.getSelectedIndex()].name;
+    String menuKeyStr =
+      MenuKey.getMenuKeySymbols()[menuKey.getSelectedIndex()].name;
     UserPreferences.set("global", "MenuKey", menuKeyStr);
     String desktopSizeString =
-      desktopSize.isSelected() ? desktopWidth.getText() + "x" + desktopHeight.getText() : "";
+      desktopSize.isSelected() ?
+        desktopWidth.getText() + "x" + desktopHeight.getText() : "";
     UserPreferences.set("global", "DesktopSize", desktopSizeString);
     UserPreferences.set("global", "FullScreen", fullScreen.isSelected());
-    UserPreferences.set("global", "FullScreenAllMonitors", fullScreenAllMonitors.isSelected());
+    UserPreferences.set("global",
+            "FullScreenAllMonitors", fullScreenAllMonitors.isSelected());
     UserPreferences.set("global", "Shared", shared.isSelected());
-    UserPreferences.set("global", "UseLocalCursor", useLocalCursor.isSelected());
+    UserPreferences.set("global",
+            "UseLocalCursor", useLocalCursor.isSelected());
     UserPreferences.set("global", "AcceptBell", acceptBell.isSelected());
     String scaleString = scalingFactor.getSelectedItem().toString();
     if (scaleString.equalsIgnoreCase("Auto")) {
@@ -400,11 +774,14 @@
     UserPreferences.set("viewer", "secVnc", secVnc.isSelected());
     UserPreferences.set("viewer", "secPlain", secPlain.isSelected());
     UserPreferences.set("viewer", "secIdent", secIdent.isSelected());
-    UserPreferences.set("global", "SendLocalUsername", sendLocalUsername.isSelected());
-    if (CSecurityTLS.x509ca.getValueStr() != "")
-      UserPreferences.set("viewer", "x509ca", CSecurityTLS.x509ca.getValueStr());
-    if (CSecurityTLS.x509crl.getValueStr() != "")
-      UserPreferences.set("viewer", "x509crl", CSecurityTLS.x509crl.getValueStr());
+    UserPreferences.set("global",
+            "SendLocalUsername", sendLocalUsername.isSelected());
+    if (!CSecurityTLS.x509ca.getValueStr().equals(""))
+      UserPreferences.set("viewer", "x509ca",
+              CSecurityTLS.x509ca.getValueStr());
+    if (!CSecurityTLS.x509crl.getValueStr().equals(""))
+      UserPreferences.set("viewer", "x509crl",
+              CSecurityTLS.x509crl.getValueStr());
   }
 
   private void restorePreferences() {
@@ -443,24 +820,32 @@
       }
     }
     noJpeg.setSelected(!UserPreferences.getBool("global", "NoJPEG"));
-    qualityLevel.setSelectedItem(UserPreferences.getInt("global", "QualityLevel"));
-    customCompressLevel.setSelected(UserPreferences.getBool("global", "CustomCompressLevel"));
-    compressLevel.setSelectedItem(UserPreferences.getInt("global", "CompressLevel"));
+    qualityLevel.setSelectedItem(UserPreferences.getInt("global",
+            "QualityLevel"));
+    customCompressLevel.setSelected(UserPreferences.getBool("global",
+            "CustomCompressLevel"));
+    compressLevel.setSelectedItem(UserPreferences.getInt("global",
+            "CompressLevel"));
     viewOnly.setSelected(UserPreferences.getBool("global", "ViewOnly"));
-    acceptClipboard.setSelected(UserPreferences.getBool("global", "AcceptClipboard"));
-    sendClipboard.setSelected(UserPreferences.getBool("global", "SendClipboard"));
+    acceptClipboard.setSelected(UserPreferences.getBool("global",
+            "AcceptClipboard"));
+    sendClipboard.setSelected(UserPreferences.getBool("global",
+            "SendClipboard"));
     menuKey.setSelectedItem(UserPreferences.get("global", "MenuKey"));
-    desktopSize.setSelected(UserPreferences.get("global", "DesktopSize") != null);
+    desktopSize.setSelected(UserPreferences.get("global", "DesktopSize")
+            != null);
     if (desktopSize.isSelected()) {
       String desktopSizeString = UserPreferences.get("global", "DesktopSize");
       desktopWidth.setText(desktopSizeString.split("x")[0]);
       desktopHeight.setText(desktopSizeString.split("x")[1]);
     }
     fullScreen.setSelected(UserPreferences.getBool("global", "FullScreen"));
-    fullScreenAllMonitors.setSelected(UserPreferences.getBool("global", "FullScreenAllMonitors"));
+    fullScreenAllMonitors.setSelected(UserPreferences.getBool("global",
+            "FullScreenAllMonitors"));
     if (shared.isEnabled())
       shared.setSelected(UserPreferences.getBool("global", "Shared"));
-    useLocalCursor.setSelected(UserPreferences.getBool("global", "UseLocalCursor"));
+    useLocalCursor.setSelected(UserPreferences.getBool("global",
+            "UseLocalCursor"));
     acceptBell.setSelected(UserPreferences.getBool("global", "AcceptBell"));
     String scaleString = UserPreferences.get("global", "ScalingFactor");
     if (scaleString != null) {
@@ -473,14 +858,16 @@
       }
     }
     if (secVeNCrypt.isEnabled()) {
-      secVeNCrypt.setSelected(UserPreferences.getBool("viewer", "secVeNCrypt", true));
+      secVeNCrypt.setSelected(UserPreferences.getBool("viewer",
+              "secVeNCrypt", true));
       if (secVeNCrypt.isSelected()) {
         encNone.setSelected(UserPreferences.getBool("viewer", "encNone", true));
         encTLS.setSelected(UserPreferences.getBool("viewer", "encTLS", true));
         encX509.setSelected(UserPreferences.getBool("viewer", "encX509", true));
         secPlain.setSelected(UserPreferences.getBool("viewer", "secPlain", true));
         secIdent.setSelected(UserPreferences.getBool("viewer", "secIdent", true));
-        sendLocalUsername.setSelected(UserPreferences.getBool("global", "SendLocalUsername"));
+        sendLocalUsername.setSelected(UserPreferences.getBool("global",
+                "SendLocalUsername"));
       }
     }
     if (secNone.isEnabled())
@@ -489,44 +876,6 @@
       secVnc.setSelected(UserPreferences.getBool("viewer", "secVnc", true));
   }
 
-  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 endDialog() {
     super.endDialog();
     if (cc.viewport != null && cc.viewport.isVisible()) {
@@ -537,103 +886,126 @@
 
   public void actionPerformed(ActionEvent e) {
     Object s = e.getSource();
-    if (s instanceof JButton && (JButton)s == okButton) {
-      if (cc != null) cc.getOptions();
-      endDialog();
-    } else if (s instanceof JButton && (JButton)s == cancelButton) {
-      endDialog();
-    } else if (s instanceof JButton && (JButton)s == cfLoadButton) {
-      JFileChooser fc = new JFileChooser();
-      fc.setDialogTitle("Path to configuration file");
-      fc.setApproveButtonText("OK");
-      fc.setFileHidingEnabled(false);
-      int ret = fc.showOpenDialog(this);
-      if (ret == JFileChooser.APPROVE_OPTION) {
-        String filename = fc.getSelectedFile().toString();
-        if (filename != null)
-          Configuration.load(filename);
+    if (s instanceof JButton) {
+      JButton button = (JButton)s;
+      if (button == okButton) {
+        JTextField[] fields =
+          { x509ca, x509crl };
+        for (JTextField field : fields) {
+          if (field.getText() != null && !field.getText().equals("")) {
+            File f = new File(field.getText());
+            if (!f.exists() || !f.canRead()) {
+              String msg = new String("The file "+f.getAbsolutePath()+
+                           " specified for option "+field.getName()+
+                           " does not exist or cannot be read.  Please "+
+                           "correct before proceeding.");
+              JOptionPane.showMessageDialog(this, msg, "WARNING",
+                                            JOptionPane.WARNING_MESSAGE);
+              return;
+            }
+          }
+        }
+        if (cc != null) cc.getOptions();
+        endDialog();
+      } else if (button == cancelButton) {
+        endDialog();
+      } else if (button == cfLoadButton) {
+        JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle("Path to configuration file");
+        fc.setApproveButtonText("OK");
+        fc.setFileHidingEnabled(false);
+        int ret = fc.showOpenDialog(this);
+        if (ret == JFileChooser.APPROVE_OPTION) {
+          String filename = fc.getSelectedFile().toString();
+          if (filename != null)
+            Configuration.load(filename);
+          cc.setOptions();
+        }
+      } else if (button == cfSaveAsButton) {
+        JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle("Save current configuration as:");
+        fc.setApproveButtonText("OK");
+        fc.setFileHidingEnabled(false);
+        int ret = fc.showOpenDialog(this);
+        if (ret == JFileChooser.APPROVE_OPTION) {
+          String filename = fc.getSelectedFile().toString();
+          if (filename != null)
+            Configuration.save(filename);
+        }
+      } else if (button == defSaveButton) {
+        updatePreferences();
+        UserPreferences.save();
+      } else if (button == defReloadButton) {
+        restorePreferences();
+      } else if (button == defClearButton) {
+        UserPreferences.clear();
         cc.setOptions();
+      } else if (button == caButton) {
+        JFileChooser fc =
+          new JFileChooser(new File(CSecurityTLS.getDefaultCA()));
+        fc.setDialogTitle("Path to X509 CA certificate");
+        fc.setApproveButtonText("OK");
+        fc.setFileHidingEnabled(false);
+        int ret = fc.showOpenDialog(this);
+        if (ret == JFileChooser.APPROVE_OPTION)
+          x509ca.setText(fc.getSelectedFile().toString());
+      } else if (button == crlButton) {
+        JFileChooser fc =
+          new JFileChooser(new File(CSecurityTLS.getDefaultCRL()));
+        fc.setDialogTitle("Path to X509 CRL file");
+        fc.setApproveButtonText("OK");
+        fc.setFileHidingEnabled(false);
+        int ret = fc.showOpenDialog(this);
+        if (ret == JFileChooser.APPROVE_OPTION)
+          x509crl.setText(fc.getSelectedFile().toString());
       }
-    } else if (s instanceof JButton && (JButton)s == cfSaveAsButton) {
-      JFileChooser fc = new JFileChooser();
-      fc.setDialogTitle("Save current configuration as:");
-      fc.setApproveButtonText("OK");
-      fc.setFileHidingEnabled(false);
-      int ret = fc.showOpenDialog(this);
-      if (ret == JFileChooser.APPROVE_OPTION) {
-        String filename = fc.getSelectedFile().toString();
-        if (filename != null)
-          Configuration.save(filename);
-      }
-    } else if (s instanceof JButton && (JButton)s == defSaveButton) {
-      updatePreferences();
-      UserPreferences.save();
-    } else if (s instanceof JButton && (JButton)s == defReloadButton) {
-      restorePreferences();
-    } else if (s instanceof JButton && (JButton)s == defClearButton) {
-      UserPreferences.clear();
-      cc.setOptions();
-    } else if (s instanceof JButton && (JButton)s == ca) {
-      JFileChooser fc = new JFileChooser(new File(CSecurityTLS.getDefaultCA()));
-      fc.setDialogTitle("Path to X509 CA certificate");
-      fc.setApproveButtonText("OK");
-      fc.setFileHidingEnabled(false);
-      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(new File(CSecurityTLS.getDefaultCRL()));
-      fc.setDialogTitle("Path to X509 CRL file");
-      fc.setApproveButtonText("OK");
-      fc.setFileHidingEnabled(false);
-      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());
-    }
-    if (s instanceof JCheckBox && (JCheckBox)s == customCompressLevel) {
-      compressLevel.setEnabled(customCompressLevel.isSelected());
-    }
-    if (s instanceof JCheckBox && (JCheckBox)s == desktopSize) {
-      desktopWidth.setEnabled(desktopSize.isSelected());
-      desktopHeight.setEnabled(desktopSize.isSelected());
-    }
-    if (s instanceof JCheckBox && (JCheckBox)s == noJpeg) {
-      qualityLevel.setEnabled(noJpeg.isSelected());
-    }
-    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());
-      secPlain.setEnabled(secVeNCrypt.isSelected());
-      sendLocalUsername.setEnabled(secVeNCrypt.isSelected());
-    }
-    if (s instanceof JCheckBox && (JCheckBox)s == encNone) {
-      secNone.setSelected(encNone.isSelected() &&
-        UserPreferences.getBool("viewer", "secNone", true));
-      secVnc.setSelected(encNone.isSelected() &&
-        UserPreferences.getBool("viewer", "secVnc", true));
-    }
-    if (s instanceof JCheckBox && (JCheckBox)s == secIdent ||
-        s instanceof JCheckBox && (JCheckBox)s == secPlain) {
-      sendLocalUsername.setEnabled(secIdent.isSelected()||secPlain.isSelected());
+    if (s instanceof JCheckBox) {
+      JCheckBox item = (JCheckBox)s;
+      boolean enable = item.isSelected();
+      if (item == autoSelect) {
+        ButtonGroup[] groups = { encodingGroup, colourGroup };
+        for (ButtonGroup grp : groups) {
+          Enumeration<AbstractButton> elems = grp.getElements();
+          while (elems.hasMoreElements())
+            elems.nextElement().setEnabled(!enable);
+        }
+      } else if (item == customCompressLevel) {
+        compressLevel.setEnabled(enable);
+      } else if (item == desktopSize) {
+        desktopWidth.setEnabled(enable);
+        desktopHeight.setEnabled(enable);
+      } else if (item == noJpeg) {
+        qualityLevel.setEnabled(enable);
+      } else if (item == encX509) {
+        x509ca.setEnabled(enable);
+        x509crl.setEnabled(enable);
+        caButton.setEnabled(enable);
+        crlButton.setEnabled(enable);
+      } else if (item == secVeNCrypt) {
+        encNone.setEnabled(enable);
+        encTLS.setEnabled(enable);
+        encX509.setEnabled(enable);
+        x509ca.setEnabled(enable && encX509.isSelected());
+        x509crl.setEnabled(enable && encX509.isSelected());
+        caButton.setEnabled(enable && encX509.isSelected());
+        crlButton.setEnabled(enable && encX509.isSelected());
+        secIdent.setEnabled(enable);
+        secPlain.setEnabled(enable);
+        sendLocalUsername.setEnabled(enable);
+      } else if (item == encNone) {
+        secNone.setSelected(enable &&
+          UserPreferences.getBool("viewer", "secNone", true));
+        secVnc.setSelected(enable &&
+          UserPreferences.getBool("viewer", "secVnc", true));
+      } else if (item == secIdent || item == secPlain) {
+        sendLocalUsername.setEnabled(secIdent.isSelected() ||
+                                     secPlain.isSelected());
+      }
     }
   }
-
 }
diff --git a/java/com/tigervnc/vncviewer/PasswdDialog.java b/java/com/tigervnc/vncviewer/PasswdDialog.java
index edd9554..26a138d 100644
--- a/java/com/tigervnc/vncviewer/PasswdDialog.java
+++ b/java/com/tigervnc/vncviewer/PasswdDialog.java
@@ -22,13 +22,20 @@
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
-import com.jcraft.jsch.*;
 
-class PasswdDialog extends Dialog implements KeyListener,
-                                             UserInfo,
+import com.jcraft.jsch.*;
+import com.tigervnc.rfb.*;
+
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.LINE_START;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.REMAINDER;
+
+class PasswdDialog extends Dialog implements UserInfo,
                                              UIKeyboardInteractive {
 
-  public PasswdDialog(String title, boolean userDisabled, boolean passwdDisabled) {
+  public PasswdDialog(String title,
+                      boolean userDisabled, boolean passwdDisabled) {
     super(true);
     setResizable(false);
     setTitle(title);
@@ -38,28 +45,45 @@
       }
     });
 
-    JPanel p1 = new JPanel();
+    JPanel p1 = new JPanel(new GridBagLayout());
+    p1.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
     userLabel = new JLabel("Username:");
-    p1.add(userLabel);
+    userLabel.setEnabled(!userDisabled);
+    p1.add(userLabel, new GridBagConstraints(0, 0,
+                                             1, 1,
+                                             LIGHT, LIGHT,
+                                             LINE_START, NONE,
+                                             new Insets(0, 0, 0, 0),
+                                             NONE, NONE));
     userEntry = new JTextField(30);
     userEntry.setEnabled(!userDisabled);
-    userLabel.setEnabled(!userDisabled);
-    p1.add(userEntry);
-    userEntry.addKeyListener(this);
+    p1.add(userEntry, new GridBagConstraints(1, 0,
+                                             1, 1,
+                                             HEAVY, LIGHT,
+                                             LINE_START, REMAINDER,
+                                             new Insets(0, 5, 0, 0),
+                                             NONE, NONE));
 
-    JPanel p2 = new JPanel();
     passwdLabel = new JLabel("Password:");
-    passwdLabel.setPreferredSize(userLabel.getPreferredSize());
-    p2.add(passwdLabel);
+    passwdLabel.setEnabled(!passwdDisabled);
+    p1.add(passwdLabel, new GridBagConstraints(0, 1,
+                                               1, 1,
+                                               LIGHT, LIGHT,
+                                               LINE_START, NONE,
+                                               new Insets(5, 0, 0, 0),
+                                               NONE, NONE));
     passwdEntry = new JPasswordField(30);
     passwdEntry.setEnabled(!passwdDisabled);
-    passwdLabel.setEnabled(!passwdDisabled);
-    p2.add(passwdEntry);
-    passwdEntry.addKeyListener(this);
+    p1.add(passwdEntry, new GridBagConstraints(1, 1,
+                                               1, 1,
+                                               HEAVY, LIGHT,
+                                               LINE_START, REMAINDER,
+                                               new Insets(5, 5, 0, 0),
+                                               NONE, NONE));
 
-    getContentPane().setLayout(new BoxLayout(getContentPane(),BoxLayout.Y_AXIS));
-    getContentPane().add(p1);
-    getContentPane().add(p2);
+    this.add(p1);
+    addListeners(this);
     pack();
     if (userEntry.isEnabled()) {
       userEntry.requestFocus();
@@ -68,10 +92,6 @@
     }
   }
 
-  /** Handle the key-typed event. */
-  public void keyTyped(KeyEvent event) { }
-  /** Handle the key-released event. */
-  public void keyReleased(KeyEvent event) { }
   /** Handle the key-pressed event. */
   public void keyPressed(KeyEvent event) {
     Object s = event.getSource();
@@ -79,7 +99,8 @@
        if (event.getKeyCode() == KeyEvent.VK_ENTER) {
          endDialog();
         }
-    } else if (s instanceof JPasswordField && (JPasswordField)s == passwdEntry) {
+    } else if (s instanceof JPasswordField
+              && (JPasswordField)s == passwdEntry) {
         if (event.getKeyCode() == KeyEvent.VK_ENTER) {
          endDialog();
         }
@@ -89,81 +110,90 @@
   public String getPassword() {
     return new String(passwdEntry.getPassword());
   }
-  public String getPassphrase(){ return null; }
-  public boolean promptPassphrase(String message){ return false; }
-  public boolean promptPassword(String message){
+
+  public String getPassphrase() { return null; }
+  public boolean promptPassphrase(String message) { return false; }
+
+  public boolean promptPassword(String message) {
     setTitle(message);
     showDialog();
-    if (passwdEntry != null)
-      return true;
+    if (userEntry.isEnabled())
+      if (userEntry.getText().equals(""))
+        return false;
+    if (passwdEntry.isEnabled())
+      if (!passwdEntry.getText().equals(""))
+        return true;
     return false;
   }
-  public void showMessage(String message){
-    JOptionPane.showMessageDialog(null, message);
+
+  public void showMessage(String message) {
+    JOptionPane.showMessageDialog(null, message, "Message",
+                                  JOptionPane.PLAIN_MESSAGE);
   }
-  public boolean promptYesNo(String str){
-    Object[] options={ "yes", "no" };
-    int foo=JOptionPane.showOptionDialog(null,
+
+  public boolean promptYesNo(String str) {
+    Object[] options={ "YES", "NO" };
+    int ret=JOptionPane.showOptionDialog(null,
            str,
            "Warning",
            JOptionPane.DEFAULT_OPTION,
            JOptionPane.WARNING_MESSAGE,
            null, options, options[0]);
-     return foo==0;
+     return (ret == 0);
   }
+
   public String[] promptKeyboardInteractive(String destination,
                                             String name,
                                             String instruction,
                                             String[] prompt,
-                                            boolean[] echo){
-    Container panel = new JPanel();
-    panel.setLayout(new GridBagLayout());
+                                            boolean[] echo) {
+    vlog.info("OK");
+    Container panel = new JPanel(new GridBagLayout());
+    ((JPanel)panel).setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
-    GridBagConstraints gbc =
-      new GridBagConstraints(0,0,1,1,1,1,
-                             GridBagConstraints.NORTHWEST,
-                             GridBagConstraints.NONE,
-                             new Insets(0,0,0,0),0,0);
-    gbc.weightx = 1.0;
-    gbc.gridwidth = GridBagConstraints.REMAINDER;
-    gbc.gridx = 0;
-    panel.add(new JLabel(instruction), gbc);
-    gbc.gridy++;
-
-    gbc.gridwidth = GridBagConstraints.RELATIVE;
+    panel.add(new JLabel(instruction),
+              new GridBagConstraints(0, 0,
+                                     REMAINDER, 1,
+                                     LIGHT, LIGHT,
+                                     LINE_START, NONE,
+                                     new Insets(0, 0, 0, 0),
+                                     NONE, NONE));
 
     JTextField[] texts=new JTextField[prompt.length];
-    for(int i=0; i<prompt.length; i++){
-      gbc.fill = GridBagConstraints.NONE;
-      gbc.gridx = 0;
-      gbc.weightx = 1;
-      panel.add(new JLabel(prompt[i]),gbc);
+    for (int i = 0; i < prompt.length; i++) {
+      panel.add(new JLabel(prompt[i]),
+                new GridBagConstraints(0, i+1,
+                                       1, 1,
+                                       LIGHT, LIGHT,
+                                       LINE_START, NONE,
+                                       new Insets(5, 0, 0, 0),
+                                       NONE, NONE));
 
-      gbc.gridx = 1;
-      gbc.fill = GridBagConstraints.HORIZONTAL;
-      gbc.weighty = 1;
-      if(echo[i]){
+      if(echo[i])
         texts[i]=new JTextField(20);
-      }
-      else{
+      else
         texts[i]=new JPasswordField(20);
-      }
-      panel.add(texts[i], gbc);
-      gbc.gridy++;
+
+      panel.add(texts[i],
+                new GridBagConstraints(1, i+1,
+                                       1, 1,
+                                       HEAVY, LIGHT,
+                                       LINE_START, HORIZONTAL,
+                                       new Insets(5, 5, 0, 0),
+                                       NONE, NONE));
     }
 
-    if(JOptionPane.showConfirmDialog(null, panel,
-                                     destination+": "+name,
-                                     JOptionPane.OK_CANCEL_OPTION,
-                                     JOptionPane.QUESTION_MESSAGE)
-       ==JOptionPane.OK_OPTION){
+    if (JOptionPane.showConfirmDialog(null, panel,
+                                      destination+": "+name,
+                                      JOptionPane.OK_CANCEL_OPTION,
+                                      JOptionPane.QUESTION_MESSAGE)
+        == JOptionPane.OK_OPTION) {
       String[] response=new String[prompt.length];
       for(int i=0; i<prompt.length; i++){
         response[i]=texts[i].getText();
       }
-	return response;
-    }
-    else{
+	    return response;
+    } else{
       return null;  // cancel
     }
   }
@@ -172,4 +202,5 @@
   JTextField userEntry;
   JLabel passwdLabel;
   JPasswordField passwdEntry;
+  static LogWriter vlog = new LogWriter("PasswdDialog");
 }
diff --git a/java/com/tigervnc/vncviewer/ServerDialog.java b/java/com/tigervnc/vncviewer/ServerDialog.java
index 7b8ee0c..172bde6 100644
--- a/java/com/tigervnc/vncviewer/ServerDialog.java
+++ b/java/com/tigervnc/vncviewer/ServerDialog.java
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright (C) 2011-2013 Brian P. Hinz
+ * Copyright (C) 2011-2016 Brian P. Hinz
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,9 +28,12 @@
 
 import com.tigervnc.rfb.*;
 
-class ServerDialog extends Dialog implements
-                           ActionListener
-{
+import static java.awt.GridBagConstraints.HORIZONTAL;
+import static java.awt.GridBagConstraints.LINE_START;
+import static java.awt.GridBagConstraints.NONE;
+import static java.awt.GridBagConstraints.REMAINDER;
+
+class ServerDialog extends Dialog {
 
   @SuppressWarnings({"unchecked","rawtypes"})
   public ServerDialog(OptionsDialog options_,
@@ -39,9 +42,8 @@
     super(true);
     cc = cc_;
     setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
-    setResizable(false);
-    setSize(new Dimension(340, 135));
     setTitle("VNC Viewer: Connection Details");
+    setResizable(false);
     addWindowListener(new WindowAdapter() {
       public void windowClosing(WindowEvent e) {
         if (VncViewer.nViewers == 1) {
@@ -54,25 +56,14 @@
     });
 
     options = options_;
-    getContentPane().setLayout(new GridBagLayout());
 
-    JLabel serverLabel = new JLabel("Server:", JLabel.RIGHT);
-    if (UserPreferences.get("ServerDialog", "history") != null) {
-      String valueStr = UserPreferences.get("ServerDialog", "history");
-      server = new JComboBox(valueStr.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 if (UIManager.getLookAndFeel().getID() == "Metal") {
-      ComboBoxEditor editor = server.getEditor();
-      JTextField jtf = (JTextField)editor.getEditorComponent();
-      jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));
-    }
+    JLabel serverLabel = new JLabel("VNC Server:", JLabel.RIGHT);
+    String valueStr = new String("");
+    if (UserPreferences.get("ServerDialog", "history") != null)
+      valueStr = UserPreferences.get("ServerDialog", "history");
+    server = new MyJComboBox(valueStr.split(","));
+    if (valueStr.equals(""))
+      server.setPrototypeDisplayValue("255.255.255.255:5900");
 
     server.setEditable(true);
     editor = server.getEditor();
@@ -88,42 +79,50 @@
       }
     });
 
-    JPanel topPanel = new JPanel(new GridBagLayout());
+    Container contentPane = this.getContentPane();
+    contentPane.setLayout(new GridBagLayout());
 
-    addGBComponent(new JLabel(VncViewer.logoIcon),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));
-
+    JLabel icon = new JLabel(VncViewer.logoIcon);
     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);
-
+    contentPane.add(icon,
+                    new GridBagConstraints(0, 0,
+                                           1, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(5, 5, 5, 5),
+                                           NONE, NONE));
+    contentPane.add(serverLabel,
+                    new GridBagConstraints(1, 0,
+                                           1, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, NONE,
+                                           new Insets(5, 10, 5, 5),
+                                           NONE, NONE));
+    contentPane.add(server,
+                    new GridBagConstraints(2, 0,
+                                           REMAINDER, 1,
+                                           HEAVY, LIGHT,
+                                           LINE_START, HORIZONTAL,
+                                           new Insets(5, 0, 5, 5),
+                                           NONE, NONE));
+    JPanel buttonPane = new JPanel();
+    buttonPane.setLayout(new GridLayout(1, 4, 5, 5));
+    buttonPane.add(aboutButton);
+    buttonPane.add(optionsButton);
+    buttonPane.add(okButton);
+    buttonPane.add(cancelButton);
+    contentPane.add(buttonPane,
+                    new GridBagConstraints(0, 1,
+                                           REMAINDER, 1,
+                                           LIGHT, LIGHT,
+                                           LINE_START, HORIZONTAL,
+                                           new Insets(5, 5, 5, 5),
+                                           NONE, NONE));
+    addListeners(this);
     pack();
   }
 
@@ -160,12 +159,14 @@
     }
     // set params
     Configuration.setParam("Server", Hostname.getHost(serverName));
-    Configuration.setParam("Port", Integer.toString(Hostname.getPort(serverName)));
+    Configuration.setParam("Port",
+                            Integer.toString(Hostname.getPort(serverName)));
     // Update the history list
     String valueStr = UserPreferences.get("ServerDialog", "history");
     String t = (valueStr == null) ? "" : valueStr;
     StringTokenizer st = new StringTokenizer(t, ",");
-    StringBuffer sb = new StringBuffer().append((String)server.getSelectedItem());
+    StringBuffer sb =
+        new StringBuffer().append((String)server.getSelectedItem());
     while (st.hasMoreTokens()) {
       String str = st.nextToken();
       if (!str.equals((String)server.getSelectedItem()) && !str.equals("")) {
@@ -180,7 +181,7 @@
 
   CConn cc;
   @SuppressWarnings("rawtypes")
-  JComboBox server;
+  MyJComboBox server;
   ComboBoxEditor editor;
   JButton aboutButton, optionsButton, okButton, cancelButton;
   OptionsDialog options;
diff --git a/java/com/tigervnc/vncviewer/Viewport.java b/java/com/tigervnc/vncviewer/Viewport.java
index 3d01b25..b55744b 100644
--- a/java/com/tigervnc/vncviewer/Viewport.java
+++ b/java/com/tigervnc/vncviewer/Viewport.java
@@ -37,6 +37,11 @@
 import java.lang.Exception;
 import java.awt.Rectangle;
 
+import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER;
+import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER;
+import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
+import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
+
 public class Viewport extends JFrame
 {
   public Viewport(String name, CConn cc_) {
@@ -86,22 +91,24 @@
           if ((sp.getSize().width != cc.desktop.scaledWidth) ||
               (sp.getSize().height != cc.desktop.scaledHeight)) {
             cc.desktop.setScaledSize();
-            sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
-            sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
+            sp.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
+            sp.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
             sp.validate();
             if (getExtendedState() != JFrame.MAXIMIZED_BOTH &&
                 !cc.fullScreen) {
               sp.setSize(new Dimension(cc.desktop.scaledWidth,
                                        cc.desktop.scaledHeight));
-              int w = cc.desktop.scaledWidth + getInsets().left + getInsets().right;
-              int h = cc.desktop.scaledHeight + getInsets().top + getInsets().bottom;
+              int w = cc.desktop.scaledWidth + getInsets().left +
+                      getInsets().right;
+              int h = cc.desktop.scaledHeight + getInsets().top +
+                      getInsets().bottom;
               if (scaleString.equalsIgnoreCase("FixedRatio"))
                 setSize(w, h);
             }
           }
         } else {
-          sp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-          sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
+          sp.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
+          sp.setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
           sp.validate();
         }
         if (cc.desktop.cursor != null) {
diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java
index 0c54d79..078076f 100644
--- a/java/com/tigervnc/vncviewer/VncViewer.java
+++ b/java/com/tigervnc/vncviewer/VncViewer.java
@@ -657,7 +657,17 @@
                      "JPEG quality level. "+
                      "0 = Low, 9 = High",
                      8);
-
+  StringParameter x509ca
+  = new StringParameter("X509CA",
+    "Path to CA certificate to use when authenticating remote servers "+
+    "using any of the X509 security schemes (X509None, X509Vnc, etc.). "+
+    "Must be in PEM format.",
+    FileUtils.getHomeDir()+".vnc/x509_ca.pem");
+  StringParameter x509crl
+  = new StringParameter("X509CRL",
+    "Path to certificate revocation list to use in conjunction with "+
+    "-X509CA. Must also be in PEM format.",
+    FileUtils.getHomeDir()+".vnc/x509_crl.pem");
   StringParameter config
   = new StringParameter("config",
   "Specifies a configuration file to load.", null);
@@ -665,5 +675,5 @@
   Thread thread;
   Socket sock;
   static int nViewers;
-  static LogWriter vlog = new LogWriter("main");
+  static LogWriter vlog = new LogWriter("VncViewer");
 }