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;
|
||||
}
|
||||
|
||||
/* 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.*/
|
||||
/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */
|
||||
@font-face {
|
||||
|
|
|
@ -61,10 +61,3 @@ html {
|
|||
display: flex;
|
||||
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,
|
||||
desktopName: "",
|
||||
|
||||
resizeTimeout: null,
|
||||
statusTimeout: null,
|
||||
hideKeyboardTimeout: null,
|
||||
idleControlbarTimeout: null,
|
||||
|
@ -87,7 +86,6 @@ var UI = {
|
|||
UI.initFullscreen();
|
||||
|
||||
// Setup event handlers
|
||||
UI.addResizeHandlers();
|
||||
UI.addControlbarHandlers();
|
||||
UI.addTouchSpecificHandlers();
|
||||
UI.addExtraKeysHandlers();
|
||||
|
@ -103,8 +101,6 @@ var UI = {
|
|||
|
||||
UI.openControlbar();
|
||||
|
||||
UI.updateViewClip();
|
||||
|
||||
UI.updateVisualState('init');
|
||||
|
||||
document.documentElement.classList.remove("noVNC_loading");
|
||||
|
@ -205,11 +201,6 @@ var UI = {
|
|||
* EVENT HANDLERS
|
||||
* ------v------*/
|
||||
|
||||
addResizeHandlers: function() {
|
||||
window.addEventListener('resize', UI.applyResizeMode);
|
||||
window.addEventListener('resize', UI.updateViewClip);
|
||||
},
|
||||
|
||||
addControlbarHandlers: function() {
|
||||
document.getElementById("noVNC_control_bar")
|
||||
.addEventListener('mousemove', UI.activateControlbar);
|
||||
|
@ -432,7 +423,6 @@ var UI = {
|
|||
UI.disableSetting('port');
|
||||
UI.disableSetting('path');
|
||||
UI.disableSetting('repeaterID');
|
||||
UI.updateViewClip();
|
||||
UI.setMouseButton(1);
|
||||
|
||||
// Hide the controlbar after 2 seconds
|
||||
|
@ -1037,7 +1027,7 @@ var UI = {
|
|||
}
|
||||
url += '/' + path;
|
||||
|
||||
UI.rfb = new RFB(document.getElementById('noVNC_canvas'), url,
|
||||
UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
|
||||
{ shared: UI.getSetting('shared'),
|
||||
repeaterID: UI.getSetting('repeaterID'),
|
||||
credentials: { password: password } });
|
||||
|
@ -1045,11 +1035,13 @@ var UI = {
|
|||
UI.rfb.addEventListener("disconnect", UI.disconnectFinished);
|
||||
UI.rfb.addEventListener("credentialsrequired", UI.credentials);
|
||||
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("bell", UI.bell);
|
||||
UI.rfb.addEventListener("fbresize", UI.updateSessionSize);
|
||||
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() {
|
||||
|
@ -1092,7 +1084,6 @@ var UI = {
|
|||
connectFinished: function (e) {
|
||||
UI.connected = true;
|
||||
UI.inhibit_reconnect = false;
|
||||
UI.doneInitialResize = false;
|
||||
|
||||
let msg;
|
||||
if (UI.getSetting('encrypt')) {
|
||||
|
@ -1104,7 +1095,7 @@ var UI = {
|
|||
UI.updateVisualState('connected');
|
||||
|
||||
// Do this last because it can only be used on rendered elements
|
||||
document.getElementById('noVNC_canvas').focus();
|
||||
UI.rfb.focus();
|
||||
},
|
||||
|
||||
disconnectFinished: function (e) {
|
||||
|
@ -1238,74 +1229,8 @@ var UI = {
|
|||
applyResizeMode: function() {
|
||||
if (!UI.rfb) return;
|
||||
|
||||
var screen = UI.screenSize();
|
||||
|
||||
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;
|
||||
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
|
||||
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
||||
},
|
||||
|
||||
/* ------^-------
|
||||
|
@ -1314,12 +1239,6 @@ var UI = {
|
|||
* VIEW CLIPPING
|
||||
* ------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
|
||||
updateViewClip: function() {
|
||||
if (!UI.rfb) return;
|
||||
|
@ -1327,11 +1246,7 @@ var UI = {
|
|||
var cur_clip = UI.rfb.clipViewport;
|
||||
var new_clip = UI.getSetting('view_clip');
|
||||
|
||||
var resizeSetting = UI.getSetting('resize');
|
||||
if (resizeSetting === 'scale') {
|
||||
// Disable viewport clipping if we are scaling
|
||||
new_clip = false;
|
||||
} else if (isTouchDevice) {
|
||||
if (isTouchDevice) {
|
||||
// Touch devices usually have shit scrollbars
|
||||
new_clip = true;
|
||||
}
|
||||
|
@ -1340,15 +1255,6 @@ var UI = {
|
|||
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
|
||||
// the dragging button
|
||||
UI.updateViewDrag();
|
||||
|
@ -1389,23 +1295,13 @@ var UI = {
|
|||
},
|
||||
|
||||
updateViewDrag: function() {
|
||||
var clipping = false;
|
||||
|
||||
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');
|
||||
|
||||
if (!clipping &&
|
||||
UI.rfb.dragViewport) {
|
||||
// The size of the remote display is the same or smaller
|
||||
// than the client display. Make sure viewport drag isn't
|
||||
// active when it can't be used.
|
||||
if (!UI.rfb.clipViewport && UI.rfb.dragViewport) {
|
||||
// We are no longer clipping the viewport. Make sure
|
||||
// viewport drag isn't active when it can't be used.
|
||||
UI.rfb.dragViewport = false;
|
||||
}
|
||||
|
||||
|
@ -1420,7 +1316,7 @@ var UI = {
|
|||
if (isTouchDevice) {
|
||||
viewDragButton.classList.remove("noVNC_hidden");
|
||||
|
||||
if (clipping) {
|
||||
if (UI.rfb.clipViewport) {
|
||||
viewDragButton.disabled = false;
|
||||
} else {
|
||||
viewDragButton.disabled = true;
|
||||
|
@ -1428,7 +1324,7 @@ var UI = {
|
|||
} else {
|
||||
viewDragButton.disabled = false;
|
||||
|
||||
if (clipping) {
|
||||
if (UI.rfb.clipViewport) {
|
||||
viewDragButton.classList.remove("noVNC_hidden");
|
||||
} else {
|
||||
viewDragButton.classList.add("noVNC_hidden");
|
||||
|
@ -1703,24 +1599,6 @@ var UI = {
|
|||
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) {
|
||||
UI.desktopName = e.detail.name;
|
||||
// Display the desktop name in the document title
|
||||
|
|
|
@ -106,11 +106,6 @@ Display.prototype = {
|
|||
return this._fb_height;
|
||||
},
|
||||
|
||||
get isClipped() {
|
||||
var vp = this._viewportLoc;
|
||||
return this._fb_width > vp.w || this._fb_height > vp.h;
|
||||
},
|
||||
|
||||
logo: null,
|
||||
|
||||
// ===== 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._capabilities = { power: false, resize: false };
|
||||
this._capabilities = { power: false };
|
||||
|
||||
this._supportsFence = false;
|
||||
|
||||
|
@ -88,6 +88,7 @@ export default function RFB(target, url, options) {
|
|||
|
||||
// Timers
|
||||
this._disconnTimer = null; // disconnection timer
|
||||
this._resizeTimeout = null; // resize rate limiting
|
||||
|
||||
// Decoder states and stats
|
||||
this._encHandlers = {};
|
||||
|
@ -140,15 +141,29 @@ export default function RFB(target, url, options) {
|
|||
// Bound event handlers
|
||||
this._eventHandlers = {
|
||||
focusCanvas: this._focusCanvas.bind(this),
|
||||
windowResize: this._windowResize.bind(this),
|
||||
};
|
||||
|
||||
// main setup
|
||||
Log.Debug(">> RFB.constructor");
|
||||
|
||||
// Target canvas must be able to have focus
|
||||
if (!this._target.hasAttribute('tabindex')) {
|
||||
this._target.tabIndex = -1;
|
||||
}
|
||||
// Create DOM elements
|
||||
this._screen = document.createElement('div');
|
||||
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
|
||||
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
|
||||
// before this point, since this can throw an exception
|
||||
try {
|
||||
this._display = new Display(this._target);
|
||||
this._display = new Display(this._canvas);
|
||||
} catch (exc) {
|
||||
Log.Error("Display exception: " + exc);
|
||||
throw exc;
|
||||
|
@ -174,10 +189,10 @@ export default function RFB(target, url, options) {
|
|||
this._display.onflush = this._onFlush.bind(this);
|
||||
this._display.clear();
|
||||
|
||||
this._keyboard = new Keyboard(this._target);
|
||||
this._keyboard = new Keyboard(this._canvas);
|
||||
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.onmousemove = this._handleMouseMove.bind(this);
|
||||
|
||||
|
@ -266,13 +281,36 @@ RFB.prototype = {
|
|||
get touchButton() { return this._mouse.touchButton; },
|
||||
set touchButton(button) { this._mouse.touchButton = button; },
|
||||
|
||||
get viewportScale() { return this._display.scale; },
|
||||
set viewportScale(scale) { this._display.scale = scale; },
|
||||
_clipViewport: false,
|
||||
get clipViewport() { return this._clipViewport; },
|
||||
set clipViewport(viewport) {
|
||||
this._clipViewport = viewport;
|
||||
this._updateClip();
|
||||
},
|
||||
|
||||
get clipViewport() { return this._display.clipViewport; },
|
||||
set clipViewport(viewport) { this._display.clipViewport = viewport; },
|
||||
_scaleViewport: false,
|
||||
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 =====
|
||||
|
||||
|
@ -341,38 +379,19 @@ RFB.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
this._canvas.focus();
|
||||
},
|
||||
|
||||
blur: function () {
|
||||
this._canvas.blur();
|
||||
},
|
||||
|
||||
clipboardPasteFrom: function (text) {
|
||||
if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
|
||||
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 =====
|
||||
|
||||
_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
|
||||
this._target.addEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||
this._target.addEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||
this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||
this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||
|
||||
Log.Debug("<< RFB.connect");
|
||||
},
|
||||
|
||||
_disconnect: function () {
|
||||
Log.Debug(">> RFB.disconnect");
|
||||
this._target.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||
this._target.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||
this._cleanup();
|
||||
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
|
||||
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
|
||||
window.removeEventListener('resize', this._eventHandlers.windowResize);
|
||||
this._keyboard.ungrab();
|
||||
this._mouse.ungrab();
|
||||
this._sock.close();
|
||||
this._print_stats();
|
||||
this._target.removeChild(this._screen);
|
||||
clearTimeout(this._resizeTimeout);
|
||||
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) {
|
||||
// Respect earlier handlers' request to not do side-effects
|
||||
if (event.defaultPrevented) {
|
||||
|
@ -447,7 +466,97 @@ RFB.prototype = {
|
|||
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) {
|
||||
this._viewportDragging = true;
|
||||
this._viewportDragPos = {'x': x, 'y': y};
|
||||
this._viewportHasMoved = false;
|
||||
|
||||
// Skip sending mouse events
|
||||
return;
|
||||
} else {
|
||||
this._viewportDragging = false;
|
||||
|
||||
// If the viewport didn't actually move, then treat as a mouse click event
|
||||
// Send the button down event here, as the button up event is sent at the end of this function
|
||||
if (!this._viewportHasMoved && !this._viewOnly) {
|
||||
RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), bmask);
|
||||
// If we actually performed a drag then we are done
|
||||
// here and should not send any mouse events
|
||||
if (this._viewportHasMoved) {
|
||||
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);
|
||||
|
||||
var event = new CustomEvent("fbresize",
|
||||
{ detail: { width: this._fb_width,
|
||||
height: this._fb_height } });
|
||||
this.dispatchEvent(event);
|
||||
// Adjust the visible viewport based on the new dimensions
|
||||
this._updateClip();
|
||||
this._updateScale();
|
||||
|
||||
this._timing.fbu_rt_start = (new Date()).getTime();
|
||||
this._updateContinuousUpdates();
|
||||
|
@ -2300,8 +2416,16 @@ RFB.encodingHandlers = {
|
|||
this._FBU.bytes = 1;
|
||||
if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) { return false; }
|
||||
|
||||
var firstUpdate = !this._supportsSetDesktopSize;
|
||||
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();
|
||||
|
||||
|
|
|
@ -89,7 +89,6 @@ None
|
|||
| clipViewport | bool | RW | false | Use viewport clipping
|
||||
| width | int | RO | | Display area width
|
||||
| height | int | RO | | Display area height
|
||||
| isClipped | bool | RO | | Is the remote display is larger than the client display
|
||||
|
||||
### 2.3.2 Methods
|
||||
|
||||
|
|
140
docs/API.md
140
docs/API.md
|
@ -23,8 +23,8 @@ protocol stream.
|
|||
|
||||
`focusOnClick`
|
||||
- Is a `boolean` indicating if keyboard focus should automatically be
|
||||
moved to the canvas when a `mousedown` or `touchstart` event is
|
||||
received.
|
||||
moved to the remote session when a `mousedown` or `touchstart`
|
||||
event is received.
|
||||
|
||||
`touchButton`
|
||||
- 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).
|
||||
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`
|
||||
- Is a `boolean` indicating if the canvas should be clipped to its
|
||||
container. When disabled the container must be able to handle the
|
||||
resulting overflow. Disabled by default.
|
||||
- Is a `boolean` indicating if the remote session should be clipped
|
||||
to its container. When disabled scrollbars will be shown to handle
|
||||
the resulting overflow. Disabled by default.
|
||||
|
||||
`dragViewport`
|
||||
- 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.
|
||||
|
||||
`isClipped` *Read only*
|
||||
- Is a `boolean` indicating if the framebuffer is larger than the
|
||||
current canvas, i.e. it is being clipped.
|
||||
`scaleViewport`
|
||||
- Is a `boolean` indicating if the remote session should be scaled
|
||||
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*
|
||||
- Is an `Object` indicating which optional extensions are available
|
||||
|
@ -59,7 +61,6 @@ protocol stream.
|
|||
| name | type | description
|
||||
| -------- | --------- | -----------
|
||||
| `power` | `boolean` | Machine power control is available
|
||||
| `resize` | `boolean` | The framebuffer can be resized
|
||||
|
||||
### Events
|
||||
|
||||
|
@ -86,9 +87,6 @@ protocol stream.
|
|||
- The `bell` event is fired when a audible bell request is received
|
||||
from the server.
|
||||
|
||||
[`fbresize`](#fbresize)
|
||||
- The `fbresize` event is fired when the framebuffer size is changed.
|
||||
|
||||
[`desktopname`](#desktopname)
|
||||
- The `desktopname` event is fired when the remote desktop name
|
||||
changes.
|
||||
|
@ -112,6 +110,12 @@ protocol stream.
|
|||
[`RFB.sendCtrlAltDel()`](#rfbsendctrlaltdel)
|
||||
- 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)
|
||||
- Request a shutdown of the remote machine.
|
||||
|
||||
|
@ -124,16 +128,6 @@ protocol stream.
|
|||
[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom)
|
||||
- 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
|
||||
|
||||
#### RFB()
|
||||
|
@ -148,9 +142,10 @@ connection to a specified VNC server.
|
|||
###### Parameters
|
||||
|
||||
**`target`**
|
||||
- A [`HTMLCanvasElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement)
|
||||
that specifies where graphics should be rendered and input events
|
||||
should be monitored.
|
||||
- A block [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)
|
||||
that specifies where the `RFB` object should attach itself. The
|
||||
existing contents of the `HTMLElement` will be untouched, but new
|
||||
elements will be added during the lifetime of the `RFB` object.
|
||||
|
||||
**`url`**
|
||||
- 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
|
||||
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
|
||||
|
||||
The `desktopname` event is fired when the name of the remote desktop
|
||||
|
@ -310,6 +299,25 @@ around [`RFB.sendKey()`](#rfbsendkey).
|
|||
|
||||
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()
|
||||
|
||||
The `RFB.machineShutdown()` method is used to request to shut down the
|
||||
|
@ -354,61 +362,3 @@ to the remote server.
|
|||
**`text`**
|
||||
- A `DOMString` specifying the clipboard data to send. Currently only
|
||||
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;
|
||||
});
|
||||
|
||||
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() {
|
||||
display.clipViewport = false;
|
||||
expect(display.absX(0)).to.equal(0);
|
||||
|
|
|
@ -9,6 +9,22 @@ import { encodings } from '../core/encodings.js';
|
|||
import FakeWebSocket from './fake.websocket.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) {
|
||||
"use strict";
|
||||
arr.push(num & 0xFF);
|
||||
|
@ -30,12 +46,16 @@ var push32 = function (arr, num) {
|
|||
|
||||
describe('Remote Frame Buffer Protocol Client', function() {
|
||||
var clock;
|
||||
var raf;
|
||||
|
||||
before(FakeWebSocket.replace);
|
||||
after(FakeWebSocket.restore);
|
||||
|
||||
before(function () {
|
||||
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
|
||||
// speed up tests
|
||||
var sock = new Websock();
|
||||
|
@ -53,28 +73,57 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
after(function () {
|
||||
Websock.prototype._allocate_buffers = Websock.prototype._old_allocate_buffers;
|
||||
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) {
|
||||
url = url || 'wss://host:8675';
|
||||
var rfb = new RFB(document.createElement('canvas'), url, options);
|
||||
var rfb = new RFB(container, url, options);
|
||||
clock.tick();
|
||||
rfb._sock._websocket._open();
|
||||
rfb._rfb_connection_state = 'connected';
|
||||
sinon.spy(rfb, "_disconnect");
|
||||
rfbs.push(rfb);
|
||||
return rfb;
|
||||
}
|
||||
|
||||
describe('Connecting/Disconnecting', function () {
|
||||
describe('#RFB', 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 = '';
|
||||
this.clock.tick();
|
||||
expect(client._rfb_connection_state).to.equal('connecting');
|
||||
});
|
||||
|
||||
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');
|
||||
this.clock.tick();
|
||||
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 () {
|
||||
sinon.spy(client._sock, 'flush');
|
||||
client._rfb_connection_state = "broken";
|
||||
client._rfb_connection_state = "connecting";
|
||||
client.sendCtrlAltDel();
|
||||
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 () {
|
||||
sinon.spy(client._sock, 'flush');
|
||||
client._rfb_connection_state = "broken";
|
||||
client._rfb_connection_state = "connecting";
|
||||
client.sendKey(123, 'Key123');
|
||||
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 () {
|
||||
it('should send the given text in a paste event', 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 () {
|
||||
sinon.spy(client._sock, 'flush');
|
||||
client._rfb_connection_state = "broken";
|
||||
client._rfb_connection_state = "connecting";
|
||||
client.clipboardPasteFrom('abc');
|
||||
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 () {
|
||||
beforeEach(function () {
|
||||
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('#_updateConnectionState', function () {
|
||||
var client;
|
||||
|
@ -321,28 +736,32 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
});
|
||||
|
||||
it('should set the rfb_connection_state', function () {
|
||||
client._rfb_connection_state = 'disconnecting';
|
||||
client._updateConnectionState('disconnected');
|
||||
expect(client._rfb_connection_state).to.equal('disconnected');
|
||||
client._rfb_connection_state = 'connecting';
|
||||
client._updateConnectionState('connected');
|
||||
expect(client._rfb_connection_state).to.equal('connected');
|
||||
});
|
||||
|
||||
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');
|
||||
expect(client._rfb_connection_state).to.not.equal('connecting');
|
||||
});
|
||||
|
||||
it('should ignore state changes to the same state', function () {
|
||||
var connectSpy = sinon.spy();
|
||||
var disconnectSpy = sinon.spy();
|
||||
client.addEventListener("connect", connectSpy);
|
||||
client.addEventListener("disconnect", disconnectSpy);
|
||||
|
||||
client._rfb_connection_state = 'connected';
|
||||
expect(client._rfb_connection_state).to.equal('connected');
|
||||
client._updateConnectionState('connected');
|
||||
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');
|
||||
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 () {
|
||||
var spy = sinon.spy();
|
||||
client.addEventListener("disconnect", spy);
|
||||
client._rfb_connection_state = 'connected';
|
||||
client._updateConnectionState('disconnected');
|
||||
expect(client._rfb_connection_state).to.not.equal('disconnected');
|
||||
expect(spy).to.not.have.been.called;
|
||||
|
@ -400,7 +818,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
describe('Connection States', function () {
|
||||
describe('connecting', 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');
|
||||
sinon.spy(client._sock, 'open');
|
||||
this.clock.tick();
|
||||
|
@ -460,11 +878,21 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
client._updateConnectionState('disconnecting');
|
||||
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 () {
|
||||
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 () {
|
||||
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;
|
||||
});
|
||||
|
||||
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 () {
|
||||
var spy = sinon.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 () {
|
||||
client._updateConnectionState = sinon.spy();
|
||||
client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
|
||||
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');
|
||||
});
|
||||
|
||||
it('should call the resize callback and resize the display', function () {
|
||||
var spy = sinon.spy();
|
||||
client.addEventListener("fbresize", spy);
|
||||
it('should resize the display', function () {
|
||||
sinon.spy(client._display, 'resize');
|
||||
send_server_init({ width: 27, height: 32 }, client);
|
||||
|
||||
expect(client._display.resize).to.have.been.calledOnce;
|
||||
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 () {
|
||||
|
@ -1471,14 +1885,9 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
|
||||
it('should handle the DesktopSize pseduo-encoding', function () {
|
||||
var spy = sinon.spy();
|
||||
client.addEventListener("fbresize", spy);
|
||||
sinon.spy(client._display, 'resize');
|
||||
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_height).to.equal(50);
|
||||
|
||||
|
@ -1490,14 +1899,12 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
var resizeSpy;
|
||||
|
||||
beforeEach(function () {
|
||||
client._supportsSetDesktopSize = false;
|
||||
// a really small frame
|
||||
client._fb_width = 4;
|
||||
client._fb_height = 4;
|
||||
client._display.resize(4, 4);
|
||||
sinon.spy(client._display, 'resize');
|
||||
resizeSpy = sinon.spy();
|
||||
client.addEventListener("fbresize", resizeSpy);
|
||||
});
|
||||
|
||||
function make_screen_data (nr_of_screens) {
|
||||
|
@ -1516,26 +1923,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
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 () {
|
||||
var reason_for_change = 1; // requested by this client
|
||||
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.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 () {
|
||||
|
@ -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.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 () {
|
||||
|
@ -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.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 () {
|
||||
|
@ -1605,8 +1980,6 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
expect(client._fb_height).to.equal(4);
|
||||
|
||||
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);
|
||||
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 () {
|
||||
|
@ -1890,7 +2209,7 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
|||
|
||||
// open events
|
||||
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();
|
||||
client._sock._websocket._open();
|
||||
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 () {
|
||||
sinon.spy(client, "_fail");
|
||||
client._rfb_connection_state = 'some_other_state';
|
||||
client._rfb_connection_state = 'connected';
|
||||
client._sock._websocket._open();
|
||||
expect(client._fail).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
// close events
|
||||
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();
|
||||
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;
|
||||
});
|
||||
|
||||
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 () {
|
||||
sinon.spy(client._sock, 'off');
|
||||
client._rfb_connection_state = 'disconnecting';
|
||||
client.disconnect();
|
||||
client._sock._websocket.close();
|
||||
expect(client._sock.off).to.have.been.calledWith('close');
|
||||
});
|
||||
|
|
23
vnc.html
23
vnc.html
|
@ -315,22 +315,15 @@
|
|||
<div class="noVNC_spinner"></div>
|
||||
</div>
|
||||
|
||||
<!-- This is where the RFB elements will attach -->
|
||||
<div id="noVNC_container">
|
||||
<!-- HTML5 Canvas -->
|
||||
<div id="noVNC_screen">
|
||||
<!-- Note that Google Chrome on Android doesn't respect any of these,
|
||||
html attributes which attempt to disable text suggestions on the
|
||||
on-screen keyboard. Let's hope Chrome implements the ime-mode
|
||||
style for example -->
|
||||
<textarea id="noVNC_keyboardinput" autocapitalize="off"
|
||||
autocorrect="off" autocomplete="off" spellcheck="false"
|
||||
mozactionhint="Enter" tabindex="-1"></textarea>
|
||||
|
||||
<canvas id="noVNC_canvas" width="0" height="0">
|
||||
Canvas not supported.
|
||||
</canvas>
|
||||
</div>
|
||||
|
||||
<!-- Note that Google Chrome on Android doesn't respect any of these,
|
||||
html attributes which attempt to disable text suggestions on the
|
||||
on-screen keyboard. Let's hope Chrome implements the ime-mode
|
||||
style for example -->
|
||||
<textarea id="noVNC_keyboardinput" autocapitalize="off"
|
||||
autocorrect="off" autocomplete="off" spellcheck="false"
|
||||
mozactionhint="Enter" tabindex="-1"></textarea>
|
||||
</div>
|
||||
|
||||
<audio id="noVNC_bell">
|
||||
|
|
|
@ -80,24 +80,8 @@
|
|||
import RFB from './core/rfb.js';
|
||||
|
||||
var rfb;
|
||||
var doneInitialResize;
|
||||
var resizeTimeout;
|
||||
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) {
|
||||
desktopName = e.detail.name;
|
||||
}
|
||||
|
@ -150,7 +134,6 @@
|
|||
|
||||
function connected(e) {
|
||||
document.getElementById('sendCtrlAltDelButton').disabled = false;
|
||||
doneInitialResize = false;
|
||||
if (WebUtil.getConfigVar('encrypt',
|
||||
(window.location.protocol === "https:"))) {
|
||||
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() {
|
||||
var powerbuttons;
|
||||
powerbuttons = document.getElementById('noVNC_power_buttons');
|
||||
|
@ -247,16 +220,18 @@
|
|||
}
|
||||
url += '/' + path;
|
||||
|
||||
rfb = new RFB(document.getElementById('noVNC_canvas'), url,
|
||||
rfb = new RFB(document.body, url,
|
||||
{ repeaterID: WebUtil.getConfigVar('repeaterID', ''),
|
||||
shared: WebUtil.getConfigVar('shared', true),
|
||||
credentials: { password: password } });
|
||||
rfb.viewOnly = WebUtil.getConfigVar('view_only', false);
|
||||
rfb.addEventListener("connect", connected);
|
||||
rfb.addEventListener("disconnect", disconnected);
|
||||
rfb.addEventListener("capabilities", function () { updatePowerButtons(); initialResize(); });
|
||||
rfb.addEventListener("capabilities", function () { updatePowerButtons(); });
|
||||
rfb.addEventListener("credentialsrequired", credentials);
|
||||
rfb.addEventListener("desktopname", updateDesktopName);
|
||||
rfb.scaleViewport = WebUtil.getConfigVar('scale', false);
|
||||
rfb.resizeSession = WebUtil.getConfigVar('resize', false);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
|
@ -278,9 +253,5 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="noVNC_canvas" width="0" height="0">
|
||||
Canvas not supported.
|
||||
</canvas>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue