Update noVNC webclient.

pull/1/head
Christian Beier 12 years ago
parent 2fba1be453
commit 2b4f616d96

@ -1,35 +1,78 @@
noVNC is Copyright (C) 2011 Joel Martin <github@martintribe.org> noVNC is Copyright (C) 2011 Joel Martin <github@martintribe.org>
The noVNC core library is licensed under the LGPLv3 (GNU Lesser
General Public License). The noVNC core library is composed of the
Javascript code necessary for full noVNC operation. This includes (but
is not limited to):
include/base64.js
include/des.js
include/display.js
include/input.js
include/jsunzip.js
include/logo.js
include/rfb.js
include/ui.js
include/util.js
include/vnc.js
include/websock.js
include/webutil.js
The HTML, CSS, font and images files that included with the noVNC
source distibution (or repository) are not considered part of the
noVNC core library and are licensed under more permissive licenses.
The intent is to allow easy integration of noVNC into existing web
sites and web applications.
The HTML, CSS, font and image files are licensed as follows:
*.html : 2-Clause BSD license
include/*.css : 2-Clause BSD license
include/Orbitron* : SIL Open Font License 1.1
(Copyright 2009 Matt McInerney)
images/ : Creative Commons Attribution-ShareAlike
http://creativecommons.org/licenses/by-sa/3.0/
In addition the following file, which is part of the noVNC core
library, may be licensed under either the LGPL-2, LGPL-3 or MPL 2.0
when it used separately from the noVNC core library.
include/input.js : LGPL-2 or any later version
Some portions of noVNC are copyright to their individual authors. Some portions of noVNC are copyright to their individual authors.
Please refer to the individual source files and/or to the noVNC commit Please refer to the individual source files and/or to the noVNC commit
history: https://github.com/kanaka/noVNC/commits/master history: https://github.com/kanaka/noVNC/commits/master
noVNC is licensed under the LGPL (GNU Lesser General Public License) The are several files and projects that have been incorporated into
version 3 with the following exceptions (all LGPL-3 compatible): the noVNC core library. Here is a list of those files and the original
licenses (all LGPL-3 compatible):
include/input.js : LGPL-2 or any later version include/base64.js : MPL 1.1, GPL-2 or LGPL-2.1
include/base64.js : Dual GPL-2 or LGPL-2.1
include/des.js : Various BSD style licenses include/des.js : Various BSD style licenses
include/jsunzip.js : zlib/libpng license include/jsunzip.js : zlib/libpng license
include/web-socket-js/ : New BSD license. Source code at include/web-socket-js/ : New BSD license (3-clause). Source code at
http://github.com/gimite/web-socket-js http://github.com/gimite/web-socket-js
include/Orbitron* : SIL Open Font License 1.1 The following license texts are included:
(Copyright 2009 Matt McInerney)
images/ : Creative Commons Attribution-ShareAlike
http://creativecommons.org/licenses/by-sa/3.0/
The license texts are included at:
docs/LICENSE.LGPL-3 and docs/LICENSE.LGPL-3 and
docs/LICENSE.GPL-3 docs/LICENSE.GPL-3
docs/LICENSE.OFL-1.1 docs/LICENSE.OFL-1.1
docs/LICENSE.BSD-3-Clause (New BSD)
docs/LICENSE.BSD-2-Clause (Simplified BSD / FreeBSD)
docs/LICENSE.zlib
docs/LICENSE.MPL-2.0
Or alternatively the license texts may be found here: Or alternatively the license texts may be found here:
http://www.gnu.org/licenses/lgpl.html and http://www.gnu.org/licenses/lgpl.html and
http://www.gnu.org/licenses/gpl.html http://www.gnu.org/licenses/gpl.html
http://scripts.sil.org/OFL http://scripts.sil.org/OFL
http://www.mozilla.org/MPL/1.1/
http://www.mozilla.org/MPL/2.0/

@ -10,7 +10,7 @@ Notable commits, announcements and news are posted to
@<a href="http://www.twitter.com/noVNC">noVNC</a> @<a href="http://www.twitter.com/noVNC">noVNC</a>
There are many companies/projects that have integrated noVNC into There are many companies/projects that have integrated noVNC into
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. 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), [LibVNCServer](http://libvncserver.sourceforge.net) and [PocketVNC](http://www.pocketvnc.com/blog/?page_id=866). See [this wiki page](https://github.com/kanaka/noVNC/wiki/ProjectsCompanies-using-noVNC) for more info and links.
### Features ### Features
@ -56,7 +56,8 @@ See more screenshots <a href="http://kanaka.github.com/noVNC/screenshots.html">h
### Server Requirements ### Server Requirements
Unless you are using a VNC server with support for WebSockets Unless you are using a VNC server with support for WebSockets
connections (such as [x11vnc/libvncserver](http://libvncserver.sourceforge.net/)), connections (such as [x11vnc/libvncserver](http://libvncserver.sourceforge.net/) or
[PocketVNC](http://www.pocketvnc.com/blog/?page_id=866)),
you need to use a WebSockets to TCP socket proxy. There is you need to use a WebSockets to TCP socket proxy. There is
a python proxy included ('websockify'). a python proxy included ('websockify').
@ -76,8 +77,9 @@ a python proxy included ('websockify').
### Other Pages ### Other Pages
* [Advanced Usage](https://github.com/kanaka/noVNC/wiki/Advanced-usage). Generating an SSL * [Encrypted Connections](https://github.com/kanaka/websockify/wiki/Encrypted-Connections). How to setup websockify so that you can use encrypted connections from noVNC.
certificate, starting a VNC server, advanced websockify usage, etc.
* [Advanced Usage](https://github.com/kanaka/noVNC/wiki/Advanced-usage). Starting a VNC server, advanced websockify usage, etc.
* [Integrating noVNC](https://github.com/kanaka/noVNC/wiki/Integration) into existing projects. * [Integrating noVNC](https://github.com/kanaka/noVNC/wiki/Integration) into existing projects.

@ -1,3 +1,10 @@
/*
* noVNC base CSS
* Copyright (C) 2012 Joel Martin
* noVNC is licensed under the LGPL-3 (see LICENSE.txt)
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
*/
body { body {
margin:0; margin:0;
padding:0; padding:0;

@ -1,3 +1,10 @@
/*
* noVNC base CSS
* Copyright (C) 2012 Joel Martin
* noVNC is licensed under the LGPL-3 (see LICENSE.txt)
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
*/
#keyboardinput { #keyboardinput {
background-color:#000; background-color:#000;
} }

@ -1,3 +1,9 @@
/*
* noVNC base CSS
* Copyright (C) 2012 Joel Martin
* noVNC is licensed under the LGPL-3 (see LICENSE.txt)
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
*/
#noVNC-control-bar { #noVNC-control-bar {
background-color:#04073d; background-color:#04073d;

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.
@ -19,9 +19,12 @@ var that = {}, // Public API methods
c_ctx = null, c_ctx = null,
c_forceCanvas = false, c_forceCanvas = false,
// Queued drawing actions for in-order rendering
renderQ = [],
// Predefine function variables (jslint) // Predefine function variables (jslint)
imageDataGet, rgbImageData, bgrxImageData, cmapImageData, imageDataGet, rgbImageData, bgrxImageData, cmapImageData,
setFillColor, rescale, setFillColor, rescale, scan_renderQ,
// The full frame buffer (logical canvas) size // The full frame buffer (logical canvas) size
fb_width = 0, fb_width = 0,
@ -412,6 +415,8 @@ that.clear = function() {
c_ctx.clearRect(0, 0, viewport.w, viewport.h); c_ctx.clearRect(0, 0, viewport.w, viewport.h);
} }
renderQ = [];
// No benefit over default ("source-over") in Chrome and firefox // No benefit over default ("source-over") in Chrome and firefox
//c_ctx.globalCompositeOperation = "copy"; //c_ctx.globalCompositeOperation = "copy";
}; };
@ -577,6 +582,58 @@ that.blitStringImage = function(str, x, y) {
img.src = str; img.src = str;
}; };
// Wrap ctx.drawImage but relative to viewport
that.drawImage = function(img, x, y) {
c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
};
that.renderQ_push = function(action) {
renderQ.push(action);
if (renderQ.length === 1) {
// If this can be rendered immediately it will be, otherwise
// the scanner will start polling the queue (every
// requestAnimationFrame interval)
scan_renderQ();
}
};
scan_renderQ = function() {
var a, ready = true;
while (ready && renderQ.length > 0) {
a = renderQ[0];
switch (a.type) {
case 'copy':
that.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height);
break;
case 'fill':
that.fillRect(a.x, a.y, a.width, a.height, a.color);
break;
case 'blit':
that.blitImage(a.x, a.y, a.width, a.height, a.data, 0);
break;
case 'blitRgb':
that.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0);
break;
case 'img':
if (a.img.complete) {
that.drawImage(a.img, a.x, a.y);
} else {
// We need to wait for this image to 'load'
// to keep things in-order
ready = false;
}
break;
}
if (ready) {
a = renderQ.shift();
}
}
if (renderQ.length > 0) {
requestAnimFrame(scan_renderQ);
}
};
that.changeCursor = function(pixels, mask, hotx, hoty, w, h) { that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
if (conf.cursor_uri === false) { if (conf.cursor_uri === false) {
Util.Warn("changeCursor called but no cursor data URI support"); Util.Warn("changeCursor called but no cursor data URI support");

@ -1167,14 +1167,14 @@ unicodeTable = {
0x21D4 : 0x08cd, 0x21D4 : 0x08cd,
0x21D2 : 0x08ce, 0x21D2 : 0x08ce,
0x2261 : 0x08cf, 0x2261 : 0x08cf,
0x221A : 0x08d6, //0x221A : 0x08d6,
0x2282 : 0x08da, 0x2282 : 0x08da,
0x2283 : 0x08db, 0x2283 : 0x08db,
0x2229 : 0x08dc, 0x2229 : 0x08dc,
0x222A : 0x08dd, 0x222A : 0x08dd,
0x2227 : 0x08de, 0x2227 : 0x08de,
0x2228 : 0x08df, 0x2228 : 0x08df,
0x2202 : 0x08ef, //0x2202 : 0x08ef,
0x0192 : 0x08f6, 0x0192 : 0x08f6,
0x2190 : 0x08fb, 0x2190 : 0x08fb,
0x2191 : 0x08fc, 0x2191 : 0x08fc,
@ -1509,7 +1509,7 @@ unicodeTable = {
0x012D : 0x100012d, 0x012D : 0x100012d,
0x01B6 : 0x10001b6, 0x01B6 : 0x10001b6,
0x01E7 : 0x10001e7, 0x01E7 : 0x10001e7,
0x01D2 : 0x10001d2, //0x01D2 : 0x10001d2,
0x0275 : 0x1000275, 0x0275 : 0x1000275,
0x018F : 0x100018f, 0x018F : 0x100018f,
0x0259 : 0x1000259, 0x0259 : 0x1000259,
@ -1908,4 +1908,4 @@ unicodeTable = {
0x28fd : 0x10028fd, 0x28fd : 0x10028fd,
0x28fe : 0x10028fe, 0x28fe : 0x10028fe,
0x28ff : 0x10028ff 0x28ff : 0x10028ff
}; };

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.LGPL-3) * Licensed under LGPL-3 (see LICENSE.LGPL-3)
*/ */

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.
@ -26,7 +26,7 @@ var that = {}, // Public API methods
pixelFormat, clientEncodings, fbUpdateRequest, fbUpdateRequests, pixelFormat, clientEncodings, fbUpdateRequest, fbUpdateRequests,
keyEvent, pointerEvent, clientCutText, keyEvent, pointerEvent, clientCutText,
getTightCLength, extract_data_uri, scan_tight_imgQ, getTightCLength, extract_data_uri,
keyPress, mouseButton, mouseMove, keyPress, mouseButton, mouseMove,
checkEvents, // Overridable for testing checkEvents, // Overridable for testing
@ -93,7 +93,6 @@ var that = {}, // Public API methods
encoding : 0, encoding : 0,
subencoding : -1, subencoding : -1,
background : null, background : null,
imgQ : [], // TIGHT_PNG image queue
zlibs : [] // TIGHT zlib streams zlibs : [] // TIGHT zlib streams
}, },
@ -103,7 +102,6 @@ var that = {}, // Public API methods
fb_height = 0, fb_height = 0,
fb_name = "", fb_name = "",
scan_imgQ_rate = 40, // 25 times per second or so
last_req_time = 0, last_req_time = 0,
rre_chunk_sz = 100, rre_chunk_sz = 100,
@ -144,6 +142,9 @@ Util.conf_defaults(conf, that, defaults, [
['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'], ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'],
['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'],
// UltraVNC repeater ID to connect to
['repeaterID', 'rw', 'str', '', 'RepeaterID to connect to'],
['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'], ['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'],
['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'], ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'],
@ -234,21 +235,28 @@ function constructor() {
} }
}); });
ws.on('close', function(e) { ws.on('close', function(e) {
Util.Warn("WebSocket on-close event");
var msg = "";
if (e.code) { if (e.code) {
Util.Info("Close code: " + e.code + ", reason: " + e.reason + ", wasClean: " + e.wasClean); msg = " (code: " + e.code;
if (e.reason) {
msg += ", reason: " + e.reason;
}
msg += ")";
} }
if (rfb_state === 'disconnect') { if (rfb_state === 'disconnect') {
updateState('disconnected', 'VNC disconnected'); updateState('disconnected', 'VNC disconnected' + msg);
} else if (rfb_state === 'ProtocolVersion') { } else if (rfb_state === 'ProtocolVersion') {
fail('Failed to connect to server'); fail('Failed to connect to server' + msg);
} else if (rfb_state in {'failed':1, 'disconnected':1}) { } else if (rfb_state in {'failed':1, 'disconnected':1}) {
Util.Error("Received onclose while disconnected"); Util.Error("Received onclose while disconnected" + msg);
} else { } else {
fail('Server disconnected'); fail('Server disconnected' + msg);
} }
}); });
ws.on('error', function(e) { ws.on('error', function(e) {
fail("WebSock error: " + e); Util.Warn("WebSocket on-error event");
//fail("WebSock reported an error");
}); });
@ -307,7 +315,6 @@ init_vars = function() {
FBU.subrects = 0; // RRE and HEXTILE FBU.subrects = 0; // RRE and HEXTILE
FBU.lines = 0; // RAW FBU.lines = 0; // RAW
FBU.tiles = 0; // HEXTILE FBU.tiles = 0; // HEXTILE
FBU.imgQ = []; // TIGHT_PNG image queue
FBU.zlibs = []; // TIGHT zlib encoders FBU.zlibs = []; // TIGHT zlib encoders
mouse_buttonMask = 0; mouse_buttonMask = 0;
mouse_arr = []; mouse_arr = [];
@ -419,16 +426,16 @@ updateState = function(state, statusMsg) {
func = Util.Warn; func = Util.Warn;
} }
cmsg = typeof(statusMsg) !== 'undefined' ? (" Msg: " + statusMsg) : "";
func("New state '" + state + "', was '" + oldstate + "'." + cmsg);
if ((oldstate === 'failed') && (state === 'disconnected')) { if ((oldstate === 'failed') && (state === 'disconnected')) {
// Do disconnect action, but stay in failed state. // Do disconnect action, but stay in failed state
rfb_state = 'failed'; rfb_state = 'failed';
} else { } else {
rfb_state = state; rfb_state = state;
} }
cmsg = typeof(statusMsg) !== 'undefined' ? (" Msg: " + statusMsg) : "";
func("New state '" + rfb_state + "', was '" + oldstate + "'." + cmsg);
if (connTimer && (rfb_state !== 'connect')) { if (connTimer && (rfb_state !== 'connect')) {
Util.Debug("Clearing connect timer"); Util.Debug("Clearing connect timer");
clearInterval(connTimer); clearInterval(connTimer);
@ -655,10 +662,10 @@ mouseMove = function(x, y) {
init_msg = function() { init_msg = function() {
//Util.Debug(">> init_msg [rfb_state '" + rfb_state + "']"); //Util.Debug(">> init_msg [rfb_state '" + rfb_state + "']");
var strlen, reason, length, sversion, cversion, var strlen, reason, length, sversion, cversion, repeaterID,
i, types, num_types, challenge, response, bpp, depth, i, types, num_types, challenge, response, bpp, depth,
big_endian, red_max, green_max, blue_max, red_shift, big_endian, red_max, green_max, blue_max, red_shift,
green_shift, blue_shift, true_color, name_length; green_shift, blue_shift, true_color, name_length, is_repeater;
//Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0)); //Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0));
switch (rfb_state) { switch (rfb_state) {
@ -669,16 +676,27 @@ init_msg = function() {
} }
sversion = ws.rQshiftStr(12).substr(4,7); sversion = ws.rQshiftStr(12).substr(4,7);
Util.Info("Server ProtocolVersion: " + sversion); Util.Info("Server ProtocolVersion: " + sversion);
is_repeater = 0;
switch (sversion) { switch (sversion) {
case "000.000": is_repeater = 1; break; // UltraVNC repeater
case "003.003": rfb_version = 3.3; break; case "003.003": rfb_version = 3.3; break;
case "003.006": rfb_version = 3.3; break; // UltraVNC case "003.006": rfb_version = 3.3; break; // UltraVNC
case "003.889": rfb_version = 3.3; break; // Apple Remote Desktop case "003.889": rfb_version = 3.3; break; // Apple Remote Desktop
case "003.007": rfb_version = 3.7; break; case "003.007": rfb_version = 3.7; break;
case "003.008": rfb_version = 3.8; break; case "003.008": rfb_version = 3.8; break;
case "004.000": rfb_version = 3.8; break; // Intel AMT KVM case "004.000": rfb_version = 3.8; break; // Intel AMT KVM
case "004.001": rfb_version = 3.8; break; // RealVNC 4.6
default: default:
return fail("Invalid server version " + sversion); return fail("Invalid server version " + sversion);
} }
if (is_repeater) {
repeaterID = conf.repeaterID;
while (repeaterID.length < 250) {
repeaterID += "\0";
}
ws.send_string(repeaterID);
break;
}
if (rfb_version > rfb_max_version) { if (rfb_version > rfb_max_version) {
rfb_version = rfb_max_version; rfb_version = rfb_max_version;
} }
@ -876,11 +894,11 @@ init_msg = function() {
response = response.concat(clientEncodings()); response = response.concat(clientEncodings());
response = response.concat(fbUpdateRequests()); response = response.concat(fbUpdateRequests());
timing.fbu_rt_start = (new Date()).getTime(); timing.fbu_rt_start = (new Date()).getTime();
timing.pixels = 0;
ws.send(response); ws.send(response);
/* Start pushing/polling */ /* Start pushing/polling */
setTimeout(checkEvents, conf.check_rate); setTimeout(checkEvents, conf.check_rate);
setTimeout(scan_tight_imgQ, scan_imgQ_rate);
if (conf.encrypt) { if (conf.encrypt) {
updateState('normal', "Connected (encrypted) to: " + fb_name); updateState('normal', "Connected (encrypted) to: " + fb_name);
@ -1027,7 +1045,7 @@ framebufferUpdate = function() {
timing.pixels += FBU.width * FBU.height; timing.pixels += FBU.width * FBU.height;
} }
if (FBU.rects === 0 || (timing.pixels >= (fb_width * fb_height))) { if (timing.pixels >= (fb_width * fb_height)) {
if (((FBU.width === fb_width) && if (((FBU.width === fb_width) &&
(FBU.height === fb_height)) || (FBU.height === fb_height)) ||
(timing.fbu_rt_start > 0)) { (timing.fbu_rt_start > 0)) {
@ -1105,9 +1123,14 @@ encHandlers.COPYRECT = function display_copy_rect() {
var old_x, old_y; var old_x, old_y;
if (ws.rQwait("COPYRECT", 4)) { return false; } if (ws.rQwait("COPYRECT", 4)) { return false; }
old_x = ws.rQshift16(); display.renderQ_push({
old_y = ws.rQshift16(); 'type': 'copy',
display.copyImage(old_x, old_y, FBU.x, FBU.y, FBU.width, FBU.height); 'old_x': ws.rQshift16(),
'old_y': ws.rQshift16(),
'x': FBU.x,
'y': FBU.y,
'width': FBU.width,
'height': FBU.height});
FBU.rects -= 1; FBU.rects -= 1;
FBU.bytes = 0; FBU.bytes = 0;
return true; return true;
@ -1401,9 +1424,9 @@ function display_tight(isTightPNG) {
} }
} }
FBU.imgQ.push({ display.renderQ_push({
'type': 'rgb', 'type': 'blitRgb',
'img': {'complete': true, 'data': dest}, 'data': dest,
'x': FBU.x, 'x': FBU.x,
'y': FBU.y, 'y': FBU.y,
'width': FBU.width, 'width': FBU.width,
@ -1432,9 +1455,9 @@ function display_tight(isTightPNG) {
data = decompress(ws.rQshiftBytes(clength[1])); data = decompress(ws.rQshiftBytes(clength[1]));
} }
FBU.imgQ.push({ display.renderQ_push({
'type': 'rgb', 'type': 'blitRgb',
'img': {'complete': true, 'data': data}, 'data': data,
'x': FBU.x, 'x': FBU.x,
'y': FBU.y, 'y': FBU.y,
'width': FBU.width, 'width': FBU.width,
@ -1456,10 +1479,10 @@ function display_tight(isTightPNG) {
else if (ctl === 0x0A) cmode = "png"; else if (ctl === 0x0A) cmode = "png";
else if (ctl & 0x04) cmode = "filter"; else if (ctl & 0x04) cmode = "filter";
else if (ctl < 0x04) cmode = "copy"; else if (ctl < 0x04) cmode = "copy";
else throw("Illegal tight compression received, ctl: " + ctl); else return fail("Illegal tight compression received, ctl: " + ctl);
if (isTightPNG && (cmode === "filter" || cmode === "copy")) { if (isTightPNG && (cmode === "filter" || cmode === "copy")) {
throw("filter/copy received in tightPNG mode"); return fail("filter/copy received in tightPNG mode");
} }
switch (cmode) { switch (cmode) {
@ -1481,9 +1504,8 @@ function display_tight(isTightPNG) {
case "fill": case "fill":
ws.rQshift8(); // shift off ctl ws.rQshift8(); // shift off ctl
color = ws.rQshiftBytes(fb_depth); color = ws.rQshiftBytes(fb_depth);
FBU.imgQ.push({ display.renderQ_push({
'type': 'fill', 'type': 'fill',
'img': {'complete': true},
'x': FBU.x, 'x': FBU.x,
'y': FBU.y, 'y': FBU.y,
'width': FBU.width, 'width': FBU.width,
@ -1501,14 +1523,13 @@ function display_tight(isTightPNG) {
// clength[0] + ", clength[1]: " + clength[1]); // clength[0] + ", clength[1]: " + clength[1]);
ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length
img = new Image(); img = new Image();
//img.onload = scan_tight_imgQ; img.src = "data:image/" + cmode +
FBU.imgQ.push({ extract_data_uri(ws.rQshiftBytes(clength[1]));
display.renderQ_push({
'type': 'img', 'type': 'img',
'img': img, 'img': img,
'x': FBU.x, 'x': FBU.x,
'y': FBU.y}); 'y': FBU.y});
img.src = "data:image/" + cmode +
extract_data_uri(ws.rQshiftBytes(clength[1]));
img = null; img = null;
break; break;
case "filter": case "filter":
@ -1542,32 +1563,13 @@ extract_data_uri = function(arr) {
return ";base64," + Base64.encode(arr); return ";base64," + Base64.encode(arr);
}; };
scan_tight_imgQ = function() {
var data, imgQ, ctx;
ctx = display.get_context();
if (rfb_state === 'normal') {
imgQ = FBU.imgQ;
while ((imgQ.length > 0) && (imgQ[0].img.complete)) {
data = imgQ.shift();
if (data.type === 'fill') {
display.fillRect(data.x, data.y, data.width, data.height, data.color);
} else if (data.type === 'rgb') {
display.blitRgbImage(data.x, data.y, data.width, data.height, data.img.data, 0);
} else {
ctx.drawImage(data.img, data.x, data.y);
}
}
setTimeout(scan_tight_imgQ, scan_imgQ_rate);
}
};
encHandlers.TIGHT = function () { return display_tight(false); }; encHandlers.TIGHT = function () { return display_tight(false); };
encHandlers.TIGHT_PNG = function () { return display_tight(true); }; encHandlers.TIGHT_PNG = function () { return display_tight(true); };
encHandlers.last_rect = function last_rect() { encHandlers.last_rect = function last_rect() {
Util.Debug(">> set_desktopsize"); //Util.Debug(">> last_rect");
FBU.rects = 0; FBU.rects = 0;
Util.Debug("<< set_desktopsize"); //Util.Debug("<< last_rect");
return true; return true;
}; };
@ -1589,7 +1591,7 @@ encHandlers.DesktopSize = function set_desktopsize() {
encHandlers.Cursor = function set_cursor() { encHandlers.Cursor = function set_cursor() {
var x, y, w, h, pixelslength, masklength; var x, y, w, h, pixelslength, masklength;
//Util.Debug(">> set_cursor"); Util.Debug(">> set_cursor");
x = FBU.x; // hotspot-x x = FBU.x; // hotspot-x
y = FBU.y; // hotspot-y y = FBU.y; // hotspot-y
w = FBU.width; w = FBU.width;
@ -1610,7 +1612,7 @@ encHandlers.Cursor = function set_cursor() {
FBU.bytes = 0; FBU.bytes = 0;
FBU.rects -= 1; FBU.rects -= 1;
//Util.Debug("<< set_cursor"); Util.Debug("<< set_cursor");
return true; return true;
}; };

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.
@ -55,6 +55,7 @@ load: function() {
UI.initSetting('view_only', false); UI.initSetting('view_only', false);
UI.initSetting('connectTimeout', 2); UI.initSetting('connectTimeout', 2);
UI.initSetting('path', 'websockify'); UI.initSetting('path', 'websockify');
UI.initSetting('repeaterID', '');
UI.rfb = RFB({'target': $D('noVNC_canvas'), UI.rfb = RFB({'target': $D('noVNC_canvas'),
'onUpdateState': UI.updateState, 'onUpdateState': UI.updateState,
@ -270,6 +271,7 @@ toggleSettingsPanel: function() {
UI.updateSetting('view_only'); UI.updateSetting('view_only');
UI.updateSetting('connectTimeout'); UI.updateSetting('connectTimeout');
UI.updateSetting('path'); UI.updateSetting('path');
UI.updateSetting('repeaterID');
UI.updateSetting('stylesheet'); UI.updateSetting('stylesheet');
UI.updateSetting('logging'); UI.updateSetting('logging');
@ -313,6 +315,7 @@ settingsApply: function() {
UI.saveSetting('view_only'); UI.saveSetting('view_only');
UI.saveSetting('connectTimeout'); UI.saveSetting('connectTimeout');
UI.saveSetting('path'); UI.saveSetting('path');
UI.saveSetting('repeaterID');
UI.saveSetting('stylesheet'); UI.saveSetting('stylesheet');
UI.saveSetting('logging'); UI.saveSetting('logging');
@ -427,6 +430,7 @@ updateVisualState: function() {
$D('noVNC_view_only').disabled = connected; $D('noVNC_view_only').disabled = connected;
$D('noVNC_connectTimeout').disabled = connected; $D('noVNC_connectTimeout').disabled = connected;
$D('noVNC_path').disabled = connected; $D('noVNC_path').disabled = connected;
$D('noVNC_repeaterID').disabled = connected;
if (connected) { if (connected) {
UI.setViewClip(); UI.setViewClip();
@ -489,8 +493,10 @@ connect: function() {
UI.rfb.set_shared(UI.getSetting('shared')); UI.rfb.set_shared(UI.getSetting('shared'));
UI.rfb.set_view_only(UI.getSetting('view_only')); UI.rfb.set_view_only(UI.getSetting('view_only'));
UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout')); UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout'));
UI.rfb.set_repeaterID(UI.getSetting('repeaterID'));
UI.rfb.connect(host, port, password, path); UI.rfb.connect(host, port, password, path);
//Close dialog. //Close dialog.
setTimeout(UI.setBarPosition, 100); setTimeout(UI.setBarPosition, 100);
$D('noVNC_logo').style.display = "none"; $D('noVNC_logo').style.display = "none";

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.
@ -57,6 +57,21 @@ if (!Array.prototype.map)
}; };
} }
//
// requestAnimationFrame shim with setTimeout fallback
//
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
/* /*
* ------------------------------------------------------ * ------------------------------------------------------
* Namespaced in Util * Namespaced in Util
@ -131,6 +146,8 @@ Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) {
} }
} else if (type in {'integer':1, 'int':1}) { } else if (type in {'integer':1, 'int':1}) {
val = parseInt(val, 10); val = parseInt(val, 10);
} else if (type === 'str') {
val = String(val);
} else if (type === 'func') { } else if (type === 'func') {
if (!val) { if (!val) {
val = function () {}; val = function () {};

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.

@ -5,7 +5,7 @@
(function() { (function() {
if (window.WebSocket) return; if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) return;
var console = window.console; var console = window.console;
if (!console || !console.log || !console.error) { if (!console || !console.log || !console.error) {

@ -1,6 +1,6 @@
/* /*
* Websock: high-performance binary WebSockets * Websock: high-performance binary WebSockets
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* Websock is similar to the standard WebSocket object but Websock * Websock is similar to the standard WebSocket object but Websock
@ -20,6 +20,11 @@
// Load Flash WebSocket emulator if needed // Load Flash WebSocket emulator if needed
// To force WebSocket emulator even when native WebSocket available
//window.WEB_SOCKET_FORCE_FLASH = true;
// To enable WebSocket emulator debug:
//window.WEB_SOCKET_DEBUG=1;
if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) { if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
Websock_native = true; Websock_native = true;
} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) { } else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
@ -28,9 +33,6 @@ if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
} else { } else {
/* no builtin WebSocket so load web_socket.js */ /* no builtin WebSocket so load web_socket.js */
// To enable debug:
// window.WEB_SOCKET_DEBUG=1;
Websock_native = false; Websock_native = false;
(function () { (function () {
function get_INCLUDE_URI() { function get_INCLUDE_URI() {
@ -280,6 +282,8 @@ function open(uri) {
Util.Debug(">> WebSock.onopen"); Util.Debug(">> WebSock.onopen");
if (websocket.protocol) { if (websocket.protocol) {
Util.Info("Server chose sub-protocol: " + websocket.protocol); Util.Info("Server chose sub-protocol: " + websocket.protocol);
} else {
Util.Error("Server select no sub-protocol!: " + websocket.protocol);
} }
eventHandlers.open(); eventHandlers.open();
Util.Debug("<< WebSock.onopen"); Util.Debug("<< WebSock.onopen");

@ -1,6 +1,6 @@
/* /*
* noVNC: HTML5 VNC client * noVNC: HTML5 VNC client
* Copyright (C) 2011 Joel Martin * Copyright (C) 2012 Joel Martin
* Licensed under LGPL-3 (see LICENSE.txt) * Licensed under LGPL-3 (see LICENSE.txt)
* *
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.

@ -2,10 +2,11 @@
<html> <html>
<head> <head>
<!-- <!--
noVNC example: simple example using default UI noVNC example: simple example using default UI
Copyright (C) 2011 Joel Martin Copyright (C) 2012 Joel Martin
Licensed under LGPL-3 (see LICENSE.txt) noVNC is licensed under the LGPL-3 (see LICENSE.txt)
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
--> -->
<title>noVNC</title> <title>noVNC</title>
@ -140,6 +141,7 @@
<li><input id="noVNC_view_only" type="checkbox"> View Only</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_connectTimeout" type="input"> Connect Timeout (s)</li>
<li><input id="noVNC_path" type="input" value="websockify"> Path</li> <li><input id="noVNC_path" type="input" value="websockify"> Path</li>
<li><input id="noVNC_repeaterID" type="input" value=""> Repeater ID</li>
<hr> <hr>
<!-- Stylesheet selection dropdown --> <!-- Stylesheet selection dropdown -->
<li><label><strong>Style: </strong> <li><label><strong>Style: </strong>

@ -1,9 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<!-- <!--
noVNC Example: Automatically connect on page load. noVNC example: simple example using default UI
Copyright (C) 2011 Joel Martin Copyright (C) 2012 Joel Martin
Licensed under LGPL-3 (see LICENSE.txt) noVNC is licensed under the LGPL-3 (see LICENSE.txt)
This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
Connect parameters are provided in query string: Connect parameters are provided in query string:
http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1 http://example.com/?host=HOST&port=PORT&encrypt=1&true_color=1
@ -103,6 +104,7 @@
password = WebUtil.getQueryVar('password', ''); password = WebUtil.getQueryVar('password', '');
path = WebUtil.getQueryVar('path', 'websockify'); path = WebUtil.getQueryVar('path', 'websockify');
if ((!host) || (!port)) { if ((!host) || (!port)) {
updateState('failed', updateState('failed',
"Must specify host and port in URL"); "Must specify host and port in URL");
@ -112,6 +114,7 @@
rfb = new RFB({'target': $D('noVNC_canvas'), rfb = new RFB({'target': $D('noVNC_canvas'),
'encrypt': WebUtil.getQueryVar('encrypt', 'encrypt': WebUtil.getQueryVar('encrypt',
(window.location.protocol === "https:")), (window.location.protocol === "https:")),
'repeaterID': WebUtil.getQueryVar('repeaterID', ''),
'true_color': WebUtil.getQueryVar('true_color', true), 'true_color': WebUtil.getQueryVar('true_color', true),
'local_cursor': WebUtil.getQueryVar('cursor', true), 'local_cursor': WebUtil.getQueryVar('cursor', true),
'shared': WebUtil.getQueryVar('shared', true), 'shared': WebUtil.getQueryVar('shared', true),

Loading…
Cancel
Save