Commit a5df24b4 authored by Joel Martin's avatar Joel Martin

Viewport clip/drag for mobile/touchscreen devices.

API changes (forward compatible):

- Display: add 'viewport' conf option to turn on and off viewport
  mode.
- RFB: add 'viewportDrag' option to enable/disable viewport dragging
  mode.

Other:

- Add clip mode setting to default UI. For touch devices, clipping is
  forced on.
- Use CSS media queries to adjust visual elements based on screen
  size. Especially disconnected logo size/position and button text size.
- Catch page unload while connected and give a confirm dialog.
- Change mouse button selector to a single button that changes between
  ' ', 'L', 'M', 'R' when clicked (empty means mouse is just being
  moved and doesn't send clicks).
- include/ui.js:setViewClip() routine sets the clipping of the
  viewport to the current size of the viewport area (if clipping is
  enabled).
- include/ui.js:setViewDrag() toggles/enables/disables viewport
  dragging mode.
- Add several images for the UI and for Apple devices:
    - images/clipboard.png: clipboard menu icon
    - images/connect.png: connect menu icon
    - images/disconnect.png: disconnect button icon
    - images/keyboard.png: show keyboard button
    - images/move.png: viewport drag/move toggle button
    - images/settings.png: settings menu icon
    - images/screen_320x460.png: iOS app/desktop link start image
    - images/screen_57x57.png: iOS app icon
    - images/screen_700x700.png: full size noVNC image
parent e0b23efe
...@@ -65,21 +65,27 @@ html { ...@@ -65,21 +65,27 @@ html {
z-index:200; z-index:200;
} }
#noVNC_view_drag_button {
display: none;
}
#sendCtrlAltDelButton {
display: none;
}
#noVNC_mobile_buttons { #noVNC_mobile_buttons {
display: none; display: none;
} }
.noVNC-buttons-left { .noVNC-buttons-left {
position:fixed; float: left;
padding-left:10px; padding-left:10px;
padding-top:9px; padding-top:4px;
} }
.noVNC-buttons-right { .noVNC-buttons-right {
float:right; float:right;
right: 0px; right: 0px;
padding-right:10px; padding-right:10px;
padding-top:9px; padding-top:4px;
} }
#noVNC_status_bar { #noVNC_status_bar {
...@@ -93,10 +99,6 @@ html { ...@@ -93,10 +99,6 @@ html {
width:100%; width:100%;
} }
.noVNC_status_button, #clipboardbutton, #connectbutton {
font-size: 14px;
}
#noVNC_status { #noVNC_status {
height:20px; height:20px;
text-align: center; text-align: center;
...@@ -141,8 +143,14 @@ html { ...@@ -141,8 +143,14 @@ html {
border-bottom-right-radius: 800px 600px; border-bottom-right-radius: 800px 600px;
/*border-top-left-radius: 800px 600px;*/ /*border-top-left-radius: 800px 600px;*/
} }
#VNC_canvas {
background: #eee; #noVNC_container, #noVNC_canvas {
margin: 0px;
padding: 0px;
}
#noVNC_canvas {
left: 0px;
} }
#VNC_clipboard_clear_button { #VNC_clipboard_clear_button {
...@@ -152,10 +160,6 @@ html { ...@@ -152,10 +160,6 @@ html {
font-size: 11px; font-size: 11px;
} }
#noVNC_Settings {
width:200px;
}
#noVNC_clipboard_clear_button { #noVNC_clipboard_clear_button {
float:right; float:right;
} }
...@@ -211,32 +215,36 @@ html { ...@@ -211,32 +215,36 @@ html {
} }
/*Bubble contents divs*/ /*Bubble contents divs*/
#noVNC_Settings { #noVNC_settings {
display:none;
margin-top:72px; margin-top:72px;
right:10px;
position:fixed; position:fixed;
right:100px;
display:none;
} }
#noVNC_controls { #noVNC_controls {
margin-top:72px; margin-top:72px;
position:fixed;
right:10px; right:10px;
position:fixed;
}
#noVNC_controls.top:after {
right:15px;
} }
#noVNC_clipboard { #noVNC_clipboard {
display:none; display:none;
margin-top:72px; margin-top:72px;
right:20px;
position:fixed; position:fixed;
right:180px; }
#noVNC_clipboard.top:after {
right:85px;
} }
/*Default noVNC logo.*/ /*Default noVNC logo.*/
#noVNC_logo { #noVNC_logo {
width:400px; margin-top: 170px;
margin-left:auto; margin-left: 10px;
margin-right:auto;
font-size:160px;
color:yellow; color:yellow;
text-align:left; text-align:left;
font-family: 'Orbitron', sans-serif; font-family: 'Orbitron', sans-serif;
...@@ -249,17 +257,80 @@ html { ...@@ -249,17 +257,80 @@ html {
1px 1px 0 #000; 1px 1px 0 #000;
} }
#noVNC_logo span{ #noVNC_logo span{
color:green; color:green;
} }
#keyboardinput { #keyboardinput {
width:0px; width:1px;
height:0px; height:1px;
background-color:#313131; background-color:#6d84a2;
border:0; border:0;
} }
.noVNC_status_warn { .noVNC_status_warn {
background-color:yellow; background-color:yellow;
} }
/* ----------------------------------------
* Media sizing
* ----------------------------------------
*/
.noVNC_status_button {
font-size: 12px;
padding: 2px;
vertical-align: middle;
}
#noVNC_clipboard_text {
width: 500px;
border-color: red;
}
#noVNC_logo {
font-size: 180px;
}
@media screen and (min-width: 481px) and (max-width: 640px) {
.noVNC_status_button {
font-size: 10px;
padding: 1px;
}
#noVNC_clipboard_text {
width: 410px;
border-color: yellow;
}
#noVNC_logo {
font-size: 150px;
}
}
@media screen and (min-width: 321px) and (max-width: 480px) {
.noVNC_status_button {
font-size: 10px;
padding: 0px;
}
#noVNC_clipboard_text {
width: 250px;
border-color: green;
}
#noVNC_logo {
font-size: 110px;
}
}
@media screen and (max-width: 320px) {
.noVNC_status_button {
font-size: 9px;
padding: 0px;
}
#noVNC_clipboard_text {
width: 220px;
border-color: blue;
}
#noVNC_logo {
font-size: 90px;
}
}
...@@ -19,3 +19,8 @@ ...@@ -19,3 +19,8 @@
background:#000; background:#000;
color:#fff; color:#fff;
} }
#keyboardinput {
background-color:#000;
}
...@@ -20,3 +20,8 @@ ...@@ -20,3 +20,8 @@
background:#04073d; background:#04073d;
color:#fff; color:#fff;
} }
#keyboardinput {
background-color:#04073d;
}
...@@ -45,6 +45,7 @@ Util.conf_defaults(conf, that, defaults, [ ...@@ -45,6 +45,7 @@ Util.conf_defaults(conf, that, defaults, [
['true_color', 'rw', 'bool', true, 'Use true-color pixel data'], ['true_color', 'rw', 'bool', true, 'Use true-color pixel data'],
['colourMap', 'rw', 'arr', [], 'Colour map array (when not true-color)'], ['colourMap', 'rw', 'arr', [], 'Colour map array (when not true-color)'],
['scale', 'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'], ['scale', 'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'],
['viewport', 'rw', 'bool', false, 'Use a viewport set with viewportChange()'],
['width', 'rw', 'int', null, 'Display area width'], ['width', 'rw', 'int', null, 'Display area width'],
['height', 'rw', 'int', null, 'Display area height'], ['height', 'rw', 'int', null, 'Display area height'],
...@@ -245,6 +246,14 @@ that.viewportChange = function(deltaX, deltaY, width, height) { ...@@ -245,6 +246,14 @@ that.viewportChange = function(deltaX, deltaY, width, height) {
var c = conf.target, v = viewport, cr = cleanRect, var c = conf.target, v = viewport, cr = cleanRect,
saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h; saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h;
if (!conf.viewport) {
Util.Debug("Setting viewport to full display region");
deltaX = -v.w; // Clamped later if out of bounds
deltaY = -v.h; // Clamped later if out of bounds
width = fb_width;
height = fb_height;
}
if (typeof(deltaX) === "undefined") { deltaX = 0; } if (typeof(deltaX) === "undefined") { deltaX = 0; }
if (typeof(deltaY) === "undefined") { deltaY = 0; } if (typeof(deltaY) === "undefined") { deltaY = 0; }
if (typeof(width) === "undefined") { width = v.w; } if (typeof(width) === "undefined") { width = v.w; }
...@@ -269,7 +278,10 @@ that.viewportChange = function(deltaX, deltaY, width, height) { ...@@ -269,7 +278,10 @@ that.viewportChange = function(deltaX, deltaY, width, height) {
v.h = height; v.h = height;
if (v.w > 0 && v.h > 0) { if (v.w > 0 && v.h > 0 && c.width > 0 && c.height > 0) {
console.log("here1:",
((c.width < v.w) ? c.width : v.w),
((c.height < v.h) ? c.height : v.h));
saveImg = c_ctx.getImageData(0, 0, saveImg = c_ctx.getImageData(0, 0,
(c.width < v.w) ? c.width : v.w, (c.width < v.w) ? c.width : v.w,
(c.height < v.h) ? c.height : v.h); (c.height < v.h) ? c.height : v.h);
...@@ -406,6 +418,13 @@ that.getCleanDirtyReset = function() { ...@@ -406,6 +418,13 @@ that.getCleanDirtyReset = function() {
'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1}; 'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1};
return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes}; return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes};
};
that.absX = function(x) {
return x + viewport.x;
}
that.absY = function(y) {
return y + viewport.y;
} }
...@@ -454,11 +473,9 @@ that.clear = function() { ...@@ -454,11 +473,9 @@ that.clear = function() {
if (conf.logo) { if (conf.logo) {
that.resize(conf.logo.width, conf.logo.height); that.resize(conf.logo.width, conf.logo.height);
that.viewportChange(0, 0, conf.logo.width, conf.logo.height);
that.blitStringImage(conf.logo.data, 0, 0); that.blitStringImage(conf.logo.data, 0, 0);
} else { } else {
that.resize(640, 20); that.resize(640, 20);
that.viewportChange(0, 0, 640, 20);
c_ctx.clearRect(0, 0, viewport.w, viewport.h); c_ctx.clearRect(0, 0, viewport.w, viewport.h);
} }
...@@ -551,7 +568,15 @@ imageDataCreate = function(width, height) { ...@@ -551,7 +568,15 @@ imageDataCreate = function(width, height) {
}; };
rgbxImageData = function(x, y, width, height, arr, offset) { rgbxImageData = function(x, y, width, height, arr, offset) {
var img, i, j, data; var img, i, j, data, v = viewport;
/*
if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
(x - v.x + width < 0) || (y - v.y + height < 0)) {
//console.log("skipping, out of bounds: ", x, y);
// Skipping because outside of viewport
return;
}
*/
img = c_imageData(width, height); img = c_imageData(width, height);
data = img.data; data = img.data;
for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) { for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
...@@ -560,7 +585,7 @@ rgbxImageData = function(x, y, width, height, arr, offset) { ...@@ -560,7 +585,7 @@ rgbxImageData = function(x, y, width, height, arr, offset) {
data[i + 2] = arr[j + 2]; data[i + 2] = arr[j + 2];
data[i + 3] = 255; // Set Alpha data[i + 3] = 255; // Set Alpha
} }
c_ctx.putImageData(img, x - viewport.x, y - viewport.y); c_ctx.putImageData(img, x - v.x, y - v.y);
}; };
// really slow fallback if we don't have imageData // really slow fallback if we don't have imageData
......
...@@ -118,7 +118,9 @@ var that = {}, // Public API methods ...@@ -118,7 +118,9 @@ var that = {}, // Public API methods
/* Mouse state */ /* Mouse state */
mouse_buttonMask = 0, mouse_buttonMask = 0,
mouse_arr = []; mouse_arr = [],
viewportDragging = false,
viewportDragPos = {};
// Configuration attributes // Configuration attributes
Util.conf_defaults(conf, that, defaults, [ Util.conf_defaults(conf, that, defaults, [
...@@ -133,6 +135,8 @@ Util.conf_defaults(conf, that, defaults, [ ...@@ -133,6 +135,8 @@ Util.conf_defaults(conf, that, defaults, [
['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'], ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'],
['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'],
['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'],
['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'], ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'],
['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'], ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'],
...@@ -547,7 +551,7 @@ function flushClient() { ...@@ -547,7 +551,7 @@ function flushClient() {
// overridable for testing // overridable for testing
checkEvents = function() { checkEvents = function() {
var now; var now;
if (rfb_state === 'normal') { if (rfb_state === 'normal' && !viewportDragging) {
if (! flushClient()) { if (! flushClient()) {
now = new Date().getTime(); now = new Date().getTime();
if (now > last_req_time + conf.fbu_req_rate) { if (now > last_req_time + conf.fbu_req_rate) {
...@@ -572,13 +576,43 @@ mouseButton = function(x, y, down, bmask) { ...@@ -572,13 +576,43 @@ mouseButton = function(x, y, down, bmask) {
} else { } else {
mouse_buttonMask ^= bmask; mouse_buttonMask ^= bmask;
} }
mouse_arr = mouse_arr.concat( pointerEvent(x, y) );
if (conf.viewportDrag) {
if (down && !viewportDragging) {
viewportDragging = true;
viewportDragPos = {'x': x, 'y': y};
// Skip sending mouse events
return;
} else {
viewportDragging = false;
}
}
mouse_arr = mouse_arr.concat(
pointerEvent(display.absX(x), display.absY(y)) );
flushClient(); flushClient();
}; };
mouseMove = function(x, y) { mouseMove = function(x, y) {
//Util.Debug('>> mouseMove ' + x + "," + y); //Util.Debug('>> mouseMove ' + x + "," + y);
mouse_arr = mouse_arr.concat( pointerEvent(x, y) ); var deltaX, deltaY;
if (viewportDragging) {
//deltaX = x - viewportDragPos.x; // drag viewport
deltaX = viewportDragPos.x - x; // drag frame buffer
//deltaY = y - viewportDragPos.y; // drag viewport
deltaY = viewportDragPos.y - y; // drag frame buffer
viewportDragPos = {'x': x, 'y': y};
display.viewportChange(deltaX, deltaY);
// Skip sending mouse events
return;
}
mouse_arr = mouse_arr.concat(
pointerEvent(display.absX(x), display.absY(y)) );
}; };
...@@ -778,7 +812,6 @@ init_msg = function() { ...@@ -778,7 +812,6 @@ init_msg = function() {
display.set_true_color(conf.true_color); display.set_true_color(conf.true_color);
display.resize(fb_width, fb_height); display.resize(fb_width, fb_height);
display.viewportChange(0, 0, fb_width, fb_height);
keyboard.grab(); keyboard.grab();
mouse.grab(); mouse.grab();
...@@ -1309,7 +1342,6 @@ encHandlers.DesktopSize = function set_desktopsize() { ...@@ -1309,7 +1342,6 @@ encHandlers.DesktopSize = function set_desktopsize() {
fb_width = FBU.width; fb_width = FBU.width;
fb_height = FBU.height; fb_height = FBU.height;
display.resize(fb_width, fb_height); display.resize(fb_width, fb_height);
display.viewportChange(0, 0, fb_width, fb_height);
timing.fbu_rt_start = (new Date()).getTime(); timing.fbu_rt_start = (new Date()).getTime();
// Send a new non-incremental request // Send a new non-incremental request
ws.send(fbUpdateRequests()); ws.send(fbUpdateRequests());
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
var UI = { var UI = {
rfb_state : 'loaded',
settingsOpen : false, settingsOpen : false,
connSettingsOpen : true, connSettingsOpen : true,
clipboardOpen: false, clipboardOpen: false,
...@@ -36,8 +37,8 @@ load: function() { ...@@ -36,8 +37,8 @@ load: function() {
// Settings with immediate effects // Settings with immediate effects
UI.initSetting('logging', 'warn'); UI.initSetting('logging', 'warn');
WebUtil.init_logging(UI.getSetting('logging')); WebUtil.init_logging(UI.getSetting('logging'));
UI.initSetting('stylesheet', 'default');
UI.initSetting('stylesheet', 'default');
WebUtil.selectStylesheet(null); WebUtil.selectStylesheet(null);
// call twice to get around webkit bug // call twice to get around webkit bug
WebUtil.selectStylesheet(UI.getSetting('stylesheet')); WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
...@@ -55,6 +56,7 @@ load: function() { ...@@ -55,6 +56,7 @@ load: function() {
UI.rfb = RFB({'target': $D('noVNC_canvas'), UI.rfb = RFB({'target': $D('noVNC_canvas'),
'onUpdateState': UI.updateState, 'onUpdateState': UI.updateState,
'onClipboard': UI.clipReceive}); 'onClipboard': UI.clipReceive});
UI.updateSettingsState(false);
// Unfocus clipboard when over the VNC area // Unfocus clipboard when over the VNC area
//$D('VNC_screen').onmousemove = function () { //$D('VNC_screen').onmousemove = function () {
...@@ -66,9 +68,15 @@ load: function() { ...@@ -66,9 +68,15 @@ load: function() {
// Show mouse selector buttons on touch screen devices // Show mouse selector buttons on touch screen devices
if ('ontouchstart' in document.documentElement) { if ('ontouchstart' in document.documentElement) {
// Show mobile buttons
$D('noVNC_mobile_buttons').style.display = "inline"; $D('noVNC_mobile_buttons').style.display = "inline";
UI.setMouseButton(); UI.setMouseButton();
window.scrollTo(0, 1); // Remove the address bar
setTimeout(function() { window.scrollTo(0, 1); }, 100);
UI.initSetting('clip', true);
$D('noVNC_clip').disabled = true;
} else {
UI.initSetting('clip', false);
} }
//iOS Safari does not support CSS position:fixed. //iOS Safari does not support CSS position:fixed.
...@@ -76,11 +84,21 @@ load: function() { ...@@ -76,11 +84,21 @@ load: function() {
if ((navigator.userAgent.match(/iPhone/i)) || if ((navigator.userAgent.match(/iPhone/i)) ||
(navigator.userAgent.match(/iPod/i)) || (navigator.userAgent.match(/iPod/i)) ||
(navigator.userAgent.match(/iPad/i))) { (navigator.userAgent.match(/iPad/i))) {
UI.setOnscroll(); //UI.setOnscroll();
UI.setResize(); //UI.setResize();
} }
$D('noVNC_host').focus(); $D('noVNC_host').focus();
UI.setViewClip();
Util.addEvent(window, 'resize', UI.setViewClip);
Util.addEvent(window, 'beforeunload', function () {
if (UI.rfb_state === 'normal') {
return "You are currently connected.";
}
} );
}, },
// Read form control compatible setting from cookie // Read form control compatible setting from cookie
...@@ -166,7 +184,6 @@ initSetting: function(name, defVal) { ...@@ -166,7 +184,6 @@ initSetting: function(name, defVal) {
clickSettingsMenu: function() { clickSettingsMenu: function() {
if (UI.settingsOpen) { if (UI.settingsOpen) {
UI.settingsApply(); UI.settingsApply();
UI.closeSettingsMenu(); UI.closeSettingsMenu();
} else { } else {
UI.updateSetting('encrypt'); UI.updateSetting('encrypt');
...@@ -177,6 +194,7 @@ clickSettingsMenu: function() { ...@@ -177,6 +194,7 @@ clickSettingsMenu: function() {
UI.updateSetting('cursor', false); UI.updateSetting('cursor', false);
$D('noVNC_cursor').disabled = true; $D('noVNC_cursor').disabled = true;
} }
UI.updateSetting('clip');
UI.updateSetting('shared'); UI.updateSetting('shared');
UI.updateSetting('connectTimeout'); UI.updateSetting('connectTimeout');
UI.updateSetting('stylesheet'); UI.updateSetting('stylesheet');
...@@ -195,32 +213,16 @@ openSettingsMenu: function() { ...@@ -195,32 +213,16 @@ openSettingsMenu: function() {
if (UI.connSettingsOpen == true) { if (UI.connSettingsOpen == true) {
UI.connectPanelbutton(); UI.connectPanelbutton();
} }
$D('noVNC_Settings').style.display = "block"; $D('noVNC_settings').style.display = "block";
UI.settingsOpen = true; UI.settingsOpen = true;
}, },
// Close menu (without applying settings) // Close menu (without applying settings)
closeSettingsMenu: function() { closeSettingsMenu: function() {
$D('noVNC_Settings').style.display = "none"; $D('noVNC_settings').style.display = "none";
UI.settingsOpen = false; UI.settingsOpen = false;
}, },
// Disable/enable controls depending on connection state
settingsDisabled: function(disabled, rfb) {
//Util.Debug(">> settingsDisabled");
$D('noVNC_encrypt').disabled = disabled;
$D('noVNC_true_color').disabled = disabled;
if (rfb && rfb.get_display() && rfb.get_display().get_cursor_uri()) {
$D('noVNC_cursor').disabled = disabled;
} else {
UI.updateSetting('cursor', false);
$D('noVNC_cursor').disabled = true;
}
$D('noVNC_shared').disabled = disabled;
$D('noVNC_connectTimeout').disabled = disabled;
//Util.Debug("<< settingsDisabled");
},
// Save/apply settings when 'Apply' button is pressed // Save/apply settings when 'Apply' button is pressed
settingsApply: function() { settingsApply: function() {
//Util.Debug(">> settingsApply"); //Util.Debug(">> settingsApply");
...@@ -229,6 +231,7 @@ settingsApply: function() { ...@@ -229,6 +231,7 @@ settingsApply: function() {
if (UI.rfb.get_display().get_cursor_uri()) { if (UI.rfb.get_display().get_cursor_uri()) {
UI.saveSetting('cursor'); UI.saveSetting('cursor');
} }
UI.saveSetting('clip');
UI.saveSetting('shared'); UI.saveSetting('shared');
UI.saveSetting('connectTimeout'); UI.saveSetting('connectTimeout');
UI.saveSetting('stylesheet'); UI.saveSetting('stylesheet');
...@@ -237,6 +240,7 @@ settingsApply: function() { ...@@ -237,6 +240,7 @@ settingsApply: function() {
// Settings with immediate (non-connected related) effect // Settings with immediate (non-connected related) effect
WebUtil.selectStylesheet(UI.getSetting('stylesheet')); WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
WebUtil.init_logging(UI.getSetting('logging')); WebUtil.init_logging(UI.getSetting('logging'));
UI.setViewClip();
//Util.Debug("<< settingsApply"); //Util.Debug("<< settingsApply");
}, },
...@@ -257,65 +261,60 @@ sendCtrlAltDel: function() { ...@@ -257,65 +261,60 @@ sendCtrlAltDel: function() {
}, },
setMouseButton: function(num) { setMouseButton: function(num) {
var b, blist = [1,2,4], button, var b, blist = [0, 1,2,4], button;
mouse = UI.rfb.get_mouse();
if (typeof num === 'undefined') { if (typeof num === 'undefined') {
// Show the default // Disable mouse buttons
num = mouse.get_touchButton(); num = -1;
} else if (num === mouse.get_touchButton()) { }
// Set all buttons off (no clicks) if (UI.rfb) {
mouse.set_touchButton(0); UI.rfb.get_mouse().set_touchButton(num);
num = 0;
} else {
// Turn on one button
mouse.set_touchButton(num);
} }
for (b = 0; b < blist.length; b++) { for (b = 0; b < blist.length; b++) {
button = $D('noVNC_mouse_button' + blist[b]); button = $D('noVNC_mouse_button' + blist[b]);
if (blist[b] === num) { if (blist[b] === num) {
button.style.display = "";
} else {
button.style.display = "none";
/*
button.style.backgroundColor = "black"; button.style.backgroundColor = "black";
button.style.color = "lightgray"; button.style.color = "lightgray";
} else {
button.style.backgroundColor = ""; button.style.backgroundColor = "";
button.style.color = ""; button.style.color = "";
*/
} }
} }
}, },
updateState: function(rfb, state, oldstate, msg) { updateState: function(rfb, state, oldstate, msg) {
var s, sb, c, cad, klass; var s, sb, c, d, cad, vd, klass;
UI.rfb_state = state;
s = $D('noVNC_status'); s = $D('noVNC_status');
sb = $D('noVNC_status_bar'); sb = $D('noVNC_status_bar');
c = $D('connectPanelbutton'); c = $D('connectPanelbutton');
cad = $D('sendCtrlAltDelButton'); d = $D('disconnectButton');
switch (state) { switch (state) {
case 'failed': case 'failed':
case 'fatal': case 'fatal':
c.disabled = true; c.style.display = "";
cad.style.display = "none"; d.style.display = "none";
UI.settingsDisabled(true, rfb); UI.updateSettingsState(false);
klass = "noVNC_status_error"; klass = "noVNC_status_error";
break; break;
case 'normal': case 'normal':
c.value = "Disconnect"; c.style.display = "none";
c.onclick = UI.disconnect; d.style.display = "";
c.disabled = false; UI.updateSettingsState(true);
cad.style.display = "";
UI.settingsDisabled(true, rfb);
klass = "noVNC_status_normal"; klass = "noVNC_status_normal";
break; break;
case 'disconnected': case 'disconnected':
$D('noVNC_logo').style.display = "block"; $D('noVNC_logo').style.display = "block";
c.value = "Connection";
c.onclick = UI.connectPanelbutton;
case 'loaded': case 'loaded':
c.value = "Connection"; //c.value = "Connection";
c.onclick = UI.connectPanelbutton; c.style.display = "";
c.disabled = false; d.style.display = "none";
cad.style.display = "none"; UI.updateSettingsState(false);
UI.settingsDisabled(false, rfb);
klass = "noVNC_status_normal"; klass = "noVNC_status_normal";
break; break;
case 'password': case 'password':
...@@ -325,15 +324,15 @@ updateState: function(rfb, state, oldstate, msg) { ...@@ -325,15 +324,15 @@ updateState: function(rfb, state, oldstate, msg) {
$D('noVNC_connect_button').onclick = UI.setPassword; $D('noVNC_connect_button').onclick = UI.setPassword;
$D('noVNC_password').focus(); $D('noVNC_password').focus();
c.disabled = false; c.style.display = "none";
cad.style.display = "none"; d.style.display = "";
UI.settingsDisabled(true, rfb); UI.updateSettingsState(false);
klass = "noVNC_status_warn"; klass = "noVNC_status_warn";
break; break;
default: default:
c.disabled = true; c.style.display = "none";
cad.style.display = "none"; d.style.display = "";
UI.settingsDisabled(true, rfb); UI.updateSettingsState(false);
klass = "noVNC_status_warn"; klass = "noVNC_status_warn";
break; break;
} }
...@@ -346,6 +345,40 @@ updateState: function(rfb, state, oldstate, msg) { ...@@ -346,6 +345,40 @@ updateState: function(rfb, state, oldstate, msg) {
}, },
// Disable/enable controls depending on connection state
updateSettingsState: function(connected) {
//Util.Debug(">> updateSettingsState");
$D('noVNC_encrypt').disabled = connected;
$D('noVNC_true_color').disabled = connected;
if (UI.rfb && UI.rfb.get_display() &&
UI.rfb.get_display().get_cursor_uri()) {
$D('noVNC_cursor').disabled = connected;
} else {
UI.updateSetting('cursor', false);
$D('noVNC_cursor').disabled = true;
}
$D('noVNC_shared').disabled = connected;
$D('noVNC_connectTimeout').disabled = connected;
if (connected) {
UI.setViewClip();
UI.setMouseButton(1);
$D('sendCtrlAltDelButton').style.display = "inline";
$D('noVNC_view_drag_button').style.display = "inline";
} else {
UI.setMouseButton();
$D('sendCtrlAltDelButton').style.display = "none";
$D('noVNC_view_drag_button').style.display = "none";
}
// State change disables viewport dragging.
// It is enabled (toggled) by direct click on the button
UI.setViewDrag(false);
//Util.Debug("<< updateSettingsState");
},
clipReceive: function(rfb, text) { clipReceive: function(rfb, text) {
Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "..."); Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "...");
$D('noVNC_clipboard_text').value = text; $D('noVNC_clipboard_text').value = text;
...@@ -412,6 +445,7 @@ clipSend: function() { ...@@ -412,6 +445,7 @@ clipSend: function() {
showClipboard: function() { showClipboard: function() {
//Close settings if open //Close settings if open
if (UI.settingsOpen == true) { if (UI.settingsOpen == true) {
UI.settingsApply();
UI.closeSettingsMenu(); UI.closeSettingsMenu();
} }
//Close connection settings if open //Close connection settings if open
...@@ -428,32 +462,67 @@ showClipboard: function() { ...@@ -428,32 +462,67 @@ showClipboard: function() {
} }
}, },
setViewClip: function(clip) {
var display, cur_clip, pos, new_w, new_h;
showKeyboard: function() { if (UI.rfb) {
//Get Current Scroll Position display = UI.rfb.get_display();
var scrollx = } else {
(document.all)?document.body.scrollLeft:window.pageXOffset; return;
var scrolly = }
(document.all)?document.body.scrollTop:window.pageYOffset;
cur_clip = display.get_viewport();
//Stop browser zooming on textbox.
UI.zoomDisable(); if (typeof(clip) === 'undefined') {
$D('keyboardinput').focus(); // Nothing
scroll(scrollx,scrolly); clip = UI.getSetting('clip');
//Renable user zoom. }
UI.zoomEnable();
if (clip && !cur_clip) {
// Turn clipping on
UI.updateSetting('clip', true);
} else if (!clip && cur_clip) {
// Turn clipping off
UI.updateSetting('clip', false);
display.set_viewport(false);
$D('noVNC_canvas').style.position = 'static';
display.viewportChange();
}
if (UI.getSetting('clip')) {
// If clipping, update clipping settings
$D('noVNC_canvas').style.position = 'absolute';
pos = Util.getPosition($D('noVNC_canvas'));
new_w = window.innerWidth - pos.x;
new_h = window.innerHeight - pos.y;
display.set_viewport(true);
display.viewportChange(0, 0, new_w, new_h);
}
}, },
zoomDisable: function() { setViewDrag: function(drag) {
//Change viewport meta data to disable zooming. var vmb = $D('noVNC_view_drag_button');
UI.changeViewportMeta("user-scalable=0"); if (!UI.rfb) { return; }
if (typeof(drag) === "undefined") {
// If not specified, then toggle
drag = !UI.rfb.get_viewportDrag();
}
if (drag) {
vmb.style.backgroundColor = "black";
vmb.style.color = "lightgray";
UI.rfb.set_viewportDrag(true);
} else {
vmb.style.backgroundColor = "";
vmb.style.color = "";
UI.rfb.set_viewportDrag(false);
}
}, },
zoomEnable: function(){ showKeyboard: function() {
//Change viewport meta data to enable user zooming. $D('keyboardinput').focus();
UI.changeViewportMeta("user-scalable=1");
}, },
changeViewportMeta: function (newattributes) { changeViewportMeta: function (newattributes) {
// First, get the array of meta-tag elements // First, get the array of meta-tag elements
...@@ -505,6 +574,7 @@ setBarPosition: function() { ...@@ -505,6 +574,7 @@ setBarPosition: function() {
connectPanelbutton: function() { connectPanelbutton: function() {
//Close connection settings if open //Close connection settings if open
if (UI.settingsOpen == true) { if (UI.settingsOpen == true) {
UI.settingsApply();
UI.closeSettingsMenu(); UI.closeSettingsMenu();
} }
if (UI.clipboardOpen == true) { if (UI.clipboardOpen == true) {
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head><title>Viewport Test</title> <head><title>Viewport Test</title>
<link rel="stylesheet" href="../include/mobile.css"> <link rel="stylesheet" href="viewport.css">
<!-- <!--
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
...@@ -166,23 +166,35 @@ ...@@ -166,23 +166,35 @@
"," + (p.offsetHeight - padH) + "]"); "," + (p.offsetHeight - padH) + "]");
display.viewportChange(0, 0, display.viewportChange(0, 0,
p.offsetWidth - padW, p.offsetHeight - padH); p.offsetWidth - padW, p.offsetHeight - padH);
/*
var pos, new_w, new_h;pos
pos = Util.getPosition($D('canvas').parentNode);
new_w = window.innerWidth - pos.x;
new_h = window.innerHeight - pos.y;
display.viewportChange(0, 0, new_w, new_h);
*/
} }
window.onload = function() { window.onload = function() {
detectPad(); detectPad();
display = new Display({'target': $D('canvas')}); display = new Display({'target': $D('canvas')});
display.resize(1600, 1024); display.resize(1600, 1024);
//display.resize(800, 600); display.set_viewport(true);
ctx = display.get_context(); ctx = display.get_context();
mouse = new Mouse({'target': $D('canvas'), mouse = new Mouse({'target': $D('canvas'),
'onMouseButton': mouseButton, 'onMouseButton': mouseButton,
'onMouseMove': mouseMove}); 'onMouseMove': mouseMove});
mouse.grab();
Util.addEvent(window, 'resize', doResize); Util.addEvent(window, 'resize', doResize);
//doResize(); // Shrink viewport for first resize call so that the
// scrollbars are disabled
display.viewportChange(0, 0, 10, 10);
setTimeout(doResize, 1); setTimeout(doResize, 1);
setInterval(dirtyRedraw, 50); setInterval(dirtyRedraw, 50);
mouse.grab();
message("Display initialized"); message("Display initialized");
}; };
......
...@@ -15,12 +15,19 @@ ...@@ -15,12 +15,19 @@
Remove this if you use the .htaccess --> Remove this if you use the .htaccess -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="user-scalable=1" /> <!-- Apple iOS Safari settings -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta names="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<!-- App Start Icon -->
<link rel="apple-touch-startup-image" href="images/screen_320x460.png" />
<!-- For iOS devices set the icon to use if user bookmarks app on their homescreen -->
<link rel="apple-touch-icon" href="images/screen_57x57.png">
<!-- <!--
<meta name="viewport" content="width=device-width,height=device-height" /> <link rel="apple-touch-icon-precomposed" href="images/screen_57x57.png" />
--> -->
<!-- Stylesheets --> <!-- Stylesheets -->
<link rel="stylesheet" href="include/base.css" /> <link rel="stylesheet" href="include/base.css" />
<link rel="alternate stylesheet" href="include/black.css" TITLE="Black" /> <link rel="alternate stylesheet" href="include/black.css" TITLE="Black" />
...@@ -28,13 +35,6 @@ ...@@ -28,13 +35,6 @@
<!-- Google web fonts --> <!-- Google web fonts -->
<link href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz|Nova+Square|Orbitron:400,500,700,900|Nova+Round|Nova+Mono|Nova+Slim|Nova+Oval|Nova+Flat|Nova+Cut' rel='stylesheet' type='text/css'> <link href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz|Nova+Square|Orbitron:400,500,700,900|Nova+Round|Nova+Mono|Nova+Slim|Nova+Oval|Nova+Flat|Nova+Cut' rel='stylesheet' type='text/css'>
<!-- App Start Icon -->
<link rel="apple-touch-startup-image" href="images/screen_640x435.png" />
<!-- For iOS devices set the icon to use if user bookmarks app on their homescreen -->
<link rel="apple-touch-icon" href="images/mobileicon.png">
<link rel="apple-touch-icon-precomposed" href="images/mobileicon.png" />
<!-- <!--
<script type='text/javascript' <script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
...@@ -48,43 +48,60 @@ ...@@ -48,43 +48,60 @@
<body> <body>
<div id="noVNC-control-bar"> <div id="noVNC-control-bar">
<!--noVNC Mobile Device only Buttons--> <!--noVNC Mobile Device only Buttons-->
<div id="noVNC_mobile_buttons" class="noVNC-buttons-left"> <div class="noVNC-buttons-left">
<nobr> <input type="image" src="images/move.png"
<span class="noVNC_mouse_buttons"> id="noVNC_view_drag_button" class="noVNC_status_button"
value="Move" title="Move/Drag Viewport"
onclick="UI.setViewDrag();">
<div id="noVNC_mobile_buttons">
<input type="button" class="noVNC_status_button" <input type="button" class="noVNC_status_button"
id="noVNC_mouse_button1" value="L" id="noVNC_mouse_button0" value=" "
onclick="UI.setMouseButton(1);"> onclick="UI.setMouseButton(1);">
<input type="button" class="noVNC_status_button" <input type="button" class="noVNC_status_button"
id="noVNC_mouse_button2" value="M" id="noVNC_mouse_button1" value="L"
onclick="UI.setMouseButton(2);"> onclick="UI.setMouseButton(2);">
<input type="button" class="noVNC_status_button" <input type="button" class="noVNC_status_button"
id="noVNC_mouse_button4" value="R" id="noVNC_mouse_button2" value="M"
onclick="UI.setMouseButton(4);"> onclick="UI.setMouseButton(4);">
<input type="button" id="showKeyboard" <input type="button" class="noVNC_status_button"
value="Keyboard" class="noVNC_status_button" id="noVNC_mouse_button4" value="R"
onclick="UI.setMouseButton(0);">
<input type="image" src="images/keyboard.png"
id="showKeyboard" class="noVNC_status_button"
value="Keyboard" title="Show Keyboard"
onclick="UI.showKeyboard()"/> onclick="UI.showKeyboard()"/>
</span> <input type="text"
</nobr> id="keyboardinput" class="noVNC_status_button"
onKeyDown="onKeyDown(event);"/>
</div>
</div> </div>
<!--noVNC Buttons--> <!--noVNC Buttons-->
<div class="noVNC-buttons-right"> <div class="noVNC-buttons-right">
<input type="button" class="noVNC_status_button" <input type="button" class="noVNC_status_button"
value="CtrlAltDel" id="sendCtrlAltDelButton" value="CtrlAltDel" id="sendCtrlAltDelButton"
onclick="UI.sendCtrlAltDel();"> onclick="UI.sendCtrlAltDel();" />
<input type="button" id="clipboardbutton" value="Clipboard" <input type="image" src="images/clipboard.png"
onclick="UI.showClipboard();"/> id="clipboardButton" class="noVNC_status_button"
<input type="button" class="noVNC_status_button" value="Clipboard" title="Clipboard"
value="Settings" id="menuButton" onclick="UI.showClipboard();" />
onclick="UI.clickSettingsMenu();"> <input type="image" src="images/settings.png"
<input type="button" id="connectPanelbutton" id="menuButton" class="noVNC_status_button"
value="Connection" class="noVNC_status_button" value="Settings" title="Settings"
onclick="UI.clickSettingsMenu();" />
<input type="image" src="images/connect.png"
id="connectPanelbutton" class="noVNC_status_button"
value="Connect" title="Connect"
onclick="UI.connectPanelbutton()" /> onclick="UI.connectPanelbutton()" />
<input type="image" src="images/disconnect.png"
id="disconnectButton" class="noVNC_status_button"
value="Disconnect" title="Disconnect"
onclick="UI.disconnect()" />
</div> </div>
<!-- Clipboard Panel --> <!-- Clipboard Panel -->
<div id="noVNC_clipboard" class="triangle-right top"> <div id="noVNC_clipboard" class="triangle-right top">
<textarea id="noVNC_clipboard_text" cols=88 rows=5 <textarea id="noVNC_clipboard_text" rows=5
onfocus="UI.displayBlur();" onblur="UI.displayFocus();" onfocus="UI.displayBlur();" onblur="UI.displayFocus();"
onchange="UI.clipSend();"> onchange="UI.clipSend();">
</textarea> </textarea>
...@@ -94,13 +111,14 @@ ...@@ -94,13 +111,14 @@
</div> </div>
<!-- Settings Panel --> <!-- Settings Panel -->
<div id="noVNC_Settings" class="triangle-right top"> <div id="noVNC_settings" class="triangle-right top">
<span id="noVNC_settings_menu" onmouseover="UI.displayBlur();" <span id="noVNC_settings_menu" onmouseover="UI.displayBlur();"
onmouseout="UI.displayFocus();"> onmouseout="UI.displayFocus();">
<ul> <ul>
<li><input id="noVNC_encrypt" type="checkbox"> Encrypt</li> <li><input id="noVNC_encrypt" type="checkbox"> Encrypt</li>
<li><input id="noVNC_true_color" type="checkbox" checked> True Color</li> <li><input id="noVNC_true_color" type="checkbox" checked> True Color</li>
<li><input id="noVNC_cursor" type="checkbox"> Local Cursor</li> <li><input id="noVNC_cursor" type="checkbox"> Local Cursor</li>
<li><input id="noVNC_clip" type="checkbox"> Clip to window</li>
<li><input id="noVNC_shared" type="checkbox"> Shared Mode</li> <li><input id="noVNC_shared" type="checkbox"> Shared Mode</li>
<li><input id="noVNC_connectTimeout" type="input"> Connect Timeout (s)</li> <li><input id="noVNC_connectTimeout" type="input"> Connect Timeout (s)</li>
<hr> <hr>
...@@ -143,13 +161,15 @@ ...@@ -143,13 +161,15 @@
<div id="noVNC_status">Loading</div> <div id="noVNC_status">Loading</div>
</div> </div>
<!-- HTML5 Canvas -->
<h1 id="noVNC_logo"><span>no</span><br />VNC</h1> <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="640px" height="20px">
Canvas not supported. Canvas not supported.
</canvas> </canvas>
</div>
<input id="keyboardinput" type="text" onKeyDown="onKeyDown(event);"/>
</div> </div>
<script> <script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment