From 5210330a6c4dde7963ac50c2c07dba7776e12d0c Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 11 May 2011 17:31:53 -0500 Subject: [PATCH] Refactor configuration attributes. - Add conf_defaults which accepts an array of configuration attributes. - Split out user configuration defaults from the actual configuration object. - Add mode field and enforce read-only, write-once, read-write modes. --- include/display.js | 60 +++++++++++------------ include/input.js | 49 ++++++++----------- include/rfb.js | 93 ++++++++++++++++------------------- include/util.js | 117 +++++++++++++++++++++++++++------------------ 4 files changed, 158 insertions(+), 161 deletions(-) diff --git a/include/display.js b/include/display.js index 9cd0d68c..d7aa43f4 100644 --- a/include/display.js +++ b/include/display.js @@ -9,11 +9,11 @@ /*jslint browser: true, white: false, bitwise: false */ /*global Util, Base64, changeCursor */ -function Display(conf) { +function Display(defaults) { "use strict"; -conf = conf || {}; // Configuration -var that = {}, // Public API interface +var that = {}, // Public API methods + conf = {}, // Configuration attributes // Private Display namespace variables c_ctx = null, @@ -33,38 +33,25 @@ var that = {}, // Public API interface c_webkit_bug = false, c_flush_timer = null; -// 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); } +// Configuration attributes +Util.conf_defaults(conf, that, defaults, [ + ['target', 'wo', 'dom', null, 'Canvas element for rendering'], + ['context', 'ro', 'raw', null, 'Canvas 2D context for rendering (read-only)'], + ['logo', 'rw', 'raw', null, 'Logo to display when cleared: {"width": width, "height": height, "data": data}'], + ['true_color', 'rw', 'bool', true, 'Use true-color pixel data'], + ['colourMap', 'rw', 'arr', [], 'Colour map array (when not true-color)'], + ['scale', 'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'], + ['width', 'rw', 'int', null, 'Display area width'], + ['height', 'rw', 'int', null, 'Display area height'], -// Capability settings, default can be overridden -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)'); + ['render_mode', 'ro', 'str', '', 'Canvas rendering mode (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'); + ['prefer_js', 'rw', 'str', null, 'Prefer Javascript over canvas methods'], + ['cursor_uri', 'rw', 'raw', null, 'Can we render cursor using data URI'] + ]); // Override some specific getters/setters -that.set_prefer_js = function(val) { - if (val && c_forceCanvas) { - Util.Warn("Preferring Javascript to Canvas ops is not supported"); - return false; - } - conf.prefer_js = val; - return true; -}; - -that.set_render_mode = function () { throw("render_mode is read-only"); }; +that.get_context = function () { return c_ctx; }; that.set_scale = function(scale) { rescale(scale); }; @@ -74,8 +61,15 @@ that.get_width = function() { return c_width; }; 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; }; +that.set_prefer_js = function(val) { + if (val && c_forceCanvas) { + Util.Warn("Preferring Javascript to Canvas ops is not supported"); + return false; + } + conf.prefer_js = val; + return true; +}; + // diff --git a/include/input.js b/include/input.js index 43c114e6..47b6d772 100644 --- a/include/input.js +++ b/include/input.js @@ -12,33 +12,28 @@ // Keyboard event handler // -function Keyboard(conf) { +function Keyboard(defaults) { "use strict"; -conf = conf || {}; // Configuration -var that = {}, // Public API interface +var that = {}, // Public API methods + conf = {}, // Configuration attributes keyDownList = []; // List of depressed keys // (even if they are happy) +// Configuration attributes +Util.conf_defaults(conf, that, defaults, [ + ['target', 'wo', 'dom', document, 'DOM element that captures keyboard input'], + ['focused', 'rw', 'bool', true, 'Capture and send key events'], -// Configuration settings -function cdef(v, type, defval, desc) { - Util.conf_default(conf, that, v, type, defval, desc); } + ['onKeyPress', 'rw', 'func', null, 'Handler for key press/release'] + ]); -// Capability settings, default can be overridden -cdef('target', 'dom', document, 'DOM element that captures keyboard input'); -cdef('focused', 'bool', true, 'Capture and send key events'); - -cdef('onKeyPress', 'func', null, 'Handler for key press/release'); - -that.set_target = function() { throw("target cannot be changed"); }; // // Private functions // - // From the event keyCode return the keysym value for keys that need // to be suppressed otherwise they may trigger unintended browser // actions @@ -452,26 +447,22 @@ return that; // Return the public API interface // Mouse event handler // -function Mouse(conf) { +function Mouse(defaults) { "use strict"; -conf = conf || {}; // Configuration -var that = {}; // Public API interface +var that = {}, // Public API methods + conf = {}; // Configuration attributes +// Configuration attributes +Util.conf_defaults(conf, that, defaults, [ + ['target', 'ro', 'dom', document, 'DOM element that captures mouse input'], + ['focused', 'rw', 'bool', true, 'Capture and send mouse clicks/movement'], + ['scale', 'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'], -// Configuration settings -function cdef(v, type, defval, desc) { - Util.conf_default(conf, that, v, type, defval, desc); } + ['onMouseButton', 'rw', 'func', null, 'Handler for mouse button click/release'], + ['onMouseMove', 'rw', 'func', null, 'Handler for mouse movement'] + ]); -// Capability settings, default can be overridden -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('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"); }; // // Private functions diff --git a/include/rfb.js b/include/rfb.js index 485adfb5..a743c1aa 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -10,11 +10,11 @@ /*global window, Util, Display, Keyboard, Mouse, Websock, Websock_native, Base64, DES, noVNC_logo */ -function RFB(conf) { +function RFB(defaults) { "use strict"; -conf = conf || {}; // Configuration -var that = {}, // Public API interface +var that = {}, // Public API methods + conf = {}, // Configuration attributes // Pre-declare private functions used before definitions (jslint) init_vars, updateState, fail, handle_message, @@ -113,56 +113,51 @@ var that = {}, // Public API interface test_mode = false, + def_con_timeout = Websock_native ? 2 : 5, + /* Mouse state */ mouse_buttonMask = 0, mouse_arr = []; +// Configuration attributes +Util.conf_defaults(conf, that, defaults, [ + ['target', 'wo', 'dom', null, 'VNC display rendering Canvas object'], + ['focusContainer', 'wo', 'dom', document, 'DOM element that captures keyboard input'], -// -// Configuration settings -// -function cdef(v, type, defval, desc) { - Util.conf_default(conf, that, v, type, defval, desc); } + ['encrypt', 'rw', 'bool', false, 'Use TLS/SSL/wss encryption'], + ['true_color', 'rw', 'bool', true, 'Request true color pixel data'], + ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'], + ['shared', 'rw', 'bool', true, 'Request shared mode'], -cdef('target', 'dom', null, 'VNC display rendering Canvas object'); -cdef('focusContainer', 'dom', document, 'DOM element that captures keyboard input'); + ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'], + ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], -cdef('encrypt', 'bool', false, 'Use TLS/SSL/wss encryption'); -cdef('true_color', 'bool', true, 'Request true color pixel data'); -cdef('local_cursor', 'bool', false, 'Request locally rendered cursor'); -cdef('shared', 'bool', true, 'Request shared mode'); + ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'], + ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'], -if (Websock_native) { - cdef('connectTimeout', 'int', 2, 'Time (s) to wait for connection'); -} else { - cdef('connectTimeout', 'int', 5, 'Time (s) to wait for connection'); -} -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'); + // Callback functions + ['onUpdateState', 'rw', 'func', function() { }, + 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '], + ['onPasswordRequired', 'rw', 'func', function() { }, + 'onPasswordRequired(rfb): VNC password is required '], + ['onClipboard', 'rw', 'func', function() { }, + 'onClipboard(rfb, text): RFB clipboard contents received'], + ['onBell', 'rw', 'func', function() { }, + 'onBell(rfb): RFB Bell message received '], + ['onFBUReceive', 'rw', 'func', function() { }, + 'onFBUReceive(rfb, fbu): RFB FBU received but not yet processed '], + ['onFBUComplete', 'rw', 'func', function() { }, + 'onFBUComplete(rfb, fbu): RFB FBU received and processed '], -// 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'); + // These callback names are deprecated + ['updateState', 'rw', 'func', function() { }, + 'obsolete, use onUpdateState'], + ['clipboardReceive', 'rw', 'func', function() { }, + 'obsolete, use onClipboard'] + ]); -// Override/add some specific getters/setters +// Override/add some specific configuration getters/setters that.set_local_cursor = function(cursor) { if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) { conf.local_cursor = false; @@ -175,18 +170,12 @@ that.set_local_cursor = function(cursor) { } }; -that.get_display = function() { - return display; -}; -that.get_keyboard = function() { - return keyboard; -}; -that.get_mouse = function() { - return mouse; -}; - +// These are fake configuration getters +that.get_display = function() { return display; }; +that.get_keyboard = function() { return keyboard; }; +that.get_mouse = function() { return mouse; }; diff --git a/include/util.js b/include/util.js index 835ea0a0..738c7bb9 100644 --- a/include/util.js +++ b/include/util.js @@ -83,60 +83,83 @@ Util.get_logging = function () { Util.init_logging(); -// Set defaults for Crockford style function namespaces -Util.conf_default = function(cfg, api, v, type, defval, desc) { - // Description - api['get_' + v + '_desc'] = desc; - // Default getter - if (typeof api['get_' + v] === 'undefined') { - api['get_' + v] = function (idx) { - if ((type in {'arr':1, 'array':1}) && - (typeof idx !== 'undefined')) { - return cfg[v][idx]; - } else { - return cfg[v]; - } - }; - } +// Set configuration default for Crockford style function namespaces +Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) { + var getter, setter; - // Default setter - if (typeof api['set_' + v] === 'undefined') { - 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; - } - }; - } + // Default getter function + getter = function (idx) { + if ((type in {'arr':1, 'array':1}) && + (typeof idx !== 'undefined')) { + return cfg[v][idx]; + } else { + return cfg[v]; + } + }; - if (typeof cfg[v] === 'undefined') { - // Set to default - if (type in {'arr':1, 'array':1}) { - if (! (defval instanceof Array)) { - defval = []; + // Default setter function + setter = 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 () {}; } } - api['set_' + v](defval); - } else { - // Coerce existing setting to the right type - api['set_' + v](cfg[v]); + if (typeof idx !== 'undefined') { + cfg[v][idx] = val; + } else { + cfg[v] = val; + } + }; + + // Set the description + api[v + '_description'] = desc; + + // Set the getter function + if (typeof api['get_' + v] === 'undefined') { + api['get_' + v] = getter; } + + // Set the setter function with extra sanity checks + if (typeof api['set_' + v] === 'undefined') { + api['set_' + v] = function (val, idx) { + if (mode in {'RO':1, 'ro':1}) { + throw(v + " is read-only"); + } else if ((mode in {'WO':1, 'wo':1}) && + (typeof cfg[v] !== 'undefined')) { + throw(v + " can only be set once"); + } + setter(val, idx); + }; + } + + // Set the default value + if (typeof defaults[v] !== 'undefined') { + defval = defaults[v]; + } else if ((type in {'arr':1, 'array':1}) && + (! (defval instanceof Array))) { + defval = []; + } + // Coerce existing setting to the right type + //Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]); + setter(defval); }; +// Set group of configuration defaults +Util.conf_defaults = function(cfg, api, defaults, arr) { + var i; + for (i = 0; i < arr.length; i++) { + Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1], + arr[i][2], arr[i][3], arr[i][4]); + } +} /*