API changes. Client cursor and settings menu.
The following API changes may affect integrators: - Settings have been moved out of the RFB.connect() call. Each setting now has it's own setter function: setEncrypt, setBase64, setTrueColor, setCursor. - Encrypt and cursor settings now default to on. - CSS changes: - VNC_status_bar for input buttons switched to a element class. - VNC_buttons split into VNC_buttons_right and VNC_buttons_left - New id styles for VNC_settings_menu and VNC_setting Note: the encrypt, true_color and cursor, logging setting can all be set on load using query string variables (in addition to host, port and password). Client cursor (cursor pseudo-encoding) support has been polished and activated. The RFB settings are now presented as radio button list items in a drop-down "Settings" menu when using the default controls. Also, in the settings menu is the ability to select between alternate style-sheets. Cookie and stylesheet selection support added to util.js.
This commit is contained in:
parent
f55b6b4185
commit
da6dd8932e
|
@ -14,6 +14,9 @@ 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:
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -29,7 +29,7 @@ Canvas = {
|
|||
|
||||
prefer_js : false, // make private
|
||||
force_canvas : false, // make private
|
||||
cursor_uri : true, // make private, create getter
|
||||
cursor_uri : true, // make private
|
||||
|
||||
true_color : false,
|
||||
colourMap : [],
|
||||
|
@ -47,6 +47,9 @@ mouseMove : null,
|
|||
|
||||
onMouseButton: function(e, down) {
|
||||
var evt, pos, bmask;
|
||||
if (! Canvas.focused) {
|
||||
return true;
|
||||
}
|
||||
evt = (e ? e : window.event);
|
||||
pos = Util.getEventPosition(e, $(Canvas.id));
|
||||
bmask = 1 << evt.button;
|
||||
|
@ -122,6 +125,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 */
|
||||
|
@ -208,7 +214,7 @@ init: function (id) {
|
|||
curDat.push(255);
|
||||
}
|
||||
curSave = c.style.cursor;
|
||||
Canvas.setCursor(curDat, curDat, 2, 2, 8, 8);
|
||||
Canvas.changeCursor(curDat, curDat, 2, 2, 8, 8);
|
||||
if (c.style.cursor) {
|
||||
Util.Info("Data URI scheme cursor supported");
|
||||
} else {
|
||||
|
@ -561,13 +567,12 @@ getKeysym: function(e) {
|
|||
isCursor: function() {
|
||||
return Canvas.cursor_uri;
|
||||
},
|
||||
|
||||
setCursor: function(pixels, mask, hotx, hoty, w, h) {
|
||||
changeCursor: function(pixels, mask, hotx, hoty, w, h) {
|
||||
var cur = [], cmap, IHDRsz, ANDsz, XORsz, url, idx, x, y;
|
||||
//Util.Debug(">> setCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
|
||||
//Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
|
||||
|
||||
if (!Canvas.cursor_uri) {
|
||||
Util.Warn("setCursor called but no cursor data URI support");
|
||||
Util.Warn("changeCursor called but no cursor data URI support");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -636,7 +641,7 @@ setCursor: function(pixels, mask, hotx, hoty, w, h) {
|
|||
|
||||
url = "data:image/x-icon;base64," + Base64.encode(cur);
|
||||
$(Canvas.id).style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
|
||||
//Util.Debug("<< setCursor, cur.length: " + cur.length);
|
||||
//Util.Debug("<< changeCursor, cur.length: " + cur.length);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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,22 +98,26 @@ 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 += '</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
|
||||
|
@ -82,6 +127,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);
|
||||
|
@ -103,6 +296,7 @@ updateState: function(state, msg) {
|
|||
case 'fatal':
|
||||
c.disabled = true;
|
||||
cad.disabled = true;
|
||||
DefaultControls.settingsDisabled(true);
|
||||
klass = "VNC_status_error";
|
||||
break;
|
||||
case 'normal':
|
||||
|
@ -110,6 +304,7 @@ updateState: function(state, msg) {
|
|||
c.onclick = DefaultControls.disconnect;
|
||||
c.disabled = false;
|
||||
cad.disabled = false;
|
||||
DefaultControls.settingsDisabled(true);
|
||||
klass = "VNC_status_normal";
|
||||
break;
|
||||
case 'disconnected':
|
||||
|
@ -119,6 +314,7 @@ updateState: function(state, msg) {
|
|||
|
||||
c.disabled = false;
|
||||
cad.disabled = true;
|
||||
DefaultControls.settingsDisabled(false);
|
||||
klass = "VNC_status_normal";
|
||||
break;
|
||||
case 'password':
|
||||
|
@ -127,11 +323,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;
|
||||
}
|
||||
|
@ -145,28 +343,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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
129
include/util.js
129
include/util.js
|
@ -14,37 +14,44 @@
|
|||
var 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) {
|
||||
|
@ -254,3 +261,69 @@ Util.Flash = (function(){
|
|||
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);
|
||||
|
||||
|
|
|
@ -61,11 +61,11 @@ RFB = {
|
|||
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
|
||||
|
||||
|
||||
|
@ -77,6 +77,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'],
|
||||
|
@ -85,9 +86,6 @@ encodings : [
|
|||
// ['compress_hi', -247, 'set_compress_level']
|
||||
],
|
||||
|
||||
encodingCursor :
|
||||
['Cursor', -239, 'set_cursor'],
|
||||
|
||||
|
||||
setUpdateState: function(externalUpdateState) {
|
||||
RFB.externalUpdateState = externalUpdateState;
|
||||
|
@ -101,6 +99,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";
|
||||
|
@ -149,14 +184,6 @@ load: function () {
|
|||
RFB.updateState('fatal', "No working Canvas");
|
||||
}
|
||||
|
||||
// Add Cursor pseudo-encoding if supported
|
||||
/*
|
||||
if (Canvas.isCursor()) {
|
||||
Util.Debug("Adding Cursor pseudo-encoding to encoding list");
|
||||
RFB.encodings.push(RFB.encodingCursor);
|
||||
}
|
||||
*/
|
||||
|
||||
// Populate encoding lookup tables
|
||||
RFB.encHandlers = {};
|
||||
RFB.encNames = {};
|
||||
|
@ -167,24 +194,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");
|
||||
|
@ -501,7 +516,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");
|
||||
|
@ -1051,9 +1070,9 @@ set_cursor: function () {
|
|||
|
||||
//Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
|
||||
|
||||
Canvas.setCursor(RFB.RQ.shiftBytes(pixelslength),
|
||||
RFB.RQ.shiftBytes(masklength),
|
||||
x, y, w, h);
|
||||
Canvas.changeCursor(RFB.RQ.shiftBytes(pixelslength),
|
||||
RFB.RQ.shiftBytes(masklength),
|
||||
x, y, w, h);
|
||||
|
||||
RFB.FBU.bytes = 0;
|
||||
RFB.FBU.rects -= 1;
|
||||
|
@ -1104,14 +1123,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;
|
||||
|
|
|
@ -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">
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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>
|
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
4
vnc.html
4
vnc.html
|
@ -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>
|
||||
|
|
|
@ -21,7 +21,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>
|
||||
|
@ -79,23 +79,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>
|
||||
|
|
Loading…
Reference in New Issue