You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2020/09/22 12:12:48 UTC
[cloudstack] branch master updated: systemvm: update novnc v1.2.0
(#4323)
This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/master by this push:
new c06e7de systemvm: update novnc v1.2.0 (#4323)
c06e7de is described below
commit c06e7ded3c52b18eb92ec0dd53f0884db0b91004
Author: davidjumani <dj...@gmail.com>
AuthorDate: Tue Sep 22 17:42:30 2020 +0530
systemvm: update novnc v1.2.0 (#4323)
Update noVNC v1.2.0, add support for clipboard, explicit button toolbar and resize screensize
---
.../com/cloud/servlet/ConsoleProxyServlet.java | 2 +-
systemvm/agent/noVNC/.eslintignore | 1 -
systemvm/agent/noVNC/.eslintrc | 48 -
.../noVNC/.github/ISSUE_TEMPLATE/bug_report.md | 34 -
.../.github/ISSUE_TEMPLATE/feature_request.md | 17 -
systemvm/agent/noVNC/.gitignore | 12 -
systemvm/agent/noVNC/.gitmodules | 0
systemvm/agent/noVNC/.travis.yml | 58 -
systemvm/agent/noVNC/AUTHORS | 13 -
systemvm/agent/noVNC/LICENSE.txt | 68 -
systemvm/agent/noVNC/README.md | 152 --
systemvm/agent/noVNC/VERSION | 1 -
systemvm/agent/noVNC/app/error-handler.js | 8 +
systemvm/agent/noVNC/app/images/alt.png | Bin 0 -> 335 bytes
systemvm/agent/noVNC/app/images/alt.svg | 92 -
systemvm/agent/noVNC/app/images/clipboard.png | Bin 0 -> 220 bytes
systemvm/agent/noVNC/app/images/clipboard.svg | 106 -
systemvm/agent/noVNC/app/images/connect.png | Bin 0 -> 424 bytes
systemvm/agent/noVNC/app/images/connect.svg | 96 -
systemvm/agent/noVNC/app/images/ctrl.png | Bin 0 -> 399 bytes
systemvm/agent/noVNC/app/images/ctrl.svg | 96 -
systemvm/agent/noVNC/app/images/ctrlaltdel.png | Bin 0 -> 191 bytes
systemvm/agent/noVNC/app/images/ctrlaltdel.svg | 100 -
systemvm/agent/noVNC/app/images/disconnect.png | Bin 0 -> 442 bytes
systemvm/agent/noVNC/app/images/disconnect.svg | 94 -
systemvm/agent/noVNC/app/images/drag.png | Bin 0 -> 336 bytes
systemvm/agent/noVNC/app/images/drag.svg | 76 -
systemvm/agent/noVNC/app/images/error.png | Bin 0 -> 348 bytes
systemvm/agent/noVNC/app/images/error.svg | 81 -
systemvm/agent/noVNC/app/images/esc.png | Bin 0 -> 365 bytes
systemvm/agent/noVNC/app/images/esc.svg | 92 -
systemvm/agent/noVNC/app/images/expander.png | Bin 0 -> 167 bytes
systemvm/agent/noVNC/app/images/expander.svg | 69 -
systemvm/agent/noVNC/app/images/fullscreen.png | Bin 0 -> 280 bytes
systemvm/agent/noVNC/app/images/fullscreen.svg | 93 -
systemvm/agent/noVNC/app/images/handle.png | Bin 0 -> 126 bytes
systemvm/agent/noVNC/app/images/handle.svg | 82 -
systemvm/agent/noVNC/app/images/handle_bg.png | Bin 0 -> 123 bytes
systemvm/agent/noVNC/app/images/handle_bg.svg | 172 --
systemvm/agent/noVNC/app/images/info.png | Bin 0 -> 448 bytes
systemvm/agent/noVNC/app/images/info.svg | 81 -
systemvm/agent/noVNC/app/images/keyboard.png | Bin 0 -> 308 bytes
systemvm/agent/noVNC/app/images/keyboard.svg | 88 -
systemvm/agent/noVNC/app/images/mouse_left.svg | 92 -
systemvm/agent/noVNC/app/images/mouse_middle.svg | 92 -
systemvm/agent/noVNC/app/images/mouse_none.svg | 92 -
systemvm/agent/noVNC/app/images/mouse_right.svg | 92 -
systemvm/agent/noVNC/app/images/power.png | Bin 0 -> 421 bytes
systemvm/agent/noVNC/app/images/power.svg | 87 -
systemvm/agent/noVNC/app/images/settings.png | Bin 0 -> 379 bytes
systemvm/agent/noVNC/app/images/settings.svg | 76 -
systemvm/agent/noVNC/app/images/tab.png | Bin 0 -> 190 bytes
systemvm/agent/noVNC/app/images/tab.svg | 86 -
.../agent/noVNC/app/images/toggleextrakeys.png | Bin 0 -> 353 bytes
.../agent/noVNC/app/images/toggleextrakeys.svg | 90 -
systemvm/agent/noVNC/app/images/warning.png | Bin 0 -> 319 bytes
systemvm/agent/noVNC/app/images/warning.svg | 81 -
systemvm/agent/noVNC/app/images/windows.png | Bin 0 -> 219 bytes
systemvm/agent/noVNC/app/images/windows.svg | 85 -
systemvm/agent/noVNC/app/locale/README | 1 +
systemvm/agent/noVNC/app/locale/ja.json | 73 +
systemvm/agent/noVNC/app/locale/sv.json | 15 +-
systemvm/agent/noVNC/app/locale/zh_CN.json | 34 +-
systemvm/agent/noVNC/app/styles/base.css | 104 +-
systemvm/agent/noVNC/app/ui.js | 349 +--
systemvm/agent/noVNC/app/webutil.js | 43 +-
systemvm/agent/noVNC/core/base64.js | 8 +-
systemvm/agent/noVNC/core/decoders/copyrect.js | 9 +-
systemvm/agent/noVNC/core/decoders/hextile.js | 82 +-
systemvm/agent/noVNC/core/decoders/raw.js | 30 +-
systemvm/agent/noVNC/core/decoders/rre.js | 4 +-
systemvm/agent/noVNC/core/decoders/tight.js | 52 +-
systemvm/agent/noVNC/core/decoders/tightpng.js | 6 +-
systemvm/agent/noVNC/core/deflator.js | 85 +
systemvm/agent/noVNC/core/display.js | 296 +--
systemvm/agent/noVNC/core/encodings.js | 5 +-
systemvm/agent/noVNC/core/inflator.js | 42 +-
systemvm/agent/noVNC/core/input/domkeytable.js | 14 +-
systemvm/agent/noVNC/core/input/gesturehandler.js | 567 +++++
systemvm/agent/noVNC/core/input/keyboard.js | 40 +-
systemvm/agent/noVNC/core/input/mouse.js | 276 ---
systemvm/agent/noVNC/core/input/uskeysym.js | 57 +
systemvm/agent/noVNC/core/input/util.js | 50 +-
systemvm/agent/noVNC/core/rfb.js | 1535 ++++++++++---
systemvm/agent/noVNC/core/util/browser.js | 42 +-
systemvm/agent/noVNC/core/util/cursor.js | 100 +-
systemvm/agent/noVNC/core/util/element.js | 32 +
systemvm/agent/noVNC/core/util/events.js | 91 +-
systemvm/agent/noVNC/core/util/eventtarget.js | 2 +-
systemvm/agent/noVNC/core/util/int.js | 15 +
systemvm/agent/noVNC/core/util/logging.js | 16 +-
systemvm/agent/noVNC/core/util/polyfill.js | 9 +-
systemvm/agent/noVNC/core/util/strings.js | 26 +-
systemvm/agent/noVNC/core/websock.js | 66 +-
systemvm/agent/noVNC/docs/API-internal.md | 122 -
systemvm/agent/noVNC/docs/API.md | 375 ---
systemvm/agent/noVNC/docs/EMBEDDING.md | 119 -
systemvm/agent/noVNC/docs/LIBRARY.md | 35 -
systemvm/agent/noVNC/docs/LICENSE.BSD-2-Clause | 22 -
systemvm/agent/noVNC/docs/LICENSE.BSD-3-Clause | 24 -
systemvm/agent/noVNC/docs/LICENSE.MPL-2.0 | 373 ---
systemvm/agent/noVNC/docs/LICENSE.OFL-1.1 | 91 -
systemvm/agent/noVNC/docs/flash_policy.txt | 4 -
systemvm/agent/noVNC/docs/links | 76 -
systemvm/agent/noVNC/docs/notes | 5 -
systemvm/agent/noVNC/docs/rfb_notes | 147 --
systemvm/agent/noVNC/docs/rfbproto-3.3.pdf | Bin 110778 -> 0 bytes
systemvm/agent/noVNC/docs/rfbproto-3.7.pdf | Bin 165552 -> 0 bytes
systemvm/agent/noVNC/docs/rfbproto-3.8.pdf | Bin 143840 -> 0 bytes
systemvm/agent/noVNC/karma.conf.js | 134 --
systemvm/agent/noVNC/package.json | 62 +-
systemvm/agent/noVNC/po/Makefile | 35 -
systemvm/agent/noVNC/po/cs.po | 294 ---
systemvm/agent/noVNC/po/de.po | 303 ---
systemvm/agent/noVNC/po/el.po | 323 ---
systemvm/agent/noVNC/po/es.po | 283 ---
systemvm/agent/noVNC/po/ko.po | 290 ---
systemvm/agent/noVNC/po/nl.po | 322 ---
systemvm/agent/noVNC/po/noVNC.pot | 302 ---
systemvm/agent/noVNC/po/pl.po | 325 ---
systemvm/agent/noVNC/po/po2js | 43 -
systemvm/agent/noVNC/po/ru.po | 306 ---
systemvm/agent/noVNC/po/sv.po | 316 ---
systemvm/agent/noVNC/po/tr.po | 288 ---
systemvm/agent/noVNC/po/xgettext-html | 115 -
systemvm/agent/noVNC/po/zh_CN.po | 284 ---
systemvm/agent/noVNC/po/zh_TW.po | 285 ---
systemvm/agent/noVNC/tests/.eslintrc | 15 -
systemvm/agent/noVNC/tests/assertions.js | 101 -
systemvm/agent/noVNC/tests/fake.websocket.js | 96 -
systemvm/agent/noVNC/tests/karma-test-main.js | 48 -
systemvm/agent/noVNC/tests/playback-ui.js | 210 --
systemvm/agent/noVNC/tests/playback.js | 172 --
systemvm/agent/noVNC/tests/test.base64.js | 33 -
systemvm/agent/noVNC/tests/test.display.js | 486 ----
systemvm/agent/noVNC/tests/test.helper.js | 223 --
systemvm/agent/noVNC/tests/test.keyboard.js | 510 -----
systemvm/agent/noVNC/tests/test.localization.js | 72 -
systemvm/agent/noVNC/tests/test.mouse.js | 304 ---
systemvm/agent/noVNC/tests/test.rfb.js | 2389 --------------------
systemvm/agent/noVNC/tests/test.util.js | 69 -
systemvm/agent/noVNC/tests/test.websock.js | 441 ----
systemvm/agent/noVNC/tests/test.webutil.js | 184 --
systemvm/agent/noVNC/tests/vnc_playback.html | 43 -
systemvm/agent/noVNC/utils/.eslintrc | 8 -
systemvm/agent/noVNC/utils/README.md | 14 -
systemvm/agent/noVNC/utils/b64-to-binary.pl | 17 -
systemvm/agent/noVNC/utils/genkeysymdef.js | 127 --
systemvm/agent/noVNC/utils/img2js.py | 40 -
systemvm/agent/noVNC/utils/json2graph.py | 206 --
systemvm/agent/noVNC/utils/launch.sh | 169 --
systemvm/agent/noVNC/utils/u2x11 | 28 -
systemvm/agent/noVNC/utils/use_require.js | 313 ---
systemvm/agent/noVNC/utils/use_require_helpers.js | 76 -
systemvm/agent/noVNC/utils/validate | 45 -
.../vendor/browser-es-module-loader/README.md | 4 +-
.../vendor/browser-es-module-loader/genworker.js | 13 +
.../browser-es-module-loader/rollup.config.js | 15 +-
.../browser-es-module-loader/src/babel-worker.js | 18 +-
.../src/browser-es-module-loader.js | 1 -
.../agent/noVNC/vendor/pako/lib/zlib/deflate.js | 60 +-
.../agent/noVNC/vendor/pako/lib/zlib/inflate.js | 34 +-
systemvm/agent/noVNC/vnc.html | 303 +--
systemvm/agent/noVNC/vnc_lite.html | 19 +-
164 files changed, 3227 insertions(+), 16263 deletions(-)
diff --git a/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java
index ed73625..b735be8 100644
--- a/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java
+++ b/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java
@@ -484,7 +484,7 @@ public class ConsoleProxyServlet extends HttpServlet {
if (param.getHypervHost() != null || !ConsoleProxyManager.NoVncConsoleDefault.value()) {
sb.append("/ajax?token=" + encryptor.encryptObject(ConsoleProxyClientParam.class, param));
} else {
- sb.append("/resource/noVNC/vnc_lite.html?port=" + ConsoleProxyManager.DEFAULT_NOVNC_PORT + "&token="
+ sb.append("/resource/noVNC/vnc.html?port=" + ConsoleProxyManager.DEFAULT_NOVNC_PORT + "&token="
+ encryptor.encryptObject(ConsoleProxyClientParam.class, param));
}
diff --git a/systemvm/agent/noVNC/.eslintignore b/systemvm/agent/noVNC/.eslintignore
deleted file mode 100644
index d381628..0000000
--- a/systemvm/agent/noVNC/.eslintignore
+++ /dev/null
@@ -1 +0,0 @@
-**/xtscancodes.js
diff --git a/systemvm/agent/noVNC/.eslintrc b/systemvm/agent/noVNC/.eslintrc
deleted file mode 100644
index 900a718..0000000
--- a/systemvm/agent/noVNC/.eslintrc
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "env": {
- "browser": true,
- "es6": true
- },
- "parserOptions": {
- "sourceType": "module"
- },
- "extends": "eslint:recommended",
- "rules": {
- // Unsafe or confusing stuff that we forbid
-
- "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }],
- "no-constant-condition": ["error", { "checkLoops": false }],
- "no-var": "error",
- "no-useless-constructor": "error",
- "object-shorthand": ["error", "methods", { "avoidQuotes": true }],
- "prefer-arrow-callback": "error",
- "arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": false } ],
- "arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
- "arrow-spacing": ["error"],
- "no-confusing-arrow": ["error", { "allowParens": true }],
-
- // Enforced coding style
-
- "brace-style": ["error", "1tbs", { "allowSingleLine": true }],
- "indent": ["error", 4, { "SwitchCase": 1,
- "CallExpression": { "arguments": "first" },
- "ArrayExpression": "first",
- "ObjectExpression": "first",
- "ignoreComments": true }],
- "comma-spacing": ["error"],
- "comma-style": ["error"],
- "curly": ["error", "multi-line"],
- "func-call-spacing": ["error"],
- "func-names": ["error"],
- "func-style": ["error", "declaration", { "allowArrowFunctions": true }],
- "key-spacing": ["error"],
- "keyword-spacing": ["error"],
- "no-trailing-spaces": ["error"],
- "semi": ["error"],
- "space-before-blocks": ["error"],
- "space-before-function-paren": ["error", { "anonymous": "always",
- "named": "never",
- "asyncArrow": "always" }],
- "switch-colon-spacing": ["error"],
- }
-}
diff --git a/systemvm/agent/noVNC/.github/ISSUE_TEMPLATE/bug_report.md b/systemvm/agent/noVNC/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 94ac6f8..0000000
--- a/systemvm/agent/noVNC/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Client (please complete the following information):**
- - OS: [e.g. iOS]
- - Browser: [e.g. chrome, safari]
- - Browser version: [e.g. 22]
-
-**Server (please complete the following information):**
- - noVNC version: [e.g. 1.0.0 or git commit id]
- - VNC server: [e.g. QEMU, TigerVNC]
- - WebSocket proxy: [e.g. websockify]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/systemvm/agent/noVNC/.github/ISSUE_TEMPLATE/feature_request.md b/systemvm/agent/noVNC/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 066b2d9..0000000
--- a/systemvm/agent/noVNC/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/systemvm/agent/noVNC/.gitignore b/systemvm/agent/noVNC/.gitignore
deleted file mode 100644
index c178dba..0000000
--- a/systemvm/agent/noVNC/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-*.pyc
-*.o
-tests/data_*.js
-utils/rebind.so
-utils/websockify
-/node_modules
-/build
-/lib
-recordings
-*.swp
-*~
-noVNC-*.tgz
diff --git a/systemvm/agent/noVNC/.gitmodules b/systemvm/agent/noVNC/.gitmodules
deleted file mode 100644
index e69de29..0000000
diff --git a/systemvm/agent/noVNC/.travis.yml b/systemvm/agent/noVNC/.travis.yml
deleted file mode 100644
index 78b521a..0000000
--- a/systemvm/agent/noVNC/.travis.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-language: node_js
-sudo: false
-cache:
- directories:
- - node_modules
-node_js:
- - 6
-env:
- matrix:
- - TEST_BROWSER_NAME=chrome TEST_BROWSER_OS='Windows 10'
-# FIXME Skip tests in Linux since Sauce Labs browser versions are ancient.
-# - TEST_BROWSER_NAME=chrome TEST_BROWSER_OS='Linux'
- - TEST_BROWSER_NAME=chrome TEST_BROWSER_OS='OS X 10.11'
- - TEST_BROWSER_NAME=firefox TEST_BROWSER_OS='Windows 10'
-# - TEST_BROWSER_NAME=firefox TEST_BROWSER_OS='Linux'
- - TEST_BROWSER_NAME=firefox TEST_BROWSER_OS='OS X 10.11'
- - TEST_BROWSER_NAME='internet explorer' TEST_BROWSER_OS='Windows 10'
- - TEST_BROWSER_NAME='internet explorer' TEST_BROWSER_OS='Windows 7'
- - TEST_BROWSER_NAME=microsoftedge TEST_BROWSER_OS='Windows 10'
- - TEST_BROWSER_NAME=safari TEST_BROWSER_OS='OS X 10.13'
-before_script: npm install -g karma-cli
-addons:
- sauce_connect:
- username: "directxman12"
- jwt:
- secure: "d3ekMYslpn6R4f0ajtRMt9SUFmNGDiItHpqaXC5T4KI0KMEsxgvEOfJot5PiFFJWg1DSpJZH6oaW2UxGZ3duJLZrXIEd/JePY8a6NtT35BNgiDPgcp+eu2Bu3rhrSNg7/HEsD1ma+JeUTnv18Ai5oMFfCCQJx2J6osIxyl/ZVxA="
-stages:
-- lint
-- test
-- name: deploy
- if: tag is PRESENT
-jobs:
- include:
- - stage: lint
- env:
- addons:
- before_script:
- script: npm run lint
- -
- env:
- addons:
- before_script:
- script: git ls-tree --name-only -r HEAD | grep -E "[.](html|css)$" | xargs ./utils/validate
- - stage: deploy
- env:
- addons:
- script: skip
- before_script: skip
- deploy:
- provider: npm
- email: ossman@cendio.se
- api_key:
- secure: "Qq2Mi9xQawO2zlAigzshzMu2QMHvu1IaN9l0ZIivE99wHJj7eS5f4miJ9wB+/mWRRgb3E8uj9ZRV24+Oc36drlBTU9sz+lHhH0uFMfAIseceK64wZV9sLAZm472fmPp2xdUeTCCqPaRy7g1XBqiJ0LyZvEFLsRijqcLjPBF+b8w="
- on:
- tags: true
- repo: novnc/noVNC
-
-
diff --git a/systemvm/agent/noVNC/AUTHORS b/systemvm/agent/noVNC/AUTHORS
deleted file mode 100644
index dec0e89..0000000
--- a/systemvm/agent/noVNC/AUTHORS
+++ /dev/null
@@ -1,13 +0,0 @@
-maintainers:
-- Joel Martin (@kanaka)
-- Solly Ross (@directxman12)
-- Samuel Mannehed for Cendio AB (@samhed)
-- Pierre Ossman for Cendio AB (@CendioOssman)
-maintainersEmeritus:
-- @astrand
-contributors:
-# There are a bunch of people that should be here.
-# If you want to be on this list, feel free send a PR
-# to add yourself.
-- jalf <gi...@jalf.dk>
-- NTT corp.
diff --git a/systemvm/agent/noVNC/LICENSE.txt b/systemvm/agent/noVNC/LICENSE.txt
deleted file mode 100644
index 20f3eb0..0000000
--- a/systemvm/agent/noVNC/LICENSE.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-noVNC is Copyright (C) 2018 The noVNC Authors
-(./AUTHORS)
-
-The noVNC core library files are licensed under the MPL 2.0 (Mozilla
-Public License 2.0). The noVNC core library is composed of the
-Javascript code necessary for full noVNC operation. This includes (but
-is not limited to):
-
- core/**/*.js
- app/*.js
- test/playback.js
-
-The HTML, CSS, font and images files that included with the noVNC
-source distibution (or repository) are not considered part of the
-noVNC core library and are licensed under more permissive licenses.
-The intent is to allow easy integration of noVNC into existing web
-sites and web applications.
-
-The HTML, CSS, font and image files are licensed as follows:
-
- *.html : 2-Clause BSD license
-
- app/styles/*.css : 2-Clause BSD license
-
- app/styles/Orbitron* : SIL Open Font License 1.1
- (Copyright 2009 Matt McInerney)
-
- app/images/ : Creative Commons Attribution-ShareAlike
- http://creativecommons.org/licenses/by-sa/3.0/
-
-Some portions of noVNC are copyright to their individual authors.
-Please refer to the individual source files and/or to the noVNC commit
-history: https://github.com/novnc/noVNC/commits/master
-
-The are several files and projects that have been incorporated into
-the noVNC core library. Here is a list of those files and the original
-licenses (all MPL 2.0 compatible):
-
- core/base64.js : MPL 2.0
-
- core/des.js : Various BSD style licenses
-
- vendor/pako/ : MIT
-
- vendor/browser-es-module-loader/src/ : MIT
-
- vendor/browser-es-module-loader/dist/ : Various BSD style licenses
-
- vendor/promise.js : MIT
-
-Any other files not mentioned above are typically marked with
-a copyright/license header at the top of the file. The default noVNC
-license is MPL-2.0.
-
-The following license texts are included:
-
- docs/LICENSE.MPL-2.0
- docs/LICENSE.OFL-1.1
- docs/LICENSE.BSD-3-Clause (New BSD)
- docs/LICENSE.BSD-2-Clause (Simplified BSD / FreeBSD)
- vendor/pako/LICENSE (MIT)
-
-Or alternatively the license texts may be found here:
-
- http://www.mozilla.org/MPL/2.0/
- http://scripts.sil.org/OFL
- http://en.wikipedia.org/wiki/BSD_licenses
- https://opensource.org/licenses/MIT
diff --git a/systemvm/agent/noVNC/README.md b/systemvm/agent/noVNC/README.md
deleted file mode 100644
index 566b8e4..0000000
--- a/systemvm/agent/noVNC/README.md
+++ /dev/null
@@ -1,152 +0,0 @@
-## noVNC: HTML VNC Client Library and Application
-
-[![Build Status](https://travis-ci.org/novnc/noVNC.svg?branch=master)](https://travis-ci.org/novnc/noVNC)
-
-### Description
-
-noVNC is both a HTML VNC client JavaScript library and an application built on
-top of that library. noVNC runs well in any modern browser including mobile
-browsers (iOS and Android).
-
-Many companies, projects and products have integrated noVNC including
-[OpenStack](http://www.openstack.org),
-[OpenNebula](http://opennebula.org/),
-[LibVNCServer](http://libvncserver.sourceforge.net), and
-[ThinLinc](https://cendio.com/thinlinc). See
-[the Projects and Companies wiki page](https://github.com/novnc/noVNC/wiki/Projects-and-companies-using-noVNC)
-for a more complete list with additional info and links.
-
-### Table of Contents
-
-- [News/help/contact](#newshelpcontact)
-- [Features](#features)
-- [Screenshots](#screenshots)
-- [Browser Requirements](#browser-requirements)
-- [Server Requirements](#server-requirements)
-- [Quick Start](#quick-start)
-- [Integration and Deployment](#integration-and-deployment)
-- [Authors/Contributors](#authorscontributors)
-
-### News/help/contact
-
-The project website is found at [novnc.com](http://novnc.com).
-Notable commits, announcements and news are posted to
-[@noVNC](http://www.twitter.com/noVNC).
-
-If you are a noVNC developer/integrator/user (or want to be) please join the
-[noVNC discussion group](https://groups.google.com/forum/?fromgroups#!forum/novnc).
-
-Bugs and feature requests can be submitted via
-[github issues](https://github.com/novnc/noVNC/issues). If you have questions
-about using noVNC then please first use the
-[discussion group](https://groups.google.com/forum/?fromgroups#!forum/novnc).
-We also have a [wiki](https://github.com/novnc/noVNC/wiki/) with lots of
-helpful information.
-
-If you are looking for a place to start contributing to noVNC, a good place to
-start would be the issues that are marked as
-["patchwelcome"](https://github.com/novnc/noVNC/issues?labels=patchwelcome).
-Please check our
-[contribution guide](https://github.com/novnc/noVNC/wiki/Contributing) though.
-
-If you want to show appreciation for noVNC you could donate to a great non-
-profits such as:
-[Compassion International](http://www.compassion.com/),
-[SIL](http://www.sil.org),
-[Habitat for Humanity](http://www.habitat.org),
-[Electronic Frontier Foundation](https://www.eff.org/),
-[Against Malaria Foundation](http://www.againstmalaria.com/),
-[Nothing But Nets](http://www.nothingbutnets.net/), etc.
-Please tweet [@noVNC](http://www.twitter.com/noVNC) if you do.
-
-
-### Features
-
-* Supports all modern browsers including mobile (iOS, Android)
-* Supported VNC encodings: raw, copyrect, rre, hextile, tight, tightPNG
-* Supports scaling, clipping and resizing the desktop
-* Local cursor rendering
-* Clipboard copy/paste
-* Translations
-* Licensed mainly under the [MPL 2.0](http://www.mozilla.org/MPL/2.0/), see
- [the license document](LICENSE.txt) for details
-
-### Screenshots
-
-Running in Firefox before and after connecting:
-
-<img src="http://novnc.com/img/noVNC-1-login.png" width=400>
-<img src="http://novnc.com/img/noVNC-3-connected.png" width=400>
-
-See more screenshots
-[here](http://novnc.com/screenshots.html).
-
-
-### Browser Requirements
-
-noVNC uses many modern web technologies so a formal requirement list is
-not available. However these are the minimum versions we are currently
-aware of:
-
-* Chrome 49, Firefox 44, Safari 10, Opera 36, IE 11, Edge 12
-
-
-### Server Requirements
-
-noVNC follows the standard VNC protocol, but unlike other VNC clients it does
-require WebSockets support. Many servers include support (e.g.
-[x11vnc/libvncserver](http://libvncserver.sourceforge.net/),
-[QEMU](http://www.qemu.org/), and
-[MobileVNC](http://www.smartlab.at/mobilevnc/)), but for the others you need to
-use a WebSockets to TCP socket proxy. noVNC has a sister project
-[websockify](https://github.com/novnc/websockify) that provides a simple such
-proxy.
-
-
-### Quick Start
-
-* Use the launch script to automatically download and start websockify, which
- includes a mini-webserver and the WebSockets proxy. The `--vnc` option is
- used to specify the location of a running VNC server:
-
- `./utils/launch.sh --vnc localhost:5901`
-
-* Point your browser to the cut-and-paste URL that is output by the launch
- script. Hit the Connect button, enter a password if the VNC server has one
- configured, and enjoy!
-
-
-### Integration and Deployment
-
-Please see our other documents for how to integrate noVNC in your own software,
-or deploying the noVNC application in production environments:
-
-* [Embedding](docs/EMBEDDING.md) - For the noVNC application
-* [Library](docs/LIBRARY.md) - For the noVNC JavaScript library
-
-
-### Authors/Contributors
-
-See [AUTHORS](AUTHORS) for a (full-ish) list of authors. If you're not on
-that list and you think you should be, feel free to send a PR to fix that.
-
-* Core team:
- * [Joel Martin](https://github.com/kanaka)
- * [Samuel Mannehed](https://github.com/samhed) (Cendio)
- * [Peter Åstrand](https://github.com/astrand) (Cendio)
- * [Solly Ross](https://github.com/DirectXMan12) (Red Hat / OpenStack)
- * [Pierre Ossman](https://github.com/CendioOssman) (Cendio)
-
-* Notable contributions:
- * UI and Icons : Pierre Ossman, Chris Gordon
- * Original Logo : Michael Sersen
- * tight encoding : Michael Tinglof (Mercuri.ca)
-
-* Included libraries:
- * base64 : Martijn Pieters (Digital Creations 2), Samuel Sieb (sieb.net)
- * DES : Dave Zimmerman (Widget Workshop), Jef Poskanzer (ACME Labs)
- * Pako : Vitaly Puzrin (https://github.com/nodeca/pako)
-
-Do you want to be on this list? Check out our
-[contribution guide](https://github.com/novnc/noVNC/wiki/Contributing) and
-start hacking!
diff --git a/systemvm/agent/noVNC/VERSION b/systemvm/agent/noVNC/VERSION
deleted file mode 100644
index 9084fa2..0000000
--- a/systemvm/agent/noVNC/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-1.1.0
diff --git a/systemvm/agent/noVNC/app/error-handler.js b/systemvm/agent/noVNC/app/error-handler.js
index 8e29416..81a6cba 100644
--- a/systemvm/agent/noVNC/app/error-handler.js
+++ b/systemvm/agent/noVNC/app/error-handler.js
@@ -1,3 +1,11 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2019 The noVNC Authors
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
// NB: this should *not* be included as a module until we have
// native support in the browsers, so that our error handler
// can catch script-loading errors.
diff --git a/systemvm/agent/noVNC/app/images/alt.png b/systemvm/agent/noVNC/app/images/alt.png
new file mode 100644
index 0000000..2d5e35e
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/alt.png differ
diff --git a/systemvm/agent/noVNC/app/images/alt.svg b/systemvm/agent/noVNC/app/images/alt.svg
deleted file mode 100644
index e5bb461..0000000
--- a/systemvm/agent/noVNC/app/images/alt.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="alt.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="18.205425"
- inkscape:cy="17.531398"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <g
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="text5290">
- <path
- d="m 9.9560547,1042.3329 -2.9394531,0 -0.4638672,1.3281 -1.8896485,0 2.7001953,-7.29 2.241211,0 2.7001958,7.29 -1.889649,0 -0.4589843,-1.3281 z m -2.4707031,-1.3526 1.9970703,0 -0.9960938,-2.9003 -1.0009765,2.9003 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5340" />
- <path
- d="m 13.188477,1036.0634 1.748046,0 0,7.5976 -1.748046,0 0,-7.5976 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5342" />
- <path
- d="m 18.535156,1036.6395 0,1.5528 1.801758,0 0,1.25 -1.801758,0 0,2.3193 q 0,0.3809 0.151367,0.5176 0.151368,0.1318 0.600586,0.1318 l 0.898438,0 0,1.25 -1.499024,0 q -1.035156,0 -1.469726,-0.4297 -0.429688,-0.4345 -0.429688,-1.4697 l 0,-2.3193 -0.86914,0 0,-1.25 0.86914,0 0,-1.5528 1.748047,0 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5344" />
- </g>
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/clipboard.png b/systemvm/agent/noVNC/app/images/clipboard.png
new file mode 100644
index 0000000..d7fe507
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/clipboard.png differ
diff --git a/systemvm/agent/noVNC/app/images/clipboard.svg b/systemvm/agent/noVNC/app/images/clipboard.svg
deleted file mode 100644
index 79af275..0000000
--- a/systemvm/agent/noVNC/app/images/clipboard.svg
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="clipboard.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="15.366606"
- inkscape:cy="16.42981"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="M 9,6 6,6 C 5.4459889,6 5,6.4459889 5,7 l 0,13 c 0,0.554011 0.4459889,1 1,1 l 13,0 c 0.554011,0 1,-0.445989 1,-1 L 20,7 C 20,6.4459889 19.554011,6 19,6 l -3,0"
- transform="translate(0,1027.3622)"
- id="rect6083"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssssssssc" />
- <rect
- style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect6085"
- width="7"
- height="4"
- x="9"
- y="1031.3622"
- ry="1.00002" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081"
- d="m 8.5071212,1038.8622 7.9999998,0"
- id="path6087"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081"
- d="m 8.5071212,1041.8622 3.9999998,0"
- id="path6089"
- inkscape:connector-curvature="0" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196081"
- d="m 8.5071212,1044.8622 5.9999998,0"
- id="path6091"
- inkscape:connector-curvature="0" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/connect.png b/systemvm/agent/noVNC/app/images/connect.png
new file mode 100644
index 0000000..abdbe42
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/connect.png differ
diff --git a/systemvm/agent/noVNC/app/images/connect.svg b/systemvm/agent/noVNC/app/images/connect.svg
deleted file mode 100644
index 56cde41..0000000
--- a/systemvm/agent/noVNC/app/images/connect.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="connect.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="37.14834"
- inkscape:cy="1.9525926"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <g
- id="g5103"
- transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,-729.15757,315.8823)">
- <path
- sodipodi:nodetypes="cssssc"
- inkscape:connector-curvature="0"
- id="rect5096"
- d="m 11,1040.3622 -5,0 c -1.108,0 -2,-0.892 -2,-2 l 0,-4 c 0,-1.108 0.892,-2 2,-2 l 5,0"
- style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- <path
- style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 14,1032.3622 5,0 c 1.108,0 2,0.892 2,2 l 0,4 c 0,1.108 -0.892,2 -2,2 l -5,0"
- id="path5099"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssssc" />
- <path
- inkscape:connector-curvature="0"
- id="path5101"
- d="m 9,1036.3622 7,0"
- style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
- </g>
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/ctrl.png b/systemvm/agent/noVNC/app/images/ctrl.png
new file mode 100644
index 0000000..fbc9e13
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/ctrl.png differ
diff --git a/systemvm/agent/noVNC/app/images/ctrl.svg b/systemvm/agent/noVNC/app/images/ctrl.svg
deleted file mode 100644
index 856e939..0000000
--- a/systemvm/agent/noVNC/app/images/ctrl.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="ctrl.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="18.205425"
- inkscape:cy="17.531398"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <g
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="text5290">
- <path
- d="m 9.1210938,1043.1898 q -0.5175782,0.2686 -1.0791016,0.4053 -0.5615235,0.1367 -1.171875,0.1367 -1.8212891,0 -2.8857422,-1.0156 -1.0644531,-1.0205 -1.0644531,-2.7637 0,-1.748 1.0644531,-2.7637 1.0644531,-1.0205 2.8857422,-1.0205 0.6103515,0 1.171875,0.1368 0.5615234,0.1367 1.0791016,0.4052 l 0,1.5088 q -0.522461,-0.3564 -1.0302735,-0.5224 -0.5078125,-0.1661 -1.0693359,-0.1661 -1.0058594,0 -1.5820313,0.6446 -0.5761719,0.6445 -0.5761719,1.7773 0,1.1279 0.5761719,1.7725 0.5761719 [...]
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5370" />
- <path
- d="m 12.514648,1036.5687 0,1.5528 1.801758,0 0,1.25 -1.801758,0 0,2.3193 q 0,0.3809 0.151368,0.5176 0.151367,0.1318 0.600586,0.1318 l 0.898437,0 0,1.25 -1.499023,0 q -1.035157,0 -1.469727,-0.4297 -0.429687,-0.4345 -0.429687,-1.4697 l 0,-2.3193 -0.8691411,0 0,-1.25 0.8691411,0 0,-1.5528 1.748046,0 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5372" />
- <path
- d="m 19.453125,1039.6107 q -0.229492,-0.1074 -0.458984,-0.1562 -0.22461,-0.054 -0.454102,-0.054 -0.673828,0 -1.040039,0.4345 -0.361328,0.4297 -0.361328,1.2354 l 0,2.5195 -1.748047,0 0,-5.4687 1.748047,0 0,0.8984 q 0.336914,-0.5371 0.771484,-0.7813 0.439453,-0.249 1.049805,-0.249 0.08789,0 0.19043,0.01 0.102539,0 0.297851,0.029 l 0.0049,1.582 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5374" />
- <path
- d="m 20.332031,1035.9926 1.748047,0 0,7.5976 -1.748047,0 0,-7.5976 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5376" />
- </g>
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/ctrlaltdel.png b/systemvm/agent/noVNC/app/images/ctrlaltdel.png
new file mode 100644
index 0000000..dd04978
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/ctrlaltdel.png differ
diff --git a/systemvm/agent/noVNC/app/images/ctrlaltdel.svg b/systemvm/agent/noVNC/app/images/ctrlaltdel.svg
deleted file mode 100644
index d7744ea..0000000
--- a/systemvm/agent/noVNC/app/images/ctrlaltdel.svg
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="ctrlaltdel.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="8"
- inkscape:cx="11.135667"
- inkscape:cy="16.407428"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <rect
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect5253"
- width="5"
- height="5.0000172"
- x="16"
- y="1031.3622"
- ry="1.0000174" />
- <rect
- y="1043.3622"
- x="4"
- height="5.0000172"
- width="5"
- id="rect5255"
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- ry="1.0000174" />
- <rect
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect5257"
- width="5"
- height="5.0000172"
- x="13"
- y="1043.3622"
- ry="1.0000174" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/disconnect.png b/systemvm/agent/noVNC/app/images/disconnect.png
new file mode 100644
index 0000000..97eb1a9
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/disconnect.png differ
diff --git a/systemvm/agent/noVNC/app/images/disconnect.svg b/systemvm/agent/noVNC/app/images/disconnect.svg
deleted file mode 100644
index 6be7d18..0000000
--- a/systemvm/agent/noVNC/app/images/disconnect.svg
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="disconnect.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="25.05707"
- inkscape:cy="11.594858"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="false">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <g
- id="g5171"
- transform="translate(-24.062499,-6.15775e-4)">
- <path
- id="path5110"
- transform="translate(0,1027.3622)"
- d="m 39.744141,3.4960938 c -0.769923,0 -1.539607,0.2915468 -2.121094,0.8730468 l -2.566406,2.5664063 1.414062,1.4140625 2.566406,-2.5664063 c 0.403974,-0.404 1.010089,-0.404 1.414063,0 l 2.828125,2.828125 c 0.40398,0.4039 0.403907,1.0101621 0,1.4140629 l -2.566406,2.566406 1.414062,1.414062 2.566406,-2.566406 c 1.163041,-1.1629 1.162968,-3.0791874 0,-4.2421874 L 41.865234,4.3691406 C 41.283747,3.7876406 40.514063,3.4960937 39.744141,3.4960938 Z M 39.017578,9.015625 a 1.0001,1.00 [...]
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:non [...]
- inkscape:connector-curvature="0" />
- <rect
- transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,0,0)"
- y="752.29541"
- x="-712.31262"
- height="18.000017"
- width="3"
- id="rect5116"
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- </g>
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/drag.png b/systemvm/agent/noVNC/app/images/drag.png
new file mode 100644
index 0000000..f006202
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/drag.png differ
diff --git a/systemvm/agent/noVNC/app/images/drag.svg b/systemvm/agent/noVNC/app/images/drag.svg
deleted file mode 100644
index 139caf9..0000000
--- a/systemvm/agent/noVNC/app/images/drag.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="drag.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="22.627417"
- inkscape:cx="9.8789407"
- inkscape:cy="9.5008608"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="true"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 7.039733,1049.3037 c -0.4309106,-0.1233 -0.7932634,-0.4631 -0.9705434,-0.9103 -0.04922,-0.1241 -0.057118,-0.2988 -0.071321,-1.5771 l -0.015972,-1.4375 -0.328125,-0.082 c -0.7668138,-0.1927 -1.1897046,-0.4275 -1.7031253,-0.9457 -0.4586773,-0.4629 -0.6804297,-0.8433 -0.867034,-1.4875 -0.067215,-0.232 -0.068001,-0.2642 -0.078682,-3.2188 -0.012078,-3.341 -0.020337,-3.2012 0.2099452,-3.5555 0.2246623,-0.3458 0.5798271,-0.5892 0.9667343,-0.6626 0.092506,-0.017 0.531898,-0.032 0.976 [...]
- id="path4379"
- inkscape:connector-curvature="0" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/error.png b/systemvm/agent/noVNC/app/images/error.png
new file mode 100644
index 0000000..04e78e1
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/error.png differ
diff --git a/systemvm/agent/noVNC/app/images/error.svg b/systemvm/agent/noVNC/app/images/error.svg
deleted file mode 100644
index 8356d3f..0000000
--- a/systemvm/agent/noVNC/app/images/error.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="error.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="14.00357"
- inkscape:cy="12.443398"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="M 7 3 C 4.7839905 3 3 4.7839905 3 7 L 3 18 C 3 20.21601 4.7839905 22 7 22 L 18 22 C 20.21601 22 22 20.21601 22 18 L 22 7 C 22 4.7839905 20.21601 3 18 3 L 7 3 z M 7.6992188 6 A 1.6916875 1.6924297 0 0 1 8.9121094 6.5117188 L 12.5 10.101562 L 16.087891 6.5117188 A 1.6916875 1.6924297 0 0 1 17.251953 6 A 1.6916875 1.6924297 0 0 1 18.480469 8.90625 L 14.892578 12.496094 L 18.480469 16.085938 A 1.6916875 1.6924297 0 1 1 16.087891 18.478516 L 12.5 14.888672 L 8.9121094 18.478516 A 1. [...]
- transform="translate(0,1027.3622)"
- id="rect4135" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/esc.png b/systemvm/agent/noVNC/app/images/esc.png
new file mode 100644
index 0000000..e1b1bfa
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/esc.png differ
diff --git a/systemvm/agent/noVNC/app/images/esc.svg b/systemvm/agent/noVNC/app/images/esc.svg
deleted file mode 100644
index 830152b..0000000
--- a/systemvm/agent/noVNC/app/images/esc.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="esc.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="18.205425"
- inkscape:cy="17.531398"
- inkscape:document-units="px"
- inkscape:current-layer="text5290"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <g
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:48px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="text5290">
- <path
- d="m 3.9331055,1036.1464 5.0732422,0 0,1.4209 -3.1933594,0 0,1.3574 3.0029297,0 0,1.4209 -3.0029297,0 0,1.6699 3.3007812,0 0,1.4209 -5.180664,0 0,-7.29 z"
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5314" />
- <path
- d="m 14.963379,1038.1385 0,1.3282 q -0.561524,-0.2344 -1.083984,-0.3516 -0.522461,-0.1172 -0.986329,-0.1172 -0.498046,0 -0.742187,0.127 -0.239258,0.122 -0.239258,0.3808 0,0.21 0.180664,0.3223 0.185547,0.1123 0.65918,0.166 l 0.307617,0.044 q 1.342773,0.1709 1.806641,0.5615 0.463867,0.3906 0.463867,1.2256 0,0.874 -0.644531,1.3134 -0.644532,0.4395 -1.923829,0.4395 -0.541992,0 -1.123046,-0.088 -0.576172,-0.083 -1.186524,-0.2539 l 0,-1.3281 q 0.522461,0.2539 1.069336,0.3808 0.551758, [...]
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5316" />
- <path
- d="m 21.066895,1038.1385 0,1.4258 q -0.356446,-0.2441 -0.717774,-0.3613 -0.356445,-0.1172 -0.742187,-0.1172 -0.732422,0 -1.142579,0.4297 -0.405273,0.4248 -0.405273,1.1914 0,0.7666 0.405273,1.1963 0.410157,0.4248 1.142579,0.4248 0.410156,0 0.776367,-0.1221 0.371094,-0.122 0.683594,-0.3613 l 0,1.4307 q -0.410157,0.1513 -0.834961,0.2246 -0.419922,0.078 -0.844727,0.078 -1.479492,0 -2.314453,-0.7568 -0.834961,-0.7618 -0.834961,-2.1143 0,-1.3525 0.834961,-2.1094 0.834961,-0.7617 2.314 [...]
- style="font-size:10px;fill:#ffffff;fill-opacity:1"
- id="path5318" />
- </g>
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/expander.png b/systemvm/agent/noVNC/app/images/expander.png
new file mode 100644
index 0000000..2793721
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/expander.png differ
diff --git a/systemvm/agent/noVNC/app/images/expander.svg b/systemvm/agent/noVNC/app/images/expander.svg
deleted file mode 100644
index e163535..0000000
--- a/systemvm/agent/noVNC/app/images/expander.svg
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="9"
- height="10"
- viewBox="0 0 9 10"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="expander.svg">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="45.254834"
- inkscape:cx="9.8737281"
- inkscape:cy="6.4583132"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="true"
- units="px"
- inkscape:snap-object-midpoints="false"
- inkscape:object-nodes="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="0"
- inkscape:window-y="27"
- inkscape:window-maximized="1">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1042.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="M 2.0800781,1042.3633 A 2.0002,2.0002 0 0 0 0,1044.3613 l 0,6 a 2.0002,2.0002 0 0 0 3.0292969,1.7168 l 5,-3 a 2.0002,2.0002 0 0 0 0,-3.4316 l -5,-3 a 2.0002,2.0002 0 0 0 -0.9492188,-0.2832 z"
- id="path4138"
- inkscape:connector-curvature="0" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/fullscreen.png b/systemvm/agent/noVNC/app/images/fullscreen.png
new file mode 100644
index 0000000..a7f2634
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/fullscreen.png differ
diff --git a/systemvm/agent/noVNC/app/images/fullscreen.svg b/systemvm/agent/noVNC/app/images/fullscreen.svg
deleted file mode 100644
index 29bd05d..0000000
--- a/systemvm/agent/noVNC/app/images/fullscreen.svg
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="fullscreen.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="16.400723"
- inkscape:cy="15.083758"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="false">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <rect
- style="opacity:1;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect5006"
- width="17"
- height="17.000017"
- x="4"
- y="1031.3622"
- ry="3.0000174" />
- <path
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="m 7.5,1044.8622 4,0 -1.5,-1.5 1.5,-1.5 -1,-1 -1.5,1.5 -1.5,-1.5 0,4 z"
- id="path5017"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path5025"
- d="m 17.5,1034.8622 -4,0 1.5,1.5 -1.5,1.5 1,1 1.5,-1.5 1.5,1.5 0,-4 z"
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/handle.png b/systemvm/agent/noVNC/app/images/handle.png
new file mode 100644
index 0000000..cf0e5d5
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/handle.png differ
diff --git a/systemvm/agent/noVNC/app/images/handle.svg b/systemvm/agent/noVNC/app/images/handle.svg
deleted file mode 100644
index 4a7a126..0000000
--- a/systemvm/agent/noVNC/app/images/handle.svg
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="5"
- height="6"
- viewBox="0 0 5 6"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="handle.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="32"
- inkscape:cx="1.3551778"
- inkscape:cy="8.7800329"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="true"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1046.3622)">
- <path
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 4.0000803,1049.3622 -3,-2 0,4 z"
- id="path4247"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/handle_bg.png b/systemvm/agent/noVNC/app/images/handle_bg.png
new file mode 100644
index 0000000..efb0357
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/handle_bg.png differ
diff --git a/systemvm/agent/noVNC/app/images/handle_bg.svg b/systemvm/agent/noVNC/app/images/handle_bg.svg
deleted file mode 100644
index 7579c42..0000000
--- a/systemvm/agent/noVNC/app/images/handle_bg.svg
+++ /dev/null
@@ -1,172 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="15"
- height="50"
- viewBox="0 0 15 50"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="handle_bg.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="-10.001409"
- inkscape:cy="24.512566"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="true"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1002.3622)">
- <rect
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect4249"
- width="1"
- height="1.0000174"
- x="9.5"
- y="1008.8622"
- ry="1.7382812e-05" />
- <rect
- ry="1.7382812e-05"
- y="1013.8622"
- x="9.5"
- height="1.0000174"
- width="1"
- id="rect4255"
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- <rect
- ry="1.7382812e-05"
- y="1008.8622"
- x="4.5"
- height="1.0000174"
- width="1"
- id="rect4261"
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- <rect
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect4263"
- width="1"
- height="1.0000174"
- x="4.5"
- y="1013.8622"
- ry="1.7382812e-05" />
- <rect
- ry="1.7382812e-05"
- y="1039.8622"
- x="9.5"
- height="1.0000174"
- width="1"
- id="rect4265"
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- <rect
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect4267"
- width="1"
- height="1.0000174"
- x="9.5"
- y="1044.8622"
- ry="1.7382812e-05" />
- <rect
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect4269"
- width="1"
- height="1.0000174"
- x="4.5"
- y="1039.8622"
- ry="1.7382812e-05" />
- <rect
- ry="1.7382812e-05"
- y="1044.8622"
- x="4.5"
- height="1.0000174"
- width="1"
- id="rect4271"
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- <rect
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect4273"
- width="1"
- height="1.0000174"
- x="9.5"
- y="1018.8622"
- ry="1.7382812e-05" />
- <rect
- ry="1.7382812e-05"
- y="1018.8622"
- x="4.5"
- height="1.0000174"
- width="1"
- id="rect4275"
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- <rect
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="rect4277"
- width="1"
- height="1.0000174"
- x="9.5"
- y="1034.8622"
- ry="1.7382812e-05" />
- <rect
- ry="1.7382812e-05"
- y="1034.8622"
- x="4.5"
- height="1.0000174"
- width="1"
- id="rect4279"
- style="opacity:0.25;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/info.png b/systemvm/agent/noVNC/app/images/info.png
new file mode 100644
index 0000000..21e3589
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/info.png differ
diff --git a/systemvm/agent/noVNC/app/images/info.svg b/systemvm/agent/noVNC/app/images/info.svg
deleted file mode 100644
index 557b772..0000000
--- a/systemvm/agent/noVNC/app/images/info.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="info.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="15.720838"
- inkscape:cy="8.9111233"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="M 12.5 3 A 9.5 9.4999914 0 0 0 3 12.5 A 9.5 9.4999914 0 0 0 12.5 22 A 9.5 9.4999914 0 0 0 22 12.5 A 9.5 9.4999914 0 0 0 12.5 3 z M 12.5 5 A 1.5 1.5000087 0 0 1 14 6.5 A 1.5 1.5000087 0 0 1 12.5 8 A 1.5 1.5000087 0 0 1 11 6.5 A 1.5 1.5000087 0 0 1 12.5 5 z M 10.521484 8.9785156 L 12.521484 8.9785156 A 1.50015 1.50015 0 0 1 14.021484 10.478516 L 14.021484 15.972656 A 1.50015 1.50015 0 0 1 14.498047 18.894531 C 14.498047 18.894531 13.74301 19.228309 12.789062 18.912109 C 12.312092 [...]
- transform="translate(0,1027.3622)"
- id="path4136" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/keyboard.png b/systemvm/agent/noVNC/app/images/keyboard.png
new file mode 100644
index 0000000..fe8056b
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/keyboard.png differ
diff --git a/systemvm/agent/noVNC/app/images/keyboard.svg b/systemvm/agent/noVNC/app/images/keyboard.svg
deleted file mode 100644
index 137b350..0000000
--- a/systemvm/agent/noVNC/app/images/keyboard.svg
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="keyboard.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/keyboard.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#717171"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="31.285341"
- inkscape:cy="8.8028469"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:snap-bbox-midpoints="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:object-paths="true"
- inkscape:snap-intersection-paths="true"
- inkscape:object-nodes="true"
- inkscape:snap-midpoints="true"
- inkscape:snap-smooth-nodes="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="M 7,3 C 4.8012876,3 3,4.8013 3,7 3,11.166667 3,15.333333 3,19.5 3,20.8764 4.1236413,22 5.5,22 l 14,0 C 20.876358,22 22,20.8764 22,19.5 22,15.333333 22,11.166667 22,7 22,4.8013 20.198712,3 18,3 Z m 0,2 11,0 c 1.125307,0 2,0.8747 2,2 L 20,12 5,12 5,7 C 5,5.8747 5.8746931,5 7,5 Z M 6.5,14 C 6.777,14 7,14.223 7,14.5 7,14.777 6.777,15 6.5,15 6.223,15 6,14.777 6,14.5 6,14.223 6.223,14 6.5,14 Z m 2,0 C 8.777,14 9,14.223 9,14.5 9,14.777 8.777,15 8.5,15 8.223,15 8,14.777 8,14.5 8,14.223 [...]
- transform="translate(0,1027.3622)"
- id="rect4160"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sccssccsssssccssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" />
- <path
- style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
- d="m 12.499929,1033.8622 -2,2 1.500071,0 0,2 1,0 0,-2 1.499929,0 z"
- id="path4150"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/mouse_left.svg b/systemvm/agent/noVNC/app/images/mouse_left.svg
deleted file mode 100644
index ce4cca4..0000000
--- a/systemvm/agent/noVNC/app/images/mouse_left.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="mouse_left.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="11.313708"
- inkscape:cx="15.551515"
- inkscape:cy="12.205592"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
- id="path6219" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
- id="path6217" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
- id="path6215" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
- id="rect6178" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/mouse_middle.svg b/systemvm/agent/noVNC/app/images/mouse_middle.svg
deleted file mode 100644
index 6603425..0000000
--- a/systemvm/agent/noVNC/app/images/mouse_middle.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="mouse_middle.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="11.313708"
- inkscape:cx="15.551515"
- inkscape:cy="12.205592"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
- id="path6219" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
- id="path6217" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
- id="path6215" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
- id="rect6178" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/mouse_none.svg b/systemvm/agent/noVNC/app/images/mouse_none.svg
deleted file mode 100644
index 3e0f838..0000000
--- a/systemvm/agent/noVNC/app/images/mouse_none.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="mouse_none.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="23.160825"
- inkscape:cy="13.208262"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
- id="path6219" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
- id="path6217" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
- id="path6215" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
- id="rect6178" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/mouse_right.svg b/systemvm/agent/noVNC/app/images/mouse_right.svg
deleted file mode 100644
index f4bad76..0000000
--- a/systemvm/agent/noVNC/app/images/mouse_right.svg
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="mouse_right.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="11.313708"
- inkscape:cx="15.551515"
- inkscape:cy="12.205592"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 8,1030.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,2 5,0 0,-2 c 0,-1.4738 1.090393,-2.7071 2.5,-2.9492 l 0,-1.0508 -3.5,0 z"
- id="path6219" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 13.5,1030.3622 0,1.0508 c 1.409607,0.2421 2.5,1.4754 2.5,2.9492 l 0,2 5,0 0,-2 c 0,-2.1987 -1.801288,-4 -4,-4 l -3.5,0 z"
- id="path6217" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 12,1033.3622 c -0.571311,0 -1,0.4287 -1,1 l 0,5 c 0,0.5713 0.428689,1 1,1 l 1,0 c 0.571311,0 1,-0.4287 1,-1 l 0,-5 c 0,-0.5713 -0.428689,-1 -1,-1 l -1,0 z"
- id="path6215" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 4,1038.3622 0,3.5 c 0,4.1377 3.362302,7.5 7.5,7.5 l 2,0 c 4.137698,0 7.5,-3.3623 7.5,-7.5 l 0,-3.5 -5,0 0,1 c 0,1.6447 -1.355293,3 -3,3 l -1,0 c -1.644707,0 -3,-1.3553 -3,-3 l 0,-1 -5,0 z"
- id="rect6178" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/power.png b/systemvm/agent/noVNC/app/images/power.png
new file mode 100644
index 0000000..7f87135
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/power.png differ
diff --git a/systemvm/agent/noVNC/app/images/power.svg b/systemvm/agent/noVNC/app/images/power.svg
deleted file mode 100644
index 4925d3e..0000000
--- a/systemvm/agent/noVNC/app/images/power.svg
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="power.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="9.3159849"
- inkscape:cy="13.436208"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="M 9 6.8183594 C 6.3418164 8.1213032 4.5 10.849161 4.5 14 C 4.5 18.4065 8.0935666 22 12.5 22 C 16.906433 22 20.5 18.4065 20.5 14 C 20.5 10.849161 18.658184 8.1213032 16 6.8183594 L 16 9.125 C 17.514327 10.211757 18.5 11.984508 18.5 14 C 18.5 17.3256 15.825553 20 12.5 20 C 9.1744469 20 6.5 17.3256 6.5 14 C 6.5 11.984508 7.4856727 10.211757 9 9.125 L 9 6.8183594 z "
- transform="translate(0,1027.3622)"
- id="path6140" />
- <path
- style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 12.5,1031.8836 0,6.4786"
- id="path6142"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/settings.png b/systemvm/agent/noVNC/app/images/settings.png
new file mode 100644
index 0000000..8d0c0d4
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/settings.png differ
diff --git a/systemvm/agent/noVNC/app/images/settings.svg b/systemvm/agent/noVNC/app/images/settings.svg
deleted file mode 100644
index dbb2e80..0000000
--- a/systemvm/agent/noVNC/app/images/settings.svg
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="settings.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="22.627417"
- inkscape:cx="14.69683"
- inkscape:cy="8.8039511"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="true"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="M 11 3 L 11 5.1601562 A 7.5 7.5 0 0 0 8.3671875 6.2460938 L 6.84375 4.7226562 L 4.7226562 6.84375 L 6.2480469 8.3691406 A 7.5 7.5 0 0 0 5.1523438 11 L 3 11 L 3 14 L 5.1601562 14 A 7.5 7.5 0 0 0 6.2460938 16.632812 L 4.7226562 18.15625 L 6.84375 20.277344 L 8.3691406 18.751953 A 7.5 7.5 0 0 0 11 19.847656 L 11 22 L 14 22 L 14 19.839844 A 7.5 7.5 0 0 0 16.632812 18.753906 L 18.15625 20.277344 L 20.277344 18.15625 L 18.751953 16.630859 A 7.5 7.5 0 0 0 19.847656 14 L 22 14 L 22 11 [...]
- transform="translate(0,1027.3622)"
- id="rect4967" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/tab.png b/systemvm/agent/noVNC/app/images/tab.png
new file mode 100644
index 0000000..6adb781
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/tab.png differ
diff --git a/systemvm/agent/noVNC/app/images/tab.svg b/systemvm/agent/noVNC/app/images/tab.svg
deleted file mode 100644
index 1ccb322..0000000
--- a/systemvm/agent/noVNC/app/images/tab.svg
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="tab.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="16"
- inkscape:cx="11.67335"
- inkscape:cy="17.881696"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="true"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 3,1031.3622 0,8 2,0 0,-4 0,-4 -2,0 z m 2,4 4,4 0,-3 13,0 0,-2 -13,0 0,-3 -4,4 z"
- id="rect5194"
- inkscape:connector-curvature="0" />
- <path
- id="path5211"
- d="m 22,1048.3622 0,-8 -2,0 0,4 0,4 2,0 z m -2,-4 -4,-4 0,3 -13,0 0,2 13,0 0,3 4,-4 z"
- style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- inkscape:connector-curvature="0" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/toggleextrakeys.png b/systemvm/agent/noVNC/app/images/toggleextrakeys.png
new file mode 100644
index 0000000..0f80f6d
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/toggleextrakeys.png differ
diff --git a/systemvm/agent/noVNC/app/images/toggleextrakeys.svg b/systemvm/agent/noVNC/app/images/toggleextrakeys.svg
deleted file mode 100644
index b578c0d..0000000
--- a/systemvm/agent/noVNC/app/images/toggleextrakeys.svg
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="extrakeys.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="15.234555"
- inkscape:cy="9.9710826"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="false">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="m 8,1031.3622 c -2.1987124,0 -4,1.8013 -4,4 l 0,8.9996 c 0,2.1987 1.8012876,4 4,4 l 9,0 c 2.198712,0 4,-1.8013 4,-4 l 0,-8.9996 c 0,-2.1987 -1.801288,-4 -4,-4 z m 0,2 9,0 c 1.125307,0 2,0.8747 2,2 l 0,7.0005 c 0,1.1253 -0.874693,2 -2,2 l -9,0 c -1.1253069,0 -2,-0.8747 -2,-2 l 0,-7.0005 c 0,-1.1253 0.8746931,-2 2,-2 z"
- id="rect5006"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ssssssssssssssssss" />
- <g
- style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10px;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'Sans Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- id="text4167"
- transform="matrix(0.96021948,0,0,0.96021948,0.18921715,41.80659)">
- <path
- d="m 14.292969,1040.6791 -2.939453,0 -0.463868,1.3281 -1.889648,0 2.700195,-7.29 2.241211,0 2.700196,7.29 -1.889649,0 -0.458984,-1.3281 z m -2.470703,-1.3526 1.99707,0 -0.996094,-2.9004 -1.000976,2.9004 z"
- id="path4172"
- inkscape:connector-curvature="0" />
- </g>
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/warning.png b/systemvm/agent/noVNC/app/images/warning.png
new file mode 100644
index 0000000..e9dd550
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/warning.png differ
diff --git a/systemvm/agent/noVNC/app/images/warning.svg b/systemvm/agent/noVNC/app/images/warning.svg
deleted file mode 100644
index 7114f9b..0000000
--- a/systemvm/agent/noVNC/app/images/warning.svg
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="25"
- height="25"
- viewBox="0 0 25 25"
- id="svg2"
- version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="warning.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs4" />
- <sodipodi:namedview
- id="base"
- pagecolor="#959595"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="16.457343"
- inkscape:cy="12.179552"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- units="px"
- inkscape:snap-bbox="true"
- inkscape:bbox-paths="true"
- inkscape:bbox-nodes="true"
- inkscape:snap-bbox-edge-midpoints="true"
- inkscape:object-paths="true"
- showguides="false"
- inkscape:window-width="1920"
- inkscape:window-height="1136"
- inkscape:window-x="1920"
- inkscape:window-y="27"
- inkscape:window-maximized="1"
- inkscape:snap-smooth-nodes="true"
- inkscape:object-nodes="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-nodes="true"
- inkscape:snap-global="true">
- <inkscape:grid
- type="xygrid"
- id="grid4136" />
- </sodipodi:namedview>
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-1027.3622)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonze [...]
- d="M 12.513672 3.0019531 C 11.751609 2.9919531 11.052563 3.4242687 10.710938 4.1054688 L 3.2109375 19.105469 C 2.5461937 20.435369 3.5132277 21.9999 5 22 L 20 22 C 21.486772 21.9999 22.453806 20.435369 21.789062 19.105469 L 14.289062 4.1054688 C 13.951849 3.4330688 13.265888 3.0066531 12.513672 3.0019531 z M 12.478516 6.9804688 A 1.50015 1.50015 0 0 1 14 8.5 L 14 14.5 A 1.50015 1.50015 0 1 1 11 14.5 L 11 8.5 A 1.50015 1.50015 0 0 1 12.478516 6.9804688 z M 12.5 17 A 1.5 1.5 0 0 1 1 [...]
- transform="translate(0,1027.3622)"
- id="path4208" />
- </g>
-</svg>
diff --git a/systemvm/agent/noVNC/app/images/windows.png b/systemvm/agent/noVNC/app/images/windows.png
new file mode 100644
index 0000000..036e1ae
Binary files /dev/null and b/systemvm/agent/noVNC/app/images/windows.png differ
diff --git a/systemvm/agent/noVNC/app/images/windows.svg b/systemvm/agent/noVNC/app/images/windows.svg
deleted file mode 100644
index 270405c..0000000
--- a/systemvm/agent/noVNC/app/images/windows.svg
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- version="1.1"
- id="svg2"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- sodipodi:docname="windows.svg"
- inkscape:export-filename="/home/ossman/devel/noVNC/images/drag.png"
- inkscape:version="0.92.3 (2405546, 2018-03-11)"
- x="0px"
- y="0px"
- viewBox="-293 384 25 23"
- xml:space="preserve"
- width="25"
- height="23"><metadata
- id="metadata21"><rdf:RDF><cc:Work
- rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
- id="defs19" /><sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1920"
- inkscape:window-height="1017"
- id="namedview17"
- showgrid="false"
- inkscape:pagecheckerboard="true"
- inkscape:zoom="9.44"
- inkscape:cx="-0.84745763"
- inkscape:cy="12.5"
- inkscape:window-x="2552"
- inkscape:window-y="122"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg2" />
-<style
- type="text/css"
- id="style2">
- .st0{fill:#FFFFFF;}
-</style>
-<g
- id="g14"
- transform="matrix(1.2624869,0,0,1.3601695,73.614445,-144.84322)">
- <g
- id="g12">
- <path
- class="st0"
- d="m -277.4,396 c -0.7,0 -1.3,0 -2,0 -0.4,0 -0.5,-0.1 -0.5,-0.5 0,-1 0,-2 0,-3 0,-0.3 0.2,-0.5 0.5,-0.5 1.3,-0.1 2.6,-0.3 3.9,-0.4 0.4,0 0.7,0.1 0.7,0.6 0,1.1 0,2.2 0,3.3 0,0.4 -0.2,0.6 -0.6,0.6 -0.7,-0.1 -1.4,-0.1 -2,-0.1 z"
- id="path4"
- inkscape:connector-curvature="0"
- style="fill:#ffffff" />
- <path
- class="st0"
- d="m -274.9,399.3 c 0,0.6 0,1.1 0,1.7 0,0.4 -0.1,0.6 -0.6,0.6 -1.4,-0.1 -2.8,-0.3 -4.1,-0.4 -0.3,0 -0.4,-0.3 -0.4,-0.5 0,-1 0,-2 0,-3 0,-0.4 0.2,-0.5 0.6,-0.5 1.3,0 2.6,0 3.9,0 0.5,0 0.6,0.2 0.6,0.6 0,0.4 0,0.9 0,1.5 z"
- id="path6"
- inkscape:connector-curvature="0"
- style="fill:#ffffff" />
- <path
- class="st0"
- d="m -283.5,396 c -0.6,0 -1.3,0 -1.9,0 -0.4,0 -0.6,-0.1 -0.6,-0.6 0,-0.8 0,-1.5 0,-2.3 0,-0.4 0.2,-0.6 0.6,-0.7 1.3,-0.1 2.7,-0.3 4,-0.4 0.4,0 0.5,0.1 0.5,0.5 0,1 0,1.9 0,2.9 0,0.4 -0.2,0.5 -0.5,0.5 -0.8,0.1 -1.5,0.1 -2.1,0.1 z"
- id="path8"
- inkscape:connector-curvature="0"
- style="fill:#ffffff" />
- <path
- class="st0"
- d="m -283.5,397 c 0.6,0 1.3,0 1.9,0 0.4,0 0.6,0.1 0.6,0.5 0,1 0,1.9 0,2.9 0,0.4 -0.2,0.5 -0.5,0.5 -1.3,-0.1 -2.7,-0.3 -4,-0.4 -0.4,0 -0.6,-0.2 -0.6,-0.7 0,-0.7 0,-1.5 0,-2.2 0,-0.5 0.2,-0.7 0.7,-0.7 0.6,0.1 1.2,0.1 1.9,0.1 z"
- id="path10"
- inkscape:connector-curvature="0"
- style="fill:#ffffff" />
- </g>
-</g>
-</svg>
\ No newline at end of file
diff --git a/systemvm/agent/noVNC/app/locale/README b/systemvm/agent/noVNC/app/locale/README
new file mode 100644
index 0000000..ca4f548
--- /dev/null
+++ b/systemvm/agent/noVNC/app/locale/README
@@ -0,0 +1 @@
+DO NOT MODIFY THE FILES IN THIS FOLDER, THEY ARE AUTOMATICALLY GENERATED FROM THE PO-FILES.
diff --git a/systemvm/agent/noVNC/app/locale/ja.json b/systemvm/agent/noVNC/app/locale/ja.json
new file mode 100644
index 0000000..e5fe340
--- /dev/null
+++ b/systemvm/agent/noVNC/app/locale/ja.json
@@ -0,0 +1,73 @@
+{
+ "Connecting...": "接続しています...",
+ "Disconnecting...": "切断しています...",
+ "Reconnecting...": "再接続しています...",
+ "Internal error": "内部エラー",
+ "Must set host": "ホストを設定する必要があります",
+ "Connected (encrypted) to ": "接続しました (暗号化済み): ",
+ "Connected (unencrypted) to ": "接続しました (暗号化されていません): ",
+ "Something went wrong, connection is closed": "何かが問題で、接続が閉じられました",
+ "Failed to connect to server": "サーバーへの接続に失敗しました",
+ "Disconnected": "切断しました",
+ "New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ",
+ "New connection has been rejected": "新規接続は拒否されました",
+ "Password is required": "パスワードが必要です",
+ "noVNC encountered an error:": "noVNC でエラーが発生しました:",
+ "Hide/Show the control bar": "コントロールバーを隠す/表示する",
+ "Move/Drag Viewport": "ビューポートを移動/ドラッグ",
+ "viewport drag": "ビューポートをドラッグ",
+ "Active Mouse Button": "アクティブなマウスボタン",
+ "No mousebutton": "マウスボタンなし",
+ "Left mousebutton": "左マウスボタン",
+ "Middle mousebutton": "中マウスボタン",
+ "Right mousebutton": "右マウスボタン",
+ "Keyboard": "キーボード",
+ "Show Keyboard": "キーボードを表示",
+ "Extra keys": "追加キー",
+ "Show Extra Keys": "追加キーを表示",
+ "Ctrl": "Ctrl",
+ "Toggle Ctrl": "Ctrl キーを切り替え",
+ "Alt": "Alt",
+ "Toggle Alt": "Alt キーを切り替え",
+ "Toggle Windows": "Windows キーを切り替え",
+ "Windows": "Windows",
+ "Send Tab": "Tab キーを送信",
+ "Tab": "Tab",
+ "Esc": "Esc",
+ "Send Escape": "Escape キーを送信",
+ "Ctrl+Alt+Del": "Ctrl+Alt+Del",
+ "Send Ctrl-Alt-Del": "Ctrl-Alt-Del を送信",
+ "Shutdown/Reboot": "シャットダウン/再起動",
+ "Shutdown/Reboot...": "シャットダウン/再起動...",
+ "Power": "電源",
+ "Shutdown": "シャットダウン",
+ "Reboot": "再起動",
+ "Reset": "リセット",
+ "Clipboard": "クリップボード",
+ "Clear": "クリア",
+ "Fullscreen": "全画面表示",
+ "Settings": "設定",
+ "Shared Mode": "共有モード",
+ "View Only": "表示のみ",
+ "Clip to Window": "ウィンドウにクリップ",
+ "Scaling Mode:": "スケーリングモード:",
+ "None": "なし",
+ "Local Scaling": "ローカルスケーリング",
+ "Remote Resizing": "リモートでリサイズ",
+ "Advanced": "高度",
+ "Repeater ID:": "リピーター ID:",
+ "WebSocket": "WebSocket",
+ "Encrypt": "暗号化",
+ "Host:": "ホスト:",
+ "Port:": "ポート:",
+ "Path:": "パス:",
+ "Automatic Reconnect": "自動再接続",
+ "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):",
+ "Show Dot when No Cursor": "カーソルがないときにドットを表示",
+ "Logging:": "ロギング:",
+ "Disconnect": "切断",
+ "Connect": "接続",
+ "Password:": "パスワード:",
+ "Send Password": "パスワードを送信",
+ "Cancel": "キャンセル"
+}
\ No newline at end of file
diff --git a/systemvm/agent/noVNC/app/locale/sv.json b/systemvm/agent/noVNC/app/locale/sv.json
index d49ea54..e46df45 100644
--- a/systemvm/agent/noVNC/app/locale/sv.json
+++ b/systemvm/agent/noVNC/app/locale/sv.json
@@ -11,16 +11,11 @@
"Disconnected": "Frånkopplad",
"New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ",
"New connection has been rejected": "Ny anslutning har blivit nekad",
- "Password is required": "Lösenord krävs",
+ "Credentials are required": "Användaruppgifter krävs",
"noVNC encountered an error:": "noVNC stötte på ett problem:",
"Hide/Show the control bar": "Göm/Visa kontrollbaren",
+ "Drag": "Dra",
"Move/Drag Viewport": "Flytta/Dra Vyn",
- "viewport drag": "dra vy",
- "Active Mouse Button": "Aktiv musknapp",
- "No mousebutton": "Ingen musknapp",
- "Left mousebutton": "Vänster musknapp",
- "Middle mousebutton": "Mitten-musknapp",
- "Right mousebutton": "Höger musknapp",
"Keyboard": "Tangentbord",
"Show Keyboard": "Visa Tangentbord",
"Extra keys": "Extraknappar",
@@ -55,6 +50,8 @@
"Local Scaling": "Lokal Skalning",
"Remote Resizing": "Ändra Storlek",
"Advanced": "Avancerat",
+ "Quality:": "Kvalitet:",
+ "Compression level:": "Kompressionsnivå:",
"Repeater ID:": "Repeater-ID:",
"WebSocket": "WebSocket",
"Encrypt": "Kryptera",
@@ -65,9 +62,11 @@
"Reconnect Delay (ms):": "Fördröjning (ms):",
"Show Dot when No Cursor": "Visa prick när ingen muspekare finns",
"Logging:": "Loggning:",
+ "Version:": "Version:",
"Disconnect": "Koppla från",
"Connect": "Anslut",
+ "Username:": "Användarnamn:",
"Password:": "Lösenord:",
- "Send Password": "Skicka lösenord",
+ "Send Credentials": "Skicka Användaruppgifter",
"Cancel": "Avbryt"
}
\ No newline at end of file
diff --git a/systemvm/agent/noVNC/app/locale/zh_CN.json b/systemvm/agent/noVNC/app/locale/zh_CN.json
index b669956..f0aea9a 100644
--- a/systemvm/agent/noVNC/app/locale/zh_CN.json
+++ b/systemvm/agent/noVNC/app/locale/zh_CN.json
@@ -1,19 +1,19 @@
{
- "Connecting...": "链接中...",
- "Disconnecting...": "正在中断连接...",
- "Reconnecting...": "重新链接中...",
+ "Connecting...": "连接中...",
+ "Disconnecting...": "正在断开连接...",
+ "Reconnecting...": "重新连接中...",
"Internal error": "内部错误",
"Must set host": "请提供主机名",
- "Connected (encrypted) to ": "已加密链接到",
- "Connected (unencrypted) to ": "未加密链接到",
- "Something went wrong, connection is closed": "发生错误,链接已关闭",
- "Failed to connect to server": "无法链接到服务器",
- "Disconnected": "链接已中断",
- "New connection has been rejected with reason: ": "链接被拒绝,原因:",
- "New connection has been rejected": "链接被拒绝",
+ "Connected (encrypted) to ": "已连接到(加密)",
+ "Connected (unencrypted) to ": "已连接到(未加密)",
+ "Something went wrong, connection is closed": "发生错误,连接已关闭",
+ "Failed to connect to server": "无法连接到服务器",
+ "Disconnected": "已断开连接",
+ "New connection has been rejected with reason: ": "连接被拒绝,原因:",
+ "New connection has been rejected": "连接被拒绝",
"Password is required": "请提供密码",
"noVNC encountered an error:": "noVNC 遇到一个错误:",
- "Hide/Show the control bar": "显示/隐藏控制列",
+ "Hide/Show the control bar": "显示/隐藏控制栏",
"Move/Drag Viewport": "拖放显示范围",
"viewport drag": "显示范围拖放",
"Active Mouse Button": "启动鼠标按鍵",
@@ -43,10 +43,10 @@
"Reset": "重置",
"Clipboard": "剪贴板",
"Clear": "清除",
- "Fullscreen": "全屏幕",
+ "Fullscreen": "全屏",
"Settings": "设置",
"Shared Mode": "分享模式",
- "View Only": "仅检视",
+ "View Only": "仅查看",
"Clip to Window": "限制/裁切窗口大小",
"Scaling Mode:": "缩放模式:",
"None": "无",
@@ -59,11 +59,11 @@
"Host:": "主机:",
"Port:": "端口:",
"Path:": "路径:",
- "Automatic Reconnect": "自动重新链接",
- "Reconnect Delay (ms):": "重新链接间隔 (ms):",
+ "Automatic Reconnect": "自动重新连接",
+ "Reconnect Delay (ms):": "重新连接间隔 (ms):",
"Logging:": "日志级别:",
- "Disconnect": "终端链接",
- "Connect": "链接",
+ "Disconnect": "中断连接",
+ "Connect": "连接",
"Password:": "密码:",
"Cancel": "取消"
}
\ No newline at end of file
diff --git a/systemvm/agent/noVNC/app/styles/base.css b/systemvm/agent/noVNC/app/styles/base.css
index 3ca9894..fd78b79 100644
--- a/systemvm/agent/noVNC/app/styles/base.css
+++ b/systemvm/agent/noVNC/app/styles/base.css
@@ -1,6 +1,6 @@
/*
* noVNC base CSS
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* noVNC is licensed under the MPL 2.0 (see LICENSE.txt)
* This file is licensed under the 2-Clause BSD license (see LICENSE.txt).
*/
@@ -83,8 +83,20 @@ html {
* ----------------------------------------
*/
-input[type=input], input[type=password], input[type=number],
-input:not([type]), textarea {
+input:not([type]),
+input[type=date],
+input[type=datetime-local],
+input[type=email],
+input[type=month],
+input[type=number],
+input[type=password],
+input[type=search],
+input[type=tel],
+input[type=text],
+input[type=time],
+input[type=url],
+input[type=week],
+textarea {
/* Disable default rendering */
-webkit-appearance: none;
-moz-appearance: none;
@@ -98,7 +110,11 @@ input:not([type]), textarea {
background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240));
}
-input[type=button], input[type=submit], select {
+input[type=button],
+input[type=color],
+input[type=reset],
+input[type=submit],
+select {
/* Disable default rendering */
-webkit-appearance: none;
-moz-appearance: none;
@@ -116,7 +132,10 @@ input[type=button], input[type=submit], select {
vertical-align: middle;
}
-input[type=button], input[type=submit] {
+input[type=button],
+input[type=color],
+input[type=reset],
+input[type=submit] {
padding-left: 20px;
padding-right: 20px;
}
@@ -126,35 +145,72 @@ option {
background: white;
}
-input[type=input]:focus, input[type=password]:focus,
-input:not([type]):focus, input[type=button]:focus,
+input:not([type]):focus,
+input[type=button]:focus,
+input[type=color]:focus,
+input[type=date]:focus,
+input[type=datetime-local]:focus,
+input[type=email]:focus,
+input[type=month]:focus,
+input[type=number]:focus,
+input[type=password]:focus,
+input[type=reset]:focus,
+input[type=search]:focus,
input[type=submit]:focus,
-textarea:focus, select:focus {
+input[type=tel]:focus,
+input[type=text]:focus,
+input[type=time]:focus,
+input[type=url]:focus,
+input[type=week]:focus,
+select:focus,
+textarea:focus {
box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5);
border-color: rgb(74, 144, 217);
outline: none;
}
input[type=button]::-moz-focus-inner,
+input[type=color]::-moz-focus-inner,
+input[type=reset]::-moz-focus-inner,
input[type=submit]::-moz-focus-inner {
border: none;
}
-input[type=input]:disabled, input[type=password]:disabled,
-input:not([type]):disabled, input[type=button]:disabled,
-input[type=submit]:disabled, input[type=number]:disabled,
-textarea:disabled, select:disabled {
+input:not([type]):disabled,
+input[type=button]:disabled,
+input[type=color]:disabled,
+input[type=date]:disabled,
+input[type=datetime-local]:disabled,
+input[type=email]:disabled,
+input[type=month]:disabled,
+input[type=number]:disabled,
+input[type=password]:disabled,
+input[type=reset]:disabled,
+input[type=search]:disabled,
+input[type=submit]:disabled,
+input[type=tel]:disabled,
+input[type=text]:disabled,
+input[type=time]:disabled,
+input[type=url]:disabled,
+input[type=week]:disabled,
+select:disabled,
+textarea:disabled {
color: rgb(128, 128, 128);
background: rgb(240, 240, 240);
}
-input[type=button]:active, input[type=submit]:active,
+input[type=button]:active,
+input[type=color]:active,
+input[type=reset]:active,
+input[type=submit]:active,
select:active {
border-bottom-width: 1px;
margin-top: 3px;
}
:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled),
+:root:not(.noVNC_touch) input[type=color]:hover:not(:disabled),
+:root:not(.noVNC_touch) input[type=reset]:hover:not(:disabled),
:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled),
:root:not(.noVNC_touch) select:hover:not(:disabled) {
background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250));
@@ -579,7 +635,7 @@ select:active {
}
/* Extra manual keys */
-:root:not(.noVNC_connected) #noVNC_extra_keys {
+:root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button {
display: none;
}
@@ -631,6 +687,16 @@ select:active {
width: 100px;
}
+/* Version */
+
+.noVNC_version_wrapper {
+ font-size: small;
+}
+
+.noVNC_version {
+ margin-left: 1rem;
+}
+
/* Connection Controls */
:root:not(.noVNC_connected) #noVNC_disconnect_button {
display: none;
@@ -780,19 +846,23 @@ select:active {
* ----------------------------------------
*/
-#noVNC_password_dlg {
+#noVNC_credentials_dlg {
position: relative;
transform: translateY(-50px);
}
-#noVNC_password_dlg.noVNC_open {
+#noVNC_credentials_dlg.noVNC_open {
transform: translateY(0);
}
-#noVNC_password_dlg ul {
+#noVNC_credentials_dlg ul {
list-style: none;
margin: 0px;
padding: 0px;
}
+.noVNC_hidden {
+ display: none;
+}
+
/* ----------------------------------------
* Main Area
diff --git a/systemvm/agent/noVNC/app/ui.js b/systemvm/agent/noVNC/app/ui.js
index 13d1c01..9158c33 100644
--- a/systemvm/agent/noVNC/app/ui.js
+++ b/systemvm/agent/noVNC/app/ui.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -8,7 +8,7 @@
import * as Log from '../core/util/logging.js';
import _, { l10n } from './localization.js';
-import { isTouchDevice, isSafari, isIOS, isAndroid, dragThreshold }
+import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold }
from '../core/util/browser.js';
import { setCapture, getPointerEvent } from '../core/util/events.js';
import KeyTable from "../core/input/keysym.js";
@@ -17,6 +17,8 @@ import Keyboard from "../core/input/keyboard.js";
import RFB from "../core/rfb.js";
import * as WebUtil from "./webutil.js";
+const PAGE_TITLE = "noVNC";
+
const UI = {
connected: false,
@@ -35,9 +37,11 @@ const UI = {
lastKeyboardinput: null,
defaultKeyboardinputLen: 100,
- inhibit_reconnect: true,
- reconnect_callback: null,
- reconnect_password: null,
+ inhibitReconnect: true,
+ reconnectCallback: null,
+ reconnectPassword: null,
+
+ fullScreen: false,
prime() {
return WebUtil.initSettings().then(() => {
@@ -59,6 +63,17 @@ const UI = {
// Translate the DOM
l10n.translateDOM();
+ WebUtil.fetchJSON('./package.json')
+ .then((packageInfo) => {
+ Array.from(document.getElementsByClassName('noVNC_version')).forEach(el => el.innerText = packageInfo.version);
+ })
+ .catch((err) => {
+ Log.Error("Couldn't fetch package.json: " + err);
+ Array.from(document.getElementsByClassName('noVNC_version_wrapper'))
+ .concat(Array.from(document.getElementsByClassName('noVNC_version_separator')))
+ .forEach(el => el.style.display = 'none');
+ });
+
// Adapt the interface for touch screen devices
if (isTouchDevice) {
document.documentElement.classList.add("noVNC_touch");
@@ -145,10 +160,13 @@ const UI = {
/* Populate the controls if defaults are provided in the URL */
UI.initSetting('host', window.location.hostname);
UI.initSetting('port', port);
+ UI.initSetting('token', window.location.token);
UI.initSetting('encrypt', (window.location.protocol === "https:"));
UI.initSetting('view_clip', false);
UI.initSetting('resize', 'off');
- UI.initSetting('shared', false);
+ UI.initSetting('quality', 6);
+ UI.initSetting('compression', 2);
+ UI.initSetting('shared', true);
UI.initSetting('view_only', false);
UI.initSetting('show_dot', false);
UI.initSetting('path', 'websockify');
@@ -219,14 +237,6 @@ const UI = {
},
addTouchSpecificHandlers() {
- document.getElementById("noVNC_mouse_button0")
- .addEventListener('click', () => UI.setMouseButton(1));
- document.getElementById("noVNC_mouse_button1")
- .addEventListener('click', () => UI.setMouseButton(2));
- document.getElementById("noVNC_mouse_button2")
- .addEventListener('click', () => UI.setMouseButton(4));
- document.getElementById("noVNC_mouse_button4")
- .addEventListener('click', () => UI.setMouseButton(0));
document.getElementById("noVNC_keyboard_button")
.addEventListener('click', UI.toggleVirtualKeyboard);
@@ -303,17 +313,17 @@ const UI = {
document.getElementById("noVNC_cancel_reconnect_button")
.addEventListener('click', UI.cancelReconnect);
- document.getElementById("noVNC_password_button")
- .addEventListener('click', UI.setPassword);
+ document.getElementById("noVNC_credentials_button")
+ .addEventListener('click', UI.setCredentials);
},
addClipboardHandlers() {
document.getElementById("noVNC_clipboard_button")
.addEventListener('click', UI.toggleClipboardPanel);
- document.getElementById("noVNC_clipboard_text")
- .addEventListener('change', UI.clipboardSend);
document.getElementById("noVNC_clipboard_clear_button")
.addEventListener('click', UI.clipboardClear);
+ document.getElementById("noVNC_clipboard_send_button")
+ .addEventListener('click', UI.clipboardSend);
},
// Add a call to save settings when the element changes,
@@ -334,6 +344,10 @@ const UI = {
UI.addSettingChangeHandler('resize');
UI.addSettingChangeHandler('resize', UI.applyResizeMode);
UI.addSettingChangeHandler('resize', UI.updateViewClip);
+ UI.addSettingChangeHandler('quality');
+ UI.addSettingChangeHandler('quality', UI.updateQuality);
+ UI.addSettingChangeHandler('compression');
+ UI.addSettingChangeHandler('compression', UI.updateCompression);
UI.addSettingChangeHandler('view_clip');
UI.addSettingChangeHandler('view_clip', UI.updateViewClip);
UI.addSettingChangeHandler('shared');
@@ -375,25 +389,25 @@ const UI = {
document.documentElement.classList.remove("noVNC_disconnecting");
document.documentElement.classList.remove("noVNC_reconnecting");
- const transition_elem = document.getElementById("noVNC_transition_text");
+ const transitionElem = document.getElementById("noVNC_transition_text");
switch (state) {
case 'init':
break;
case 'connecting':
- transition_elem.textContent = _("Connecting...");
+ transitionElem.textContent = _("Connecting...");
document.documentElement.classList.add("noVNC_connecting");
break;
case 'connected':
document.documentElement.classList.add("noVNC_connected");
break;
case 'disconnecting':
- transition_elem.textContent = _("Disconnecting...");
+ transitionElem.textContent = _("Disconnecting...");
document.documentElement.classList.add("noVNC_disconnecting");
break;
case 'disconnected':
break;
case 'reconnecting':
- transition_elem.textContent = _("Reconnecting...");
+ transitionElem.textContent = _("Reconnecting...");
document.documentElement.classList.add("noVNC_reconnecting");
break;
default:
@@ -411,7 +425,6 @@ const UI = {
UI.disableSetting('port');
UI.disableSetting('path');
UI.disableSetting('repeaterID');
- UI.setMouseButton(1);
// Hide the controlbar after 2 seconds
UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000);
@@ -426,38 +439,35 @@ const UI = {
UI.keepControlbar();
}
- // State change closes the password dialog
- document.getElementById('noVNC_password_dlg')
+ // State change closes dialogs as they may not be relevant
+ // anymore
+ UI.closeAllPanels();
+ document.getElementById('noVNC_credentials_dlg')
.classList.remove('noVNC_open');
},
- showStatus(text, status_type, time) {
+ showStatus(text, statusType, time) {
const statusElem = document.getElementById('noVNC_status');
- clearTimeout(UI.statusTimeout);
-
- if (typeof status_type === 'undefined') {
- status_type = 'normal';
+ if (typeof statusType === 'undefined') {
+ statusType = 'normal';
}
// Don't overwrite more severe visible statuses and never
// errors. Only shows the first error.
- let visible_status_type = 'none';
if (statusElem.classList.contains("noVNC_open")) {
if (statusElem.classList.contains("noVNC_status_error")) {
- visible_status_type = 'error';
- } else if (statusElem.classList.contains("noVNC_status_warn")) {
- visible_status_type = 'warn';
- } else {
- visible_status_type = 'normal';
+ return;
+ }
+ if (statusElem.classList.contains("noVNC_status_warn") &&
+ statusType === 'normal') {
+ return;
}
}
- if (visible_status_type === 'error' ||
- (visible_status_type === 'warn' && status_type === 'normal')) {
- return;
- }
- switch (status_type) {
+ clearTimeout(UI.statusTimeout);
+
+ switch (statusType) {
case 'error':
statusElem.classList.remove("noVNC_status_warn");
statusElem.classList.remove("noVNC_status_normal");
@@ -487,7 +497,7 @@ const UI = {
}
// Error messages do not timeout
- if (status_type !== 'error') {
+ if (statusType !== 'error') {
UI.statusTimeout = window.setTimeout(UI.hideStatus, time);
}
},
@@ -507,6 +517,13 @@ const UI = {
},
idleControlbar() {
+ // Don't fade if a child of the control bar has focus
+ if (document.getElementById('noVNC_control_bar')
+ .contains(document.activeElement) && document.hasFocus()) {
+ UI.activateControlbar();
+ return;
+ }
+
document.getElementById('noVNC_control_bar_anchor')
.classList.add("noVNC_idle");
},
@@ -524,6 +541,7 @@ const UI = {
UI.closeAllPanels();
document.getElementById('noVNC_control_bar')
.classList.remove("noVNC_open");
+ UI.rfb.focus();
},
toggleControlbar() {
@@ -821,6 +839,8 @@ const UI = {
UI.updateSetting('encrypt');
UI.updateSetting('view_clip');
UI.updateSetting('resize');
+ UI.updateSetting('quality');
+ UI.updateSetting('compression');
UI.updateSetting('shared');
UI.updateSetting('view_only');
UI.updateSetting('path');
@@ -927,6 +947,8 @@ const UI = {
UI.closeClipboardPanel();
} else {
UI.openClipboardPanel();
+ setTimeout(() => document
+ .getElementById('noVNC_clipboard_text').focus(), 100);
}
},
@@ -938,14 +960,13 @@ const UI = {
clipboardClear() {
document.getElementById('noVNC_clipboard_text').value = "";
- UI.rfb.clipboardPasteFrom("");
},
clipboardSend() {
const text = document.getElementById('noVNC_clipboard_text').value;
- Log.Debug(">> UI.clipboardSend: " + text.substr(0, 40) + "...");
- UI.rfb.clipboardPasteFrom(text);
- Log.Debug("<< UI.clipboardSend");
+ UI.rfb.sendText(text);
+ UI.closeClipboardPanel();
+ UI.focusOnConsole();
},
/* ------^-------
@@ -974,10 +995,11 @@ const UI = {
const host = UI.getSetting('host');
const port = UI.getSetting('port');
const path = UI.getSetting('path');
+ const token = UI.getSetting('token')
if (typeof password === 'undefined') {
password = WebUtil.getConfigVar('password');
- UI.reconnect_password = password;
+ UI.reconnectPassword = password;
}
if (password === null) {
@@ -992,7 +1014,6 @@ const UI = {
return;
}
- UI.closeAllPanels();
UI.closeConnectPanel();
UI.updateVisualState('connecting');
@@ -1006,16 +1027,10 @@ const UI = {
url += ':' + port;
}
url += '/' + path;
-
- var urlParams = new URLSearchParams(window.location.search);
- var param = urlParams.get('token');
- if (param) {
- url += "?token=" + param
- }
+ url += '?token=' + token;
UI.rfb = new RFB(document.getElementById('noVNC_container'), url,
{ shared: UI.getSetting('shared'),
- showDotCursor: UI.getSetting('show_dot'),
repeaterID: UI.getSetting('repeaterID'),
credentials: { password: password } });
UI.rfb.addEventListener("connect", UI.connectFinished);
@@ -1029,18 +1044,20 @@ const UI = {
UI.rfb.clipViewport = UI.getSetting('view_clip');
UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale';
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
+ UI.rfb.qualityLevel = parseInt(UI.getSetting('quality'));
+ UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
+ UI.rfb.showDotCursor = UI.getSetting('show_dot');
UI.updateViewOnly(); // requires UI.rfb
},
disconnect() {
- UI.closeAllPanels();
UI.rfb.disconnect();
UI.connected = false;
// Disable automatic reconnecting
- UI.inhibit_reconnect = true;
+ UI.inhibitReconnect = true;
UI.updateVisualState('disconnecting');
@@ -1048,20 +1065,20 @@ const UI = {
},
reconnect() {
- UI.reconnect_callback = null;
+ UI.reconnectCallback = null;
// if reconnect has been disabled in the meantime, do nothing.
- if (UI.inhibit_reconnect) {
+ if (UI.inhibitReconnect) {
return;
}
- UI.connect(null, UI.reconnect_password);
+ UI.connect(null, UI.reconnectPassword);
},
cancelReconnect() {
- if (UI.reconnect_callback !== null) {
- clearTimeout(UI.reconnect_callback);
- UI.reconnect_callback = null;
+ if (UI.reconnectCallback !== null) {
+ clearTimeout(UI.reconnectCallback);
+ UI.reconnectCallback = null;
}
UI.updateVisualState('disconnected');
@@ -1072,13 +1089,13 @@ const UI = {
connectFinished(e) {
UI.connected = true;
- UI.inhibit_reconnect = false;
+ UI.inhibitReconnect = false;
let msg;
if (UI.getSetting('encrypt')) {
- msg = _("Connected (encrypted) to ") + UI.desktopName;
+ msg = _("Connected");
} else {
- msg = _("Connected (unencrypted) to ") + UI.desktopName;
+ msg = _("Connected")
}
UI.showStatus(msg);
UI.updateVisualState('connected');
@@ -1106,17 +1123,19 @@ const UI = {
} else {
UI.showStatus(_("Failed to connect to server"), 'error');
}
- } else if (UI.getSetting('reconnect', false) === true && !UI.inhibit_reconnect) {
+ } else if (UI.getSetting('reconnect', false) === true && !UI.inhibitReconnect) {
UI.updateVisualState('reconnecting');
const delay = parseInt(UI.getSetting('reconnect_delay'));
- UI.reconnect_callback = setTimeout(UI.reconnect, delay);
+ UI.reconnectCallback = setTimeout(UI.reconnect, delay);
return;
} else {
UI.updateVisualState('disconnected');
UI.showStatus(_("Disconnected"), 'normal');
}
+ document.title = PAGE_TITLE;
+
UI.openControlbar();
UI.openConnectPanel();
},
@@ -1143,27 +1162,46 @@ const UI = {
credentials(e) {
// FIXME: handle more types
- document.getElementById('noVNC_password_dlg')
+
+ document.getElementById("noVNC_username_block").classList.remove("noVNC_hidden");
+ document.getElementById("noVNC_password_block").classList.remove("noVNC_hidden");
+
+ let inputFocus = "none";
+ if (e.detail.types.indexOf("username") === -1) {
+ document.getElementById("noVNC_username_block").classList.add("noVNC_hidden");
+ } else {
+ inputFocus = inputFocus === "none" ? "noVNC_username_input" : inputFocus;
+ }
+ if (e.detail.types.indexOf("password") === -1) {
+ document.getElementById("noVNC_password_block").classList.add("noVNC_hidden");
+ } else {
+ inputFocus = inputFocus === "none" ? "noVNC_password_input" : inputFocus;
+ }
+ document.getElementById('noVNC_credentials_dlg')
.classList.add('noVNC_open');
setTimeout(() => document
- .getElementById('noVNC_password_input').focus(), 100);
+ .getElementById(inputFocus).focus(), 100);
- Log.Warn("Server asked for a password");
- UI.showStatus(_("Password is required"), "warning");
+ Log.Warn("Server asked for credentials");
+ UI.showStatus(_("Credentials are required"), "warning");
},
- setPassword(e) {
+ setCredentials(e) {
// Prevent actually submitting the form
e.preventDefault();
- const inputElem = document.getElementById('noVNC_password_input');
- const password = inputElem.value;
+ let inputElemUsername = document.getElementById('noVNC_username_input');
+ const username = inputElemUsername.value;
+
+ let inputElemPassword = document.getElementById('noVNC_password_input');
+ const password = inputElemPassword.value;
// Clear the input after reading the password
- inputElem.value = "";
- UI.rfb.sendCredentials({ password: password });
- UI.reconnect_password = password;
- document.getElementById('noVNC_password_dlg')
+ inputElemPassword.value = "";
+
+ UI.rfb.sendCredentials({ username: username, password: password });
+ UI.reconnectPassword = password;
+ document.getElementById('noVNC_credentials_dlg')
.classList.remove('noVNC_open');
},
@@ -1174,38 +1212,14 @@ const UI = {
* ------v------*/
toggleFullscreen() {
- if (document.fullscreenElement || // alternative standard method
- document.mozFullScreenElement || // currently working methods
- document.webkitFullscreenElement ||
- document.msFullscreenElement) {
- if (document.exitFullscreen) {
- document.exitFullscreen();
- } else if (document.mozCancelFullScreen) {
- document.mozCancelFullScreen();
- } else if (document.webkitExitFullscreen) {
- document.webkitExitFullscreen();
- } else if (document.msExitFullscreen) {
- document.msExitFullscreen();
- }
- } else {
- if (document.documentElement.requestFullscreen) {
- document.documentElement.requestFullscreen();
- } else if (document.documentElement.mozRequestFullScreen) {
- document.documentElement.mozRequestFullScreen();
- } else if (document.documentElement.webkitRequestFullscreen) {
- document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
- } else if (document.body.msRequestFullscreen) {
- document.body.msRequestFullscreen();
- }
- }
- UI.updateFullscreenButton();
+ this.fullScreen = !this.fullScreen
+ UI.rfb.scaleViewport = this.fullScreen
+ UI.updateFullscreenButton(this.fullScreen);
+ UI.focusOnConsole();
},
- updateFullscreenButton() {
- if (document.fullscreenElement || // alternative standard method
- document.mozFullScreenElement || // currently working methods
- document.webkitFullscreenElement ||
- document.msFullscreenElement ) {
+ updateFullscreenButton(fullScreen) {
+ if (fullScreen) {
document.getElementById('noVNC_fullscreen_button')
.classList.add("noVNC_selected");
} else {
@@ -1246,8 +1260,9 @@ const UI = {
// Can't be clipping if viewport is scaled to fit
UI.forceSetting('view_clip', false);
UI.rfb.clipViewport = false;
- } else if (isIOS() || isAndroid()) {
- // iOS and Android usually have shit scrollbars
+ } else if (!hasScrollbarGutter) {
+ // Some platforms have scrollbars that are difficult
+ // to use in our case, so we always use our own panning
UI.forceSetting('view_clip', true);
UI.rfb.clipViewport = true;
} else {
@@ -1290,30 +1305,40 @@ const UI = {
viewDragButton.classList.remove("noVNC_selected");
}
- // Different behaviour for touch vs non-touch
- // The button is disabled instead of hidden on touch devices
- if (isTouchDevice) {
+ if (UI.rfb.clipViewport) {
viewDragButton.classList.remove("noVNC_hidden");
-
- if (UI.rfb.clipViewport) {
- viewDragButton.disabled = false;
- } else {
- viewDragButton.disabled = true;
- }
} else {
- viewDragButton.disabled = false;
-
- if (UI.rfb.clipViewport) {
- viewDragButton.classList.remove("noVNC_hidden");
- } else {
- viewDragButton.classList.add("noVNC_hidden");
- }
+ viewDragButton.classList.add("noVNC_hidden");
}
},
/* ------^-------
* /VIEWDRAG
* ==============
+ * QUALITY
+ * ------v------*/
+
+ updateQuality() {
+ if (!UI.rfb) return;
+
+ UI.rfb.qualityLevel = parseInt(UI.getSetting('quality'));
+ },
+
+/* ------^-------
+ * /QUALITY
+ * ==============
+ * COMPRESSION
+ * ------v------*/
+
+ updateCompression() {
+ if (!UI.rfb) return;
+
+ UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
+ },
+
+/* ------^-------
+ * /COMPRESSION
+ * ==============
* KEYBOARD
* ------v------*/
@@ -1508,20 +1533,20 @@ const UI = {
},
sendEsc() {
- UI.rfb.sendKey(KeyTable.XK_Escape, "Escape");
+ UI.sendKey(KeyTable.XK_Escape, "Escape");
},
sendTab() {
- UI.rfb.sendKey(KeyTable.XK_Tab);
+ UI.sendKey(KeyTable.XK_Tab, "Tab");
},
toggleCtrl() {
const btn = document.getElementById('noVNC_toggle_ctrl_button');
if (btn.classList.contains("noVNC_selected")) {
- UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", false);
+ UI.sendKey(KeyTable.XK_Control_L, "ControlLeft", false);
btn.classList.remove("noVNC_selected");
} else {
- UI.rfb.sendKey(KeyTable.XK_Control_L, "ControlLeft", true);
+ UI.sendKey(KeyTable.XK_Control_L, "ControlLeft", true);
btn.classList.add("noVNC_selected");
}
},
@@ -1529,10 +1554,10 @@ const UI = {
toggleWindows() {
const btn = document.getElementById('noVNC_toggle_windows_button');
if (btn.classList.contains("noVNC_selected")) {
- UI.rfb.sendKey(KeyTable.XK_Super_L, "MetaLeft", false);
+ UI.sendKey(KeyTable.XK_Super_L, "MetaLeft", false);
btn.classList.remove("noVNC_selected");
} else {
- UI.rfb.sendKey(KeyTable.XK_Super_L, "MetaLeft", true);
+ UI.sendKey(KeyTable.XK_Super_L, "MetaLeft", true);
btn.classList.add("noVNC_selected");
}
},
@@ -1540,16 +1565,42 @@ const UI = {
toggleAlt() {
const btn = document.getElementById('noVNC_toggle_alt_button');
if (btn.classList.contains("noVNC_selected")) {
- UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", false);
+ UI.sendKey(KeyTable.XK_Alt_L, "AltLeft", false);
btn.classList.remove("noVNC_selected");
} else {
- UI.rfb.sendKey(KeyTable.XK_Alt_L, "AltLeft", true);
+ UI.sendKey(KeyTable.XK_Alt_L, "AltLeft", true);
btn.classList.add("noVNC_selected");
}
},
sendCtrlAltDel() {
UI.rfb.sendCtrlAltDel();
+ // See below
+ UI.rfb.focus();
+ UI.idleControlbar();
+ },
+
+ // Move focus to the screen in order to be able to use the
+ // keyboard right after these extra keys.
+ // The exception is when a virtual keyboard is used, because
+ // if we focus the screen the virtual keyboard would be closed.
+ // In this case we focus our special virtual keyboard input
+ // element instead.
+ focusOnConsole() {
+ if (document.getElementById('noVNC_keyboard_button')
+ .classList.contains("noVNC_selected")) {
+ document.getElementById('noVNC_keyboardinput').focus();
+ } else {
+ UI.rfb.focus();
+ }
+ },
+
+ sendKey(keysym, code, down) {
+ UI.rfb.sendKey(keysym, code, down);
+ UI.focusOnConsole()
+ // fade out the controlbar to highlight that
+ // the focus has been moved to the screen
+ UI.idleControlbar();
},
/* ------^-------
@@ -1558,24 +1609,6 @@ const UI = {
* MISC
* ------v------*/
- setMouseButton(num) {
- const view_only = UI.rfb.viewOnly;
- if (UI.rfb && !view_only) {
- UI.rfb.touchButton = num;
- }
-
- const blist = [0, 1, 2, 4];
- for (let b = 0; b < blist.length; b++) {
- const button = document.getElementById('noVNC_mouse_button' +
- blist[b]);
- if (blist[b] === num && !view_only) {
- button.classList.remove("noVNC_hidden");
- } else {
- button.classList.add("noVNC_hidden");
- }
- }
- },
-
updateViewOnly() {
if (!UI.rfb) return;
UI.rfb.viewOnly = UI.getSetting('view_only');
@@ -1586,14 +1619,14 @@ const UI = {
.classList.add('noVNC_hidden');
document.getElementById('noVNC_toggle_extra_keys_button')
.classList.add('noVNC_hidden');
- document.getElementById('noVNC_mouse_button' + UI.rfb.touchButton)
+ document.getElementById('noVNC_clipboard_button')
.classList.add('noVNC_hidden');
} else {
document.getElementById('noVNC_keyboard_button')
.classList.remove('noVNC_hidden');
document.getElementById('noVNC_toggle_extra_keys_button')
.classList.remove('noVNC_hidden');
- document.getElementById('noVNC_mouse_button' + UI.rfb.touchButton)
+ document.getElementById('noVNC_clipboard_button')
.classList.remove('noVNC_hidden');
}
},
@@ -1604,13 +1637,13 @@ const UI = {
},
updateLogging() {
- WebUtil.init_logging(UI.getSetting('logging'));
+ WebUtil.initLogging(UI.getSetting('logging'));
},
updateDesktopName(e) {
UI.desktopName = e.detail.name;
// Display the desktop name in the document title
- document.title = e.detail.name + " - noVNC";
+ document.title = e.detail.name + " - " + PAGE_TITLE;
},
bell(e) {
@@ -1646,7 +1679,7 @@ const UI = {
};
// Set up translations
-const LINGUAS = ["cs", "de", "el", "es", "ko", "nl", "pl", "ru", "sv", "tr", "zh_CN", "zh_TW"];
+const LINGUAS = ["cs", "de", "el", "es", "ja", "ko", "nl", "pl", "ru", "sv", "tr", "zh_CN", "zh_TW"];
l10n.setup(LINGUAS);
if (l10n.language === "en" || l10n.dictionary !== undefined) {
UI.prime();
diff --git a/systemvm/agent/noVNC/app/webutil.js b/systemvm/agent/noVNC/app/webutil.js
index 98e1d9e..568f0e2 100644
--- a/systemvm/agent/noVNC/app/webutil.js
+++ b/systemvm/agent/noVNC/app/webutil.js
@@ -1,21 +1,21 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*/
-import { init_logging as main_init_logging } from '../core/util/logging.js';
+import { initLogging as mainInitLogging } from '../core/util/logging.js';
// init log level reading the logging HTTP param
-export function init_logging(level) {
+export function initLogging(level) {
"use strict";
if (typeof level !== "undefined") {
- main_init_logging(level);
+ mainInitLogging(level);
} else {
const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/);
- main_init_logging(param || undefined);
+ mainInitLogging(param || undefined);
}
}
@@ -115,13 +115,8 @@ export function eraseCookie(name) {
let settings = {};
export function initSettings() {
- if (!window.chrome || !window.chrome.storage) {
- settings = {};
- return Promise.resolve();
- }
-
- return new Promise(resolve => window.chrome.storage.sync.get(resolve))
- .then((cfg) => { settings = cfg; });
+ settings = {};
+ return Promise.resolve();
}
// Update the settings cache, but do not write to permanent storage
@@ -134,22 +129,13 @@ export function writeSetting(name, value) {
"use strict";
if (settings[name] === value) return;
settings[name] = value;
- if (window.chrome && window.chrome.storage) {
- window.chrome.storage.sync.set(settings);
- } else {
- localStorage.setItem(name, value);
- }
}
export function readSetting(name, defaultValue) {
"use strict";
let value;
- if ((name in settings) || (window.chrome && window.chrome.storage)) {
- value = settings[name];
- } else {
- value = localStorage.getItem(name);
- settings[name] = value;
- }
+ value = settings[name];
+
if (typeof value === "undefined") {
value = null;
}
@@ -169,11 +155,6 @@ export function eraseSetting(name) {
// between this delete and the next read, it could lead to an unexpected
// value change.
delete settings[name];
- if (window.chrome && window.chrome.storage) {
- window.chrome.storage.sync.remove(name);
- } else {
- localStorage.removeItem(name);
- }
}
export function injectParamIfMissing(path, param, value) {
@@ -184,7 +165,7 @@ export function injectParamIfMissing(path, param, value) {
const elem = document.createElement('a');
elem.href = path;
- const param_eq = encodeURIComponent(param) + "=";
+ const paramEq = encodeURIComponent(param) + "=";
let query;
if (elem.search) {
query = elem.search.slice(1).split('&');
@@ -192,8 +173,8 @@ export function injectParamIfMissing(path, param, value) {
query = [];
}
- if (!query.some(v => v.startsWith(param_eq))) {
- query.push(param_eq + encodeURIComponent(value));
+ if (!query.some(v => v.startsWith(paramEq))) {
+ query.push(paramEq + encodeURIComponent(value));
elem.search = "?" + query.join("&");
}
diff --git a/systemvm/agent/noVNC/core/base64.js b/systemvm/agent/noVNC/core/base64.js
index 88e7454..db572c2 100644
--- a/systemvm/agent/noVNC/core/base64.js
+++ b/systemvm/agent/noVNC/core/base64.js
@@ -57,12 +57,12 @@ export default {
/* eslint-enable comma-spacing */
decode(data, offset = 0) {
- let data_length = data.indexOf('=') - offset;
- if (data_length < 0) { data_length = data.length - offset; }
+ let dataLength = data.indexOf('=') - offset;
+ if (dataLength < 0) { dataLength = data.length - offset; }
/* Every four characters is 3 resulting numbers */
- const result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
- const result = new Array(result_length);
+ const resultLength = (dataLength >> 2) * 3 + Math.floor((dataLength % 4) / 1.5);
+ const result = new Array(resultLength);
// Convert one by one.
diff --git a/systemvm/agent/noVNC/core/decoders/copyrect.js b/systemvm/agent/noVNC/core/decoders/copyrect.js
index a78ded7..9e6391a 100644
--- a/systemvm/agent/noVNC/core/decoders/copyrect.js
+++ b/systemvm/agent/noVNC/core/decoders/copyrect.js
@@ -1,8 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2018 Pierre Ossman for Cendio AB
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -17,6 +15,11 @@ export default class CopyRectDecoder {
let deltaX = sock.rQshift16();
let deltaY = sock.rQshift16();
+
+ if ((width === 0) || (height === 0)) {
+ return true;
+ }
+
display.copyImage(deltaX, deltaY, x, y, width, height);
return true;
diff --git a/systemvm/agent/noVNC/core/decoders/hextile.js b/systemvm/agent/noVNC/core/decoders/hextile.js
index aa76d2f..ac21eff 100644
--- a/systemvm/agent/noVNC/core/decoders/hextile.js
+++ b/systemvm/agent/noVNC/core/decoders/hextile.js
@@ -1,8 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2018 Pierre Ossman for Cendio AB
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -15,14 +13,15 @@ export default class HextileDecoder {
constructor() {
this._tiles = 0;
this._lastsubencoding = 0;
+ this._tileBuffer = new Uint8Array(16 * 16 * 4);
}
decodeRect(x, y, width, height, sock, display, depth) {
if (this._tiles === 0) {
- this._tiles_x = Math.ceil(width / 16);
- this._tiles_y = Math.ceil(height / 16);
- this._total_tiles = this._tiles_x * this._tiles_y;
- this._tiles = this._total_tiles;
+ this._tilesX = Math.ceil(width / 16);
+ this._tilesY = Math.ceil(height / 16);
+ this._totalTiles = this._tilesX * this._tilesY;
+ this._tiles = this._totalTiles;
}
while (this._tiles > 0) {
@@ -41,11 +40,11 @@ export default class HextileDecoder {
subencoding + ")");
}
- const curr_tile = this._total_tiles - this._tiles;
- const tile_x = curr_tile % this._tiles_x;
- const tile_y = Math.floor(curr_tile / this._tiles_x);
- const tx = x + tile_x * 16;
- const ty = y + tile_y * 16;
+ const currTile = this._totalTiles - this._tiles;
+ const tileX = currTile % this._tilesX;
+ const tileY = Math.floor(currTile / this._tilesX);
+ const tx = x + tileX * 16;
+ const ty = y + tileY * 16;
const tw = Math.min(16, (x + width) - tx);
const th = Math.min(16, (y + height) - ty);
@@ -89,6 +88,11 @@ export default class HextileDecoder {
display.fillRect(tx, ty, tw, th, this._background);
}
} else if (subencoding & 0x01) { // Raw
+ let pixels = tw * th;
+ // Max sure the image is fully opaque
+ for (let i = 0;i < pixels;i++) {
+ rQ[rQi + i * 4 + 3] = 255;
+ }
display.blitImage(tx, ty, tw, th, rQ, rQi);
rQi += bytes - 1;
} else {
@@ -101,7 +105,7 @@ export default class HextileDecoder {
rQi += 4;
}
- display.startTile(tx, ty, tw, th, this._background);
+ this._startTile(tx, ty, tw, th, this._background);
if (subencoding & 0x08) { // AnySubrects
let subrects = rQ[rQi];
rQi++;
@@ -124,10 +128,10 @@ export default class HextileDecoder {
const sw = (wh >> 4) + 1;
const sh = (wh & 0x0f) + 1;
- display.subTile(sx, sy, sw, sh, color);
+ this._subTile(sx, sy, sw, sh, color);
}
}
- display.finishTile();
+ this._finishTile(display);
}
sock.rQi = rQi;
this._lastsubencoding = subencoding;
@@ -136,4 +140,52 @@ export default class HextileDecoder {
return true;
}
+
+ // start updating a tile
+ _startTile(x, y, width, height, color) {
+ this._tileX = x;
+ this._tileY = y;
+ this._tileW = width;
+ this._tileH = height;
+
+ const red = color[0];
+ const green = color[1];
+ const blue = color[2];
+
+ const data = this._tileBuffer;
+ for (let i = 0; i < width * height * 4; i += 4) {
+ data[i] = red;
+ data[i + 1] = green;
+ data[i + 2] = blue;
+ data[i + 3] = 255;
+ }
+ }
+
+ // update sub-rectangle of the current tile
+ _subTile(x, y, w, h, color) {
+ const red = color[0];
+ const green = color[1];
+ const blue = color[2];
+ const xend = x + w;
+ const yend = y + h;
+
+ const data = this._tileBuffer;
+ const width = this._tileW;
+ for (let j = y; j < yend; j++) {
+ for (let i = x; i < xend; i++) {
+ const p = (i + (j * width)) * 4;
+ data[p] = red;
+ data[p + 1] = green;
+ data[p + 2] = blue;
+ data[p + 3] = 255;
+ }
+ }
+ }
+
+ // draw the current tile to the screen
+ _finishTile(display) {
+ display.blitImage(this._tileX, this._tileY,
+ this._tileW, this._tileH,
+ this._tileBuffer, 0);
+ }
}
diff --git a/systemvm/agent/noVNC/core/decoders/raw.js b/systemvm/agent/noVNC/core/decoders/raw.js
index f676e0d..e8ea178 100644
--- a/systemvm/agent/noVNC/core/decoders/raw.js
+++ b/systemvm/agent/noVNC/core/decoders/raw.js
@@ -1,8 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2018 Pierre Ossman for Cendio AB
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -15,6 +13,10 @@ export default class RawDecoder {
}
decodeRect(x, y, width, height, sock, display, depth) {
+ if ((width === 0) || (height === 0)) {
+ return true;
+ }
+
if (this._lines === 0) {
this._lines = height;
}
@@ -26,29 +28,35 @@ export default class RawDecoder {
return false;
}
- const cur_y = y + (height - this._lines);
- const curr_height = Math.min(this._lines,
- Math.floor(sock.rQlen / bytesPerLine));
+ const curY = y + (height - this._lines);
+ const currHeight = Math.min(this._lines,
+ Math.floor(sock.rQlen / bytesPerLine));
+ const pixels = width * currHeight;
+
let data = sock.rQ;
let index = sock.rQi;
// Convert data if needed
if (depth == 8) {
- const pixels = width * curr_height;
const newdata = new Uint8Array(pixels * 4);
for (let i = 0; i < pixels; i++) {
newdata[i * 4 + 0] = ((data[index + i] >> 0) & 0x3) * 255 / 3;
newdata[i * 4 + 1] = ((data[index + i] >> 2) & 0x3) * 255 / 3;
newdata[i * 4 + 2] = ((data[index + i] >> 4) & 0x3) * 255 / 3;
- newdata[i * 4 + 4] = 0;
+ newdata[i * 4 + 3] = 255;
}
data = newdata;
index = 0;
}
- display.blitImage(x, cur_y, width, curr_height, data, index);
- sock.rQskipBytes(curr_height * bytesPerLine);
- this._lines -= curr_height;
+ // Max sure the image is fully opaque
+ for (let i = 0; i < pixels; i++) {
+ data[i * 4 + 3] = 255;
+ }
+
+ display.blitImage(x, curY, width, currHeight, data, index);
+ sock.rQskipBytes(currHeight * bytesPerLine);
+ this._lines -= currHeight;
if (this._lines > 0) {
return false;
}
diff --git a/systemvm/agent/noVNC/core/decoders/rre.js b/systemvm/agent/noVNC/core/decoders/rre.js
index 57414a0..6219369 100644
--- a/systemvm/agent/noVNC/core/decoders/rre.js
+++ b/systemvm/agent/noVNC/core/decoders/rre.js
@@ -1,8 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2018 Pierre Ossman for Cendio AB
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
diff --git a/systemvm/agent/noVNC/core/decoders/tight.js b/systemvm/agent/noVNC/core/decoders/tight.js
index bcda04c..7952707 100644
--- a/systemvm/agent/noVNC/core/decoders/tight.js
+++ b/systemvm/agent/noVNC/core/decoders/tight.js
@@ -1,9 +1,7 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
+ * Copyright (C) 2019 The noVNC Authors
* (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2018 Pierre Ossman for Cendio AB
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -58,7 +56,7 @@ export default class TightDecoder {
} else if (this._ctl === 0x0A) {
ret = this._pngRect(x, y, width, height,
sock, display, depth);
- } else if ((this._ctl & 0x80) == 0) {
+ } else if ((this._ctl & 0x08) == 0) {
ret = this._basicRect(this._ctl, x, y, width, height,
sock, display, depth);
} else {
@@ -82,7 +80,7 @@ export default class TightDecoder {
const rQ = sock.rQ;
display.fillRect(x, y, width, height,
- [rQ[rQi + 2], rQ[rQi + 1], rQ[rQi]], false);
+ [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], false);
sock.rQskipBytes(3);
return true;
@@ -94,7 +92,7 @@ export default class TightDecoder {
return false;
}
- display.imageRect(x, y, "image/jpeg", data);
+ display.imageRect(x, y, width, height, "image/jpeg", data);
return true;
}
@@ -150,6 +148,10 @@ export default class TightDecoder {
const uncompressedSize = width * height * 3;
let data;
+ if (uncompressedSize === 0) {
+ return true;
+ }
+
if (uncompressedSize < 12) {
if (sock.rQwait("TIGHT", uncompressedSize)) {
return false;
@@ -162,13 +164,20 @@ export default class TightDecoder {
return false;
}
- data = this._zlibs[streamId].inflate(data, true, uncompressedSize);
- if (data.length != uncompressedSize) {
- throw new Error("Incomplete zlib block");
- }
+ this._zlibs[streamId].setInput(data);
+ data = this._zlibs[streamId].inflate(uncompressedSize);
+ this._zlibs[streamId].setInput(null);
+ }
+
+ let rgbx = new Uint8Array(width * height * 4);
+ for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) {
+ rgbx[i] = data[j];
+ rgbx[i + 1] = data[j + 1];
+ rgbx[i + 2] = data[j + 2];
+ rgbx[i + 3] = 255; // Alpha
}
- display.blitRgbImage(x, y, width, height, data, 0, false);
+ display.blitImage(x, y, width, height, rgbx, 0, false);
return true;
}
@@ -198,6 +207,10 @@ export default class TightDecoder {
let data;
+ if (uncompressedSize === 0) {
+ return true;
+ }
+
if (uncompressedSize < 12) {
if (sock.rQwait("TIGHT", uncompressedSize)) {
return false;
@@ -210,10 +223,9 @@ export default class TightDecoder {
return false;
}
- data = this._zlibs[streamId].inflate(data, true, uncompressedSize);
- if (data.length != uncompressedSize) {
- throw new Error("Incomplete zlib block");
- }
+ this._zlibs[streamId].setInput(data);
+ data = this._zlibs[streamId].inflate(uncompressedSize);
+ this._zlibs[streamId].setInput(null);
}
// Convert indexed (palette based) image data to RGB
@@ -241,7 +253,7 @@ export default class TightDecoder {
for (let b = 7; b >= 0; b--) {
dp = (y * width + x * 8 + 7 - b) * 4;
sp = (data[y * w + x] >> b & 1) * 3;
- dest[dp] = palette[sp];
+ dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
@@ -251,14 +263,14 @@ export default class TightDecoder {
for (let b = 7; b >= 8 - width % 8; b--) {
dp = (y * width + x * 8 + 7 - b) * 4;
sp = (data[y * w + x] >> b & 1) * 3;
- dest[dp] = palette[sp];
+ dest[dp] = palette[sp];
dest[dp + 1] = palette[sp + 1];
dest[dp + 2] = palette[sp + 2];
dest[dp + 3] = 255;
}
}
- display.blitRgbxImage(x, y, width, height, dest, 0, false);
+ display.blitImage(x, y, width, height, dest, 0, false);
}
_paletteRect(x, y, width, height, data, palette, display) {
@@ -267,13 +279,13 @@ export default class TightDecoder {
const total = width * height * 4;
for (let i = 0, j = 0; i < total; i += 4, j++) {
const sp = data[j] * 3;
- dest[i] = palette[sp];
+ dest[i] = palette[sp];
dest[i + 1] = palette[sp + 1];
dest[i + 2] = palette[sp + 2];
dest[i + 3] = 255;
}
- display.blitRgbxImage(x, y, width, height, dest, 0, false);
+ display.blitImage(x, y, width, height, dest, 0, false);
}
_gradientFilter(streamId, x, y, width, height, sock, display, depth) {
diff --git a/systemvm/agent/noVNC/core/decoders/tightpng.js b/systemvm/agent/noVNC/core/decoders/tightpng.js
index 7bbde3a..82f492d 100644
--- a/systemvm/agent/noVNC/core/decoders/tightpng.js
+++ b/systemvm/agent/noVNC/core/decoders/tightpng.js
@@ -1,8 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2018 Samuel Mannehed for Cendio AB
- * Copyright (C) 2018 Pierre Ossman for Cendio AB
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -18,7 +16,7 @@ export default class TightPNGDecoder extends TightDecoder {
return false;
}
- display.imageRect(x, y, "image/png", data);
+ display.imageRect(x, y, width, height, "image/png", data);
return true;
}
diff --git a/systemvm/agent/noVNC/core/deflator.js b/systemvm/agent/noVNC/core/deflator.js
new file mode 100644
index 0000000..fe2a8f7
--- /dev/null
+++ b/systemvm/agent/noVNC/core/deflator.js
@@ -0,0 +1,85 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2020 The noVNC Authors
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
+import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js";
+import { Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js";
+import ZStream from "../vendor/pako/lib/zlib/zstream.js";
+
+export default class Deflator {
+ constructor() {
+ this.strm = new ZStream();
+ this.chunkSize = 1024 * 10 * 10;
+ this.outputBuffer = new Uint8Array(this.chunkSize);
+ this.windowBits = 5;
+
+ deflateInit(this.strm, this.windowBits);
+ }
+
+ deflate(inData) {
+ /* eslint-disable camelcase */
+ this.strm.input = inData;
+ this.strm.avail_in = this.strm.input.length;
+ this.strm.next_in = 0;
+ this.strm.output = this.outputBuffer;
+ this.strm.avail_out = this.chunkSize;
+ this.strm.next_out = 0;
+ /* eslint-enable camelcase */
+
+ let lastRet = deflate(this.strm, Z_FULL_FLUSH);
+ let outData = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
+
+ if (lastRet < 0) {
+ throw new Error("zlib deflate failed");
+ }
+
+ if (this.strm.avail_in > 0) {
+ // Read chunks until done
+
+ let chunks = [outData];
+ let totalLen = outData.length;
+ do {
+ /* eslint-disable camelcase */
+ this.strm.output = new Uint8Array(this.chunkSize);
+ this.strm.next_out = 0;
+ this.strm.avail_out = this.chunkSize;
+ /* eslint-enable camelcase */
+
+ lastRet = deflate(this.strm, Z_FULL_FLUSH);
+
+ if (lastRet < 0) {
+ throw new Error("zlib deflate failed");
+ }
+
+ let chunk = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
+ totalLen += chunk.length;
+ chunks.push(chunk);
+ } while (this.strm.avail_in > 0);
+
+ // Combine chunks into a single data
+
+ let newData = new Uint8Array(totalLen);
+ let offset = 0;
+
+ for (let i = 0; i < chunks.length; i++) {
+ newData.set(chunks[i], offset);
+ offset += chunks[i].length;
+ }
+
+ outData = newData;
+ }
+
+ /* eslint-disable camelcase */
+ this.strm.input = null;
+ this.strm.avail_in = 0;
+ this.strm.next_in = 0;
+ /* eslint-enable camelcase */
+
+ return outData;
+ }
+
+}
diff --git a/systemvm/agent/noVNC/core/display.js b/systemvm/agent/noVNC/core/display.js
index 1528384..8eaa800 100644
--- a/systemvm/agent/noVNC/core/display.js
+++ b/systemvm/agent/noVNC/core/display.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -9,24 +9,20 @@
import * as Log from './util/logging.js';
import Base64 from "./base64.js";
import { supportsImageMetadata } from './util/browser.js';
+import { toSigned32bit } from './util/int.js';
export default class Display {
constructor(target) {
this._drawCtx = null;
- this._c_forceCanvas = false;
this._renderQ = []; // queue drawing actions for in-oder rendering
this._flushing = false;
// the full frame buffer (logical canvas) size
- this._fb_width = 0;
- this._fb_height = 0;
+ this._fbWidth = 0;
+ this._fbHeight = 0;
this._prevDrawStyle = "";
- this._tile = null;
- this._tile16x16 = null;
- this._tile_x = 0;
- this._tile_y = 0;
Log.Debug(">> Display.constructor");
@@ -60,21 +56,17 @@ export default class Display {
Log.Debug("User Agent: " + navigator.userAgent);
- this.clear();
-
// Check canvas features
if (!('createImageData' in this._drawCtx)) {
throw new Error("Canvas does not support createImageData");
}
- this._tile16x16 = this._drawCtx.createImageData(16, 16);
Log.Debug("<< Display.constructor");
// ===== PROPERTIES =====
this._scale = 1.0;
this._clipViewport = false;
- this.logo = null;
// ===== EVENT HANDLERS =====
@@ -98,11 +90,11 @@ export default class Display {
}
get width() {
- return this._fb_width;
+ return this._fbWidth;
}
get height() {
- return this._fb_height;
+ return this._fbHeight;
}
// ===== PUBLIC METHODS =====
@@ -125,15 +117,15 @@ export default class Display {
if (deltaX < 0 && vp.x + deltaX < 0) {
deltaX = -vp.x;
}
- if (vx2 + deltaX >= this._fb_width) {
- deltaX -= vx2 + deltaX - this._fb_width + 1;
+ if (vx2 + deltaX >= this._fbWidth) {
+ deltaX -= vx2 + deltaX - this._fbWidth + 1;
}
if (vp.y + deltaY < 0) {
deltaY = -vp.y;
}
- if (vy2 + deltaY >= this._fb_height) {
- deltaY -= (vy2 + deltaY - this._fb_height + 1);
+ if (vy2 + deltaY >= this._fbHeight) {
+ deltaY -= (vy2 + deltaY - this._fbHeight + 1);
}
if (deltaX === 0 && deltaY === 0) {
@@ -156,18 +148,18 @@ export default class Display {
typeof(height) === "undefined") {
Log.Debug("Setting viewport to full display region");
- width = this._fb_width;
- height = this._fb_height;
+ width = this._fbWidth;
+ height = this._fbHeight;
}
width = Math.floor(width);
height = Math.floor(height);
- if (width > this._fb_width) {
- width = this._fb_width;
+ if (width > this._fbWidth) {
+ width = this._fbWidth;
}
- if (height > this._fb_height) {
- height = this._fb_height;
+ if (height > this._fbHeight) {
+ height = this._fbHeight;
}
const vp = this._viewportLoc;
@@ -194,21 +186,21 @@ export default class Display {
if (this._scale === 0) {
return 0;
}
- return x / this._scale + this._viewportLoc.x;
+ return toSigned32bit(x / this._scale + this._viewportLoc.x);
}
absY(y) {
if (this._scale === 0) {
return 0;
}
- return y / this._scale + this._viewportLoc.y;
+ return toSigned32bit(y / this._scale + this._viewportLoc.y);
}
resize(width, height) {
this._prevDrawStyle = "";
- this._fb_width = width;
- this._fb_height = height;
+ this._fbWidth = width;
+ this._fbHeight = height;
const canvas = this._backbuffer;
if (canvas.width !== width || canvas.height !== height) {
@@ -256,9 +248,9 @@ export default class Display {
// Update the visible canvas with the contents of the
// rendering canvas
- flip(from_queue) {
- if (this._renderQ.length !== 0 && !from_queue) {
- this._renderQ_push({
+ flip(fromQueue) {
+ if (this._renderQ.length !== 0 && !fromQueue) {
+ this._renderQPush({
'type': 'flip'
});
} else {
@@ -302,17 +294,6 @@ export default class Display {
}
}
- clear() {
- if (this._logo) {
- this.resize(this._logo.width, this._logo.height);
- this.imageRect(0, 0, this._logo.type, this._logo.data);
- } else {
- this.resize(240, 20);
- this._drawCtx.clearRect(0, 0, this._fb_width, this._fb_height);
- }
- this.flip();
- }
-
pending() {
return this._renderQ.length > 0;
}
@@ -325,9 +306,9 @@ export default class Display {
}
}
- fillRect(x, y, width, height, color, from_queue) {
- if (this._renderQ.length !== 0 && !from_queue) {
- this._renderQ_push({
+ fillRect(x, y, width, height, color, fromQueue) {
+ if (this._renderQ.length !== 0 && !fromQueue) {
+ this._renderQPush({
'type': 'fill',
'x': x,
'y': y,
@@ -342,14 +323,14 @@ export default class Display {
}
}
- copyImage(old_x, old_y, new_x, new_y, w, h, from_queue) {
- if (this._renderQ.length !== 0 && !from_queue) {
- this._renderQ_push({
+ copyImage(oldX, oldY, newX, newY, w, h, fromQueue) {
+ if (this._renderQ.length !== 0 && !fromQueue) {
+ this._renderQPush({
'type': 'copy',
- 'old_x': old_x,
- 'old_y': old_y,
- 'x': new_x,
- 'y': new_y,
+ 'oldX': oldX,
+ 'oldY': oldY,
+ 'x': newX,
+ 'y': newY,
'width': w,
'height': h,
});
@@ -367,131 +348,60 @@ export default class Display {
this._drawCtx.imageSmoothingEnabled = false;
this._drawCtx.drawImage(this._backbuffer,
- old_x, old_y, w, h,
- new_x, new_y, w, h);
- this._damage(new_x, new_y, w, h);
+ oldX, oldY, w, h,
+ newX, newY, w, h);
+ this._damage(newX, newY, w, h);
}
}
- imageRect(x, y, mime, arr) {
+ imageRect(x, y, width, height, mime, arr) {
+ /* The internal logic cannot handle empty images, so bail early */
+ if ((width === 0) || (height === 0)) {
+ return;
+ }
+
const img = new Image();
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
- this._renderQ_push({
+
+ this._renderQPush({
'type': 'img',
'img': img,
'x': x,
- 'y': y
+ 'y': y,
+ 'width': width,
+ 'height': height
});
}
- // start updating a tile
- startTile(x, y, width, height, color) {
- this._tile_x = x;
- this._tile_y = y;
- if (width === 16 && height === 16) {
- this._tile = this._tile16x16;
- } else {
- this._tile = this._drawCtx.createImageData(width, height);
- }
-
- const red = color[2];
- const green = color[1];
- const blue = color[0];
-
- const data = this._tile.data;
- for (let i = 0; i < width * height * 4; i += 4) {
- data[i] = red;
- data[i + 1] = green;
- data[i + 2] = blue;
- data[i + 3] = 255;
- }
- }
-
- // update sub-rectangle of the current tile
- subTile(x, y, w, h, color) {
- const red = color[2];
- const green = color[1];
- const blue = color[0];
- const xend = x + w;
- const yend = y + h;
-
- const data = this._tile.data;
- const width = this._tile.width;
- for (let j = y; j < yend; j++) {
- for (let i = x; i < xend; i++) {
- const p = (i + (j * width)) * 4;
- data[p] = red;
- data[p + 1] = green;
- data[p + 2] = blue;
- data[p + 3] = 255;
- }
- }
- }
-
- // draw the current tile to the screen
- finishTile() {
- this._drawCtx.putImageData(this._tile, this._tile_x, this._tile_y);
- this._damage(this._tile_x, this._tile_y,
- this._tile.width, this._tile.height);
- }
-
- blitImage(x, y, width, height, arr, offset, from_queue) {
- if (this._renderQ.length !== 0 && !from_queue) {
+ blitImage(x, y, width, height, arr, offset, fromQueue) {
+ if (this._renderQ.length !== 0 && !fromQueue) {
// NB(directxman12): it's technically more performant here to use preallocated arrays,
// but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
// this probably isn't getting called *nearly* as much
- const new_arr = new Uint8Array(width * height * 4);
- new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
- this._renderQ_push({
+ const newArr = new Uint8Array(width * height * 4);
+ newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
+ this._renderQPush({
'type': 'blit',
- 'data': new_arr,
+ 'data': newArr,
'x': x,
'y': y,
'width': width,
'height': height,
});
} else {
- this._bgrxImageData(x, y, width, height, arr, offset);
- }
- }
-
- blitRgbImage(x, y, width, height, arr, offset, from_queue) {
- if (this._renderQ.length !== 0 && !from_queue) {
- // NB(directxman12): it's technically more performant here to use preallocated arrays,
- // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
- // this probably isn't getting called *nearly* as much
- const new_arr = new Uint8Array(width * height * 3);
- new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
- this._renderQ_push({
- 'type': 'blitRgb',
- 'data': new_arr,
- 'x': x,
- 'y': y,
- 'width': width,
- 'height': height,
- });
- } else {
- this._rgbImageData(x, y, width, height, arr, offset);
- }
- }
-
- blitRgbxImage(x, y, width, height, arr, offset, from_queue) {
- if (this._renderQ.length !== 0 && !from_queue) {
- // NB(directxman12): it's technically more performant here to use preallocated arrays,
- // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue,
- // this probably isn't getting called *nearly* as much
- const new_arr = new Uint8Array(width * height * 4);
- new_arr.set(new Uint8Array(arr.buffer, 0, new_arr.length));
- this._renderQ_push({
- 'type': 'blitRgbx',
- 'data': new_arr,
- 'x': x,
- 'y': y,
- 'width': width,
- 'height': height,
- });
- } else {
- this._rgbxImageData(x, y, width, height, arr, offset);
+ // NB(directxman12): arr must be an Type Array view
+ let data = new Uint8ClampedArray(arr.buffer,
+ arr.byteOffset + offset,
+ width * height * 4);
+ let img;
+ if (supportsImageMetadata) {
+ img = new ImageData(data, width, height);
+ } else {
+ img = this._drawCtx.createImageData(width, height);
+ img.data.set(data);
+ }
+ this._drawCtx.putImageData(img, x, y);
+ this._damage(x, y, width, height);
}
}
@@ -543,69 +453,30 @@ export default class Display {
}
_setFillColor(color) {
- const newStyle = 'rgb(' + color[2] + ',' + color[1] + ',' + color[0] + ')';
+ const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')';
if (newStyle !== this._prevDrawStyle) {
this._drawCtx.fillStyle = newStyle;
this._prevDrawStyle = newStyle;
}
}
- _rgbImageData(x, y, width, height, arr, offset) {
- const img = this._drawCtx.createImageData(width, height);
- const data = img.data;
- for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 3) {
- data[i] = arr[j];
- data[i + 1] = arr[j + 1];
- data[i + 2] = arr[j + 2];
- data[i + 3] = 255; // Alpha
- }
- this._drawCtx.putImageData(img, x, y);
- this._damage(x, y, img.width, img.height);
- }
-
- _bgrxImageData(x, y, width, height, arr, offset) {
- const img = this._drawCtx.createImageData(width, height);
- const data = img.data;
- for (let i = 0, j = offset; i < width * height * 4; i += 4, j += 4) {
- data[i] = arr[j + 2];
- data[i + 1] = arr[j + 1];
- data[i + 2] = arr[j];
- data[i + 3] = 255; // Alpha
- }
- this._drawCtx.putImageData(img, x, y);
- this._damage(x, y, img.width, img.height);
- }
-
- _rgbxImageData(x, y, width, height, arr, offset) {
- // NB(directxman12): arr must be an Type Array view
- let img;
- if (supportsImageMetadata) {
- img = new ImageData(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4), width, height);
- } else {
- img = this._drawCtx.createImageData(width, height);
- img.data.set(new Uint8ClampedArray(arr.buffer, arr.byteOffset, width * height * 4));
- }
- this._drawCtx.putImageData(img, x, y);
- this._damage(x, y, img.width, img.height);
- }
-
- _renderQ_push(action) {
+ _renderQPush(action) {
this._renderQ.push(action);
if (this._renderQ.length === 1) {
// If this can be rendered immediately it will be, otherwise
// the scanner will wait for the relevant event
- this._scan_renderQ();
+ this._scanRenderQ();
}
}
- _resume_renderQ() {
+ _resumeRenderQ() {
// "this" is the object that is ready, not the
// display object
- this.removeEventListener('load', this._noVNC_display._resume_renderQ);
- this._noVNC_display._scan_renderQ();
+ this.removeEventListener('load', this._noVNCDisplay._resumeRenderQ);
+ this._noVNCDisplay._scanRenderQ();
}
- _scan_renderQ() {
+ _scanRenderQ() {
let ready = true;
while (ready && this._renderQ.length > 0) {
const a = this._renderQ[0];
@@ -614,7 +485,7 @@ export default class Display {
this.flip(true);
break;
case 'copy':
- this.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height, true);
+ this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, true);
break;
case 'fill':
this.fillRect(a.x, a.y, a.width, a.height, a.color, true);
@@ -622,18 +493,19 @@ export default class Display {
case 'blit':
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, true);
break;
- case 'blitRgb':
- this.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0, true);
- break;
- case 'blitRgbx':
- this.blitRgbxImage(a.x, a.y, a.width, a.height, a.data, 0, true);
- break;
case 'img':
- if (a.img.complete) {
+ /* IE tends to set "complete" prematurely, so check dimensions */
+ if (a.img.complete && (a.img.width !== 0) && (a.img.height !== 0)) {
+ if (a.img.width !== a.width || a.img.height !== a.height) {
+ Log.Error("Decoded image has incorrect dimensions. Got " +
+ a.img.width + "x" + a.img.height + ". Expected " +
+ a.width + "x" + a.height + ".");
+ return;
+ }
this.drawImage(a.img, a.x, a.y);
} else {
- a.img._noVNC_display = this;
- a.img.addEventListener('load', this._resume_renderQ);
+ a.img._noVNCDisplay = this;
+ a.img.addEventListener('load', this._resumeRenderQ);
// We need to wait for this image to 'load'
// to keep things in-order
ready = false;
diff --git a/systemvm/agent/noVNC/core/encodings.js b/systemvm/agent/noVNC/core/encodings.js
index 9fd38d5..51c0992 100644
--- a/systemvm/agent/noVNC/core/encodings.js
+++ b/systemvm/agent/noVNC/core/encodings.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -20,12 +20,15 @@ export const encodings = {
pseudoEncodingLastRect: -224,
pseudoEncodingCursor: -239,
pseudoEncodingQEMUExtendedKeyEvent: -258,
+ pseudoEncodingDesktopName: -307,
pseudoEncodingExtendedDesktopSize: -308,
pseudoEncodingXvp: -309,
pseudoEncodingFence: -312,
pseudoEncodingContinuousUpdates: -313,
pseudoEncodingCompressLevel9: -247,
pseudoEncodingCompressLevel0: -256,
+ pseudoEncodingVMwareCursor: 0x574d5664,
+ pseudoEncodingExtendedClipboard: 0xc0a1e5ce
};
export function encodingName(num) {
diff --git a/systemvm/agent/noVNC/core/inflator.js b/systemvm/agent/noVNC/core/inflator.js
index 0eab8fe..4b33760 100644
--- a/systemvm/agent/noVNC/core/inflator.js
+++ b/systemvm/agent/noVNC/core/inflator.js
@@ -1,3 +1,11 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2020 The noVNC Authors
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
import { inflateInit, inflate, inflateReset } from "../vendor/pako/lib/zlib/inflate.js";
import ZStream from "../vendor/pako/lib/zlib/zstream.js";
@@ -11,12 +19,22 @@ export default class Inflate {
inflateInit(this.strm, this.windowBits);
}
- inflate(data, flush, expected) {
- this.strm.input = data;
- this.strm.avail_in = this.strm.input.length;
- this.strm.next_in = 0;
- this.strm.next_out = 0;
+ setInput(data) {
+ if (!data) {
+ //FIXME: flush remaining data.
+ /* eslint-disable camelcase */
+ this.strm.input = null;
+ this.strm.avail_in = 0;
+ this.strm.next_in = 0;
+ } else {
+ this.strm.input = data;
+ this.strm.avail_in = this.strm.input.length;
+ this.strm.next_in = 0;
+ /* eslint-enable camelcase */
+ }
+ }
+ inflate(expected) {
// resize our output buffer if it's too small
// (we could just use multiple chunks, but that would cause an extra
// allocation each time to flatten the chunks)
@@ -25,9 +43,19 @@ export default class Inflate {
this.strm.output = new Uint8Array(this.chunkSize);
}
- this.strm.avail_out = this.chunkSize;
+ /* eslint-disable camelcase */
+ this.strm.next_out = 0;
+ this.strm.avail_out = expected;
+ /* eslint-enable camelcase */
+
+ let ret = inflate(this.strm, 0); // Flush argument not used.
+ if (ret < 0) {
+ throw new Error("zlib inflate failed");
+ }
- inflate(this.strm, flush);
+ if (this.strm.next_out != expected) {
+ throw new Error("Incomplete zlib block");
+ }
return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out);
}
diff --git a/systemvm/agent/noVNC/core/input/domkeytable.js b/systemvm/agent/noVNC/core/input/domkeytable.js
index 60ae3f9..b84ad45 100644
--- a/systemvm/agent/noVNC/core/input/domkeytable.js
+++ b/systemvm/agent/noVNC/core/input/domkeytable.js
@@ -43,12 +43,10 @@ addStandard("CapsLock", KeyTable.XK_Caps_Lock);
addLeftRight("Control", KeyTable.XK_Control_L, KeyTable.XK_Control_R);
// - Fn
// - FnLock
-addLeftRight("Hyper", KeyTable.XK_Super_L, KeyTable.XK_Super_R);
addLeftRight("Meta", KeyTable.XK_Super_L, KeyTable.XK_Super_R);
addStandard("NumLock", KeyTable.XK_Num_Lock);
addStandard("ScrollLock", KeyTable.XK_Scroll_Lock);
addLeftRight("Shift", KeyTable.XK_Shift_L, KeyTable.XK_Shift_R);
-addLeftRight("Super", KeyTable.XK_Super_L, KeyTable.XK_Super_R);
// - Symbol
// - SymbolLock
@@ -72,6 +70,9 @@ addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior);
// 2.5. Editing Keys
addStandard("Backspace", KeyTable.XK_BackSpace);
+// Browsers send "Clear" for the numpad 5 without NumLock because
+// Windows uses VK_Clear for that key. But Unix expects KP_Begin for
+// that scenario.
addNumpad("Clear", KeyTable.XK_Clear, KeyTable.XK_KP_Begin);
addStandard("Copy", KeyTable.XF86XK_Copy);
// - CrSel
@@ -194,7 +195,8 @@ addStandard("F35", KeyTable.XK_F35);
addStandard("Close", KeyTable.XF86XK_Close);
addStandard("MailForward", KeyTable.XF86XK_MailForward);
addStandard("MailReply", KeyTable.XF86XK_Reply);
-addStandard("MainSend", KeyTable.XF86XK_Send);
+addStandard("MailSend", KeyTable.XF86XK_Send);
+// - MediaClose
addStandard("MediaFastForward", KeyTable.XF86XK_AudioForward);
addStandard("MediaPause", KeyTable.XF86XK_AudioPause);
addStandard("MediaPlay", KeyTable.XF86XK_AudioPlay);
@@ -218,11 +220,9 @@ addStandard("SpellCheck", KeyTable.XF86XK_Spell);
// - AudioBalanceLeft
// - AudioBalanceRight
-// - AudioBassDown
// - AudioBassBoostDown
// - AudioBassBoostToggle
// - AudioBassBoostUp
-// - AudioBassUp
// - AudioFaderFront
// - AudioFaderRear
// - AudioSurroundModeNext
@@ -243,12 +243,12 @@ addStandard("MicrophoneVolumeMute", KeyTable.XF86XK_AudioMicMute);
// 2.14. Application Keys
-addStandard("LaunchCalculator", KeyTable.XF86XK_Calculator);
+addStandard("LaunchApplication1", KeyTable.XF86XK_MyComputer);
+addStandard("LaunchApplication2", KeyTable.XF86XK_Calculator);
addStandard("LaunchCalendar", KeyTable.XF86XK_Calendar);
addStandard("LaunchMail", KeyTable.XF86XK_Mail);
addStandard("LaunchMediaPlayer", KeyTable.XF86XK_AudioMedia);
addStandard("LaunchMusicPlayer", KeyTable.XF86XK_Music);
-addStandard("LaunchMyComputer", KeyTable.XF86XK_MyComputer);
addStandard("LaunchPhone", KeyTable.XF86XK_Phone);
addStandard("LaunchScreenSaver", KeyTable.XF86XK_ScreenSaver);
addStandard("LaunchSpreadsheet", KeyTable.XF86XK_Excel);
diff --git a/systemvm/agent/noVNC/core/input/gesturehandler.js b/systemvm/agent/noVNC/core/input/gesturehandler.js
new file mode 100644
index 0000000..6fa72d2
--- /dev/null
+++ b/systemvm/agent/noVNC/core/input/gesturehandler.js
@@ -0,0 +1,567 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2020 The noVNC Authors
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ *
+ */
+
+const GH_NOGESTURE = 0;
+const GH_ONETAP = 1;
+const GH_TWOTAP = 2;
+const GH_THREETAP = 4;
+const GH_DRAG = 8;
+const GH_LONGPRESS = 16;
+const GH_TWODRAG = 32;
+const GH_PINCH = 64;
+
+const GH_INITSTATE = 127;
+
+const GH_MOVE_THRESHOLD = 50;
+const GH_ANGLE_THRESHOLD = 90; // Degrees
+
+// Timeout when waiting for gestures (ms)
+const GH_MULTITOUCH_TIMEOUT = 250;
+
+// Maximum time between press and release for a tap (ms)
+const GH_TAP_TIMEOUT = 1000;
+
+// Timeout when waiting for longpress (ms)
+const GH_LONGPRESS_TIMEOUT = 1000;
+
+// Timeout when waiting to decide between PINCH and TWODRAG (ms)
+const GH_TWOTOUCH_TIMEOUT = 50;
+
+export default class GestureHandler {
+ constructor() {
+ this._target = null;
+
+ this._state = GH_INITSTATE;
+
+ this._tracked = [];
+ this._ignored = [];
+
+ this._waitingRelease = false;
+ this._releaseStart = 0.0;
+
+ this._longpressTimeoutId = null;
+ this._twoTouchTimeoutId = null;
+
+ this._boundEventHandler = this._eventHandler.bind(this);
+ }
+
+ attach(target) {
+ this.detach();
+
+ this._target = target;
+ this._target.addEventListener('touchstart',
+ this._boundEventHandler);
+ this._target.addEventListener('touchmove',
+ this._boundEventHandler);
+ this._target.addEventListener('touchend',
+ this._boundEventHandler);
+ this._target.addEventListener('touchcancel',
+ this._boundEventHandler);
+ }
+
+ detach() {
+ if (!this._target) {
+ return;
+ }
+
+ this._stopLongpressTimeout();
+ this._stopTwoTouchTimeout();
+
+ this._target.removeEventListener('touchstart',
+ this._boundEventHandler);
+ this._target.removeEventListener('touchmove',
+ this._boundEventHandler);
+ this._target.removeEventListener('touchend',
+ this._boundEventHandler);
+ this._target.removeEventListener('touchcancel',
+ this._boundEventHandler);
+ this._target = null;
+ }
+
+ _eventHandler(e) {
+ let fn;
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ switch (e.type) {
+ case 'touchstart':
+ fn = this._touchStart;
+ break;
+ case 'touchmove':
+ fn = this._touchMove;
+ break;
+ case 'touchend':
+ case 'touchcancel':
+ fn = this._touchEnd;
+ break;
+ }
+
+ for (let i = 0; i < e.changedTouches.length; i++) {
+ let touch = e.changedTouches[i];
+ fn.call(this, touch.identifier, touch.clientX, touch.clientY);
+ }
+ }
+
+ _touchStart(id, x, y) {
+ // Ignore any new touches if there is already an active gesture,
+ // or we're in a cleanup state
+ if (this._hasDetectedGesture() || (this._state === GH_NOGESTURE)) {
+ this._ignored.push(id);
+ return;
+ }
+
+ // Did it take too long between touches that we should no longer
+ // consider this a single gesture?
+ if ((this._tracked.length > 0) &&
+ ((Date.now() - this._tracked[0].started) > GH_MULTITOUCH_TIMEOUT)) {
+ this._state = GH_NOGESTURE;
+ this._ignored.push(id);
+ return;
+ }
+
+ // If we're waiting for fingers to release then we should no longer
+ // recognize new touches
+ if (this._waitingRelease) {
+ this._state = GH_NOGESTURE;
+ this._ignored.push(id);
+ return;
+ }
+
+ this._tracked.push({
+ id: id,
+ started: Date.now(),
+ active: true,
+ firstX: x,
+ firstY: y,
+ lastX: x,
+ lastY: y,
+ angle: 0
+ });
+
+ switch (this._tracked.length) {
+ case 1:
+ this._startLongpressTimeout();
+ break;
+
+ case 2:
+ this._state &= ~(GH_ONETAP | GH_DRAG | GH_LONGPRESS);
+ this._stopLongpressTimeout();
+ break;
+
+ case 3:
+ this._state &= ~(GH_TWOTAP | GH_TWODRAG | GH_PINCH);
+ break;
+
+ default:
+ this._state = GH_NOGESTURE;
+ }
+ }
+
+ _touchMove(id, x, y) {
+ let touch = this._tracked.find(t => t.id === id);
+
+ // If this is an update for a touch we're not tracking, ignore it
+ if (touch === undefined) {
+ return;
+ }
+
+ // Update the touches last position with the event coordinates
+ touch.lastX = x;
+ touch.lastY = y;
+
+ let deltaX = x - touch.firstX;
+ let deltaY = y - touch.firstY;
+
+ // Update angle when the touch has moved
+ if ((touch.firstX !== touch.lastX) ||
+ (touch.firstY !== touch.lastY)) {
+ touch.angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI;
+ }
+
+ if (!this._hasDetectedGesture()) {
+ // Ignore moves smaller than the minimum threshold
+ if (Math.hypot(deltaX, deltaY) < GH_MOVE_THRESHOLD) {
+ return;
+ }
+
+ // Can't be a tap or long press as we've seen movement
+ this._state &= ~(GH_ONETAP | GH_TWOTAP | GH_THREETAP | GH_LONGPRESS);
+ this._stopLongpressTimeout();
+
+ if (this._tracked.length !== 1) {
+ this._state &= ~(GH_DRAG);
+ }
+ if (this._tracked.length !== 2) {
+ this._state &= ~(GH_TWODRAG | GH_PINCH);
+ }
+
+ // We need to figure out which of our different two touch gestures
+ // this might be
+ if (this._tracked.length === 2) {
+
+ // The other touch is the one where the id doesn't match
+ let prevTouch = this._tracked.find(t => t.id !== id);
+
+ // How far the previous touch point has moved since start
+ let prevDeltaMove = Math.hypot(prevTouch.firstX - prevTouch.lastX,
+ prevTouch.firstY - prevTouch.lastY);
+
+ // We know that the current touch moved far enough,
+ // but unless both touches moved further than their
+ // threshold we don't want to disqualify any gestures
+ if (prevDeltaMove > GH_MOVE_THRESHOLD) {
+
+ // The angle difference between the direction of the touch points
+ let deltaAngle = Math.abs(touch.angle - prevTouch.angle);
+ deltaAngle = Math.abs(((deltaAngle + 180) % 360) - 180);
+
+ // PINCH or TWODRAG can be eliminated depending on the angle
+ if (deltaAngle > GH_ANGLE_THRESHOLD) {
+ this._state &= ~GH_TWODRAG;
+ } else {
+ this._state &= ~GH_PINCH;
+ }
+
+ if (this._isTwoTouchTimeoutRunning()) {
+ this._stopTwoTouchTimeout();
+ }
+ } else if (!this._isTwoTouchTimeoutRunning()) {
+ // We can't determine the gesture right now, let's
+ // wait and see if more events are on their way
+ this._startTwoTouchTimeout();
+ }
+ }
+
+ if (!this._hasDetectedGesture()) {
+ return;
+ }
+
+ this._pushEvent('gesturestart');
+ }
+
+ this._pushEvent('gesturemove');
+ }
+
+ _touchEnd(id, x, y) {
+ // Check if this is an ignored touch
+ if (this._ignored.indexOf(id) !== -1) {
+ // Remove this touch from ignored
+ this._ignored.splice(this._ignored.indexOf(id), 1);
+
+ // And reset the state if there are no more touches
+ if ((this._ignored.length === 0) &&
+ (this._tracked.length === 0)) {
+ this._state = GH_INITSTATE;
+ this._waitingRelease = false;
+ }
+ return;
+ }
+
+ // We got a touchend before the timer triggered,
+ // this cannot result in a gesture anymore.
+ if (!this._hasDetectedGesture() &&
+ this._isTwoTouchTimeoutRunning()) {
+ this._stopTwoTouchTimeout();
+ this._state = GH_NOGESTURE;
+ }
+
+ // Some gestures don't trigger until a touch is released
+ if (!this._hasDetectedGesture()) {
+ // Can't be a gesture that relies on movement
+ this._state &= ~(GH_DRAG | GH_TWODRAG | GH_PINCH);
+ // Or something that relies on more time
+ this._state &= ~GH_LONGPRESS;
+ this._stopLongpressTimeout();
+
+ if (!this._waitingRelease) {
+ this._releaseStart = Date.now();
+ this._waitingRelease = true;
+
+ // Can't be a tap that requires more touches than we current have
+ switch (this._tracked.length) {
+ case 1:
+ this._state &= ~(GH_TWOTAP | GH_THREETAP);
+ break;
+
+ case 2:
+ this._state &= ~(GH_ONETAP | GH_THREETAP);
+ break;
+ }
+ }
+ }
+
+ // Waiting for all touches to release? (i.e. some tap)
+ if (this._waitingRelease) {
+ // Were all touches released at roughly the same time?
+ if ((Date.now() - this._releaseStart) > GH_MULTITOUCH_TIMEOUT) {
+ this._state = GH_NOGESTURE;
+ }
+
+ // Did too long time pass between press and release?
+ if (this._tracked.some(t => (Date.now() - t.started) > GH_TAP_TIMEOUT)) {
+ this._state = GH_NOGESTURE;
+ }
+
+ let touch = this._tracked.find(t => t.id === id);
+ touch.active = false;
+
+ // Are we still waiting for more releases?
+ if (this._hasDetectedGesture()) {
+ this._pushEvent('gesturestart');
+ } else {
+ // Have we reached a dead end?
+ if (this._state !== GH_NOGESTURE) {
+ return;
+ }
+ }
+ }
+
+ if (this._hasDetectedGesture()) {
+ this._pushEvent('gestureend');
+ }
+
+ // Ignore any remaining touches until they are ended
+ for (let i = 0; i < this._tracked.length; i++) {
+ if (this._tracked[i].active) {
+ this._ignored.push(this._tracked[i].id);
+ }
+ }
+ this._tracked = [];
+
+ this._state = GH_NOGESTURE;
+
+ // Remove this touch from ignored if it's in there
+ if (this._ignored.indexOf(id) !== -1) {
+ this._ignored.splice(this._ignored.indexOf(id), 1);
+ }
+
+ // We reset the state if ignored is empty
+ if ((this._ignored.length === 0)) {
+ this._state = GH_INITSTATE;
+ this._waitingRelease = false;
+ }
+ }
+
+ _hasDetectedGesture() {
+ if (this._state === GH_NOGESTURE) {
+ return false;
+ }
+ // Check to see if the bitmask value is a power of 2
+ // (i.e. only one bit set). If it is, we have a state.
+ if (this._state & (this._state - 1)) {
+ return false;
+ }
+
+ // For taps we also need to have all touches released
+ // before we've fully detected the gesture
+ if (this._state & (GH_ONETAP | GH_TWOTAP | GH_THREETAP)) {
+ if (this._tracked.some(t => t.active)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ _startLongpressTimeout() {
+ this._stopLongpressTimeout();
+ this._longpressTimeoutId = setTimeout(() => this._longpressTimeout(),
+ GH_LONGPRESS_TIMEOUT);
+ }
+
+ _stopLongpressTimeout() {
+ clearTimeout(this._longpressTimeoutId);
+ this._longpressTimeoutId = null;
+ }
+
+ _longpressTimeout() {
+ if (this._hasDetectedGesture()) {
+ throw new Error("A longpress gesture failed, conflict with a different gesture");
+ }
+
+ this._state = GH_LONGPRESS;
+ this._pushEvent('gesturestart');
+ }
+
+ _startTwoTouchTimeout() {
+ this._stopTwoTouchTimeout();
+ this._twoTouchTimeoutId = setTimeout(() => this._twoTouchTimeout(),
+ GH_TWOTOUCH_TIMEOUT);
+ }
+
+ _stopTwoTouchTimeout() {
+ clearTimeout(this._twoTouchTimeoutId);
+ this._twoTouchTimeoutId = null;
+ }
+
+ _isTwoTouchTimeoutRunning() {
+ return this._twoTouchTimeoutId !== null;
+ }
+
+ _twoTouchTimeout() {
+ if (this._tracked.length === 0) {
+ throw new Error("A pinch or two drag gesture failed, no tracked touches");
+ }
+
+ // How far each touch point has moved since start
+ let avgM = this._getAverageMovement();
+ let avgMoveH = Math.abs(avgM.x);
+ let avgMoveV = Math.abs(avgM.y);
+
+ // The difference in the distance between where
+ // the touch points started and where they are now
+ let avgD = this._getAverageDistance();
+ let deltaTouchDistance = Math.abs(Math.hypot(avgD.first.x, avgD.first.y) -
+ Math.hypot(avgD.last.x, avgD.last.y));
+
+ if ((avgMoveV < deltaTouchDistance) &&
+ (avgMoveH < deltaTouchDistance)) {
+ this._state = GH_PINCH;
+ } else {
+ this._state = GH_TWODRAG;
+ }
+
+ this._pushEvent('gesturestart');
+ this._pushEvent('gesturemove');
+ }
+
+ _pushEvent(type) {
+ let detail = { type: this._stateToGesture(this._state) };
+
+ // For most gesture events the current (average) position is the
+ // most useful
+ let avg = this._getPosition();
+ let pos = avg.last;
+
+ // However we have a slight distance to detect gestures, so for the
+ // first gesture event we want to use the first positions we saw
+ if (type === 'gesturestart') {
+ pos = avg.first;
+ }
+
+ // For these gestures, we always want the event coordinates
+ // to be where the gesture began, not the current touch location.
+ switch (this._state) {
+ case GH_TWODRAG:
+ case GH_PINCH:
+ pos = avg.first;
+ break;
+ }
+
+ detail['clientX'] = pos.x;
+ detail['clientY'] = pos.y;
+
+ // FIXME: other coordinates?
+
+ // Some gestures also have a magnitude
+ if (this._state === GH_PINCH) {
+ let distance = this._getAverageDistance();
+ if (type === 'gesturestart') {
+ detail['magnitudeX'] = distance.first.x;
+ detail['magnitudeY'] = distance.first.y;
+ } else {
+ detail['magnitudeX'] = distance.last.x;
+ detail['magnitudeY'] = distance.last.y;
+ }
+ } else if (this._state === GH_TWODRAG) {
+ if (type === 'gesturestart') {
+ detail['magnitudeX'] = 0.0;
+ detail['magnitudeY'] = 0.0;
+ } else {
+ let movement = this._getAverageMovement();
+ detail['magnitudeX'] = movement.x;
+ detail['magnitudeY'] = movement.y;
+ }
+ }
+
+ let gev = new CustomEvent(type, { detail: detail });
+ this._target.dispatchEvent(gev);
+ }
+
+ _stateToGesture(state) {
+ switch (state) {
+ case GH_ONETAP:
+ return 'onetap';
+ case GH_TWOTAP:
+ return 'twotap';
+ case GH_THREETAP:
+ return 'threetap';
+ case GH_DRAG:
+ return 'drag';
+ case GH_LONGPRESS:
+ return 'longpress';
+ case GH_TWODRAG:
+ return 'twodrag';
+ case GH_PINCH:
+ return 'pinch';
+ }
+
+ throw new Error("Unknown gesture state: " + state);
+ }
+
+ _getPosition() {
+ if (this._tracked.length === 0) {
+ throw new Error("Failed to get gesture position, no tracked touches");
+ }
+
+ let size = this._tracked.length;
+ let fx = 0, fy = 0, lx = 0, ly = 0;
+
+ for (let i = 0; i < this._tracked.length; i++) {
+ fx += this._tracked[i].firstX;
+ fy += this._tracked[i].firstY;
+ lx += this._tracked[i].lastX;
+ ly += this._tracked[i].lastY;
+ }
+
+ return { first: { x: fx / size,
+ y: fy / size },
+ last: { x: lx / size,
+ y: ly / size } };
+ }
+
+ _getAverageMovement() {
+ if (this._tracked.length === 0) {
+ throw new Error("Failed to get gesture movement, no tracked touches");
+ }
+
+ let totalH, totalV;
+ totalH = totalV = 0;
+ let size = this._tracked.length;
+
+ for (let i = 0; i < this._tracked.length; i++) {
+ totalH += this._tracked[i].lastX - this._tracked[i].firstX;
+ totalV += this._tracked[i].lastY - this._tracked[i].firstY;
+ }
+
+ return { x: totalH / size,
+ y: totalV / size };
+ }
+
+ _getAverageDistance() {
+ if (this._tracked.length === 0) {
+ throw new Error("Failed to get gesture distance, no tracked touches");
+ }
+
+ // Distance between the first and last tracked touches
+
+ let first = this._tracked[0];
+ let last = this._tracked[this._tracked.length - 1];
+
+ let fdx = Math.abs(last.firstX - first.firstX);
+ let fdy = Math.abs(last.firstY - first.firstY);
+
+ let ldx = Math.abs(last.lastX - first.lastX);
+ let ldy = Math.abs(last.lastY - first.lastY);
+
+ return { first: { x: fdx, y: fdy },
+ last: { x: ldx, y: ldy } };
+ }
+}
diff --git a/systemvm/agent/noVNC/core/input/keyboard.js b/systemvm/agent/noVNC/core/input/keyboard.js
index 9dbc8d6..9e6af2a 100644
--- a/systemvm/agent/noVNC/core/input/keyboard.js
+++ b/systemvm/agent/noVNC/core/input/keyboard.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
*/
@@ -118,9 +118,7 @@ export default class Keyboard {
// We cannot handle keys we cannot track, but we also need
// to deal with virtual keyboards which omit key info
- // (iOS omits tracking info on keyup events, which forces us to
- // special treat that platform here)
- if ((code === 'Unidentified') || browser.isIOS()) {
+ if (code === 'Unidentified') {
if (keysym) {
// If it's a virtual keyboard then it should be
// sufficient to just send press and release right
@@ -137,7 +135,7 @@ export default class Keyboard {
// keys around a bit to make things more sane for the remote
// server. This method is used by RealVNC and TigerVNC (and
// possibly others).
- if (browser.isMac()) {
+ if (browser.isMac() || browser.isIOS()) {
switch (keysym) {
case KeyTable.XK_Super_L:
keysym = KeyTable.XK_Alt_L;
@@ -164,7 +162,7 @@ export default class Keyboard {
// state change events. That gets extra confusing for CapsLock
// which toggles on each press, but not on release. So pretend
// it was a quick press and release of the button.
- if (browser.isMac() && (code === 'CapsLock')) {
+ if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
stopEvent(e);
@@ -276,13 +274,28 @@ export default class Keyboard {
}
// See comment in _handleKeyDown()
- if (browser.isMac() && (code === 'CapsLock')) {
+ if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) {
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true);
this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false);
return;
}
this._sendKeyEvent(this._keyDownList[code], code, false);
+
+ // Windows has a rather nasty bug where it won't send key
+ // release events for a Shift button if the other Shift is still
+ // pressed
+ if (browser.isWindows() && ((code === 'ShiftLeft') ||
+ (code === 'ShiftRight'))) {
+ if ('ShiftRight' in this._keyDownList) {
+ this._sendKeyEvent(this._keyDownList['ShiftRight'],
+ 'ShiftRight', false);
+ }
+ if ('ShiftLeft' in this._keyDownList) {
+ this._sendKeyEvent(this._keyDownList['ShiftLeft'],
+ 'ShiftLeft', false);
+ }
+ }
}
_handleAltGrTimeout() {
@@ -299,8 +312,11 @@ export default class Keyboard {
Log.Debug("<< Keyboard.allKeysUp");
}
- // Firefox Alt workaround, see below
+ // Alt workaround for Firefox on Windows, see below
_checkAlt(e) {
+ if (e.skipCheckAlt) {
+ return;
+ }
if (e.altKey) {
return;
}
@@ -315,6 +331,7 @@ export default class Keyboard {
const event = new KeyboardEvent('keyup',
{ key: downList[code],
code: code });
+ event.skipCheckAlt = true;
target.dispatchEvent(event);
});
}
@@ -331,9 +348,10 @@ export default class Keyboard {
// Release (key up) if window loses focus
window.addEventListener('blur', this._eventHandlers.blur);
- // Firefox has broken handling of Alt, so we need to poll as
- // best we can for releases (still doesn't prevent the menu
- // from popping up though as we can't call preventDefault())
+ // Firefox on Windows has broken handling of Alt, so we need to
+ // poll as best we can for releases (still doesn't prevent the
+ // menu from popping up though as we can't call
+ // preventDefault())
if (browser.isWindows() && browser.isFirefox()) {
const handler = this._eventHandlers.checkalt;
['mousedown', 'mouseup', 'mousemove', 'wheel',
diff --git a/systemvm/agent/noVNC/core/input/mouse.js b/systemvm/agent/noVNC/core/input/mouse.js
deleted file mode 100644
index 58a2982..0000000
--- a/systemvm/agent/noVNC/core/input/mouse.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
- * Licensed under MPL 2.0 or any later version (see LICENSE.txt)
- */
-
-import * as Log from '../util/logging.js';
-import { isTouchDevice } from '../util/browser.js';
-import { setCapture, stopEvent, getPointerEvent } from '../util/events.js';
-
-const WHEEL_STEP = 10; // Delta threshold for a mouse wheel step
-const WHEEL_STEP_TIMEOUT = 50; // ms
-const WHEEL_LINE_HEIGHT = 19;
-
-export default class Mouse {
- constructor(target) {
- this._target = target || document;
-
- this._doubleClickTimer = null;
- this._lastTouchPos = null;
-
- this._pos = null;
- this._wheelStepXTimer = null;
- this._wheelStepYTimer = null;
- this._accumulatedWheelDeltaX = 0;
- this._accumulatedWheelDeltaY = 0;
-
- this._eventHandlers = {
- 'mousedown': this._handleMouseDown.bind(this),
- 'mouseup': this._handleMouseUp.bind(this),
- 'mousemove': this._handleMouseMove.bind(this),
- 'mousewheel': this._handleMouseWheel.bind(this),
- 'mousedisable': this._handleMouseDisable.bind(this)
- };
-
- // ===== PROPERTIES =====
-
- this.touchButton = 1; // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
-
- // ===== EVENT HANDLERS =====
-
- this.onmousebutton = () => {}; // Handler for mouse button click/release
- this.onmousemove = () => {}; // Handler for mouse movement
- }
-
- // ===== PRIVATE METHODS =====
-
- _resetDoubleClickTimer() {
- this._doubleClickTimer = null;
- }
-
- _handleMouseButton(e, down) {
- this._updateMousePosition(e);
- let pos = this._pos;
-
- let bmask;
- if (e.touches || e.changedTouches) {
- // Touch device
-
- // When two touches occur within 500 ms of each other and are
- // close enough together a double click is triggered.
- if (down == 1) {
- if (this._doubleClickTimer === null) {
- this._lastTouchPos = pos;
- } else {
- clearTimeout(this._doubleClickTimer);
-
- // When the distance between the two touches is small enough
- // force the position of the latter touch to the position of
- // the first.
-
- const xs = this._lastTouchPos.x - pos.x;
- const ys = this._lastTouchPos.y - pos.y;
- const d = Math.sqrt((xs * xs) + (ys * ys));
-
- // The goal is to trigger on a certain physical width, the
- // devicePixelRatio brings us a bit closer but is not optimal.
- const threshold = 20 * (window.devicePixelRatio || 1);
- if (d < threshold) {
- pos = this._lastTouchPos;
- }
- }
- this._doubleClickTimer = setTimeout(this._resetDoubleClickTimer.bind(this), 500);
- }
- bmask = this.touchButton;
- // If bmask is set
- } else if (e.which) {
- /* everything except IE */
- bmask = 1 << e.button;
- } else {
- /* IE including 9 */
- bmask = (e.button & 0x1) + // Left
- (e.button & 0x2) * 2 + // Right
- (e.button & 0x4) / 2; // Middle
- }
-
- Log.Debug("onmousebutton " + (down ? "down" : "up") +
- ", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
- this.onmousebutton(pos.x, pos.y, down, bmask);
-
- stopEvent(e);
- }
-
- _handleMouseDown(e) {
- // Touch events have implicit capture
- if (e.type === "mousedown") {
- setCapture(this._target);
- }
-
- this._handleMouseButton(e, 1);
- }
-
- _handleMouseUp(e) {
- this._handleMouseButton(e, 0);
- }
-
- // Mouse wheel events are sent in steps over VNC. This means that the VNC
- // protocol can't handle a wheel event with specific distance or speed.
- // Therefor, if we get a lot of small mouse wheel events we combine them.
- _generateWheelStepX() {
-
- if (this._accumulatedWheelDeltaX < 0) {
- this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 5);
- this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 5);
- } else if (this._accumulatedWheelDeltaX > 0) {
- this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 6);
- this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 6);
- }
-
- this._accumulatedWheelDeltaX = 0;
- }
-
- _generateWheelStepY() {
-
- if (this._accumulatedWheelDeltaY < 0) {
- this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 3);
- this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 3);
- } else if (this._accumulatedWheelDeltaY > 0) {
- this.onmousebutton(this._pos.x, this._pos.y, 1, 1 << 4);
- this.onmousebutton(this._pos.x, this._pos.y, 0, 1 << 4);
- }
-
- this._accumulatedWheelDeltaY = 0;
- }
-
- _resetWheelStepTimers() {
- window.clearTimeout(this._wheelStepXTimer);
- window.clearTimeout(this._wheelStepYTimer);
- this._wheelStepXTimer = null;
- this._wheelStepYTimer = null;
- }
-
- _handleMouseWheel(e) {
- this._resetWheelStepTimers();
-
- this._updateMousePosition(e);
-
- let dX = e.deltaX;
- let dY = e.deltaY;
-
- // Pixel units unless it's non-zero.
- // Note that if deltamode is line or page won't matter since we aren't
- // sending the mouse wheel delta to the server anyway.
- // The difference between pixel and line can be important however since
- // we have a threshold that can be smaller than the line height.
- if (e.deltaMode !== 0) {
- dX *= WHEEL_LINE_HEIGHT;
- dY *= WHEEL_LINE_HEIGHT;
- }
-
- this._accumulatedWheelDeltaX += dX;
- this._accumulatedWheelDeltaY += dY;
-
- // Generate a mouse wheel step event when the accumulated delta
- // for one of the axes is large enough.
- // Small delta events that do not pass the threshold get sent
- // after a timeout.
- if (Math.abs(this._accumulatedWheelDeltaX) > WHEEL_STEP) {
- this._generateWheelStepX();
- } else {
- this._wheelStepXTimer =
- window.setTimeout(this._generateWheelStepX.bind(this),
- WHEEL_STEP_TIMEOUT);
- }
- if (Math.abs(this._accumulatedWheelDeltaY) > WHEEL_STEP) {
- this._generateWheelStepY();
- } else {
- this._wheelStepYTimer =
- window.setTimeout(this._generateWheelStepY.bind(this),
- WHEEL_STEP_TIMEOUT);
- }
-
- stopEvent(e);
- }
-
- _handleMouseMove(e) {
- this._updateMousePosition(e);
- this.onmousemove(this._pos.x, this._pos.y);
- stopEvent(e);
- }
-
- _handleMouseDisable(e) {
- /*
- * Stop propagation if inside canvas area
- * Note: This is only needed for the 'click' event as it fails
- * to fire properly for the target element so we have
- * to listen on the document element instead.
- */
- if (e.target == this._target) {
- stopEvent(e);
- }
- }
-
- // Update coordinates relative to target
- _updateMousePosition(e) {
- e = getPointerEvent(e);
- const bounds = this._target.getBoundingClientRect();
- let x;
- let y;
- // Clip to target bounds
- if (e.clientX < bounds.left) {
- x = 0;
- } else if (e.clientX >= bounds.right) {
- x = bounds.width - 1;
- } else {
- x = e.clientX - bounds.left;
- }
- if (e.clientY < bounds.top) {
- y = 0;
- } else if (e.clientY >= bounds.bottom) {
- y = bounds.height - 1;
- } else {
- y = e.clientY - bounds.top;
- }
- this._pos = {x: x, y: y};
- }
-
- // ===== PUBLIC METHODS =====
-
- grab() {
- if (isTouchDevice) {
- this._target.addEventListener('touchstart', this._eventHandlers.mousedown);
- this._target.addEventListener('touchend', this._eventHandlers.mouseup);
- this._target.addEventListener('touchmove', this._eventHandlers.mousemove);
- }
- this._target.addEventListener('mousedown', this._eventHandlers.mousedown);
- this._target.addEventListener('mouseup', this._eventHandlers.mouseup);
- this._target.addEventListener('mousemove', this._eventHandlers.mousemove);
- this._target.addEventListener('wheel', this._eventHandlers.mousewheel);
-
- /* Prevent middle-click pasting (see above for why we bind to document) */
- document.addEventListener('click', this._eventHandlers.mousedisable);
-
- /* preventDefault() on mousedown doesn't stop this event for some
- reason so we have to explicitly block it */
- this._target.addEventListener('contextmenu', this._eventHandlers.mousedisable);
- }
-
- ungrab() {
- this._resetWheelStepTimers();
-
- if (isTouchDevice) {
- this._target.removeEventListener('touchstart', this._eventHandlers.mousedown);
- this._target.removeEventListener('touchend', this._eventHandlers.mouseup);
- this._target.removeEventListener('touchmove', this._eventHandlers.mousemove);
- }
- this._target.removeEventListener('mousedown', this._eventHandlers.mousedown);
- this._target.removeEventListener('mouseup', this._eventHandlers.mouseup);
- this._target.removeEventListener('mousemove', this._eventHandlers.mousemove);
- this._target.removeEventListener('wheel', this._eventHandlers.mousewheel);
-
- document.removeEventListener('click', this._eventHandlers.mousedisable);
-
- this._target.removeEventListener('contextmenu', this._eventHandlers.mousedisable);
- }
-}
diff --git a/systemvm/agent/noVNC/core/input/uskeysym.js b/systemvm/agent/noVNC/core/input/uskeysym.js
new file mode 100644
index 0000000..97c5ae4
--- /dev/null
+++ b/systemvm/agent/noVNC/core/input/uskeysym.js
@@ -0,0 +1,57 @@
+export default {
+ '1': 0x0031, /* U+0031 DIGIT ONE */
+ '2': 0x0032, /* U+0032 DIGIT TWO */
+ '3': 0x0033, /* U+0033 DIGIT THREE */
+ '4': 0x0034, /* U+0034 DIGIT FOUR */
+ '5': 0x0035, /* U+0035 DIGIT FIVE */
+ '6': 0x0036, /* U+0036 DIGIT SIX */
+ '7': 0x0037, /* U+0037 DIGIT SEVEN */
+ '8': 0x0038, /* U+0038 DIGIT EIGHT */
+ '9': 0x0039, /* U+0039 DIGIT NINE */
+ '0': 0x0030, /* U+0030 DIGIT ZERO */
+
+ 'a': 0x0061, /* U+0061 LATIN SMALL LETTER A */
+ 'b': 0x0062, /* U+0062 LATIN SMALL LETTER B */
+ 'c': 0x0063, /* U+0063 LATIN SMALL LETTER C */
+ 'd': 0x0064, /* U+0064 LATIN SMALL LETTER D */
+ 'e': 0x0065, /* U+0065 LATIN SMALL LETTER E */
+ 'f': 0x0066, /* U+0066 LATIN SMALL LETTER F */
+ 'g': 0x0067, /* U+0067 LATIN SMALL LETTER G */
+ 'h': 0x0068, /* U+0068 LATIN SMALL LETTER H */
+ 'i': 0x0069, /* U+0069 LATIN SMALL LETTER I */
+ 'j': 0x006a, /* U+006A LATIN SMALL LETTER J */
+ 'k': 0x006b, /* U+006B LATIN SMALL LETTER K */
+ 'l': 0x006c, /* U+006C LATIN SMALL LETTER L */
+ 'm': 0x006d, /* U+006D LATIN SMALL LETTER M */
+ 'n': 0x006e, /* U+006E LATIN SMALL LETTER N */
+ 'o': 0x006f, /* U+006F LATIN SMALL LETTER O */
+ 'p': 0x0070, /* U+0070 LATIN SMALL LETTER P */
+ 'q': 0x0071, /* U+0071 LATIN SMALL LETTER Q */
+ 'r': 0x0072, /* U+0072 LATIN SMALL LETTER R */
+ 's': 0x0073, /* U+0073 LATIN SMALL LETTER S */
+ 't': 0x0074, /* U+0074 LATIN SMALL LETTER T */
+ 'u': 0x0075, /* U+0075 LATIN SMALL LETTER U */
+ 'v': 0x0076, /* U+0076 LATIN SMALL LETTER V */
+ 'w': 0x0077, /* U+0077 LATIN SMALL LETTER W */
+ 'x': 0x0078, /* U+0078 LATIN SMALL LETTER X */
+ 'y': 0x0079, /* U+0079 LATIN SMALL LETTER Y */
+ 'z': 0x007a, /* U+007A LATIN SMALL LETTER Z */
+
+ '`': 0x0060, /* U+0060 GRAVE ACCENT */
+ '-': 0x002d, /* U+002D HYPHEN-MINUS */
+ '=': 0x003d, /* U+003D EQUALS SIGN */
+
+ '[': 0x005b, /* U+005B LEFT SQUARE BRACKET */
+ ']': 0x005d, /* U+005D RIGHT SQUARE BRACKET */
+ '\\': 0x005c, /* U+005C REVERSE SOLIDUS */
+
+ ';': 0x003b, /* U+003B SEMICOLON */
+ '\'': 0x0027, /* U+0027 APOSTROPHE */
+
+ ',': 0x002c, /* U+002C COMMA */
+ '.': 0x002e, /* U+002E FULL STOP */
+ '/': 0x002f, /* U+002F SOLIDUS */
+
+ ' ': 0x0020, /* U+0020 SPACE */
+ '\n': 0xff0d
+}
\ No newline at end of file
diff --git a/systemvm/agent/noVNC/core/input/util.js b/systemvm/agent/noVNC/core/input/util.js
index f177ef5..1b98040 100644
--- a/systemvm/agent/noVNC/core/input/util.js
+++ b/systemvm/agent/noVNC/core/input/util.js
@@ -1,3 +1,4 @@
+import KeyTable from "./keysym.js";
import keysyms from "./keysymdef.js";
import vkeys from "./vkeys.js";
import fixedkeys from "./fixedkeys.js";
@@ -91,6 +92,8 @@ export function getKey(evt) {
// Mozilla isn't fully in sync with the spec yet
switch (evt.key) {
case 'OS': return 'Meta';
+ case 'LaunchMyComputer': return 'LaunchApplication1';
+ case 'LaunchCalculator': return 'LaunchApplication2';
}
// iOS leaks some OS names
@@ -102,9 +105,21 @@ export function getKey(evt) {
case 'UIKeyInputEscape': return 'Escape';
}
- // IE and Edge have broken handling of AltGraph so we cannot
- // trust them for printable characters
- if ((evt.key.length !== 1) || (!browser.isIE() && !browser.isEdge())) {
+ // Broken behaviour in Chrome
+ if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) {
+ return 'Delete';
+ }
+
+ // IE and Edge need special handling, but for everyone else we
+ // can trust the value provided
+ if (!browser.isIE() && !browser.isEdge()) {
+ return evt.key;
+ }
+
+ // IE and Edge have broken handling of AltGraph so we can only
+ // trust them for non-printable characters (and unfortunately
+ // they also specify 'Unidentified' for some problem keys)
+ if ((evt.key.length !== 1) && (evt.key !== 'Unidentified')) {
return evt.key;
}
}
@@ -141,10 +156,39 @@ export function getKeysym(evt) {
location = 2;
}
+ // And for Clear
+ if ((key === 'Clear') && (location === 3)) {
+ let code = getKeycode(evt);
+ if (code === 'NumLock') {
+ location = 0;
+ }
+ }
+
if ((location === undefined) || (location > 3)) {
location = 0;
}
+ // The original Meta key now gets confused with the Windows key
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=1020141
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1232918
+ if (key === 'Meta') {
+ let code = getKeycode(evt);
+ if (code === 'AltLeft') {
+ return KeyTable.XK_Meta_L;
+ } else if (code === 'AltRight') {
+ return KeyTable.XK_Meta_R;
+ }
+ }
+
+ // macOS has Clear instead of NumLock, but the remote system is
+ // probably not macOS, so lying here is probably best...
+ if (key === 'Clear') {
+ let code = getKeycode(evt);
+ if (code === 'NumLock') {
+ return KeyTable.XK_Num_Lock;
+ }
+ }
+
return DOMKeyTable[key][location];
}
diff --git a/systemvm/agent/noVNC/core/rfb.js b/systemvm/agent/noVNC/core/rfb.js
index e40df66..eda1597 100644
--- a/systemvm/agent/noVNC/core/rfb.js
+++ b/systemvm/agent/noVNC/core/rfb.js
@@ -1,23 +1,29 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2020 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*
*/
+import { toUnsigned32bit, toSigned32bit } from './util/int.js';
import * as Log from './util/logging.js';
-import { decodeUTF8 } from './util/strings.js';
+import { encodeUTF8, decodeUTF8 } from './util/strings.js';
import { dragThreshold } from './util/browser.js';
+import { clientToElement } from './util/element.js';
+import { setCapture } from './util/events.js';
import EventTargetMixin from './util/eventtarget.js';
import Display from "./display.js";
+import Inflator from "./inflator.js";
+import Deflator from "./deflator.js";
import Keyboard from "./input/keyboard.js";
-import Mouse from "./input/mouse.js";
+import GestureHandler from "./input/gesturehandler.js";
import Cursor from "./util/cursor.js";
import Websock from "./websock.js";
import DES from "./des.js";
import KeyTable from "./input/keysym.js";
+import USKeyTable from "./input/uskeysym.js";
import XtScancode from "./input/xtscancodes.js";
import { encodings } from "./encodings.js";
import "./util/polyfill.js";
@@ -33,6 +39,36 @@ import TightPNGDecoder from "./decoders/tightpng.js";
const DISCONNECT_TIMEOUT = 3;
const DEFAULT_BACKGROUND = 'rgb(40, 40, 40)';
+// Minimum wait (ms) between two mouse moves
+const MOUSE_MOVE_DELAY = 17;
+
+// Wheel thresholds
+const WHEEL_STEP = 50; // Pixels needed for one step
+const WHEEL_LINE_HEIGHT = 19; // Assumed pixels for one line step
+
+// Gesture thresholds
+const GESTURE_ZOOMSENS = 75;
+const GESTURE_SCRLSENS = 50;
+const DOUBLE_TAP_TIMEOUT = 1000;
+const DOUBLE_TAP_THRESHOLD = 50;
+
+// Extended clipboard pseudo-encoding formats
+const extendedClipboardFormatText = 1;
+/*eslint-disable no-unused-vars */
+const extendedClipboardFormatRtf = 1 << 1;
+const extendedClipboardFormatHtml = 1 << 2;
+const extendedClipboardFormatDib = 1 << 3;
+const extendedClipboardFormatFiles = 1 << 4;
+/*eslint-enable */
+
+// Extended clipboard pseudo-encoding actions
+const extendedClipboardActionCaps = 1 << 24;
+const extendedClipboardActionRequest = 1 << 25;
+const extendedClipboardActionPeek = 1 << 26;
+const extendedClipboardActionNotify = 1 << 27;
+const extendedClipboardActionProvide = 1 << 28;
+
+
export default class RFB extends EventTargetMixin {
constructor(target, url, options) {
if (!target) {
@@ -49,27 +85,28 @@ export default class RFB extends EventTargetMixin {
// Connection details
options = options || {};
- this._rfb_credentials = options.credentials || {};
- this._shared = false;
+ this._rfbCredentials = options.credentials || {};
+ this._shared = 'shared' in options ? !!options.shared : true;
this._repeaterID = options.repeaterID || '';
- this._showDotCursor = options.showDotCursor || false;
+ this._wsProtocols = ['binary'];
// Internal state
- this._rfb_connection_state = '';
- this._rfb_init_state = '';
- this._rfb_auth_scheme = -1;
- this._rfb_clean_disconnect = true;
+ this._rfbConnectionState = '';
+ this._rfbInitState = '';
+ this._rfbAuthScheme = -1;
+ this._rfbCleanDisconnect = true;
// Server capabilities
- this._rfb_version = 0;
- this._rfb_max_version = 3.8;
- this._rfb_tightvnc = false;
- this._rfb_xvp_ver = 0;
+ this._rfbVersion = 0;
+ this._rfbMaxVersion = 3.8;
+ this._rfbTightVNC = false;
+ this._rfbVeNCryptState = 0;
+ this._rfbXvpVer = 0;
- this._fb_width = 0;
- this._fb_height = 0;
+ this._fbWidth = 0;
+ this._fbHeight = 0;
- this._fb_name = "";
+ this._fbName = "";
this._capabilities = { power: false };
@@ -79,21 +116,26 @@ export default class RFB extends EventTargetMixin {
this._enabledContinuousUpdates = false;
this._supportsSetDesktopSize = false;
- this._screen_id = 0;
- this._screen_flags = 0;
+ this._screenID = 0;
+ this._screenFlags = 0;
this._qemuExtKeyEventSupported = false;
+ this._clipboardText = null;
+ this._clipboardServerCapabilitiesActions = {};
+ this._clipboardServerCapabilitiesFormats = {};
+
// Internal objects
this._sock = null; // Websock object
this._display = null; // Display object
this._flushing = false; // Display flushing state
this._keyboard = null; // Keyboard input handler object
- this._mouse = null; // Mouse input handler object
+ this._gestures = null; // Gesture input handler object
// Timers
this._disconnTimer = null; // disconnection timer
this._resizeTimeout = null; // resize rate limiting
+ this._mouseMoveTimer = null;
// Decoder states
this._decoders = {};
@@ -108,16 +150,28 @@ export default class RFB extends EventTargetMixin {
};
// Mouse state
- this._mouse_buttonMask = 0;
- this._mouse_arr = [];
+ this._mousePos = {};
+ this._mouseButtonMask = 0;
+ this._mouseLastMoveTime = 0;
this._viewportDragging = false;
this._viewportDragPos = {};
this._viewportHasMoved = false;
+ this._accumulatedWheelDeltaX = 0;
+ this._accumulatedWheelDeltaY = 0;
+
+ // Gesture state
+ this._gestureLastTapTime = null;
+ this._gestureFirstDoubleTapEv = null;
+ this._gestureLastMagnitudeX = 0;
+ this._gestureLastMagnitudeY = 0;
// Bound event handlers
this._eventHandlers = {
focusCanvas: this._focusCanvas.bind(this),
windowResize: this._windowResize.bind(this),
+ handleMouse: this._handleMouse.bind(this),
+ handleWheel: this._handleWheel.bind(this),
+ handleGesture: this._handleGesture.bind(this),
};
// main setup
@@ -172,27 +226,24 @@ export default class RFB extends EventTargetMixin {
throw exc;
}
this._display.onflush = this._onFlush.bind(this);
- this._display.clear();
this._keyboard = new Keyboard(this._canvas);
this._keyboard.onkeyevent = this._handleKeyEvent.bind(this);
- this._mouse = new Mouse(this._canvas);
- this._mouse.onmousebutton = this._handleMouseButton.bind(this);
- this._mouse.onmousemove = this._handleMouseMove.bind(this);
+ this._gestures = new GestureHandler();
this._sock = new Websock();
this._sock.on('message', () => {
- this._handle_message();
+ this._handleMessage();
});
this._sock.on('open', () => {
- if ((this._rfb_connection_state === 'connecting') &&
- (this._rfb_init_state === '')) {
- this._rfb_init_state = 'ProtocolVersion';
+ if ((this._rfbConnectionState === 'connecting') &&
+ (this._rfbInitState === '')) {
+ this._rfbInitState = 'ProtocolVersion';
Log.Debug("Starting VNC handshake");
} else {
this._fail("Unexpected server connection while " +
- this._rfb_connection_state);
+ this._rfbConnectionState);
}
});
this._sock.on('close', (e) => {
@@ -205,7 +256,7 @@ export default class RFB extends EventTargetMixin {
}
msg += ")";
}
- switch (this._rfb_connection_state) {
+ switch (this._rfbConnectionState) {
case 'connecting':
this._fail("Connection closed " + msg);
break;
@@ -246,6 +297,15 @@ export default class RFB extends EventTargetMixin {
this._clipViewport = false;
this._scaleViewport = false;
this._resizeSession = false;
+
+ this._showDotCursor = false;
+ if (options.showDotCursor !== undefined) {
+ Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated");
+ this._showDotCursor = options.showDotCursor;
+ }
+
+ this._qualityLevel = 6;
+ this._compressionLevel = 2;
}
// ===== PROPERTIES =====
@@ -254,22 +314,20 @@ export default class RFB extends EventTargetMixin {
set viewOnly(viewOnly) {
this._viewOnly = viewOnly;
- if (this._rfb_connection_state === "connecting" ||
- this._rfb_connection_state === "connected") {
+ if (this._rfbConnectionState === "connecting" ||
+ this._rfbConnectionState === "connected") {
if (viewOnly) {
this._keyboard.ungrab();
- this._mouse.ungrab();
} else {
this._keyboard.grab();
- this._mouse.grab();
}
}
}
get capabilities() { return this._capabilities; }
- get touchButton() { return this._mouse.touchButton; }
- set touchButton(button) { this._mouse.touchButton = button; }
+ get touchButton() { return 0; }
+ set touchButton(button) { Log.Warn("Using old API!"); }
get clipViewport() { return this._clipViewport; }
set clipViewport(viewport) {
@@ -308,6 +366,46 @@ export default class RFB extends EventTargetMixin {
get background() { return this._screen.style.background; }
set background(cssValue) { this._screen.style.background = cssValue; }
+ get qualityLevel() {
+ return this._qualityLevel;
+ }
+ set qualityLevel(qualityLevel) {
+ if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) {
+ Log.Error("qualityLevel must be an integer between 0 and 9");
+ return;
+ }
+
+ if (this._qualityLevel === qualityLevel) {
+ return;
+ }
+
+ this._qualityLevel = qualityLevel;
+
+ if (this._rfbConnectionState === 'connected') {
+ this._sendEncodings();
+ }
+ }
+
+ get compressionLevel() {
+ return this._compressionLevel;
+ }
+ set compressionLevel(compressionLevel) {
+ if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) {
+ Log.Error("compressionLevel must be an integer between 0 and 9");
+ return;
+ }
+
+ if (this._compressionLevel === compressionLevel) {
+ return;
+ }
+
+ this._compressionLevel = compressionLevel;
+
+ if (this._rfbConnectionState === 'connected') {
+ this._sendEncodings();
+ }
+ }
+
// ===== PUBLIC METHODS =====
disconnect() {
@@ -318,12 +416,29 @@ export default class RFB extends EventTargetMixin {
}
sendCredentials(creds) {
- this._rfb_credentials = creds;
- setTimeout(this._init_msg.bind(this), 0);
+ this._rfbCredentials = creds;
+ setTimeout(this._initMsg.bind(this), 0);
+ }
+
+ sendText(text) {
+ for (var i = 0; i < text.length; i++) {
+ const character = text.charAt(i);
+ var charCode = USKeyTable[character] || false;
+ if (charCode) {
+ this.sendKey(charCode, character, true);
+ this.sendKey(charCode, character, false);
+ } else {
+ charCode = text.charCodeAt(i)
+ this.sendKey(KeyTable.XK_Shift_L, "ShiftLeft", true);
+ this.sendKey(charCode, character, true);
+ this.sendKey(charCode, character, false);
+ this.sendKey(KeyTable.XK_Shift_L, "ShiftLeft", false);
+ }
+ }
}
sendCtrlAltDel() {
- if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
+ if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
Log.Info("Sending Ctrl-Alt-Del");
this.sendKey(KeyTable.XK_Control_L, "ControlLeft", true);
@@ -359,7 +474,7 @@ export default class RFB extends EventTargetMixin {
// Send a key press. If 'down' is not specified then send a down key
// followed by an up key.
sendKey(keysym, code, down) {
- if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
+ if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
if (down === undefined) {
this.sendKey(keysym, code, true);
@@ -394,8 +509,22 @@ export default class RFB extends EventTargetMixin {
}
clipboardPasteFrom(text) {
- if (this._rfb_connection_state !== 'connected' || this._viewOnly) { return; }
- RFB.messages.clientCutText(this._sock, text);
+ if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; }
+
+ if (this._clipboardServerCapabilitiesFormats[extendedClipboardFormatText] &&
+ this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
+
+ this._clipboardText = text;
+ RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
+ } else {
+ let data = new Uint8Array(text.length);
+ for (let i = 0; i < text.length; i++) {
+ // FIXME: text can have values outside of Latin1/Uint8
+ data[i] = text.charCodeAt(i);
+ }
+
+ RFB.messages.clientCutText(this._sock, data);
+ }
}
// ===== PRIVATE METHODS =====
@@ -407,7 +536,7 @@ export default class RFB extends EventTargetMixin {
try {
// WebSocket.onopen transitions to the RFB init states
- this._sock.open(this._url, ['binary']);
+ this._sock.open(this._url, this._wsProtocols);
} catch (e) {
if (e.name === 'SyntaxError') {
this._fail("Invalid host or port (" + e + ")");
@@ -419,6 +548,8 @@ export default class RFB extends EventTargetMixin {
// Make our elements part of the page
this._target.appendChild(this._screen);
+ this._gestures.attach(this._canvas);
+
this._cursor.attach(this._canvas);
this._refreshCursor();
@@ -430,17 +561,44 @@ export default class RFB extends EventTargetMixin {
this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas);
this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas);
+ // Mouse events
+ this._canvas.addEventListener('mousedown', this._eventHandlers.handleMouse);
+ this._canvas.addEventListener('mouseup', this._eventHandlers.handleMouse);
+ this._canvas.addEventListener('mousemove', this._eventHandlers.handleMouse);
+ // Prevent middle-click pasting (see handler for why we bind to document)
+ this._canvas.addEventListener('click', this._eventHandlers.handleMouse);
+ // preventDefault() on mousedown doesn't stop this event for some
+ // reason so we have to explicitly block it
+ this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse);
+
+ // Wheel events
+ this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel);
+
+ // Gesture events
+ this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture);
+ this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture);
+ this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture);
+
Log.Debug("<< RFB.connect");
}
_disconnect() {
Log.Debug(">> RFB.disconnect");
this._cursor.detach();
+ this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture);
+ this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture);
+ this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture);
+ this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel);
+ this._canvas.removeEventListener('mousedown', this._eventHandlers.handleMouse);
+ this._canvas.removeEventListener('mouseup', this._eventHandlers.handleMouse);
+ this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse);
+ this._canvas.removeEventListener('click', this._eventHandlers.handleMouse);
+ this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse);
this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas);
this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas);
window.removeEventListener('resize', this._eventHandlers.windowResize);
this._keyboard.ungrab();
- this._mouse.ungrab();
+ this._gestures.detach();
this._sock.close();
try {
this._target.removeChild(this._screen);
@@ -453,15 +611,11 @@ export default class RFB extends EventTargetMixin {
}
}
clearTimeout(this._resizeTimeout);
+ clearTimeout(this._mouseMoveTimer);
Log.Debug("<< RFB.disconnect");
}
_focusCanvas(event) {
- // Respect earlier handlers' request to not do side-effects
- if (event.defaultPrevented) {
- return;
- }
-
if (!this.focusOnClick) {
return;
}
@@ -469,6 +623,13 @@ export default class RFB extends EventTargetMixin {
this.focus();
}
+ _setDesktopName(name) {
+ this._fbName = name;
+ this.dispatchEvent(new CustomEvent(
+ "desktopname",
+ { detail: { name: this._fbName } }));
+ }
+
_windowResize(event) {
// If the window resized then our screen element might have
// as well. Update the viewport dimensions.
@@ -491,19 +652,19 @@ export default class RFB extends EventTargetMixin {
// Update state of clipping in Display object, and make sure the
// configured viewport matches the current screen size
_updateClip() {
- const cur_clip = this._display.clipViewport;
- let new_clip = this._clipViewport;
+ const curClip = this._display.clipViewport;
+ let newClip = this._clipViewport;
if (this._scaleViewport) {
// Disable viewport clipping if we are scaling
- new_clip = false;
+ newClip = false;
}
- if (cur_clip !== new_clip) {
- this._display.clipViewport = new_clip;
+ if (curClip !== newClip) {
+ this._display.clipViewport = newClip;
}
- if (new_clip) {
+ if (newClip) {
// When clipping is enabled, the screen is limited to
// the size of the container.
const size = this._screenSize();
@@ -536,7 +697,7 @@ export default class RFB extends EventTargetMixin {
const size = this._screenSize();
RFB.messages.setDesktopSize(this._sock,
Math.floor(size.w), Math.floor(size.h),
- this._screen_id, this._screen_flags);
+ this._screenID, this._screenFlags);
Log.Debug('Requested new desktop size: ' +
size.w + 'x' + size.h);
@@ -568,7 +729,7 @@ export default class RFB extends EventTargetMixin {
* disconnected - permanent state
*/
_updateConnectionState(state) {
- const oldstate = this._rfb_connection_state;
+ const oldstate = this._rfbConnectionState;
if (state === oldstate) {
Log.Debug("Already in state '" + state + "', ignoring");
@@ -622,7 +783,7 @@ export default class RFB extends EventTargetMixin {
// State change actions
- this._rfb_connection_state = state;
+ this._rfbConnectionState = state;
Log.Debug("New state '" + state + "', was '" + oldstate + "'.");
@@ -656,7 +817,7 @@ export default class RFB extends EventTargetMixin {
case 'disconnected':
this.dispatchEvent(new CustomEvent(
"disconnect", { detail:
- { clean: this._rfb_clean_disconnect } }));
+ { clean: this._rfbCleanDisconnect } }));
break;
}
}
@@ -667,7 +828,7 @@ export default class RFB extends EventTargetMixin {
* should be logged but not sent to the user interface.
*/
_fail(details) {
- switch (this._rfb_connection_state) {
+ switch (this._rfbConnectionState) {
case 'disconnecting':
Log.Error("Failed when disconnecting: " + details);
break;
@@ -681,7 +842,7 @@ export default class RFB extends EventTargetMixin {
Log.Error("RFB failure: " + details);
break;
}
- this._rfb_clean_disconnect = false; //This is sent to the UI
+ this._rfbCleanDisconnect = false; //This is sent to the UI
// Transition to disconnected without waiting for socket to close
this._updateConnectionState('disconnecting');
@@ -696,13 +857,13 @@ export default class RFB extends EventTargetMixin {
{ detail: { capabilities: this._capabilities } }));
}
- _handle_message() {
+ _handleMessage() {
if (this._sock.rQlen === 0) {
- Log.Warn("handle_message called on an empty receive queue");
+ Log.Warn("handleMessage called on an empty receive queue");
return;
}
- switch (this._rfb_connection_state) {
+ switch (this._rfbConnectionState) {
case 'disconnected':
Log.Error("Got data while disconnected");
break;
@@ -711,7 +872,7 @@ export default class RFB extends EventTargetMixin {
if (this._flushing) {
break;
}
- if (!this._normal_msg()) {
+ if (!this._normalMsg()) {
break;
}
if (this._sock.rQlen === 0) {
@@ -720,7 +881,7 @@ export default class RFB extends EventTargetMixin {
}
break;
default:
- this._init_msg();
+ this._initMsg();
break;
}
}
@@ -729,13 +890,52 @@ export default class RFB extends EventTargetMixin {
this.sendKey(keysym, code, down);
}
- _handleMouseButton(x, y, down, bmask) {
- if (down) {
- this._mouse_buttonMask |= bmask;
- } else {
- this._mouse_buttonMask &= ~bmask;
+ _handleMouse(ev) {
+ /*
+ * We don't check connection status or viewOnly here as the
+ * mouse events might be used to control the viewport
+ */
+
+ if (ev.type === 'click') {
+ /*
+ * Note: This is only needed for the 'click' event as it fails
+ * to fire properly for the target element so we have
+ * to listen on the document element instead.
+ */
+ if (ev.target !== this._canvas) {
+ return;
+ }
}
+ // FIXME: if we're in view-only and not dragging,
+ // should we stop events?
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ if ((ev.type === 'click') || (ev.type === 'contextmenu')) {
+ return;
+ }
+
+ let pos = clientToElement(ev.clientX, ev.clientY,
+ this._canvas);
+
+ switch (ev.type) {
+ case 'mousedown':
+ setCapture(this._canvas);
+ this._handleMouseButton(pos.x, pos.y,
+ true, 1 << ev.button);
+ break;
+ case 'mouseup':
+ this._handleMouseButton(pos.x, pos.y,
+ false, 1 << ev.button);
+ break;
+ case 'mousemove':
+ this._handleMouseMove(pos.x, pos.y);
+ break;
+ }
+ }
+
+ _handleMouseButton(x, y, down, bmask) {
if (this.dragViewport) {
if (down && !this._viewportDragging) {
this._viewportDragging = true;
@@ -756,17 +956,24 @@ export default class RFB extends EventTargetMixin {
// 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);
+ this._sendMouse(x, y, bmask);
}
}
- if (this._viewOnly) { return; } // View only, skip mouse events
+ // Flush waiting move event first
+ if (this._mouseMoveTimer !== null) {
+ clearTimeout(this._mouseMoveTimer);
+ this._mouseMoveTimer = null;
+ this._sendMouse(x, y, this._mouseButtonMask);
+ }
+
+ if (down) {
+ this._mouseButtonMask |= bmask;
+ } else {
+ this._mouseButtonMask &= ~bmask;
+ }
- if (this._rfb_connection_state !== 'connected') { return; }
- RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask);
+ this._sendMouse(x, y, this._mouseButtonMask);
}
_handleMouseMove(x, y) {
@@ -786,66 +993,304 @@ export default class RFB extends EventTargetMixin {
return;
}
+ this._mousePos = { 'x': x, 'y': y };
+
+ // Limit many mouse move events to one every MOUSE_MOVE_DELAY ms
+ if (this._mouseMoveTimer == null) {
+
+ const timeSinceLastMove = Date.now() - this._mouseLastMoveTime;
+ if (timeSinceLastMove > MOUSE_MOVE_DELAY) {
+ this._sendMouse(x, y, this._mouseButtonMask);
+ this._mouseLastMoveTime = Date.now();
+ } else {
+ // Too soon since the latest move, wait the remaining time
+ this._mouseMoveTimer = setTimeout(() => {
+ this._handleDelayedMouseMove();
+ }, MOUSE_MOVE_DELAY - timeSinceLastMove);
+ }
+ }
+ }
+
+ _handleDelayedMouseMove() {
+ this._mouseMoveTimer = null;
+ this._sendMouse(this._mousePos.x, this._mousePos.y,
+ this._mouseButtonMask);
+ this._mouseLastMoveTime = Date.now();
+ }
+
+ _sendMouse(x, y, mask) {
+ if (this._rfbConnectionState !== 'connected') { return; }
if (this._viewOnly) { return; } // View only, skip mouse events
- if (this._rfb_connection_state !== 'connected') { return; }
- RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask);
+ RFB.messages.pointerEvent(this._sock, this._display.absX(x),
+ this._display.absY(y), mask);
+ }
+
+ _handleWheel(ev) {
+ if (this._rfbConnectionState !== 'connected') { return; }
+ if (this._viewOnly) { return; } // View only, skip mouse events
+
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ let pos = clientToElement(ev.clientX, ev.clientY,
+ this._canvas);
+
+ let dX = ev.deltaX;
+ let dY = ev.deltaY;
+
+ // Pixel units unless it's non-zero.
+ // Note that if deltamode is line or page won't matter since we aren't
+ // sending the mouse wheel delta to the server anyway.
+ // The difference between pixel and line can be important however since
+ // we have a threshold that can be smaller than the line height.
+ if (ev.deltaMode !== 0) {
+ dX *= WHEEL_LINE_HEIGHT;
+ dY *= WHEEL_LINE_HEIGHT;
+ }
+
+ // Mouse wheel events are sent in steps over VNC. This means that the VNC
+ // protocol can't handle a wheel event with specific distance or speed.
+ // Therefor, if we get a lot of small mouse wheel events we combine them.
+ this._accumulatedWheelDeltaX += dX;
+ this._accumulatedWheelDeltaY += dY;
+
+ // Generate a mouse wheel step event when the accumulated delta
+ // for one of the axes is large enough.
+ if (Math.abs(this._accumulatedWheelDeltaX) >= WHEEL_STEP) {
+ if (this._accumulatedWheelDeltaX < 0) {
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 5);
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 5);
+ } else if (this._accumulatedWheelDeltaX > 0) {
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 6);
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 6);
+ }
+
+ this._accumulatedWheelDeltaX = 0;
+ }
+ if (Math.abs(this._accumulatedWheelDeltaY) >= WHEEL_STEP) {
+ if (this._accumulatedWheelDeltaY < 0) {
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 3);
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 3);
+ } else if (this._accumulatedWheelDeltaY > 0) {
+ this._handleMouseButton(pos.x, pos.y, true, 1 << 4);
+ this._handleMouseButton(pos.x, pos.y, false, 1 << 4);
+ }
+
+ this._accumulatedWheelDeltaY = 0;
+ }
+ }
+
+ _fakeMouseMove(ev, elementX, elementY) {
+ this._handleMouseMove(elementX, elementY);
+ this._cursor.move(ev.detail.clientX, ev.detail.clientY);
+ }
+
+ _handleTapEvent(ev, bmask) {
+ let pos = clientToElement(ev.detail.clientX, ev.detail.clientY,
+ this._canvas);
+
+ // If the user quickly taps multiple times we assume they meant to
+ // hit the same spot, so slightly adjust coordinates
+
+ if ((this._gestureLastTapTime !== null) &&
+ ((Date.now() - this._gestureLastTapTime) < DOUBLE_TAP_TIMEOUT) &&
+ (this._gestureFirstDoubleTapEv.detail.type === ev.detail.type)) {
+ let dx = this._gestureFirstDoubleTapEv.detail.clientX - ev.detail.clientX;
+ let dy = this._gestureFirstDoubleTapEv.detail.clientY - ev.detail.clientY;
+ let distance = Math.hypot(dx, dy);
+
+ if (distance < DOUBLE_TAP_THRESHOLD) {
+ pos = clientToElement(this._gestureFirstDoubleTapEv.detail.clientX,
+ this._gestureFirstDoubleTapEv.detail.clientY,
+ this._canvas);
+ } else {
+ this._gestureFirstDoubleTapEv = ev;
+ }
+ } else {
+ this._gestureFirstDoubleTapEv = ev;
+ }
+ this._gestureLastTapTime = Date.now();
+
+ this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y);
+ this._handleMouseButton(pos.x, pos.y, true, bmask);
+ this._handleMouseButton(pos.x, pos.y, false, bmask);
+ }
+
+ _handleGesture(ev) {
+ let magnitude;
+
+ let pos = clientToElement(ev.detail.clientX, ev.detail.clientY,
+ this._canvas);
+ switch (ev.type) {
+ case 'gesturestart':
+ switch (ev.detail.type) {
+ case 'onetap':
+ this._handleTapEvent(ev, 0x1);
+ break;
+ case 'twotap':
+ this._handleTapEvent(ev, 0x4);
+ break;
+ case 'threetap':
+ this._handleTapEvent(ev, 0x2);
+ break;
+ case 'drag':
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ this._handleMouseButton(pos.x, pos.y, true, 0x1);
+ break;
+ case 'longpress':
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ this._handleMouseButton(pos.x, pos.y, true, 0x4);
+ break;
+
+ case 'twodrag':
+ this._gestureLastMagnitudeX = ev.detail.magnitudeX;
+ this._gestureLastMagnitudeY = ev.detail.magnitudeY;
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ break;
+ case 'pinch':
+ this._gestureLastMagnitudeX = Math.hypot(ev.detail.magnitudeX,
+ ev.detail.magnitudeY);
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ break;
+ }
+ break;
+
+ case 'gesturemove':
+ switch (ev.detail.type) {
+ case 'onetap':
+ case 'twotap':
+ case 'threetap':
+ break;
+ case 'drag':
+ case 'longpress':
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ break;
+ case 'twodrag':
+ // Always scroll in the same position.
+ // We don't know if the mouse was moved so we need to move it
+ // every update.
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) > GESTURE_SCRLSENS) {
+ this._handleMouseButton(pos.x, pos.y, true, 0x8);
+ this._handleMouseButton(pos.x, pos.y, false, 0x8);
+ this._gestureLastMagnitudeY += GESTURE_SCRLSENS;
+ }
+ while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) < -GESTURE_SCRLSENS) {
+ this._handleMouseButton(pos.x, pos.y, true, 0x10);
+ this._handleMouseButton(pos.x, pos.y, false, 0x10);
+ this._gestureLastMagnitudeY -= GESTURE_SCRLSENS;
+ }
+ while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) > GESTURE_SCRLSENS) {
+ this._handleMouseButton(pos.x, pos.y, true, 0x20);
+ this._handleMouseButton(pos.x, pos.y, false, 0x20);
+ this._gestureLastMagnitudeX += GESTURE_SCRLSENS;
+ }
+ while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) < -GESTURE_SCRLSENS) {
+ this._handleMouseButton(pos.x, pos.y, true, 0x40);
+ this._handleMouseButton(pos.x, pos.y, false, 0x40);
+ this._gestureLastMagnitudeX -= GESTURE_SCRLSENS;
+ }
+ break;
+ case 'pinch':
+ // Always scroll in the same position.
+ // We don't know if the mouse was moved so we need to move it
+ // every update.
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ magnitude = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY);
+ if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
+ this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true);
+ while ((magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) {
+ this._handleMouseButton(pos.x, pos.y, true, 0x8);
+ this._handleMouseButton(pos.x, pos.y, false, 0x8);
+ this._gestureLastMagnitudeX += GESTURE_ZOOMSENS;
+ }
+ while ((magnitude - this._gestureLastMagnitudeX) < -GESTURE_ZOOMSENS) {
+ this._handleMouseButton(pos.x, pos.y, true, 0x10);
+ this._handleMouseButton(pos.x, pos.y, false, 0x10);
+ this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS;
+ }
+ }
+ this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", false);
+ break;
+ }
+ break;
+
+ case 'gestureend':
+ switch (ev.detail.type) {
+ case 'onetap':
+ case 'twotap':
+ case 'threetap':
+ case 'pinch':
+ case 'twodrag':
+ break;
+ case 'drag':
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ this._handleMouseButton(pos.x, pos.y, false, 0x1);
+ break;
+ case 'longpress':
+ this._fakeMouseMove(ev, pos.x, pos.y);
+ this._handleMouseButton(pos.x, pos.y, false, 0x4);
+ break;
+ }
+ break;
+ }
}
// Message Handlers
- _negotiate_protocol_version() {
+ _negotiateProtocolVersion() {
if (this._sock.rQwait("version", 12)) {
return false;
}
const sversion = this._sock.rQshiftStr(12).substr(4, 7);
Log.Info("Server ProtocolVersion: " + sversion);
- let is_repeater = 0;
+ let isRepeater = 0;
switch (sversion) {
case "000.000": // UltraVNC repeater
- is_repeater = 1;
+ isRepeater = 1;
break;
case "003.003":
case "003.006": // UltraVNC
case "003.889": // Apple Remote Desktop
- this._rfb_version = 3.3;
+ this._rfbVersion = 3.3;
break;
case "003.007":
- this._rfb_version = 3.7;
+ this._rfbVersion = 3.7;
break;
case "003.008":
case "004.000": // Intel AMT KVM
case "004.001": // RealVNC 4.6
case "005.000": // RealVNC 5.3
- this._rfb_version = 3.8;
+ this._rfbVersion = 3.8;
break;
default:
return this._fail("Invalid server version " + sversion);
}
- if (is_repeater) {
+ if (isRepeater) {
let repeaterID = "ID:" + this._repeaterID;
while (repeaterID.length < 250) {
repeaterID += "\0";
}
- this._sock.send_string(repeaterID);
+ this._sock.sendString(repeaterID);
return true;
}
- if (this._rfb_version > this._rfb_max_version) {
- this._rfb_version = this._rfb_max_version;
+ if (this._rfbVersion > this._rfbMaxVersion) {
+ this._rfbVersion = this._rfbMaxVersion;
}
- const cversion = "00" + parseInt(this._rfb_version, 10) +
- ".00" + ((this._rfb_version * 10) % 10);
- this._sock.send_string("RFB " + cversion + "\n");
+ const cversion = "00" + parseInt(this._rfbVersion, 10) +
+ ".00" + ((this._rfbVersion * 10) % 10);
+ this._sock.sendString("RFB " + cversion + "\n");
Log.Debug('Sent ProtocolVersion: ' + cversion);
- this._rfb_init_state = 'Security';
+ this._rfbInitState = 'Security';
}
- _negotiate_security() {
+ _negotiateSecurity() {
// Polyfill since IE and PhantomJS doesn't have
// TypedArray.includes()
function includes(item, array) {
@@ -857,55 +1302,57 @@ export default class RFB extends EventTargetMixin {
return false;
}
- if (this._rfb_version >= 3.7) {
+ if (this._rfbVersion >= 3.7) {
// Server sends supported list, client decides
- const num_types = this._sock.rQshift8();
- if (this._sock.rQwait("security type", num_types, 1)) { return false; }
-
- if (num_types === 0) {
- this._rfb_init_state = "SecurityReason";
- this._security_context = "no security types";
- this._security_status = 1;
- return this._init_msg();
+ const numTypes = this._sock.rQshift8();
+ if (this._sock.rQwait("security type", numTypes, 1)) { return false; }
+
+ if (numTypes === 0) {
+ this._rfbInitState = "SecurityReason";
+ this._securityContext = "no security types";
+ this._securityStatus = 1;
+ return this._initMsg();
}
- const types = this._sock.rQshiftBytes(num_types);
+ const types = this._sock.rQshiftBytes(numTypes);
Log.Debug("Server security types: " + types);
// Look for each auth in preferred order
if (includes(1, types)) {
- this._rfb_auth_scheme = 1; // None
+ this._rfbAuthScheme = 1; // None
} else if (includes(22, types)) {
- this._rfb_auth_scheme = 22; // XVP
+ this._rfbAuthScheme = 22; // XVP
} else if (includes(16, types)) {
- this._rfb_auth_scheme = 16; // Tight
+ this._rfbAuthScheme = 16; // Tight
} else if (includes(2, types)) {
- this._rfb_auth_scheme = 2; // VNC Auth
+ this._rfbAuthScheme = 2; // VNC Auth
+ } else if (includes(19, types)) {
+ this._rfbAuthScheme = 19; // VeNCrypt Auth
} else {
return this._fail("Unsupported security types (types: " + types + ")");
}
- this._sock.send([this._rfb_auth_scheme]);
+ this._sock.send([this._rfbAuthScheme]);
} else {
// Server decides
if (this._sock.rQwait("security scheme", 4)) { return false; }
- this._rfb_auth_scheme = this._sock.rQshift32();
+ this._rfbAuthScheme = this._sock.rQshift32();
- if (this._rfb_auth_scheme == 0) {
- this._rfb_init_state = "SecurityReason";
- this._security_context = "authentication scheme";
- this._security_status = 1;
- return this._init_msg();
+ if (this._rfbAuthScheme == 0) {
+ this._rfbInitState = "SecurityReason";
+ this._securityContext = "authentication scheme";
+ this._securityStatus = 1;
+ return this._initMsg();
}
}
- this._rfb_init_state = 'Authentication';
- Log.Debug('Authenticating using scheme: ' + this._rfb_auth_scheme);
+ this._rfbInitState = 'Authentication';
+ Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme);
- return this._init_msg(); // jump to authentication
+ return this._initMsg(); // jump to authentication
}
- _handle_security_reason() {
+ _handleSecurityReason() {
if (this._sock.rQwait("reason length", 4)) {
return false;
}
@@ -920,46 +1367,134 @@ export default class RFB extends EventTargetMixin {
if (reason !== "") {
this.dispatchEvent(new CustomEvent(
"securityfailure",
- { detail: { status: this._security_status,
+ { detail: { status: this._securityStatus,
reason: reason } }));
return this._fail("Security negotiation failed on " +
- this._security_context +
+ this._securityContext +
" (reason: " + reason + ")");
} else {
this.dispatchEvent(new CustomEvent(
"securityfailure",
- { detail: { status: this._security_status } }));
+ { detail: { status: this._securityStatus } }));
return this._fail("Security negotiation failed on " +
- this._security_context);
+ this._securityContext);
}
}
// authentication
- _negotiate_xvp_auth() {
- if (!this._rfb_credentials.username ||
- !this._rfb_credentials.password ||
- !this._rfb_credentials.target) {
+ _negotiateXvpAuth() {
+ if (this._rfbCredentials.username === undefined ||
+ this._rfbCredentials.password === undefined ||
+ this._rfbCredentials.target === undefined) {
this.dispatchEvent(new CustomEvent(
"credentialsrequired",
{ detail: { types: ["username", "password", "target"] } }));
return false;
}
- const xvp_auth_str = String.fromCharCode(this._rfb_credentials.username.length) +
- String.fromCharCode(this._rfb_credentials.target.length) +
- this._rfb_credentials.username +
- this._rfb_credentials.target;
- this._sock.send_string(xvp_auth_str);
- this._rfb_auth_scheme = 2;
- return this._negotiate_authentication();
+ const xvpAuthStr = String.fromCharCode(this._rfbCredentials.username.length) +
+ String.fromCharCode(this._rfbCredentials.target.length) +
+ this._rfbCredentials.username +
+ this._rfbCredentials.target;
+ this._sock.sendString(xvpAuthStr);
+ this._rfbAuthScheme = 2;
+ return this._negotiateAuthentication();
}
- _negotiate_std_vnc_auth() {
+ // VeNCrypt authentication, currently only supports version 0.2 and only Plain subtype
+ _negotiateVeNCryptAuth() {
+
+ // waiting for VeNCrypt version
+ if (this._rfbVeNCryptState == 0) {
+ if (this._sock.rQwait("vencrypt version", 2)) { return false; }
+
+ const major = this._sock.rQshift8();
+ const minor = this._sock.rQshift8();
+
+ if (!(major == 0 && minor == 2)) {
+ return this._fail("Unsupported VeNCrypt version " + major + "." + minor);
+ }
+
+ this._sock.send([0, 2]);
+ this._rfbVeNCryptState = 1;
+ }
+
+ // waiting for ACK
+ if (this._rfbVeNCryptState == 1) {
+ if (this._sock.rQwait("vencrypt ack", 1)) { return false; }
+
+ const res = this._sock.rQshift8();
+
+ if (res != 0) {
+ return this._fail("VeNCrypt failure " + res);
+ }
+
+ this._rfbVeNCryptState = 2;
+ }
+ // must fall through here (i.e. no "else if"), beacause we may have already received
+ // the subtypes length and won't be called again
+
+ if (this._rfbVeNCryptState == 2) { // waiting for subtypes length
+ if (this._sock.rQwait("vencrypt subtypes length", 1)) { return false; }
+
+ const subtypesLength = this._sock.rQshift8();
+ if (subtypesLength < 1) {
+ return this._fail("VeNCrypt subtypes empty");
+ }
+
+ this._rfbVeNCryptSubtypesLength = subtypesLength;
+ this._rfbVeNCryptState = 3;
+ }
+
+ // waiting for subtypes list
+ if (this._rfbVeNCryptState == 3) {
+ if (this._sock.rQwait("vencrypt subtypes", 4 * this._rfbVeNCryptSubtypesLength)) { return false; }
+
+ const subtypes = [];
+ for (let i = 0; i < this._rfbVeNCryptSubtypesLength; i++) {
+ subtypes.push(this._sock.rQshift32());
+ }
+
+ // 256 = Plain subtype
+ if (subtypes.indexOf(256) != -1) {
+ // 0x100 = 256
+ this._sock.send([0, 0, 1, 0]);
+ this._rfbVeNCryptState = 4;
+ } else {
+ return this._fail("VeNCrypt Plain subtype not offered by server");
+ }
+ }
+
+ // negotiated Plain subtype, server waits for password
+ if (this._rfbVeNCryptState == 4) {
+ if (!this._rfbCredentials.username ||
+ !this._rfbCredentials.password) {
+ this.dispatchEvent(new CustomEvent(
+ "credentialsrequired",
+ { detail: { types: ["username", "password"] } }));
+ return false;
+ }
+
+ const user = encodeUTF8(this._rfbCredentials.username);
+ const pass = encodeUTF8(this._rfbCredentials.password);
+
+ // XXX we assume lengths are <= 255 (should not be an issue in the real world)
+ this._sock.send([0, 0, 0, user.length]);
+ this._sock.send([0, 0, 0, pass.length]);
+ this._sock.sendString(user);
+ this._sock.sendString(pass);
+
+ this._rfbInitState = "SecurityResult";
+ return true;
+ }
+ }
+
+ _negotiateStdVNCAuth() {
if (this._sock.rQwait("auth challenge", 16)) { return false; }
- if (!this._rfb_credentials.password) {
+ if (this._rfbCredentials.password === undefined) {
this.dispatchEvent(new CustomEvent(
"credentialsrequired",
{ detail: { types: ["password"] } }));
@@ -968,23 +1503,40 @@ export default class RFB extends EventTargetMixin {
// TODO(directxman12): make genDES not require an Array
const challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
- const response = RFB.genDES(this._rfb_credentials.password, challenge);
+ const response = RFB.genDES(this._rfbCredentials.password, challenge);
this._sock.send(response);
- this._rfb_init_state = "SecurityResult";
+ this._rfbInitState = "SecurityResult";
+ return true;
+ }
+
+ _negotiateTightUnixAuth() {
+ if (this._rfbCredentials.username === undefined ||
+ this._rfbCredentials.password === undefined) {
+ this.dispatchEvent(new CustomEvent(
+ "credentialsrequired",
+ { detail: { types: ["username", "password"] } }));
+ return false;
+ }
+
+ this._sock.send([0, 0, 0, this._rfbCredentials.username.length]);
+ this._sock.send([0, 0, 0, this._rfbCredentials.password.length]);
+ this._sock.sendString(this._rfbCredentials.username);
+ this._sock.sendString(this._rfbCredentials.password);
+ this._rfbInitState = "SecurityResult";
return true;
}
- _negotiate_tight_tunnels(numTunnels) {
+ _negotiateTightTunnels(numTunnels) {
const clientSupportedTunnelTypes = {
0: { vendor: 'TGHT', signature: 'NOTUNNEL' }
};
const serverSupportedTunnelTypes = {};
// receive tunnel capabilities
for (let i = 0; i < numTunnels; i++) {
- const cap_code = this._sock.rQshift32();
- const cap_vendor = this._sock.rQshiftStr(4);
- const cap_signature = this._sock.rQshiftStr(8);
- serverSupportedTunnelTypes[cap_code] = { vendor: cap_vendor, signature: cap_signature };
+ const capCode = this._sock.rQshift32();
+ const capVendor = this._sock.rQshiftStr(4);
+ const capSignature = this._sock.rQshiftStr(8);
+ serverSupportedTunnelTypes[capCode] = { vendor: capVendor, signature: capSignature };
}
Log.Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes);
@@ -1015,16 +1567,16 @@ export default class RFB extends EventTargetMixin {
}
}
- _negotiate_tight_auth() {
- if (!this._rfb_tightvnc) { // first pass, do the tunnel negotiation
+ _negotiateTightAuth() {
+ if (!this._rfbTightVNC) { // first pass, do the tunnel negotiation
if (this._sock.rQwait("num tunnels", 4)) { return false; }
const numTunnels = this._sock.rQshift32();
if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) { return false; }
- this._rfb_tightvnc = true;
+ this._rfbTightVNC = true;
if (numTunnels > 0) {
- this._negotiate_tight_tunnels(numTunnels);
+ this._negotiateTightTunnels(numTunnels);
return false; // wait until we receive the sub auth to continue
}
}
@@ -1033,7 +1585,7 @@ export default class RFB extends EventTargetMixin {
if (this._sock.rQwait("sub auth count", 4)) { return false; }
const subAuthCount = this._sock.rQshift32();
if (subAuthCount === 0) { // empty sub-auth list received means 'no auth' subtype selected
- this._rfb_init_state = 'SecurityResult';
+ this._rfbInitState = 'SecurityResult';
return true;
}
@@ -1041,7 +1593,8 @@ export default class RFB extends EventTargetMixin {
const clientSupportedTypes = {
'STDVNOAUTH__': 1,
- 'STDVVNCAUTH_': 2
+ 'STDVVNCAUTH_': 2,
+ 'TGHTULGNAUTH': 129
};
const serverSupportedTypes = [];
@@ -1061,11 +1614,14 @@ export default class RFB extends EventTargetMixin {
switch (authType) {
case 'STDVNOAUTH__': // no auth
- this._rfb_init_state = 'SecurityResult';
+ this._rfbInitState = 'SecurityResult';
return true;
case 'STDVVNCAUTH_': // VNC auth
- this._rfb_auth_scheme = 2;
- return this._init_msg();
+ this._rfbAuthScheme = 2;
+ return this._initMsg();
+ case 'TGHTULGNAUTH': // UNIX auth
+ this._rfbAuthScheme = 129;
+ return this._initMsg();
default:
return this._fail("Unsupported tiny auth scheme " +
"(scheme: " + authType + ")");
@@ -1076,46 +1632,52 @@ export default class RFB extends EventTargetMixin {
return this._fail("No supported sub-auth types!");
}
- _negotiate_authentication() {
- switch (this._rfb_auth_scheme) {
+ _negotiateAuthentication() {
+ switch (this._rfbAuthScheme) {
case 1: // no auth
- if (this._rfb_version >= 3.8) {
- this._rfb_init_state = 'SecurityResult';
+ if (this._rfbVersion >= 3.8) {
+ this._rfbInitState = 'SecurityResult';
return true;
}
- this._rfb_init_state = 'ClientInitialisation';
- return this._init_msg();
+ this._rfbInitState = 'ClientInitialisation';
+ return this._initMsg();
case 22: // XVP auth
- return this._negotiate_xvp_auth();
+ return this._negotiateXvpAuth();
case 2: // VNC authentication
- return this._negotiate_std_vnc_auth();
+ return this._negotiateStdVNCAuth();
case 16: // TightVNC Security Type
- return this._negotiate_tight_auth();
+ return this._negotiateTightAuth();
+
+ case 19: // VeNCrypt Security Type
+ return this._negotiateVeNCryptAuth();
+
+ case 129: // TightVNC UNIX Security Type
+ return this._negotiateTightUnixAuth();
default:
return this._fail("Unsupported auth scheme (scheme: " +
- this._rfb_auth_scheme + ")");
+ this._rfbAuthScheme + ")");
}
}
- _handle_security_result() {
+ _handleSecurityResult() {
if (this._sock.rQwait('VNC auth response ', 4)) { return false; }
const status = this._sock.rQshift32();
if (status === 0) { // OK
- this._rfb_init_state = 'ClientInitialisation';
+ this._rfbInitState = 'ClientInitialisation';
Log.Debug('Authentication OK');
- return this._init_msg();
+ return this._initMsg();
} else {
- if (this._rfb_version >= 3.8) {
- this._rfb_init_state = "SecurityReason";
- this._security_context = "security result";
- this._security_status = status;
- return this._init_msg();
+ if (this._rfbVersion >= 3.8) {
+ this._rfbInitState = "SecurityReason";
+ this._securityContext = "security result";
+ this._securityStatus = status;
+ return this._initMsg();
} else {
this.dispatchEvent(new CustomEvent(
"securityfailure",
@@ -1126,7 +1688,7 @@ export default class RFB extends EventTargetMixin {
}
}
- _negotiate_server_init() {
+ _negotiateServerInit() {
if (this._sock.rQwait("server initialization", 24)) { return false; }
/* Screen size */
@@ -1136,27 +1698,28 @@ export default class RFB extends EventTargetMixin {
/* PIXEL_FORMAT */
const bpp = this._sock.rQshift8();
const depth = this._sock.rQshift8();
- const big_endian = this._sock.rQshift8();
- const true_color = this._sock.rQshift8();
-
- const red_max = this._sock.rQshift16();
- const green_max = this._sock.rQshift16();
- const blue_max = this._sock.rQshift16();
- const red_shift = this._sock.rQshift8();
- const green_shift = this._sock.rQshift8();
- const blue_shift = this._sock.rQshift8();
+ const bigEndian = this._sock.rQshift8();
+ const trueColor = this._sock.rQshift8();
+
+ const redMax = this._sock.rQshift16();
+ const greenMax = this._sock.rQshift16();
+ const blueMax = this._sock.rQshift16();
+ const redShift = this._sock.rQshift8();
+ const greenShift = this._sock.rQshift8();
+ const blueShift = this._sock.rQshift8();
this._sock.rQskipBytes(3); // padding
// NB(directxman12): we don't want to call any callbacks or print messages until
// *after* we're past the point where we could backtrack
/* Connection name/title */
- const name_length = this._sock.rQshift32();
- if (this._sock.rQwait('server init name', name_length, 24)) { return false; }
- this._fb_name = decodeUTF8(this._sock.rQshiftStr(name_length));
+ const nameLength = this._sock.rQshift32();
+ if (this._sock.rQwait('server init name', nameLength, 24)) { return false; }
+ let name = this._sock.rQshiftStr(nameLength);
+ name = decodeUTF8(name, true);
- if (this._rfb_tightvnc) {
- if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + name_length)) { return false; }
+ if (this._rfbTightVNC) {
+ if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + nameLength)) { return false; }
// In TightVNC mode, ServerInit message is extended
const numServerMessages = this._sock.rQshift16();
const numClientMessages = this._sock.rQshift16();
@@ -1164,7 +1727,7 @@ export default class RFB extends EventTargetMixin {
this._sock.rQskipBytes(2); // padding
const totalMessagesLength = (numServerMessages + numClientMessages + numEncodings) * 16;
- if (this._sock.rQwait('TightVNC extended server init header', totalMessagesLength, 32 + name_length)) { return false; }
+ if (this._sock.rQwait('TightVNC extended server init header', totalMessagesLength, 32 + nameLength)) { return false; }
// we don't actually do anything with the capability information that TIGHT sends,
// so we just skip the all of this.
@@ -1183,42 +1746,31 @@ export default class RFB extends EventTargetMixin {
// if we backtrack
Log.Info("Screen: " + width + "x" + height +
", bpp: " + bpp + ", depth: " + depth +
- ", big_endian: " + big_endian +
- ", true_color: " + true_color +
- ", red_max: " + red_max +
- ", green_max: " + green_max +
- ", blue_max: " + blue_max +
- ", red_shift: " + red_shift +
- ", green_shift: " + green_shift +
- ", blue_shift: " + blue_shift);
-
- if (big_endian !== 0) {
- Log.Warn("Server native endian is not little endian");
- }
-
- if (red_shift !== 16) {
- Log.Warn("Server native red-shift is not 16");
- }
-
- if (blue_shift !== 0) {
- Log.Warn("Server native blue-shift is not 0");
- }
-
+ ", bigEndian: " + bigEndian +
+ ", trueColor: " + trueColor +
+ ", redMax: " + redMax +
+ ", greenMax: " + greenMax +
+ ", blueMax: " + blueMax +
+ ", redShift: " + redShift +
+ ", greenShift: " + greenShift +
+ ", blueShift: " + blueShift);
+
+ // we're past the point where we could backtrack, so it's safe to call this
+ this._setDesktopName(name);
this._resize(width, height);
if (!this._viewOnly) { this._keyboard.grab(); }
- if (!this._viewOnly) { this._mouse.grab(); }
- this._fb_depth = 24;
+ this._fbDepth = 24;
- if (this._fb_name === "Intel(r) AMT KVM") {
+ if (this._fbName === "Intel(r) AMT KVM") {
Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode.");
- this._fb_depth = 8;
+ this._fbDepth = 8;
}
- RFB.messages.pixelFormat(this._sock, this._fb_depth, true);
+ RFB.messages.pixelFormat(this._sock, this._fbDepth, true);
this._sendEncodings();
- RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fb_width, this._fb_height);
+ RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fbWidth, this._fbHeight);
this._updateConnectionState('connected');
return true;
@@ -1230,7 +1782,7 @@ export default class RFB extends EventTargetMixin {
// In preference order
encs.push(encodings.encodingCopyRect);
// Only supported with full depth support
- if (this._fb_depth == 24) {
+ if (this._fbDepth == 24) {
encs.push(encodings.encodingTight);
encs.push(encodings.encodingTightPNG);
encs.push(encodings.encodingHextile);
@@ -1239,8 +1791,8 @@ export default class RFB extends EventTargetMixin {
encs.push(encodings.encodingRaw);
// Psuedo-encoding settings
- encs.push(encodings.pseudoEncodingQualityLevel0 + 6);
- encs.push(encodings.pseudoEncodingCompressLevel0 + 2);
+ encs.push(encodings.pseudoEncodingQualityLevel0 + this._qualityLevel);
+ encs.push(encodings.pseudoEncodingCompressLevel0 + this._compressionLevel);
encs.push(encodings.pseudoEncodingDesktopSize);
encs.push(encodings.pseudoEncodingLastRect);
@@ -1249,8 +1801,11 @@ export default class RFB extends EventTargetMixin {
encs.push(encodings.pseudoEncodingXvp);
encs.push(encodings.pseudoEncodingFence);
encs.push(encodings.pseudoEncodingContinuousUpdates);
+ encs.push(encodings.pseudoEncodingDesktopName);
+ encs.push(encodings.pseudoEncodingExtendedClipboard);
- if (this._fb_depth == 24) {
+ if (this._fbDepth == 24) {
+ encs.push(encodings.pseudoEncodingVMwareCursor);
encs.push(encodings.pseudoEncodingCursor);
}
@@ -1265,63 +1820,212 @@ export default class RFB extends EventTargetMixin {
* ClientInitialization - not triggered by server message
* ServerInitialization
*/
- _init_msg() {
- switch (this._rfb_init_state) {
+ _initMsg() {
+ switch (this._rfbInitState) {
case 'ProtocolVersion':
- return this._negotiate_protocol_version();
+ return this._negotiateProtocolVersion();
case 'Security':
- return this._negotiate_security();
+ return this._negotiateSecurity();
case 'Authentication':
- return this._negotiate_authentication();
+ return this._negotiateAuthentication();
case 'SecurityResult':
- return this._handle_security_result();
+ return this._handleSecurityResult();
case 'SecurityReason':
- return this._handle_security_reason();
+ return this._handleSecurityReason();
case 'ClientInitialisation':
- this._sock.send([0]); // ClientInitialisation for exclusive access
- this._rfb_init_state = 'ServerInitialisation';
+ this._sock.send([this._shared ? 1 : 0]); // ClientInitialisation
+ this._rfbInitState = 'ServerInitialisation';
return true;
case 'ServerInitialisation':
- return this._negotiate_server_init();
+ return this._negotiateServerInit();
default:
return this._fail("Unknown init state (state: " +
- this._rfb_init_state + ")");
+ this._rfbInitState + ")");
}
}
- _handle_set_colour_map_msg() {
+ _handleSetColourMapMsg() {
Log.Debug("SetColorMapEntries");
return this._fail("Unexpected SetColorMapEntries message");
}
- _handle_server_cut_text() {
+ _handleServerCutText() {
Log.Debug("ServerCutText");
if (this._sock.rQwait("ServerCutText header", 7, 1)) { return false; }
+
this._sock.rQskipBytes(3); // Padding
- const length = this._sock.rQshift32();
- if (this._sock.rQwait("ServerCutText", length, 8)) { return false; }
- const text = this._sock.rQshiftStr(length);
+ let length = this._sock.rQshift32();
+ length = toSigned32bit(length);
- if (this._viewOnly) { return true; }
+ if (this._sock.rQwait("ServerCutText content", Math.abs(length), 8)) { return false; }
- this.dispatchEvent(new CustomEvent(
- "clipboard",
- { detail: { text: text } }));
+ if (length >= 0) {
+ //Standard msg
+ const text = this._sock.rQshiftStr(length);
+ if (this._viewOnly) {
+ return true;
+ }
+
+ this.dispatchEvent(new CustomEvent(
+ "clipboard",
+ { detail: { text: text } }));
+ } else {
+ //Extended msg.
+ length = Math.abs(length);
+ const flags = this._sock.rQshift32();
+ let formats = flags & 0x0000FFFF;
+ let actions = flags & 0xFF000000;
+
+ let isCaps = (!!(actions & extendedClipboardActionCaps));
+ if (isCaps) {
+ this._clipboardServerCapabilitiesFormats = {};
+ this._clipboardServerCapabilitiesActions = {};
+
+ // Update our server capabilities for Formats
+ for (let i = 0; i <= 15; i++) {
+ let index = 1 << i;
+
+ // Check if format flag is set.
+ if ((formats & index)) {
+ this._clipboardServerCapabilitiesFormats[index] = true;
+ // We don't send unsolicited clipboard, so we
+ // ignore the size
+ this._sock.rQshift32();
+ }
+ }
+
+ // Update our server capabilities for Actions
+ for (let i = 24; i <= 31; i++) {
+ let index = 1 << i;
+ this._clipboardServerCapabilitiesActions[index] = !!(actions & index);
+ }
+
+ /* Caps handling done, send caps with the clients
+ capabilities set as a response */
+ let clientActions = [
+ extendedClipboardActionCaps,
+ extendedClipboardActionRequest,
+ extendedClipboardActionPeek,
+ extendedClipboardActionNotify,
+ extendedClipboardActionProvide
+ ];
+ RFB.messages.extendedClipboardCaps(this._sock, clientActions, {extendedClipboardFormatText: 0});
+
+ } else if (actions === extendedClipboardActionRequest) {
+ if (this._viewOnly) {
+ return true;
+ }
+
+ // Check if server has told us it can handle Provide and there is clipboard data to send.
+ if (this._clipboardText != null &&
+ this._clipboardServerCapabilitiesActions[extendedClipboardActionProvide]) {
+
+ if (formats & extendedClipboardFormatText) {
+ RFB.messages.extendedClipboardProvide(this._sock, [extendedClipboardFormatText], [this._clipboardText]);
+ }
+ }
+
+ } else if (actions === extendedClipboardActionPeek) {
+ if (this._viewOnly) {
+ return true;
+ }
+
+ if (this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) {
+
+ if (this._clipboardText != null) {
+ RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]);
+ } else {
+ RFB.messages.extendedClipboardNotify(this._sock, []);
+ }
+ }
+
+ } else if (actions === extendedClipboardActionNotify) {
+ if (this._viewOnly) {
+ return true;
+ }
+
+ if (this._clipboardServerCapabilitiesActions[extendedClipboardActionRequest]) {
+
+ if (formats & extendedClipboardFormatText) {
+ RFB.messages.extendedClipboardRequest(this._sock, [extendedClipboardFormatText]);
+ }
+ }
+
+ } else if (actions === extendedClipboardActionProvide) {
+ if (this._viewOnly) {
+ return true;
+ }
+
+ if (!(formats & extendedClipboardFormatText)) {
+ return true;
+ }
+ // Ignore what we had in our clipboard client side.
+ this._clipboardText = null;
+
+ // FIXME: Should probably verify that this data was actually requested
+ let zlibStream = this._sock.rQshiftBytes(length - 4);
+ let streamInflator = new Inflator();
+ let textData = null;
+
+ streamInflator.setInput(zlibStream);
+ for (let i = 0; i <= 15; i++) {
+ let format = 1 << i;
+
+ if (formats & format) {
+
+ let size = 0x00;
+ let sizeArray = streamInflator.inflate(4);
+
+ size |= (sizeArray[0] << 24);
+ size |= (sizeArray[1] << 16);
+ size |= (sizeArray[2] << 8);
+ size |= (sizeArray[3]);
+ let chunk = streamInflator.inflate(size);
+
+ if (format === extendedClipboardFormatText) {
+ textData = chunk;
+ }
+ }
+ }
+ streamInflator.setInput(null);
+
+ if (textData !== null) {
+ let tmpText = "";
+ for (let i = 0; i < textData.length; i++) {
+ tmpText += String.fromCharCode(textData[i]);
+ }
+ textData = tmpText;
+
+ textData = decodeUTF8(textData);
+ if ((textData.length > 0) && "\0" === textData.charAt(textData.length - 1)) {
+ textData = textData.slice(0, -1);
+ }
+
+ textData = textData.replace("\r\n", "\n");
+
+ this.dispatchEvent(new CustomEvent(
+ "clipboard",
+ { detail: { text: textData } }));
+ }
+ } else {
+ return this._fail("Unexpected action in extended clipboard message: " + actions);
+ }
+ }
return true;
}
- _handle_server_fence_msg() {
+ _handleServerFenceMsg() {
if (this._sock.rQwait("ServerFence header", 8, 1)) { return false; }
this._sock.rQskipBytes(3); // Padding
let flags = this._sock.rQshift32();
@@ -1363,49 +2067,49 @@ export default class RFB extends EventTargetMixin {
return true;
}
- _handle_xvp_msg() {
+ _handleXvpMsg() {
if (this._sock.rQwait("XVP version and message", 3, 1)) { return false; }
this._sock.rQskipBytes(1); // Padding
- const xvp_ver = this._sock.rQshift8();
- const xvp_msg = this._sock.rQshift8();
+ const xvpVer = this._sock.rQshift8();
+ const xvpMsg = this._sock.rQshift8();
- switch (xvp_msg) {
+ switch (xvpMsg) {
case 0: // XVP_FAIL
Log.Error("XVP Operation Failed");
break;
case 1: // XVP_INIT
- this._rfb_xvp_ver = xvp_ver;
- Log.Info("XVP extensions enabled (version " + this._rfb_xvp_ver + ")");
+ this._rfbXvpVer = xvpVer;
+ Log.Info("XVP extensions enabled (version " + this._rfbXvpVer + ")");
this._setCapability("power", true);
break;
default:
- this._fail("Illegal server XVP message (msg: " + xvp_msg + ")");
+ this._fail("Illegal server XVP message (msg: " + xvpMsg + ")");
break;
}
return true;
}
- _normal_msg() {
- let msg_type;
+ _normalMsg() {
+ let msgType;
if (this._FBU.rects > 0) {
- msg_type = 0;
+ msgType = 0;
} else {
- msg_type = this._sock.rQshift8();
+ msgType = this._sock.rQshift8();
}
let first, ret;
- switch (msg_type) {
+ switch (msgType) {
case 0: // FramebufferUpdate
ret = this._framebufferUpdate();
if (ret && !this._enabledContinuousUpdates) {
RFB.messages.fbUpdateRequest(this._sock, true, 0, 0,
- this._fb_width, this._fb_height);
+ this._fbWidth, this._fbHeight);
}
return ret;
case 1: // SetColorMapEntries
- return this._handle_set_colour_map_msg();
+ return this._handleSetColourMapMsg();
case 2: // Bell
Log.Debug("Bell");
@@ -1415,7 +2119,7 @@ export default class RFB extends EventTargetMixin {
return true;
case 3: // ServerCutText
- return this._handle_server_cut_text();
+ return this._handleServerCutText();
case 150: // EndOfContinuousUpdates
first = !this._supportsContinuousUpdates;
@@ -1432,13 +2136,13 @@ export default class RFB extends EventTargetMixin {
return true;
case 248: // ServerFence
- return this._handle_server_fence_msg();
+ return this._handleServerFenceMsg();
case 250: // XVP
- return this._handle_xvp_msg();
+ return this._handleXvpMsg();
default:
- this._fail("Unexpected server message (type " + msg_type + ")");
+ this._fail("Unexpected server message (type " + msgType + ")");
Log.Debug("sock.rQslice(0, 30): " + this._sock.rQslice(0, 30));
return true;
}
@@ -1448,7 +2152,7 @@ export default class RFB extends EventTargetMixin {
this._flushing = false;
// Resume processing
if (this._sock.rQlen > 0) {
- this._handle_message();
+ this._handleMessage();
}
}
@@ -1500,6 +2204,9 @@ export default class RFB extends EventTargetMixin {
this._FBU.rects = 1; // Will be decreased when we return
return true;
+ case encodings.pseudoEncodingVMwareCursor:
+ return this._handleVMwareCursor();
+
case encodings.pseudoEncodingCursor:
return this._handleCursor();
@@ -1515,6 +2222,9 @@ export default class RFB extends EventTargetMixin {
}
return true;
+ case encodings.pseudoEncodingDesktopName:
+ return this._handleDesktopName();
+
case encodings.pseudoEncodingDesktopSize:
this._resize(this._FBU.width, this._FBU.height);
return true;
@@ -1527,6 +2237,122 @@ export default class RFB extends EventTargetMixin {
}
}
+ _handleVMwareCursor() {
+ const hotx = this._FBU.x; // hotspot-x
+ const hoty = this._FBU.y; // hotspot-y
+ const w = this._FBU.width;
+ const h = this._FBU.height;
+ if (this._sock.rQwait("VMware cursor encoding", 1)) {
+ return false;
+ }
+
+ const cursorType = this._sock.rQshift8();
+
+ this._sock.rQshift8(); //Padding
+
+ let rgba;
+ const bytesPerPixel = 4;
+
+ //Classic cursor
+ if (cursorType == 0) {
+ //Used to filter away unimportant bits.
+ //OR is used for correct conversion in js.
+ const PIXEL_MASK = 0xffffff00 | 0;
+ rgba = new Array(w * h * bytesPerPixel);
+
+ if (this._sock.rQwait("VMware cursor classic encoding",
+ (w * h * bytesPerPixel) * 2, 2)) {
+ return false;
+ }
+
+ let andMask = new Array(w * h);
+ for (let pixel = 0; pixel < (w * h); pixel++) {
+ andMask[pixel] = this._sock.rQshift32();
+ }
+
+ let xorMask = new Array(w * h);
+ for (let pixel = 0; pixel < (w * h); pixel++) {
+ xorMask[pixel] = this._sock.rQshift32();
+ }
+
+ for (let pixel = 0; pixel < (w * h); pixel++) {
+ if (andMask[pixel] == 0) {
+ //Fully opaque pixel
+ let bgr = xorMask[pixel];
+ let r = bgr >> 8 & 0xff;
+ let g = bgr >> 16 & 0xff;
+ let b = bgr >> 24 & 0xff;
+
+ rgba[(pixel * bytesPerPixel) ] = r; //r
+ rgba[(pixel * bytesPerPixel) + 1 ] = g; //g
+ rgba[(pixel * bytesPerPixel) + 2 ] = b; //b
+ rgba[(pixel * bytesPerPixel) + 3 ] = 0xff; //a
+
+ } else if ((andMask[pixel] & PIXEL_MASK) ==
+ PIXEL_MASK) {
+ //Only screen value matters, no mouse colouring
+ if (xorMask[pixel] == 0) {
+ //Transparent pixel
+ rgba[(pixel * bytesPerPixel) ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 1 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 2 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 3 ] = 0x00;
+
+ } else if ((xorMask[pixel] & PIXEL_MASK) ==
+ PIXEL_MASK) {
+ //Inverted pixel, not supported in browsers.
+ //Fully opaque instead.
+ rgba[(pixel * bytesPerPixel) ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 1 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 2 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 3 ] = 0xff;
+
+ } else {
+ //Unhandled xorMask
+ rgba[(pixel * bytesPerPixel) ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 1 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 2 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 3 ] = 0xff;
+ }
+
+ } else {
+ //Unhandled andMask
+ rgba[(pixel * bytesPerPixel) ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 1 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 2 ] = 0x00;
+ rgba[(pixel * bytesPerPixel) + 3 ] = 0xff;
+ }
+ }
+
+ //Alpha cursor.
+ } else if (cursorType == 1) {
+ if (this._sock.rQwait("VMware cursor alpha encoding",
+ (w * h * 4), 2)) {
+ return false;
+ }
+
+ rgba = new Array(w * h * bytesPerPixel);
+
+ for (let pixel = 0; pixel < (w * h); pixel++) {
+ let data = this._sock.rQshift32();
+
+ rgba[(pixel * 4) ] = data >> 24 & 0xff; //r
+ rgba[(pixel * 4) + 1 ] = data >> 16 & 0xff; //g
+ rgba[(pixel * 4) + 2 ] = data >> 8 & 0xff; //b
+ rgba[(pixel * 4) + 3 ] = data & 0xff; //a
+ }
+
+ } else {
+ Log.Warn("The given cursor type is not supported: "
+ + cursorType + " given.");
+ return false;
+ }
+
+ this._updateCursor(rgba, hotx, hoty, w, h);
+
+ return true;
+ }
+
_handleCursor() {
const hotx = this._FBU.x; // hotspot-x
const hoty = this._FBU.y; // hotspot-y
@@ -1546,16 +2372,16 @@ export default class RFB extends EventTargetMixin {
const mask = this._sock.rQshiftBytes(masklength);
let rgba = new Uint8Array(w * h * 4);
- let pix_idx = 0;
+ let pixIdx = 0;
for (let y = 0; y < h; y++) {
for (let x = 0; x < w; x++) {
- let mask_idx = y * Math.ceil(w / 8) + Math.floor(x / 8);
- let alpha = (mask[mask_idx] << (x % 8)) & 0x80 ? 255 : 0;
- rgba[pix_idx ] = pixels[pix_idx + 2];
- rgba[pix_idx + 1] = pixels[pix_idx + 1];
- rgba[pix_idx + 2] = pixels[pix_idx];
- rgba[pix_idx + 3] = alpha;
- pix_idx += 4;
+ let maskIdx = y * Math.ceil(w / 8) + Math.floor(x / 8);
+ let alpha = (mask[maskIdx] << (x % 8)) & 0x80 ? 255 : 0;
+ rgba[pixIdx ] = pixels[pixIdx + 2];
+ rgba[pixIdx + 1] = pixels[pixIdx + 1];
+ rgba[pixIdx + 2] = pixels[pixIdx];
+ rgba[pixIdx + 3] = alpha;
+ pixIdx += 4;
}
}
@@ -1564,14 +2390,33 @@ export default class RFB extends EventTargetMixin {
return true;
}
+ _handleDesktopName() {
+ if (this._sock.rQwait("DesktopName", 4)) {
+ return false;
+ }
+
+ let length = this._sock.rQshift32();
+
+ if (this._sock.rQwait("DesktopName", length, 4)) {
+ return false;
+ }
+
+ let name = this._sock.rQshiftStr(length);
+ name = decodeUTF8(name, true);
+
+ this._setDesktopName(name);
+
+ return true;
+ }
+
_handleExtendedDesktopSize() {
if (this._sock.rQwait("ExtendedDesktopSize", 4)) {
return false;
}
- const number_of_screens = this._sock.rQpeek8();
+ const numberOfScreens = this._sock.rQpeek8();
- let bytes = 4 + (number_of_screens * 16);
+ let bytes = 4 + (numberOfScreens * 16);
if (this._sock.rQwait("ExtendedDesktopSize", bytes)) {
return false;
}
@@ -1590,15 +2435,15 @@ export default class RFB extends EventTargetMixin {
this._sock.rQskipBytes(1); // number-of-screens
this._sock.rQskipBytes(3); // padding
- for (let i = 0; i < number_of_screens; i += 1) {
+ for (let i = 0; i < numberOfScreens; i += 1) {
// Save the id and flags of the first screen
if (i === 0) {
- this._screen_id = this._sock.rQshiftBytes(4); // id
+ this._screenID = this._sock.rQshiftBytes(4); // id
this._sock.rQskipBytes(2); // x-position
this._sock.rQskipBytes(2); // y-position
this._sock.rQskipBytes(2); // width
this._sock.rQskipBytes(2); // height
- this._screen_flags = this._sock.rQshiftBytes(4); // flags
+ this._screenFlags = this._sock.rQshiftBytes(4); // flags
} else {
this._sock.rQskipBytes(16);
}
@@ -1651,7 +2496,7 @@ export default class RFB extends EventTargetMixin {
return decoder.decodeRect(this._FBU.x, this._FBU.y,
this._FBU.width, this._FBU.height,
this._sock, this._display,
- this._fb_depth);
+ this._fbDepth);
} catch (err) {
this._fail("Error decoding rect: " + err);
return false;
@@ -1662,14 +2507,14 @@ export default class RFB extends EventTargetMixin {
if (!this._enabledContinuousUpdates) { return; }
RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0,
- this._fb_width, this._fb_height);
+ this._fbWidth, this._fbHeight);
}
_resize(width, height) {
- this._fb_width = width;
- this._fb_height = height;
+ this._fbWidth = width;
+ this._fbHeight = height;
- this._display.resize(this._fb_width, this._fb_height);
+ this._display.resize(this._fbWidth, this._fbHeight);
// Adjust the visible viewport based on the new dimensions
this._updateClip();
@@ -1679,7 +2524,7 @@ export default class RFB extends EventTargetMixin {
}
_xvpOp(ver, op) {
- if (this._rfb_xvp_ver < ver) { return; }
+ if (this._rfbXvpVer < ver) { return; }
Log.Info("Sending XVP operation " + op + " (version " + ver + ")");
RFB.messages.xvpOp(this._sock, ver, op);
}
@@ -1715,6 +2560,10 @@ export default class RFB extends EventTargetMixin {
}
_refreshCursor() {
+ if (this._rfbConnectionState !== "connecting" &&
+ this._rfbConnectionState !== "connected") {
+ return;
+ }
const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage;
this._cursor.change(image.rgbaPixels,
image.hotx, image.hoty,
@@ -1750,13 +2599,13 @@ RFB.messages = {
},
QEMUExtendedKeyEvent(sock, keysym, down, keycode) {
- function getRFBkeycode(xt_scancode) {
+ function getRFBkeycode(xtScanCode) {
const upperByte = (keycode >> 8);
const lowerByte = (keycode & 0x00ff);
if (upperByte === 0xe0 && lowerByte < 0x7f) {
return lowerByte | 0x80;
}
- return xt_scancode;
+ return xtScanCode;
}
const buff = sock._sQ;
@@ -1802,8 +2651,102 @@ RFB.messages = {
sock.flush();
},
- // TODO(directxman12): make this unicode compatible?
- clientCutText(sock, text) {
+ // Used to build Notify and Request data.
+ _buildExtendedClipboardFlags(actions, formats) {
+ let data = new Uint8Array(4);
+ let formatFlag = 0x00000000;
+ let actionFlag = 0x00000000;
+
+ for (let i = 0; i < actions.length; i++) {
+ actionFlag |= actions[i];
+ }
+
+ for (let i = 0; i < formats.length; i++) {
+ formatFlag |= formats[i];
+ }
+
+ data[0] = actionFlag >> 24; // Actions
+ data[1] = 0x00; // Reserved
+ data[2] = 0x00; // Reserved
+ data[3] = formatFlag; // Formats
+
+ return data;
+ },
+
+ extendedClipboardProvide(sock, formats, inData) {
+ // Deflate incomming data and their sizes
+ let deflator = new Deflator();
+ let dataToDeflate = [];
+
+ for (let i = 0; i < formats.length; i++) {
+ // We only support the format Text at this time
+ if (formats[i] != extendedClipboardFormatText) {
+ throw new Error("Unsupported extended clipboard format for Provide message.");
+ }
+
+ // Change lone \r or \n into \r\n as defined in rfbproto
+ inData[i] = inData[i].replace(/\r\n|\r|\n/gm, "\r\n");
+
+ // Check if it already has \0
+ let text = encodeUTF8(inData[i] + "\0");
+
+ dataToDeflate.push( (text.length >> 24) & 0xFF,
+ (text.length >> 16) & 0xFF,
+ (text.length >> 8) & 0xFF,
+ (text.length & 0xFF));
+
+ for (let j = 0; j < text.length; j++) {
+ dataToDeflate.push(text.charCodeAt(j));
+ }
+ }
+
+ let deflatedData = deflator.deflate(new Uint8Array(dataToDeflate));
+
+ // Build data to send
+ let data = new Uint8Array(4 + deflatedData.length);
+ data.set(RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionProvide],
+ formats));
+ data.set(deflatedData, 4);
+
+ RFB.messages.clientCutText(sock, data, true);
+ },
+
+ extendedClipboardNotify(sock, formats) {
+ let flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionNotify],
+ formats);
+ RFB.messages.clientCutText(sock, flags, true);
+ },
+
+ extendedClipboardRequest(sock, formats) {
+ let flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionRequest],
+ formats);
+ RFB.messages.clientCutText(sock, flags, true);
+ },
+
+ extendedClipboardCaps(sock, actions, formats) {
+ let formatKeys = Object.keys(formats);
+ let data = new Uint8Array(4 + (4 * formatKeys.length));
+
+ formatKeys.map(x => parseInt(x));
+ formatKeys.sort((a, b) => a - b);
+
+ data.set(RFB.messages._buildExtendedClipboardFlags(actions, []));
+
+ let loopOffset = 4;
+ for (let i = 0; i < formatKeys.length; i++) {
+ data[loopOffset] = formats[formatKeys[i]] >> 24;
+ data[loopOffset + 1] = formats[formatKeys[i]] >> 16;
+ data[loopOffset + 2] = formats[formatKeys[i]] >> 8;
+ data[loopOffset + 3] = formats[formatKeys[i]] >> 0;
+
+ loopOffset += 4;
+ data[3] |= (1 << formatKeys[i]); // Update our format flags
+ }
+
+ RFB.messages.clientCutText(sock, data, true);
+ },
+
+ clientCutText(sock, data, extended = false) {
const buff = sock._sQ;
const offset = sock._sQlen;
@@ -1813,7 +2756,12 @@ RFB.messages = {
buff[offset + 2] = 0; // padding
buff[offset + 3] = 0; // padding
- let length = text.length;
+ let length;
+ if (extended) {
+ length = toUnsigned32bit(-data.length);
+ } else {
+ length = data.length;
+ }
buff[offset + 4] = length >> 24;
buff[offset + 5] = length >> 16;
@@ -1822,24 +2770,25 @@ RFB.messages = {
sock._sQlen += 8;
- // We have to keep track of from where in the text we begin creating the
+ // We have to keep track of from where in the data we begin creating the
// buffer for the flush in the next iteration.
- let textOffset = 0;
+ let dataOffset = 0;
- let remaining = length;
+ let remaining = data.length;
while (remaining > 0) {
let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen));
for (let i = 0; i < flushSize; i++) {
- buff[sock._sQlen + i] = text.charCodeAt(textOffset + i);
+ buff[sock._sQlen + i] = data[dataOffset + i];
}
sock._sQlen += flushSize;
sock.flush();
remaining -= flushSize;
- textOffset += flushSize;
+ dataOffset += flushSize;
}
+
},
setDesktopSize(sock, width, height, id, flags) {
@@ -1925,7 +2874,7 @@ RFB.messages = {
sock.flush();
},
- pixelFormat(sock, depth, true_color) {
+ pixelFormat(sock, depth, trueColor) {
const buff = sock._sQ;
const offset = sock._sQlen;
@@ -1950,7 +2899,7 @@ RFB.messages = {
buff[offset + 4] = bpp; // bits-per-pixel
buff[offset + 5] = depth; // depth
buff[offset + 6] = 0; // little-endian
- buff[offset + 7] = true_color ? 1 : 0; // true-color
+ buff[offset + 7] = trueColor ? 1 : 0; // true-color
buff[offset + 8] = 0; // red-max
buff[offset + 9] = (1 << bits) - 1; // red-max
@@ -1961,9 +2910,9 @@ RFB.messages = {
buff[offset + 12] = 0; // blue-max
buff[offset + 13] = (1 << bits) - 1; // blue-max
- buff[offset + 14] = bits * 2; // red-shift
+ buff[offset + 14] = bits * 0; // red-shift
buff[offset + 15] = bits * 1; // green-shift
- buff[offset + 16] = bits * 0; // blue-shift
+ buff[offset + 16] = bits * 2; // blue-shift
buff[offset + 17] = 0; // padding
buff[offset + 18] = 0; // padding
diff --git a/systemvm/agent/noVNC/core/util/browser.js b/systemvm/agent/noVNC/core/util/browser.js
index 8996cfe..1554801 100644
--- a/systemvm/agent/noVNC/core/util/browser.js
+++ b/systemvm/agent/noVNC/core/util/browser.js
@@ -1,9 +1,11 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
+ *
+ * Browser feature support detection
*/
import * as Log from './logging.js';
@@ -31,7 +33,7 @@ try {
const target = document.createElement('canvas');
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAA [...]
- if (target.style.cursor) {
+ if (target.style.cursor.indexOf("url") === 0) {
Log.Info("Data URI scheme cursor supported");
_supportsCursorURIs = true;
} else {
@@ -52,6 +54,38 @@ try {
}
export const supportsImageMetadata = _supportsImageMetadata;
+let _hasScrollbarGutter = true;
+try {
+ // Create invisible container
+ const container = document.createElement('div');
+ container.style.visibility = 'hidden';
+ container.style.overflow = 'scroll'; // forcing scrollbars
+ document.body.appendChild(container);
+
+ // Create a div and place it in the container
+ const child = document.createElement('div');
+ container.appendChild(child);
+
+ // Calculate the difference between the container's full width
+ // and the child's width - the difference is the scrollbars
+ const scrollbarWidth = (container.offsetWidth - child.offsetWidth);
+
+ // Clean up
+ container.parentNode.removeChild(container);
+
+ _hasScrollbarGutter = scrollbarWidth != 0;
+} catch (exc) {
+ Log.Error("Scrollbar test exception: " + exc);
+}
+export const hasScrollbarGutter = _hasScrollbarGutter;
+
+/*
+ * The functions for detection of platforms and browsers below are exported
+ * but the use of these should be minimized as much as possible.
+ *
+ * It's better to use feature detection than platform detection.
+ */
+
export function isMac() {
return navigator && !!(/mac/i).exec(navigator.platform);
}
@@ -67,10 +101,6 @@ export function isIOS() {
!!(/ipod/i).exec(navigator.platform));
}
-export function isAndroid() {
- return navigator && !!(/android/i).exec(navigator.userAgent);
-}
-
export function isSafari() {
return navigator && (navigator.userAgent.indexOf('Safari') !== -1 &&
navigator.userAgent.indexOf('Chrome') === -1);
diff --git a/systemvm/agent/noVNC/core/util/cursor.js b/systemvm/agent/noVNC/core/util/cursor.js
index 0d0b754..4db1dab 100644
--- a/systemvm/agent/noVNC/core/util/cursor.js
+++ b/systemvm/agent/noVNC/core/util/cursor.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
*/
@@ -20,7 +20,6 @@ export default class Cursor {
this._canvas.style.pointerEvents = 'none';
// Can't use "display" because of Firefox bug #1445997
this._canvas.style.visibility = 'hidden';
- document.body.appendChild(this._canvas);
}
this._position = { x: 0, y: 0 };
@@ -31,9 +30,6 @@ export default class Cursor {
'mouseleave': this._handleMouseLeave.bind(this),
'mousemove': this._handleMouseMove.bind(this),
'mouseup': this._handleMouseUp.bind(this),
- 'touchstart': this._handleTouchStart.bind(this),
- 'touchmove': this._handleTouchMove.bind(this),
- 'touchend': this._handleTouchEnd.bind(this),
};
}
@@ -45,6 +41,8 @@ export default class Cursor {
this._target = target;
if (useFallback) {
+ document.body.appendChild(this._canvas);
+
// FIXME: These don't fire properly except for mouse
/// movement in IE. We want to also capture element
// movement, size changes, visibility, etc.
@@ -53,17 +51,16 @@ export default class Cursor {
this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options);
this._target.addEventListener('mousemove', this._eventHandlers.mousemove, options);
this._target.addEventListener('mouseup', this._eventHandlers.mouseup, options);
-
- // There is no "touchleave" so we monitor touchstart globally
- window.addEventListener('touchstart', this._eventHandlers.touchstart, options);
- this._target.addEventListener('touchmove', this._eventHandlers.touchmove, options);
- this._target.addEventListener('touchend', this._eventHandlers.touchend, options);
}
this.clear();
}
detach() {
+ if (!this._target) {
+ return;
+ }
+
if (useFallback) {
const options = { capture: true, passive: true };
this._target.removeEventListener('mouseover', this._eventHandlers.mouseover, options);
@@ -71,9 +68,7 @@ export default class Cursor {
this._target.removeEventListener('mousemove', this._eventHandlers.mousemove, options);
this._target.removeEventListener('mouseup', this._eventHandlers.mouseup, options);
- window.removeEventListener('touchstart', this._eventHandlers.touchstart, options);
- this._target.removeEventListener('touchmove', this._eventHandlers.touchmove, options);
- this._target.removeEventListener('touchend', this._eventHandlers.touchend, options);
+ document.body.removeChild(this._canvas);
}
this._target = null;
@@ -124,6 +119,27 @@ export default class Cursor {
this._hotSpot.y = 0;
}
+ // Mouse events might be emulated, this allows
+ // moving the cursor in such cases
+ move(clientX, clientY) {
+ if (!useFallback) {
+ return;
+ }
+ // clientX/clientY are relative the _visual viewport_,
+ // but our position is relative the _layout viewport_,
+ // so try to compensate when we can
+ if (window.visualViewport) {
+ this._position.x = clientX + window.visualViewport.offsetLeft;
+ this._position.y = clientY + window.visualViewport.offsetTop;
+ } else {
+ this._position.x = clientX;
+ this._position.y = clientY;
+ }
+ this._updatePosition();
+ let target = document.elementFromPoint(clientX, clientY);
+ this._updateVisibility(target);
+ }
+
_handleMouseOver(event) {
// This event could be because we're entering the target, or
// moving around amongst its sub elements. Let the move handler
@@ -132,7 +148,8 @@ export default class Cursor {
}
_handleMouseLeave(event) {
- this._hideCursor();
+ // Check if we should show the cursor on the element we are leaving to
+ this._updateVisibility(event.relatedTarget);
}
_handleMouseMove(event) {
@@ -150,27 +167,29 @@ export default class Cursor {
// now and adjust visibility based on that.
let target = document.elementFromPoint(event.clientX, event.clientY);
this._updateVisibility(target);
- }
- _handleTouchStart(event) {
- // Just as for mouseover, we let the move handler deal with it
- this._handleTouchMove(event);
- }
-
- _handleTouchMove(event) {
- this._updateVisibility(event.target);
-
- this._position.x = event.changedTouches[0].clientX - this._hotSpot.x;
- this._position.y = event.changedTouches[0].clientY - this._hotSpot.y;
-
- this._updatePosition();
- }
-
- _handleTouchEnd(event) {
- // Same principle as for mouseup
- let target = document.elementFromPoint(event.changedTouches[0].clientX,
- event.changedTouches[0].clientY);
- this._updateVisibility(target);
+ // Captures end with a mouseup but we can't know the event order of
+ // mouseup vs releaseCapture.
+ //
+ // In the cases when releaseCapture comes first, the code above is
+ // enough.
+ //
+ // In the cases when the mouseup comes first, we need wait for the
+ // browser to flush all events and then check again if the cursor
+ // should be visible.
+ if (this._captureIsActive()) {
+ window.setTimeout(() => {
+ // We might have detached at this point
+ if (!this._target) {
+ return;
+ }
+ // Refresh the target from elementFromPoint since queued events
+ // might have altered the DOM
+ target = document.elementFromPoint(event.clientX,
+ event.clientY);
+ this._updateVisibility(target);
+ }, 0);
+ }
}
_showCursor() {
@@ -189,6 +208,9 @@ export default class Cursor {
// (i.e. are we over the target, or a child of the target without a
// different cursor set)
_shouldShowCursor(target) {
+ if (!target) {
+ return false;
+ }
// Easy case
if (target === this._target) {
return true;
@@ -207,6 +229,11 @@ export default class Cursor {
}
_updateVisibility(target) {
+ // When the cursor target has capture we want to show the cursor.
+ // So, if a capture is active - look at the captured element instead.
+ if (this._captureIsActive()) {
+ target = document.captureElement;
+ }
if (this._shouldShowCursor(target)) {
this._showCursor();
} else {
@@ -218,4 +245,9 @@ export default class Cursor {
this._canvas.style.left = this._position.x + "px";
this._canvas.style.top = this._position.y + "px";
}
+
+ _captureIsActive() {
+ return document.captureElement &&
+ document.documentElement.contains(document.captureElement);
+ }
}
diff --git a/systemvm/agent/noVNC/core/util/element.js b/systemvm/agent/noVNC/core/util/element.js
new file mode 100644
index 0000000..466a745
--- /dev/null
+++ b/systemvm/agent/noVNC/core/util/element.js
@@ -0,0 +1,32 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2020 The noVNC Authors
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
+/*
+ * HTML element utility functions
+ */
+
+export function clientToElement(x, y, elem) {
+ const bounds = elem.getBoundingClientRect();
+ let pos = { x: 0, y: 0 };
+ // Clip to target bounds
+ if (x < bounds.left) {
+ pos.x = 0;
+ } else if (x >= bounds.right) {
+ pos.x = bounds.width - 1;
+ } else {
+ pos.x = x - bounds.left;
+ }
+ if (y < bounds.top) {
+ pos.y = 0;
+ } else if (y >= bounds.bottom) {
+ pos.y = bounds.height - 1;
+ } else {
+ pos.y = y - bounds.top;
+ }
+ return pos;
+}
diff --git a/systemvm/agent/noVNC/core/util/events.js b/systemvm/agent/noVNC/core/util/events.js
index f122279..39eefd4 100644
--- a/systemvm/agent/noVNC/core/util/events.js
+++ b/systemvm/agent/noVNC/core/util/events.js
@@ -21,7 +21,8 @@ export function stopEvent(e) {
// Emulate Element.setCapture() when not supported
let _captureRecursion = false;
-let _captureElem = null;
+let _elementForUnflushedEvents = null;
+document.captureElement = null;
function _captureProxy(e) {
// Recursion protection as we'll see our own event
if (_captureRecursion) return;
@@ -30,7 +31,11 @@ function _captureProxy(e) {
const newEv = new e.constructor(e.type, e);
_captureRecursion = true;
- _captureElem.dispatchEvent(newEv);
+ if (document.captureElement) {
+ document.captureElement.dispatchEvent(newEv);
+ } else {
+ _elementForUnflushedEvents.dispatchEvent(newEv);
+ }
_captureRecursion = false;
// Avoid double events
@@ -48,58 +53,56 @@ function _captureProxy(e) {
}
// Follow cursor style of target element
-function _captureElemChanged() {
- const captureElem = document.getElementById("noVNC_mouse_capture_elem");
- captureElem.style.cursor = window.getComputedStyle(_captureElem).cursor;
+function _capturedElemChanged() {
+ const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
+ proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor;
}
-const _captureObserver = new MutationObserver(_captureElemChanged);
-
-let _captureIndex = 0;
+const _captureObserver = new MutationObserver(_capturedElemChanged);
-export function setCapture(elem) {
- if (elem.setCapture) {
+export function setCapture(target) {
+ if (target.setCapture) {
- elem.setCapture();
+ target.setCapture();
+ document.captureElement = target;
// IE releases capture on 'click' events which might not trigger
- elem.addEventListener('mouseup', releaseCapture);
+ target.addEventListener('mouseup', releaseCapture);
} else {
// Release any existing capture in case this method is
// called multiple times without coordination
releaseCapture();
- let captureElem = document.getElementById("noVNC_mouse_capture_elem");
+ let proxyElem = document.getElementById("noVNC_mouse_capture_elem");
- if (captureElem === null) {
- captureElem = document.createElement("div");
- captureElem.id = "noVNC_mouse_capture_elem";
- captureElem.style.position = "fixed";
- captureElem.style.top = "0px";
- captureElem.style.left = "0px";
- captureElem.style.width = "100%";
- captureElem.style.height = "100%";
- captureElem.style.zIndex = 10000;
- captureElem.style.display = "none";
- document.body.appendChild(captureElem);
+ if (proxyElem === null) {
+ proxyElem = document.createElement("div");
+ proxyElem.id = "noVNC_mouse_capture_elem";
+ proxyElem.style.position = "fixed";
+ proxyElem.style.top = "0px";
+ proxyElem.style.left = "0px";
+ proxyElem.style.width = "100%";
+ proxyElem.style.height = "100%";
+ proxyElem.style.zIndex = 10000;
+ proxyElem.style.display = "none";
+ document.body.appendChild(proxyElem);
// This is to make sure callers don't get confused by having
// our blocking element as the target
- captureElem.addEventListener('contextmenu', _captureProxy);
+ proxyElem.addEventListener('contextmenu', _captureProxy);
- captureElem.addEventListener('mousemove', _captureProxy);
- captureElem.addEventListener('mouseup', _captureProxy);
+ proxyElem.addEventListener('mousemove', _captureProxy);
+ proxyElem.addEventListener('mouseup', _captureProxy);
}
- _captureElem = elem;
- _captureIndex++;
+ document.captureElement = target;
// Track cursor and get initial cursor
- _captureObserver.observe(elem, {attributes: true});
- _captureElemChanged();
+ _captureObserver.observe(target, {attributes: true});
+ _capturedElemChanged();
- captureElem.style.display = "";
+ proxyElem.style.display = "";
// We listen to events on window in order to keep tracking if it
// happens to leave the viewport
@@ -112,26 +115,26 @@ export function releaseCapture() {
if (document.releaseCapture) {
document.releaseCapture();
+ document.captureElement = null;
} else {
- if (!_captureElem) {
+ if (!document.captureElement) {
return;
}
- // There might be events already queued, so we need to wait for
- // them to flush. E.g. contextmenu in Microsoft Edge
- window.setTimeout((expected) => {
- // Only clear it if it's the expected grab (i.e. no one
- // else has initiated a new grab)
- if (_captureIndex === expected) {
- _captureElem = null;
- }
- }, 0, _captureIndex);
+ // There might be events already queued. The event proxy needs
+ // access to the captured element for these queued events.
+ // E.g. contextmenu (right-click) in Microsoft Edge
+ //
+ // Before removing the capturedElem pointer we save it to a
+ // temporary variable that the unflushed events can use.
+ _elementForUnflushedEvents = document.captureElement;
+ document.captureElement = null;
_captureObserver.disconnect();
- const captureElem = document.getElementById("noVNC_mouse_capture_elem");
- captureElem.style.display = "none";
+ const proxyElem = document.getElementById("noVNC_mouse_capture_elem");
+ proxyElem.style.display = "none";
window.removeEventListener('mousemove', _captureProxy);
window.removeEventListener('mouseup', _captureProxy);
diff --git a/systemvm/agent/noVNC/core/util/eventtarget.js b/systemvm/agent/noVNC/core/util/eventtarget.js
index f54ca9b..a21aa54 100644
--- a/systemvm/agent/noVNC/core/util/eventtarget.js
+++ b/systemvm/agent/noVNC/core/util/eventtarget.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
diff --git a/systemvm/agent/noVNC/core/util/int.js b/systemvm/agent/noVNC/core/util/int.js
new file mode 100644
index 0000000..001f40f
--- /dev/null
+++ b/systemvm/agent/noVNC/core/util/int.js
@@ -0,0 +1,15 @@
+/*
+ * noVNC: HTML5 VNC client
+ * Copyright (C) 2020 The noVNC Authors
+ * Licensed under MPL 2.0 (see LICENSE.txt)
+ *
+ * See README.md for usage and integration instructions.
+ */
+
+export function toUnsigned32bit(toConvert) {
+ return toConvert >>> 0;
+}
+
+export function toSigned32bit(toConvert) {
+ return toConvert | 0;
+}
diff --git a/systemvm/agent/noVNC/core/util/logging.js b/systemvm/agent/noVNC/core/util/logging.js
index 4c8943d..fe449e9 100644
--- a/systemvm/agent/noVNC/core/util/logging.js
+++ b/systemvm/agent/noVNC/core/util/logging.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -10,18 +10,18 @@
* Logging/debug routines
*/
-let _log_level = 'warn';
+let _logLevel = 'warn';
let Debug = () => {};
let Info = () => {};
let Warn = () => {};
let Error = () => {};
-export function init_logging(level) {
+export function initLogging(level) {
if (typeof level === 'undefined') {
- level = _log_level;
+ level = _logLevel;
} else {
- _log_level = level;
+ _logLevel = level;
}
Debug = Info = Warn = Error = () => {};
@@ -46,11 +46,11 @@ export function init_logging(level) {
}
}
-export function get_logging() {
- return _log_level;
+export function getLogging() {
+ return _logLevel;
}
export { Debug, Info, Warn, Error };
// Initialize logging level
-init_logging();
+initLogging();
diff --git a/systemvm/agent/noVNC/core/util/polyfill.js b/systemvm/agent/noVNC/core/util/polyfill.js
index 648ceeb..0e458c8 100644
--- a/systemvm/agent/noVNC/core/util/polyfill.js
+++ b/systemvm/agent/noVNC/core/util/polyfill.js
@@ -1,6 +1,6 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2020 The noVNC Authors
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
*/
@@ -52,3 +52,10 @@ if (typeof Object.assign != 'function') {
window.CustomEvent = CustomEvent;
}
})();
+
+/* Number.isInteger() (taken from MDN) */
+Number.isInteger = Number.isInteger || function isInteger(value) {
+ return typeof value === 'number' &&
+ isFinite(value) &&
+ Math.floor(value) === value;
+};
diff --git a/systemvm/agent/noVNC/core/util/strings.js b/systemvm/agent/noVNC/core/util/strings.js
index 61f4f23..3dd4b29 100644
--- a/systemvm/agent/noVNC/core/util/strings.js
+++ b/systemvm/agent/noVNC/core/util/strings.js
@@ -1,14 +1,28 @@
/*
* noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
*/
-/*
- * Decode from UTF-8
- */
-export function decodeUTF8(utf8string) {
- return decodeURIComponent(escape(utf8string));
+// Decode from UTF-8
+export function decodeUTF8(utf8string, allowLatin1=false) {
+ try {
+ return decodeURIComponent(escape(utf8string));
+ } catch (e) {
+ if (e instanceof URIError) {
+ if (allowLatin1) {
+ // If we allow Latin1 we can ignore any decoding fails
+ // and in these cases return the original string
+ return utf8string;
+ }
+ }
+ throw e;
+ }
+}
+
+// Encode to UTF-8
+export function encodeUTF8(DOMString) {
+ return unescape(encodeURIComponent(DOMString));
}
diff --git a/systemvm/agent/noVNC/core/websock.js b/systemvm/agent/noVNC/core/websock.js
index 51b9a66..3156aed 100644
--- a/systemvm/agent/noVNC/core/websock.js
+++ b/systemvm/agent/noVNC/core/websock.js
@@ -1,6 +1,6 @@
/*
* Websock: high-performance binary WebSockets
- * Copyright (C) 2018 The noVNC Authors
+ * Copyright (C) 2019 The noVNC Authors
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* Websock is similar to the standard WebSocket object but with extra
@@ -17,6 +17,8 @@ import * as Log from './util/logging.js';
// this has performance issues in some versions Chromium, and
// doesn't gain a tremendous amount of performance increase in Firefox
// at the moment. It may be valuable to turn it on in the future.
+// Also copyWithin() for TypedArrays is not supported in IE 11 or
+// Safari 13 (at the moment we want to support Safari 11).
const ENABLE_COPYWITHIN = false;
const MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB
@@ -27,7 +29,6 @@ export default class Websock {
this._rQi = 0; // Receive queue index
this._rQlen = 0; // Next write position in the receive queue
this._rQbufferSize = 1024 * 1024 * 4; // Receive queue buffer size (4 MiB)
- this._rQmax = this._rQbufferSize / 8;
// called in init: this._rQ = new Uint8Array(this._rQbufferSize);
this._rQ = null; // Receive queue
@@ -143,7 +144,7 @@ export default class Websock {
flush() {
if (this._sQlen > 0 && this._websocket.readyState === WebSocket.OPEN) {
- this._websocket.send(this._encode_message());
+ this._websocket.send(this._encodeMessage());
this._sQlen = 0;
}
}
@@ -154,7 +155,7 @@ export default class Websock {
this.flush();
}
- send_string(str) {
+ sendString(str) {
this.send(str.split('').map(chr => chr.charCodeAt(0)));
}
@@ -167,13 +168,13 @@ export default class Websock {
this._eventHandlers[evt] = handler;
}
- _allocate_buffers() {
+ _allocateBuffers() {
this._rQ = new Uint8Array(this._rQbufferSize);
this._sQ = new Uint8Array(this._sQbufferSize);
}
init() {
- this._allocate_buffers();
+ this._allocateBuffers();
this._rQi = 0;
this._websocket = null;
}
@@ -184,7 +185,7 @@ export default class Websock {
this._websocket = new WebSocket(uri, protocols);
this._websocket.binaryType = 'arraybuffer';
- this._websocket.onmessage = this._recv_message.bind(this);
+ this._websocket.onmessage = this._recvMessage.bind(this);
this._websocket.onopen = () => {
Log.Debug('>> WebSock.onopen');
if (this._websocket.protocol) {
@@ -219,42 +220,46 @@ export default class Websock {
}
// private methods
- _encode_message() {
+ _encodeMessage() {
// Put in a binary arraybuffer
// according to the spec, you can send ArrayBufferViews with the send method
return new Uint8Array(this._sQ.buffer, 0, this._sQlen);
}
- _expand_compact_rQ(min_fit) {
- const resizeNeeded = min_fit || this.rQlen > this._rQbufferSize / 2;
+ // We want to move all the unread data to the start of the queue,
+ // e.g. compacting.
+ // The function also expands the receive que if needed, and for
+ // performance reasons we combine these two actions to avoid
+ // unneccessary copying.
+ _expandCompactRQ(minFit) {
+ // if we're using less than 1/8th of the buffer even with the incoming bytes, compact in place
+ // instead of resizing
+ const requiredBufferSize = (this._rQlen - this._rQi + minFit) * 8;
+ const resizeNeeded = this._rQbufferSize < requiredBufferSize;
+
if (resizeNeeded) {
- if (!min_fit) {
- // just double the size if we need to do compaction
- this._rQbufferSize *= 2;
- } else {
- // otherwise, make sure we satisy rQlen - rQi + min_fit < rQbufferSize / 8
- this._rQbufferSize = (this.rQlen + min_fit) * 8;
- }
+ // Make sure we always *at least* double the buffer size, and have at least space for 8x
+ // the current amount of data
+ this._rQbufferSize = Math.max(this._rQbufferSize * 2, requiredBufferSize);
}
// we don't want to grow unboundedly
if (this._rQbufferSize > MAX_RQ_GROW_SIZE) {
this._rQbufferSize = MAX_RQ_GROW_SIZE;
- if (this._rQbufferSize - this.rQlen < min_fit) {
+ if (this._rQbufferSize - this.rQlen < minFit) {
throw new Error("Receive Queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit");
}
}
if (resizeNeeded) {
- const old_rQbuffer = this._rQ.buffer;
- this._rQmax = this._rQbufferSize / 8;
+ const oldRQbuffer = this._rQ.buffer;
this._rQ = new Uint8Array(this._rQbufferSize);
- this._rQ.set(new Uint8Array(old_rQbuffer, this._rQi));
+ this._rQ.set(new Uint8Array(oldRQbuffer, this._rQi, this._rQlen - this._rQi));
} else {
if (ENABLE_COPYWITHIN) {
- this._rQ.copyWithin(0, this._rQi);
+ this._rQ.copyWithin(0, this._rQi, this._rQlen);
} else {
- this._rQ.set(new Uint8Array(this._rQ.buffer, this._rQi));
+ this._rQ.set(new Uint8Array(this._rQ.buffer, this._rQi, this._rQlen - this._rQi));
}
}
@@ -262,26 +267,25 @@ export default class Websock {
this._rQi = 0;
}
- _decode_message(data) {
- // push arraybuffer values onto the end
+ // push arraybuffer values onto the end of the receive que
+ _DecodeMessage(data) {
const u8 = new Uint8Array(data);
if (u8.length > this._rQbufferSize - this._rQlen) {
- this._expand_compact_rQ(u8.length);
+ this._expandCompactRQ(u8.length);
}
this._rQ.set(u8, this._rQlen);
this._rQlen += u8.length;
}
- _recv_message(e) {
- this._decode_message(e.data);
+ _recvMessage(e) {
+ this._DecodeMessage(e.data);
if (this.rQlen > 0) {
this._eventHandlers.message();
- // Compact the receive queue
if (this._rQlen == this._rQi) {
+ // All data has now been processed, this means we
+ // can reset the receive queue.
this._rQlen = 0;
this._rQi = 0;
- } else if (this._rQlen > this._rQmax) {
- this._expand_compact_rQ();
}
} else {
Log.Debug("Ignoring empty message");
diff --git a/systemvm/agent/noVNC/docs/API-internal.md b/systemvm/agent/noVNC/docs/API-internal.md
deleted file mode 100644
index 0b29afb..0000000
--- a/systemvm/agent/noVNC/docs/API-internal.md
+++ /dev/null
@@ -1,122 +0,0 @@
-# 1. Internal Modules
-
-The noVNC client is composed of several internal modules that handle
-rendering, input, networking, etc. Each of the modules is designed to
-be cross-browser and independent from each other.
-
-Note however that the API of these modules is not guaranteed to be
-stable, and this documentation is not maintained as well as the
-official external API.
-
-
-## 1.1 Module List
-
-* __Mouse__ (core/input/mouse.js): Mouse input event handler with
-limited touch support.
-
-* __Keyboard__ (core/input/keyboard.js): Keyboard input event handler with
-non-US keyboard support. Translates keyDown and keyUp events to X11
-keysym values.
-
-* __Display__ (core/display.js): Efficient 2D rendering abstraction
-layered on the HTML5 canvas element.
-
-* __Websock__ (core/websock.js): Websock client from websockify
-with transparent binary data support.
-[Websock API](https://github.com/novnc/websockify/wiki/websock.js) wiki page.
-
-
-## 1.2 Callbacks
-
-For the Mouse, Keyboard and Display objects the callback functions are
-assigned to configuration attributes, just as for the RFB object. The
-WebSock module has a method named 'on' that takes two parameters: the
-callback event name, and the callback function.
-
-## 2. Modules
-
-## 2.1 Mouse Module
-
-### 2.1.1 Configuration Attributes
-
-| name | type | mode | default | description
-| ----------- | ---- | ---- | -------- | ------------
-| touchButton | int | RW | 1 | Button mask (1, 2, 4) for which click to send on touch devices. 0 means ignore clicks.
-
-### 2.1.2 Methods
-
-| name | parameters | description
-| ------ | ---------- | ------------
-| grab | () | Begin capturing mouse events
-| ungrab | () | Stop capturing mouse events
-
-### 2.1.2 Callbacks
-
-| name | parameters | description
-| ------------- | ------------------- | ------------
-| onmousebutton | (x, y, down, bmask) | Handler for mouse button click/release
-| onmousemove | (x, y) | Handler for mouse movement
-
-
-## 2.2 Keyboard Module
-
-### 2.2.1 Configuration Attributes
-
-None
-
-### 2.2.2 Methods
-
-| name | parameters | description
-| ------ | ---------- | ------------
-| grab | () | Begin capturing keyboard events
-| ungrab | () | Stop capturing keyboard events
-
-### 2.2.3 Callbacks
-
-| name | parameters | description
-| ---------- | -------------------- | ------------
-| onkeypress | (keysym, code, down) | Handler for key press/release
-
-
-## 2.3 Display Module
-
-### 2.3.1 Configuration Attributes
-
-| name | type | mode | default | description
-| ------------ | ----- | ---- | ------- | ------------
-| logo | raw | RW | | Logo to display when cleared: {"width": width, "height": height, "type": mime-type, "data": data}
-| scale | float | RW | 1.0 | Display area scale factor 0.0 - 1.0
-| clipViewport | bool | RW | false | Use viewport clipping
-| width | int | RO | | Display area width
-| height | int | RO | | Display area height
-
-### 2.3.2 Methods
-
-| name | parameters | description
-| ------------------ | ------------------------------------------------------- | ------------
-| viewportChangePos | (deltaX, deltaY) | Move the viewport relative to the current location
-| viewportChangeSize | (width, height) | Change size of the viewport
-| absX | (x) | Return X relative to the remote display
-| absY | (y) | Return Y relative to the remote display
-| resize | (width, height) | Set width and height
-| flip | (from_queue) | Update the visible canvas with the contents of the rendering canvas
-| clear | () | Clear the display (show logo if set)
-| pending | () | Check if there are waiting items in the render queue
-| flush | () | Resume processing the render queue unless it's empty
-| fillRect | (x, y, width, height, color, from_queue) | Draw a filled in rectangle
-| copyImage | (old_x, old_y, new_x, new_y, width, height, from_queue) | Copy a rectangular area
-| imageRect | (x, y, mime, arr) | Draw a rectangle with an image
-| startTile | (x, y, width, height, color) | Begin updating a tile
-| subTile | (tile, x, y, w, h, color) | Update a sub-rectangle within the given tile
-| finishTile | () | Draw the current tile to the display
-| blitImage | (x, y, width, height, arr, offset, from_queue) | Blit pixels (of R,G,B,A) to the display
-| blitRgbImage | (x, y, width, height, arr, offset, from_queue) | Blit RGB encoded image to display
-| blitRgbxImage | (x, y, width, height, arr, offset, from_queue) | Blit RGBX encoded image to display
-| drawImage | (img, x, y) | Draw image and track damage
-| autoscale | (containerWidth, containerHeight) | Scale the display
-
-### 2.3.3 Callbacks
-
-| name | parameters | description
-| ------- | ---------- | ------------
-| onflush | () | A display flush has been requested and we are now ready to resume FBU processing
diff --git a/systemvm/agent/noVNC/docs/API.md b/systemvm/agent/noVNC/docs/API.md
deleted file mode 100644
index d587429..0000000
--- a/systemvm/agent/noVNC/docs/API.md
+++ /dev/null
@@ -1,375 +0,0 @@
-# noVNC API
-
-The interface of the noVNC client consists of a single RFB object that
-is instantiated once per connection.
-
-## RFB
-
-The `RFB` object represents a single connection to a VNC server. It
-communicates using a WebSocket that must provide a standard RFB
-protocol stream.
... 13080 lines suppressed ...