Commit d890e864 authored by Joel Martin's avatar Joel Martin

API changes/cleanup.

API changes:
    - include/canvas.js renamed to include/display.js
    - Display.rescale() method removed from API. Use Display.set_scale() instead.
    - Make logo configuration attribute of Display and display it when
      clear() is called if it is set.

API deprecations:
    - use RFB onUpdateState instead of updateState.
    - use RFB onClipboard instead of clipboardReceive.

See https://github.com/kanaka/noVNC/wiki/ModuleAPI for detailed noVNC
modules and API description.

Expand and normalize the event/callback interfaces. Standize on
"onEventName" form for callbacks.

    Callback Renames:
        - RFB updateState -> onUpdateState
        - RFB clipboardReceive -> onClipboard
        - Keyboard keyPress -> onKeyPress
        - Mouse mouseButton -> onMouseButton
        - Mouse mouseMove -> onMouseMove

    Callback Additions:
        - RFB onPasswordRequired
        - RFB onBell
        - RFB onFBUReceive
        - RFB onFBUComplete

Other:
- Add array type support to Util.conf_default()
- Removed a bunch of routines from the Display API that were just used
  internally and not actually by noVNC: flush, setFillColor,
  imageDataGet, imageDataCreate, rgbxImageData, rgbxImageFill,
  cmapImageData, cmapImageFill.
- More keyboard/mouse logging when debug turned on.
- Some JSLinting
parent 2fb665ec
......@@ -41,7 +41,6 @@
*
* ***** END LICENSE BLOCK ***** */
"use strict";
/*jslint white: false, bitwise: false, plusplus: false */
/*global console */
......@@ -52,6 +51,7 @@ toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+
base64Pad : '=',
encode: function (data) {
"use strict";
var result = '',
chrTable = Base64.toBase64Table.split(''),
pad = Base64.base64Pad,
......@@ -95,6 +95,7 @@ toBinaryTable : [
],
decode: function (data, offset) {
"use strict";
offset = typeof(offset) !== 'undefined' ? offset : 0;
var binTable = Base64.toBinaryTable,
pad = Base64.base64Pad,
......
......@@ -9,15 +9,22 @@
/*jslint browser: true, white: false, bitwise: false */
/*global Util, Base64, changeCursor */
function Canvas(conf) {
"use strict";
function Display(conf) {
"use strict";
conf = conf || {}; // Configuration
var that = {}, // Public API interface
// Private Canvas namespace variables
// Private Display namespace variables
c_ctx = null,
c_forceCanvas = false,
c_imageData, c_rgbxImage, c_cmapImage,
// Predefine function variables (jslint)
imageDataCreate, imageDataGet, rgbxImageData, cmapImageData,
rgbxImageFill, cmapImageFill, setFillColor, rescale, flush,
c_width = 0,
c_height = 0,
......@@ -29,19 +36,24 @@ var that = {}, // Public API interface
// Configuration settings
function cdef(v, type, defval, desc) {
Util.conf_default(conf, that, v, type, defval, desc); }
function cdef_ro(v, type, defval, desc) {
Util.conf_default({}, that, v, type, defval, desc); }
// Capability settings, default can be overridden
cdef('prefer_js', 'raw', null, 'Prefer Javascript over canvas methods');
cdef('target', 'dom', null, 'Canvas element for rendering');
cdef_ro('context', 'raw', null, 'Canvas 2D context for rendering (read-only)');
cdef('logo', 'raw', null, 'Logo to display when cleared: {"width": width, "height": height, "data": data}');
cdef('true_color', 'bool', true, 'Use true-color pixel data');
cdef('colourMap', 'arr', [], 'Colour map array (when not true-color)');
cdef('scale', 'float', 1.0, 'Display area scale factor 0.0 - 1.0');
cdef_ro('width', 'int', null, 'Display area width (read-only)');
cdef_ro('height', 'int', null, 'Display area height (read-only)');
cdef_ro('render_mode', 'str', '', 'Canvas rendering mode (read-only)');
cdef('prefer_js', 'str', null, 'Prefer Javascript over canvas methods');
cdef('cursor_uri', 'raw', null, 'Can we render cursor using data URI');
cdef('target', 'dom', null, 'Canvas element for VNC viewport');
cdef('focusContainer', 'dom', document, 'DOM element that traps keyboard input');
cdef('true_color', 'bool', true, 'Request true color pixel data');
cdef('colourMap', 'raw', [], 'Colour map array (not true color)');
cdef('scale', 'float', 1.0, 'Viewport scale factor 0.1 - 1.0');
cdef('render_mode', 'str', '', 'Canvas rendering mode (read-only)');
// Override some specific getters/setters
that.set_prefer_js = function(val) {
if (val && c_forceCanvas) {
......@@ -52,34 +64,19 @@ that.set_prefer_js = function(val) {
return true;
};
that.get_colourMap = function(idx) {
if (typeof idx === 'undefined') {
return conf.colourMap;
} else {
return conf.colourMap[idx];
}
};
that.set_render_mode = function () { throw("render_mode is read-only"); };
that.set_colourMap = function(val, idx) {
if (typeof idx === 'undefined') {
conf.colourMap = val;
} else {
conf.colourMap[idx] = val;
}
};
that.set_scale = function(scale) { rescale(scale); };
that.set_render_mode = function () { throw("render_mode is read-only"); };
that.set_width = function (val) { that.resize(val, c_height); };
that.get_width = function() { return c_width; };
that.set_scale = function(scale) { that.rescale(scale); };
that.set_height = function (val) { that.resize(c_width, val); };
that.get_height = function() { return c_height; };
that.set_context = function () { throw("context is read-only"); };
that.get_context = function () { return c_ctx; };
// Add some other getters/setters
that.get_width = function() {
return c_width;
};
that.get_height = function() {
return c_height;
};
//
// Private functions
......@@ -87,9 +84,9 @@ that.get_height = function() {
// Create the public API interface
function constructor() {
Util.Debug(">> Canvas.init");
Util.Debug(">> Display.constructor");
var c, ctx, func, imgTest, tval, i, curDat, curSave,
var c, func, imgTest, tval, i, curDat, curSave,
has_imageData = false, UE = Util.Engine;
if (! conf.target) { throw("target must be set"); }
......@@ -102,8 +99,7 @@ function constructor() {
if (! c.getContext) { throw("no getContext method"); }
if (! conf.ctx) { conf.ctx = c.getContext('2d'); }
ctx = conf.ctx;
if (! c_ctx) { c_ctx = c.getContext('2d'); }
Util.Debug("User Agent: " + navigator.userAgent);
if (UE.gecko) { Util.Debug("Browser: gecko " + UE.gecko); }
......@@ -119,11 +115,11 @@ function constructor() {
*/
tval = 0;
try {
imgTest = ctx.getImageData(0, 0, 1,1);
imgTest = c_ctx.getImageData(0, 0, 1,1);
imgTest.data[0] = 123;
imgTest.data[3] = 255;
ctx.putImageData(imgTest, 0, 0);
tval = ctx.getImageData(0, 0, 1, 1).data[0];
c_ctx.putImageData(imgTest, 0, 0);
tval = c_ctx.getImageData(0, 0, 1, 1).data[0];
if (tval === 123) {
has_imageData = true;
}
......@@ -132,30 +128,30 @@ function constructor() {
if (has_imageData) {
Util.Info("Canvas supports imageData");
c_forceCanvas = false;
if (ctx.createImageData) {
if (c_ctx.createImageData) {
// If it's there, it's faster
Util.Info("Using Canvas createImageData");
conf.render_mode = "createImageData rendering";
that.imageData = that.imageDataCreate;
} else if (ctx.getImageData) {
c_imageData = imageDataCreate;
} else if (c_ctx.getImageData) {
// I think this is mostly just Opera
Util.Info("Using Canvas getImageData");
conf.render_mode = "getImageData rendering";
that.imageData = that.imageDataGet;
c_imageData = imageDataGet;
}
Util.Info("Prefering javascript operations");
if (conf.prefer_js === null) {
conf.prefer_js = true;
}
that.rgbxImage = that.rgbxImageData;
that.cmapImage = that.cmapImageData;
c_rgbxImage = rgbxImageData;
c_cmapImage = cmapImageData;
} else {
Util.Warn("Canvas lacks imageData, using fillRect (slow)");
conf.render_mode = "fillRect rendering (slow)";
c_forceCanvas = true;
conf.prefer_js = false;
that.rgbxImage = that.rgbxImageFill;
that.cmapImage = that.cmapImageFill;
c_rgbxImage = rgbxImageFill;
c_cmapImage = cmapImageFill;
}
if (UE.webkit && UE.webkit >= 534.7 && UE.webkit <= 534.9) {
......@@ -171,7 +167,7 @@ function constructor() {
return function() {
myfunc.apply(this, arguments);
if (!c_flush_timer) {
c_flush_timer = setTimeout(that.flush, 100);
c_flush_timer = setTimeout(flush, 100);
}
};
}());
......@@ -206,19 +202,11 @@ function constructor() {
conf.cursor_uri = false;
}
Util.Debug("<< Canvas.init");
Util.Debug("<< Display.constructor");
return that ;
}
//
// Public API interface functions
//
that.getContext = function () {
return conf.ctx;
};
that.rescale = function(factor) {
rescale = function(factor) {
var c, tp, x, y,
properties = ['transform', 'WebkitTransform', 'MozTransform', null];
c = conf.target;
......@@ -242,7 +230,7 @@ that.rescale = function(factor) {
}
if (conf.scale === factor) {
//Util.Debug("Canvas already scaled to '" + factor + "'");
//Util.Debug("Display already scaled to '" + factor + "'");
return;
}
......@@ -252,35 +240,10 @@ that.rescale = function(factor) {
c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)";
};
that.resize = function(width, height, true_color) {
var c = conf.target;
if (typeof true_color !== "undefined") {
conf.true_color = true_color;
}
c_prevStyle = "";
c.width = width;
c.height = height;
c_width = c.offsetWidth;
c_height = c.offsetHeight;
that.rescale(conf.scale);
};
that.clear = function() {
that.resize(640, 20);
conf.ctx.clearRect(0, 0, c_width, c_height);
// No benefit over default ("source-over") in Chrome and firefox
//conf.ctx.globalCompositeOperation = "copy";
};
that.flush = function() {
// Force canvas redraw (for webkit bug #46319 workaround)
flush = function() {
var old_val;
//Util.Debug(">> flush");
// Force canvas redraw (for webkit bug #46319 workaround)
old_val = conf.target.style.marginRight;
conf.target.style.marginRight = "1px";
c_flush_timer = null;
......@@ -289,7 +252,7 @@ that.flush = function() {
}, 1);
};
that.setFillColor = function(color) {
setFillColor = function(color) {
var rgb, newStyle;
if (conf.true_color) {
rgb = color;
......@@ -298,18 +261,51 @@ that.setFillColor = function(color) {
}
newStyle = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
if (newStyle !== c_prevStyle) {
conf.ctx.fillStyle = newStyle;
c_ctx.fillStyle = newStyle;
c_prevStyle = newStyle;
}
};
//
// Public API interface functions
//
that.resize = function(width, height) {
var c = conf.target;
c_prevStyle = "";
c.width = width;
c.height = height;
c_width = c.offsetWidth;
c_height = c.offsetHeight;
rescale(conf.scale);
};
that.clear = function() {
if (conf.logo) {
that.resize(conf.logo.width, conf.logo.height);
that.blitStringImage(conf.logo.data, 0, 0);
} else {
that.resize(640, 20);
c_ctx.clearRect(0, 0, c_width, c_height);
}
// No benefit over default ("source-over") in Chrome and firefox
//c_ctx.globalCompositeOperation = "copy";
};
that.fillRect = function(x, y, width, height, color) {
that.setFillColor(color);
conf.ctx.fillRect(x, y, width, height);
setFillColor(color);
c_ctx.fillRect(x, y, width, height);
};
that.copyImage = function(old_x, old_y, new_x, new_y, width, height) {
conf.ctx.drawImage(conf.target, old_x, old_y, width, height,
c_ctx.drawImage(conf.target, old_x, old_y, width, height,
new_x, new_y, width, height);
};
......@@ -374,36 +370,36 @@ that.setSubTile = function(img, x, y, w, h, color) {
that.putTile = function(img) {
if (conf.prefer_js) {
that.rgbxImage(img.x, img.y, img.width, img.height, img.data, 0);
c_rgbxImage(img.x, img.y, img.width, img.height, img.data, 0);
}
// else: No-op, under gecko already done by setSubTile
};
that.imageDataGet = function(width, height) {
return conf.ctx.getImageData(0, 0, width, height);
imageDataGet = function(width, height) {
return c_ctx.getImageData(0, 0, width, height);
};
that.imageDataCreate = function(width, height) {
return conf.ctx.createImageData(width, height);
imageDataCreate = function(width, height) {
return c_ctx.createImageData(width, height);
};
that.rgbxImageData = function(x, y, width, height, arr, offset) {
rgbxImageData = function(x, y, width, height, arr, offset) {
var img, i, j, data;
img = that.imageData(width, height);
img = c_imageData(width, height);
data = img.data;
for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
data[i + 0] = arr[j + 0];
data[i ] = arr[j ];
data[i + 1] = arr[j + 1];
data[i + 2] = arr[j + 2];
data[i + 3] = 255; // Set Alpha
}
conf.ctx.putImageData(img, x, y);
c_ctx.putImageData(img, x, y);
};
// really slow fallback if we don't have imageData
that.rgbxImageFill = function(x, y, width, height, arr, offset) {
rgbxImageFill = function(x, y, width, height, arr, offset) {
var i, j, sx = 0, sy = 0;
for (i=0, j=offset; i < (width * height); i+=1, j+=4) {
that.fillRect(x+sx, y+sy, 1, 1, [arr[j+0], arr[j+1], arr[j+2]]);
that.fillRect(x+sx, y+sy, 1, 1, [arr[j], arr[j+1], arr[j+2]]);
sx += 1;
if ((sx % width) === 0) {
sx = 0;
......@@ -412,22 +408,22 @@ that.rgbxImageFill = function(x, y, width, height, arr, offset) {
}
};
that.cmapImageData = function(x, y, width, height, arr, offset) {
cmapImageData = function(x, y, width, height, arr, offset) {
var img, i, j, data, rgb, cmap;
img = that.imageData(width, height);
img = c_imageData(width, height);
data = img.data;
cmap = conf.colourMap;
for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
rgb = cmap[arr[j]];
data[i + 0] = rgb[0];
data[i ] = rgb[0];
data[i + 1] = rgb[1];
data[i + 2] = rgb[2];
data[i + 3] = 255; // Set Alpha
}
conf.ctx.putImageData(img, x, y);
c_ctx.putImageData(img, x, y);
};
that.cmapImageFill = function(x, y, width, height, arr, offset) {
cmapImageFill = function(x, y, width, height, arr, offset) {
var i, j, sx = 0, sy = 0, cmap;
cmap = conf.colourMap;
for (i=0, j=offset; i < (width * height); i+=1, j+=1) {
......@@ -443,15 +439,15 @@ that.cmapImageFill = function(x, y, width, height, arr, offset) {
that.blitImage = function(x, y, width, height, arr, offset) {
if (conf.true_color) {
that.rgbxImage(x, y, width, height, arr, offset);
c_rgbxImage(x, y, width, height, arr, offset);
} else {
that.cmapImage(x, y, width, height, arr, offset);
c_cmapImage(x, y, width, height, arr, offset);
}
};
that.blitStringImage = function(str, x, y) {
var img = new Image();
img.onload = function () { conf.ctx.drawImage(img, x, y); };
img.onload = function () { c_ctx.drawImage(img, x, y); };
img.src = str;
};
......@@ -469,16 +465,17 @@ that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
};
that.defaultCursor = function() {
conf.target.style.cursor = "default";
conf.target.style.cursor = "default";
};
return constructor(); // Return the public API interface
} // End of Canvas()
} // End of Display()
/* Set CSS cursor property using data URI encoded cursor file */
function changeCursor(target, pixels, mask, hotx, hoty, w, h, cmap) {
"use strict";
var cur = [], rgb, IHDRsz, RGBsz, ANDsz, XORsz, url, idx, alpha, x, y;
//Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w: " + w + ", h: " + h);
......@@ -549,7 +546,7 @@ function changeCursor(target, pixels, mask, hotx, hoty, w, h, cmap) {
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(pixels[idx ]); // red
cur.push(alpha); // alpha
}
}
......
......@@ -13,7 +13,7 @@
//
function Keyboard(conf) {
"use strict";
"use strict";
conf = conf || {}; // Configuration
var that = {}, // Public API interface
......@@ -27,12 +27,12 @@ function cdef(v, type, defval, desc) {
Util.conf_default(conf, that, v, type, defval, desc); }
// Capability settings, default can be overridden
cdef('target', 'dom', document, 'DOM element that grabs keyboard input');
cdef('focused', 'bool', true, 'Capture and send key strokes');
cdef('target', 'dom', document, 'DOM element that captures keyboard input');
cdef('focused', 'bool', true, 'Capture and send key events');
cdef('keyPress', 'func', null, 'Handler for key press/release');
cdef('onKeyPress', 'func', null, 'Handler for key press/release');
that.set_target = function () { throw("target cannot be changed"); }
that.set_target = function() { throw("target cannot be changed"); };
//
// Private functions
......@@ -187,7 +187,7 @@ function getKeysym(evt) {
}
if ((keysym > 255) && (keysym < 0xFF00)) {
msg = "Mapping keysym " + keysym;
msg = "Mapping character code " + keysym;
// Map Unicode outside Latin 1 to X11 keysyms
keysym = unicodeTable[keysym];
if (typeof(keysym) === 'undefined') {
......@@ -200,12 +200,13 @@ function getKeysym(evt) {
}
function show_keyDownList(kind) {
var c;
var msg = "keyDownList (" + kind + "):\n";
for (var c = 0; c < keyDownList.length; c++) {
for (c = 0; c < keyDownList.length; c++) {
msg = msg + " " + c + " - keyCode: " + keyDownList[c].keyCode +
" - which: " + keyDownList[c].which + "\n";
}
//Util.Debug(msg);
Util.Debug(msg);
}
function copyKeyEvent(evt) {
......@@ -302,7 +303,7 @@ function onKeyDown(e) {
}
var fevt = null, evt = (e ? e : window.event),
keysym = null, suppress = false;
Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
//Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
fevt = copyKeyEvent(evt);
......@@ -313,10 +314,11 @@ function onKeyDown(e) {
// If it is a key or key combination that might trigger
// browser behaviors or it has no corresponding keyPress
// event, then send it immediately
if (conf.keyPress && !ignoreKeyEvent(evt)) {
Util.Debug("keyPress down 1, keysym: " + keysym +
" (key: " + evt.keyCode + ", which: " + evt.which + ")");
conf.keyPress(keysym, 1, evt);
if (conf.onKeyPress && !ignoreKeyEvent(evt)) {
Util.Debug("onKeyPress down, keysym: " + keysym +
" (onKeyDown key: " + evt.keyCode +
", which: " + evt.which + ")");
conf.onKeyPress(keysym, 1, evt);
}
suppress = true;
}
......@@ -324,7 +326,7 @@ function onKeyDown(e) {
if (! ignoreKeyEvent(evt)) {
// Add it to the list of depressed keys
pushKeyEvent(fevt);
show_keyDownList('down');
//show_keyDownList('down');
}
if (suppress) {
......@@ -344,7 +346,7 @@ function onKeyPress(e) {
}
var evt = (e ? e : window.event),
kdlen = keyDownList.length, keysym = null;
Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
//Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
if (((evt.which !== "undefined") && (evt.which === 0)) ||
(getKeysymSpecial(evt))) {
......@@ -369,13 +371,14 @@ function onKeyPress(e) {
Util.Warn("keyDownList empty when keyPress triggered");
}
show_keyDownList('press');
//show_keyDownList('press');
// Send the translated keysym
if (conf.keyPress && (keysym > 0)) {
Util.Debug("keyPress down 2, keysym: " + keysym +
" (key: " + evt.keyCode + ", which: " + evt.which + ")");
conf.keyPress(keysym, 1, evt);
if (conf.onKeyPress && (keysym > 0)) {
Util.Debug("onKeyPress down, keysym: " + keysym +
" (onKeyPress key: " + evt.keyCode +
", which: " + evt.which + ")");
conf.onKeyPress(keysym, 1, evt);
}
// Stop keypress events just in case
......@@ -387,8 +390,8 @@ function onKeyUp(e) {
if (! conf.focused) {
return true;
}
var fevt = null, evt = (e ? e : window.event), i, keysym;
Util.Debug("onKeyUp kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
var fevt = null, evt = (e ? e : window.event), keysym;
//Util.Debug("onKeyUp kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
fevt = getKeyEvent(evt.keyCode, true);
......@@ -400,12 +403,15 @@ function onKeyUp(e) {
keysym = 0;
}
show_keyDownList('up');
//show_keyDownList('up');
if (conf.keyPress && (keysym > 0)) {
Util.Debug("keyPress up, keysym: " + keysym +
" (key: " + evt.keyCode + ", which: " + evt.which + ")");
conf.keyPress(keysym, 0, evt);
if (conf.onKeyPress && (keysym > 0)) {
//Util.Debug("keyPress up, keysym: " + keysym +
// " (key: " + evt.keyCode + ", which: " + evt.which + ")");
Util.Debug("onKeyPress up, keysym: " + keysym +
" (onKeyPress key: " + evt.keyCode +
", which: " + evt.which + ")");
conf.onKeyPress(keysym, 0, evt);
}
Util.stopEvent(e);
return false;
......@@ -447,7 +453,7 @@ return that; // Return the public API interface
//
function Mouse(conf) {
"use strict";
"use strict";
conf = conf || {}; // Configuration
var that = {}; // Public API interface
......@@ -458,14 +464,14 @@ function cdef(v, type, defval, desc) {
Util.conf_default(conf, that, v, type, defval, desc); }
// Capability settings, default can be overridden
cdef('target', 'dom', document, 'DOM element that grabs mouse input');
cdef('target', 'dom', document, 'DOM element that captures mouse input');
cdef('focused', 'bool', true, 'Capture and send mouse clicks/movement');
cdef('scale', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0');
cdef('mouseButton', 'func', null, 'Handler for mouse button click/release');
cdef('mouseMove', 'func', null, 'Handler for mouse movement');
cdef('onMouseButton', 'func', null, 'Handler for mouse button click/release');
cdef('onMouseMove', 'func', null, 'Handler for mouse movement');
that.set_target = function () { throw("target cannot be changed"); }
that.set_target = function() { throw("target cannot be changed"); };
//
// Private functions
......@@ -489,8 +495,10 @@ function onMouseButton(e, down) {
}
//Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down +
// " bmask: " + bmask + "(evt.button: " + evt.button + ")");
if (conf.mouseButton) {
conf.mouseButton(pos.x, pos.y, down, bmask);
if (conf.onMouseButton) {
Util.Debug("onMouseButton " + (down ? "down" : "up") +
", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
conf.onMouseButton(pos.x, pos.y, down, bmask);
}
Util.stopEvent(e);
return false;
......@@ -518,9 +526,9 @@ function onMouseWheel(e) {
bmask = 1 << 4;
}
//Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y);
if (conf.mouseButton) {
conf.mouseButton(pos.x, pos.y, 1, bmask);
conf.mouseButton(pos.x, pos.y, 0, bmask);
if (conf.onMouseButton) {
conf.onMouseButton(pos.x, pos.y, 1, bmask);
conf.onMouseButton(pos.x, pos.y, 0, bmask);
}
Util.stopEvent(e);
return false;
......@@ -534,8 +542,8 @@ function onMouseMove(e) {
evt = (e ? e : window.event);
pos = Util.getEventPosition(e, conf.target, conf.scale);
//Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y);
if (conf.mouseMove) {
conf.mouseMove(pos.x, pos.y);
if (conf.onMouseMove) {
conf.onMouseMove(pos.x, pos.y);
}
}
......@@ -1862,5 +1870,5 @@ unicodeTable = {
0x28fc : 0x10028fc,
0x28fd : 0x10028fd,
0x28fe : 0x10028fe,
0x28ff : 0x10028ff,
0x28ff : 0x10028ff
};
......@@ -7,11 +7,11 @@
*/
/*jslint white: false, browser: true, bitwise: false, plusplus: false */
/*global window, Util, Canvas, Keyboard, Mouse, Websock, Websock_native, Base64, DES, noVNC_logo */
/*global window, Util, Display, Keyboard, Mouse, Websock, Websock_native, Base64, DES, noVNC_logo */
function RFB(conf) {
"use strict";
"use strict";
conf = conf || {}; // Configuration
var that = {}, // Public API interface
......@@ -64,7 +64,7 @@ var that = {}, // Public API interface
encStats = {}, // [rectCnt, rectCntTot]
ws = null, // Websock object
canvas = null, // Canvas object
display = null, // Display object
keyboard = null, // Keyboard input handler object
mouse = null, // Mouse input handler object
sendTimer = null, // Send Queue check timer
......@@ -124,8 +124,8 @@ var that = {}, // Public API interface
function cdef(v, type, defval, desc) {
Util.conf_default(conf, that, v, type, defval, desc); }
cdef('target', 'str', null, 'VNC viewport rendering Canvas');
cdef('focusContainer', 'dom', document, 'Area that traps keyboard input');
cdef('target', 'dom', null, 'VNC display rendering Canvas object');
cdef('focusContainer', 'dom', document, 'DOM element that captures keyboard input');
cdef('encrypt', 'bool', false, 'Use TLS/SSL/wss encryption');
cdef('true_color', 'bool', true, 'Request true color pixel data');
......@@ -141,12 +141,25 @@ cdef('disconnectTimeout', 'int', 3, 'Time (s) to wait for disconnection');
cdef('check_rate', 'int', 217, 'Timing (ms) of send/receive check');
cdef('fbu_req_rate', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests');
cdef('updateState',
'func', function() { Util.Debug("updateState stub"); },
'callback: state update');
cdef('clipboardReceive',
'func', function() { Util.Debug("clipboardReceive stub"); },
'callback: clipboard contents received');
// Callback functions
cdef('onUpdateState', 'func', function() { },
'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change ');
cdef('onPasswordRequired', 'func', function() { },
'onPasswordRequired(rfb): VNC password is required ');
cdef('onClipboard', 'func', function() { },
'onClipboard(rfb, text): RFB clipboard contents received');
cdef('onBell', 'func', function() { },
'onBell(rfb): RFB Bell message received ');
cdef('onFBUReceive', 'func', function() { },
'onFBUReceive(rfb, fbu): RFB FBU received but not yet processed ');
cdef('onFBUComplete', 'func', function() { },
'onFBUComplete(rfb, fbu): RFB FBU received and processed ');
// These callback names are deprecated
cdef('updateState', 'func', function() { },
'obsolete, use onUpdateState');
cdef('clipboardReceive', 'func', function() { },
'obsolete, use onClipboard');
// Override/add some specific getters/setters
......@@ -154,7 +167,7 @@ that.set_local_cursor = function(cursor) {
if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) {
conf.local_cursor = false;
} else {
if (canvas.get_cursor_uri()) {
if (display.get_cursor_uri()) {
conf.local_cursor = true;
} else {
Util.Warn("Browser does not support local cursor");
......@@ -162,8 +175,8 @@ that.set_local_cursor = function(cursor) {
}
};
that.get_canvas = function() {
return canvas;
that.get_display = function() {
return display;
};
that.get_keyboard = function() {
return keyboard;
......@@ -181,7 +194,8 @@ that.get_mouse = function() {
// Setup routines
//
// Create the public API interface and initialize
// Create the public API interface and initialize values that stay
// constant across connect/disconnect
function constructor() {
var i, rmode;
Util.Debug(">> RFB.constructor");
......@@ -192,19 +206,49 @@ function constructor() {
encNames[encodings[i][1]] = encodings[i][0];
encStats[encodings[i][1]] = [0, 0];
}
// Initialize canvas, mouse and keyboard
// Initialize display, mouse, keyboard, and websock
try {
canvas = new Canvas({'target': conf.target});
keyboard = new Keyboard({'target': conf.focusContainer,
'keyPress': keyPress});
mouse = new Mouse({'target': conf.target,
'mouseButton': mouseButton,
'mouseMove': mouseMove});
display = new Display({'target': conf.target});
} catch (exc) {
Util.Error("Canvas exception: " + exc);
updateState('fatal', "No working Canvas");
Util.Error("Display exception: " + exc);
updateState('fatal', "No working Display");
}
rmode = canvas.get_render_mode();
keyboard = new Keyboard({'target': conf.focusContainer,
'onKeyPress': keyPress});
mouse = new Mouse({'target': conf.target,
'onMouseButton': mouseButton,
'onMouseMove': mouseMove});
rmode = display.get_render_mode();
if (typeof noVNC_logo !== 'undefined') {
display.set_logo(noVNC_logo);
}
ws = new Websock();
ws.on('message', handle_message);
ws.on('open', function() {
if (rfb_state === "connect") {
updateState('ProtocolVersion', "Starting VNC handshake");
} else {
fail("Got unexpected WebSockets connection");
}
});
ws.on('close', function() {
if (rfb_state === 'disconnect') {
updateState('disconnected', 'VNC disconnected');
} else if (rfb_state === 'ProtocolVersion') {
fail('Failed to connect to server');
} else if (rfb_state in {'failed':1, 'disconnected':1}) {
Util.Error("Received onclose while disconnected");
} else {
fail('Server disconnected');
}
});
ws.on('error', function(e) {
fail("WebSock error: " + e);
});
init_vars();
......@@ -246,36 +290,13 @@ function connect() {
Util.Debug("<< RFB.connect");
}
// Initialize variables that are reset before each connection
init_vars = function() {
var i;
/* Reset state */
ws = new Websock();
ws.init();
ws.on('message', handle_message);
ws.on('open', function() {
if (rfb_state === "connect") {
updateState('ProtocolVersion', "Starting VNC handshake");
} else {
fail("Got unexpected WebSockets connection");
}
});
ws.on('close', function() {
if (rfb_state === 'disconnect') {
updateState('disconnected', 'VNC disconnected');
} else if (rfb_state === 'ProtocolVersion') {
fail('Failed to connect to server');
} else if (rfb_state in {'failed':1, 'disconnected':1}) {
Util.Error("Received onclose while disconnected");
} else {
fail('Server disconnected');
}
});
ws.on('error', function(e) {
fail("WebSock error: " + e);
});
FBU.rects = 0;
FBU.subrects = 0; // RRE and HEXTILE
FBU.lines = 0; // RAW
......@@ -317,25 +338,23 @@ print_stats = function() {
/*
* Running states:
* disconnected - idle state
* normal - connected
*
* Page states:
* loaded - page load, equivalent to disconnected
* connect - starting initialization
* disconnect - starting disconnect
* failed - abnormal transition to disconnected
* disconnected - idle state
* connect - starting to connect (to ProtocolVersion)
* normal - connected
* disconnect - starting to disconnect
* failed - abnormal disconnect
* fatal - failed to load page, or fatal error
*
* VNC initialization states:
* ProtocolVersion
* RFB protocol initialization states:
* ProtocolVersion
* Security
* Authentication
* password - waiting for password, not part of RFB
* SecurityResult
* ClientInitialization - not triggered by server message
* ServerInitialization
* ServerInitialization (to normal)
*/
updateState = function(state, statusMsg) {
var func, cmsg, oldstate = rfb_state;
......@@ -362,22 +381,15 @@ updateState = function(state, statusMsg) {
msgTimer = null;
}
if (canvas && canvas.getContext()) {
if (display && display.get_context()) {
keyboard.ungrab();
mouse.ungrab();
canvas.defaultCursor();
if (Util.get_logging() !== 'debug') {
canvas.clear();
}
display.defaultCursor();
if ((Util.get_logging() !== 'debug') ||
(state === 'loaded')) {
// Show noVNC logo on load and when disconnected if
// debug is off
if (typeof noVNC_logo !== 'undefined' && noVNC_logo) {
canvas.resize(noVNC_logo.width, noVNC_logo.height);
canvas.blitStringImage(noVNC_logo.data, 0, 0);
}
display.clear();
}
}
......@@ -476,9 +488,11 @@ updateState = function(state, statusMsg) {
if ((oldstate === 'failed') && (state === 'disconnected')) {
// Leave the failed message
conf.updateState(that, state, oldstate);
conf.updateState(that, state, oldstate); // Obsolete
conf.onUpdateState(that, state, oldstate);
} else {
conf.updateState(that, state, oldstate, statusMsg);
conf.updateState(that, state, oldstate, statusMsg); // Obsolete
conf.onUpdateState(that, state, oldstate, statusMsg);
}
};
......@@ -681,7 +695,10 @@ init_msg = function() {
break;
case 2: // VNC authentication
if (rfb_password.length === 0) {
// Notify via both callbacks since it is kind of
// a RFB state change and a UI interface issue.
updateState('password', "Password Required");
conf.onPasswordRequired(that);
return;
}
if (ws.rQwait("auth challenge", 16)) { return false; }
......@@ -759,7 +776,8 @@ init_msg = function() {
name_length = ws.rQshift32();
fb_name = ws.rQshiftStr(name_length);
canvas.resize(fb_width, fb_height, conf.true_color);
display.set_true_color(conf.true_color);
display.resize(fb_width, fb_height);
keyboard.grab();
mouse.grab();
......@@ -796,7 +814,7 @@ init_msg = function() {
normal_msg = function() {
//Util.Debug(">> normal_msg");
var ret = true, msg_type, length,
var ret = true, msg_type, length, text,
c, first_colour, num_colours, red, green, blue;
if (FBU.rects > 0) {
......@@ -820,13 +838,15 @@ normal_msg = function() {
//Util.Debug("red after: " + red);
green = parseInt(ws.rQshift16() / 256, 10);
blue = parseInt(ws.rQshift16() / 256, 10);
canvas.set_colourMap([red, green, blue], first_colour + c);
Util.Debug("*** colourMap: " + display.get_colourMap());
display.set_colourMap([red, green, blue], first_colour + c);
}
Util.Info("Registered " + num_colours + " colourMap entries");
//Util.Debug("colourMap: " + canvas.get_colourMap());
//Util.Debug("colourMap: " + display.get_colourMap());
break;
case 2: // Bell
Util.Warn("Bell (unsupported)");
Util.Debug("Bell");
conf.onBell(that);
break;
case 3: // ServerCutText
Util.Debug("ServerCutText");
......@@ -835,7 +855,9 @@ normal_msg = function() {
length = ws.rQshift32();
if (ws.rQwait("ServerCutText", length, 8)) { return false; }
conf.clipboardReceive(that, ws.rQshiftStr(length));
text = ws.rQshiftStr(length);
conf.clipboardReceive(that, text); // Obsolete
conf.onClipboard(that, text);
break;
default:
fail("Disconnected: illegal server message type " + msg_type);
......@@ -883,6 +905,12 @@ framebufferUpdate = function() {
FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
(hdr[10] << 8) + hdr[11], 10);
conf.onFBUReceive(that,
{'x': FBU.x, 'y': FBU.y,
'width': FBU.width, 'height': FBU.height,
'encoding': FBU.encoding,
'encodingName': encNames[FBU.encoding]});
if (encNames[FBU.encoding]) {
// Debug:
/*
......@@ -943,6 +971,13 @@ framebufferUpdate = function() {
return ret; // false ret means need more data
}
}
conf.onFBUComplete(that,
{'x': FBU.x, 'y': FBU.y,
'width': FBU.width, 'height': FBU.height,
'encoding': FBU.encoding,
'encodingName': encNames[FBU.encoding]});
return true; // We finished this FBU
};
......@@ -963,7 +998,7 @@ encHandlers.RAW = function display_raw() {
cur_y = FBU.y + (FBU.height - FBU.lines);
cur_height = Math.min(FBU.lines,
Math.floor(ws.rQlen()/(FBU.width * fb_Bpp)));
canvas.blitImage(FBU.x, cur_y, FBU.width, cur_height,
display.blitImage(FBU.x, cur_y, FBU.width, cur_height,
ws.get_rQ(), ws.get_rQi());
ws.rQshiftBytes(FBU.width * cur_height * fb_Bpp);
FBU.lines -= cur_height;
......@@ -986,7 +1021,7 @@ encHandlers.COPYRECT = function display_copy_rect() {
if (ws.rQwait("COPYRECT", 4)) { return false; }
old_x = ws.rQshift16();
old_y = ws.rQshift16();
canvas.copyImage(old_x, old_y, FBU.x, FBU.y, FBU.width, FBU.height);
display.copyImage(old_x, old_y, FBU.x, FBU.y, FBU.width, FBU.height);
FBU.rects -= 1;
FBU.bytes = 0;
return true;
......@@ -1000,7 +1035,7 @@ encHandlers.RRE = function display_rre() {
if (ws.rQwait("RRE", 4+fb_Bpp)) { return false; }
FBU.subrects = ws.rQshift32();
color = ws.rQshiftBytes(fb_Bpp); // Background
canvas.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
display.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
}
while ((FBU.subrects > 0) && (ws.rQlen() >= (fb_Bpp + 8))) {
color = ws.rQshiftBytes(fb_Bpp);
......@@ -1008,7 +1043,7 @@ encHandlers.RRE = function display_rre() {
y = ws.rQshift16();
width = ws.rQshift16();
height = ws.rQshift16();
canvas.fillRect(FBU.x + x, FBU.y + y, width, height, color);
display.fillRect(FBU.x + x, FBU.y + y, width, height, color);
FBU.subrects -= 1;
}
//Util.Debug(" display_rre: rects: " + FBU.rects +
......@@ -1101,10 +1136,10 @@ encHandlers.HEXTILE = function display_hextile() {
/* Weird: ignore blanks after RAW */
Util.Debug(" Ignoring blank after RAW");
} else {
canvas.fillRect(x, y, w, h, FBU.background);
display.fillRect(x, y, w, h, FBU.background);
}
} else if (FBU.subencoding & 0x01) { // Raw
canvas.blitImage(x, y, w, h, rQ, rQi);
display.blitImage(x, y, w, h, rQ, rQi);
rQi += FBU.bytes - 1;
} else {
if (FBU.subencoding & 0x02) { // Background
......@@ -1116,7 +1151,7 @@ encHandlers.HEXTILE = function display_hextile() {
rQi += fb_Bpp;
}
tile = canvas.getTile(x, y, w, h, FBU.background);
tile = display.getTile(x, y, w, h, FBU.background);
if (FBU.subencoding & 0x08) { // AnySubrects
subrects = rQ[rQi];
rQi += 1;
......@@ -1137,10 +1172,10 @@ encHandlers.HEXTILE = function display_hextile() {
sw = (wh >> 4) + 1;
sh = (wh & 0x0f) + 1;
canvas.setSubTile(tile, sx, sy, sw, sh, color);
display.setSubTile(tile, sx, sy, sw, sh, color);
}
}
canvas.putTile(tile);
display.putTile(tile);
}
ws.set_rQi(rQi);
FBU.lastsubencoding = FBU.subencoding;
......@@ -1205,7 +1240,7 @@ encHandlers.TIGHT_PNG = function display_tight_png() {
case "fill":
ws.rQshift8(); // shift off ctl
color = ws.rQshiftBytes(fb_depth);
canvas.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
display.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
break;
case "jpeg":
case "png":
......@@ -1242,7 +1277,7 @@ extract_data_uri = function(arr) {
scan_tight_imgQ = function() {
var img, imgQ, ctx;
ctx = canvas.getContext();
ctx = display.get_context();
if (rfb_state === 'normal') {
imgQ = FBU.imgQ;
while ((imgQ.length > 0) && (imgQ[0][0].complete)) {
......@@ -1257,8 +1292,7 @@ encHandlers.DesktopSize = function set_desktopsize() {
Util.Debug(">> set_desktopsize");
fb_width = FBU.width;
fb_height = FBU.height;
canvas.clear();
canvas.resize(fb_width, fb_height);
display.resize(fb_width, fb_height);
timing.fbu_rt_start = (new Date()).getTime();
// Send a new non-incremental request
ws.send(fbUpdateRequest(0));
......@@ -1286,7 +1320,7 @@ encHandlers.Cursor = function set_cursor() {
//Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
canvas.changeCursor(ws.rQshiftBytes(pixelslength),
display.changeCursor(ws.rQshiftBytes(pixelslength),
ws.rQshiftBytes(masklength),
x, y, w, h);
......
......@@ -8,7 +8,7 @@
"use strict";
/*jslint white: false, browser: true */
/*global window, $D, Util, WebUtil, RFB, Canvas, Element, Fx */
/*global window, $D, Util, WebUtil, RFB, Display */
var UI = {
......@@ -59,8 +59,8 @@ load: function(target) {
html += ' id="menuButton"';
html += ' onclick="UI.clickSettingsMenu();">';
html += ' <span id="VNC_settings_menu"';
html += ' onmouseover="UI.canvasBlur();"';
html += ' onmouseout="UI.canvasFocus();">';
html += ' onmouseover="UI.displayBlur();"';
html += ' onmouseout="UI.displayFocus();">';
html += ' <ul>';
html += ' <li><input id="VNC_encrypt"';
html += ' type="checkbox"> Encrypt</li>';
......@@ -115,8 +115,8 @@ load: function(target) {
html += ' onclick="UI.clipClear();">';
html += ' <br>';
html += ' <textarea id="VNC_clipboard_text" cols=80 rows=5';
html += ' onfocus="UI.canvasBlur();"';
html += ' onblur="UI.canvasFocus();"';
html += ' onfocus="UI.displayBlur();"';
html += ' onblur="UI.displayFocus();"';
html += ' onchange="UI.clipSend();"></textarea>';
html += '</div>';
target.innerHTML = html;
......@@ -140,8 +140,8 @@ load: function(target) {
UI.initSetting('connectTimeout', 2);
UI.rfb = RFB({'target': $D('VNC_canvas'),
'updateState': UI.updateState,
'clipboardReceive': UI.clipReceive});
'onUpdateState': UI.updateState,
'onClipboard': UI.clipReceive});
// Unfocus clipboard when over the VNC area
$D('VNC_screen').onmousemove = function () {
......@@ -233,7 +233,7 @@ clickSettingsMenu: function() {
} else {
UI.updateSetting('encrypt');
UI.updateSetting('true_color');
if (UI.rfb.get_canvas().get_cursor_uri()) {
if (UI.rfb.get_display().get_cursor_uri()) {
UI.updateSetting('cursor');
} else {
UI.updateSetting('cursor', false);
......@@ -265,7 +265,7 @@ settingsDisabled: function(disabled, rfb) {
//Util.Debug(">> settingsDisabled");
$D('VNC_encrypt').disabled = disabled;
$D('VNC_true_color').disabled = disabled;
if (rfb && rfb.get_canvas() && rfb.get_canvas().get_cursor_uri()) {
if (rfb && rfb.get_display() && rfb.get_display().get_cursor_uri()) {
$D('VNC_cursor').disabled = disabled;
} else {
UI.updateSetting('cursor', false);
......@@ -281,7 +281,7 @@ settingsApply: function() {
//Util.Debug(">> settingsApply");
UI.saveSetting('encrypt');
UI.saveSetting('true_color');
if (UI.rfb.get_canvas().get_cursor_uri()) {
if (UI.rfb.get_display().get_cursor_uri()) {
UI.saveSetting('cursor');
}
UI.saveSetting('shared');
......@@ -398,12 +398,12 @@ disconnect: function() {
UI.rfb.disconnect();
},
canvasBlur: function() {
displayBlur: function() {
UI.rfb.get_keyboard().set_focused(false);
UI.rfb.get_mouse().set_focused(false);
},
canvasFocus: function() {
displayFocus: function() {
UI.rfb.get_keyboard().set_focused(true);
UI.rfb.get_mouse().set_focused(true);
},
......
......@@ -89,32 +89,47 @@ Util.conf_default = function(cfg, api, v, type, defval, desc) {
api['get_' + v + '_desc'] = desc;
// Default getter
if (typeof api['get_' + v] === 'undefined') {
api['get_' + v] = function () {
api['get_' + v] = function (idx) {
if ((type in {'arr':1, 'array':1}) &&
(typeof idx !== 'undefined')) {
return cfg[v][idx];
} else {
return cfg[v];
};
}
};
}
// Default setter
if (typeof api['set_' + v] === 'undefined') {
api['set_' + v] = function (val) {
if (type in {'boolean':1, 'bool':1}) {
if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
val = false;
} else {
val = true;
}
} else if (type in {'integer':1, 'int':1}) {
val = parseInt(val, 10);
} else if (type === 'func') {
if (!val) {
val = function () {};
}
api['set_' + v] = function (val, idx) {
if (type in {'boolean':1, 'bool':1}) {
if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
val = false;
} else {
val = true;
}
} else if (type in {'integer':1, 'int':1}) {
val = parseInt(val, 10);
} else if (type === 'func') {
if (!val) {
val = function () {};
}
}
if (typeof idx !== 'undefined') {
cfg[v][idx] = val;
} else {
cfg[v] = val;
};
}
};
}
if (typeof cfg[v] === 'undefined') {
// Set to default
if (type in {'arr':1, 'array':1}) {
if (! (defval instanceof Array)) {
defval = [];
}
}
api['set_' + v](defval);
} else {
// Coerce existing setting to the right type
......
......@@ -6,7 +6,6 @@
* See README.md for usage and integration instructions.
*/
"use strict";
/*jslint evil: true */
/*global window, document, INCLUDE_URI */
......@@ -18,6 +17,8 @@ function get_INCLUDE_URI() {
}
(function () {
"use strict";
var extra = "", start, end;
start = "<script src='" + get_INCLUDE_URI();
......@@ -34,7 +35,7 @@ function get_INCLUDE_URI() {
extra += start + "websock.js" + end;
extra += start + "des.js" + end;
extra += start + "input.js" + end;
extra += start + "canvas.js" + end;
extra += start + "display.js" + end;
extra += start + "rfb.js" + end;
document.write(extra);
......
......@@ -45,6 +45,7 @@ if (window.WebSocket) {
function Websock() {
"use strict";
var api = {}, // Public API
websocket = null, // WebSocket object
......@@ -75,7 +76,7 @@ function get_rQ() {
function get_rQi() {
return rQi;
}
set_rQi = function(val) {
function set_rQi(val) {
rQi = val;
};
......@@ -252,23 +253,28 @@ function init() {
function open(uri) {
init();
websocket = new WebSocket(uri);
websocket = new WebSocket(uri, 'base64');
// TODO: future native binary support
//websocket = new WebSocket(uri, ['binary', 'base64']);
websocket.onmessage = recv_message;
websocket.onopen = function(e) {
websocket.onopen = function() {
Util.Debug(">> WebSock.onopen");
if (websocket.protocol) {
Util.Info("Server chose sub-protocol: " + websocket.protocol);
}
eventHandlers.open();
Util.Debug("<< WebSock.onopen");
};
websocket.onclose = function(e) {
Util.Debug(">> WebSock.onclose");
eventHandlers.close();
eventHandlers.close(e);
Util.Debug("<< WebSock.onclose");
};
websocket.onerror = function(e) {
Util.Debug("<< WebSock.onerror: " + e);
Util.Debug(">> WebSock.onerror: " + e);
eventHandlers.error(e);
Util.Debug("<< WebSock.onerror: ");
Util.Debug("<< WebSock.onerror");
};
}
......@@ -309,7 +315,6 @@ function constructor() {
api.send = send;
api.send_string = send_string;
api.recv_message = recv_message;
api.on = on;
api.init = init;
api.open = open;
......
......@@ -42,6 +42,16 @@
var rfb;
function passwordRequired(rfb) {
var msg;
msg = '<form onsubmit="return setPassword();"';
msg += ' style="margin-bottom: 0px">';
msg += 'Password Required: ';
msg += '<input type=password size=10 id="password_input" class="VNC_status">';
msg += '<\/form>';
$D('VNC_status_bar').setAttribute("class", "VNC_status_warn");
$D('VNC_status').innerHTML = msg;
}
function setPassword() {
rfb.sendPassword($D('password_input').value);
return false;
......@@ -51,39 +61,24 @@
return false;
}
function updateState(rfb, state, oldstate, msg) {
var s, sb, cad, klass;
var s, sb, cad, level;
s = $D('VNC_status');
sb = $D('VNC_status_bar');
cad = $D('sendCtrlAltDelButton');
switch (state) {
case 'failed':
case 'fatal':
klass = "VNC_status_error";
break;
case 'normal':
klass = "VNC_status_normal";
break;
case 'disconnected':
case 'loaded':
klass = "VNC_status_normal";
break;
case 'password':
msg = '<form onsubmit="return setPassword();"';
msg += ' style="margin-bottom: 0px">';
msg += 'Password Required: ';
msg += '<input type=password size=10 id="password_input" class="VNC_status">';
msg += '<\/form>';
klass = "VNC_status_warn";
break;
default:
klass = "VNC_status_warn";
case 'failed': level = "error"; break;
case 'fatal': level = "error"; break;
case 'normal': level = "normal"; break;
case 'disconnected': level = "normal"; break;
case 'loaded': level = "normal"; break;
default: level = "warn"; break;
}
if (state === "normal") { cad.disabled = false; }
else { cad.disabled = true; }
if (typeof(msg) !== 'undefined') {
sb.setAttribute("class", klass);
sb.setAttribute("class", "VNC_status_" + level);
s.innerHTML = msg;
}
}
......@@ -107,7 +102,8 @@
'true_color': WebUtil.getQueryVar('true_color', true),
'local_cursor': WebUtil.getQueryVar('cursor', true),
'shared': WebUtil.getQueryVar('shared', true),
'updateState': updateState});
'updateState': updateState,
'onPasswordRequired': passwordRequired});
rfb.connect(host, port, password);
};
</script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment