Commit 98f40377 authored by Christian Beier's avatar Christian Beier

Update our copy of noVNC.

Bugfixes and support for tight encoding with zlib.
parent efcdab50
......@@ -13,6 +13,8 @@ version 3 with the following exceptions (all LGPL-3 compatible):
include/des.js : Various BSD style licenses
include/jsunzip.js : zlib/libpng license
include/web-socket-js/ : New BSD license. Source code at
http://github.com/gimite/web-socket-js
......
......@@ -3,20 +3,28 @@
### Description
noVNC is a VNC client implemented using HTML5 technologies,
specifically Canvas and WebSockets (supports 'wss://' encryption).
noVNC is licensed under the
[LGPLv3](http://www.gnu.org/licenses/lgpl.html).
noVNC is a HTML5 VNC client that runs well in any modern browser
including mobile browsers (iPhone/iPad and Android).
Special thanks to [Sentry Data Systems](http://www.sentryds.com) for
sponsoring ongoing development of this project (and for employing me).
Notable commits, announcements and news are posted to
@<a href="http://www.twitter.com/noVNC">noVNC</a>
There are many companies/projects that have integrated noVNC into
their products including: [Sentry Data Systems](http://www.sentryds.com), [Ganeti Web Manager](http://code.osuosl.org/projects/ganeti-webmgr), [Archipel](http://archipelproject.org), [openQRM](http://www.openqrm.com/), [OpenNode](http://www.opennodecloud.com/), [OpenStack](http://www.openstack.org), [Broadway (HTML5 GDK/GTK+ backend)](http://blogs.gnome.org/alexl/2011/03/15/gtk-html-backend-update/), [OpenNebula](http://opennebula.org/), [CloudSigma](http://www.cloudsigma.com/), [Zentyal (formerly eBox)](http://www.zentyal.org/), and [SlapOS](http://www.slapos.org). See [this wiki page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) for more info and links.
their products including: [Ganeti Web Manager](http://code.osuosl.org/projects/ganeti-webmgr), [Archipel](http://archipelproject.org), [openQRM](http://www.openqrm.com/), [OpenNode](http://www.opennodecloud.com/), [OpenStack](http://www.openstack.org), [Broadway (HTML5 GDK/GTK+ backend)](http://blogs.gnome.org/alexl/2011/03/15/gtk-html-backend-update/), [OpenNebula](http://opennebula.org/), [CloudSigma](http://www.cloudsigma.com/), [Zentyal (formerly eBox)](http://www.zentyal.org/), [SlapOS](http://www.slapos.org), [Intel MeshCentral](https://meshcentral.com), [Amahi](http://amahi.org), [Brightbox](http://brightbox.com/), [Foreman](http://theforeman.org) and [LibVNCServer](http://libvncserver.sourceforge.net). See [this wiki page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) for more info and links.
Notable commits, announcements and news are posted to
@<a href="http://www.twitter.com/noVNC">noVNC</a>
### Features
* Supports all modern browsers including mobile (iOS, Android)
* Supported VNC encodings: raw, copyrect, rre, hextile, tight, tightPNG
* WebSocket SSL/TLS encryption (i.e. "wss://") support
* 24-bit true color and 8 bit colour mapped
* Supports desktop resize notification/pseudo-encoding
* Local or remote cursor
* Clipboard copy/paste
* Clipping or scolling modes for large remote screens
* Easy site integration and theming (3 example themes included)
* Licensed under the [LGPLv3](http://www.gnu.org/licenses/lgpl.html)
### Screenshots
......@@ -38,10 +46,8 @@ See more screenshots <a href="http://kanaka.github.com/noVNC/screenshots.html">h
a WebSockets emulator using Adobe Flash. iOS 4.2+ has built-in
WebSocket support.
* Fast Javascript Engine: noVNC avoids using new Javascript
functionality so it will run on older browsers, but decode and
rendering happen in Javascript, so a slow Javascript engine will
mean noVNC is painfully slow.
* Fast Javascript Engine: this is not strictly a requirement, but
without a fast Javascript engine, noVNC might be painfully slow.
* I maintain a more detailed browser compatibility list <a
href="https://github.com/kanaka/noVNC/wiki/Browser-support">here</a>.
......@@ -50,22 +56,9 @@ See more screenshots <a href="http://kanaka.github.com/noVNC/screenshots.html">h
### Server Requirements
Unless you are using a VNC server with support for WebSockets
connections (only my [fork of libvncserver](http://github.com/kanaka/libvncserver)
currently), you need to use a WebSockets to TCP socket proxy. There is
a python proxy included ('websockify'). One advantage of using the
proxy is that it has builtin support for SSL/TLS encryption (i.e.
"wss://").
There a few reasons why a proxy is required:
1. WebSockets is not a pure socket protocol. There is an initial HTTP
like handshake to allow easy hand-off by web servers and allow
some origin policy exchange. Also, each WebSockets frame begins
with 0 ('\x00') and ends with 255 ('\xff').
2. Javascript itself does not have the ability to handle pure byte
arrays. The python proxy encodes the data as base64 so that the
Javascript client can decode the data as an integer array.
connections (such as [x11vnc/libvncserver](http://libvncserver.sourceforge.net/)),
you need to use a WebSockets to TCP socket proxy. There is
a python proxy included ('websockify').
### Quick Start
......@@ -91,3 +84,19 @@ There a few reasons why a proxy is required:
* [Troubleshooting noVNC](https://github.com/kanaka/noVNC/wiki/Troubleshooting) problems.
### Authors/Contributors
* noVNC : Joel Martin (github.com/kanaka)
* New UI and Icons : Chris Gordon
* Original Logo : Michael Sersen
* tight encoding : Michael Tinglof (Mercuri.ca)
* Included libraries:
* web-socket-js : Hiroshi Ichikawa (github.com/gimite/web-socket-js)
* as3crypto : Henri Torgemane (code.google.com/p/as3crypto)
* base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
* jsunzip : Erik Moller (github.com/operasoftware/jsunzip),
* tinflate : Joergen Ibsen (ibsensoftware.com)
* DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs)
......@@ -153,6 +153,7 @@ html {
}
#noVNC_controls {
display:none;
margin-top:77px;
right:12px;
position:fixed;
......@@ -161,6 +162,23 @@ html {
right:15px;
}
#noVNC_description {
display:none;
position:fixed;
margin-top:77px;
right:20px;
left:20px;
padding:15px;
color:#000;
background:#eee; /* default background for browsers without gradient support */
border:2px solid #E0E0E0;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
#noVNC_clipboard {
display:none;
margin-top:77px;
......
......@@ -116,7 +116,7 @@ decode: function (data, offset) {
padding = (data.charAt(i) === pad);
// Skip illegal characters and whitespace
if (c === -1) {
console.error("Illegal character '" + data.charCodeAt(i) + "'");
console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
continue;
}
......
......@@ -20,7 +20,7 @@ var that = {}, // Public API methods
c_forceCanvas = false,
// Predefine function variables (jslint)
imageDataGet, rgbxImageData, cmapImageData,
imageDataGet, rgbImageData, bgrxImageData, cmapImageData,
setFillColor, rescale,
// The full frame buffer (logical canvas) size
......@@ -183,13 +183,13 @@ rescale = function(factor) {
};
setFillColor = function(color) {
var rgb, newStyle;
var bgr, newStyle;
if (conf.true_color) {
rgb = color;
bgr = color;
} else {
rgb = conf.colourMap[color[0]];
bgr = conf.colourMap[color[0]];
}
newStyle = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
newStyle = "rgb(" + bgr[2] + "," + bgr[1] + "," + bgr[0] + ")";
if (newStyle !== c_prevStyle) {
c_ctx.fillStyle = newStyle;
c_prevStyle = newStyle;
......@@ -386,10 +386,10 @@ that.getCleanDirtyReset = function() {
// Translate viewport coordinates to absolute coordinates
that.absX = function(x) {
return x + viewport.x;
}
};
that.absY = function(y) {
return y + viewport.y;
}
};
that.resize = function(width, height) {
......@@ -430,7 +430,7 @@ that.copyImage = function(old_x, old_y, new_x, new_y, w, h) {
// Start updating a tile
that.startTile = function(x, y, width, height, color) {
var data, rgb, red, green, blue, i;
var data, bgr, red, green, blue, i;
tile_x = x;
tile_y = y;
if ((width === 16) && (height === 16)) {
......@@ -441,13 +441,13 @@ that.startTile = function(x, y, width, height, color) {
data = tile.data;
if (conf.prefer_js) {
if (conf.true_color) {
rgb = color;
bgr = color;
} else {
rgb = conf.colourMap[color[0]];
bgr = conf.colourMap[color[0]];
}
red = rgb[0];
green = rgb[1];
blue = rgb[2];
red = bgr[2];
green = bgr[1];
blue = bgr[0];
for (i = 0; i < (width * height * 4); i+=4) {
data[i ] = red;
data[i + 1] = green;
......@@ -461,18 +461,18 @@ that.startTile = function(x, y, width, height, color) {
// Update sub-rectangle of the current tile
that.subTile = function(x, y, w, h, color) {
var data, p, rgb, red, green, blue, width, j, i, xend, yend;
var data, p, bgr, red, green, blue, width, j, i, xend, yend;
if (conf.prefer_js) {
data = tile.data;
width = tile.width;
if (conf.true_color) {
rgb = color;
bgr = color;
} else {
rgb = conf.colourMap[color[0]];
bgr = conf.colourMap[color[0]];
}
red = rgb[0];
green = rgb[1];
blue = rgb[2];
red = bgr[2];
green = bgr[1];
blue = bgr[0];
xend = x + w;
yend = y + h;
for (j = y; j < yend; j += 1) {
......@@ -492,12 +492,12 @@ that.subTile = function(x, y, w, h, color) {
// Draw the current tile to the screen
that.finishTile = function() {
if (conf.prefer_js) {
c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y)
c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y);
}
// else: No-op, if not prefer_js then already done by setSubTile
};
rgbxImageData = function(x, y, width, height, arr, offset) {
rgbImageData = function(x, y, width, height, arr, offset) {
var img, i, j, data, v = viewport;
/*
if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
......@@ -508,7 +508,7 @@ rgbxImageData = function(x, y, width, height, arr, offset) {
*/
img = c_ctx.createImageData(width, height);
data = img.data;
for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+3) {
data[i ] = arr[j ];
data[i + 1] = arr[j + 1];
data[i + 2] = arr[j + 2];
......@@ -517,16 +517,36 @@ rgbxImageData = function(x, y, width, height, arr, offset) {
c_ctx.putImageData(img, x - v.x, y - v.y);
};
bgrxImageData = function(x, y, width, height, arr, offset) {
var img, i, j, data, v = viewport;
/*
if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
(x - v.x + width < 0) || (y - v.y + height < 0)) {
// Skipping because outside of viewport
return;
}
*/
img = c_ctx.createImageData(width, height);
data = img.data;
for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
data[i ] = arr[j + 2];
data[i + 1] = arr[j + 1];
data[i + 2] = arr[j ];
data[i + 3] = 255; // Set Alpha
}
c_ctx.putImageData(img, x - v.x, y - v.y);
};
cmapImageData = function(x, y, width, height, arr, offset) {
var img, i, j, data, rgb, cmap;
var img, i, j, data, bgr, cmap;
img = c_ctx.createImageData(width, height);
data = img.data;
cmap = conf.colourMap;
for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
rgb = cmap[arr[j]];
data[i ] = rgb[0];
data[i + 1] = rgb[1];
data[i + 2] = rgb[2];
bgr = cmap[arr[j]];
data[i ] = bgr[2];
data[i + 1] = bgr[1];
data[i + 2] = bgr[0];
data[i + 3] = 255; // Set Alpha
}
c_ctx.putImageData(img, x - viewport.x, y - viewport.y);
......@@ -534,8 +554,17 @@ cmapImageData = function(x, y, width, height, arr, offset) {
that.blitImage = function(x, y, width, height, arr, offset) {
if (conf.true_color) {
rgbxImageData(x, y, width, height, arr, offset);
bgrxImageData(x, y, width, height, arr, offset);
} else {
cmapImageData(x, y, width, height, arr, offset);
}
};
that.blitRgbImage = function(x, y, width, height, arr, offset) {
if (conf.true_color) {
rgbImageData(x, y, width, height, arr, offset);
} else {
// prolly wrong...
cmapImageData(x, y, width, height, arr, offset);
}
};
......
......@@ -412,6 +412,26 @@ function onKeyUp(e) {
return false;
}
function allKeysUp() {
Util.Debug(">> Keyboard.allKeysUp");
if (keyDownList.length > 0) {
Util.Info("Releasing pressed/down keys");
}
var i, keysym, fevt = null;
for (i = keyDownList.length-1; i >= 0; i--) {
fevt = keyDownList.splice(i, 1)[0];
keysym = fevt.keysym;
if (conf.onKeyPress && (keysym > 0)) {
Util.Debug("allKeysUp, keysym: " + keysym +
" (keyCode: " + fevt.keyCode +
", which: " + fevt.which + ")");
conf.onKeyPress(keysym, 0, fevt);
}
}
Util.Debug("<< Keyboard.allKeysUp");
return;
}
//
// Public API interface functions
//
......@@ -424,6 +444,9 @@ that.grab = function() {
Util.addEvent(c, 'keyup', onKeyUp);
Util.addEvent(c, 'keypress', onKeyPress);
// Release (key up) if window loses focus
Util.addEvent(window, 'blur', allKeysUp);
//Util.Debug("<< Keyboard.grab");
};
......@@ -434,6 +457,10 @@ that.ungrab = function() {
Util.removeEvent(c, 'keydown', onKeyDown);
Util.removeEvent(c, 'keyup', onKeyUp);
Util.removeEvent(c, 'keypress', onKeyPress);
Util.removeEvent(window, 'blur', allKeysUp);
// Release (key up) all keys that are in a down state
allKeysUp();
//Util.Debug(">> Keyboard.ungrab");
};
......
This diff is collapsed.
This diff is collapsed.
......@@ -14,7 +14,7 @@ var UI = {
rfb_state : 'loaded',
settingsOpen : false,
connSettingsOpen : true,
connSettingsOpen : false,
clipboardOpen: false,
keyboardVisible: false,
......@@ -45,15 +45,16 @@ load: function() {
WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
/* Populate the controls if defaults are provided in the URL */
UI.initSetting('host', '');
UI.initSetting('port', '');
UI.initSetting('host', window.location.hostname);
UI.initSetting('port', window.location.port);
UI.initSetting('password', '');
UI.initSetting('encrypt', false);
UI.initSetting('encrypt', (window.location.protocol === "https:"));
UI.initSetting('true_color', true);
UI.initSetting('cursor', false);
UI.initSetting('shared', true);
UI.initSetting('view_only', false);
UI.initSetting('connectTimeout', 2);
UI.initSetting('path', '');
UI.initSetting('path', 'websockify');
UI.rfb = RFB({'target': $D('noVNC_canvas'),
'onUpdateState': UI.updateState,
......@@ -101,6 +102,14 @@ load: function() {
}
} );
// Show description by default when hosted at for kanaka.github.com
if (location.host === "kanaka.github.com") {
// Open the description dialog
$D('noVNC_description').style.display = "block";
} else {
// Open the connect panel on first load
UI.toggleConnectPanel();
}
},
// Read form control compatible setting from cookie
......@@ -188,17 +197,19 @@ forceSetting: function(name, val) {
// Show the clipboard panel
toggleClipboardPanel: function() {
// Close the description panel
$D('noVNC_description').style.display = "none";
//Close settings if open
if (UI.settingsOpen == true) {
if (UI.settingsOpen === true) {
UI.settingsApply();
UI.closeSettingsMenu();
}
//Close connection settings if open
if (UI.connSettingsOpen == true) {
if (UI.connSettingsOpen === true) {
UI.toggleConnectPanel();
}
//Toggle Clipboard Panel
if (UI.clipboardOpen == true) {
if (UI.clipboardOpen === true) {
$D('noVNC_clipboard').style.display = "none";
$D('clipboardButton').className = "noVNC_status_button";
UI.clipboardOpen = false;
......@@ -211,18 +222,20 @@ toggleClipboardPanel: function() {
// 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) {
if (UI.settingsOpen === true) {
UI.settingsApply();
UI.closeSettingsMenu();
$D('connectButton').className = "noVNC_status_button";
}
if (UI.clipboardOpen == true) {
if (UI.clipboardOpen === true) {
UI.toggleClipboardPanel();
}
//Toggle Connection Panel
if (UI.connSettingsOpen == true) {
if (UI.connSettingsOpen === true) {
$D('noVNC_controls').style.display = "none";
$D('connectButton').className = "noVNC_status_button";
UI.connSettingsOpen = false;
......@@ -238,6 +251,8 @@ toggleConnectPanel: function() {
// On open, settings are refreshed from saved cookies.
// On close, settings are applied
toggleSettingsPanel: function() {
// Close the description panel
$D('noVNC_description').style.display = "none";
if (UI.settingsOpen) {
UI.settingsApply();
UI.closeSettingsMenu();
......@@ -252,6 +267,7 @@ toggleSettingsPanel: function() {
}
UI.updateSetting('clip');
UI.updateSetting('shared');
UI.updateSetting('view_only');
UI.updateSetting('connectTimeout');
UI.updateSetting('path');
UI.updateSetting('stylesheet');
......@@ -263,11 +279,13 @@ toggleSettingsPanel: function() {
// Open menu
openSettingsMenu: function() {
if (UI.clipboardOpen == true) {
// Close the description panel
$D('noVNC_description').style.display = "none";
if (UI.clipboardOpen === true) {
UI.toggleClipboardPanel();
}
//Close connection settings if open
if (UI.connSettingsOpen == true) {
if (UI.connSettingsOpen === true) {
UI.toggleConnectPanel();
}
$D('noVNC_settings').style.display = "block";
......@@ -292,6 +310,7 @@ settingsApply: function() {
}
UI.saveSetting('clip');
UI.saveSetting('shared');
UI.saveSetting('view_only');
UI.saveSetting('connectTimeout');
UI.saveSetting('path');
UI.saveSetting('stylesheet');
......@@ -363,6 +382,7 @@ updateState: function(rfb, state, oldstate, msg) {
break;
case 'disconnected':
$D('noVNC_logo').style.display = "block";
// Fall through
case 'loaded':
klass = "noVNC_status_normal";
break;
......@@ -404,16 +424,19 @@ updateVisualState: function() {
$D('noVNC_cursor').disabled = true;
}
$D('noVNC_shared').disabled = connected;
$D('noVNC_view_only').disabled = connected;
$D('noVNC_connectTimeout').disabled = connected;
$D('noVNC_path').disabled = connected;
if (connected) {
UI.setViewClip();
UI.setMouseButton(1);
$D('clipboardButton').style.display = "inline";
$D('showKeyboard').style.display = "inline";
$D('sendCtrlAltDelButton').style.display = "inline";
} else {
UI.setMouseButton();
$D('clipboardButton').style.display = "none";
$D('showKeyboard').style.display = "none";
$D('sendCtrlAltDelButton').style.display = "none";
}
......@@ -464,6 +487,7 @@ connect: function() {
UI.rfb.set_true_color(UI.getSetting('true_color'));
UI.rfb.set_local_cursor(UI.getSetting('cursor'));
UI.rfb.set_shared(UI.getSetting('shared'));
UI.rfb.set_view_only(UI.getSetting('view_only'));
UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout'));
UI.rfb.connect(host, port, password, path);
......@@ -569,11 +593,11 @@ setViewDrag: function(drag) {
// On touch devices, show the OS keyboard
showKeyboard: function() {
if(UI.keyboardVisible == false) {
if(UI.keyboardVisible === false) {
$D('keyboardinput').focus();
UI.keyboardVisible = true;
$D('showKeyboard').className = "noVNC_status_button_selected";
} else if(UI.keyboardVisible == true) {
} else if(UI.keyboardVisible === true) {
$D('keyboardinput').blur();
$D('showKeyboard').className = "noVNC_status_button";
UI.keyboardVisible = false;
......@@ -585,7 +609,7 @@ keyInputBlur: function() {
//Weird bug in iOS if you change keyboardVisible
//here it does not actually occur so next time
//you click keyboard icon it doesnt work.
setTimeout("UI.setKeyboard()",100)
setTimeout(function() { UI.setKeyboard(); },100);
},
setKeyboard: function() {
......
......@@ -33,6 +33,30 @@ Array.prototype.push32 = function (num) {
(num ) & 0xFF );
};
// IE does not support map (even in IE9)
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.map)
{
Array.prototype.map = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array(len);
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
res[i] = fun.call(thisp, this[i], i, this);
}
return res;
};
}
/*
* ------------------------------------------------------
* Namespaced in Util
......@@ -159,7 +183,7 @@ Util.conf_defaults = function(cfg, api, defaults, arr) {
Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1],
arr[i][2], arr[i][3], arr[i][4]);
}
}
};
/*
......@@ -240,8 +264,11 @@ Util.stopEvent = function(e) {
Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
Util.Engine = {
'presto': (function() {
return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
// Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
//'presto': (function() {
// return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
'presto': (function() { return (!window.opera) ? false : true; }()),
'trident': (function() {
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()),
'webkit': (function() {
......
......@@ -36,6 +36,7 @@ function get_INCLUDE_URI() {
extra += start + "input.js" + end;
extra += start + "display.js" + end;
extra += start + "rfb.js" + end;
extra += start + "jsunzip.js" + end;
document.write(extra);
}());
......
......@@ -14,16 +14,23 @@
* read binary data off of the receive queue.
*/
/*jslint browser: true, bitwise: false, plusplus: false */
/*global Util, Base64 */
// Load Flash WebSocket emulator if needed
if (window.WebSocket) {
if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
Websock_native = true;
} else if (window.MozWebSocket) {
} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
Websock_native = true;
window.WebSocket = window.MozWebSocket;
} else {
/* no builtin WebSocket so load web_socket.js */
// To enable debug:
// window.WEB_SOCKET_DEBUG=1;
Websock_native = false;
(function () {
function get_INCLUDE_URI() {
......@@ -34,11 +41,11 @@ if (window.WebSocket) {
var start = "<script src='" + get_INCLUDE_URI(),
end = "'><\/script>", extra = "";
WEB_SOCKET_SWF_LOCATION = get_INCLUDE_URI() +
window.WEB_SOCKET_SWF_LOCATION = get_INCLUDE_URI() +
"web-socket-js/WebSocketMain.swf";
if (Util.Engine.trident) {
Util.Debug("Forcing uncached load of WebSocketMain.swf");
WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
window.WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
}
extra += start + "web-socket-js/swfobject.js" + end;
extra += start + "web-socket-js/web_socket.js" + end;
......@@ -83,7 +90,7 @@ function get_rQi() {
}
function set_rQi(val) {
rQi = val;
};
}
function rQlen() {
return rQ.length - rQi;
......@@ -115,6 +122,7 @@ function rQshift32() {
(rQ[rQi++] );
}
function rQshiftStr(len) {
if (typeof(len) === 'undefined') { len = rQlen(); }
var arr = rQ.slice(rQi, rQi + len);
rQi += len;
return arr.map(function (num) {
......@@ -122,6 +130,7 @@ function rQshiftStr(len) {
}
function rQshiftBytes(len) {
if (typeof(len) === 'undefined') { len = rQlen(); }
rQi += len;
return rQ.slice(rQi-len, rQi);
}
......
......@@ -8,7 +8,7 @@
"use strict";
/*jslint bitwise: false, white: false */
/*global window, document */
/*global Util, window, document */
// Globals defined here
var WebUtil = {}, $D;
......@@ -17,7 +17,7 @@ var WebUtil = {}, $D;
* Simple DOM selector by ID
*/
if (!window.$D) {
$D = function (id) {
window.$D = function (id) {
if (document.getElementById) {
return document.getElementById(id);
} else if (document.all) {
......@@ -42,8 +42,8 @@ WebUtil.init_logging = function() {
/logging=([A-Za-z0-9\._\-]*)/) ||
['', Util._log_level])[1];
Util.init_logging()
}
Util.init_logging();
};
WebUtil.init_logging();
......
......@@ -90,7 +90,7 @@
title="Settings"
onclick="UI.toggleSettingsPanel();" />
<input type="image" src="images/connect.png"
id="connectButton" class="noVNC_status_button_selected"
id="connectButton" class="noVNC_status_button"
title="Connect"
onclick="UI.toggleConnectPanel()" />
<input type="image" src="images/disconnect.png"
......@@ -99,6 +99,23 @@
onclick="UI.disconnect()" />
</div>
<!-- Description Panel -->
<!-- Shown by default when hosted at for kanaka.github.com -->
<div id="noVNC_description" style="display:none;" class="">
noVNC is a browser based VNC client implemented using HTML5 Canvas
and WebSockets. You will either need a VNC server with WebSockets
support (such as <a href="http://libvncserver.sourceforge.net/">libvncserver</a>)
or you will need to use
<a href="https://github.com/kanaka/websockify">websockify</a>
to bridge between your browser and VNC server. See the noVNC
<a href="https://github.com/kanaka/noVNC">README</a>
and <a href="http://kanaka.github.com/noVNC">website</a>
for more information.
<br />
<input type="button" value="Close"
onclick="UI.toggleConnectPanel();">
</div>
<!-- Clipboard Panel -->
<div id="noVNC_clipboard" class="triangle-right top">
<textarea id="noVNC_clipboard_text" rows=5
......@@ -118,10 +135,11 @@
<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_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_connectTimeout" type="input"> Connect Timeout (s)</li>
<li><input id="noVNC_path" type="input"> Path</li>
<li><input id="noVNC_path" type="input" value="websockify"> Path</li>
<hr>
<!-- Stylesheet selection dropdown -->
<li><label><strong>Style: </strong>
......
......@@ -84,16 +84,25 @@
}
window.onload = function () {
var host, port, password, path;
var host, port, password, path, token;
$D('sendCtrlAltDelButton').style.display = "inline";
$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
document.title = unescape(WebUtil.getQueryVar('title', 'noVNC'));
host = WebUtil.getQueryVar('host', null);
port = WebUtil.getQueryVar('port', null);
// By default, use the host and port of server that served this file
host = WebUtil.getQueryVar('host', window.location.hostname);
port = WebUtil.getQueryVar('port', window.location.port);
// If a token variable is passed in, set the parameter in a cookie.
// This is used by nova-novncproxy.
token = WebUtil.getQueryVar('token', null);
if (token) {
WebUtil.createCookie('token', token, 1)
}
password = WebUtil.getQueryVar('password', '');
path = WebUtil.getQueryVar('path', '');
path = WebUtil.getQueryVar('path', 'websockify');
if ((!host) || (!port)) {
updateState('failed',
"Must specify host and port in URL");
......@@ -101,10 +110,12 @@
}
rfb = new RFB({'target': $D('noVNC_canvas'),
'encrypt': WebUtil.getQueryVar('encrypt', false),
'encrypt': WebUtil.getQueryVar('encrypt',
(window.location.protocol === "https:")),
'true_color': WebUtil.getQueryVar('true_color', true),
'local_cursor': WebUtil.getQueryVar('cursor', true),
'shared': WebUtil.getQueryVar('shared', true),
'view_only': WebUtil.getQueryVar('view_only', false),
'updateState': updateState,
'onPasswordRequired': passwordRequired});
rfb.connect(host, port, password, path);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment