summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsamhed <samuel@cendio.se>2015-03-09 14:30:56 +0100
committersamhed <samuel@cendio.se>2015-03-09 14:30:56 +0100
commitfdedbafb1de63c8c704db5396fbb15a4187d9c62 (patch)
tree383ae9111821013499f137e645f4ae0cc8e993d8
parent798340b98d097afd7e7cd949d9256dcf2a74eef4 (diff)
downloadnovnc-fdedbafb1de63c8c704db5396fbb15a4187d9c62.tar.gz
* Don't check specific html elements from the display code (Fixes #446)
* Renamed and reworked fbuClip to clippingDisplay * Added tests for clippingDisplay * Use the a noVNC_container which covers the entire page to get the full size (Fixes #463) * Added maxWidth and maxHeight to the canvas which can limit the viewport size * Only show either the canvas or the logo, hide one when the other is shown * Always center the canvas (previously it was only centered when not clipping) * Removed iOS specific "position-fixed" fixes and start calling setBarPosition on every resize * Removed the noVNC_screen_pad
-rw-r--r--include/base.css22
-rw-r--r--include/display.js98
-rw-r--r--include/ui.js147
-rw-r--r--tests/test.display.js34
-rw-r--r--vnc.html4
5 files changed, 194 insertions, 111 deletions
diff --git a/include/base.css b/include/base.css
index e2c9a96..478b4d0 100644
--- a/include/base.css
+++ b/include/base.css
@@ -112,13 +112,7 @@ html {
/* Do not set width/height for VNC_screen or VNC_canvas or incorrect
* scaling will occur. Canvas resizes to remote VNC settings */
-#noVNC_screen_pad {
- margin: 0px;
- padding: 0px;
- height: 36px;
-}
#noVNC_screen {
- text-align: center;
display: table;
width:100%;
height:100%;
@@ -127,13 +121,25 @@ html {
/*border-top-left-radius: 800px 600px;*/
}
-#noVNC_container, #noVNC_canvas {
+#noVNC_container {
+ display: none;
+ position: absolute;
margin: 0px;
padding: 0px;
+ bottom: 0px;
+ top: 36px; /* the height of the control bar */
+ left: 0px;
+ right: 0px;
+ width: auto;
+ height: auto;
}
#noVNC_canvas {
- left: 0px;
+ position: absolute;
+ left: 0;
+ right: 0;
+ margin-left: auto;
+ margin-right: auto;
}
#VNC_clipboard_clear_button {
diff --git a/include/display.js b/include/display.js
index 2b1b827..d10d9b9 100644
--- a/include/display.js
+++ b/include/display.js
@@ -1,6 +1,7 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
+ * Copyright (C) 2015 Samuel Mannehed for Cendio AB
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -24,6 +25,10 @@ var Display;
this._fb_width = 0;
this._fb_height = 0;
+ // the size limit of the viewport (start disabled)
+ this._maxWidth = 0;
+ this._maxHeight = 0;
+
// the visible "physical canvas" viewport
this._viewportLoc = { 'x': 0, 'y': 0, 'w': 0, 'h': 0 };
this._cleanRect = { 'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1 };
@@ -202,8 +207,7 @@ var Display;
viewportChangeSize: function(width, height) {
- if (!this._viewport ||
- typeof(width) === "undefined" || typeof(height) === "undefined") {
+ if (typeof(width) === "undefined" || typeof(height) === "undefined") {
Util.Debug("Setting viewport to full display region");
width = this._fb_width;
@@ -213,41 +217,49 @@ var Display;
var vp = this._viewportLoc;
if (vp.w !== width || vp.h !== height) {
+ if (this._viewport) {
+ if (this._maxWidth !== 0 && width > this._maxWidth) {
+ width = this._maxWidth;
+ }
+ if (this._maxHeight !== 0 && height > this._maxHeight) {
+ height = this._maxHeight;
+ }
+ }
+
var cr = this._cleanRect;
if (width < vp.w && cr.x2 > vp.x + width - 1) {
cr.x2 = vp.x + width - 1;
}
-
if (height < vp.h && cr.y2 > vp.y + height - 1) {
cr.y2 = vp.y + height - 1;
}
- if (this.fbuClip()) {
- // clipping
- vp.w = window.innerWidth;
- var cb = document.getElementById('noVNC-control-bar');
- var controlbar_h = (cb !== null) ? cb.offsetHeight : 0;
- vp.h = window.innerHeight - controlbar_h - 5;
- } else {
- // scrollbars
- vp.w = width;
- vp.h = height;
- }
+ vp.w = width;
+ vp.h = height;
- var saveImg = null;
var canvas = this._target;
- if (vp.w > 0 && vp.h > 0 && canvas.width > 0 && canvas.height > 0) {
- var img_width = canvas.width < vp.w ? canvas.width : vp.w;
- var img_height = canvas.height < vp.h ? canvas.height : vp.h;
- saveImg = this._drawCtx.getImageData(0, 0, img_width, img_height);
- }
+ if (canvas.width !== width || canvas.height !== height) {
+
+ // We have to save the canvas data since changing the size will clear it
+ var saveImg = null;
+ if (vp.w > 0 && vp.h > 0 && canvas.width > 0 && canvas.height > 0) {
+ var img_width = canvas.width < vp.w ? canvas.width : vp.w;
+ var img_height = canvas.height < vp.h ? canvas.height : vp.h;
+ saveImg = this._drawCtx.getImageData(0, 0, img_width, img_height);
+ }
+
+ if (canvas.width !== width) { canvas.width = width; }
+ if (canvas.height !== height) { canvas.height = height; }
- canvas.width = vp.w;
- canvas.height = vp.h;
+ if (this._viewport) {
+ canvas.style.height = height + 'px';
+ canvas.style.width = width + 'px';
+ }
- if (saveImg) {
- this._drawCtx.putImageData(saveImg, 0, 0);
+ if (saveImg) {
+ this._drawCtx.putImageData(saveImg, 0, 0);
+ }
}
}
},
@@ -487,12 +499,18 @@ var Display;
this._target.style.cursor = "none";
},
- fbuClip: function () {
- var cb = document.getElementById('noVNC-control-bar');
- var controlbar_h = (cb !== null) ? cb.offsetHeight : 0;
- return (this._viewport &&
- (this._fb_width > window.innerWidth
- || this._fb_height > window.innerHeight - controlbar_h - 5));
+ clippingDisplay: function () {
+ var vp = this._viewportLoc;
+
+ var fbClip = this._fb_width > vp.w || this._fb_height > vp.h;
+ var limitedVp = this._maxWidth !== 0 && this._maxHeight !== 0;
+ var clipping = false;
+
+ if (limitedVp) {
+ clipping = vp.w > this._maxWidth || vp.h > this._maxHeight;
+ }
+
+ return fbClip || (limitedVp && clipping);
},
// Overridden getters/setters
@@ -558,8 +576,20 @@ var Display;
_rescale: function (factor) {
this._scale = factor;
- this._target.style.width = Math.round(factor * this._fb_width) + 'px';
- this._target.style.height = Math.round(factor * this._fb_height) + 'px';
+ var w;
+ var h;
+
+ if (this._viewport &&
+ this._maxWidth !== 0 && this._maxHeight !== 0) {
+ w = Math.min(this._fb_width, this._maxWidth);
+ h = Math.min(this._fb_height, this._maxHeight);
+ } else {
+ w = this._fb_width;
+ h = this._fb_height;
+ }
+
+ this._target.style.width = Math.round(factor * w) + 'px';
+ this._target.style.height = Math.round(factor * h) + 'px';
},
_setFillColor: function (color) {
@@ -661,9 +691,11 @@ var Display;
['true_color', 'rw', 'bool'], // Use true-color pixel data
['colourMap', 'rw', 'arr'], // Colour map array (when not true-color)
['scale', 'rw', 'float'], // Display area scale factor 0.0 - 1.0
- ['viewport', 'rw', 'bool'], // Use a viewport set with viewportChange()
+ ['viewport', 'rw', 'bool'], // Use viewport clipping
['width', 'rw', 'int'], // Display area width
['height', 'rw', 'int'], // Display area height
+ ['maxWidth', 'rw', 'int'], // Viewport max width (0 if disabled)
+ ['maxHeight', 'rw', 'int'], // Viewport max height (0 if disabled)
['render_mode', 'ro', 'str'], // Canvas rendering mode (read-only)
diff --git a/include/ui.js b/include/ui.js
index fb28e3e..bcc0a94 100644
--- a/include/ui.js
+++ b/include/ui.js
@@ -1,7 +1,7 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 Samuel Mannehed for Cendio AB
+ * Copyright (C) 2015 Samuel Mannehed for Cendio AB
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -45,33 +45,6 @@ var UI;
WebUtil.initSettings(UI.start, callback);
},
- onresize: function (callback) {
- var innerW = window.innerWidth;
- var innerH = window.innerHeight;
- var controlbarH = $D('noVNC-control-bar').offsetHeight;
- // For some unknown reason the container is higher than the canvas,
- // 5px higher in Firefox and 4px higher in Chrome
- var padding = 5;
- var effectiveH = innerH - controlbarH - padding;
-
- var display = UI.rfb.get_display();
-
- if (innerW !== undefined && innerH !== undefined) {
- var scaleType = UI.getSetting('resize');
- if (scaleType === 'remote') {
- // use remote resizing
- Util.Debug('Attempting setDesktopSize(' + innerW + ', ' + effectiveH + ')');
- UI.rfb.setDesktopSize(innerW, effectiveH);
- } else if (scaleType === 'scale' || scaleType === 'downscale') {
- // use local scaling
- var downscaleOnly = scaleType === 'downscale';
- var scaleRatio = display.autoscale(innerW, effectiveH, downscaleOnly);
- UI.rfb.get_mouse().set_scale(scaleRatio);
- Util.Debug('Scaling by ' + UI.rfb.get_mouse().get_scale());
- }
- }
- },
-
// Render default UI and initialize settings menu
start: function(callback) {
UI.isTouchDevice = 'ontouchstart' in document.documentElement;
@@ -136,6 +109,8 @@ var UI;
UI.updateVisualState();
+ $D('noVNC_host').focus();
+
// Show mouse selector buttons on touch screen devices
if (UI.isTouchDevice) {
// Show mobile buttons
@@ -148,29 +123,14 @@ var UI;
UI.initSetting('clip', false);
}
- //iOS Safari does not support CSS position:fixed.
- //This detects iOS devices and enables javascript workaround.
- if ((navigator.userAgent.match(/iPhone/i)) ||
- (navigator.userAgent.match(/iPod/i)) ||
- (navigator.userAgent.match(/iPad/i))) {
- //UI.setOnscroll();
- //UI.setResize();
- }
- UI.setBarPosition();
-
- $D('noVNC_host').focus();
-
UI.setViewClip();
+ UI.setBarPosition();
Util.addEvent(window, 'resize', function () {
+ UI.onresize();
UI.setViewClip();
- // 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(){
- UI.onresize();
- }, 500);
+ UI.updateViewDragButton();
+ UI.setBarPosition();
} );
Util.addEvent(window, 'load', UI.keyboardinputReset);
@@ -258,6 +218,55 @@ var UI;
};
},
+ onresize: function (callback) {
+ var size = UI.getCanvasLimit();
+
+ if (size && UI.rfb_state === 'normal' && UI.rfb.get_display()) {
+ var display = UI.rfb.get_display();
+ var scaleType = UI.getSetting('resize');
+ if (scaleType === 'remote') {
+ // use remote resizing
+
+ // When the local 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(){
+ display.set_maxWidth(size.w);
+ display.set_maxHeight(size.h);
+ Util.Debug('Attempting setDesktopSize(' +
+ size.w + ', ' + size.h + ')');
+ UI.rfb.setDesktopSize(size.w, size.h);
+ }, 500);
+ } else if (scaleType === 'scale' || scaleType === 'downscale') {
+ // use local scaling
+
+ var downscaleOnly = scaleType === 'downscale';
+ var scaleRatio = display.autoscale(size.w, size.h, downscaleOnly);
+ UI.rfb.get_mouse().set_scale(scaleRatio);
+ Util.Debug('Scaling by ' + UI.rfb.get_mouse().get_scale());
+ }
+ }
+ },
+
+ getCanvasLimit: function () {
+ var container = $D('noVNC_container');
+
+ // Hide the scrollbars until the size is calculated
+ container.style.overflow = "hidden";
+
+ var w = Util.getPosition(container).width;
+ var h = Util.getPosition(container).height;
+
+ container.style.overflow = "visible";
+
+ if (isNaN(w) || isNaN(h)) {
+ return false;
+ } else {
+ return {w: w, h: h};
+ }
+ },
+
// Read form control compatible setting from cookie
getSetting: function(name) {
var ctrl = $D('noVNC_' + name);
@@ -613,6 +622,7 @@ var UI;
break;
case 'disconnected':
$D('noVNC_logo').style.display = "block";
+ $D('noVNC_container').style.display = "none";
/* falls through */
case 'loaded':
klass = "noVNC_status_normal";
@@ -781,6 +791,7 @@ var UI;
//Close dialog.
setTimeout(UI.setBarPosition, 100);
$D('noVNC_logo').style.display = "none";
+ $D('noVNC_container').style.display = "inline";
},
disconnect: function() {
@@ -791,6 +802,8 @@ var UI;
UI.rfb.set_onFBUComplete(UI.FBUComplete);
$D('noVNC_logo').style.display = "block";
+ $D('noVNC_container').style.display = "none";
+
// Don't display the connection settings until we're actually disconnected
},
@@ -839,17 +852,30 @@ var UI;
// Turn clipping off
UI.updateSetting('clip', false);
display.set_viewport(false);
- $D('noVNC_canvas').style.position = 'static';
+ display.set_maxWidth(0);
+ display.set_maxHeight(0);
display.viewportChangeSize();
}
if (UI.getSetting('clip')) {
// If clipping, update clipping settings
- $D('noVNC_canvas').style.position = 'absolute';
- var pos = Util.getPosition($D('noVNC_canvas'));
- var new_w = window.innerWidth - pos.x;
- var new_h = window.innerHeight - pos.y;
display.set_viewport(true);
- display.viewportChangeSize(new_w, new_h);
+
+ var size = UI.getCanvasLimit();
+ if (size) {
+ display.set_maxWidth(size.w);
+ display.set_maxHeight(size.h);
+
+ // Hide potential scrollbars that can skew the position
+ $D('noVNC_container').style.overflow = "hidden";
+
+ // The x position marks the left margin of the canvas,
+ // remove the margin from both sides to keep it centered
+ var new_w = size.w - (2 * Util.getPosition($D('noVNC_canvas')).x);
+
+ $D('noVNC_container').style.overflow = "visible";
+
+ display.viewportChangeSize(new_w, size.h);
+ }
}
},
@@ -878,7 +904,7 @@ var UI;
var vmb = $D('noVNC_view_drag_button');
if (UI.rfb_state === 'normal' &&
UI.rfb.get_display().get_viewport() &&
- UI.rfb.get_display().fbuClip()) {
+ UI.rfb.get_display().clippingDisplay()) {
vmb.style.display = "inline";
} else {
vmb.style.display = "none";
@@ -1058,19 +1084,6 @@ var UI;
UI.keyboardVisible = false;
},
- // iOS < Version 5 does not support position fixed. Javascript workaround:
- setOnscroll: function() {
- window.onscroll = function() {
- UI.setBarPosition();
- };
- },
-
- setResize: function () {
- window.onResize = function() {
- UI.setBarPosition();
- };
- },
-
//Helper to add options to dropdown.
addOption: function(selectbox, text, value) {
var optn = document.createElement("OPTION");
diff --git a/tests/test.display.js b/tests/test.display.js
index f122dca..d54cb82 100644
--- a/tests/test.display.js
+++ b/tests/test.display.js
@@ -134,6 +134,40 @@ describe('Display/Canvas Helper', function () {
});
});
+ describe('clipping', function () {
+ var display;
+ beforeEach(function () {
+ display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
+ display.resize(4, 3);
+ });
+
+ it('should report true when no max-size and framebuffer > viewport', function () {
+ display.viewportChangeSize(2,2);
+ var clipping = display.clippingDisplay();
+ expect(clipping).to.be.true;
+ });
+
+ it('should report false when no max-size and framebuffer = viewport', function () {
+ var clipping = display.clippingDisplay();
+ expect(clipping).to.be.false;
+ });
+
+ it('should report true when viewport > max-size and framebuffer > viewport', function () {
+ display.viewportChangeSize(2,2);
+ display.set_maxWidth(1);
+ display.set_maxHeight(2);
+ var clipping = display.clippingDisplay();
+ expect(clipping).to.be.true;
+ });
+
+ it('should report true when viewport > max-size and framebuffer = viewport', function () {
+ display.set_maxWidth(1);
+ display.set_maxHeight(2);
+ var clipping = display.clippingDisplay();
+ expect(clipping).to.be.true;
+ });
+ });
+
describe('resizing', function () {
var display;
beforeEach(function () {
diff --git a/vnc.html b/vnc.html
index faa4e33..b8bda05 100644
--- a/vnc.html
+++ b/vnc.html
@@ -203,13 +203,11 @@
<div id="noVNC_screen">
- <div id="noVNC_screen_pad"></div>
-
<h1 id="noVNC_logo"><span>no</span><br />VNC</h1>
<!-- HTML5 Canvas -->
<div id="noVNC_container">
- <canvas id="noVNC_canvas" width="640px" height="20px">
+ <canvas id="noVNC_canvas" width="0" height="0">
Canvas not supported.
</canvas>
</div>