* conflict resolution

This commit is contained in:
primalmotion
2010-07-22 14:28:37 +02:00
14 changed files with 764 additions and 110 deletions
+3 -1
View File
@@ -178,7 +178,9 @@ In the following table Jaunty is Ubuntu 9.04 and WinXP is Windows XP.
is faster than Firefox 3.5, the high variability of web-socket-js
performance results in overall performance being lower. Middle mouse
clicks and keyboard events need some work to work properly under
Opera.
Opera. Also, Opera does not have support for setting the cursor
style url to a data URI scheme, so cursor pseudo-encoding is
disabled.
### Integration
+6 -4
View File
@@ -1,5 +1,8 @@
Short Term:
- Proper Javascript namespacing for Canvas and RFB (using function for
true local variables and functions).
- Timing delta between frames in proxy record log, for playback
support (for demo and test).
@@ -11,13 +14,12 @@ Short Term:
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:
- Implement Cursor pseudo-encoding (CSS cursor)
http://en.wikipedia.org/wiki/ICO_(file_format)
https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
- Viewport and/or scaling support.
- Status bar buttons:
+5
View File
@@ -29,6 +29,11 @@ TLS Protocol:
Generate self-signed certificate:
http://docs.python.org/dev/library/ssl.html#certificates
Cursor appearance/style (for Cursor pseudo-encoding):
http://en.wikipedia.org/wiki/ICO_(file_format)
http://www.daubnet.com/en/file-format-cur
https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
Related projects:
+27 -5
View File
@@ -1,5 +1,4 @@
body {
background: #ddd;
margin: 0;
font-size: 13px;
color: #111;
@@ -56,7 +55,7 @@ body {
margin: 0px;
padding: 1em;
}
#VNC_status_bar input {
.VNC_status_button {
font-size: 10px;
margin: 0px;
padding: 0px;
@@ -64,24 +63,46 @@ body {
#VNC_status {
text-align: center;
}
#VNC_buttons {
text-align: right;
#VNC_settings_menu {
display: none;
position: absolute;
width: 12em;
border: 1px solid #888;
background-color: #f0f2f6;
padding: 5px; margin: 3px;
z-index: 100; opacity: 1;
text-align: left; white-space: normal;
}
#VNC_settings_menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.VNC_buttons_right {
text-align: right;
}
.VNC_buttons_left {
text-align: left;
}
.VNC_status_normal {
background: #111;
color: #fff;
}
.VNC_status_error {
background: #111;
color: #f44;
}
.VNC_status_warn {
background: #111;
color: #ff4;
}
#VNC_screen {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
background: #000;
background: #111;
padding: 20px;
margin: 0 auto;
color: #FFF;
@@ -93,6 +114,7 @@ body {
table-layout: auto;
}
#VNC_canvas {
background: #111;
margin: 0 auto;
}
#VNC_clipboard {
+115 -4
View File
@@ -16,8 +16,9 @@ Canvas_native = true;
// Everything namespaced inside Canvas
Canvas = {
prefer_js : false,
force_canvas : false,
prefer_js : false, // make private
force_canvas : false, // make private
cursor_uri : true, // make private
true_color : false,
colourMap : [],
@@ -49,6 +50,9 @@ loadExtra : function () {
onMouseButton: function(e, down) {
var evt, pos, bmask;
if (! Canvas.focused) {
return true;
}
evt = (e ? e : window.event);
pos = Util.getEventPosition(e, $(Canvas.id), Canvas.scale);
bmask = 1 << evt.button;
@@ -124,6 +128,9 @@ onKeyUp : function (e) {
onMouseDisable: function (e) {
var evt, pos;
if (! Canvas.focused) {
return true;
}
evt = (e ? e : window.event);
pos = Util.getPosition($(Canvas.id));
/* Stop propagation if inside canvas area */
@@ -141,7 +148,7 @@ onMouseDisable: function (e) {
init: function (id) {
var c, imgTest, arora;
var c, imgTest, tval, i, curTest, curSave;
Util.Debug(">> Canvas.init");
Canvas.id = id;
@@ -201,6 +208,25 @@ init: function (id) {
Canvas._cmapImage = Canvas._cmapImageFill;
}
/*
* Determine browser support for setting the cursor via data URI
* scheme
*/
curDat = [];
for (i=0; i < 8 * 8 * 4; i++) {
curDat.push(255);
}
curSave = c.style.cursor;
Canvas.changeCursor(curDat, curDat, 2, 2, 8, 8);
if (c.style.cursor) {
Util.Info("Data URI scheme cursor supported");
} else {
Canvas.cursor_uri = false;
Util.Warn("Data URI scheme cursor not supported");
}
c.style.cursor = curSave;
Canvas.colourMap = [];
Canvas.prevStyle = "";
Canvas.focused = true;
@@ -319,6 +345,11 @@ stop: function () {
/* Work around right and middle click browser behaviors */
Util.removeEvent(document, 'click', Canvas.onMouseDisable);
Util.removeEvent(document.body, 'contextmenu', Canvas.onMouseDisable);
// Turn off cursor rendering
if (Canvas.cursor_uri) {
c.style.cursor = "default";
}
},
/*
@@ -586,8 +617,88 @@ getKeysym: function(e) {
}
return keysym;
}
},
isCursor: function() {
return Canvas.cursor_uri;
},
changeCursor: function(pixels, mask, hotx, hoty, w, h) {
var cur = [], cmap, IHDRsz, ANDsz, XORsz, url, idx, x, y;
//Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
if (!Canvas.cursor_uri) {
Util.Warn("changeCursor called but no cursor data URI support");
return;
}
cmap = Canvas.colourMap;
IHDRsz = 40;
ANDsz = w * h * 4;
XORsz = Math.ceil( (w * h) / 8.0 );
// Main header
cur.push16le(0); // Reserved
cur.push16le(2); // .CUR type
cur.push16le(1); // Number of images, 1 for non-animated ico
// Cursor #1 header
cur.push(w); // width
cur.push(h); // height
cur.push(0); // colors, 0 -> true-color
cur.push(0); // reserved
cur.push16le(hotx); // hotspot x coordinate
cur.push16le(hoty); // hotspot y coordinate
cur.push32le(IHDRsz + XORsz + ANDsz); // cursor data byte size
cur.push32le(22); // offset of cursor data in the file
// Cursor #1 InfoHeader
cur.push32le(IHDRsz); // Infoheader size
cur.push32le(w); // Cursor width
cur.push32le(h*2); // XOR+AND height
cur.push16le(1); // number of planes
cur.push16le(32); // bits per pixel
cur.push32le(0); // Type of compression
cur.push32le(XORsz + ANDsz); // Size of Image
cur.push32le(0);
cur.push32le(0);
cur.push32le(0);
cur.push32le(0);
// XOR/color data
for (y = h-1; y >= 0; y--) {
for (x = 0; x < w; x++) {
idx = y * Math.ceil(w / 8) + Math.floor(x/8);
alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
if (Canvas.true_color) {
idx = ((w * y) + x) * 4;
cur.push(pixels[idx + 2]); // blue
cur.push(pixels[idx + 1]); // green
cur.push(pixels[idx + 0]); // red
cur.push(alpha); // red
} else {
idx = (w * y) + x;
rgb = cmap[pixels[idx]];
cur.push(rgb[2]); // blue
cur.push(rgb[1]); // green
cur.push(rgb[0]); // red
cur.push(alpha); // alpha
}
}
}
// AND/bitmask data (ignored, just needs to be right size)
for (y = 0; y < h; y++) {
for (x = 0; x < Math.ceil(w / 8); x++) {
cur.push(0x00);
}
}
url = "data:image/x-icon;base64," + Base64.encode(cur);
$(Canvas.id).style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
//Util.Debug("<< changeCursor, cur.length: " + cur.length);
}
};
+232 -26
View File
@@ -10,12 +10,16 @@
var DefaultControls = {
settingsOpen : false,
// Render default controls and initialize settings menu
load: function(target) {
var url, html;
var url, html, encrypt, cursor, base64, i, sheet, sheets,
DC = DefaultControls;
/* Handle state updates */
RFB.setUpdateState(DefaultControls.updateState);
RFB.setClipboardReceive(DefaultControls.clipReceive);
RFB.setUpdateState(DC.updateState);
RFB.setClipboardReceive(DC.clipReceive);
/* Populate the 'target' DOM element with default controls */
if (!target) { target = 'vnc'; }
@@ -27,10 +31,6 @@ load: function(target) {
html += ' <li>Port: <input id="VNC_port"></li>';
html += ' <li>Password: <input id="VNC_password"';
html += ' type="password"></li>';
html += ' <li>Encrypt: <input id="VNC_encrypt"';
html += ' type="checkbox"></li>';
html += ' <li>True Color: <input id="VNC_true_color"';
html += ' type="checkbox" checked></li>';
html += ' <li><input id="VNC_connect_button" type="button"';
html += ' value="Loading" disabled></li>';
html += ' </ul>';
@@ -39,8 +39,49 @@ load: function(target) {
html += ' <div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">';
html += ' <table border=0 width=100%><tr>';
html += ' <td><div id="VNC_status">Loading</div></td>';
html += ' <td width=10%><div id="VNC_buttons">';
html += ' <input type=button value="Send CtrlAltDel"';
html += ' <td width=1%><div class="VNC_buttons_right">';
html += ' <input type=button class="VNC_status_button" value="Settings"';
html += ' id="menuButton"';
html += ' onclick="DefaultControls.clickSettingsMenu();">';
html += ' <span id="VNC_settings_menu"';
html += ' onmouseover="DefaultControls.canvasBlur();"';
html += ' onmouseout="DefaultControls.canvasFocus();">';
html += ' <ul>';
html += ' <li><input id="VNC_encrypt"';
html += ' type="checkbox" checked> Encrypt</li>';
html += ' <li><input id="VNC_base64"';
html += ' type="checkbox" checked> Base64 Encode</li>';
html += ' <li><input id="VNC_true_color"';
html += ' type="checkbox" checked> True Color</li>';
html += ' <li><input id="VNC_cursor"';
html += ' type="checkbox" checked> Local Cursor</li>';
html += ' <hr>';
// Stylesheet selection dropdown
html += ' <li><select id="VNC_stylesheet" name="vncStyle">';
html += ' <option value="default">default</option>';
sheet = Util.selectStylesheet();
sheets = Util.getStylesheets();
for (i = 0; i < sheets.length; i++) {
html += '<option value="' + sheets[i].title + '">' + sheets[i].title + '</option>';
}
html += ' </select> Style</li>';
// Logging selection dropdown
html += ' <li><select id="VNC_logging" name="vncLogging">';
llevels = ['error', 'warn', 'info', 'debug'];
for (i = 0; i < llevels.length; i++) {
html += '<option value="' + llevels[i] + '">' + llevels[i] + '</option>';
}
html += ' </select> Logging</li>';
html += ' <hr>';
html += ' <li><input type="button" id="VNC_apply" value="Apply"';
html += ' onclick="DefaultControls.settingsApply()"></li>';
html += ' </ul>';
html += ' </span></div></td>';
html += ' <td width=1%><div class="VNC_buttons_right">';
html += ' <input type=button class="VNC_status_button" value="Send CtrlAltDel"';
html += ' id="sendCtrlAltDelButton"';
html += ' onclick="DefaultControls.sendCtrlAltDel();"></div></td>';
html += ' </tr></table>';
@@ -57,8 +98,8 @@ load: function(target) {
html += ' onclick="DefaultControls.clipClear();">';
html += ' <br>';
html += ' <textarea id="VNC_clipboard_text" cols=80 rows=5';
html += ' onfocus="DefaultControls.clipFocus();"';
html += ' onblur="DefaultControls.clipBlur();"';
html += ' onfocus="DefaultControls.canvasBlur();"';
html += ' onblur="DefaultControls.canvasFocus();"';
html += ' onchange="DefaultControls.clipSend();"></textarea>';
html += ' <br>';
html += ' <input id="VNC_scale" type="text"';
@@ -70,16 +111,20 @@ load: function(target) {
html += '</div>';
$(target).innerHTML = html;
// Settings with immediate effects
DC.initSetting('logging', 'default');
Util.init_logging(DC.getSetting('logging'));
DC.initSetting('stylesheet', 'default');
Util.selectStylesheet(DC.getSetting('stylesheet'));
/* Populate the controls if defaults are provided in the URL */
url = document.location.href;
$('VNC_host').value = (url.match(/host=([A-Za-z0-9.\-]*)/) ||
['',''])[1];
$('VNC_port').value = (url.match(/port=([0-9]*)/) ||
['',''])[1];
$('VNC_password').value = (url.match(/password=([^&#]*)/) ||
['',''])[1];
$('VNC_encrypt').checked = (url.match(/encrypt=([A-Za-z0-9]*)/) ||
['',''])[1];
DC.initSetting('host', '');
DC.initSetting('port', '');
DC.initSetting('password', '');
DC.initSetting('encrypt', true);
DC.initSetting('base64', true);
DC.initSetting('true_color', true);
DC.initSetting('cursor', true);
$('VNC_screen').onmousemove = function () {
// Unfocus clipboard when over the VNC area
@@ -89,6 +134,154 @@ load: function(target) {
};
},
// Read a query string variable
getQueryVar: function(name) {
var re = new RegExp('[\?].*' + name + '=([^\&\#]*)');
return (document.location.href.match(re) || ['',null])[1];
},
// Read form control compatible setting from cookie
getSetting: function(name) {
var val, ctrl = $('VNC_' + name);
val = Util.readCookie(name);
if (ctrl.type === 'checkbox') {
if (val.toLowerCase() in {'0':1, 'no':1, 'false':1}) {
val = false;
} else {
val = true;
}
}
return val;
},
// Update cookie and form control setting. If value is not set, then
// updates from control to current cookie setting.
updateSetting: function(name, value) {
var i, ctrl = $('VNC_' + name);
// Save the cookie for this session
if (typeof value !== 'undefined') {
Util.createCookie(name, value);
}
// Update the settings control
value = DefaultControls.getSetting(name);
if (ctrl.type === 'checkbox') {
ctrl.checked = value;
} else if (typeof ctrl.options !== 'undefined') {
for (i = 0; i < ctrl.options.length; i++) {
if (ctrl.options[i].value === value) {
ctrl.selectedIndex = i;
break;
}
}
} else {
ctrl.value = value;
}
},
// Save control setting to cookie
saveSetting: function(name) {
var val, ctrl = $('VNC_' + name);
if (ctrl.type === 'checkbox') {
val = ctrl.checked;
} else if (typeof ctrl.options !== 'undefined') {
val = ctrl.options[ctrl.selectedIndex].value;
} else {
val = ctrl.value;
}
Util.createCookie(name, val);
Util.Debug("Setting saved '" + name + "=" + val + "'");
return val;
},
// Initial page load read/initialization of settings
initSetting: function(name, defVal) {
var val, ctrl = $('VNC_' + name), DC = DefaultControls;
// Check Query string followed by cookie
val = DC.getQueryVar(name);
if (val === null) {
val = Util.readCookie(name, defVal);
}
DC.updateSetting(name, val);
Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
return val;
},
// Toggle the settings menu:
// On open, settings are refreshed from saved cookies.
// On close, settings are applied
clickSettingsMenu: function() {
var DC = DefaultControls;
if (DefaultControls.settingsOpen) {
DC.settingsApply();
DC.closeSettingsMenu();
} else {
DC.updateSetting('encrypt');
DC.updateSetting('base64');
DC.updateSetting('true_color');
if (Canvas.isCursor()) {
DC.updateSetting('cursor');
} else {
DC.updateSettings('cursor', false);
$('VNC_cursor').disabled = true;
}
DC.updateSetting('stylesheet');
DC.updateSetting('logging');
DC.openSettingsMenu();
}
},
// Open menu
openSettingsMenu: function() {
$('VNC_settings_menu').style.display = "block";
DefaultControls.settingsOpen = true;
},
// Close menu (without applying settings)
closeSettingsMenu: function() {
$('VNC_settings_menu').style.display = "none";
DefaultControls.settingsOpen = false;
},
// Disable/enable controls depending on connection state
settingsDisabled: function(disabled) {
$('VNC_encrypt').disabled = disabled;
$('VNC_base64').disabled = disabled;
$('VNC_true_color').disabled = disabled;
if (Canvas.isCursor()) {
$('VNC_cursor').disabled = disabled;
} else {
DefaultControls.updateSettings('cursor', false);
$('VNC_cursor').disabled = true;
}
},
// Save/apply settings when 'Apply' button is pressed
settingsApply: function() {
Util.Debug(">> settingsApply");
var curSS, newSS, DC = DefaultControls;
DC.saveSetting('encrypt');
DC.saveSetting('base64');
DC.saveSetting('true_color');
if (Canvas.isCursor()) {
DC.saveSetting('cursor');
}
DC.saveSetting('stylesheet');
DC.saveSetting('logging');
// Settings with immediate (non-connected related) effect
Util.selectStylesheet(DC.getSetting('stylesheet'));
Util.init_logging(DC.getSetting('logging'));
Util.Debug("<< settingsApply");
},
setPassword: function() {
console.log("setPassword");
RFB.sendPassword($('VNC_password').value);
@@ -113,6 +306,7 @@ updateState: function(state, msg) {
case 'fatal':
c.disabled = true;
cad.disabled = true;
DefaultControls.settingsDisabled(true);
klass = "VNC_status_error";
break;
case 'normal':
@@ -121,6 +315,7 @@ updateState: function(state, msg) {
zb.onclick = DefaultControls.setScale;
c.disabled = false;
cad.disabled = false;
DefaultControls.settingsDisabled(true);
klass = "VNC_status_normal";
break;
@@ -131,6 +326,7 @@ updateState: function(state, msg) {
c.disabled = false;
cad.disabled = true;
DefaultControls.settingsDisabled(false);
klass = "VNC_status_normal";
break;
case 'password':
@@ -139,11 +335,13 @@ updateState: function(state, msg) {
c.disabled = false;
cad.disabled = true;
DefaultControls.settingsDisabled(true);
klass = "VNC_status_warn";
break;
default:
c.disabled = true;
cad.disabled = true;
DefaultControls.settingsDisabled(true);
klass = "VNC_status_warn";
break;
}
@@ -157,28 +355,36 @@ updateState: function(state, msg) {
},
connect: function() {
var host, port, password, encrypt, true_color;
var host, port, password, DC = DefaultControls;
DC.closeSettingsMenu();
host = $('VNC_host').value;
port = $('VNC_port').value;
password = $('VNC_password').value;
encrypt = $('VNC_encrypt').checked;
true_color = $('VNC_true_color').checked;
if ((!host) || (!port)) {
throw("Must set host and port");
}
RFB.connect(host, port, password, encrypt, true_color);
RFB.setEncrypt(DC.getSetting('encrypt'));
RFB.setBase64(DC.getSetting('base64'));
RFB.setTrueColor(DC.getSetting('true_color'));
RFB.setCursor(DC.getSetting('cursor'));
RFB.connect(host, port, password);
},
disconnect: function() {
DefaultControls.closeSettingsMenu();
RFB.disconnect();
},
clipFocus: function() {
canvasBlur: function() {
Canvas.focused = false;
},
clipBlur: function() {
canvasFocus: function() {
Canvas.focused = true;
},
+21 -3
View File
@@ -36,7 +36,7 @@
margin: 0px;
padding: 0px;
}
#VNC_status_bar input {
.VNC_status_button {
font-size: 10px;
margin: 0px;
padding: 0px;
@@ -44,10 +44,28 @@
#VNC_status {
text-align: center;
}
#VNC_buttons {
text-align: right;
#VNC_settings_menu {
display: none;
position: absolute;
width: 12em;
border: 1px solid #888;
background-color: #f0f2f6;
padding: 5px; margin: 3px;
z-index: 100; opacity: 1;
text-align: left; white-space: normal;
}
#VNC_settings_menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.VNC_buttons_right {
text-align: right;
}
.VNC_buttons_left {
text-align: left;
}
.VNC_status_normal {
background: #eee;
}
+113 -28
View File
@@ -14,37 +14,44 @@
Util = {};
// Logging/debug routines
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) {}};
/*
* 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); };
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.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
Util.logging = (document.location.href.match(
/logging=([A-Za-z0-9\._\-]*)/) || ['', 'warn'])[1];
switch (Util.logging) {
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 '" + Util.logging + "'");
}
// Simple DOM selector by ID
/*
* Simple DOM selector by ID
*/
if (!window.$) {
$ = function (id) {
if (document.getElementById) {
@@ -77,6 +84,10 @@ Array.prototype.push16 = function (num) {
this.push((num >> 8) & 0xFF,
(num ) & 0xFF );
};
Array.prototype.push16le = function (num) {
this.push((num ) & 0xFF,
(num >> 8) & 0xFF );
};
Array.prototype.shift32 = function () {
@@ -97,6 +108,13 @@ Array.prototype.push32 = function (num) {
(num >> 8) & 0xFF,
(num ) & 0xFF );
};
Array.prototype.push32le = function (num) {
this.push((num ) & 0xFF,
(num >> 8) & 0xFF,
(num >> 16) & 0xFF,
(num >> 24) & 0xFF );
};
Array.prototype.shiftStr = function (len) {
var arr = this.splice(0, len);
@@ -245,3 +263,70 @@ Util.Flash = (function(){
version = v.match(/\d+/g);
return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
}());
/*
* Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
*/
// No days means only for this browser session
Util.createCookie = function(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
};
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);
}
return (typeof defaultValue !== 'undefined') ? defaultValue : null;
};
Util.eraseCookie = function(name) {
createCookie(name,"",-1);
};
/*
* Alternate stylesheet selection
*/
Util.getStylesheets = function() { var i, links, sheets = [];
links = document.getElementsByTagName("link")
for (i = 0; i < links.length; i++) {
if (links[i].title &&
links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) {
sheets.push(links[i]);
}
}
return sheets;
};
// No sheet means try and use value from cookie, null sheet used to
// clear all alternates.
Util.selectStylesheet = function(sheet) {
var i, link, sheets = Util.getStylesheets();
if (typeof sheet === 'undefined') {
sheet = 'default';
}
for (i=0; i < sheets.length; i++) {
link = sheets[i];
if (link.title === sheet) {
Util.Debug("Using stylesheet " + sheet);
link.disabled = false;
} else {
Util.Debug("Skipping stylesheet " + link.title);
link.disabled = true;
}
}
return sheet;
};
// call once to disable alternates and get around webkit bug
Util.selectStylesheet(null);
+95 -22
View File
@@ -58,11 +58,11 @@ loadExtras: function () {
host : '',
port : 5900,
password : '',
encrypt : true,
true_color : false,
b64encode : true, // false means UTF-8 on the wire
//b64encode : false, // false means UTF-8 on the wire
local_cursor : true,
connectTimeout : 2000, // time to wait for connection
@@ -74,6 +74,7 @@ encodings : [
['RRE', 0x02, 'display_rre'],
['RAW', 0x00, 'display_raw'],
['DesktopSize', -223, 'set_desktopsize'],
['Cursor', -239, 'set_cursor'],
// Psuedo-encoding settings
['JPEG_quality_lo', -32, 'set_jpeg_quality'],
@@ -82,6 +83,7 @@ encodings : [
// ['compress_hi', -247, 'set_compress_level']
],
setUpdateState: function(externalUpdateState) {
RFB.externalUpdateState = externalUpdateState;
},
@@ -94,6 +96,43 @@ setCanvasID: function(canvasID) {
RFB.canvasID = canvasID;
},
setEncrypt: function(encrypt) {
if ((!encrypt) || (encrypt in {'0':1, 'no':1, 'false':1})) {
RFB.encrypt = false;
} else {
RFB.encrypt = true;
}
},
setBase64: function(b64) {
if ((!b64) || (b64 in {'0':1, 'no':1, 'false':1})) {
RFB.b64encode = false;
} else {
RFB.b64encode = true;
}
Util.Debug("Set b64encode to: " + RFB.b64encode);
},
setTrueColor: function(trueColor) {
if ((!trueColor) || (trueColor in {'0':1, 'no':1, 'false':1})) {
RFB.true_color = false;
} else {
RFB.true_color = true;
}
},
setCursor: function(cursor) {
if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) {
RFB.local_cursor = false;
} else {
if (Canvas.isCursor()) {
RFB.local_cursor = true;
} else {
Util.Warn("Browser does not support local cursor");
}
}
},
sendPassword: function(passwd) {
RFB.password = passwd;
RFB.state = "Authentication";
@@ -151,24 +190,12 @@ load: function () {
//Util.Debug("<< load");
},
connect: function (host, port, password, encrypt, true_color) {
connect: function (host, port, password) {
//Util.Debug(">> connect");
RFB.host = host;
RFB.port = port;
RFB.password = (password !== undefined) ? password : "";
RFB.encrypt = (encrypt !== undefined) ? encrypt : true;
if ((RFB.encrypt === "0") ||
(RFB.encrypt === "no") ||
(RFB.encrypt === "false")) {
RFB.encrypt = false;
}
RFB.true_color = (true_color !== undefined) ? true_color: true;
if ((RFB.true_color === "0") ||
(RFB.true_color === "no") ||
(RFB.true_color === "false")) {
RFB.true_color = false;
}
if ((!RFB.host) || (!RFB.port)) {
RFB.updateState('failed', "Must set host and port");
@@ -486,7 +513,11 @@ init_msg: function () {
RFB.timing.history_start = (new Date()).getTime();
setTimeout(RFB.update_timings, 1000);
RFB.updateState('normal', "Connected to: " + RFB.fb_name);
if (RFB.encrypt) {
RFB.updateState('normal', "Connected (encrypted) to: " + RFB.fb_name);
} else {
RFB.updateState('normal', "Connected (unencrypted) to: " + RFB.fb_name);
}
break;
}
//Util.Debug("<< init_msg");
@@ -1010,10 +1041,40 @@ set_desktopsize : function () {
RFB.timing.fbu_rt_start = (new Date()).getTime();
// Send a new non-incremental request
RFB.send_array(RFB.fbUpdateRequest(0));
Util.Debug("<< set_desktopsize");
RFB.FBU.bytes = 0;
RFB.FBU.rects -= 1;
Util.Debug("<< set_desktopsize");
},
set_cursor: function () {
var x, y, w, h, pixelslength, masklength;
//Util.Debug(">> set_cursor");
x = RFB.FBU.x; // hotspot-x
y = RFB.FBU.y; // hotspot-y
w = RFB.FBU.width;
h = RFB.FBU.height;
pixelslength = w * h * RFB.fb_Bpp;
masklength = Math.floor((w + 7) / 8) * h;
if (RFB.RQ.length < (pixelslength + masklength)) {
//Util.Debug("waiting for cursor encoding bytes");
RFB.FBU.bytes = pixelslength + masklength;
return false;
}
//Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
Canvas.changeCursor(RFB.RQ.shiftBytes(pixelslength),
RFB.RQ.shiftBytes(masklength),
x, y, w, h);
RFB.FBU.bytes = 0;
RFB.FBU.rects -= 1;
//Util.Debug("<< set_cursor");
},
set_jpeg_quality : function () {
@@ -1059,14 +1120,24 @@ fixColourMapEntries: function () {
clientEncodings: function () {
//Util.Debug(">> clientEncodings");
var arr, i;
var arr, i, encList = [];
for (i=0; i<RFB.encodings.length; i += 1) {
if ((RFB.encodings[i][0] === "Cursor") &&
(! RFB.local_cursor)) {
Util.Debug("Skipping Cursor pseudo-encoding");
} else {
//Util.Debug("Adding encoding: " + RFB.encodings[i][0]);
encList.push(RFB.encodings[i][1]);
}
}
arr = [2]; // msg-type
arr.push8(0); // padding
arr.push16(RFB.encodings.length); // encoding count
for (i=0; i<RFB.encodings.length; i += 1) {
arr.push32(RFB.encodings[i][1]);
arr.push16(encList.length); // encoding count
for (i=0; i < encList.length; i += 1) {
arr.push32(encList[i]);
}
//Util.Debug("<< clientEncodings: " + arr);
return arr;
@@ -1533,6 +1604,8 @@ init_ws: function () {
Util.Debug(">> WebSocket.onclose");
if (RFB.state === 'normal') {
RFB.updateState('failed', 'Server disconnected');
} else if (RFB.state === 'ProtocolVersion') {
RFB.updateState('failed', 'Failed to connect to server');
} else {
RFB.updateState('disconnected', 'VNC disconnected');
}
+14 -10
View File
@@ -1,5 +1,14 @@
<html>
<head><title>Canvas Performance Test</title></head>
<head>
<title>Canvas Performance Test</title>
<meta http-equiv="X-UA-Compatible" content="IE=8,chrome=1">
<script type='text/javascript'
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 src="face.png.js"></script>
</head>
<body>
Iterations: <input id='iterations' style='width:50' value="100">&nbsp;
@@ -22,13 +31,6 @@
<textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
</body>
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="include/util.js"></script>
<script src="include/canvas.js"></script>
<script src="face.png.js"></script>
<script>
var msg_cnt = 0;
var start_width = 300, start_height = 100;
@@ -39,17 +41,18 @@
cell = $('messages');
cell.innerHTML += msg_cnt + ": " + str + "\n";
cell.scrollTop = cell.scrollHeight;
msg_cnt += 1;
}
function test_functions () {
var img, x, y;
Canvas.fillRect(0, 0, Canvas.c_wx, Canvas.c_wy, [240,240,240]);
Canvas.blitStringImage("data:image/png;base64," + face64, 150, 40);
Canvas.blitStringImage("data:image/png;base64," + face64, 150, 10);
var himg = new Image();
himg.onload = function () {
Canvas.ctx.drawImage(himg, 200, 10); };
Canvas.ctx.drawImage(himg, 200, 40); };
himg.src = "face.png";
/* Test array image data */
@@ -123,6 +126,7 @@
}
window.onload = function() {
message("in onload");
$('iterations').value = 10;
Canvas.init('canvas');
Canvas.resize(start_width, start_height, true);
+123
View File
@@ -0,0 +1,123 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Cursor Change test</title>
<meta charset="UTF-8">
<!--
<script type='text/javascript'
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>
</head>
<body>
<h1>Roll over the buttons to test cursors</h1>
<br>
<input id=button1 type="button" value="Cursor from file (smiley face)">
<input id=button2 type="button" value="Data URI cursor (crosshair)">
<br>
<br>
<br>
Debug:<br>
<textarea id="debug" style="font-size: 9px;" cols=80 rows=25></textarea>
<br>
<br>
<canvas id="testcanvas" width="100px" height="20px">
Canvas not supported.
</canvas>
</body>
<script>
function debug(str) {
console.log(str);
cell = $('debug');
cell.innerHTML += str + "\n";
cell.scrollTop = cell.scrollHeight;
}
function makeCursor() {
var arr = [], x, y, w = 32, h = 32, hx = 16, hy = 16;
var IHDRsz = 40;
var ANDsz = w * h * 4;
var XORsz = Math.ceil( (w * h) / 8.0 );
// Main header
arr.push16le(0); // Reserved
arr.push16le(2); // .CUR type
arr.push16le(1); // Number of images, 1 for non-animated arr
// Cursor #1
arr.push(w); // width
arr.push(h); // height
arr.push(0); // colors, 0 -> true-color
arr.push(0); // reserved
arr.push16le(hx); // hotspot x coordinate
arr.push16le(hy); // hotspot y coordinate
arr.push32le(IHDRsz + XORsz + ANDsz); // cursor data byte size
arr.push32le(22); // offset of cursor data in the file
// Infoheader for Cursor #1
arr.push32le(IHDRsz); // Infoheader size
arr.push32le(w); // Cursor width
arr.push32le(h*2); // XOR+AND height
arr.push16le(1); // number of planes
arr.push16le(32); // bits per pixel
arr.push32le(0); // type of compression
arr.push32le(XORsz + ANDsz); // Size of Image
arr.push32le(0);
arr.push32le(0);
arr.push32le(0);
arr.push32le(0);
// XOR/color data
for (y = h-1; y >= 0; y--) {
for (x = 0; x < w; x++) {
//if ((x === hx) || (y === (h-hy-1))) {
if ((x === hx) || (y === hy)) {
arr.push(0xe0); // blue
arr.push(0x00); // green
arr.push(0x00); // red
arr.push(0xff); // alpha
} else {
arr.push(0x05); // blue
arr.push(0xe6); // green
arr.push(0x00); // red
arr.push(0x80); // alpha
}
}
}
// AND/bitmask data (seems to be ignored)
for (y = 0; y < h; y++) {
for (x = 0; x < Math.ceil(w / 8); x++) {
arr.push(0x00);
}
}
debug("cursor generated");
return arr;
}
window.onload = function() {
debug("onload");
var cross, cursor, cursor64;
Canvas.init("testcanvas");
debug("Canvas.init() indicates Data URI cursor support is: " + Canvas.isCursor());
$('button1').style.cursor="url(face.png), default";
cursor = makeCursor();
cursor64 = Base64.encode(cursor);
//debug("cursor: " + cursor.slice(0,100) + " (" + cursor.length + ")");
//debug("cursor64: " + cursor64.slice(0,100) + " (" + cursor64.length + ")");
$('button2').style.cursor="url(data:image/x-icon;base64," + cursor64 + "), default";
debug("onload complete");
}
</script>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

+2 -2
View File
@@ -4,8 +4,8 @@ noVNC example: simple example using default controls
<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">
<link rel="alternate stylesheet" href="include/black.css" TITLE="Black">
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+8 -5
View File
@@ -22,7 +22,7 @@ Connect parameters are provided in query string:
<div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">
<table border=0 width=100%><tr>
<td><div id="VNC_status">Loading</div></td>
<td width=10%><div id="VNC_buttons">
<td width=1%><div id="VNC_buttons">
<input type=button value="Send CtrlAltDel"
id="sendCtrlAltDelButton"
onclick="sendCtrlAltDel();"></div></td>
@@ -80,23 +80,26 @@ Connect parameters are provided in query string:
}
window.onload = function () {
var host, port, password, encrypt;
var host, port, password;
url = document.location.href;
host = (url.match(/host=([A-Za-z0-9.\-]*)/) || ['',''])[1];
port = (url.match(/port=([0-9]*)/) || ['',''])[1];
password = (url.match(/password=([^&#]*)/) || ['',''])[1];
encrypt = (url.match(/encrypt=([A-Za-z0-9]*)/) || ['',1])[1];
true_color = (url.match(/true_color=([A-Za-z0-9]*)/) || ['',1])[1];
if ((!host) || (!port)) {
updateState('failed',
"Must specify host and port in URL");
return;
}
RFB.setEncrypt((url.match(/encrypt=([A-Za-z0-9]*)/) || ['',1])[1]);
RFB.setBase64((url.match(/base64=([A-Za-z0-9]*)/) || ['',1])[1]);
RFB.setTrueColor((url.match(/true_color=([A-Za-z0-9]*)/) || ['',1])[1]);
RFB.setCursor((url.match(/cursor=([A-Za-z0-9]*)/) || ['',true])[1]);
RFB.setUpdateState(updateState);
RFB.load();
RFB.connect(host, port, password, encrypt, true_color);
RFB.connect(host, port, password);
}
</script>
</html>