Selaa lähdekoodia

Merge branch 'ui-cleanup' of https://github.com/kanaka/noVNC

samhed 9 vuotta sitten
vanhempi
commit
5fd3f88e50
7 muutettua tiedostoa jossa 704 lisäystä ja 638 poistoa
  1. 0 0
      images/toggleextrakeys.png
  2. 32 31
      include/base.css
  3. 1 1
      include/black.css
  4. 1 1
      include/blue.css
  5. 2 0
      include/rfb.js
  6. 614 551
      include/ui.js
  7. 54 54
      vnc.html

+ 0 - 0
images/showextrakeys.png → images/toggleextrakeys.png


+ 32 - 31
include/base.css

@@ -1,7 +1,7 @@
 /*
  * noVNC base CSS
  * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 Samuel Mannehed for Cendio AB
+ * Copyright (C) 2016 Samuel Mannehed for Cendio AB
  * noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
  * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
  */
@@ -30,18 +30,18 @@ html {
   padding-bottom:8px;
 }
 
-#noVNC_host {
+#noVNC_setting_host {
   width:150px;
 }
-#noVNC_port {
+#noVNC_setting_port {
   width: 80px;
 }
-#noVNC_password {
+#noVNC_setting_password {
   width: 150px;
 }
-#noVNC_encrypt {
+#noVNC_setting_encrypt {
 }
-#noVNC_path {
+#noVNC_setting_path {
   width: 100px;
 }
 #noVNC_connect_button {
@@ -56,10 +56,10 @@ html {
 #noVNC_view_drag_button {
   display: none;
 }
-#sendCtrlAltDelButton {
+#noVNC_sendCtrlAltDel_button {
   display: none;
 }
-#fullscreenButton {
+#noVNC_fullscreen_button {
   display: none;
 }
 #noVNC_xvp_buttons {
@@ -77,13 +77,13 @@ html {
   position: relative;
 }
 
-.noVNC-buttons-left {
+.noVNC_buttons_left {
   float: left;
   z-index: 1;
   position: relative;
 }
 
-.noVNC-buttons-right {
+.noVNC_buttons_right {
   float:right;
   right: 0px;
   z-index: 2;
@@ -109,13 +109,11 @@ html {
   padding: 0px;
 }
 
-#noVNC_apply {
+#noVNC_settings_apply {
   float:right;
 }
 
-/* Do not set width/height for VNC_screen or VNC_canvas or incorrect
- * scaling will occur. Canvas resizes to remote VNC settings */
-#noVNC_screen {
+#noVNC_container {
   display: table;
   width:100%;
   height:100%;
@@ -124,7 +122,7 @@ html {
   /*border-top-left-radius: 800px 600px;*/
 }
 
-#noVNC_container {
+#noVNC_screen {
   display: none;
   position: absolute;
   margin: 0px;
@@ -137,6 +135,9 @@ html {
   height: auto;
 }
 
+/* Do not set width/height for VNC_canvas or incorrect
+ * scaling will occur. Canvas size depends on remote VNC
+ * settings and noVNC settings. */
 #noVNC_canvas {
   position: absolute;
   left: 0;
@@ -232,7 +233,7 @@ html {
   right:85px;
 }
 
-#keyboardinput {
+#noVNC_keyboardinput {
   width:1px;
   height:1px;
   background-color:#fff;
@@ -277,7 +278,7 @@ html {
 }
 
 /* Control bar */
-#noVNC-control-bar {
+#noVNC_control_bar {
   position:fixed;
   
   display:block;
@@ -426,11 +427,11 @@ html {
   font-size: 180px;
 }
 
-.noVNC-buttons-left {
+.noVNC_buttons_left {
   padding-left: 10px;
 }
 
-.noVNC-buttons-right {
+.noVNC_buttons_right {
   padding-right: 10px;
 }
 
@@ -441,11 +442,11 @@ html {
   margin-left: 0px;
 }
 
-#showExtraKeysButton { display: none; }
-#toggleCtrlButton { display: inline; }
-#toggleAltButton {  display: inline; }
-#sendTabButton { display: inline; }
-#sendEscButton { display: inline; }
+#noVNC_toggleExtraKeys_button { display: none; }
+#noVNC_toggleCtrl_button { display: inline; }
+#noVNC_toggleAlt_button {  display: inline; }
+#noVNC_sendTab_button { display: inline; }
+#noVNC_sendEsc_button { display: inline; }
 
 /* left-align the status text on lower resolutions */
 @media screen and (max-width: 800px){
@@ -468,35 +469,35 @@ html {
   .noVNC_status_button {
     font-size: 10px;
   }
-  .noVNC-buttons-left {
+  .noVNC_buttons_left {
     padding-left: 0px;
   }
-  .noVNC-buttons-right {
+  .noVNC_buttons_right {
     padding-right: 0px;
   }
   /* collapse the extra keys on lower resolutions */
-  #showExtraKeysButton {
+  #noVNC_toggleExtraKeys_button {
     display: inline;
   }
-  #toggleCtrlButton {
+  #noVNC_toggleCtrl_button {
     display: none;
     position: absolute;
     top: 30px;
     left: 0px;
   }
-  #toggleAltButton {
+  #noVNC_toggleAlt_button {
     display: none;
     position: absolute;
     top: 65px;
     left: 0px;
   }
-  #sendTabButton {
+  #noVNC_sendTab_button {
     display: none;
     position: absolute;
     top: 100px;
     left: 0px;
   }
-  #sendEscButton {
+  #noVNC_sendEsc_button {
     display: none;
     position: absolute;
     top: 135px;

+ 1 - 1
include/black.css

@@ -6,7 +6,7 @@
  * This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
  */
 
-#keyboardinput {
+#noVNC_keyboardinput {
   background-color:#000;
 }
 

+ 1 - 1
include/blue.css

@@ -58,7 +58,7 @@
   color:#fff;
 }
 
-#keyboardinput {
+#noVNC_keyboardinput {
   background-color:#04073d;
 }
 

+ 2 - 0
include/rfb.js

@@ -311,6 +311,8 @@ var RFB;
             this._sock.flush();
         },
 
+        // Requests a change of remote desktop size. This message is an extension
+        // and may only be sent if we have received an ExtendedDesktopSize message
         requestDesktopSize: function (width, height) {
             if (this._rfb_state !== "normal") { return; }
 

+ 614 - 551
include/ui.js

@@ -1,7 +1,7 @@
 /*
  * noVNC: HTML5 VNC client
  * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2015 Samuel Mannehed for Cendio AB
+ * Copyright (C) 2016 Samuel Mannehed for Cendio AB
  * Licensed under MPL 2.0 (see LICENSE.txt)
  *
  * See README.md for usage and integration instructions.
@@ -47,7 +47,7 @@ var UI;
 
         // Setup rfb object, load settings from browser storage, then call
         // UI.init to setup the UI/menus
-        load: function (callback) {
+        load: function(callback) {
             WebUtil.initSettings(UI.start, callback);
         },
 
@@ -60,13 +60,13 @@ var UI;
             var sheets = WebUtil.getStylesheets();
             var i;
             for (i = 0; i < sheets.length; i += 1) {
-                UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title);
+                UI.addOption($D('noVNC_setting_stylesheet'),sheets[i].title, sheets[i].title);
             }
 
             // Logging selection dropdown
             var llevels = ['error', 'warn', 'info', 'debug'];
             for (i = 0; i < llevels.length; i += 1) {
-                UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
+                UI.addOption($D('noVNC_setting_logging'),llevels[i], llevels[i]);
             }
 
             // Settings with immediate effects
@@ -114,7 +114,7 @@ var UI;
 
             UI.updateVisualState();
 
-            $D('noVNC_host').focus();
+            $D('noVNC_setting_host').focus();
 
             // Show mouse selector buttons on touch screen devices
             if (UI.isTouchDevice) {
@@ -132,7 +132,7 @@ var UI;
             UI.setBarPosition();
 
             Util.addEvent(window, 'resize', function () {
-                UI.onresize();
+                UI.applyResizeMode();
                 UI.setViewClip();
                 UI.updateViewDrag();
                 UI.setBarPosition();
@@ -148,7 +148,7 @@ var UI;
                  document.documentElement.mozRequestFullScreen ||
                  document.documentElement.webkitRequestFullscreen ||
                  document.body.msRequestFullscreen)) {
-                $D('fullscreenButton').style.display = "inline";
+                $D('noVNC_fullscreen_button').style.display = "inline";
                 Util.addEvent(window, 'fullscreenchange', UI.updateFullscreenButton);
                 Util.addEvent(window, 'mozfullscreenchange', UI.updateFullscreenButton);
                 Util.addEvent(window, 'webkitfullscreenchange', UI.updateFullscreenButton);
@@ -182,13 +182,13 @@ var UI;
             }
         },
 
-        initRFB: function () {
+        initRFB: function() {
             try {
                 UI.rfb = new RFB({'target': $D('noVNC_canvas'),
                                   'onUpdateState': UI.updateState,
-                                  'onXvpInit': UI.updateXvpVisualState,
-                                  'onClipboard': UI.clipReceive,
-                                  'onFBUComplete': UI.FBUComplete,
+                                  'onXvpInit': UI.updateXvpButton,
+                                  'onClipboard': UI.clipboardReceive,
+                                  'onFBUComplete': UI.initialResize,
                                   'onFBResize': UI.updateViewDrag,
                                   'onDesktopName': UI.updateDocumentTitle});
                 return true;
@@ -205,109 +205,194 @@ var UI;
             $D("noVNC_mouse_button1").onclick = function () { UI.setMouseButton(2); };
             $D("noVNC_mouse_button2").onclick = function () { UI.setMouseButton(4); };
             $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); };
-            $D("showKeyboard").onclick = UI.showKeyboard;
-
-            $D("keyboardinput").oninput = UI.keyInput;
-            $D("keyboardinput").onblur = UI.keyInputBlur;
-            $D("keyboardinput").onsubmit = function () { return false; };
-
-            $D("showExtraKeysButton").onclick = UI.showExtraKeys;
-            $D("toggleCtrlButton").onclick = UI.toggleCtrl;
-            $D("toggleAltButton").onclick = UI.toggleAlt;
-            $D("sendTabButton").onclick = UI.sendTab;
-            $D("sendEscButton").onclick = UI.sendEsc;
-
-            $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel;
-            $D("xvpShutdownButton").onclick = UI.xvpShutdown;
-            $D("xvpRebootButton").onclick = UI.xvpReboot;
-            $D("xvpResetButton").onclick = UI.xvpReset;
-            $D("noVNC_status").onclick = UI.togglePopupStatus;
-            $D("noVNC_popup_status").onclick = UI.togglePopupStatus;
-            $D("xvpButton").onclick = UI.toggleXvpPanel;
-            $D("clipboardButton").onclick = UI.toggleClipboardPanel;
-            $D("fullscreenButton").onclick = UI.toggleFullscreen;
-            $D("settingsButton").onclick = UI.toggleSettingsPanel;
-            $D("connectButton").onclick = UI.toggleConnectPanel;
-            $D("disconnectButton").onclick = UI.disconnect;
-            $D("descriptionButton").onclick = UI.toggleConnectPanel;
+            $D("noVNC_keyboard_button").onclick = UI.showKeyboard;
+
+            $D("noVNC_keyboardinput").oninput = UI.keyInput;
+            $D("noVNC_keyboardinput").onblur = UI.hideKeyboard;
+            $D("noVNC_keyboardinput").onsubmit = function () { return false; };
+
+            $D("noVNC_toggleExtraKeys_button").onclick = UI.toggleExtraKeys;
+            $D("noVNC_toggleCtrl_button").onclick = UI.toggleCtrl;
+            $D("noVNC_toggleAlt_button").onclick = UI.toggleAlt;
+            $D("noVNC_sendTab_button").onclick = UI.sendTab;
+            $D("noVNC_sendEsc_button").onclick = UI.sendEsc;
+
+            $D("noVNC_sendCtrlAltDel_button").onclick = UI.sendCtrlAltDel;
+            $D("noVNC_xvpShutdown_button").onclick = function() { UI.rfb.xvpShutdown(); },
+            $D("noVNC_xvpReboot_button").onclick = function() { UI.rfb.xvpReboot(); },
+            $D("noVNC_xvpReset_button").onclick = function() { UI.rfb.xvpReset(); },
+            $D("noVNC_status").onclick = UI.popupStatus;
+            $D("noVNC_popup_status").onclick = UI.closePopup;
+            $D("noVNC_toggleXvp_button").onclick = UI.toggleXvpPanel;
+            $D("noVNC_clipboard_button").onclick = UI.toggleClipboardPanel;
+            $D("noVNC_fullscreen_button").onclick = UI.toggleFullscreen;
+            $D("noVNC_settings_button").onclick = UI.toggleSettingsPanel;
+            $D("noVNC_connectPanel_button").onclick = UI.toggleConnectPanel;
+            $D("noVNC_disconnect_button").onclick = UI.disconnect;
+            $D("noVNC_description_button").onclick = UI.toggleConnectPanel;
 
             $D("noVNC_clipboard_text").onfocus = UI.displayBlur;
             $D("noVNC_clipboard_text").onblur = UI.displayFocus;
-            $D("noVNC_clipboard_text").onchange = UI.clipSend;
-            $D("noVNC_clipboard_clear_button").onclick = UI.clipClear;
+            $D("noVNC_clipboard_text").onchange = UI.clipboardSend;
+            $D("noVNC_clipboard_clear_button").onclick = UI.clipboardClear;
 
             $D("noVNC_settings_menu").onmouseover = UI.displayBlur;
             $D("noVNC_settings_menu").onmouseover = UI.displayFocus;
-            $D("noVNC_apply").onclick = UI.settingsApply;
+            $D("noVNC_settings_apply").onclick = UI.settingsApply;
 
             $D("noVNC_connect_button").onclick = UI.connect;
 
-            $D("noVNC_resize").onchange = UI.enableDisableViewClip;
+            $D("noVNC_setting_resize").onchange = UI.enableDisableViewClip;
         },
 
-        onresize: function (callback) {
-            if (!UI.rfb) return;
+/* ------^-------
+ *     /INIT
+ * ==============
+ *     VISUAL
+ * ------v------*/
 
-            var size = UI.getCanvasLimit();
+        updateState: function(rfb, state, oldstate, msg) {
+            UI.rfb_state = state;
+            var klass;
+            switch (state) {
+                case 'failed':
+                case 'fatal':
+                    klass = "noVNC_status_error";
+                    break;
+                case 'normal':
+                    klass = "noVNC_status_normal";
+                    break;
+                case 'disconnected':
+                    $D('noVNC_logo').style.display = "block";
+                    $D('noVNC_screen').style.display = "none";
+                    /* falls through */
+                case 'loaded':
+                    klass = "noVNC_status_normal";
+                    break;
+                case 'password':
+                    UI.toggleConnectPanel();
 
-            if (size && UI.rfb_state === 'normal' && UI.rfb.get_display()) {
-                var display = UI.rfb.get_display();
-                var scaleType = UI.getSetting('resize');
-                if (scaleType === 'remote') {
-                    // use remote resizing
+                    $D('noVNC_connect_button').value = "Send Password";
+                    $D('noVNC_connect_button').onclick = UI.setPassword;
+                    $D('noVNC_setting_password').focus();
 
-                    // When the local window has been resized, wait until the size remains
-                    // the same for 0.5 seconds before sending the request for changing
-                    // the resolution of the session
-                    clearTimeout(UI.resizeTimeout);
-                    UI.resizeTimeout = setTimeout(function(){
-                        display.set_maxWidth(size.w);
-                        display.set_maxHeight(size.h);
-                        Util.Debug('Attempting requestDesktopSize(' +
-                                   size.w + ', ' + size.h + ')');
-                        UI.rfb.requestDesktopSize(size.w, size.h);
-                    }, 500);
-                } else if (scaleType === 'scale' || scaleType === 'downscale') {
-                    // use local scaling
+                    klass = "noVNC_status_warn";
+                    break;
+                default:
+                    klass = "noVNC_status_warn";
+                    break;
+            }
 
-                    var downscaleOnly = scaleType === 'downscale';
-                    var scaleRatio = display.autoscale(size.w, size.h, downscaleOnly);
-                    UI.rfb.get_mouse().set_scale(scaleRatio);
-                    Util.Debug('Scaling by ' + UI.rfb.get_mouse().get_scale());
-                }
+            if (typeof(msg) !== 'undefined') {
+                $D('noVNC_control_bar').setAttribute("class", klass);
+                $D('noVNC_status').innerHTML = msg;
             }
+
+            UI.updateVisualState();
         },
 
-        getCanvasLimit: function () {
-            var container = $D('noVNC_container');
+        // Disable/enable controls depending on connection state
+        updateVisualState: function() {
+            var connected = UI.rfb && UI.rfb_state === 'normal';
 
-            // Hide the scrollbars until the size is calculated
-            container.style.overflow = "hidden";
+            //Util.Debug(">> updateVisualState");
+            $D('noVNC_setting_encrypt').disabled = connected;
+            $D('noVNC_setting_true_color').disabled = connected;
+            if (Util.browserSupportsCursorURIs()) {
+                $D('noVNC_setting_cursor').disabled = connected;
+            } else {
+                UI.updateSetting('cursor', !UI.isTouchDevice);
+                $D('noVNC_setting_cursor').disabled = true;
+            }
 
-            var pos = Util.getPosition(container);
-            var w = pos.width;
-            var h = pos.height;
+            UI.enableDisableViewClip();
+            $D('noVNC_setting_resize').disabled = connected;
+            $D('noVNC_setting_shared').disabled = connected;
+            $D('noVNC_setting_view_only').disabled = connected;
+            $D('noVNC_setting_path').disabled = connected;
+            $D('noVNC_setting_repeaterID').disabled = connected;
 
-            container.style.overflow = "visible";
+            if (connected) {
+                UI.setViewClip();
+                UI.setMouseButton(1);
+                $D('noVNC_clipboard_button').style.display = "inline";
+                $D('noVNC_keyboard_button').style.display = "inline";
+                $D('noVNC_extra_keys').style.display = "";
+                $D('noVNC_sendCtrlAltDel_button').style.display = "inline";
+            } else {
+                UI.setMouseButton();
+                $D('noVNC_clipboard_button').style.display = "none";
+                $D('noVNC_keyboard_button').style.display = "none";
+                $D('noVNC_extra_keys').style.display = "none";
+                $D('noVNC_sendCtrlAltDel_button').style.display = "none";
+                UI.updateXvpButton(0);
+            }
 
-            if (isNaN(w) || isNaN(h)) {
-                return false;
+            // State change disables viewport dragging.
+            // It is enabled (toggled) by direct click on the button
+            UI.updateViewDrag(false);
+
+            switch (UI.rfb_state) {
+                case 'fatal':
+                case 'failed':
+                case 'disconnected':
+                    $D('noVNC_connectPanel_button').style.display = "";
+                    $D('noVNC_disconnect_button').style.display = "none";
+                    UI.connSettingsOpen = false;
+                    UI.toggleConnectPanel();
+                    break;
+                case 'loaded':
+                    $D('noVNC_connectPanel_button').style.display = "";
+                    $D('noVNC_disconnect_button').style.display = "none";
+                    break;
+                default:
+                    $D('noVNC_connectPanel_button').style.display = "none";
+                    $D('noVNC_disconnect_button').style.display = "";
+                    break;
+            }
+
+            //Util.Debug("<< updateVisualState");
+        },
+
+        popupStatus: function(text) {
+            var psp = $D('noVNC_popup_status');
+
+            clearTimeout(UI.popupStatusTimeout);
+
+            if (typeof text === 'string') {
+                psp.innerHTML = text;
             } else {
-                return {w: w, h: h};
+                psp.innerHTML = $D('noVNC_status').innerHTML;
             }
+            psp.style.display = "block";
+            psp.style.left = window.innerWidth/2 -
+                parseInt(window.getComputedStyle(psp).width)/2 -30 + "px";
+
+            // Show the popup for a maximum of 1.5 seconds
+            UI.popupStatusTimeout = setTimeout(function() {
+                UI.closePopup();
+            }, 1500);
         },
 
-        // Read form control compatible setting from cookie
-        getSetting: function(name) {
-            var ctrl = $D('noVNC_' + name);
-            var val = WebUtil.readSetting(name);
-            if (typeof val !== 'undefined' && val !== null && ctrl.type === 'checkbox') {
-                if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
-                    val = false;
-                } else {
-                    val = true;
-                }
+        closePopup: function() {
+            clearTimeout(UI.popupStatusTimeout);
+            $D('noVNC_popup_status').style.display = "none";
+        },
+
+/* ------^-------
+ *    /VISUAL
+ * ==============
+ *    SETTINGS
+ * ------v------*/
+
+        // Initial page load read/initialization of settings
+        initSetting: function(name, defVal) {
+            // Check Query string followed by cookie
+            var val = WebUtil.getConfigVar(name);
+            if (val === null) {
+                val = WebUtil.readSetting(name, defVal);
             }
+            UI.updateSetting(name, val);
             return val;
         },
 
@@ -323,7 +408,7 @@ var UI;
             // Update the settings control
             value = UI.getSetting(name);
 
-            var ctrl = $D('noVNC_' + name);
+            var ctrl = $D('noVNC_setting_' + name);
             if (ctrl.type === 'checkbox') {
                 ctrl.checked = value;
 
@@ -346,7 +431,7 @@ var UI;
 
         // Save control setting to cookie
         saveSetting: function(name) {
-            var val, ctrl = $D('noVNC_' + name);
+            var val, ctrl = $D('noVNC_setting_' + name);
             if (ctrl.type === 'checkbox') {
                 val = ctrl.checked;
             } else if (typeof ctrl.options !== 'undefined') {
@@ -359,181 +444,83 @@ var UI;
             return val;
         },
 
-        // Initial page load read/initialization of settings
-        initSetting: function(name, defVal) {
-            // Check Query string followed by cookie
-            var val = WebUtil.getConfigVar(name);
-            if (val === null) {
-                val = WebUtil.readSetting(name, defVal);
-            }
-            UI.updateSetting(name, val);
-            return val;
-        },
-
         // Force a setting to be a certain value
         forceSetting: function(name, val) {
             UI.updateSetting(name, val);
             return val;
         },
 
-
-        // Show the popup status
-        togglePopupStatus: function(text) {
-            var psp = $D('noVNC_popup_status');
-
-            var closePopup = function() { psp.style.display = "none"; };
-
-            if (window.getComputedStyle(psp).display === 'none') {
-                if (typeof text === 'string') {
-                    psp.innerHTML = text;
+        // Read form control compatible setting from cookie
+        getSetting: function(name) {
+            var ctrl = $D('noVNC_setting_' + name);
+            var val = WebUtil.readSetting(name);
+            if (typeof val !== 'undefined' && val !== null && ctrl.type === 'checkbox') {
+                if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
+                    val = false;
                 } else {
-                    psp.innerHTML = $D('noVNC_status').innerHTML;
+                    val = true;
                 }
-                psp.style.display = "block";
-                psp.style.left = window.innerWidth/2 -
-                    parseInt(window.getComputedStyle(psp).width)/2 -30 + "px";
-
-                // Show the popup for a maximum of 1.5 seconds
-                UI.popupStatusTimeout = setTimeout(function() { closePopup(); }, 1500);
-            } else {
-                clearTimeout(UI.popupStatusTimeout);
-                closePopup();
             }
+            return val;
         },
 
-        // Show the XVP panel
-        toggleXvpPanel: function() {
-            // Close the description panel
-            $D('noVNC_description').style.display = "none";
-            // Close settings if open
-            if (UI.settingsOpen === true) {
-                UI.settingsApply();
-                UI.closeSettingsMenu();
-            }
-            // Close connection settings if open
-            if (UI.connSettingsOpen === true) {
-                UI.toggleConnectPanel();
-            }
-            // Close clipboard panel if open
-            if (UI.clipboardOpen === true) {
-                UI.toggleClipboardPanel();
-            }
-            // Toggle XVP panel
-            if (UI.xvpOpen === true) {
-                $D('noVNC_xvp').style.display = "none";
-                $D('xvpButton').className = "noVNC_status_button";
-                UI.xvpOpen = false;
-            } else {
-                $D('noVNC_xvp').style.display = "block";
-                $D('xvpButton').className = "noVNC_status_button_selected";
-                UI.xvpOpen = true;
+        // Save/apply settings when 'Apply' button is pressed
+        settingsApply: function() {
+            //Util.Debug(">> settingsApply");
+            UI.saveSetting('encrypt');
+            UI.saveSetting('true_color');
+            if (Util.browserSupportsCursorURIs()) {
+                UI.saveSetting('cursor');
             }
-        },
 
-        // Show the clipboard panel
-        toggleClipboardPanel: function() {
-            // Close the description panel
-            $D('noVNC_description').style.display = "none";
-            // Close settings if open
-            if (UI.settingsOpen === true) {
-                UI.settingsApply();
-                UI.closeSettingsMenu();
-            }
-            // Close connection settings if open
-            if (UI.connSettingsOpen === true) {
-                UI.toggleConnectPanel();
-            }
-            // Close XVP panel if open
-            if (UI.xvpOpen === true) {
-                UI.toggleXvpPanel();
-            }
-            // Toggle Clipboard Panel
-            if (UI.clipboardOpen === true) {
-                $D('noVNC_clipboard').style.display = "none";
-                $D('clipboardButton').className = "noVNC_status_button";
-                UI.clipboardOpen = false;
-            } else {
-                $D('noVNC_clipboard').style.display = "block";
-                $D('clipboardButton').className = "noVNC_status_button_selected";
-                UI.clipboardOpen = true;
-            }
-        },
+            UI.saveSetting('resize');
 
-        // Toggle fullscreen mode
-        toggleFullscreen: function() {
-            if (document.fullscreenElement || // alternative standard method
-                document.mozFullScreenElement || // currently working methods
-                document.webkitFullscreenElement ||
-                document.msFullscreenElement) {
-                if (document.exitFullscreen) {
-                    document.exitFullscreen();
-                } else if (document.mozCancelFullScreen) {
-                    document.mozCancelFullScreen();
-                } else if (document.webkitExitFullscreen) {
-                    document.webkitExitFullscreen();
-                } else if (document.msExitFullscreen) {
-                    document.msExitFullscreen();
-                }
-            } else {
-                if (document.documentElement.requestFullscreen) {
-                    document.documentElement.requestFullscreen();
-                } else if (document.documentElement.mozRequestFullScreen) {
-                    document.documentElement.mozRequestFullScreen();
-                } else if (document.documentElement.webkitRequestFullscreen) {
-                    document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
-                } else if (document.body.msRequestFullscreen) {
-                    document.body.msRequestFullscreen();
-                }
+            if (UI.getSetting('resize') === 'downscale' || UI.getSetting('resize') === 'scale') {
+                UI.forceSetting('clip', false);
             }
-            UI.enableDisableViewClip();
-            UI.updateFullscreenButton();
-        },
 
-        updateFullscreenButton: function() {
-            if (document.fullscreenElement || // alternative standard method
-                document.mozFullScreenElement || // currently working methods
-                document.webkitFullscreenElement ||
-                document.msFullscreenElement ) {
-                $D('fullscreenButton').className = "noVNC_status_button_selected";
-            } else {
-                $D('fullscreenButton').className = "noVNC_status_button";
-            }
+            UI.saveSetting('clip');
+            UI.saveSetting('shared');
+            UI.saveSetting('view_only');
+            UI.saveSetting('path');
+            UI.saveSetting('repeaterID');
+            UI.saveSetting('stylesheet');
+            UI.saveSetting('logging');
+
+            // Settings with immediate (non-connected related) effect
+            WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
+            WebUtil.init_logging(UI.getSetting('logging'));
+            UI.setViewClip();
+            UI.updateViewDrag();
+            //Util.Debug("<< settingsApply");
         },
 
-        // Show the connection settings panel/menu
-        toggleConnectPanel: function() {
+        // Open menu
+        openSettingsMenu: function() {
             // Close the description panel
             $D('noVNC_description').style.display = "none";
-            // Close connection settings if open
-            if (UI.settingsOpen === true) {
-                UI.settingsApply();
-                UI.closeSettingsMenu();
-                $D('connectButton').className = "noVNC_status_button";
-            }
             // Close clipboard panel if open
             if (UI.clipboardOpen === true) {
                 UI.toggleClipboardPanel();
             }
+            // Close connection settings if open
+            if (UI.connSettingsOpen === true) {
+                UI.toggleConnectPanel();
+            }
             // Close XVP panel if open
             if (UI.xvpOpen === true) {
                 UI.toggleXvpPanel();
             }
+            $D('noVNC_settings').style.display = "block";
+            $D('noVNC_settings_button').className = "noVNC_status_button_selected";
+            UI.settingsOpen = true;
+        },
 
-            // Toggle Connection Panel
-            if (UI.connSettingsOpen === true) {
-                $D('noVNC_controls').style.display = "none";
-                $D('connectButton').className = "noVNC_status_button";
-                UI.connSettingsOpen = false;
-                UI.saveSetting('host');
-                UI.saveSetting('port');
-                UI.saveSetting('token');
-                //UI.saveSetting('password');
-            } else {
-                $D('noVNC_controls').style.display = "block";
-                $D('connectButton').className = "noVNC_status_button_selected";
-                UI.connSettingsOpen = true;
-                $D('noVNC_host').focus();
-            }
+        // Close menu (without applying settings)
+        closeSettingsMenu: function() {
+            $D('noVNC_settings').style.display = "none";
+            $D('noVNC_settings_button').className = "noVNC_status_button";
+            UI.settingsOpen = false;
         },
 
         // Toggle the settings menu:
@@ -552,7 +539,7 @@ var UI;
                     UI.updateSetting('cursor');
                 } else {
                     UI.updateSetting('cursor', !UI.isTouchDevice);
-                    $D('noVNC_cursor').disabled = true;
+                    $D('noVNC_setting_cursor').disabled = true;
                 }
                 UI.updateSetting('clip');
                 UI.updateSetting('resize');
@@ -567,222 +554,47 @@ var UI;
             }
         },
 
-        // Open menu
-        openSettingsMenu: function() {
+/* ------^-------
+ *   /SETTINGS
+ * ==============
+ *      XVP
+ * ------v------*/
+
+        // Show the XVP panel
+        toggleXvpPanel: function() {
             // Close the description panel
             $D('noVNC_description').style.display = "none";
-            // Close clipboard panel if open
-            if (UI.clipboardOpen === true) {
-                UI.toggleClipboardPanel();
+            // Close settings if open
+            if (UI.settingsOpen === true) {
+                UI.settingsApply();
+                UI.closeSettingsMenu();
             }
             // Close connection settings if open
             if (UI.connSettingsOpen === true) {
                 UI.toggleConnectPanel();
             }
-            // Close XVP panel if open
-            if (UI.xvpOpen === true) {
-                UI.toggleXvpPanel();
-            }
-            $D('noVNC_settings').style.display = "block";
-            $D('settingsButton').className = "noVNC_status_button_selected";
-            UI.settingsOpen = true;
-        },
-
-        // Close menu (without applying settings)
-        closeSettingsMenu: function() {
-            $D('noVNC_settings').style.display = "none";
-            $D('settingsButton').className = "noVNC_status_button";
-            UI.settingsOpen = false;
-        },
-
-        // Save/apply settings when 'Apply' button is pressed
-        settingsApply: function() {
-            //Util.Debug(">> settingsApply");
-            UI.saveSetting('encrypt');
-            UI.saveSetting('true_color');
-            if (Util.browserSupportsCursorURIs()) {
-                UI.saveSetting('cursor');
-            }
-
-            UI.saveSetting('resize');
-
-            if (UI.getSetting('resize') === 'downscale' || UI.getSetting('resize') === 'scale') {
-                UI.forceSetting('clip', false);
-            }
-
-            UI.saveSetting('clip');
-            UI.saveSetting('shared');
-            UI.saveSetting('view_only');
-            UI.saveSetting('path');
-            UI.saveSetting('repeaterID');
-            UI.saveSetting('stylesheet');
-            UI.saveSetting('logging');
-
-            // Settings with immediate (non-connected related) effect
-            WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
-            WebUtil.init_logging(UI.getSetting('logging'));
-            UI.setViewClip();
-            UI.updateViewDrag();
-            //Util.Debug("<< settingsApply");
-        },
-
-
-
-        setPassword: function() {
-            UI.rfb.sendPassword($D('noVNC_password').value);
-            //Reset connect button.
-            $D('noVNC_connect_button').value = "Connect";
-            $D('noVNC_connect_button').onclick = UI.connect;
-            //Hide connection panel.
-            UI.toggleConnectPanel();
-            return false;
-        },
-
-        sendCtrlAltDel: function() {
-            UI.rfb.sendCtrlAltDel();
-        },
-
-        xvpShutdown: function() {
-            UI.rfb.xvpShutdown();
-        },
-
-        xvpReboot: function() {
-            UI.rfb.xvpReboot();
-        },
-
-        xvpReset: function() {
-            UI.rfb.xvpReset();
-        },
-
-        setMouseButton: function(num) {
-            if (typeof num === 'undefined') {
-                // Disable mouse buttons
-                num = -1;
-            }
-            if (UI.rfb) {
-                UI.rfb.get_mouse().set_touchButton(num);
-            }
-
-            var blist = [0, 1,2,4];
-            for (var b = 0; b < blist.length; b++) {
-                var button = $D('noVNC_mouse_button' + blist[b]);
-                if (blist[b] === num) {
-                    button.style.display = "";
-                } else {
-                    button.style.display = "none";
-                }
-            }
-        },
-
-        updateState: function(rfb, state, oldstate, msg) {
-            UI.rfb_state = state;
-            var klass;
-            switch (state) {
-                case 'failed':
-                case 'fatal':
-                    klass = "noVNC_status_error";
-                    break;
-                case 'normal':
-                    klass = "noVNC_status_normal";
-                    break;
-                case 'disconnected':
-                    $D('noVNC_logo').style.display = "block";
-                    $D('noVNC_container').style.display = "none";
-                    /* falls through */
-                case 'loaded':
-                    klass = "noVNC_status_normal";
-                    break;
-                case 'password':
-                    UI.toggleConnectPanel();
-
-                    $D('noVNC_connect_button').value = "Send Password";
-                    $D('noVNC_connect_button').onclick = UI.setPassword;
-                    $D('noVNC_password').focus();
-
-                    klass = "noVNC_status_warn";
-                    break;
-                default:
-                    klass = "noVNC_status_warn";
-                    break;
-            }
-
-            if (typeof(msg) !== 'undefined') {
-                $D('noVNC-control-bar').setAttribute("class", klass);
-                $D('noVNC_status').innerHTML = msg;
-            }
-
-            UI.updateVisualState();
-        },
-
-        // Disable/enable controls depending on connection state
-        updateVisualState: function() {
-            var connected = UI.rfb && UI.rfb_state === 'normal';
-
-            //Util.Debug(">> updateVisualState");
-            $D('noVNC_encrypt').disabled = connected;
-            $D('noVNC_true_color').disabled = connected;
-            if (Util.browserSupportsCursorURIs()) {
-                $D('noVNC_cursor').disabled = connected;
-            } else {
-                UI.updateSetting('cursor', !UI.isTouchDevice);
-                $D('noVNC_cursor').disabled = true;
-            }
-
-            UI.enableDisableViewClip();
-            $D('noVNC_resize').disabled = connected;
-            $D('noVNC_shared').disabled = connected;
-            $D('noVNC_view_only').disabled = connected;
-            $D('noVNC_path').disabled = connected;
-            $D('noVNC_repeaterID').disabled = connected;
-
-            if (connected) {
-                UI.setViewClip();
-                UI.setMouseButton(1);
-                $D('clipboardButton').style.display = "inline";
-                $D('showKeyboard').style.display = "inline";
-                $D('noVNC_extra_keys').style.display = "";
-                $D('sendCtrlAltDelButton').style.display = "inline";
-            } else {
-                UI.setMouseButton();
-                $D('clipboardButton').style.display = "none";
-                $D('showKeyboard').style.display = "none";
-                $D('noVNC_extra_keys').style.display = "none";
-                $D('sendCtrlAltDelButton').style.display = "none";
-                UI.updateXvpVisualState(0);
+            // Close clipboard panel if open
+            if (UI.clipboardOpen === true) {
+                UI.toggleClipboardPanel();
             }
-
-            // State change disables viewport dragging.
-            // It is enabled (toggled) by direct click on the button
-            UI.updateViewDrag(false);
-
-            switch (UI.rfb_state) {
-                case 'fatal':
-                case 'failed':
-                case 'disconnected':
-                    $D('connectButton').style.display = "";
-                    $D('disconnectButton').style.display = "none";
-                    UI.connSettingsOpen = false;
-                    UI.toggleConnectPanel();
-                    break;
-                case 'loaded':
-                    $D('connectButton').style.display = "";
-                    $D('disconnectButton').style.display = "none";
-                    break;
-                default:
-                    $D('connectButton').style.display = "none";
-                    $D('disconnectButton').style.display = "";
-                    break;
+            // Toggle XVP panel
+            if (UI.xvpOpen === true) {
+                $D('noVNC_xvp').style.display = "none";
+                $D('noVNC_toggleXvp_button').className = "noVNC_status_button";
+                UI.xvpOpen = false;
+            } else {
+                $D('noVNC_xvp').style.display = "block";
+                $D('noVNC_toggleXvp_button').className = "noVNC_status_button_selected";
+                UI.xvpOpen = true;
             }
-
-            //Util.Debug("<< updateVisualState");
         },
 
         // Disable/enable XVP button
-        updateXvpVisualState: function(ver) {
+        updateXvpButton: function(ver) {
             if (ver >= 1) {
-                $D('xvpButton').style.display = 'inline';
+                $D('noVNC_toggleXvp_button').style.display = 'inline';
             } else {
-                $D('xvpButton').style.display = 'none';
+                $D('noVNC_toggleXvp_button').style.display = 'none';
                 // Close XVP panel if open
                 if (UI.xvpOpen === true) {
                     UI.toggleXvpPanel();
@@ -790,36 +602,110 @@ var UI;
             }
         },
 
-        // This resize can not be done until we know from the first Frame Buffer Update
-        // if it is supported or not.
-        // The resize is needed to make sure the server desktop size is updated to the
-        // corresponding size of the current local window when reconnecting to an
-        // existing session.
-        FBUComplete: function(rfb, fbu) {
-            UI.onresize();
-            UI.rfb.set_onFBUComplete(function() { });
-        },
+/* ------^-------
+ *     /XVP
+ * ==============
+ *   CLIPBOARD
+ * ------v------*/
 
-        // Display the desktop name in the document title
-        updateDocumentTitle: function(rfb, name) {
-            document.title = name + " - noVNC";
+        // Show the clipboard panel
+        toggleClipboardPanel: function() {
+            // Close the description panel
+            $D('noVNC_description').style.display = "none";
+            // Close settings if open
+            if (UI.settingsOpen === true) {
+                UI.settingsApply();
+                UI.closeSettingsMenu();
+            }
+            // Close connection settings if open
+            if (UI.connSettingsOpen === true) {
+                UI.toggleConnectPanel();
+            }
+            // Close XVP panel if open
+            if (UI.xvpOpen === true) {
+                UI.toggleXvpPanel();
+            }
+            // Toggle Clipboard Panel
+            if (UI.clipboardOpen === true) {
+                $D('noVNC_clipboard').style.display = "none";
+                $D('noVNC_clipboard_button').className = "noVNC_status_button";
+                UI.clipboardOpen = false;
+            } else {
+                $D('noVNC_clipboard').style.display = "block";
+                $D('noVNC_clipboard_button').className = "noVNC_status_button_selected";
+                UI.clipboardOpen = true;
+            }
         },
 
-        clipReceive: function(rfb, text) {
-            Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "...");
+        clipboardReceive: function(rfb, text) {
+            Util.Debug(">> UI.clipboardReceive: " + text.substr(0,40) + "...");
             $D('noVNC_clipboard_text').value = text;
-            Util.Debug("<< UI.clipReceive");
+            Util.Debug("<< UI.clipboardReceive");
+        },
+
+        clipboardClear: function() {
+            $D('noVNC_clipboard_text').value = "";
+            UI.rfb.clipboardPasteFrom("");
+        },
+
+        clipboardSend: function() {
+            var text = $D('noVNC_clipboard_text').value;
+            Util.Debug(">> UI.clipboardSend: " + text.substr(0,40) + "...");
+            UI.rfb.clipboardPasteFrom(text);
+            Util.Debug("<< UI.clipboardSend");
+        },
+
+/* ------^-------
+ *  /CLIPBOARD
+ * ==============
+ *  CONNECTION
+ * ------v------*/
+
+        // Show the connection settings panel/menu
+        toggleConnectPanel: function() {
+            // Close the description panel
+            $D('noVNC_description').style.display = "none";
+            // Close connection settings if open
+            if (UI.settingsOpen === true) {
+                UI.settingsApply();
+                UI.closeSettingsMenu();
+                $D('noVNC_connectPanel_button').className = "noVNC_status_button";
+            }
+            // Close clipboard panel if open
+            if (UI.clipboardOpen === true) {
+                UI.toggleClipboardPanel();
+            }
+            // Close XVP panel if open
+            if (UI.xvpOpen === true) {
+                UI.toggleXvpPanel();
+            }
+
+            // Toggle Connection Panel
+            if (UI.connSettingsOpen === true) {
+                $D('noVNC_controls').style.display = "none";
+                $D('noVNC_connectPanel_button').className = "noVNC_status_button";
+                UI.connSettingsOpen = false;
+                UI.saveSetting('host');
+                UI.saveSetting('port');
+                UI.saveSetting('token');
+                //UI.saveSetting('password');
+            } else {
+                $D('noVNC_controls').style.display = "block";
+                $D('noVNC_connectPanel_button').className = "noVNC_status_button_selected";
+                UI.connSettingsOpen = true;
+                $D('noVNC_setting_host').focus();
+            }
         },
 
         connect: function() {
             UI.closeSettingsMenu();
             UI.toggleConnectPanel();
 
-            var host = $D('noVNC_host').value;
-            var port = $D('noVNC_port').value;
-            var password = $D('noVNC_password').value;
-            var token = $D('noVNC_token').value;
-            var path = $D('noVNC_path').value;
+            var host = $D('noVNC_setting_host').value;
+            var port = $D('noVNC_setting_port').value;
+            var password = $D('noVNC_setting_password').value;
+            var token = $D('noVNC_setting_token').value;
+            var path = $D('noVNC_setting_path').value;
 
             //if token is in path then ignore the new token variable
             if (token) {
@@ -842,9 +728,9 @@ var UI;
             UI.rfb.connect(host, port, password, path);
 
             //Close dialog.
-            setTimeout(UI.setBarPosition, 100);
+            setTimeout(function () { UI.setBarPosition; } );
             $D('noVNC_logo').style.display = "none";
-            $D('noVNC_container').style.display = "inline";
+            $D('noVNC_screen').style.display = "inline";
         },
 
         disconnect: function() {
@@ -852,40 +738,156 @@ var UI;
             UI.rfb.disconnect();
 
             // Restore the callback used for initial resize
-            UI.rfb.set_onFBUComplete(UI.FBUComplete);
+            UI.rfb.set_onFBUComplete(UI.initialResize);
 
             $D('noVNC_logo').style.display = "block";
-            $D('noVNC_container').style.display = "none";
+            $D('noVNC_screen').style.display = "none";
 
             // Don't display the connection settings until we're actually disconnected
         },
 
-        displayBlur: function() {
-            if (!UI.rfb) return;
+        setPassword: function() {
+            UI.rfb.sendPassword($D('noVNC_setting_password').value);
+            //Reset connect button.
+            $D('noVNC_connect_button').value = "Connect";
+            $D('noVNC_connect_button').onclick = UI.connect;
+            //Hide connection panel.
+            UI.toggleConnectPanel();
+            return false;
+        },
 
-            UI.rfb.get_keyboard().set_focused(false);
-            UI.rfb.get_mouse().set_focused(false);
+/* ------^-------
+ *  /CONNECTION
+ * ==============
+ *   FULLSCREEN
+ * ------v------*/
+
+        toggleFullscreen: function() {
+            if (document.fullscreenElement || // alternative standard method
+                document.mozFullScreenElement || // currently working methods
+                document.webkitFullscreenElement ||
+                document.msFullscreenElement) {
+                if (document.exitFullscreen) {
+                    document.exitFullscreen();
+                } else if (document.mozCancelFullScreen) {
+                    document.mozCancelFullScreen();
+                } else if (document.webkitExitFullscreen) {
+                    document.webkitExitFullscreen();
+                } else if (document.msExitFullscreen) {
+                    document.msExitFullscreen();
+                }
+            } else {
+                if (document.documentElement.requestFullscreen) {
+                    document.documentElement.requestFullscreen();
+                } else if (document.documentElement.mozRequestFullScreen) {
+                    document.documentElement.mozRequestFullScreen();
+                } else if (document.documentElement.webkitRequestFullscreen) {
+                    document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+                } else if (document.body.msRequestFullscreen) {
+                    document.body.msRequestFullscreen();
+                }
+            }
+            UI.enableDisableViewClip();
+            UI.updateFullscreenButton();
         },
 
-        displayFocus: function() {
+        updateFullscreenButton: function() {
+            if (document.fullscreenElement || // alternative standard method
+                document.mozFullScreenElement || // currently working methods
+                document.webkitFullscreenElement ||
+                document.msFullscreenElement ) {
+                $D('noVNC_fullscreen_button').className = "noVNC_status_button_selected";
+            } else {
+                $D('noVNC_fullscreen_button').className = "noVNC_status_button";
+            }
+        },
+
+/* ------^-------
+ *  /FULLSCREEN
+ * ==============
+ *     RESIZE
+ * ------v------*/
+
+        // Apply remote resizing or local scaling
+        applyResizeMode: function() {
             if (!UI.rfb) return;
 
-            UI.rfb.get_keyboard().set_focused(true);
-            UI.rfb.get_mouse().set_focused(true);
+            var screen = UI.screenSize();
+
+            if (screen && UI.rfb_state === 'normal' && UI.rfb.get_display()) {
+
+                var display = UI.rfb.get_display();
+                var resizeMode = UI.getSetting('resize');
+
+                if (resizeMode === 'remote') {
+
+                    // Request changing the resolution of the remote display to
+                    // the size of the local browser viewport.
+
+                    // In order to not send multiple requests before the browser-resize
+                    // is finished we wait 0.5 seconds before sending the request.
+                    clearTimeout(UI.resizeTimeout);
+                    UI.resizeTimeout = setTimeout(function(){
+
+                        // Limit the viewport to the size of the browser window
+                        display.set_maxWidth(screen.w);
+                        display.set_maxHeight(screen.h);
+
+                        Util.Debug('Attempting requestDesktopSize(' +
+                                   screen.w + ', ' + screen.h + ')');
+
+                        // Request a remote size covering the viewport
+                        UI.rfb.requestDesktopSize(screen.w, screen.h);
+                    }, 500);
+
+                } else if (resizeMode === 'scale' || resizeMode === 'downscale') {
+                    var downscaleOnly = resizeMode === 'downscale';
+                    var scaleRatio = display.autoscale(screen.w, screen.h, downscaleOnly);
+                    UI.rfb.get_mouse().set_scale(scaleRatio);
+                    Util.Debug('Scaling by ' + UI.rfb.get_mouse().get_scale());
+                }
+            }
         },
 
-        clipClear: function() {
-            $D('noVNC_clipboard_text').value = "";
-            UI.rfb.clipboardPasteFrom("");
+        // The screen is always the same size as the available viewport
+        // in the browser window minus the height of the control bar
+        screenSize: function() {
+            var screen = $D('noVNC_screen');
+
+            // Hide the scrollbars until the size is calculated
+            screen.style.overflow = "hidden";
+
+            var pos = Util.getPosition(screen);
+            var w = pos.width;
+            var h = pos.height;
+
+            screen.style.overflow = "visible";
+
+            if (isNaN(w) || isNaN(h)) {
+                return false;
+            } else {
+                return {w: w, h: h};
+            }
         },
 
-        clipSend: function() {
-            var text = $D('noVNC_clipboard_text').value;
-            Util.Debug(">> UI.clipSend: " + text.substr(0,40) + "...");
-            UI.rfb.clipboardPasteFrom(text);
-            Util.Debug("<< UI.clipSend");
+        // Normally we only apply the current resize mode after a window resize
+        // event. This means that when a new connection is opened, there is no
+        // resize mode active.
+        // We have to wait until the first FBU because this is where the client
+        // will find the supported encodings of the server. Some calls later in
+        // the chain is dependant on knowing the server-capabilities.
+        initialResize: function(rfb, fbu) {
+            UI.applyResizeMode();
+            // After doing this once, we remove the callback.
+            UI.rfb.set_onFBUComplete(function() { });
         },
 
+/* ------^-------
+ *    /RESIZE
+ * ==============
+ *    CLIPPING
+ * ------v------*/
+
         // Set and configure viewport clipping
         setViewClip: function(clip) {
             var display;
@@ -919,19 +921,19 @@ var UI;
                 // If clipping, update clipping settings
                 display.set_viewport(true);
 
-                var size = UI.getCanvasLimit();
+                var size = UI.screenSize();
                 if (size) {
                     display.set_maxWidth(size.w);
                     display.set_maxHeight(size.h);
 
                     // Hide potential scrollbars that can skew the position
-                    $D('noVNC_container').style.overflow = "hidden";
+                    $D('noVNC_screen').style.overflow = "hidden";
 
                     // The x position marks the left margin of the canvas,
                     // remove the margin from both sides to keep it centered
                     var new_w = size.w - (2 * Util.getPosition($D('noVNC_canvas')).x);
 
-                    $D('noVNC_container').style.overflow = "visible";
+                    $D('noVNC_screen').style.overflow = "visible";
 
                     display.viewportChangeSize(new_w, size.h);
                 }
@@ -939,71 +941,75 @@ var UI;
         },
 
         // Handle special cases where clipping is forced on/off or locked
-        enableDisableViewClip: function () {
-            var resizeElem = $D('noVNC_resize');
+        enableDisableViewClip: function() {
+            var resizeSetting = $D('noVNC_setting_resize');
             var connected = UI.rfb && UI.rfb_state === 'normal';
 
             if (UI.isSafari) {
                 // Safari auto-hides the scrollbars which makes them
                 // impossible to use in most cases
                 UI.setViewClip(true);
-                $D('noVNC_clip').disabled = true;
-            } else if (resizeElem.value === 'downscale' || resizeElem.value === 'scale') {
+                $D('noVNC_setting_clip').disabled = true;
+            } else if (resizeSetting.value === 'downscale' || resizeSetting.value === 'scale') {
                 // Disable clipping if we are scaling
                 UI.setViewClip(false);
-                $D('noVNC_clip').disabled = true;
+                $D('noVNC_setting_clip').disabled = true;
             } else if (document.msFullscreenElement) {
                 // The browser is IE and we are in fullscreen mode.
                 // - We need to force clipping while in fullscreen since
                 //   scrollbars doesn't work.
-                UI.togglePopupStatus("Forcing clipping mode since scrollbars aren't supported by IE in fullscreen");
+                UI.popupStatus("Forcing clipping mode since scrollbars aren't supported by IE in fullscreen");
                 UI.rememberedClipSetting = UI.getSetting('clip');
                 UI.setViewClip(true);
-                $D('noVNC_clip').disabled = true;
+                $D('noVNC_setting_clip').disabled = true;
             } else if (document.body.msRequestFullscreen && UI.rememberedClip !== null) {
                 // Restore view clip to what it was before fullscreen on IE
                 UI.setViewClip(UI.rememberedClipSetting);
-                $D('noVNC_clip').disabled = connected || UI.isTouchDevice;
+                $D('noVNC_setting_clip').disabled = connected || UI.isTouchDevice;
             } else {
-                $D('noVNC_clip').disabled = connected || UI.isTouchDevice;
+                $D('noVNC_setting_clip').disabled = connected || UI.isTouchDevice;
                 if (UI.isTouchDevice) {
                     UI.setViewClip(true);
                 }
             }
         },
 
-        // Update the viewport drag/move button
+/* ------^-------
+ *   /CLIPPING
+ * ==============
+ *    VIEWDRAG
+ * ------v------*/
+
+        // Update the viewport drag state
         updateViewDrag: function(drag) {
             if (!UI.rfb) return;
 
-            var vmb = $D('noVNC_view_drag_button');
+            var viewDragButton = $D('noVNC_view_drag_button');
 
-            // Check if viewport drag is possible
+            // Check if viewport drag is possible. It is only possible
+            // if the remote display is clipping the client display.
             if (UI.rfb_state === 'normal' &&
                 UI.rfb.get_display().get_viewport() &&
                 UI.rfb.get_display().clippingDisplay()) {
 
-                // Show and enable the drag button
-                vmb.style.display = "inline";
-                vmb.disabled = false;
+                viewDragButton.style.display = "inline";
+                viewDragButton.disabled = false;
 
             } else {
-                // The VNC content is the same size as
-                // or smaller than the display
-
+                // The size of the remote display is the same or smaller
+                // than the client display. Make sure viewport drag isn't
+                // active when it can't be used.
                 if (UI.rfb.get_viewportDrag) {
-                    // Turn off viewport drag when it's
-                    // active since it can't be used here
-                    vmb.className = "noVNC_status_button";
+                    viewDragButton.className = "noVNC_status_button";
                     UI.rfb.set_viewportDrag(false);
                 }
 
-                // Disable or hide the drag button
+                // The button is disabled instead of hidden on touch devices
                 if (UI.rfb_state === 'normal' && UI.isTouchDevice) {
-                    vmb.style.display = "inline";
-                    vmb.disabled = true;
+                    viewDragButton.style.display = "inline";
+                    viewDragButton.disabled = true;
                 } else {
-                    vmb.style.display = "none";
+                    viewDragButton.style.display = "none";
                 }
                 return;
             }
@@ -1011,10 +1017,10 @@ var UI;
             if (typeof(drag) !== "undefined" &&
                 typeof(drag) !== "object") {
                 if (drag) {
-                    vmb.className = "noVNC_status_button_selected";
+                    viewDragButton.className = "noVNC_status_button_selected";
                     UI.rfb.set_viewportDrag(true);
                 } else {
-                    vmb.className = "noVNC_status_button";
+                    viewDragButton.className = "noVNC_status_button";
                     UI.rfb.set_viewportDrag(false);
                 }
             }
@@ -1023,20 +1029,26 @@ var UI;
         toggleViewDrag: function() {
             if (!UI.rfb) return;
 
-            var vmb = $D('noVNC_view_drag_button');
+            var viewDragButton = $D('noVNC_view_drag_button');
             if (UI.rfb.get_viewportDrag()) {
-                vmb.className = "noVNC_status_button";
+                viewDragButton.className = "noVNC_status_button";
                 UI.rfb.set_viewportDrag(false);
             } else {
-                vmb.className = "noVNC_status_button_selected";
+                viewDragButton.className = "noVNC_status_button_selected";
                 UI.rfb.set_viewportDrag(true);
             }
         },
 
+/* ------^-------
+ *   /VIEWDRAG
+ * ==============
+ *    KEYBOARD
+ * ------v------*/
+
         // On touch devices, show the OS keyboard
         showKeyboard: function() {
-            var kbi = $D('keyboardinput');
-            var skb = $D('showKeyboard');
+            var kbi = $D('noVNC_keyboardinput');
+            var skb = $D('noVNC_keyboard_button');
             var l = kbi.value.length;
             if(UI.keyboardVisible === false) {
                 kbi.focus();
@@ -1051,19 +1063,29 @@ var UI;
             }
         },
 
+        hideKeyboard: function() {
+            $D('noVNC_keyboard_button').className = "noVNC_status_button";
+            //Weird bug in iOS if you change keyboardVisible
+            //here it does not actually occur so next time
+            //you click keyboard icon it doesnt work.
+            UI.hideKeyboardTimeout = setTimeout(function() {
+                UI.keyboardVisible = false;
+            },100);
+        },
+
         keepKeyboard: function() {
             clearTimeout(UI.hideKeyboardTimeout);
             if(UI.keyboardVisible === true) {
-                $D('keyboardinput').focus();
-                $D('showKeyboard').className = "noVNC_status_button_selected";
+                $D('noVNC_keyboardinput').focus();
+                $D('noVNC_keyboard_button').className = "noVNC_status_button_selected";
             } else if(UI.keyboardVisible === false) {
-                $D('keyboardinput').blur();
-                $D('showKeyboard').className = "noVNC_status_button";
+                $D('noVNC_keyboardinput').blur();
+                $D('noVNC_keyboard_button').className = "noVNC_status_button";
             }
         },
 
         keyboardinputReset: function() {
-            var kbi = $D('keyboardinput');
+            var kbi = $D('noVNC_keyboardinput');
             kbi.value = new Array(UI.defaultKeyboardinputLen).join("_");
             UI.lastKeyboardinput = kbi.value;
         },
@@ -1139,42 +1161,44 @@ var UI;
             }
         },
 
-        keyInputBlur: function() {
-            $D('showKeyboard').className = "noVNC_status_button";
-            //Weird bug in iOS if you change keyboardVisible
-            //here it does not actually occur so next time
-            //you click keyboard icon it doesnt work.
-            UI.hideKeyboardTimeout = setTimeout(function() { UI.setKeyboard(); },100);
-        },
-
-        showExtraKeys: function() {
+        toggleExtraKeys: function() {
             UI.keepKeyboard();
             if(UI.extraKeysVisible === false) {
-                $D('toggleCtrlButton').style.display = "inline";
-                $D('toggleAltButton').style.display = "inline";
-                $D('sendTabButton').style.display = "inline";
-                $D('sendEscButton').style.display = "inline";
-                $D('showExtraKeysButton').className = "noVNC_status_button_selected";
+                $D('noVNC_toggleCtrl_button').style.display = "inline";
+                $D('noVNC_toggleAlt_button').style.display = "inline";
+                $D('noVNC_sendTab_button').style.display = "inline";
+                $D('noVNC_sendEsc_button').style.display = "inline";
+                $D('noVNC_toggleExtraKeys_button').className = "noVNC_status_button_selected";
                 UI.extraKeysVisible = true;
             } else if(UI.extraKeysVisible === true) {
-                $D('toggleCtrlButton').style.display = "";
-                $D('toggleAltButton').style.display = "";
-                $D('sendTabButton').style.display = "";
-                $D('sendEscButton').style.display = "";
-                $D('showExtraKeysButton').className = "noVNC_status_button";
+                $D('noVNC_toggleCtrl_button').style.display = "";
+                $D('noVNC_toggleAlt_button').style.display = "";
+                $D('noVNC_sendTab_button').style.display = "";
+                $D('noVNC_sendEsc_button').style.display = "";
+                $D('noVNC_toggleExtraKeys_button').className = "noVNC_status_button";
                 UI.extraKeysVisible = false;
             }
         },
 
+        sendEsc: function() {
+            UI.keepKeyboard();
+            UI.rfb.sendKey(XK_Escape);
+        },
+
+        sendTab: function() {
+            UI.keepKeyboard();
+            UI.rfb.sendKey(XK_Tab);
+        },
+
         toggleCtrl: function() {
             UI.keepKeyboard();
             if(UI.ctrlOn === false) {
                 UI.rfb.sendKey(XK_Control_L, true);
-                $D('toggleCtrlButton').className = "noVNC_status_button_selected";
+                $D('noVNC_toggleCtrl_button').className = "noVNC_status_button_selected";
                 UI.ctrlOn = true;
             } else if(UI.ctrlOn === true) {
                 UI.rfb.sendKey(XK_Control_L, false);
-                $D('toggleCtrlButton').className = "noVNC_status_button";
+                $D('noVNC_toggleCtrl_button').className = "noVNC_status_button";
                 UI.ctrlOn = false;
             }
         },
@@ -1183,27 +1207,62 @@ var UI;
             UI.keepKeyboard();
             if(UI.altOn === false) {
                 UI.rfb.sendKey(XK_Alt_L, true);
-                $D('toggleAltButton').className = "noVNC_status_button_selected";
+                $D('noVNC_toggleAlt_button').className = "noVNC_status_button_selected";
                 UI.altOn = true;
             } else if(UI.altOn === true) {
                 UI.rfb.sendKey(XK_Alt_L, false);
-                $D('toggleAltButton').className = "noVNC_status_button";
+                $D('noVNC_toggleAlt_button').className = "noVNC_status_button";
                 UI.altOn = false;
             }
         },
 
-        sendTab: function() {
-            UI.keepKeyboard();
-            UI.rfb.sendKey(XK_Tab);
+        sendCtrlAltDel: function() {
+            UI.rfb.sendCtrlAltDel();
         },
 
-        sendEsc: function() {
-            UI.keepKeyboard();
-            UI.rfb.sendKey(XK_Escape);
+/* ------^-------
+ *   /KEYBOARD
+ * ==============
+ *     MISC
+ * ------v------*/
+
+        setMouseButton: function(num) {
+            if (typeof num === 'undefined') {
+                // Disable mouse buttons
+                num = -1;
+            }
+            if (UI.rfb) {
+                UI.rfb.get_mouse().set_touchButton(num);
+            }
+
+            var blist = [0, 1,2,4];
+            for (var b = 0; b < blist.length; b++) {
+                var button = $D('noVNC_mouse_button' + blist[b]);
+                if (blist[b] === num) {
+                    button.style.display = "";
+                } else {
+                    button.style.display = "none";
+                }
+            }
+        },
+
+        displayBlur: function() {
+            if (!UI.rfb) return;
+
+            UI.rfb.get_keyboard().set_focused(false);
+            UI.rfb.get_mouse().set_focused(false);
+        },
+
+        displayFocus: function() {
+            if (!UI.rfb) return;
+
+            UI.rfb.get_keyboard().set_focused(true);
+            UI.rfb.get_mouse().set_focused(true);
         },
 
-        setKeyboard: function() {
-            UI.keyboardVisible = false;
+        // Display the desktop name in the document title
+        updateDocumentTitle: function(rfb, name) {
+            document.title = name + " - noVNC";
         },
 
         //Helper to add options to dropdown.
@@ -1215,12 +1274,16 @@ var UI;
         },
 
         setBarPosition: function() {
-            $D('noVNC-control-bar').style.top = (window.pageYOffset) + 'px';
+            $D('noVNC_control_bar').style.top = (window.pageYOffset) + 'px';
             $D('noVNC_mobile_buttons').style.left = (window.pageXOffset) + 'px';
 
-            var vncwidth = $D('noVNC_screen').style.offsetWidth;
-            $D('noVNC-control-bar').style.width = vncwidth + 'px';
+            var vncwidth = $D('noVNC_container').style.offsetWidth;
+            $D('noVNC_control_bar').style.width = vncwidth + 'px';
         }
 
+/* ------^-------
+ *    /MISC
+ * ==============
+ */
     };
 })();

+ 54 - 54
vnc.html

@@ -5,7 +5,7 @@
     <!--
     noVNC example: simple example using default UI
     Copyright (C) 2012 Joel Martin
-    Copyright (C) 2013 Samuel Mannehed for Cendio AB
+    Copyright (C) 2016 Samuel Mannehed for Cendio AB
     noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
     This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
 
@@ -16,20 +16,20 @@
     -->
     <title>noVNC</title>
 
-    <meta charset="utf-8">
+    <meta charset="utf-8" />
 
     <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
                 Remove this if you use the .htaccess -->
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
 
     <!-- Apple iOS Safari settings -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
     <meta name="apple-mobile-web-app-capable" content="yes" />
     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
     <!-- App Start Icon  -->
     <link rel="apple-touch-startup-image" href="images/screen_320x460.png" />
     <!-- For iOS devices set the icon to use if user bookmarks app on their homescreen -->
-    <link rel="apple-touch-icon" href="images/screen_57x57.png">
+    <link rel="apple-touch-icon" href="images/screen_57x57.png" />
     <!--
     <link rel="apple-touch-icon-precomposed" href="images/screen_57x57.png" />
     -->
@@ -48,42 +48,42 @@
 </head>
 
 <body>
-    <div id="noVNC-control-bar" class="noVNC_status_normal">
+    <div id="noVNC_control_bar" class="noVNC_status_normal">
         <!--noVNC Mobile Device only Buttons-->
-        <div class="noVNC-buttons-left">
+        <div class="noVNC_buttons_left">
             <input type="image" alt="viewport drag" src="images/drag.png"
                 id="noVNC_view_drag_button" class="noVNC_status_button"
-                title="Move/Drag Viewport">
+                title="Move/Drag Viewport" />
             <div id="noVNC_mobile_buttons">
                 <input type="image" alt="No mousebutton" src="images/mouse_none.png"
-                    id="noVNC_mouse_button0" class="noVNC_status_button">
+                    id="noVNC_mouse_button0" class="noVNC_status_button" />
                 <input type="image" alt="Left mousebutton" src="images/mouse_left.png"
-                    id="noVNC_mouse_button1" class="noVNC_status_button">
+                    id="noVNC_mouse_button1" class="noVNC_status_button" />
                 <input type="image" alt="Middle mousebutton" src="images/mouse_middle.png"
-                    id="noVNC_mouse_button2" class="noVNC_status_button">
+                    id="noVNC_mouse_button2" class="noVNC_status_button" />
                 <input type="image" alt="Right mousebutton" src="images/mouse_right.png"
-                    id="noVNC_mouse_button4" class="noVNC_status_button">
+                    id="noVNC_mouse_button4" class="noVNC_status_button" />
                 <input type="image" alt="Keyboard" src="images/keyboard.png"
-                    id="showKeyboard" class="noVNC_status_button"
-                    value="Keyboard" title="Show Keyboard"/>
+                    id="noVNC_keyboard_button" class="noVNC_status_button"
+                    value="Keyboard" title="Show Keyboard" />
                 <!-- Note that Google Chrome on Android doesn't respect any of these,
                      html attributes which attempt to disable text suggestions on the
                      on-screen keyboard. Let's hope Chrome implements the ime-mode
                      style for example -->
-                <textarea id="keyboardinput" autocapitalize="off"
+                <textarea id="noVNC_keyboardinput" autocapitalize="off"
                     autocorrect="off" autocomplete="off" spellcheck="false"
                     mozactionhint="Enter"></textarea>
                 <div id="noVNC_extra_keys">
-                    <input type="image" alt="Extra keys" src="images/showextrakeys.png"
-                        id="showExtraKeysButton" class="noVNC_status_button">
+                    <input type="image" alt="Extra keys" src="images/toggleextrakeys.png"
+                        id="noVNC_toggleExtraKeys_button" class="noVNC_status_button" />
                     <input type="image" alt="Ctrl" src="images/ctrl.png"
-                        id="toggleCtrlButton" class="noVNC_status_button">
+                        id="noVNC_toggleCtrl_button" class="noVNC_status_button" />
                     <input type="image" alt="Alt" src="images/alt.png"
-                        id="toggleAltButton" class="noVNC_status_button">
+                        id="noVNC_toggleAlt_button" class="noVNC_status_button" />
                     <input type="image" alt="Tab" src="images/tab.png"
-                        id="sendTabButton" class="noVNC_status_button">
+                        id="noVNC_sendTab_button" class="noVNC_status_button" />
                     <input type="image" alt="Esc" src="images/esc.png"
-                        id="sendEscButton" class="noVNC_status_button">
+                        id="noVNC_sendEsc_button" class="noVNC_status_button" />
                 </div>
             </div>
         </div>
@@ -91,27 +91,27 @@
         <div id="noVNC_status"></div>
 
         <!--noVNC Buttons-->
-        <div class="noVNC-buttons-right">
+        <div class="noVNC_buttons_right">
             <input type="image" alt="Ctrl+Alt+Del" src="images/ctrlaltdel.png"
-                id="sendCtrlAltDelButton" class="noVNC_status_button"
+                id="noVNC_sendCtrlAltDel_button" class="noVNC_status_button"
                 title="Send Ctrl-Alt-Del" />
             <input type="image" alt="Shutdown/Reboot" src="images/power.png"
-                id="xvpButton" class="noVNC_status_button"
+                id="noVNC_toggleXvp_button" class="noVNC_status_button"
                 title="Shutdown/Reboot..." />
             <input type="image" alt="Clipboard" src="images/clipboard.png"
-                id="clipboardButton" class="noVNC_status_button"
+                id="noVNC_clipboard_button" class="noVNC_status_button"
                 title="Clipboard" />
             <input type="image" alt="Fullscreen" src="images/fullscreen.png"
-                id="fullscreenButton" class="noVNC_status_button"
+                id="noVNC_fullscreen_button" class="noVNC_status_button"
                 title="Fullscreen" />
             <input type="image" alt="Settings" src="images/settings.png"
-                id="settingsButton" class="noVNC_status_button"
+                id="noVNC_settings_button" class="noVNC_status_button"
                 title="Settings" />
             <input type="image" alt="Connect" src="images/connect.png"
-                id="connectButton" class="noVNC_status_button"
+                id="noVNC_connectPanel_button" class="noVNC_status_button"
                 title="Connect" />
             <input type="image" alt="Disconnect" src="images/disconnect.png"
-                id="disconnectButton" class="noVNC_status_button"
+                id="noVNC_disconnect_button" class="noVNC_status_button"
                 title="Disconnect" />
         </div>
 
@@ -128,7 +128,7 @@
             and <a href="http://kanaka.github.com/noVNC">website</a>
             for more information.
             <br />
-            <input id="descriptionButton" type="button" value="Close">
+            <input id="noVNC_description_button" type="button" value="Close" />
         </div>
 
         <!-- Popup Status -->
@@ -141,15 +141,15 @@
             </textarea>
             <br />
             <input id="noVNC_clipboard_clear_button" type="button"
-                value="Clear">
+                value="Clear" />
         </div>
 
         <!-- XVP Shutdown/Reboot Panel -->
         <div id="noVNC_xvp" class="triangle-right top">
             <span id="noVNC_xvp_menu">
-                <input type="button" id="xvpShutdownButton" value="Shutdown" />
-                <input type="button" id="xvpRebootButton" value="Reboot" />
-                <input type="button" id="xvpResetButton" value="Reset" />
+                <input type="button" id="noVNC_xvpShutdown_button" value="Shutdown" />
+                <input type="button" id="noVNC_xvpReboot_button" value="Reboot" />
+                <input type="button" id="noVNC_xvpReset_button" value="Reset" />
             </span>
         </div>
 
@@ -157,38 +157,38 @@
         <div id="noVNC_settings" class="triangle-right top">
             <span id="noVNC_settings_menu">
                 <ul>
-                    <li><input id="noVNC_encrypt" type="checkbox"> Encrypt</li>
-                    <li><input id="noVNC_true_color" type="checkbox" checked> True Color</li>
-                    <li><input id="noVNC_cursor" type="checkbox"> Local Cursor</li>
-                    <li><input id="noVNC_clip" type="checkbox"> Clip to Window</li>
-                    <li><input id="noVNC_shared" type="checkbox"> Shared Mode</li>
-                    <li><input id="noVNC_view_only" type="checkbox"> View Only</li>
+                    <li><input id="noVNC_setting_encrypt" type="checkbox" /> Encrypt</li>
+                    <li><input id="noVNC_setting_true_color" type="checkbox" checked /> True Color</li>
+                    <li><input id="noVNC_setting_cursor" type="checkbox" /> Local Cursor</li>
+                    <li><input id="noVNC_setting_clip" type="checkbox" /> Clip to Window</li>
+                    <li><input id="noVNC_setting_shared" type="checkbox" /> Shared Mode</li>
+                    <li><input id="noVNC_setting_view_only" type="checkbox" /> View Only</li>
                     <hr>
-                    <li><input id="noVNC_path" type="input" value="websockify"> Path</li>
+                    <li><input id="noVNC_setting_path" type="input" value="websockify" /> Path</li>
                     <li><label>
-                        <select id="noVNC_resize" name="vncResize">
+                        <select id="noVNC_setting_resize" name="vncResize">
                             <option value="off">None</option>
                             <option value="scale">Local Scaling</option>
                             <option value="downscale">Local Downscaling</option>
                             <option value="remote">Remote Resizing</option>
                         </select> Scaling Mode</label>
                     </li>
-                    <li><input id="noVNC_repeaterID" type="input" value=""> Repeater ID</li>
+                    <li><input id="noVNC_setting_repeaterID" type="input" value="" /> Repeater ID</li>
                     <hr>
                     <!-- Stylesheet selection dropdown -->
                     <li><label><strong>Style: </strong>
-                        <select id="noVNC_stylesheet" name="vncStyle">
+                        <select id="noVNC_setting_stylesheet" name="vncStyle">
                             <option value="default">default</option>
                         </select></label>
                     </li>
 
                     <!-- Logging selection dropdown -->
                     <li><label><strong>Logging: </strong>
-                        <select id="noVNC_logging" name="vncLogging">
+                        <select id="noVNC_setting_logging" name="vncLogging">
                         </select></label>
                     </li>
                     <hr>
-                    <li><input type="button" id="noVNC_apply" value="Apply"></li>
+                    <li><input type="button" id="noVNC_settings_apply" value="Apply" /></li>
                 </ul>
             </span>
         </div>
@@ -196,22 +196,22 @@
         <!-- Connection Panel -->
         <div id="noVNC_controls" class="triangle-right top">
             <ul>
-                <li><label><strong>Host: </strong><input id="noVNC_host" /></label></li>
-                <li><label><strong>Port: </strong><input id="noVNC_port" /></label></li>
-                <li><label><strong>Password: </strong><input id="noVNC_password" type="password" /></label></li>
-                <li><label><strong>Token: </strong><input id="noVNC_token"/></label></li>
-                <li><input id="noVNC_connect_button" type="button" value="Connect"></li>
+                <li><label><strong>Host: </strong><input id="noVNC_setting_host" /></label></li>
+                <li><label><strong>Port: </strong><input id="noVNC_setting_port" /></label></li>
+                <li><label><strong>Password: </strong><input id="noVNC_setting_password" type="password" /></label></li>
+                <li><label><strong>Token: </strong><input id="noVNC_setting_token" /></label></li>
+                <li><input id="noVNC_connect_button" type="button" value="Connect" /></li>
             </ul>
         </div>
 
-    </div> <!-- End of noVNC-control-bar -->
+    </div> <!-- End of noVNC_control_bar -->
 
 
-    <div id="noVNC_screen">
+    <div id="noVNC_container">
         <h1 id="noVNC_logo"><span>no</span><br />VNC</h1>
 
         <!-- HTML5 Canvas -->
-        <div id="noVNC_container">
+        <div id="noVNC_screen">
             <canvas id="noVNC_canvas" width="0" height="0">
                         Canvas not supported.
             </canvas>