Merge branch 'resize' of https://github.com/CendioOssman/noVNC
This commit is contained in:
commit
4f4f62261a
|
@ -854,30 +854,6 @@ select:active {
|
||||||
ime-mode: disabled;
|
ime-mode: disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HTML5 Canvas */
|
|
||||||
#noVNC_screen {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
background-color: rgb(40, 40, 40);
|
|
||||||
}
|
|
||||||
:root:not(.noVNC_connected) #noVNC_screen {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not set width/height for VNC_canvas or incorrect
|
|
||||||
* scaling will occur. Canvas size depends on remote VNC
|
|
||||||
* settings and noVNC settings. */
|
|
||||||
#noVNC_canvas {
|
|
||||||
margin: auto;
|
|
||||||
/* IE miscalculates width without this :( */
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
#noVNC_canvas:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Default noVNC logo.*/
|
/*Default noVNC logo.*/
|
||||||
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
|
@ -61,10 +61,3 @@ html {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not set width/height for VNC_canvas or incorrect
|
|
||||||
* scaling will occur. Canvas size depends on remote VNC
|
|
||||||
* settings and noVNC settings. */
|
|
||||||
#noVNC_canvas {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
150
app/ui.js
150
app/ui.js
|
@ -27,7 +27,6 @@ var UI = {
|
||||||
connected: false,
|
connected: false,
|
||||||
desktopName: "",
|
desktopName: "",
|
||||||
|
|
||||||
resizeTimeout: null,
|
|
||||||
statusTimeout: null,
|
statusTimeout: null,
|
||||||
hideKeyboardTimeout: null,
|
hideKeyboardTimeout: null,
|
||||||
idleControlbarTimeout: null,
|
idleControlbarTimeout: null,
|
||||||
|
@ -87,7 +86,6 @@ var UI = {
|
||||||
UI.initFullscreen();
|
UI.initFullscreen();
|
||||||
|
|
||||||
// Setup event handlers
|
// Setup event handlers
|
||||||
UI.addResizeHandlers();
|
|
||||||
UI.addControlbarHandlers();
|
UI.addControlbarHandlers();
|
||||||
UI.addTouchSpecificHandlers();
|
UI.addTouchSpecificHandlers();
|
||||||
UI.addExtraKeysHandlers();
|
UI.addExtraKeysHandlers();
|
||||||
|
@ -103,8 +101,6 @@ var UI = {
|
||||||
|
|
||||||
UI.openControlbar();
|
UI.openControlbar();
|
||||||
|
|
||||||
UI.updateViewClip();
|
|
||||||
|
|
||||||
UI.updateVisualState('init');
|
UI.updateVisualState('init');
|
||||||
|
|
||||||
document.documentElement.classList.remove("noVNC_loading");
|
document.documentElement.classList.remove("noVNC_loading");
|
||||||
|
@ -205,11 +201,6 @@ var UI = {
|
||||||
* EVENT HANDLERS
|
* EVENT HANDLERS
|
||||||
* ------v------*/
|
* ------v------*/
|
||||||
|
|
||||||
addResizeHandlers: function() {
|
|
||||||
window.addEventListener('resize', UI.applyResizeMode);
|
|
||||||
window.addEventListener('resize', UI.updateViewClip);
|
|
||||||
},
|
|
||||||
|
|
||||||
addControlbarHandlers: function() {
|
addControlbarHandlers: function() {
|
||||||
document.getElementById("noVNC_control_bar")
|
document.getElementById("noVNC_control_bar")
|
||||||
.addEventListener('mousemove', UI.activateControlbar);
|
.addEventListener('mousemove', UI.activateControlbar);
|
||||||
|
@ -432,7 +423,6 @@ var UI = {
|
||||||
UI.disableSetting('port');
|
UI.disableSetting('port');
|
||||||
UI.disableSetting('path');
|
UI.disableSetting('path');
|
||||||
UI.disableSetting('repeaterID');
|
UI.disableSetting('repeaterID');
|
||||||
UI.updateViewClip();
|
|
||||||
UI.setMouseButton(1);
|
UI.setMouseButton(1);
|
||||||
|
|
||||||
// Hide the controlbar after 2 seconds
|
// Hide the controlbar after 2 seconds
|
||||||
|
@ -1037,7 +1027,7 @@ var UI = {
|
||||||
}
|
}
|
||||||
url += '/' + path;
|
url += '/' + path;
|
||||||
|
|
||||||
UI.rfb = new RFB(document.getElementById('noVNC_canvas'), url,
|
UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
|
||||||
{ shared: UI.getSetting('shared'),
|
{ shared: UI.getSetting('shared'),
|
||||||
repeaterID: UI.getSetting('repeaterID'),
|
repeaterID: UI.getSetting('repeaterID'),
|
||||||
credentials: { password: password } });
|
credentials: { password: password } });
|
||||||
|
@ -1045,11 +1035,13 @@ var UI = {
|
||||||
UI.rfb.addEventListener("disconnect", UI.disconnectFinished);
|
UI.rfb.addEventListener("disconnect", UI.disconnectFinished);
|
||||||
UI.rfb.addEventListener("credentialsrequired", UI.credentials);
|
UI.rfb.addEventListener("credentialsrequired", UI.credentials);
|
||||||
UI.rfb.addEventListener("securityfailure", UI.securityFailed);
|
UI.rfb.addEventListener("securityfailure", UI.securityFailed);
|
||||||
UI.rfb.addEventListener("capabilities", function () { UI.updatePowerButton(); UI.initialResize(); });
|
UI.rfb.addEventListener("capabilities", function () { UI.updatePowerButton(); });
|
||||||
UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
|
UI.rfb.addEventListener("clipboard", UI.clipboardReceive);
|
||||||
UI.rfb.addEventListener("bell", UI.bell);
|
UI.rfb.addEventListener("bell", UI.bell);
|
||||||
UI.rfb.addEventListener("fbresize", UI.updateSessionSize);
|
|
||||||
UI.rfb.addEventListener("desktopname", UI.updateDesktopName);
|
UI.rfb.addEventListener("desktopname", UI.updateDesktopName);
|
||||||
|
UI.rfb.clipViewport = UI.getSetting('view_clip');
|
||||||
|
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
||||||
|
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
||||||
},
|
},
|
||||||
|
|
||||||
disconnect: function() {
|
disconnect: function() {
|
||||||
|
@ -1092,7 +1084,6 @@ var UI = {
|
||||||
connectFinished: function (e) {
|
connectFinished: function (e) {
|
||||||
UI.connected = true;
|
UI.connected = true;
|
||||||
UI.inhibit_reconnect = false;
|
UI.inhibit_reconnect = false;
|
||||||
UI.doneInitialResize = false;
|
|
||||||
|
|
||||||
let msg;
|
let msg;
|
||||||
if (UI.getSetting('encrypt')) {
|
if (UI.getSetting('encrypt')) {
|
||||||
|
@ -1104,7 +1095,7 @@ var UI = {
|
||||||
UI.updateVisualState('connected');
|
UI.updateVisualState('connected');
|
||||||
|
|
||||||
// Do this last because it can only be used on rendered elements
|
// Do this last because it can only be used on rendered elements
|
||||||
document.getElementById('noVNC_canvas').focus();
|
UI.rfb.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
disconnectFinished: function (e) {
|
disconnectFinished: function (e) {
|
||||||
|
@ -1238,74 +1229,8 @@ var UI = {
|
||||||
applyResizeMode: function() {
|
applyResizeMode: function() {
|
||||||
if (!UI.rfb) return;
|
if (!UI.rfb) return;
|
||||||
|
|
||||||
var screen = UI.screenSize();
|
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
||||||
|
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
||||||
if (screen && UI.connected) {
|
|
||||||
|
|
||||||
var resizeMode = UI.getSetting('resize');
|
|
||||||
UI.rfb.viewportScale = 1.0;
|
|
||||||
|
|
||||||
// Make sure the viewport is adjusted first
|
|
||||||
UI.updateViewClip();
|
|
||||||
|
|
||||||
if (resizeMode === 'remote') {
|
|
||||||
|
|
||||||
// Request changing the resolution of the remote display to
|
|
||||||
// the size of the local browser viewport.
|
|
||||||
|
|
||||||
// In order to not send multiple requests before the browser-resize
|
|
||||||
// is finished we wait 0.5 seconds before sending the request.
|
|
||||||
clearTimeout(UI.resizeTimeout);
|
|
||||||
UI.resizeTimeout = setTimeout(function(){
|
|
||||||
// Request a remote size covering the viewport
|
|
||||||
if (UI.rfb.requestDesktopSize(screen.w, screen.h)) {
|
|
||||||
Log.Debug('Requested new desktop size: ' +
|
|
||||||
screen.w + 'x' + screen.h);
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
UI.updateScaling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Re-calculate local scaling
|
|
||||||
updateScaling: function() {
|
|
||||||
if (!UI.rfb) return;
|
|
||||||
|
|
||||||
var resizeMode = UI.getSetting('resize');
|
|
||||||
if (resizeMode !== 'scale') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var screen = UI.screenSize();
|
|
||||||
|
|
||||||
if (!screen || !UI.connected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UI.rfb.autoscale(screen.w, screen.h);
|
|
||||||
UI.fixScrollbars();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Gets the the size of the available viewport in the browser window
|
|
||||||
screenSize: function() {
|
|
||||||
var screen = document.getElementById('noVNC_screen');
|
|
||||||
return {w: screen.offsetWidth, h: screen.offsetHeight};
|
|
||||||
},
|
|
||||||
|
|
||||||
// Normally we only apply the current resize mode after a window resize
|
|
||||||
// event. This means that when a new connection is opened, there is no
|
|
||||||
// resize mode active.
|
|
||||||
// We have to wait until we know the capabilities of the server as
|
|
||||||
// some calls later in the chain is dependant on knowing the
|
|
||||||
// server-capabilities.
|
|
||||||
initialResize: function() {
|
|
||||||
if (UI.doneInitialResize) return;
|
|
||||||
|
|
||||||
UI.applyResizeMode();
|
|
||||||
UI.doneInitialResize = true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/* ------^-------
|
/* ------^-------
|
||||||
|
@ -1314,12 +1239,6 @@ var UI = {
|
||||||
* VIEW CLIPPING
|
* VIEW CLIPPING
|
||||||
* ------v------*/
|
* ------v------*/
|
||||||
|
|
||||||
// Set and configure viewport clipping
|
|
||||||
setViewClip: function(clip) {
|
|
||||||
UI.updateSetting('view_clip', clip);
|
|
||||||
UI.updateViewClip();
|
|
||||||
},
|
|
||||||
|
|
||||||
// Update parameters that depend on the viewport clip setting
|
// Update parameters that depend on the viewport clip setting
|
||||||
updateViewClip: function() {
|
updateViewClip: function() {
|
||||||
if (!UI.rfb) return;
|
if (!UI.rfb) return;
|
||||||
|
@ -1327,11 +1246,7 @@ var UI = {
|
||||||
var cur_clip = UI.rfb.clipViewport;
|
var cur_clip = UI.rfb.clipViewport;
|
||||||
var new_clip = UI.getSetting('view_clip');
|
var new_clip = UI.getSetting('view_clip');
|
||||||
|
|
||||||
var resizeSetting = UI.getSetting('resize');
|
if (isTouchDevice) {
|
||||||
if (resizeSetting === 'scale') {
|
|
||||||
// Disable viewport clipping if we are scaling
|
|
||||||
new_clip = false;
|
|
||||||
} else if (isTouchDevice) {
|
|
||||||
// Touch devices usually have shit scrollbars
|
// Touch devices usually have shit scrollbars
|
||||||
new_clip = true;
|
new_clip = true;
|
||||||
}
|
}
|
||||||
|
@ -1340,15 +1255,6 @@ var UI = {
|
||||||
UI.rfb.clipViewport = new_clip;
|
UI.rfb.clipViewport = new_clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
var size = UI.screenSize();
|
|
||||||
|
|
||||||
if (new_clip && size) {
|
|
||||||
// When clipping is enabled, the screen is limited to
|
|
||||||
// the size of the browser window.
|
|
||||||
UI.rfb.viewportChangeSize(size.w, size.h);
|
|
||||||
UI.fixScrollbars();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Changing the viewport may change the state of
|
// Changing the viewport may change the state of
|
||||||
// the dragging button
|
// the dragging button
|
||||||
UI.updateViewDrag();
|
UI.updateViewDrag();
|
||||||
|
@ -1389,23 +1295,13 @@ var UI = {
|
||||||
},
|
},
|
||||||
|
|
||||||
updateViewDrag: function() {
|
updateViewDrag: function() {
|
||||||
var clipping = false;
|
|
||||||
|
|
||||||
if (!UI.connected) return;
|
if (!UI.connected) return;
|
||||||
|
|
||||||
// Check if viewport drag is possible. It is only possible
|
|
||||||
// if the remote display is clipping the client display.
|
|
||||||
if (UI.rfb.clipViewport && UI.rfb.isClipped) {
|
|
||||||
clipping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewDragButton = document.getElementById('noVNC_view_drag_button');
|
var viewDragButton = document.getElementById('noVNC_view_drag_button');
|
||||||
|
|
||||||
if (!clipping &&
|
if (!UI.rfb.clipViewport && UI.rfb.dragViewport) {
|
||||||
UI.rfb.dragViewport) {
|
// We are no longer clipping the viewport. Make sure
|
||||||
// The size of the remote display is the same or smaller
|
// viewport drag isn't active when it can't be used.
|
||||||
// than the client display. Make sure viewport drag isn't
|
|
||||||
// active when it can't be used.
|
|
||||||
UI.rfb.dragViewport = false;
|
UI.rfb.dragViewport = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1420,7 +1316,7 @@ var UI = {
|
||||||
if (isTouchDevice) {
|
if (isTouchDevice) {
|
||||||
viewDragButton.classList.remove("noVNC_hidden");
|
viewDragButton.classList.remove("noVNC_hidden");
|
||||||
|
|
||||||
if (clipping) {
|
if (UI.rfb.clipViewport) {
|
||||||
viewDragButton.disabled = false;
|
viewDragButton.disabled = false;
|
||||||
} else {
|
} else {
|
||||||
viewDragButton.disabled = true;
|
viewDragButton.disabled = true;
|
||||||
|
@ -1428,7 +1324,7 @@ var UI = {
|
||||||
} else {
|
} else {
|
||||||
viewDragButton.disabled = false;
|
viewDragButton.disabled = false;
|
||||||
|
|
||||||
if (clipping) {
|
if (UI.rfb.clipViewport) {
|
||||||
viewDragButton.classList.remove("noVNC_hidden");
|
viewDragButton.classList.remove("noVNC_hidden");
|
||||||
} else {
|
} else {
|
||||||
viewDragButton.classList.add("noVNC_hidden");
|
viewDragButton.classList.add("noVNC_hidden");
|
||||||
|
@ -1703,24 +1599,6 @@ var UI = {
|
||||||
WebUtil.init_logging(UI.getSetting('logging'));
|
WebUtil.init_logging(UI.getSetting('logging'));
|
||||||
},
|
},
|
||||||
|
|
||||||
updateSessionSize: function(e) {
|
|
||||||
UI.updateViewClip();
|
|
||||||
UI.updateScaling();
|
|
||||||
UI.fixScrollbars();
|
|
||||||
},
|
|
||||||
|
|
||||||
fixScrollbars: function() {
|
|
||||||
// This is a hack because Chrome screws up the calculation
|
|
||||||
// for when scrollbars are needed. So to fix it we temporarily
|
|
||||||
// toggle them off and on.
|
|
||||||
var screen = document.getElementById('noVNC_screen');
|
|
||||||
screen.style.overflow = 'hidden';
|
|
||||||
// Force Chrome to recalculate the layout by asking for
|
|
||||||
// an element's dimensions
|
|
||||||
screen.getBoundingClientRect();
|
|
||||||
screen.style.overflow = "";
|
|
||||||
},
|
|
||||||
|
|
||||||
updateDesktopName: function(e) {
|
updateDesktopName: function(e) {
|
||||||
UI.desktopName = e.detail.name;
|
UI.desktopName = e.detail.name;
|
||||||
// Display the desktop name in the document title
|
// Display the desktop name in the document title
|
||||||
|
|
|
@ -106,11 +106,6 @@ Display.prototype = {
|
||||||
return this._fb_height;
|
return this._fb_height;
|
||||||
},
|
},
|
||||||
|
|
||||||
get isClipped() {
|
|
||||||
var vp = this._viewportLoc;
|
|
||||||
return this._fb_width > vp.w || this._fb_height > vp.h;
|
|
||||||
},
|
|
||||||
|
|
||||||
logo: null,
|
logo: null,
|
||||||
|
|
||||||
// ===== EVENT HANDLERS =====
|
// ===== EVENT HANDLERS =====
|
||||||
|
|
258
core/rfb.js
258
core/rfb.js
|
@ -66,7 +66,7 @@ export default function RFB(target, url, options) {
|
||||||
|
|
||||||
this._fb_name = "";
|
this._fb_name = "";
|
||||||
|
|
||||||
this._capabilities = { power: false, resize: false };
|
this._capabilities = { power: false };
|
||||||
|
|
||||||
this._supportsFence = false;
|
this._supportsFence = false;
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ export default function RFB(target, url, options) {
|
||||||
|
|
||||||
// Timers
|
// Timers
|
||||||
this._disconnTimer = null; // disconnection timer
|
this._disconnTimer = null; // disconnection timer
|
||||||
|
this._resizeTimeout = null; // resize rate limiting
|
||||||
|
|
||||||
// Decoder states and stats
|
// Decoder states and stats
|
||||||
this._encHandlers = {};
|
this._encHandlers = {};
|
||||||
|
@ -140,15 +141,29 @@ export default function RFB(target, url, options) {
|
||||||
// Bound event handlers
|
// Bound event handlers
|
||||||
this._eventHandlers = {
|
this._eventHandlers = {
|
||||||
focusCanvas: this._focusCanvas.bind(this),
|
focusCanvas: this._focusCanvas.bind(this),
|
||||||
|
windowResize: this._windowResize.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
// main setup
|
// main setup
|
||||||
Log.Debug(">> RFB.constructor");
|
Log.Debug(">> RFB.constructor");
|
||||||
|
|
||||||
// Target canvas must be able to have focus
|
// Create DOM elements
|
||||||
if (!this._target.hasAttribute('tabindex')) {
|
this._screen = document.createElement('div');
|
||||||
this._target.tabIndex = -1;
|
this._screen.style.display = 'flex';
|
||||||
}
|
this._screen.style.width = '100%';
|
||||||
|
this._screen.style.height = '100%';
|
||||||
|
this._screen.style.overflow = 'auto';
|
||||||
|
this._screen.style.backgroundColor = 'rgb(40, 40, 40)';
|
||||||
|
this._canvas = document.createElement('canvas');
|
||||||
|
this._canvas.style.margin = 'auto';
|
||||||
|
// Some browsers add an outline on focus
|
||||||
|
this._canvas.style.outline = 'none';
|
||||||
|
// IE miscalculates width without this :(
|
||||||
|
this._canvas.style.flexShrink = '0';
|
||||||
|
this._canvas.width = 0;
|
||||||
|
this._canvas.height = 0;
|
||||||
|
this._canvas.tabIndex = -1;
|
||||||
|
this._screen.appendChild(this._canvas);
|
||||||
|
|
||||||
// populate encHandlers with bound versions
|
// populate encHandlers with bound versions
|
||||||
this._encHandlers[encodings.encodingRaw] = RFB.encodingHandlers.RAW.bind(this);
|
this._encHandlers[encodings.encodingRaw] = RFB.encodingHandlers.RAW.bind(this);
|
||||||
|
@ -166,7 +181,7 @@ export default function RFB(target, url, options) {
|
||||||
// NB: nothing that needs explicit teardown should be done
|
// NB: nothing that needs explicit teardown should be done
|
||||||
// before this point, since this can throw an exception
|
// before this point, since this can throw an exception
|
||||||
try {
|
try {
|
||||||
this._display = new Display(this._target);
|
this._display = new Display(this._canvas);
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
Log.Error("Display exception: " + exc);
|
Log.Error("Display exception: " + exc);
|
||||||
throw exc;
|
throw exc;
|
||||||
|
@ -174,10 +189,10 @@ export default function RFB(target, url, options) {
|
||||||
this._display.onflush = this._onFlush.bind(this);
|
this._display.onflush = this._onFlush.bind(this);
|
||||||
this._display.clear();
|
this._display.clear();
|
||||||
|
|
||||||
this._keyboard = new Keyboard(this._target);
|
this._keyboard = new Keyboard(this._canvas);
|
||||||
this._keyboard.onkeyevent = this._handleKeyEvent.bind(this);
|
this._keyboard.onkeyevent = this._handleKeyEvent.bind(this);
|
||||||
|
|
||||||
this._mouse = new Mouse(this._target);
|
this._mouse = new Mouse(this._canvas);
|
||||||
this._mouse.onmousebutton = this._handleMouseButton.bind(this);
|
this._mouse.onmousebutton = this._handleMouseButton.bind(this);
|
||||||
this._mouse.onmousemove = this._handleMouseMove.bind(this);
|
this._mouse.onmousemove = this._handleMouseMove.bind(this);
|
||||||
|
|
||||||
|
@ -266,13 +281,36 @@ RFB.prototype = {
|
||||||
get touchButton() { return this._mouse.touchButton; },
|
get touchButton() { return this._mouse.touchButton; },
|
||||||
set touchButton(button) { this._mouse.touchButton = button; },
|
set touchButton(button) { this._mouse.touchButton = button; },
|
||||||
|
|
||||||
get viewportScale() { return this._display.scale; },
|
_clipViewport: false,
|
||||||
set viewportScale(scale) { this._display.scale = scale; },
|
get clipViewport() { return this._clipViewport; },
|
||||||
|
set clipViewport(viewport) {
|
||||||
|
this._clipViewport = viewport;
|
||||||
|
this._updateClip();
|
||||||
|
},
|
||||||
|
|
||||||
get clipViewport() { return this._display.clipViewport; },
|
_scaleViewport: false,
|
||||||
set clipViewport(viewport) { this._display.clipViewport = viewport; },
|
get scaleViewport() { return this._scaleViewport; },
|
||||||
|
set scaleViewport(scale) {
|
||||||
|
this._scaleViewport = scale;
|
||||||
|
// Scaling trumps clipping, so we may need to adjust
|
||||||
|
// clipping when enabling or disabling scaling
|
||||||
|
if (scale && this._clipViewport) {
|
||||||
|
this._updateClip();
|
||||||
|
}
|
||||||
|
this._updateScale();
|
||||||
|
if (!scale && this._clipViewport) {
|
||||||
|
this._updateClip();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
get isClipped() { return this._display.isClipped; },
|
_resizeSession: false,
|
||||||
|
get resizeSession() { return this._resizeSession; },
|
||||||
|
set resizeSession(resize) {
|
||||||
|
this._resizeSession = resize;
|
||||||
|
if (resize) {
|
||||||
|
this._requestRemoteResize();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// ===== PUBLIC METHODS =====
|
// ===== PUBLIC METHODS =====
|
||||||
|
|
||||||
|
@ -341,38 +379,19 @@ RFB.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
focus: function () {
|
||||||
|
this._canvas.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
blur: function () {
|
||||||
|
this._canvas.blur();
|
||||||
|
},
|
||||||
|
|
||||||
clipboardPasteFrom: function (text) {
|
clipboardPasteFrom: function (text) {
|
||||||
if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
|
if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
|
||||||
RFB.messages.clientCutText(this._sock, text);
|
RFB.messages.clientCutText(this._sock, text);
|
||||||
},
|
},
|
||||||
|
|
||||||
autoscale: function (width, height) {
|
|
||||||
if (this._rfb_connection_state !== 'connected') { return; }
|
|
||||||
this._display.autoscale(width, height);
|
|
||||||
},
|
|
||||||
|
|
||||||
viewportChangeSize: function(width, height) {
|
|
||||||
if (this._rfb_connection_state !== 'connected') { return; }
|
|
||||||
this._display.viewportChangeSize(width, height);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Requests a change of remote desktop size. This message is an extension
|
|
||||||
// and may only be sent if we have received an ExtendedDesktopSize message
|
|
||||||
requestDesktopSize: function (width, height) {
|
|
||||||
if (this._rfb_connection_state !== 'connected' ||
|
|
||||||
this._viewOnly) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._supportsSetDesktopSize) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RFB.messages.setDesktopSize(this._sock, width, height,
|
|
||||||
this._screen_id, this._screen_flags);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
// ===== PRIVATE METHODS =====
|
// ===== PRIVATE METHODS =====
|
||||||
|
|
||||||
_connect: function () {
|
_connect: function () {
|
||||||
|
@ -391,20 +410,31 @@ RFB.prototype = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make our elements part of the page
|
||||||
|
this._target.appendChild(this._screen);
|
||||||
|
|
||||||
|
// Monitor size changes of the screen
|
||||||
|
// FIXME: Use ResizeObserver, or hidden overflow
|
||||||
|
window.addEventListener('resize', this._eventHandlers.windowResize);
|
||||||
|
|
||||||
// Always grab focus on some kind of click event
|
// Always grab focus on some kind of click event
|
||||||
this._target.addEventListener("mousedown", this._eventHandlers.focusCanvas);
|
this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||||
this._target.addEventListener("touchstart", this._eventHandlers.focusCanvas);
|
this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||||
|
|
||||||
Log.Debug("<< RFB.connect");
|
Log.Debug("<< RFB.connect");
|
||||||
},
|
},
|
||||||
|
|
||||||
_disconnect: function () {
|
_disconnect: function () {
|
||||||
Log.Debug(">> RFB.disconnect");
|
Log.Debug(">> RFB.disconnect");
|
||||||
this._target.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||||
this._target.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||||
this._cleanup();
|
window.removeEventListener('resize', this._eventHandlers.windowResize);
|
||||||
|
this._keyboard.ungrab();
|
||||||
|
this._mouse.ungrab();
|
||||||
this._sock.close();
|
this._sock.close();
|
||||||
this._print_stats();
|
this._print_stats();
|
||||||
|
this._target.removeChild(this._screen);
|
||||||
|
clearTimeout(this._resizeTimeout);
|
||||||
Log.Debug("<< RFB.disconnect");
|
Log.Debug("<< RFB.disconnect");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -426,17 +456,6 @@ RFB.prototype = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_cleanup: function () {
|
|
||||||
if (!this._viewOnly) { this._keyboard.ungrab(); }
|
|
||||||
if (!this._viewOnly) { this._mouse.ungrab(); }
|
|
||||||
this._display.defaultCursor();
|
|
||||||
if (Log.get_logging() !== 'debug') {
|
|
||||||
// Show noVNC logo when disconnected, unless in
|
|
||||||
// debug mode
|
|
||||||
this._display.clear();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_focusCanvas: function(event) {
|
_focusCanvas: function(event) {
|
||||||
// Respect earlier handlers' request to not do side-effects
|
// Respect earlier handlers' request to not do side-effects
|
||||||
if (event.defaultPrevented) {
|
if (event.defaultPrevented) {
|
||||||
|
@ -447,7 +466,97 @@ RFB.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._target.focus();
|
this.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
_windowResize: function (event) {
|
||||||
|
// If the window resized then our screen element might have
|
||||||
|
// as well. Update the viewport dimensions.
|
||||||
|
window.requestAnimationFrame(function () {
|
||||||
|
this._updateClip();
|
||||||
|
this._updateScale();
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
if (this._resizeSession) {
|
||||||
|
// Request changing the resolution of the remote display to
|
||||||
|
// the size of the local browser viewport.
|
||||||
|
|
||||||
|
// In order to not send multiple requests before the browser-resize
|
||||||
|
// is finished we wait 0.5 seconds before sending the request.
|
||||||
|
clearTimeout(this._resizeTimeout);
|
||||||
|
this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this), 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Update state of clipping in Display object, and make sure the
|
||||||
|
// configured viewport matches the current screen size
|
||||||
|
_updateClip: function () {
|
||||||
|
var cur_clip = this._display.clipViewport;
|
||||||
|
var new_clip = this._clipViewport;
|
||||||
|
|
||||||
|
if (this._scaleViewport) {
|
||||||
|
// Disable viewport clipping if we are scaling
|
||||||
|
new_clip = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_clip !== new_clip) {
|
||||||
|
this._display.clipViewport = new_clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_clip) {
|
||||||
|
// When clipping is enabled, the screen is limited to
|
||||||
|
// the size of the container.
|
||||||
|
let size = this._screenSize();
|
||||||
|
this._display.viewportChangeSize(size.w, size.h);
|
||||||
|
this._fixScrollbars();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateScale: function () {
|
||||||
|
if (!this._scaleViewport) {
|
||||||
|
this._display.scale = 1.0;
|
||||||
|
} else {
|
||||||
|
let size = this._screenSize();
|
||||||
|
this._display.autoscale(size.w, size.h);
|
||||||
|
}
|
||||||
|
this._fixScrollbars();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Requests a change of remote desktop size. This message is an extension
|
||||||
|
// and may only be sent if we have received an ExtendedDesktopSize message
|
||||||
|
_requestRemoteResize: function () {
|
||||||
|
clearTimeout(this._resizeTimeout);
|
||||||
|
this._resizeTimeout = null;
|
||||||
|
|
||||||
|
if (!this._resizeSession || this._viewOnly ||
|
||||||
|
!this._supportsSetDesktopSize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = this._screenSize();
|
||||||
|
RFB.messages.setDesktopSize(this._sock, size.w, size.h,
|
||||||
|
this._screen_id, this._screen_flags);
|
||||||
|
|
||||||
|
Log.Debug('Requested new desktop size: ' +
|
||||||
|
size.w + 'x' + size.h);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Gets the the size of the available screen
|
||||||
|
_screenSize: function () {
|
||||||
|
return { w: this._screen.offsetWidth,
|
||||||
|
h: this._screen.offsetHeight };
|
||||||
|
},
|
||||||
|
|
||||||
|
_fixScrollbars: function () {
|
||||||
|
// This is a hack because Chrome screws up the calculation
|
||||||
|
// for when scrollbars are needed. So to fix it we temporarily
|
||||||
|
// toggle them off and on.
|
||||||
|
var orig = this._screen.style.overflow;
|
||||||
|
this._screen.style.overflow = 'hidden';
|
||||||
|
// Force Chrome to recalculate the layout by asking for
|
||||||
|
// an element's dimensions
|
||||||
|
this._screen.getBoundingClientRect();
|
||||||
|
this._screen.style.overflow = orig;
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -634,18 +743,26 @@ RFB.prototype = {
|
||||||
if (down && !this._viewportDragging) {
|
if (down && !this._viewportDragging) {
|
||||||
this._viewportDragging = true;
|
this._viewportDragging = true;
|
||||||
this._viewportDragPos = {'x': x, 'y': y};
|
this._viewportDragPos = {'x': x, 'y': y};
|
||||||
|
this._viewportHasMoved = false;
|
||||||
|
|
||||||
// Skip sending mouse events
|
// Skip sending mouse events
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this._viewportDragging = false;
|
this._viewportDragging = false;
|
||||||
|
|
||||||
// If the viewport didn't actually move, then treat as a mouse click event
|
// If we actually performed a drag then we are done
|
||||||
// Send the button down event here, as the button up event is sent at the end of this function
|
// here and should not send any mouse events
|
||||||
if (!this._viewportHasMoved && !this._viewOnly) {
|
if (this._viewportHasMoved) {
|
||||||
RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), bmask);
|
return;
|
||||||
}
|
}
|
||||||
this._viewportHasMoved = false;
|
|
||||||
|
// Otherwise we treat this as a mouse click event.
|
||||||
|
// Send the button down event here, as the button up
|
||||||
|
// event is sent at the end of this function.
|
||||||
|
RFB.messages.pointerEvent(this._sock,
|
||||||
|
this._display.absX(x),
|
||||||
|
this._display.absY(y),
|
||||||
|
bmask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1459,10 +1576,9 @@ RFB.prototype = {
|
||||||
|
|
||||||
this._display.resize(this._fb_width, this._fb_height);
|
this._display.resize(this._fb_width, this._fb_height);
|
||||||
|
|
||||||
var event = new CustomEvent("fbresize",
|
// Adjust the visible viewport based on the new dimensions
|
||||||
{ detail: { width: this._fb_width,
|
this._updateClip();
|
||||||
height: this._fb_height } });
|
this._updateScale();
|
||||||
this.dispatchEvent(event);
|
|
||||||
|
|
||||||
this._timing.fbu_rt_start = (new Date()).getTime();
|
this._timing.fbu_rt_start = (new Date()).getTime();
|
||||||
this._updateContinuousUpdates();
|
this._updateContinuousUpdates();
|
||||||
|
@ -2300,8 +2416,16 @@ RFB.encodingHandlers = {
|
||||||
this._FBU.bytes = 1;
|
this._FBU.bytes = 1;
|
||||||
if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) { return false; }
|
if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) { return false; }
|
||||||
|
|
||||||
|
var firstUpdate = !this._supportsSetDesktopSize;
|
||||||
this._supportsSetDesktopSize = true;
|
this._supportsSetDesktopSize = true;
|
||||||
this._setCapability("resize", true);
|
|
||||||
|
// Normally we only apply the current resize mode after a
|
||||||
|
// window resize event. However there is no such trigger on the
|
||||||
|
// initial connect. And we don't know if the server supports
|
||||||
|
// resizing until we've gotten here.
|
||||||
|
if (firstUpdate) {
|
||||||
|
this._requestRemoteResize();
|
||||||
|
}
|
||||||
|
|
||||||
var number_of_screens = this._sock.rQpeek8();
|
var number_of_screens = this._sock.rQpeek8();
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,6 @@ None
|
||||||
| clipViewport | bool | RW | false | Use viewport clipping
|
| clipViewport | bool | RW | false | Use viewport clipping
|
||||||
| width | int | RO | | Display area width
|
| width | int | RO | | Display area width
|
||||||
| height | int | RO | | Display area height
|
| height | int | RO | | Display area height
|
||||||
| isClipped | bool | RO | | Is the remote display is larger than the client display
|
|
||||||
|
|
||||||
### 2.3.2 Methods
|
### 2.3.2 Methods
|
||||||
|
|
||||||
|
|
140
docs/API.md
140
docs/API.md
|
@ -23,8 +23,8 @@ protocol stream.
|
||||||
|
|
||||||
`focusOnClick`
|
`focusOnClick`
|
||||||
- Is a `boolean` indicating if keyboard focus should automatically be
|
- Is a `boolean` indicating if keyboard focus should automatically be
|
||||||
moved to the canvas when a `mousedown` or `touchstart` event is
|
moved to the remote session when a `mousedown` or `touchstart`
|
||||||
received.
|
event is received.
|
||||||
|
|
||||||
`touchButton`
|
`touchButton`
|
||||||
- Is a `long` controlling the button mask that should be simulated
|
- Is a `long` controlling the button mask that should be simulated
|
||||||
|
@ -32,24 +32,26 @@ protocol stream.
|
||||||
[`MouseEvent.button`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button).
|
[`MouseEvent.button`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button).
|
||||||
Is set to `1` by default.
|
Is set to `1` by default.
|
||||||
|
|
||||||
`viewportScale`
|
|
||||||
- Is a `double` indicating how the framebuffer contents should be
|
|
||||||
scaled before being rendered on to the canvas. See also
|
|
||||||
[`RFB.autoscale()`](#rfbautoscale). Is set to `1.0` by default.
|
|
||||||
|
|
||||||
`clipViewport`
|
`clipViewport`
|
||||||
- Is a `boolean` indicating if the canvas should be clipped to its
|
- Is a `boolean` indicating if the remote session should be clipped
|
||||||
container. When disabled the container must be able to handle the
|
to its container. When disabled scrollbars will be shown to handle
|
||||||
resulting overflow. Disabled by default.
|
the resulting overflow. Disabled by default.
|
||||||
|
|
||||||
`dragViewport`
|
`dragViewport`
|
||||||
- Is a `boolean` indicating if mouse events should control the
|
- Is a `boolean` indicating if mouse events should control the
|
||||||
relative position of a clipped canvas. Only relevant if
|
relative position of a clipped remote session. Only relevant if
|
||||||
`clipViewport` is enabled. Disabled by default.
|
`clipViewport` is enabled. Disabled by default.
|
||||||
|
|
||||||
`isClipped` *Read only*
|
`scaleViewport`
|
||||||
- Is a `boolean` indicating if the framebuffer is larger than the
|
- Is a `boolean` indicating if the remote session should be scaled
|
||||||
current canvas, i.e. it is being clipped.
|
locally so it fits its container. When disabled it will be centered
|
||||||
|
if the remote session is smaller than its container, or handled
|
||||||
|
according to `clipViewport` if it is larger. Disabled by default.
|
||||||
|
|
||||||
|
`resizeSession`
|
||||||
|
- Is a `boolean` indicating if a request to resize the remote session
|
||||||
|
should be sent whenever the container changes dimensions. Disabled
|
||||||
|
by default.
|
||||||
|
|
||||||
`capabilities` *Read only*
|
`capabilities` *Read only*
|
||||||
- Is an `Object` indicating which optional extensions are available
|
- Is an `Object` indicating which optional extensions are available
|
||||||
|
@ -59,7 +61,6 @@ protocol stream.
|
||||||
| name | type | description
|
| name | type | description
|
||||||
| -------- | --------- | -----------
|
| -------- | --------- | -----------
|
||||||
| `power` | `boolean` | Machine power control is available
|
| `power` | `boolean` | Machine power control is available
|
||||||
| `resize` | `boolean` | The framebuffer can be resized
|
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
@ -86,9 +87,6 @@ protocol stream.
|
||||||
- The `bell` event is fired when a audible bell request is received
|
- The `bell` event is fired when a audible bell request is received
|
||||||
from the server.
|
from the server.
|
||||||
|
|
||||||
[`fbresize`](#fbresize)
|
|
||||||
- The `fbresize` event is fired when the framebuffer size is changed.
|
|
||||||
|
|
||||||
[`desktopname`](#desktopname)
|
[`desktopname`](#desktopname)
|
||||||
- The `desktopname` event is fired when the remote desktop name
|
- The `desktopname` event is fired when the remote desktop name
|
||||||
changes.
|
changes.
|
||||||
|
@ -112,6 +110,12 @@ protocol stream.
|
||||||
[`RFB.sendCtrlAltDel()`](#rfbsendctrlaltdel)
|
[`RFB.sendCtrlAltDel()`](#rfbsendctrlaltdel)
|
||||||
- Send Ctrl-Alt-Del key sequence.
|
- Send Ctrl-Alt-Del key sequence.
|
||||||
|
|
||||||
|
[`RFB.focus()`](#rfbfocus)
|
||||||
|
- Move keyboard focus to the remote session.
|
||||||
|
|
||||||
|
[`RFB.blur()`](#rfbblur)
|
||||||
|
- Remove keyboard focus from the remote session.
|
||||||
|
|
||||||
[`RFB.machineShutdown()`](#rfbmachineshutdown)
|
[`RFB.machineShutdown()`](#rfbmachineshutdown)
|
||||||
- Request a shutdown of the remote machine.
|
- Request a shutdown of the remote machine.
|
||||||
|
|
||||||
|
@ -124,16 +128,6 @@ protocol stream.
|
||||||
[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom)
|
[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom)
|
||||||
- Send clipboard contents to server.
|
- Send clipboard contents to server.
|
||||||
|
|
||||||
[`RFB.autoscale()`](#rfbautoscale)
|
|
||||||
- Set `RFB.viewportScale` so that the framebuffer fits a specified
|
|
||||||
container.
|
|
||||||
|
|
||||||
[`RFB.requestDesktopSize()`](#rfbrequestDesktopSize)
|
|
||||||
- Send a request to change the remote desktop size.
|
|
||||||
|
|
||||||
[`RFB.viewportChangeSize()`](#rfbviewportChangeSize)
|
|
||||||
- Change size of the viewport.
|
|
||||||
|
|
||||||
### Details
|
### Details
|
||||||
|
|
||||||
#### RFB()
|
#### RFB()
|
||||||
|
@ -148,9 +142,10 @@ connection to a specified VNC server.
|
||||||
###### Parameters
|
###### Parameters
|
||||||
|
|
||||||
**`target`**
|
**`target`**
|
||||||
- A [`HTMLCanvasElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement)
|
- A block [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)
|
||||||
that specifies where graphics should be rendered and input events
|
that specifies where the `RFB` object should attach itself. The
|
||||||
should be monitored.
|
existing contents of the `HTMLElement` will be untouched, but new
|
||||||
|
elements will be added during the lifetime of the `RFB` object.
|
||||||
|
|
||||||
**`url`**
|
**`url`**
|
||||||
- A `DOMString` specifying the VNC server to connect to. This must be
|
- A `DOMString` specifying the VNC server to connect to. This must be
|
||||||
|
@ -233,12 +228,6 @@ which is a `DOMString` with the clipboard data.
|
||||||
The `bell` event is fired when the server has requested an audible
|
The `bell` event is fired when the server has requested an audible
|
||||||
bell.
|
bell.
|
||||||
|
|
||||||
#### fbresize
|
|
||||||
|
|
||||||
The `fbresize` event is fired when the framebuffer has changed
|
|
||||||
dimensions. The `detail` property is an `Object` with the properties
|
|
||||||
`width` and `height` specifying the new dimensions.
|
|
||||||
|
|
||||||
#### desktopname
|
#### desktopname
|
||||||
|
|
||||||
The `desktopname` event is fired when the name of the remote desktop
|
The `desktopname` event is fired when the name of the remote desktop
|
||||||
|
@ -310,6 +299,25 @@ around [`RFB.sendKey()`](#rfbsendkey).
|
||||||
|
|
||||||
RFB.sendCtrlAltDel( );
|
RFB.sendCtrlAltDel( );
|
||||||
|
|
||||||
|
#### RFB.focus()
|
||||||
|
|
||||||
|
The `RFB.focus()` method sets the keyboard focus on the remote session.
|
||||||
|
Keyboard events will be sent to the remote server after this point.
|
||||||
|
|
||||||
|
##### Syntax
|
||||||
|
|
||||||
|
RFB.focus( );
|
||||||
|
|
||||||
|
#### RFB.blur()
|
||||||
|
|
||||||
|
The `RFB.blur()` method remove keyboard focus on the remote session.
|
||||||
|
Keyboard events will no longer be sent to the remote server after this
|
||||||
|
point.
|
||||||
|
|
||||||
|
##### Syntax
|
||||||
|
|
||||||
|
RFB.blur( );
|
||||||
|
|
||||||
#### RFB.machineShutdown()
|
#### RFB.machineShutdown()
|
||||||
|
|
||||||
The `RFB.machineShutdown()` method is used to request to shut down the
|
The `RFB.machineShutdown()` method is used to request to shut down the
|
||||||
|
@ -354,61 +362,3 @@ to the remote server.
|
||||||
**`text`**
|
**`text`**
|
||||||
- A `DOMString` specifying the clipboard data to send. Currently only
|
- A `DOMString` specifying the clipboard data to send. Currently only
|
||||||
characters from ISO 8859-1 are supported.
|
characters from ISO 8859-1 are supported.
|
||||||
|
|
||||||
#### RFB.autoscale()
|
|
||||||
|
|
||||||
The `RFB.autoscale()` method is used to automatically adjust
|
|
||||||
`RFB.viewportScale` to fit given dimensions.
|
|
||||||
|
|
||||||
##### Syntax
|
|
||||||
|
|
||||||
RFB.autoscale( width, height );
|
|
||||||
|
|
||||||
###### Parameters
|
|
||||||
|
|
||||||
**`width`**
|
|
||||||
- A `long` specifying the maximum width of the canvas in CSS pixels.
|
|
||||||
|
|
||||||
**`height`**
|
|
||||||
- A `long` specifying the maximum height of the canvas in CSS pixels.
|
|
||||||
|
|
||||||
#### RFB.requestDesktopSize()
|
|
||||||
|
|
||||||
The `RFB.requestDesktopSize()` method is used to request a change of
|
|
||||||
the framebuffer. The capability `resize` must be set for this method to
|
|
||||||
have any effect.
|
|
||||||
|
|
||||||
Note that this is merely a request and the server may deny it.
|
|
||||||
The [`fbresize`](#fbresize) event will be fired when the framebuffer
|
|
||||||
actually changes dimensions.
|
|
||||||
|
|
||||||
##### Syntax
|
|
||||||
|
|
||||||
RFB.requestDesktopSize( width, height );
|
|
||||||
|
|
||||||
###### Parameters
|
|
||||||
|
|
||||||
**`width`**
|
|
||||||
- A `long` specifying the new requested width in CSS pixels.
|
|
||||||
|
|
||||||
**`height`**
|
|
||||||
- A `long` specifying the new requested height in CSS pixels.
|
|
||||||
|
|
||||||
#### RFB.viewportChangeSize()
|
|
||||||
|
|
||||||
The `RFB.viewportChangeSize()` method is used to change the size of the
|
|
||||||
canvas rather than the underlying framebuffer.
|
|
||||||
|
|
||||||
This method has no effect if `RFB.clipViewport` is set to `false`.
|
|
||||||
|
|
||||||
##### Syntax
|
|
||||||
|
|
||||||
RFB.viewportChangeSize( width, height );
|
|
||||||
|
|
||||||
###### Parameters
|
|
||||||
|
|
||||||
**`width`**
|
|
||||||
- A `long` specifying the new width in CSS pixels.
|
|
||||||
|
|
||||||
**`height`**
|
|
||||||
- A `long` specifying the new height in CSS pixels.
|
|
||||||
|
|
|
@ -91,15 +91,6 @@ describe('Display/Canvas Helper', function () {
|
||||||
expect(display.flip).to.have.been.calledOnce;
|
expect(display.flip).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report clipping when framebuffer > viewport', function () {
|
|
||||||
expect(display.isClipped).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should report not clipping when framebuffer = viewport', function () {
|
|
||||||
display.viewportChangeSize(5, 5);
|
|
||||||
expect(display.isClipped).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should show the entire framebuffer when disabling the viewport', function() {
|
it('should show the entire framebuffer when disabling the viewport', function() {
|
||||||
display.clipViewport = false;
|
display.clipViewport = false;
|
||||||
expect(display.absX(0)).to.equal(0);
|
expect(display.absX(0)).to.equal(0);
|
||||||
|
|
|
@ -9,6 +9,22 @@ import { encodings } from '../core/encodings.js';
|
||||||
import FakeWebSocket from './fake.websocket.js';
|
import FakeWebSocket from './fake.websocket.js';
|
||||||
import sinon from '../vendor/sinon.js';
|
import sinon from '../vendor/sinon.js';
|
||||||
|
|
||||||
|
/* UIEvent constructor polyfill for IE */
|
||||||
|
(function () {
|
||||||
|
if (typeof window.UIEvent === "function") return;
|
||||||
|
|
||||||
|
function UIEvent ( event, params ) {
|
||||||
|
params = params || { bubbles: false, cancelable: false, view: window, detail: undefined };
|
||||||
|
var evt = document.createEvent( 'UIEvent' );
|
||||||
|
evt.initUIEvent( event, params.bubbles, params.cancelable, params.view, params.detail );
|
||||||
|
return evt;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIEvent.prototype = window.UIEvent.prototype;
|
||||||
|
|
||||||
|
window.UIEvent = UIEvent;
|
||||||
|
})();
|
||||||
|
|
||||||
var push8 = function (arr, num) {
|
var push8 = function (arr, num) {
|
||||||
"use strict";
|
"use strict";
|
||||||
arr.push(num & 0xFF);
|
arr.push(num & 0xFF);
|
||||||
|
@ -30,12 +46,16 @@ var push32 = function (arr, num) {
|
||||||
|
|
||||||
describe('Remote Frame Buffer Protocol Client', function() {
|
describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
var clock;
|
var clock;
|
||||||
|
var raf;
|
||||||
|
|
||||||
before(FakeWebSocket.replace);
|
before(FakeWebSocket.replace);
|
||||||
after(FakeWebSocket.restore);
|
after(FakeWebSocket.restore);
|
||||||
|
|
||||||
before(function () {
|
before(function () {
|
||||||
this.clock = clock = sinon.useFakeTimers();
|
this.clock = clock = sinon.useFakeTimers();
|
||||||
|
// sinon doesn't support this yet
|
||||||
|
raf = window.requestAnimationFrame;
|
||||||
|
window.requestAnimationFrame = setTimeout;
|
||||||
// Use a single set of buffers instead of reallocating to
|
// Use a single set of buffers instead of reallocating to
|
||||||
// speed up tests
|
// speed up tests
|
||||||
var sock = new Websock();
|
var sock = new Websock();
|
||||||
|
@ -53,28 +73,57 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
after(function () {
|
after(function () {
|
||||||
Websock.prototype._allocate_buffers = Websock.prototype._old_allocate_buffers;
|
Websock.prototype._allocate_buffers = Websock.prototype._old_allocate_buffers;
|
||||||
this.clock.restore();
|
this.clock.restore();
|
||||||
|
window.requestAnimationFrame = raf;
|
||||||
|
});
|
||||||
|
|
||||||
|
var container;
|
||||||
|
var rfbs;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
// Create a container element for all RFB objects to attach to
|
||||||
|
container = document.createElement('div');
|
||||||
|
container.style.width = "100%";
|
||||||
|
container.style.height = "100%";
|
||||||
|
document.body.appendChild(container);
|
||||||
|
|
||||||
|
// And track all created RFB objects
|
||||||
|
rfbs = [];
|
||||||
|
});
|
||||||
|
afterEach(function () {
|
||||||
|
// Make sure every created RFB object is properly cleaned up
|
||||||
|
// or they might affect subsequent tests
|
||||||
|
rfbs.forEach(function (rfb) {
|
||||||
|
rfb.disconnect();
|
||||||
|
expect(rfb._disconnect).to.have.been.called;
|
||||||
|
});
|
||||||
|
rfbs = [];
|
||||||
|
|
||||||
|
document.body.removeChild(container);
|
||||||
|
container = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
function make_rfb (url, options) {
|
function make_rfb (url, options) {
|
||||||
url = url || 'wss://host:8675';
|
url = url || 'wss://host:8675';
|
||||||
var rfb = new RFB(document.createElement('canvas'), url, options);
|
var rfb = new RFB(container, url, options);
|
||||||
clock.tick();
|
clock.tick();
|
||||||
rfb._sock._websocket._open();
|
rfb._sock._websocket._open();
|
||||||
rfb._rfb_connection_state = 'connected';
|
rfb._rfb_connection_state = 'connected';
|
||||||
|
sinon.spy(rfb, "_disconnect");
|
||||||
|
rfbs.push(rfb);
|
||||||
return rfb;
|
return rfb;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Connecting/Disconnecting', function () {
|
describe('Connecting/Disconnecting', function () {
|
||||||
describe('#RFB', function () {
|
describe('#RFB', function () {
|
||||||
it('should set the current state to "connecting"', function () {
|
it('should set the current state to "connecting"', function () {
|
||||||
var client = new RFB(document.createElement('canvas'), 'wss://host:8675');
|
var client = new RFB(document.createElement('div'), 'wss://host:8675');
|
||||||
client._rfb_connection_state = '';
|
client._rfb_connection_state = '';
|
||||||
this.clock.tick();
|
this.clock.tick();
|
||||||
expect(client._rfb_connection_state).to.equal('connecting');
|
expect(client._rfb_connection_state).to.equal('connecting');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should actually connect to the websocket', function () {
|
it('should actually connect to the websocket', function () {
|
||||||
var client = new RFB(document.createElement('canvas'), 'ws://HOST:8675/PATH');
|
var client = new RFB(document.createElement('div'), 'ws://HOST:8675/PATH');
|
||||||
sinon.spy(client._sock, 'open');
|
sinon.spy(client._sock, 'open');
|
||||||
this.clock.tick();
|
this.clock.tick();
|
||||||
expect(client._sock.open).to.have.been.calledOnce;
|
expect(client._sock.open).to.have.been.calledOnce;
|
||||||
|
@ -161,7 +210,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
it('should not send the keys if we are not in a normal state', function () {
|
it('should not send the keys if we are not in a normal state', function () {
|
||||||
sinon.spy(client._sock, 'flush');
|
sinon.spy(client._sock, 'flush');
|
||||||
client._rfb_connection_state = "broken";
|
client._rfb_connection_state = "connecting";
|
||||||
client.sendCtrlAltDel();
|
client.sendCtrlAltDel();
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
expect(client._sock.flush).to.not.have.been.called;
|
||||||
});
|
});
|
||||||
|
@ -192,7 +241,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
it('should not send the key if we are not in a normal state', function () {
|
it('should not send the key if we are not in a normal state', function () {
|
||||||
sinon.spy(client._sock, 'flush');
|
sinon.spy(client._sock, 'flush');
|
||||||
client._rfb_connection_state = "broken";
|
client._rfb_connection_state = "connecting";
|
||||||
client.sendKey(123, 'Key123');
|
client.sendKey(123, 'Key123');
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
expect(client._sock.flush).to.not.have.been.called;
|
||||||
});
|
});
|
||||||
|
@ -221,6 +270,22 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#focus', function () {
|
||||||
|
it('should move focus to canvas object', function () {
|
||||||
|
client._canvas.focus = sinon.spy();
|
||||||
|
client.focus();
|
||||||
|
expect(client._canvas.focus).to.have.been.called.once;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#blur', function () {
|
||||||
|
it('should remove focus from canvas object', function () {
|
||||||
|
client._canvas.blur = sinon.spy();
|
||||||
|
client.blur();
|
||||||
|
expect(client._canvas.blur).to.have.been.called.once;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#clipboardPasteFrom', function () {
|
describe('#clipboardPasteFrom', function () {
|
||||||
it('should send the given text in a paste event', function () {
|
it('should send the given text in a paste event', function () {
|
||||||
var expected = {_sQ: new Uint8Array(11), _sQlen: 0, flush: function () {}};
|
var expected = {_sQ: new Uint8Array(11), _sQlen: 0, flush: function () {}};
|
||||||
|
@ -231,50 +296,12 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
it('should not send the text if we are not in a normal state', function () {
|
it('should not send the text if we are not in a normal state', function () {
|
||||||
sinon.spy(client._sock, 'flush');
|
sinon.spy(client._sock, 'flush');
|
||||||
client._rfb_connection_state = "broken";
|
client._rfb_connection_state = "connecting";
|
||||||
client.clipboardPasteFrom('abc');
|
client.clipboardPasteFrom('abc');
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
expect(client._sock.flush).to.not.have.been.called;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#requestDesktopSize", function () {
|
|
||||||
beforeEach(function() {
|
|
||||||
client._supportsSetDesktopSize = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should send the request with the given width and height', function () {
|
|
||||||
var expected = [251];
|
|
||||||
push8(expected, 0); // padding
|
|
||||||
push16(expected, 1); // width
|
|
||||||
push16(expected, 2); // height
|
|
||||||
push8(expected, 1); // number-of-screens
|
|
||||||
push8(expected, 0); // padding before screen array
|
|
||||||
push32(expected, 0); // id
|
|
||||||
push16(expected, 0); // x-position
|
|
||||||
push16(expected, 0); // y-position
|
|
||||||
push16(expected, 1); // width
|
|
||||||
push16(expected, 2); // height
|
|
||||||
push32(expected, 0); // flags
|
|
||||||
|
|
||||||
client.requestDesktopSize(1, 2);
|
|
||||||
expect(client._sock).to.have.sent(new Uint8Array(expected));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not send the request if the client has not recieved a ExtendedDesktopSize rectangle', function () {
|
|
||||||
sinon.spy(client._sock, 'flush');
|
|
||||||
client._supportsSetDesktopSize = false;
|
|
||||||
client.requestDesktopSize(1,2);
|
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not send the request if we are not in a normal state', function () {
|
|
||||||
sinon.spy(client._sock, 'flush');
|
|
||||||
client._rfb_connection_state = "broken";
|
|
||||||
client.requestDesktopSize(1,2);
|
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("XVP operations", function () {
|
describe("XVP operations", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
client._rfb_xvp_ver = 1;
|
client._rfb_xvp_ver = 1;
|
||||||
|
@ -303,6 +330,394 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Clipping', function () {
|
||||||
|
var client;
|
||||||
|
beforeEach(function () {
|
||||||
|
client = make_rfb();
|
||||||
|
container.style.width = '70px';
|
||||||
|
container.style.height = '80px';
|
||||||
|
client.clipViewport = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update display clip state when changing the property', function () {
|
||||||
|
var spy = sinon.spy(client._display, "clipViewport", ["set"]);
|
||||||
|
|
||||||
|
client.clipViewport = false;
|
||||||
|
expect(spy.set).to.have.been.calledOnce;
|
||||||
|
expect(spy.set).to.have.been.calledWith(false);
|
||||||
|
spy.set.reset();
|
||||||
|
|
||||||
|
client.clipViewport = true;
|
||||||
|
expect(spy.set).to.have.been.calledOnce;
|
||||||
|
expect(spy.set).to.have.been.calledWith(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the viewport when the container size changes', function () {
|
||||||
|
sinon.spy(client._display, "viewportChangeSize");
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
|
expect(client._display.viewportChangeSize).to.have.been.calledOnce;
|
||||||
|
expect(client._display.viewportChangeSize).to.have.been.calledWith(40, 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the viewport when the remote session resizes', function () {
|
||||||
|
// Simple ExtendedDesktopSize FBU message
|
||||||
|
var incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00 ];
|
||||||
|
|
||||||
|
sinon.spy(client._display, "viewportChangeSize");
|
||||||
|
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array(incoming));
|
||||||
|
|
||||||
|
// FIXME: Display implicitly calls viewportChangeSize() when
|
||||||
|
// resizing the framebuffer, hence calledTwice.
|
||||||
|
expect(client._display.viewportChangeSize).to.have.been.calledTwice;
|
||||||
|
expect(client._display.viewportChangeSize).to.have.been.calledWith(70, 80);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update the viewport if not clipping', function () {
|
||||||
|
client.clipViewport = false;
|
||||||
|
sinon.spy(client._display, "viewportChangeSize");
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
|
expect(client._display.viewportChangeSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update the viewport if scaling', function () {
|
||||||
|
client.scaleViewport = true;
|
||||||
|
sinon.spy(client._display, "viewportChangeSize");
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
|
expect(client._display.viewportChangeSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Dragging', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
client.dragViewport = true;
|
||||||
|
sinon.spy(RFB.messages, "pointerEvent");
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
RFB.messages.pointerEvent.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not send button messages when initiating viewport dragging', function () {
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send button messages when release without movement', function () {
|
||||||
|
// Just up and down
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
client._handleMouseButton(13, 9, 0x000);
|
||||||
|
expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
|
||||||
|
|
||||||
|
RFB.messages.pointerEvent.reset();
|
||||||
|
|
||||||
|
// Small movement
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
client._handleMouseMove(15, 14);
|
||||||
|
client._handleMouseButton(15, 14, 0x000);
|
||||||
|
expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send button message directly when drag is disabled', function () {
|
||||||
|
client.dragViewport = false;
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be initiate viewport dragging on sufficient movement', function () {
|
||||||
|
sinon.spy(client._display, "viewportChangePos");
|
||||||
|
|
||||||
|
// Too small movement
|
||||||
|
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
client._handleMouseMove(18, 9);
|
||||||
|
|
||||||
|
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||||
|
expect(client._display.viewportChangePos).to.not.have.been.called;
|
||||||
|
|
||||||
|
// Sufficient movement
|
||||||
|
|
||||||
|
client._handleMouseMove(43, 9);
|
||||||
|
|
||||||
|
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||||
|
expect(client._display.viewportChangePos).to.have.been.calledOnce;
|
||||||
|
expect(client._display.viewportChangePos).to.have.been.calledWith(-30, 0);
|
||||||
|
|
||||||
|
client._display.viewportChangePos.reset();
|
||||||
|
|
||||||
|
// Now a small movement should move right away
|
||||||
|
|
||||||
|
client._handleMouseMove(43, 14);
|
||||||
|
|
||||||
|
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||||
|
expect(client._display.viewportChangePos).to.have.been.calledOnce;
|
||||||
|
expect(client._display.viewportChangePos).to.have.been.calledWith(0, -5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not send button messages when dragging ends', function () {
|
||||||
|
// First the movement
|
||||||
|
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
client._handleMouseMove(43, 9);
|
||||||
|
client._handleMouseButton(43, 9, 0x000);
|
||||||
|
|
||||||
|
expect(RFB.messages.pointerEvent).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should terminate viewport dragging on a button up event', function () {
|
||||||
|
// First the dragging movement
|
||||||
|
|
||||||
|
client._handleMouseButton(13, 9, 0x001);
|
||||||
|
client._handleMouseMove(43, 9);
|
||||||
|
client._handleMouseButton(43, 9, 0x000);
|
||||||
|
|
||||||
|
// Another movement now should not move the viewport
|
||||||
|
|
||||||
|
sinon.spy(client._display, "viewportChangePos");
|
||||||
|
|
||||||
|
client._handleMouseMove(43, 59);
|
||||||
|
|
||||||
|
expect(client._display.viewportChangePos).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Scaling', function () {
|
||||||
|
var client;
|
||||||
|
beforeEach(function () {
|
||||||
|
client = make_rfb();
|
||||||
|
container.style.width = '70px';
|
||||||
|
container.style.height = '80px';
|
||||||
|
client.scaleViewport = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update display scale factor when changing the property', function () {
|
||||||
|
var spy = sinon.spy(client._display, "scale", ["set"]);
|
||||||
|
sinon.spy(client._display, "autoscale");
|
||||||
|
|
||||||
|
client.scaleViewport = false;
|
||||||
|
expect(spy.set).to.have.been.calledOnce;
|
||||||
|
expect(spy.set).to.have.been.calledWith(1.0);
|
||||||
|
expect(client._display.autoscale).to.not.have.been.called;
|
||||||
|
|
||||||
|
client.scaleViewport = true;
|
||||||
|
expect(client._display.autoscale).to.have.been.calledOnce;
|
||||||
|
expect(client._display.autoscale).to.have.been.calledWith(70, 80);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the clipping setting when changing the property', function () {
|
||||||
|
client.clipViewport = true;
|
||||||
|
|
||||||
|
var spy = sinon.spy(client._display, "clipViewport", ["set"]);
|
||||||
|
|
||||||
|
client.scaleViewport = false;
|
||||||
|
expect(spy.set).to.have.been.calledOnce;
|
||||||
|
expect(spy.set).to.have.been.calledWith(true);
|
||||||
|
|
||||||
|
spy.set.reset();
|
||||||
|
|
||||||
|
client.scaleViewport = true;
|
||||||
|
expect(spy.set).to.have.been.calledOnce;
|
||||||
|
expect(spy.set).to.have.been.calledWith(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the scaling when the container size changes', function () {
|
||||||
|
sinon.spy(client._display, "autoscale");
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
|
expect(client._display.autoscale).to.have.been.calledOnce;
|
||||||
|
expect(client._display.autoscale).to.have.been.calledWith(40, 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the scaling when the remote session resizes', function () {
|
||||||
|
// Simple ExtendedDesktopSize FBU message
|
||||||
|
var incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00 ];
|
||||||
|
|
||||||
|
sinon.spy(client._display, "autoscale");
|
||||||
|
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array(incoming));
|
||||||
|
|
||||||
|
expect(client._display.autoscale).to.have.been.calledOnce;
|
||||||
|
expect(client._display.autoscale).to.have.been.calledWith(70, 80);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update the display scale factor if not scaling', function () {
|
||||||
|
client.scaleViewport = false;
|
||||||
|
|
||||||
|
sinon.spy(client._display, "autoscale");
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
|
expect(client._display.autoscale).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Remote resize', function () {
|
||||||
|
var client;
|
||||||
|
beforeEach(function () {
|
||||||
|
client = make_rfb();
|
||||||
|
client._supportsSetDesktopSize = true;
|
||||||
|
client.resizeSession = true;
|
||||||
|
container.style.width = '70px';
|
||||||
|
container.style.height = '80px';
|
||||||
|
sinon.spy(RFB.messages, "setDesktopSize");
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
RFB.messages.setDesktopSize.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only request a resize when turned on', function () {
|
||||||
|
client.resizeSession = false;
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
client.resizeSession = true;
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should request a resize when initially connecting', function () {
|
||||||
|
// Simple ExtendedDesktopSize FBU message
|
||||||
|
var incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
|
||||||
|
0x00, 0x00, 0x00, 0x00 ];
|
||||||
|
|
||||||
|
// First message should trigger a resize
|
||||||
|
|
||||||
|
client._supportsSetDesktopSize = false;
|
||||||
|
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array(incoming));
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 70, 80, 0, 0);
|
||||||
|
|
||||||
|
RFB.messages.setDesktopSize.reset();
|
||||||
|
|
||||||
|
// Second message should not trigger a resize
|
||||||
|
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array(incoming));
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should request a resize when the container resizes', function () {
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick(1000);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 40, 50, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not resize until the container size is stable', function () {
|
||||||
|
container.style.width = '20px';
|
||||||
|
container.style.height = '30px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick(400);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick(400);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
|
||||||
|
clock.tick(200);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
|
||||||
|
expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 40, 50, 0, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not resize when resize is disabled', function () {
|
||||||
|
client._resizeSession = false;
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick(1000);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not resize when resize is not supported', function () {
|
||||||
|
client._supportsSetDesktopSize = false;
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick(1000);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not resize when in view only mode', function () {
|
||||||
|
client._viewOnly = true;
|
||||||
|
|
||||||
|
container.style.width = '40px';
|
||||||
|
container.style.height = '50px';
|
||||||
|
var event = new UIEvent('resize');
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
clock.tick(1000);
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not try to override a server resize', function () {
|
||||||
|
// Simple ExtendedDesktopSize FBU message
|
||||||
|
var incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
|
||||||
|
0x00, 0x00, 0x00, 0x00 ];
|
||||||
|
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array(incoming));
|
||||||
|
|
||||||
|
expect(RFB.messages.setDesktopSize).to.not.have.been.called;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Misc Internals', function () {
|
describe('Misc Internals', function () {
|
||||||
describe('#_updateConnectionState', function () {
|
describe('#_updateConnectionState', function () {
|
||||||
var client;
|
var client;
|
||||||
|
@ -321,28 +736,32 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the rfb_connection_state', function () {
|
it('should set the rfb_connection_state', function () {
|
||||||
client._rfb_connection_state = 'disconnecting';
|
client._rfb_connection_state = 'connecting';
|
||||||
client._updateConnectionState('disconnected');
|
client._updateConnectionState('connected');
|
||||||
expect(client._rfb_connection_state).to.equal('disconnected');
|
expect(client._rfb_connection_state).to.equal('connected');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not change the state when we are disconnected', function () {
|
it('should not change the state when we are disconnected', function () {
|
||||||
client._rfb_connection_state = 'disconnected';
|
client.disconnect();
|
||||||
|
expect(client._rfb_connection_state).to.equal('disconnected');
|
||||||
client._updateConnectionState('connecting');
|
client._updateConnectionState('connecting');
|
||||||
expect(client._rfb_connection_state).to.not.equal('connecting');
|
expect(client._rfb_connection_state).to.not.equal('connecting');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore state changes to the same state', function () {
|
it('should ignore state changes to the same state', function () {
|
||||||
var connectSpy = sinon.spy();
|
var connectSpy = sinon.spy();
|
||||||
var disconnectSpy = sinon.spy();
|
|
||||||
client.addEventListener("connect", connectSpy);
|
client.addEventListener("connect", connectSpy);
|
||||||
client.addEventListener("disconnect", disconnectSpy);
|
|
||||||
|
|
||||||
client._rfb_connection_state = 'connected';
|
expect(client._rfb_connection_state).to.equal('connected');
|
||||||
client._updateConnectionState('connected');
|
client._updateConnectionState('connected');
|
||||||
expect(connectSpy).to.not.have.been.called;
|
expect(connectSpy).to.not.have.been.called;
|
||||||
|
|
||||||
client._rfb_connection_state = 'disconnected';
|
client.disconnect();
|
||||||
|
|
||||||
|
var disconnectSpy = sinon.spy();
|
||||||
|
client.addEventListener("disconnect", disconnectSpy);
|
||||||
|
|
||||||
|
expect(client._rfb_connection_state).to.equal('disconnected');
|
||||||
client._updateConnectionState('disconnected');
|
client._updateConnectionState('disconnected');
|
||||||
expect(disconnectSpy).to.not.have.been.called;
|
expect(disconnectSpy).to.not.have.been.called;
|
||||||
});
|
});
|
||||||
|
@ -350,7 +769,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
it('should ignore illegal state changes', function () {
|
it('should ignore illegal state changes', function () {
|
||||||
var spy = sinon.spy();
|
var spy = sinon.spy();
|
||||||
client.addEventListener("disconnect", spy);
|
client.addEventListener("disconnect", spy);
|
||||||
client._rfb_connection_state = 'connected';
|
|
||||||
client._updateConnectionState('disconnected');
|
client._updateConnectionState('disconnected');
|
||||||
expect(client._rfb_connection_state).to.not.equal('disconnected');
|
expect(client._rfb_connection_state).to.not.equal('disconnected');
|
||||||
expect(spy).to.not.have.been.called;
|
expect(spy).to.not.have.been.called;
|
||||||
|
@ -400,7 +818,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
describe('Connection States', function () {
|
describe('Connection States', function () {
|
||||||
describe('connecting', function () {
|
describe('connecting', function () {
|
||||||
it('should open the websocket connection', function () {
|
it('should open the websocket connection', function () {
|
||||||
var client = new RFB(document.createElement('canvas'),
|
var client = new RFB(document.createElement('div'),
|
||||||
'ws://HOST:8675/PATH');
|
'ws://HOST:8675/PATH');
|
||||||
sinon.spy(client._sock, 'open');
|
sinon.spy(client._sock, 'open');
|
||||||
this.clock.tick();
|
this.clock.tick();
|
||||||
|
@ -460,11 +878,21 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
client._updateConnectionState('disconnecting');
|
client._updateConnectionState('disconnecting');
|
||||||
expect(client._sock.close).to.have.been.calledOnce;
|
expect(client._sock.close).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not result in a disconnect event', function () {
|
||||||
|
var spy = sinon.spy();
|
||||||
|
client.addEventListener("disconnect", spy);
|
||||||
|
client._sock._websocket.close = function () {}; // explicitly don't call onclose
|
||||||
|
client._updateConnectionState('disconnecting');
|
||||||
|
expect(spy).to.not.have.been.called;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('disconnected', function () {
|
describe('disconnected', function () {
|
||||||
var client;
|
var client;
|
||||||
beforeEach(function () { client = make_rfb(); });
|
beforeEach(function () {
|
||||||
|
client = new RFB(document.createElement('div'), 'ws://HOST:8675/PATH');
|
||||||
|
});
|
||||||
|
|
||||||
it('should result in a disconnect event if state becomes "disconnected"', function () {
|
it('should result in a disconnect event if state becomes "disconnected"', function () {
|
||||||
var spy = sinon.spy();
|
var spy = sinon.spy();
|
||||||
|
@ -475,14 +903,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
expect(spy.args[0][0].detail.clean).to.be.true;
|
expect(spy.args[0][0].detail.clean).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not result in a disconnect event if the state is not "disconnected"', function () {
|
|
||||||
var spy = sinon.spy();
|
|
||||||
client.addEventListener("disconnect", spy);
|
|
||||||
client._sock._websocket.close = function () {}; // explicitly don't call onclose
|
|
||||||
client._updateConnectionState('disconnecting');
|
|
||||||
expect(spy).to.not.have.been.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should result in a disconnect event without msg when no reason given', function () {
|
it('should result in a disconnect event without msg when no reason given', function () {
|
||||||
var spy = sinon.spy();
|
var spy = sinon.spy();
|
||||||
client.addEventListener("disconnect", spy);
|
client.addEventListener("disconnect", spy);
|
||||||
|
@ -892,7 +1312,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fall through to ServerInitialisation on a response code of 0', function () {
|
it('should fall through to ServerInitialisation on a response code of 0', function () {
|
||||||
client._updateConnectionState = sinon.spy();
|
|
||||||
client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
|
client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
|
||||||
expect(client._rfb_init_state).to.equal('ServerInitialisation');
|
expect(client._rfb_init_state).to.equal('ServerInitialisation');
|
||||||
});
|
});
|
||||||
|
@ -1060,17 +1479,12 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
expect(client._rfb_connection_state).to.equal('connected');
|
expect(client._rfb_connection_state).to.equal('connected');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the resize callback and resize the display', function () {
|
it('should resize the display', function () {
|
||||||
var spy = sinon.spy();
|
|
||||||
client.addEventListener("fbresize", spy);
|
|
||||||
sinon.spy(client._display, 'resize');
|
sinon.spy(client._display, 'resize');
|
||||||
send_server_init({ width: 27, height: 32 }, client);
|
send_server_init({ width: 27, height: 32 }, client);
|
||||||
|
|
||||||
expect(client._display.resize).to.have.been.calledOnce;
|
expect(client._display.resize).to.have.been.calledOnce;
|
||||||
expect(client._display.resize).to.have.been.calledWith(27, 32);
|
expect(client._display.resize).to.have.been.calledWith(27, 32);
|
||||||
expect(spy).to.have.been.calledOnce;
|
|
||||||
expect(spy.args[0][0].detail.width).to.equal(27);
|
|
||||||
expect(spy.args[0][0].detail.height).to.equal(32);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should grab the mouse and keyboard', function () {
|
it('should grab the mouse and keyboard', function () {
|
||||||
|
@ -1471,14 +1885,9 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
it('should handle the DesktopSize pseduo-encoding', function () {
|
it('should handle the DesktopSize pseduo-encoding', function () {
|
||||||
var spy = sinon.spy();
|
var spy = sinon.spy();
|
||||||
client.addEventListener("fbresize", spy);
|
|
||||||
sinon.spy(client._display, 'resize');
|
sinon.spy(client._display, 'resize');
|
||||||
send_fbu_msg([{ x: 0, y: 0, width: 20, height: 50, encoding: -223 }], [[]], client);
|
send_fbu_msg([{ x: 0, y: 0, width: 20, height: 50, encoding: -223 }], [[]], client);
|
||||||
|
|
||||||
expect(spy).to.have.been.calledOnce;
|
|
||||||
expect(spy.args[0][0].detail.width).to.equal(20);
|
|
||||||
expect(spy.args[0][0].detail.height).to.equal(50);
|
|
||||||
|
|
||||||
expect(client._fb_width).to.equal(20);
|
expect(client._fb_width).to.equal(20);
|
||||||
expect(client._fb_height).to.equal(50);
|
expect(client._fb_height).to.equal(50);
|
||||||
|
|
||||||
|
@ -1490,14 +1899,12 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
var resizeSpy;
|
var resizeSpy;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
client._supportsSetDesktopSize = false;
|
|
||||||
// a really small frame
|
// a really small frame
|
||||||
client._fb_width = 4;
|
client._fb_width = 4;
|
||||||
client._fb_height = 4;
|
client._fb_height = 4;
|
||||||
client._display.resize(4, 4);
|
client._display.resize(4, 4);
|
||||||
sinon.spy(client._display, 'resize');
|
sinon.spy(client._display, 'resize');
|
||||||
resizeSpy = sinon.spy();
|
resizeSpy = sinon.spy();
|
||||||
client.addEventListener("fbresize", resizeSpy);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function make_screen_data (nr_of_screens) {
|
function make_screen_data (nr_of_screens) {
|
||||||
|
@ -1516,26 +1923,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
it('should call callback when resize is supported', function () {
|
|
||||||
var spy = sinon.spy();
|
|
||||||
client.addEventListener("capabilities", spy);
|
|
||||||
|
|
||||||
expect(client._supportsSetDesktopSize).to.be.false;
|
|
||||||
expect(client.capabilities.resize).to.be.false;
|
|
||||||
|
|
||||||
var reason_for_change = 0; // server initiated
|
|
||||||
var status_code = 0; // No error
|
|
||||||
|
|
||||||
send_fbu_msg([{ x: reason_for_change, y: status_code,
|
|
||||||
width: 4, height: 4, encoding: -308 }],
|
|
||||||
make_screen_data(1), client);
|
|
||||||
|
|
||||||
expect(client._supportsSetDesktopSize).to.be.true;
|
|
||||||
expect(spy).to.have.been.calledOnce;
|
|
||||||
expect(spy.args[0][0].detail.capabilities.resize).to.be.true;
|
|
||||||
expect(client.capabilities.resize).to.be.true;
|
|
||||||
}),
|
|
||||||
|
|
||||||
it('should handle a resize requested by this client', function () {
|
it('should handle a resize requested by this client', function () {
|
||||||
var reason_for_change = 1; // requested by this client
|
var reason_for_change = 1; // requested by this client
|
||||||
var status_code = 0; // No error
|
var status_code = 0; // No error
|
||||||
|
@ -1549,10 +1936,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
expect(client._display.resize).to.have.been.calledOnce;
|
expect(client._display.resize).to.have.been.calledOnce;
|
||||||
expect(client._display.resize).to.have.been.calledWith(20, 50);
|
expect(client._display.resize).to.have.been.calledWith(20, 50);
|
||||||
|
|
||||||
expect(resizeSpy).to.have.been.calledOnce;
|
|
||||||
expect(resizeSpy.args[0][0].detail.width).to.equal(20);
|
|
||||||
expect(resizeSpy.args[0][0].detail.height).to.equal(50);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle a resize requested by another client', function () {
|
it('should handle a resize requested by another client', function () {
|
||||||
|
@ -1568,10 +1951,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
expect(client._display.resize).to.have.been.calledOnce;
|
expect(client._display.resize).to.have.been.calledOnce;
|
||||||
expect(client._display.resize).to.have.been.calledWith(20, 50);
|
expect(client._display.resize).to.have.been.calledWith(20, 50);
|
||||||
|
|
||||||
expect(resizeSpy).to.have.been.calledOnce;
|
|
||||||
expect(resizeSpy.args[0][0].detail.width).to.equal(20);
|
|
||||||
expect(resizeSpy.args[0][0].detail.height).to.equal(50);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to recieve requests which contain data for multiple screens', function () {
|
it('should be able to recieve requests which contain data for multiple screens', function () {
|
||||||
|
@ -1587,10 +1966,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
expect(client._display.resize).to.have.been.calledOnce;
|
expect(client._display.resize).to.have.been.calledOnce;
|
||||||
expect(client._display.resize).to.have.been.calledWith(60, 50);
|
expect(client._display.resize).to.have.been.calledWith(60, 50);
|
||||||
|
|
||||||
expect(resizeSpy).to.have.been.calledOnce;
|
|
||||||
expect(resizeSpy.args[0][0].detail.width).to.equal(60);
|
|
||||||
expect(resizeSpy.args[0][0].detail.height).to.equal(50);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not handle a failed request', function () {
|
it('should not handle a failed request', function () {
|
||||||
|
@ -1605,8 +1980,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
expect(client._fb_height).to.equal(4);
|
expect(client._fb_height).to.equal(4);
|
||||||
|
|
||||||
expect(client._display.resize).to.not.have.been.called;
|
expect(client._display.resize).to.not.have.been.called;
|
||||||
|
|
||||||
expect(resizeSpy).to.not.have.been.called;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1786,60 +2159,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
RFB.messages.pointerEvent(pointer_msg, 13, 9, 0x010);
|
RFB.messages.pointerEvent(pointer_msg, 13, 9, 0x010);
|
||||||
expect(client._sock).to.have.sent(pointer_msg._sQ);
|
expect(client._sock).to.have.sent(pointer_msg._sQ);
|
||||||
});
|
});
|
||||||
|
|
||||||
// NB(directxman12): we don't need to test not sending messages in
|
|
||||||
// non-normal modes, since we haven't grabbed input
|
|
||||||
// yet (grabbing input should be checked in the lifecycle tests).
|
|
||||||
|
|
||||||
it('should not send movement messages when viewport dragging', function () {
|
|
||||||
client._viewportDragging = true;
|
|
||||||
client._display.viewportChangePos = sinon.spy();
|
|
||||||
sinon.spy(client._sock, 'flush');
|
|
||||||
client._handleMouseMove(13, 9);
|
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not send button messages when initiating viewport dragging', function () {
|
|
||||||
client.dragViewport = true;
|
|
||||||
sinon.spy(client._sock, 'flush');
|
|
||||||
client._handleMouseButton(13, 9, 0x001);
|
|
||||||
expect(client._sock.flush).to.not.have.been.called;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be initiate viewport dragging on a button down event, if enabled', function () {
|
|
||||||
client.dragViewport = true;
|
|
||||||
client._handleMouseButton(13, 9, 0x001);
|
|
||||||
expect(client._viewportDragging).to.be.true;
|
|
||||||
expect(client._viewportDragPos).to.deep.equal({ x: 13, y: 9 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should terminate viewport dragging on a button up event, if enabled', function () {
|
|
||||||
client.dragViewport = true;
|
|
||||||
client._viewportDragging = true;
|
|
||||||
client._handleMouseButton(13, 9, 0x000);
|
|
||||||
expect(client._viewportDragging).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('if enabled, viewportDragging should occur on mouse movement while a button is down', function () {
|
|
||||||
var oldX = 123;
|
|
||||||
var oldY = 109;
|
|
||||||
var newX = 123 + 11 * window.devicePixelRatio;
|
|
||||||
var newY = 109 + 4 * window.devicePixelRatio;
|
|
||||||
|
|
||||||
client.dragViewport = true;
|
|
||||||
client._viewportDragging = true;
|
|
||||||
client._viewportHasMoved = false;
|
|
||||||
client._viewportDragPos = { x: oldX, y: oldY };
|
|
||||||
client._display.viewportChangePos = sinon.spy();
|
|
||||||
|
|
||||||
client._handleMouseMove(newX, newY);
|
|
||||||
|
|
||||||
expect(client._viewportDragging).to.be.true;
|
|
||||||
expect(client._viewportHasMoved).to.be.true;
|
|
||||||
expect(client._viewportDragPos).to.deep.equal({ x: newX, y: newY });
|
|
||||||
expect(client._display.viewportChangePos).to.have.been.calledOnce;
|
|
||||||
expect(client._display.viewportChangePos).to.have.been.calledWith(oldX - newX, oldY - newY);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Keyboard Event Handlers', function () {
|
describe('Keyboard Event Handlers', function () {
|
||||||
|
@ -1890,7 +2209,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
// open events
|
// open events
|
||||||
it('should update the state to ProtocolVersion on open (if the state is "connecting")', function () {
|
it('should update the state to ProtocolVersion on open (if the state is "connecting")', function () {
|
||||||
client = new RFB(document.createElement('canvas'), 'wss://host:8675');
|
client = new RFB(document.createElement('div'), 'wss://host:8675');
|
||||||
this.clock.tick();
|
this.clock.tick();
|
||||||
client._sock._websocket._open();
|
client._sock._websocket._open();
|
||||||
expect(client._rfb_init_state).to.equal('ProtocolVersion');
|
expect(client._rfb_init_state).to.equal('ProtocolVersion');
|
||||||
|
@ -1898,14 +2217,18 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
|
|
||||||
it('should fail if we are not currently ready to connect and we get an "open" event', function () {
|
it('should fail if we are not currently ready to connect and we get an "open" event', function () {
|
||||||
sinon.spy(client, "_fail");
|
sinon.spy(client, "_fail");
|
||||||
client._rfb_connection_state = 'some_other_state';
|
client._rfb_connection_state = 'connected';
|
||||||
client._sock._websocket._open();
|
client._sock._websocket._open();
|
||||||
expect(client._fail).to.have.been.calledOnce;
|
expect(client._fail).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
|
|
||||||
// close events
|
// close events
|
||||||
it('should transition to "disconnected" from "disconnecting" on a close event', function () {
|
it('should transition to "disconnected" from "disconnecting" on a close event', function () {
|
||||||
client._rfb_connection_state = 'disconnecting';
|
var real = client._sock._websocket.close;
|
||||||
|
client._sock._websocket.close = function () {};
|
||||||
|
client.disconnect();
|
||||||
|
expect(client._rfb_connection_state).to.equal('disconnecting');
|
||||||
|
client._sock._websocket.close = real;
|
||||||
client._sock._websocket.close();
|
client._sock._websocket.close();
|
||||||
expect(client._rfb_connection_state).to.equal('disconnected');
|
expect(client._rfb_connection_state).to.equal('disconnected');
|
||||||
});
|
});
|
||||||
|
@ -1917,16 +2240,9 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
expect(client._fail).to.have.been.calledOnce;
|
expect(client._fail).to.have.been.calledOnce;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail if we get a close event while disconnected', function () {
|
|
||||||
sinon.spy(client, "_fail");
|
|
||||||
client._rfb_connection_state = 'disconnected';
|
|
||||||
client._sock._websocket.close();
|
|
||||||
expect(client._fail).to.have.been.calledOnce;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should unregister close event handler', function () {
|
it('should unregister close event handler', function () {
|
||||||
sinon.spy(client._sock, 'off');
|
sinon.spy(client._sock, 'off');
|
||||||
client._rfb_connection_state = 'disconnecting';
|
client.disconnect();
|
||||||
client._sock._websocket.close();
|
client._sock._websocket.close();
|
||||||
expect(client._sock.off).to.have.been.calledWith('close');
|
expect(client._sock.off).to.have.been.calledWith('close');
|
||||||
});
|
});
|
||||||
|
|
9
vnc.html
9
vnc.html
|
@ -315,9 +315,8 @@
|
||||||
<div class="noVNC_spinner"></div>
|
<div class="noVNC_spinner"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- This is where the RFB elements will attach -->
|
||||||
<div id="noVNC_container">
|
<div id="noVNC_container">
|
||||||
<!-- HTML5 Canvas -->
|
|
||||||
<div id="noVNC_screen">
|
|
||||||
<!-- Note that Google Chrome on Android doesn't respect any of these,
|
<!-- Note that Google Chrome on Android doesn't respect any of these,
|
||||||
html attributes which attempt to disable text suggestions on the
|
html attributes which attempt to disable text suggestions on the
|
||||||
on-screen keyboard. Let's hope Chrome implements the ime-mode
|
on-screen keyboard. Let's hope Chrome implements the ime-mode
|
||||||
|
@ -325,12 +324,6 @@
|
||||||
<textarea id="noVNC_keyboardinput" autocapitalize="off"
|
<textarea id="noVNC_keyboardinput" autocapitalize="off"
|
||||||
autocorrect="off" autocomplete="off" spellcheck="false"
|
autocorrect="off" autocomplete="off" spellcheck="false"
|
||||||
mozactionhint="Enter" tabindex="-1"></textarea>
|
mozactionhint="Enter" tabindex="-1"></textarea>
|
||||||
|
|
||||||
<canvas id="noVNC_canvas" width="0" height="0">
|
|
||||||
Canvas not supported.
|
|
||||||
</canvas>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<audio id="noVNC_bell">
|
<audio id="noVNC_bell">
|
||||||
|
|
|
@ -80,24 +80,8 @@
|
||||||
import RFB from './core/rfb.js';
|
import RFB from './core/rfb.js';
|
||||||
|
|
||||||
var rfb;
|
var rfb;
|
||||||
var doneInitialResize;
|
|
||||||
var resizeTimeout;
|
|
||||||
var desktopName;
|
var desktopName;
|
||||||
|
|
||||||
function UIresize() {
|
|
||||||
if (WebUtil.getConfigVar('resize', false)) {
|
|
||||||
var innerW = window.innerWidth;
|
|
||||||
var innerH = window.innerHeight;
|
|
||||||
var controlbarH = document.getElementById('noVNC_status_bar').offsetHeight;
|
|
||||||
if (innerW !== undefined && innerH !== undefined)
|
|
||||||
rfb.requestDesktopSize(innerW, innerH - controlbarH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function initialResize() {
|
|
||||||
if (doneInitialResize) return;
|
|
||||||
UIresize();
|
|
||||||
doneInitialResize = true;
|
|
||||||
}
|
|
||||||
function updateDesktopName(e) {
|
function updateDesktopName(e) {
|
||||||
desktopName = e.detail.name;
|
desktopName = e.detail.name;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +134,6 @@
|
||||||
|
|
||||||
function connected(e) {
|
function connected(e) {
|
||||||
document.getElementById('sendCtrlAltDelButton').disabled = false;
|
document.getElementById('sendCtrlAltDelButton').disabled = false;
|
||||||
doneInitialResize = false;
|
|
||||||
if (WebUtil.getConfigVar('encrypt',
|
if (WebUtil.getConfigVar('encrypt',
|
||||||
(window.location.protocol === "https:"))) {
|
(window.location.protocol === "https:"))) {
|
||||||
status("Connected (encrypted) to " + desktopName, "normal");
|
status("Connected (encrypted) to " + desktopName, "normal");
|
||||||
|
@ -169,16 +152,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onresize = function () {
|
|
||||||
// When the window has been resized, wait until the size remains
|
|
||||||
// the same for 0.5 seconds before sending the request for changing
|
|
||||||
// the resolution of the session
|
|
||||||
clearTimeout(resizeTimeout);
|
|
||||||
resizeTimeout = setTimeout(function(){
|
|
||||||
UIresize();
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
|
|
||||||
function updatePowerButtons() {
|
function updatePowerButtons() {
|
||||||
var powerbuttons;
|
var powerbuttons;
|
||||||
powerbuttons = document.getElementById('noVNC_power_buttons');
|
powerbuttons = document.getElementById('noVNC_power_buttons');
|
||||||
|
@ -247,16 +220,18 @@
|
||||||
}
|
}
|
||||||
url += '/' + path;
|
url += '/' + path;
|
||||||
|
|
||||||
rfb = new RFB(document.getElementById('noVNC_canvas'), url,
|
rfb = new RFB(document.body, url,
|
||||||
{ repeaterID: WebUtil.getConfigVar('repeaterID', ''),
|
{ repeaterID: WebUtil.getConfigVar('repeaterID', ''),
|
||||||
shared: WebUtil.getConfigVar('shared', true),
|
shared: WebUtil.getConfigVar('shared', true),
|
||||||
credentials: { password: password } });
|
credentials: { password: password } });
|
||||||
rfb.viewOnly = WebUtil.getConfigVar('view_only', false);
|
rfb.viewOnly = WebUtil.getConfigVar('view_only', false);
|
||||||
rfb.addEventListener("connect", connected);
|
rfb.addEventListener("connect", connected);
|
||||||
rfb.addEventListener("disconnect", disconnected);
|
rfb.addEventListener("disconnect", disconnected);
|
||||||
rfb.addEventListener("capabilities", function () { updatePowerButtons(); initialResize(); });
|
rfb.addEventListener("capabilities", function () { updatePowerButtons(); });
|
||||||
rfb.addEventListener("credentialsrequired", credentials);
|
rfb.addEventListener("credentialsrequired", credentials);
|
||||||
rfb.addEventListener("desktopname", updateDesktopName);
|
rfb.addEventListener("desktopname", updateDesktopName);
|
||||||
|
rfb.scaleViewport = WebUtil.getConfigVar('scale', false);
|
||||||
|
rfb.resizeSession = WebUtil.getConfigVar('resize', false);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -278,9 +253,5 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="noVNC_canvas" width="0" height="0">
|
|
||||||
Canvas not supported.
|
|
||||||
</canvas>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue