Merge remote branch 'upstream/master'

Conflicts:
	include/canvas.js
	include/rfb.js
	include/util.js
	vnc.html
This commit is contained in:
primalmotion 2010-08-03 10:11:03 +02:00
commit 5e5d81dd86
11 changed files with 1629 additions and 1526 deletions

View File

@ -195,7 +195,7 @@ The client is designed to be easily integrated with existing web
structure and style.
At a minimum you must include the `vnc.js` and `default_controls.js`
scripts and call their load() functions. For example:
scripts and call DefaultControls.load(). For example:
<head>
<script src='include/vnc.js'></script>
@ -203,12 +203,13 @@ scripts and call their load() functions. For example:
</head>
<body>
<div id='vnc'>Loading</div>
<script>
window.onload = function () {
DefaultControls.load('vnc');
}
</script>
</body>
<script>
window.onload = function () {
DefaultControls.load('vnc');
RFB.load(); };
</script>
See `vnc.html` and `vnc_auto.html` for examples. The file
`include/plain.css` has a list of stylable elements.

View File

@ -10,38 +10,22 @@ Short Term:
- Test on IE 9 preview 3.
- Possibly support IE <= 8.0 using excanvas or fxcanvas:
http://excanvas.sourceforge.net/
http://code.google.com/p/fxcanvas/
- Fix cursor URI detection in Arora:
- allows data URI, but doesn't actually work
Medium Term:
- Viewport and/or scaling support.
- Viewport support
- Status bar buttons:
- Isolate menu UI in DefaultControls.js
- Icons in status area upper left
- Dialogs float over canvas
- Turn off events while menu open (but still update display)
- Status bar menu/buttons:
- Explanatory hover text over buttons
- Connect/disconnect button
- Configuration menu:
- Store in cookies
- Items (move to public settings):
- Host
- Port
- Password
- Encrypt
- TrueColor
- speed vs. bandwidth selection
- b64encoding
- shared mode
- Tunable: speed vs. bandwidth selection
- Tunable: CPU use versus latency.
- shared mode
- Scaling
- Keyboard menu:
- Ctrl Lock, Alt Lock, SysRq Lock
@ -50,10 +34,6 @@ Medium Term:
- Clipboard button -> popup:
- text, clear and send buttons
- password popup:
- when none set, but password required
- session only, should not store in cookie
Longer Term:

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
* See README.md for usage and integration instructions.
*/
"use strict";
/*jslint white: false */
/*global $, Util, RFB, Canvas, VNC_uri_prefix, Element, Fx */
var DefaultControls = {
@ -16,10 +17,6 @@ settingsOpen : false,
load: function(target) {
var html, i, DC = DefaultControls, sheet, sheets, llevels;
/* Handle state updates */
RFB.setUpdateState(DC.updateState);
RFB.setClipboardReceive(DC.clipReceive);
/* Populate the 'target' DOM element with default controls */
if (!target) { target = 'vnc'; }
@ -61,7 +58,7 @@ load: function(target) {
html += ' <option value="default">default</option>';
sheet = Util.selectStylesheet();
sheets = Util.getStylesheets();
for (i = 0; i < sheets.length; i++) {
for (i = 0; i < sheets.length; i += 1) {
html += '<option value="' + sheets[i].title + '">' + sheets[i].title + '</option>';
}
html += ' </select> Style</li>';
@ -69,7 +66,7 @@ load: function(target) {
// Logging selection dropdown
html += ' <li><select id="VNC_logging" name="vncLogging">';
llevels = ['error', 'warn', 'info', 'debug'];
for (i = 0; i < llevels.length; i++) {
for (i = 0; i < llevels.length; i += 1) {
html += '<option value="' + llevels[i] + '">' + llevels[i] + '</option>';
}
html += ' </select> Logging</li>';
@ -107,6 +104,8 @@ load: function(target) {
DC.initSetting('logging', 'warn');
Util.init_logging(DC.getSetting('logging'));
DC.initSetting('stylesheet', 'default');
Util.selectStylesheet(null); // call twice to get around webkit bug
Util.selectStylesheet(DC.getSetting('stylesheet'));
/* Populate the controls if defaults are provided in the URL */
@ -118,12 +117,19 @@ load: function(target) {
DC.initSetting('true_color', true);
DC.initSetting('cursor', true);
DC.rfb = RFB({'target': 'VNC_canvas',
'updateState': DC.updateState,
'clipboardReceive': DC.clipReceive});
DC.rfb.init();
// Unfocus clipboard when over the VNC area
$('VNC_screen').onmousemove = function () {
// Unfocus clipboard when over the VNC area
if (! Canvas.focused) {
var canvas = DC.rfb.get_canvas();
if ((! canvas) || (! canvas.get_focused())) {
$('VNC_clipboard_text').blur();
}
};
},
// Read form control compatible setting from cookie
@ -154,7 +160,7 @@ updateSetting: function(name, value) {
if (ctrl.type === 'checkbox') {
ctrl.checked = value;
} else if (typeof ctrl.options !== 'undefined') {
for (i = 0; i < ctrl.options.length; i++) {
for (i = 0; i < ctrl.options.length; i += 1) {
if (ctrl.options[i].value === value) {
ctrl.selectedIndex = i;
break;
@ -176,7 +182,7 @@ saveSetting: function(name) {
val = ctrl.value;
}
Util.createCookie(name, val);
Util.Debug("Setting saved '" + name + "=" + val + "'");
//Util.Debug("Setting saved '" + name + "=" + val + "'");
return val;
},
@ -190,7 +196,7 @@ initSetting: function(name, defVal) {
val = Util.readCookie(name, defVal);
}
DefaultControls.updateSetting(name, val);
Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
//Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
return val;
},
@ -208,7 +214,7 @@ clickSettingsMenu: function() {
DC.updateSetting('encrypt');
DC.updateSetting('base64');
DC.updateSetting('true_color');
if (Canvas.isCursor()) {
if (DC.rfb.get_canvas().get_cursor_uri()) {
DC.updateSetting('cursor');
} else {
DC.updateSetting('cursor', false);
@ -235,10 +241,11 @@ closeSettingsMenu: function() {
// Disable/enable controls depending on connection state
settingsDisabled: function(disabled) {
var DC = DefaultControls;
$('VNC_encrypt').disabled = disabled;
$('VNC_base64').disabled = disabled;
$('VNC_true_color').disabled = disabled;
if (Canvas.isCursor()) {
if (DC.rfb && DC.rfb.get_canvas().get_cursor_uri()) {
$('VNC_cursor').disabled = disabled;
} else {
DefaultControls.updateSetting('cursor', false);
@ -248,12 +255,12 @@ settingsDisabled: function(disabled) {
// Save/apply settings when 'Apply' button is pressed
settingsApply: function() {
Util.Debug(">> settingsApply");
//Util.Debug(">> settingsApply");
var DC = DefaultControls;
DC.saveSetting('encrypt');
DC.saveSetting('base64');
DC.saveSetting('true_color');
if (Canvas.isCursor()) {
if (DC.rfb.get_canvas().get_cursor_uri()) {
DC.saveSetting('cursor');
}
DC.saveSetting('stylesheet');
@ -263,21 +270,21 @@ settingsApply: function() {
Util.selectStylesheet(DC.getSetting('stylesheet'));
Util.init_logging(DC.getSetting('logging'));
Util.Debug("<< settingsApply");
//Util.Debug("<< settingsApply");
},
setPassword: function() {
RFB.sendPassword($('VNC_password').value);
DefaultControls.rfb.sendPassword($('VNC_password').value);
return false;
},
sendCtrlAltDel: function() {
RFB.sendCtrlAltDel();
DefaultControls.rfb.sendCtrlAltDel();
},
updateState: function(state, msg) {
updateState: function(rfb, state, oldstate, msg) {
var s, sb, c, cad, klass;
s = $('VNC_status');
sb = $('VNC_status_bar');
@ -334,6 +341,13 @@ updateState: function(state, msg) {
},
clipReceive: function(rfb, text) {
Util.Debug(">> DefaultControls.clipReceive: " + text.substr(0,40) + "...");
$('VNC_clipboard_text').value = text;
Util.Debug("<< DefaultControls.clipReceive");
},
connect: function() {
var host, port, password, DC = DefaultControls;
@ -346,43 +360,37 @@ connect: function() {
throw("Must set host and port");
}
RFB.setEncrypt(DC.getSetting('encrypt'));
RFB.setBase64(DC.getSetting('base64'));
RFB.setTrueColor(DC.getSetting('true_color'));
RFB.setCursor(DC.getSetting('cursor'));
DC.rfb.set_encrypt(DC.getSetting('encrypt'));
DC.rfb.set_b64encode(DC.getSetting('base64'));
DC.rfb.set_true_color(DC.getSetting('true_color'));
DC.rfb.set_local_cursor(DC.getSetting('cursor'));
RFB.connect(host, port, password);
DC.rfb.connect(host, port, password);
},
disconnect: function() {
DefaultControls.closeSettingsMenu();
RFB.disconnect();
DefaultControls.rfb.disconnect();
},
canvasBlur: function() {
Canvas.focused = false;
DefaultControls.rfb.get_canvas().set_focused(false);
},
canvasFocus: function() {
Canvas.focused = true;
DefaultControls.rfb.get_canvas().set_focused(true);
},
clipClear: function() {
$('VNC_clipboard_text').value = "";
RFB.clipboardPasteFrom("");
},
clipReceive: function(text) {
Util.Debug(">> DefaultControls.clipReceive: " + text.substr(0,40) + "...");
$('VNC_clipboard_text').value = text;
Util.Debug("<< DefaultControls.clipReceive");
DefaultControls.rfb.clipboardPasteFrom("");
},
clipSend: function() {
var text = $('VNC_clipboard_text').value;
Util.Debug(">> DefaultControls.clipSend: " + text.substr(0,40) + "...");
RFB.clipboardPasteFrom(text);
DefaultControls.rfb.clipboardPasteFrom(text);
Util.Debug("<< DefaultControls.clipSend");
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
* See README.md for usage and integration instructions.
*/
//"use strict";
"use strict";
/*jslint bitwise: false, white: false */
/*global window, document, navigator, ActiveXObject*/
@ -14,38 +14,6 @@
Util = {};
/*
* Logging/debug routines
*/
Util.init_logging = function (level) {
if (typeof window.console === "undefined") {
if (typeof window.opera !== "undefined") {
window.console = {
'log' : window.opera.postError,
'warn' : window.opera.postError,
'error': window.opera.postError };
} else {
window.console = {
'log' : function(m) {},
'warn' : function(m) {},
'error': function(m) {}};
}
}
Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
switch (level) {
case 'none': break;
case 'debug': Util.Debug = function (msg) { console.log(msg); };
case 'info': Util.Info = function (msg) { console.log(msg); };
case 'warn': Util.Warn = function (msg) { console.warn(msg); };
case 'error': Util.Error = function (msg) { console.error(msg); };
break;
default:
throw("invalid logging type '" + level + "'");
}
}
/*
* Simple DOM selector by ID
*/
@ -135,6 +103,42 @@ Array.prototype.shiftBytes = function (len) {
* ------------------------------------------------------
*/
/*
* Logging/debug routines
*/
Util.init_logging = function (level) {
if (typeof window.console === "undefined") {
if (typeof window.opera !== "undefined") {
window.console = {
'log' : window.opera.postError,
'warn' : window.opera.postError,
'error': window.opera.postError };
} else {
window.console = {
'log' : function(m) {},
'warn' : function(m) {},
'error': function(m) {}};
}
}
Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
switch (level) {
case 'debug': Util.Debug = function (msg) { console.log(msg); };
case 'info': Util.Info = function (msg) { console.log(msg); };
case 'warn': Util.Warn = function (msg) { console.warn(msg); };
case 'error': Util.Error = function (msg) { console.error(msg); };
case 'none':
break;
default:
throw("invalid logging type '" + level + "'");
}
};
// Initialize logging level
Util.init_logging( (document.location.href.match(
/logging=([A-Za-z0-9\._\-]*)/) ||
['', 'warn'])[1] );
Util.dirObj = function (obj, depth, parent) {
var i, msg = "", val = "";
if (! depth) { depth=2; }
@ -157,6 +161,41 @@ Util.dirObj = function (obj, depth, parent) {
return msg;
};
// Read a query string variable
Util.getQueryVar = function(name, defVal) {
var re = new RegExp('[?][^#]*' + name + '=([^&#]*)');
if (typeof defVal === 'undefined') { defVal = null; }
return (document.location.href.match(re) || ['',defVal])[1];
};
// Set defaults for Crockford style function namespaces
Util.conf_default = function(cfg, api, v, val, force_bool) {
if (typeof cfg[v] === 'undefined') {
cfg[v] = val;
}
// Default getter
if (typeof api['get_' + v] === 'undefined') {
api['get_' + v] = function () {
return cfg[v];
};
}
// Default setter
if (typeof api['set_' + v] === 'undefined') {
api['set_' + v] = function (val) {
if (force_bool) {
if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
val = false;
} else {
val = true;
}
}
cfg[v] = val;
};
}
};
/*
* Cross-browser routines
*/
@ -276,12 +315,11 @@ Util.createCookie = function(name,value,days) {
};
Util.readCookie = function(name, defaultValue) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
var i, c, nameEQ = name + "=", ca = document.cookie.split(';');
for(i=0; i < ca.length; i += 1) {
c = ca[i];
while (c.charAt(0) === ' ') { c = c.substring(1,c.length); }
if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
}
return (typeof defaultValue !== 'undefined') ? defaultValue : null;
};
@ -294,8 +332,8 @@ Util.eraseCookie = function(name) {
* Alternate stylesheet selection
*/
Util.getStylesheets = function() { var i, links, sheets = [];
links = document.getElementsByTagName("link")
for (i = 0; i < links.length; i++) {
links = document.getElementsByTagName("link");
for (i = 0; i < links.length; i += 1) {
if (links[i].title &&
links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) {
sheets.push(links[i]);
@ -311,17 +349,15 @@ Util.selectStylesheet = function(sheet) {
if (typeof sheet === 'undefined') {
sheet = 'default';
}
for (i=0; i < sheets.length; i++) {
for (i=0; i < sheets.length; i += 1) {
link = sheets[i];
if (link.title === sheet) {
Util.Debug("Using stylesheet " + sheet);
link.disabled = false;
} else {
Util.Debug("Skipping stylesheet " + link.title);
//Util.Debug("Skipping stylesheet " + link.title);
link.disabled = true;
}
}
return sheet;
};

View File

@ -46,14 +46,16 @@
}
function test_functions () {
var img, x, y;
Canvas.fillRect(0, 0, Canvas.c_wx, Canvas.c_wy, [240,240,240]);
var img, x, y, w, h, ctx = canvas.getContext();
w = canvas.get_width();
h = canvas.get_height();
canvas.fillRect(0, 0, w, h, [240,240,240]);
Canvas.blitStringImage("data:image/png;base64," + face64, 150, 10);
canvas.blitStringImage("data:image/png;base64," + face64, 150, 10);
var himg = new Image();
himg.onload = function () {
Canvas.ctx.drawImage(himg, 200, 40); };
ctx.drawImage(himg, 200, 40); };
himg.src = "face.png";
/* Test array image data */
@ -66,15 +68,14 @@
data[(y*50 + x)*4 + 3] = 255;
}
}
Canvas.blitImage(30, 10, 50, 50, data, 0);
canvas.blitImage(30, 10, 50, 50, data, 0);
//Canvas.prefer_js = false;
img = Canvas.getTile(5,5,16,16,[0,128,128]);
Canvas.putTile(img);
img = canvas.getTile(5,5,16,16,[0,128,128]);
canvas.putTile(img);
img = Canvas.getTile(90,15,16,16,[0,0,0]);
Canvas.setSubTile(img, 0,0,16,16,[128,128,0]);
Canvas.putTile(img);
img = canvas.getTile(90,15,16,16,[0,0,0]);
canvas.setSubTile(img, 0,0,16,16,[128,128,0]);
canvas.putTile(img);
}
function begin () {
@ -85,30 +86,35 @@
}
function start_delayed () {
var ret;
message("Running test: prefer Javascript");
Canvas.prefer_js = true;
var time1 = run_test();
message("prefer Javascript: " + time1 + "ms total, " +
(time1 / iterations) + "ms per frame");
ret = canvas.set_prefer_js(true);
if (ret) {
message("Running test: prefer Javascript ops");
var time1 = run_test();
message("prefer Javascript ops: " + time1 + "ms total, " +
(time1 / iterations) + "ms per frame");
} else {
message("Could not run: prefer Javascript ops");
}
canvas.set_prefer_js(false);
message("Running test: prefer Canvas ops");
Canvas.prefer_js = false;
var time2 = run_test();
message("prefer Canvas ops: " + time2 + "ms total, " +
(time2 / iterations) + "ms per frame");
Canvas.resize(start_width, start_height, true);
canvas.resize(start_width, start_height, true);
test_functions();
$('startButton').disabled = false;
$('startButton').value = "Start";
$('startButton').value = "Do Performance Test";
}
function run_test () {
var width, height;
width = $('width').value;
height = $('height').value;
Canvas.resize(width, height);
canvas.resize(width, height);
var color, start_time = (new Date()).getTime(), w, h;
for (var i=0; i < iterations; i++) {
color = [128, 128, (255 / iterations) * i, 0];
@ -116,9 +122,9 @@
for (var y=0; y < height; y = y + 16) {
w = Math.min(16, width - x);
h = Math.min(16, height - y);
var tile = Canvas.getTile(x, y, w, h, color);
Canvas.setSubTile(tile, 0, 0, w, h, color);
Canvas.putTile(tile);
var tile = canvas.getTile(x, y, w, h, color);
canvas.setSubTile(tile, 0, 0, w, h, color);
canvas.putTile(tile);
}
}
}
@ -129,8 +135,8 @@
window.onload = function() {
message("in onload");
$('iterations').value = 10;
Canvas.init('canvas');
Canvas.resize(start_width, start_height, true);
canvas = Canvas({'target' : 'canvas'});
canvas.resize(start_width, start_height, true);
message("Canvas initialized");
test_functions();
}

View File

@ -105,10 +105,10 @@
window.onload = function() {
debug("onload");
var cross, cursor, cursor64;
var canvas, cross, cursor, cursor64;
Canvas.init("testcanvas");
debug("Canvas.init() indicates Data URI cursor support is: " + Canvas.isCursor());
canvas = new Canvas({'target' : "testcanvas"});
debug("canvas indicates Data URI cursor support is: " + canvas.get_cursor_uri());
$('button1').style.cursor="url(face.png), default";

View File

@ -19,6 +19,7 @@
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="include/util.js"></script>
<script src="include/base64.js"></script>
<script src="include/canvas.js"></script>
<script>
var msg_cnt = 0;
@ -51,9 +52,9 @@
}
window.onload = function() {
Canvas.init('canvas');
Canvas.resize(width, height);
Canvas.start(keyPress, mouseButton, mouseMove);
var canvas = Canvas({'target' : 'canvas'});
canvas.resize(width, height, true);
canvas.start(keyPress, mouseButton, mouseMove);
message("Canvas initialized");
}
</script>

View File

@ -16,13 +16,12 @@ noVNC example: simple example using default controls
<body>
<div id='vnc'>Loading</div>
</body>
<script>
RFB.loadExtras();
<script>
window.onload = function () {
DefaultControls.load('vnc');
RFB.load();
}
</script>
};
</script>
</body>
</html>

View File

@ -7,8 +7,7 @@ Connect parameters are provided in query string:
<html>
<head>
<title>VNC Client</title>
<link rel="stylesheet" href="include/plain.css" TITLE="plain">
<link rel="Alternate StyleSheet" href="include/black.css" TITLE="Black">
<link rel="stylesheet" href="include/plain.css" title="plain">
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
@ -20,31 +19,36 @@ Connect parameters are provided in query string:
<body style="margin: 0px;">
<div id="VNC_screen">
<div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">
<table border=0 width=100%><tr>
<table border=0 width="100%"><tr>
<td><div id="VNC_status">Loading</div></td>
<td width=1%><div id="VNC_buttons">
<td width="1%"><div id="VNC_buttons">
<input type=button value="Send CtrlAltDel"
id="sendCtrlAltDelButton"
onclick="sendCtrlAltDel();"></div></td>
id="sendCtrlAltDelButton">
</div></td>
</tr></table>
</div>
<canvas id="VNC_canvas" width="640px" height="20px">
Canvas not supported.
</canvas>
</div>
</body>
<script>
<script>
/*jslint white: false */
/*global window, $, Util, RFB, */
"use strict";
var rfb;
function setPassword() {
RFB.sendPassword($('password_input').value);
rfb.sendPassword($('password_input').value);
return false;
}
function sendCtrlAltDel() {
RFB.sendCtrlAltDel();
rfb.sendCtrlAltDel();
return false;
}
function updateState(state, msg) {
var s, sb, klass, html;
function updateState(rfb, state, oldstate, msg) {
var s, sb, cad, klass;
s = $('VNC_status');
sb = $('VNC_status_bar');
cad = $('sendCtrlAltDelButton');
@ -65,8 +69,9 @@ Connect parameters are provided in query string:
msg += ' style="margin-bottom: 0px">';
msg += 'Password Required: ';
msg += '<input type=password size=10 id="password_input" class="VNC_status">';
msg += '</form>';
// Fall through
msg += '<\/form>';
klass = "VNC_status_warn";
break;
default:
klass = "VNC_status_warn";
}
@ -83,6 +88,8 @@ Connect parameters are provided in query string:
window.onload = function () {
var host, port, password;
$('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
host = Util.getQueryVar('host', null);
port = Util.getQueryVar('port', null);
password = Util.getQueryVar('password', '');
@ -92,15 +99,15 @@ Connect parameters are provided in query string:
return;
}
RFB.setEncrypt(Util.getQueryVar('encrypt', true));
RFB.setBase64(Util.getQueryVar('base64', true));
RFB.setTrueColor(Util.getQueryVar('true_color', true));
RFB.setCursor(Util.getQueryVar('cursor', true));
RFB.setUpdateState(updateState);
rfb = new RFB({'encrypt': Util.getQueryVar('encrypt', true),
'b64encode': Util.getQueryVar('base64', true),
'true_color': Util.getQueryVar('true_color', true),
'local_cursor': Util.getQueryVar('cursor', true),
'updateState': updateState});
rfb.connect(host, port, password);
};
</script>
RFB.load();
RFB.connect(host, port, password);
}
</script>
</body>
</html>