This commit is contained in:
Pierre Ossman 2017-12-11 16:48:54 +01:00
commit 4f4f62261a
11 changed files with 754 additions and 568 deletions

View File

@ -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 {

View File

@ -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
View File

@ -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

View File

@ -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 =====

View File

@ -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();

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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');
}); });

View File

@ -315,22 +315,15 @@
<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 --> <!-- Note that Google Chrome on Android doesn't respect any of these,
<div id="noVNC_screen"> html attributes which attempt to disable text suggestions on the
<!-- Note that Google Chrome on Android doesn't respect any of these, on-screen keyboard. Let's hope Chrome implements the ime-mode
html attributes which attempt to disable text suggestions on the style for example -->
on-screen keyboard. Let's hope Chrome implements the ime-mode <textarea id="noVNC_keyboardinput" autocapitalize="off"
style for example --> autocorrect="off" autocomplete="off" spellcheck="false"
<textarea id="noVNC_keyboardinput" autocapitalize="off" mozactionhint="Enter" tabindex="-1"></textarea>
autocorrect="off" autocomplete="off" spellcheck="false"
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">

View File

@ -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>