systemvm: update novnc v1.2.0 (#4323)
Update noVNC v1.2.0, add support for clipboard, explicit button toolbar and resize screensize
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 @@
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
--- a/systemvm/agent/noVNC/.gitmodules
+++ /dev/null
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 <git@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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/alt.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/clipboard.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/connect.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/ctrl.png
Binary files 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,0.6445 1.5820313,0.6445 0.5615234,0 1.0693359,-0.166 0.5078125,-0.166 1.0302735,-0.5225 l 0,1.5088 z"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/ctrlaltdel.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/disconnect.png
Binary files 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.0001 0 0 0 -0.6875,0.3027344 l -0.445312,0.4453125 1.414062,1.4140621 0.445313,-0.445312 A 1.0001,1.0001 0 0 0 39.017578,9.015625 Z m -6.363281,0.7070312 a 1.0001,1.0001 0 0 0 -0.6875,0.3027348 L 28.431641,13.5625 c -1.163042,1.163 -1.16297,3.079187 0,4.242188 l 2.828125,2.828124 c 1.162974,1.163101 3.079213,1.163101 4.242187,0 l 3.535156,-3.535156 a 1.0001,1.0001 0 1 0 -1.414062,-1.414062 l -3.535156,3.535156 c -0.403974,0.404 -1.010089,0.404 -1.414063,0 l -2.828125,-2.828125 c -0.403981,-0.404 -0.403908,-1.010162 0,-1.414063 l 3.535156,-3.537109 A 1.0001,1.0001 0 0 0 32.654297,9.7226562 Z m 3.109375,2.1621098 -2.382813,2.384765 a 1.0001,1.0001 0 1 0 1.414063,1.414063 l 2.382812,-2.384766 -1.414062,-1.414062 z"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/drag.png
Binary files 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.9764271,-0.032 l 0.8082347,0 1.157e-4,1.336 c 1.125e-4,1.2779 0.00281,1.3403 0.062214,1.4378 0.091785,0.1505 0.2357707,0.226 0.4314082,0.2261 0.285389,2e-4 0.454884,-0.1352 0.5058962,-0.4042 0.019355,-0.102 0.031616,-0.982 0.031616,-2.269 0,-1.9756 0.00357,-2.1138 0.059205,-2.2926 0.1645475,-0.5287 0.6307616,-0.9246 1.19078,-1.0113 0.8000572,-0.1238 1.5711277,0.4446 1.6860387,1.2429 0.01732,0.1203 0.03177,0.8248 0.03211,1.5657 6.19e-4,1.3449 7.22e-4,1.347 0.07093,1.4499 0.108355,0.1587 0.255268,0.2248 0.46917,0.2108 0.204069,-0.013 0.316116,-0.08 0.413642,-0.2453 0.06028,-0.1024 0.06307,-0.1778 0.07862,-2.1218 0.01462,-1.8283 0.02124,-2.0285 0.07121,-2.1549 0.260673,-0.659 0.934894,-1.0527 1.621129,-0.9465 0.640523,0.099 1.152269,0.6104 1.243187,1.2421 0.01827,0.1269 0.03175,0.9943 0.03211,2.0657 l 6.19e-4,1.8469 0.07031,0.103 c 0.108355,0.1587 0.255267,0.2248 0.46917,0.2108 0.204069,-0.013 0.316115,-0.08 0.413642,-0.2453 0.05951,-0.1011 0.06329,-0.1786 0.07907,-1.6218 0.01469,-1.3438 0.02277,-1.5314 0.07121,-1.6549 0.257975,-0.6576 0.934425,-1.0527 1.620676,-0.9465 0.640522,0.099 1.152269,0.6104 1.243186,1.2421 0.0186,0.1292 0.03179,1.0759 0.03222,2.3125 7.15e-4,2.0335 0.0025,2.0966 0.06283,2.1956 0.09178,0.1505 0.235771,0.226 0.431409,0.2261 0.285388,2e-4 0.454884,-0.1352 0.505897,-0.4042 0.01874,-0.099 0.03161,-0.8192 0.03161,-1.769 0,-1.4848 0.0043,-1.6163 0.0592,-1.7926 0.164548,-0.5287 0.630762,-0.9246 1.19078,-1.0113 0.800057,-0.1238 1.571128,0.4446 1.686039,1.2429 0.04318,0.2999 0.04372,9.1764 5.78e-4,9.4531 -0.04431,0.2841 -0.217814,0.6241 -0.420069,0.8232 -0.320102,0.315 -0.63307,0.4268 -1.194973,0.4268 l -0.35281,0 -2.51e-4,1.2734 c -1.25e-4,0.7046 -0.01439,1.3642 -0.03191,1.4766 -0.06665,0.4274 -0.372966,0.8704 -0.740031,1.0702 -0.349999,0.1905 0.01748,0.18 -6.242199,0.1776 -5.3622439,0 -5.7320152,-0.01 -5.9121592,-0.057 l 1.4e-5,0 z"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/error.png
Binary files 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.6916875 1.6924297 0 1 1 6.5214844 16.085938 L 10.109375 12.496094 L 6.5214844 8.90625 A 1.6916875 1.6924297 0 0 1 7.6992188 6 z "
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/esc.png
Binary files 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,0.127 1.118164,0.127 0.512695,0 0.771485,-0.1416 0.258789,-0.1416 0.258789,-0.4199 0,-0.2344 -0.180664,-0.3467 -0.175782,-0.1172 -0.708008,-0.1807 l -0.307617,-0.039 q -1.166993,-0.1465 -1.635743,-0.542 -0.46875,-0.3955 -0.46875,-1.2012 0,-0.8691 0.595703,-1.2891 0.595704,-0.4199 1.826172,-0.4199 0.483399,0 1.015625,0.073 0.532227,0.073 1.157227,0.2294 z"
- 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.314453,-0.7617 0.429688,0 0.844727,0.078 0.419921,0.073 0.834961,0.2246 z"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/expander.png
Binary files 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/fullscreen.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/handle.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/handle_bg.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/info.png
Binary files 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 18.754109 11.776235 18.366625 11.458984 17.828125 C 11.141734 17.289525 11.021484 16.668469 11.021484 15.980469 L 11.021484 11.980469 L 10.521484 11.980469 A 1.50015 1.50015 0 1 1 10.521484 8.9804688 L 10.521484 8.9785156 z "
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/keyboard.png
Binary files 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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 8.223,14 8.5,14 Z m 2,0 C 10.777,14 11,14.223 11,14.5 11,14.777 10.777,15 10.5,15 10.223,15 10,14.777 10,14.5 10,14.223 10.223,14 10.5,14 Z m 2,0 C 12.777,14 13,14.223 13,14.5 13,14.777 12.777,15 12.5,15 12.223,15 12,14.777 12,14.5 12,14.223 12.223,14 12.5,14 Z m 2,0 C 14.777,14 15,14.223 15,14.5 15,14.777 14.777,15 14.5,15 14.223,15 14,14.777 14,14.5 14,14.223 14.223,14 14.5,14 Z m 2,0 C 16.777,14 17,14.223 17,14.5 17,14.777 16.777,15 16.5,15 16.223,15 16,14.777 16,14.5 16,14.223 16.223,14 16.5,14 Z m 2,0 C 18.777,14 19,14.223 19,14.5 19,14.777 18.777,15 18.5,15 18.223,15 18,14.777 18,14.5 18,14.223 18.223,14 18.5,14 Z m -13,2 C 5.777,16 6,16.223 6,16.5 6,16.777 5.777,17 5.5,17 5.223,17 5,16.777 5,16.5 5,16.223 5.223,16 5.5,16 Z m 2,0 C 7.777,16 8,16.223 8,16.5 8,16.777 7.777,17 7.5,17 7.223,17 7,16.777 7,16.5 7,16.223 7.223,16 7.5,16 Z m 2,0 C 9.777,16 10,16.223 10,16.5 10,16.777 9.777,17 9.5,17 9.223,17 9,16.777 9,16.5 9,16.223 9.223,16 9.5,16 Z m 2,0 C 11.777,16 12,16.223 12,16.5 12,16.777 11.777,17 11.5,17 11.223,17 11,16.777 11,16.5 11,16.223 11.223,16 11.5,16 Z m 2,0 C 13.777,16 14,16.223 14,16.5 14,16.777 13.777,17 13.5,17 13.223,17 13,16.777 13,16.5 13,16.223 13.223,16 13.5,16 Z m 2,0 C 15.777,16 16,16.223 16,16.5 16,16.777 15.777,17 15.5,17 15.223,17 15,16.777 15,16.5 15,16.223 15.223,16 15.5,16 Z m 2,0 C 17.777,16 18,16.223 18,16.5 18,16.777 17.777,17 17.5,17 17.223,17 17,16.777 17,16.5 17,16.223 17.223,16 17.5,16 Z m 2,0 C 19.777,16 20,16.223 20,16.5 20,16.777 19.777,17 19.5,17 19.223,17 19,16.777 19,16.5 19,16.223 19.223,16 19.5,16 Z M 6,18 c 0.554,0 1,0.446 1,1 0,0.554 -0.446,1 -1,1 -0.554,0 -1,-0.446 -1,-1 0,-0.554 0.446,-1 1,-1 z m 2.8261719,0 7.3476561,0 C 16.631643,18 17,18.368372 17,18.826172 l 0,0.347656 C 17,19.631628 16.631643,20 16.173828,20 L 8.8261719,20 C 8.3683573,20 8,19.631628 8,19.173828 L 8,18.826172 C 8,18.368372 8.3683573,18 8.8261719,18 Z m 10.1113281,0 0.125,0 C 19.581551,18 20,18.4184 20,18.9375 l 0,0.125 C 20,19.5816 19.581551,20 19.0625,20 l -0.125,0 C 18.418449,20 18,19.5816 18,19.0625 l 0,-0.125 C 18,18.4184 18.418449,18 18.9375,18 Z"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0068f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0068f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0068f6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/power.png
Binary files 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/settings.png
Binary files 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 L 19.839844 11 A 7.5 7.5 0 0 0 18.753906 8.3671875 L 20.277344 6.84375 L 18.15625 4.7226562 L 16.630859 6.2480469 A 7.5 7.5 0 0 0 14 5.1523438 L 14 3 L 11 3 z M 12.5 10 A 2.5 2.5 0 0 1 15 12.5 A 2.5 2.5 0 0 1 12.5 15 A 2.5 2.5 0 0 1 10 12.5 A 2.5 2.5 0 0 1 12.5 10 z "
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/tab.png
Binary files 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/toggleextrakeys.png
Binary files 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/warning.png
Binary files 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:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- 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 14 18.5 A 1.5 1.5 0 0 1 12.5 20 A 1.5 1.5 0 0 1 11 18.5 A 1.5 1.5 0 0 1 12.5 17 z "
- 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
--- /dev/null
+++ b/systemvm/agent/noVNC/app/images/windows.png
Binary files 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 @@
* ----------------------------------------
*/
-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 @@
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 @@
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 @@
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 @@
}
/* 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 @@
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 @@
* ----------------------------------------
*/
-#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 RFB from "../core/rfb.js";
import * as WebUtil from "./webutil.js";
+const PAGE_TITLE = "noVNC";
+
const UI = {
connected: false,
@@ -35,9 +37,11 @@
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 @@
// 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 @@
/* 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 @@
},
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
// Error messages do not timeout
- if (status_type !== 'error') {
+ if (statusType !== 'error') {
UI.statusTimeout = window.setTimeout(UI.hideStatus, time);
}
},
@@ -507,6 +517,13 @@
},
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 @@
UI.closeAllPanels();
document.getElementById('noVNC_control_bar')
.classList.remove("noVNC_open");
+ UI.rfb.focus();
},
toggleControlbar() {
@@ -821,6 +839,8 @@
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 @@
UI.closeClipboardPanel();
} else {
UI.openClipboardPanel();
+ setTimeout(() => document
+ .getElementById('noVNC_clipboard_text').focus(), 100);
}
},
@@ -938,14 +960,13 @@
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 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 @@
return;
}
- UI.closeAllPanels();
UI.closeConnectPanel();
UI.updateVisualState('connecting');
@@ -1006,16 +1027,10 @@
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 @@
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 @@
},
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 @@
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 @@
} 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 @@
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 @@
* ------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 @@
// 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 @@
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 @@
},
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 @@
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 @@
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 @@
* 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 @@
.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 @@
},
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 @@
};
// 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 @@
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 @@
"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 @@
// 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
} 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 @@
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 @@
return false;
}
- display.imageRect(x, y, "image/jpeg", data);
+ display.imageRect(x, y, width, height, "image/jpeg", data);
return true;
}
@@ -150,6 +148,10 @@
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 @@
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);
}
- display.blitRgbImage(x, y, width, height, data, 0, false);
+ 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.blitImage(x, y, width, height, rgbx, 0, false);
return true;
}
@@ -198,6 +207,10 @@
let data;
+ if (uncompressedSize === 0) {
+ return true;
+ }
+
if (uncompressedSize < 12) {
if (sock.rQwait("TIGHT", uncompressedSize)) {
return false;
@@ -210,10 +223,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
get width() {
- return this._fb_width;
+ return this._fbWidth;
}
get height() {
- return this._fb_height;
+ return this._fbHeight;
}
// ===== PUBLIC METHODS =====
@@ -125,15 +117,15 @@
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 @@
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 @@
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 @@
// 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 @@
}
}
- 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 @@
}
}
- 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 @@
}
}
- 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 @@
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 @@
}
_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 @@
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 @@
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 @@
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 @@
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 @@
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 */
- inflate(this.strm, flush);
+ let ret = inflate(this.strm, 0); // Flush argument not used.
+ if (ret < 0) {
+ throw new Error("zlib inflate failed");
+ }
+
+ 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 @@
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 @@
// 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("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 @@
// - AudioBalanceLeft
// - AudioBalanceRight
-// - AudioBassDown
// - AudioBassBoostDown
// - AudioBassBoostToggle
// - AudioBassBoostUp
-// - AudioBassUp
// - AudioFaderFront
// - AudioFaderRear
// - AudioSurroundModeNext
@@ -243,12 +243,12 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
}
// 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 @@
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 @@
const event = new KeyboardEvent('keyup',
{ key: downList[code],
code: code });
+ event.skipCheckAlt = true;
target.dispatchEvent(event);
});
}
@@ -331,9 +348,10 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
};
// 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 @@
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 @@
}
msg += ")";
}
- switch (this._rfb_connection_state) {
+ switch (this._rfbConnectionState) {
case 'connecting':
this._fail("Connection closed " + msg);
break;
@@ -246,6 +297,15 @@
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 @@
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 @@
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 @@
}
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 @@
// 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 @@
}
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 @@
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 @@
// 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 @@
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 @@
}
}
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 @@
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 @@
// 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 @@
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 @@
* 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 @@
// State change actions
- this._rfb_connection_state = state;
+ this._rfbConnectionState = state;
Log.Debug("New state '" + state + "', was '" + oldstate + "'.");
@@ -656,7 +817,7 @@
case 'disconnected':
this.dispatchEvent(new CustomEvent(
"disconnect", { detail:
- { clean: this._rfb_clean_disconnect } }));
+ { clean: this._rfbCleanDisconnect } }));
break;
}
}
@@ -667,7 +828,7 @@
* 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 @@
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 @@
{ 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 @@
if (this._flushing) {
break;
}
- if (!this._normal_msg()) {
+ if (!this._normalMsg()) {
break;
}
if (this._sock.rQlen === 0) {
@@ -720,7 +881,7 @@
}
break;
default:
- this._init_msg();
+ this._initMsg();
break;
}
}
@@ -729,13 +890,52 @@
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 @@
// 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 (this._rfb_connection_state !== 'connected') { return; }
- RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), this._mouse_buttonMask);
+ if (down) {
+ this._mouseButtonMask |= bmask;
+ } else {
+ this._mouseButtonMask &= ~bmask;
+ }
+
+ this._sendMouse(x, y, this._mouseButtonMask);
}
_handleMouseMove(x, y) {
@@ -786,66 +993,304 @@
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 @@
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; }
+ const numTypes = this._sock.rQshift8();
+ if (this._sock.rQwait("security type", numTypes, 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();
+ 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 @@
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 @@
// 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;
}
- _negotiate_tight_tunnels(numTunnels) {
+ _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;
+ }
+
+ _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 @@
}
}
- _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 @@
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 @@
const clientSupportedTypes = {
'STDVNOAUTH__': 1,
- 'STDVVNCAUTH_': 2
+ 'STDVVNCAUTH_': 2,
+ 'TGHTULGNAUTH': 129
};
const serverSupportedTypes = [];
@@ -1061,11 +1614,14 @@
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 @@
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 @@
}
}
- _negotiate_server_init() {
+ _negotiateServerInit() {
if (this._sock.rQwait("server initialization", 24)) { return false; }
/* Screen size */
@@ -1136,27 +1698,28 @@
/* 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 bigEndian = this._sock.rQshift8();
+ const trueColor = 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 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 @@
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 @@
// 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);
+ ", bigEndian: " + bigEndian +
+ ", trueColor: " + trueColor +
+ ", redMax: " + redMax +
+ ", greenMax: " + greenMax +
+ ", blueMax: " + blueMax +
+ ", redShift: " + redShift +
+ ", greenShift: " + greenShift +
+ ", blueShift: " + blueShift);
- 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");
- }
-
+ // 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 @@
// 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 @@
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 @@
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 @@
* 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 @@
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 @@
return true;
case 3: // ServerCutText
- return this._handle_server_cut_text();
+ return this._handleServerCutText();
case 150: // EndOfContinuousUpdates
first = !this._supportsContinuousUpdates;
@@ -1432,13 +2136,13 @@
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 @@
this._flushing = false;
// Resume processing
if (this._sock.rQlen > 0) {
- this._handle_message();
+ this._handleMessage();
}
}
@@ -1500,6 +2204,9 @@
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 @@
}
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 @@
}
}
+ _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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
_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 @@
}
_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 @@
},
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 @@
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 @@
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 @@
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 @@
sock.flush();
},
- pixelFormat(sock, depth, true_color) {
+ pixelFormat(sock, depth, trueColor) {
const buff = sock._sQ;
const offset = sock._sQlen;
@@ -1950,7 +2899,7 @@
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 @@
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 @@
const target = document.createElement('canvas');
target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default';
- 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 @@
}
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 @@
!!(/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 @@
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 @@
'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 @@
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 @@
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 @@
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 @@
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 @@
}
_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 @@
// 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 @@
// (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 @@
}
_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 @@
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 @@
// 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 @@
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 @@
}
// 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);
+const _captureObserver = new MutationObserver(_capturedElemChanged);
-let _captureIndex = 0;
+export function setCapture(target) {
+ if (target.setCapture) {
-export function setCapture(elem) {
- if (elem.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 @@
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 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 @@
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 @@
// 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 @@
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 @@
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 @@
this.flush();
}
- send_string(str) {
+ sendString(str) {
this.send(str.split('').map(chr => chr.charCodeAt(0)));
}
@@ -167,13 +168,13 @@
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 @@
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 @@
}
// 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 @@
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.
-
-### Constructor
-
-[`RFB()`](#rfb-1)
- - Creates and returns a new `RFB` object.
-
-### Properties
-
-`viewOnly`
- - Is a `boolean` indicating if any events (e.g. key presses or mouse
- movement) should be prevented from being sent to the server.
- Disabled by default.
-
-`focusOnClick`
- - Is a `boolean` indicating if keyboard focus should automatically be
- moved to the remote session when a `mousedown` or `touchstart`
- event is received.
-
-`touchButton`
- - Is a `long` controlling the button mask that should be simulated
- when a touch event is recieved. Uses the same values as
- [`MouseEvent.button`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button).
- Is set to `1` by default.
-
-`clipViewport`
- - Is a `boolean` indicating if the remote session should be clipped
- to its container. When disabled scrollbars will be shown to handle
- the resulting overflow. Disabled by default.
-
-`dragViewport`
- - Is a `boolean` indicating if mouse events should control the
- relative position of a clipped remote session. Only relevant if
- `clipViewport` is enabled. Disabled by default.
-
-`scaleViewport`
- - Is a `boolean` indicating if the remote session should be scaled
- locally so it fits its container. When disabled it will be centered
- if the remote session is smaller than its container, or handled
- according to `clipViewport` if it is larger. Disabled by default.
-
-`resizeSession`
- - Is a `boolean` indicating if a request to resize the remote session
- should be sent whenever the container changes dimensions. Disabled
- by default.
-
-`showDotCursor`
- - Is a `boolean` indicating whether a dot cursor should be shown
- instead of a zero-sized or fully-transparent cursor if the server
- sets such invisible cursor. Disabled by default.
-
-`background`
- - Is a valid CSS [background](https://developer.mozilla.org/en-US/docs/Web/CSS/background)
- style value indicating which background style should be applied
- to the element containing the remote session screen. The default value is `rgb(40, 40, 40)`
- (solid gray color).
-
-`capabilities` *Read only*
- - Is an `Object` indicating which optional extensions are available
- on the server. Some methods may only be called if the corresponding
- capability is set. The following capabilities are defined:
-
- | name | type | description
- | -------- | --------- | -----------
- | `power` | `boolean` | Machine power control is available
-
-### Events
-
-[`connect`](#connect)
- - The `connect` event is fired when the `RFB` object has completed
- the connection and handshaking with the server.
-
-[`disconnect`](#disconnected)
- - The `disconnect` event is fired when the `RFB` object disconnects.
-
-[`credentialsrequired`](#credentialsrequired)
- - The `credentialsrequired` event is fired when more credentials must
- be given to continue.
-
-[`securityfailure`](#securityfailure)
- - The `securityfailure` event is fired when the security negotiation
- with the server fails.
-
-[`clipboard`](#clipboard)
- - The `clipboard` event is fired when clipboard data is received from
- the server.
-
-[`bell`](#bell)
- - The `bell` event is fired when a audible bell request is received
- from the server.
-
-[`desktopname`](#desktopname)
- - The `desktopname` event is fired when the remote desktop name
- changes.
-
-[`capabilities`](#capabilities)
- - The `capabilities` event is fired when `RFB.capabilities` is
- updated.
-
-### Methods
-
-[`RFB.disconnect()`](#rfbdisconnect)
- - Disconnect from the server.
-
-[`RFB.sendCredentials()`](#rfbsendcredentials)
- - Send credentials to server. Should be called after the
- [`credentialsrequired`](#credentialsrequired) event has fired.
-
-[`RFB.sendKey()`](#rfbsendKey)
- - Send a key event.
-
-[`RFB.sendCtrlAltDel()`](#rfbsendctrlaltdel)
- - Send Ctrl-Alt-Del key sequence.
-
-[`RFB.focus()`](#rfbfocus)
- - Move keyboard focus to the remote session.
-
-[`RFB.blur()`](#rfbblur)
- - Remove keyboard focus from the remote session.
-
-[`RFB.machineShutdown()`](#rfbmachineshutdown)
- - Request a shutdown of the remote machine.
-
-[`RFB.machineReboot()`](#rfbmachinereboot)
- - Request a reboot of the remote machine.
-
-[`RFB.machineReset()`](#rfbmachinereset)
- - Request a reset of the remote machine.
-
-[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom)
- - Send clipboard contents to server.
-
-### Details
-
-#### RFB()
-
-The `RFB()` constructor returns a new `RFB` object and initiates a new
-connection to a specified VNC server.
-
-##### Syntax
-
- let rfb = new RFB( target, url [, options] );
-
-###### Parameters
-
-**`target`**
- - A block [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)
- that specifies where the `RFB` object should attach itself. The
- existing contents of the `HTMLElement` will be untouched, but new
- elements will be added during the lifetime of the `RFB` object.
-
-**`url`**
- - A `DOMString` specifying the VNC server to connect to. This must be
- a valid WebSocket URL.
-
-**`options`** *Optional*
- - An `Object` specifying extra details about how the connection
- should be made.
-
- Possible options:
-
- `shared`
- - A `boolean` indicating if the remote server should be shared or
- if any other connected clients should be disconnected. Enabled
- by default.
-
- `credentials`
- - An `Object` specifying the credentials to provide to the server
- when authenticating. The following credentials are possible:
-
- | name | type | description
- | ------------ | ----------- | -----------
- | `"username"` | `DOMString` | The user that authenticates
- | `"password"` | `DOMString` | Password for the user
- | `"target"` | `DOMString` | Target machine or session
-
- `repeaterID`
- - A `DOMString` specifying the ID to provide to any VNC repeater
- encountered.
-
-#### connect
-
-The `connect` event is fired after all the handshaking with the server
-is completed and the connection is fully established. After this event
-the `RFB` object is ready to recieve graphics updates and to send input.
-
-#### disconnect
-
-The `disconnect` event is fired when the connection has been
-terminated. The `detail` property is an `Object` that contains the
-property `clean`. `clean` is a `boolean` indicating if the termination
-was clean or not. In the event of an unexpected termination or an error
-`clean` will be set to false.
-
-#### credentialsrequired
-
-The `credentialsrequired` event is fired when the server requests more
-credentials than were specified to [`RFB()`](#rfb-1). The `detail`
-property is an `Object` containing the property `types` which is an
-`Array` of `DOMString` listing the credentials that are required.
-
-#### securityfailure
-
-The `securityfailure` event is fired when the handshaking process with
-the server fails during the security negotiation step. The `detail`
-property is an `Object` containing the following properties:
-
-| Property | Type | Description
-| -------- | ----------- | -----------
-| `status` | `long` | The failure status code
-| `reason` | `DOMString` | The **optional** reason for the failure
-
-The property `status` corresponds to the
-[SecurityResult](https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#securityresult)
-status code in cases of failure. A status of zero will not be sent in
-this event since that indicates a successful security handshaking
-process. The optional property `reason` is provided by the server and
-thus the language of the string is not known. However most servers will
-probably send English strings. The server can choose to not send a
-reason and in these cases the `reason` property will be omitted.
-
-#### clipboard
-
-The `clipboard` event is fired when the server has sent clipboard data.
-The `detail` property is an `Object` containing the property `text`
-which is a `DOMString` with the clipboard data.
-
-#### bell
-
-The `bell` event is fired when the server has requested an audible
-bell.
-
-#### desktopname
-
-The `desktopname` event is fired when the name of the remote desktop
-changes. The `detail` property is an `Object` with the property `name`
-which is a `DOMString` specifying the new name.
-
-#### capabilities
-
-The `capabilities` event is fired whenever an entry is added or removed
-from `RFB.capabilities`. The `detail` property is an `Object` with the
-property `capabilities` containing the new value of `RFB.capabilities`.
-
-#### RFB.disconnect()
-
-The `RFB.disconnect()` method is used to disconnect from the currently
-connected server.
-
-##### Syntax
-
- RFB.disconnect( );
-
-#### RFB.sendCredentials()
-
-The `RFB.sendCredentials()` method is used to provide the missing
-credentials after a `credentialsrequired` event has been fired.
-
-##### Syntax
-
- RFB.sendCredentials( credentials );
-
-###### Parameters
-
-**`credentials`**
- - An `Object` specifying the credentials to provide to the server
- when authenticating. See [`RFB()`](#rfb-1) for details.
-
-#### RFB.sendKey()
-
-The `RFB.sendKey()` method is used to send a key event to the server.
-
-##### Syntax
-
- RFB.sendKey( keysym, code [, down] );
-
-###### Parameters
-
-**`keysym`**
- - A `long` specifying the RFB keysym to send. Can be `0` if a valid
- **`code`** is specified.
-
-**`code`**
- - A `DOMString` specifying the physical key to send. Valid values are
- those that can be specified to
- [`KeyboardEvent.code`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code).
- If the physical key cannot be determined then `null` shall be
- specified.
-
-**`down`** *Optional*
- - A `boolean` specifying if a press or a release event should be
- sent. If omitted then both a press and release event are sent.
-
-#### RFB.sendCtrlAltDel()
-
-The `RFB.sendCtrlAltDel()` method is used to send the key sequence
-*left Control*, *left Alt*, *Delete*. This is a convenience wrapper
-around [`RFB.sendKey()`](#rfbsendkey).
-
-##### Syntax
-
- RFB.sendCtrlAltDel( );
-
-#### RFB.focus()
-
-The `RFB.focus()` method sets the keyboard focus on the remote session.
-Keyboard events will be sent to the remote server after this point.
-
-##### Syntax
-
- RFB.focus( );
-
-#### RFB.blur()
-
-The `RFB.blur()` method remove keyboard focus on the remote session.
-Keyboard events will no longer be sent to the remote server after this
-point.
-
-##### Syntax
-
- RFB.blur( );
-
-#### RFB.machineShutdown()
-
-The `RFB.machineShutdown()` method is used to request to shut down the
-remote machine. The capability `power` must be set for this method to
-have any effect.
-
-##### Syntax
-
- RFB.machineShutdown( );
-
-#### RFB.machineReboot()
-
-The `RFB.machineReboot()` method is used to request a clean reboot of
-the remote machine. The capability `power` must be set for this method
-to have any effect.
-
-##### Syntax
-
- RFB.machineReboot( );
-
-#### RFB.machineReset()
-
-The `RFB.machineReset()` method is used to request a forced reset of
-the remote machine. The capability `power` must be set for this method
-to have any effect.
-
-##### Syntax
-
- RFB.machineReset( );
-
-#### RFB.clipboardPasteFrom()
-
-The `RFB.clipboardPasteFrom()` method is used to send clipboard data
-to the remote server.
-
-##### Syntax
-
- RFB.clipboardPasteFrom( text );
-
-###### Parameters
-
-**`text`**
- - A `DOMString` specifying the clipboard data to send. Currently only
- characters from ISO 8859-1 are supported.
diff --git a/systemvm/agent/noVNC/docs/EMBEDDING.md b/systemvm/agent/noVNC/docs/EMBEDDING.md
deleted file mode 100644
index 5399b48..0000000
--- a/systemvm/agent/noVNC/docs/EMBEDDING.md
+++ /dev/null
@@ -1,119 +0,0 @@
-# Embedding and Deploying noVNC Application
-
-This document describes how to embed and deploy the noVNC application, which
-includes settings and a full user interface. If you are looking for
-documentation on how to use the core noVNC library in your own application,
-then please see our [library documentation](LIBRARY.md).
-
-## Files
-
-The noVNC application consists of the following files and directories:
-
-* `vnc.html` - The main page for the application and where users should go. It
- is possible to rename this file.
-
-* `app/` - Support files for the application. Contains code, images, styles and
- translations.
-
-* `core/` - The core noVNC library.
-
-* `vendor/` - Third party support libraries used by the application and the
- core library.
-
-The most basic deployment consists of simply serving these files from a web
-server and setting up a WebSocket proxy to the VNC server.
-
-## Parameters
-
-The noVNC application can be controlled by including certain settings in the
-query string. Currently the following options are available:
-
-* `autoconnect` - Automatically connect as soon as the page has finished
- loading.
-
-* `reconnect` - If noVNC should automatically reconnect if the connection is
- dropped.
-
-* `reconnect_delay` - How long to wait in milliseconds before attempting to
- reconnect.
-
-* `host` - The WebSocket host to connect to.
-
-* `port` - The WebSocket port to connect to.
-
-* `encrypt` - If TLS should be used for the WebSocket connection.
-
-* `path` - The WebSocket path to use.
-
-* `password` - The password sent to the server, if required.
-
-* `repeaterID` - The repeater ID to use if a VNC repeater is detected.
-
-* `shared` - If other VNC clients should be disconnected when noVNC connects.
-
-* `bell` - If the keyboard bell should be enabled or not.
-
-* `view_only` - If the remote session should be in non-interactive mode.
-
-* `view_clip` - If the remote session should be clipped or use scrollbars if
- it cannot fit in the browser.
-
-* `resize` - How to resize the remote session if it is not the same size as
- the browser window. Can be one of `off`, `scale` and `remote`.
-
-* `show_dot` - If a dot cursor should be shown when the remote server provides
- no local cursor, or provides a fully-transparent (invisible) cursor.
-
-* `logging` - The console log level. Can be one of `error`, `warn`, `info` or
- `debug`.
-
-## Pre-conversion of Modules
-
-noVNC is written using ECMAScript 6 modules. Many of the major browsers support
-these modules natively, but not all. By default the noVNC application includes
-a script that can convert these modules to an older format as they are being
-loaded. However this process can be slow and severely increases the load time
-for the application.
-
-It is possible to perform this conversion ahead of time, avoiding the extra
-load times. To do this please follow these steps:
-
- 1. Install Node.js
- 2. Run `npm install` in the noVNC directory
- 3. Run `./utils/use_require.js --with-app --as commonjs`
-
-This will produce a `build/` directory that includes everything needed to run
-the noVNC application.
-
-## HTTP Serving Considerations
-### Browser Cache Issue
-
-If you serve noVNC files using a web server that provides an ETag header, and
-include any options in the query string, a nasty browser cache issue can bite
-you on upgrade, resulting in a red error box. The issue is caused by a mismatch
-between the new vnc.html (which is reloaded because the user has used it with
-new query string after the upgrade) and the old javascript files (that the
-browser reuses from its cache). To avoid this issue, the browser must be told
-to always revalidate cached files using conditional requests. The correct
-semantics are achieved via the (confusingly named) `Cache-Control: no-cache`
-header that needs to be provided in the web server responses.
-
-### Example Server Configurations
-
-Apache:
-
-```
- # In the main configuration file
- # (Debian/Ubuntu users: use "a2enmod headers" instead)
- LoadModule headers_module modules/mod_headers.so
-
- # In the <Directory> or <Location> block related to noVNC
- Header set Cache-Control "no-cache"
-```
-
-Nginx:
-
-```
- # In the location block related to noVNC
- add_header Cache-Control no-cache;
-```
diff --git a/systemvm/agent/noVNC/docs/LIBRARY.md b/systemvm/agent/noVNC/docs/LIBRARY.md
deleted file mode 100644
index 63f55e8..0000000
--- a/systemvm/agent/noVNC/docs/LIBRARY.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Using the noVNC JavaScript library
-
-This document describes how to make use of the noVNC JavaScript library for
-integration in your own VNC client application. If you wish to embed the more
-complete noVNC application with its included user interface then please see
-our [embedding documentation](EMBEDDING.md).
-
-## API
-
-The API of noVNC consists of a single object called `RFB`. The formal
-documentation for that object can be found in our [API documentation](API.md).
-
-## Example
-
-noVNC includes a small example application called `vnc_lite.html`. This does
-not make use of all the features of noVNC, but is a good start to see how to
-do things.
-
-## Conversion of Modules
-
-noVNC is written using ECMAScript 6 modules. Many of the major browsers support
-these modules natively, but not all. They are also not supported by Node.js. To
-use noVNC in these places the library must first be converted.
-
-Fortunately noVNC includes a script to handle this conversion. Please follow
-the following steps:
-
- 1. Install Node.js
- 2. Run `npm install` in the noVNC directory
- 3. Run `./utils/use_require.js --as <module format>`
-
-Several module formats are available. Please run
-`./utils/use_require.js --help` to see them all.
-
-The result of the conversion is available in the `lib/` directory.
diff --git a/systemvm/agent/noVNC/docs/LICENSE.BSD-2-Clause b/systemvm/agent/noVNC/docs/LICENSE.BSD-2-Clause
deleted file mode 100644
index 9d66ec9..0000000
--- a/systemvm/agent/noVNC/docs/LICENSE.BSD-2-Clause
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright (c) <year>, <copyright holder>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/systemvm/agent/noVNC/docs/LICENSE.BSD-3-Clause b/systemvm/agent/noVNC/docs/LICENSE.BSD-3-Clause
deleted file mode 100644
index e160466..0000000
--- a/systemvm/agent/noVNC/docs/LICENSE.BSD-3-Clause
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) <year>, <copyright holder>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the <organization> nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/systemvm/agent/noVNC/docs/LICENSE.MPL-2.0 b/systemvm/agent/noVNC/docs/LICENSE.MPL-2.0
deleted file mode 100644
index 14e2f77..0000000
--- a/systemvm/agent/noVNC/docs/LICENSE.MPL-2.0
+++ /dev/null
@@ -1,373 +0,0 @@
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
- means each individual or legal entity that creates, contributes to
- the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
- means the combination of the Contributions of others (if any) used
- by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
- means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
- means Source Code Form to which the initial Contributor has attached
- the notice in Exhibit A, the Executable Form of such Source Code
- Form, and Modifications of such Source Code Form, in each case
- including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
- means
-
- (a) that the initial Contributor has attached the notice described
- in Exhibit B to the Covered Software; or
-
- (b) that the Covered Software was made available under the terms of
- version 1.1 or earlier of the License, but not also under the
- terms of a Secondary License.
-
-1.6. "Executable Form"
- means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
- means a work that combines Covered Software with other material, in
- a separate file or files, that is not Covered Software.
-
-1.8. "License"
- means this document.
-
-1.9. "Licensable"
- means having the right to grant, to the maximum extent possible,
- whether at the time of the initial grant or subsequently, any and
- all of the rights conveyed by this License.
-
-1.10. "Modifications"
- means any of the following:
-
- (a) any file in Source Code Form that results from an addition to,
- deletion from, or modification of the contents of Covered
- Software; or
-
- (b) any new file in Source Code Form that contains any Covered
- Software.
-
-1.11. "Patent Claims" of a Contributor
- means any patent claim(s), including without limitation, method,
- process, and apparatus claims, in any patent Licensable by such
- Contributor that would be infringed, but for the grant of the
- License, by the making, using, selling, offering for sale, having
- made, import, or transfer of either its Contributions or its
- Contributor Version.
-
-1.12. "Secondary License"
- means either the GNU General Public License, Version 2.0, the GNU
- Lesser General Public License, Version 2.1, the GNU Affero General
- Public License, Version 3.0, or any later versions of those
- licenses.
-
-1.13. "Source Code Form"
- means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
- means an individual or a legal entity exercising rights under this
- License. For legal entities, "You" includes any entity that
- controls, is controlled by, or is under common control with You. For
- purposes of this definition, "control" means (a) the power, direct
- or indirect, to cause the direction or management of such entity,
- whether by contract or otherwise, or (b) ownership of more than
- fifty percent (50%) of the outstanding shares or beneficial
- ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
- Licensable by such Contributor to use, reproduce, make available,
- modify, display, perform, distribute, and otherwise exploit its
- Contributions, either on an unmodified basis, with Modifications, or
- as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
- for sale, have made, import, and otherwise transfer either its
- Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
- or
-
-(b) for infringements caused by: (i) Your and any other third party's
- modifications of Covered Software, or (ii) the combination of its
- Contributions with other software (except as part of its Contributor
- Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
- its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
- Form, as described in Section 3.1, and You must inform recipients of
- the Executable Form how they can obtain a copy of such Source Code
- Form by reasonable means in a timely manner, at a charge no more
- than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
- License, or sublicense it under different terms, provided that the
- license for the Executable Form does not attempt to limit or alter
- the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-* *
-* 6. Disclaimer of Warranty *
-* ------------------------- *
-* *
-* Covered Software is provided under this License on an "as is" *
-* basis, without warranty of any kind, either expressed, implied, or *
-* statutory, including, without limitation, warranties that the *
-* Covered Software is free of defects, merchantable, fit for a *
-* particular purpose or non-infringing. The entire risk as to the *
-* quality and performance of the Covered Software is with You. *
-* Should any Covered Software prove defective in any respect, You *
-* (not any Contributor) assume the cost of any necessary servicing, *
-* repair, or correction. This disclaimer of warranty constitutes an *
-* essential part of this License. No use of any Covered Software is *
-* authorized under this License except under this disclaimer. *
-* *
-************************************************************************
-
-************************************************************************
-* *
-* 7. Limitation of Liability *
-* -------------------------- *
-* *
-* Under no circumstances and under no legal theory, whether tort *
-* (including negligence), contract, or otherwise, shall any *
-* Contributor, or anyone who distributes Covered Software as *
-* permitted above, be liable to You for any direct, indirect, *
-* special, incidental, or consequential damages of any character *
-* including, without limitation, damages for lost profits, loss of *
-* goodwill, work stoppage, computer failure or malfunction, or any *
-* and all other commercial damages or losses, even if such party *
-* shall have been informed of the possibility of such damages. This *
-* limitation of liability shall not apply to liability for death or *
-* personal injury resulting from such party's negligence to the *
-* extent applicable law prohibits such limitation. Some *
-* jurisdictions do not allow the exclusion or limitation of *
-* incidental or consequential damages, so this exclusion and *
-* limitation may not apply to You. *
-* *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
- This Source Code Form is "Incompatible With Secondary Licenses", as
- defined by the Mozilla Public License, v. 2.0.
diff --git a/systemvm/agent/noVNC/docs/LICENSE.OFL-1.1 b/systemvm/agent/noVNC/docs/LICENSE.OFL-1.1
deleted file mode 100644
index 77b1731..0000000
--- a/systemvm/agent/noVNC/docs/LICENSE.OFL-1.1
+++ /dev/null
@@ -1,91 +0,0 @@
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/systemvm/agent/noVNC/docs/flash_policy.txt b/systemvm/agent/noVNC/docs/flash_policy.txt
deleted file mode 100644
index df325c0..0000000
--- a/systemvm/agent/noVNC/docs/flash_policy.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Manual setup:
-
-DATA="echo \'<cross-domain-policy><allow-access-from domain=\\\"*\\\" to-ports=\\\"*\\\" /></cross-domain-policy>\'"
-/usr/bin/socat -T 1 TCP-L:843,reuseaddr,fork,crlf SYSTEM:"$DATA"
diff --git a/systemvm/agent/noVNC/docs/links b/systemvm/agent/noVNC/docs/links
deleted file mode 100644
index 31544ce..0000000
--- a/systemvm/agent/noVNC/docs/links
+++ /dev/null
@@ -1,76 +0,0 @@
-New tight PNG protocol:
- http://wiki.qemu.org/VNC_Tight_PNG
- http://xf.iksaif.net/blog/index.php?post/2010/06/14/QEMU:-Tight-PNG-and-some-profiling
-
-RFB protocol and extensions:
- http://tigervnc.org/cgi-bin/rfbproto
-
-Canvas Browser Compatibility:
- http://philip.html5.org/tests/canvas/suite/tests/results.html
-
-WebSockets API standard:
- http://www.whatwg.org/specs/web-apps/current-work/complete.html#websocket
- http://dev.w3.org/html5/websockets/
- http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt
-
-Browser Keyboard Events detailed:
- http://unixpapa.com/js/key.html
-
-ActionScript (Flash) WebSocket implementation:
- http://github.com/gimite/web-socket-js
-
-ActionScript (Flash) crypto/TLS library:
- http://code.google.com/p/as3crypto
- http://github.com/lyokato/as3crypto_patched
-
-TLS Protocol:
- http://en.wikipedia.org/wiki/Transport_Layer_Security
-
-Generate self-signed certificate:
- http://docs.python.org/dev/library/ssl.html#certificates
-
-Cursor appearance/style (for Cursor pseudo-encoding):
- http://en.wikipedia.org/wiki/ICO_(file_format)
- http://www.daubnet.com/en/file-format-cur
- https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property
- http://www.fileformat.info/format/bmp/egff.htm
-
-Icon/Cursor file format:
- http://msdn.microsoft.com/en-us/library/ms997538
- http://msdn.microsoft.com/en-us/library/aa921550.aspx
- http://msdn.microsoft.com/en-us/library/aa930622.aspx
-
-
-RDP Protocol specification:
- http://msdn.microsoft.com/en-us/library/cc240445(v=PROT.10).aspx
-
-
-Related projects:
-
- guacamole: http://guacamole.sourceforge.net/
-
- - Web client, but Java servlet does pre-processing
-
- jsvnc: http://code.google.com/p/jsvnc/
-
- - No releases
-
- webvnc: http://code.google.com/p/webvnc/
-
- - Jetty web server gateway, no updates since April 2008.
-
- RealVNC Java applet: http://www.realvnc.com/support/javavncviewer.html
-
- - Java applet
-
- Flashlight-VNC: http://www.wizhelp.com/flashlight-vnc/
-
- - Adobe Flash implementation
-
- FVNC: http://osflash.org/fvnc
-
- - Adbove Flash implementation
-
- CanVNC: http://canvnc.sourceforge.net/
-
- - HTML client with REST to VNC python proxy. Mostly vapor.
diff --git a/systemvm/agent/noVNC/docs/notes b/systemvm/agent/noVNC/docs/notes
deleted file mode 100644
index dfef0bd..0000000
--- a/systemvm/agent/noVNC/docs/notes
+++ /dev/null
@@ -1,5 +0,0 @@
-Rebuilding inflator.js
-
-- Download pako from npm
-- Install browserify using npm
-- browserify core/inflator.mod.js -o core/inflator.js -s Inflator
diff --git a/systemvm/agent/noVNC/docs/rfb_notes b/systemvm/agent/noVNC/docs/rfb_notes
deleted file mode 100644
index 643e16c..0000000
--- a/systemvm/agent/noVNC/docs/rfb_notes
+++ /dev/null
@@ -1,147 +0,0 @@
-5.1.1 ProtocolVersion: 12, 12 bytes
-
- - Sent by server, max supported
- 12 ascii - "RFB 003.008\n"
- - Response by client, version to use
- 12 ascii - "RFB 003.003\n"
-
-5.1.2 Authentication: >=4, [16, 4] bytes
-
- - Sent by server
- CARD32 - authentication-scheme
- 0 - connection failed
- CARD32 - length
- length - reason
- 1 - no authentication
-
- 2 - VNC authentication
- 16 CARD8 - challenge (random bytes)
-
- - Response by client (if VNC authentication)
- 16 CARD8 - client encrypts the challenge with DES, using user
- password as key, sends resulting 16 byte response
-
- - Response by server (if VNC authentication)
- CARD32 - 0 - OK
- 1 - failed
- 2 - too-many
-
-5.1.3 ClientInitialisation: 1 byte
- - Sent by client
- CARD8 - shared-flag, 0 exclusive, non-zero shared
-
-5.1.4 ServerInitialisation: >=24 bytes
- - Sent by server
- CARD16 - framebuffer-width
- CARD16 - framebuffer-height
- 16 byte PIXEL_FORMAT - server-pixel-format
- CARD8 - bits-per-pixel
- CARD8 - depth
- CARD8 - big-endian-flag, non-zero is big endian
- CARD8 - true-color-flag, non-zero then next 6 apply
- CARD16 - red-max
- CARD16 - green-max
- CARD16 - blue-max
- CARD8 - red-shift
- CARD8 - green-shift
- CARD8 - blue-shift
- 3 bytes - padding
- CARD32 - name-length
-
- CARD8[length] - name-string
-
-
-
-Client to Server Messages:
-
-5.2.1 SetPixelFormat: 20 bytes
- CARD8: 0 - message-type
- ...
-
-5.2.2 FixColourMapEntries: >=6 bytes
- CARD8: 1 - message-type
- ...
-
-5.2.3 SetEncodings: >=8 bytes
- CARD8: 2 - message-type
- CARD8 - padding
- CARD16 - numer-of-encodings
-
- CARD32 - encoding-type in preference order
- 0 - raw
- 1 - copy-rectangle
- 2 - RRE
- 4 - CoRRE
- 5 - hextile
-
-5.2.4 FramebufferUpdateRequest (10 bytes)
- CARD8: 3 - message-type
- CARD8 - incremental (0 for full-update, non-zero for incremental)
- CARD16 - x-position
- CARD16 - y-position
- CARD16 - width
- CARD16 - height
-
-
-5.2.5 KeyEvent: 8 bytes
- CARD8: 4 - message-type
- CARD8 - down-flag
- 2 bytes - padding
- CARD32 - key (X-Windows keysym values)
-
-5.2.6 PointerEvent: 6 bytes
- CARD8: 5 - message-type
- CARD8 - button-mask
- CARD16 - x-position
- CARD16 - y-position
-
-5.2.7 ClientCutText: >=9 bytes
- CARD8: 6 - message-type
- ...
-
-
-Server to Client Messages:
-
-5.3.1 FramebufferUpdate
- CARD8: 0 - message-type
- 1 byte - padding
- CARD16 - number-of-rectangles
-
- CARD16 - x-position
- CARD16 - y-position
- CARD16 - width
- CARD16 - height
- CARD16 - encoding-type:
- 0 - raw
- 1 - copy rectangle
- 2 - RRE
- 4 - CoRRE
- 5 - hextile
-
- raw:
- - width x height pixel values
-
- copy rectangle:
- CARD16 - src-x-position
- CARD16 - src-y-position
-
- RRE:
- CARD32 - N number-of-subrectangles
- Nxd bytes - background-pixel-value (d bits-per-pixel)
-
- ...
-
-5.3.2 SetColourMapEntries (no support)
- CARD8: 1 - message-type
- ...
-
-5.3.3 Bell
- CARD8: 2 - message-type
-
-5.3.4 ServerCutText
- CARD8: 3 - message-type
-
-
-
-
-
diff --git a/systemvm/agent/noVNC/docs/rfbproto-3.3.pdf b/systemvm/agent/noVNC/docs/rfbproto-3.3.pdf
deleted file mode 100644
index 56b8764..0000000
--- a/systemvm/agent/noVNC/docs/rfbproto-3.3.pdf
+++ /dev/null
Binary files differ
diff --git a/systemvm/agent/noVNC/docs/rfbproto-3.7.pdf b/systemvm/agent/noVNC/docs/rfbproto-3.7.pdf
deleted file mode 100644
index 1ef5462..0000000
--- a/systemvm/agent/noVNC/docs/rfbproto-3.7.pdf
+++ /dev/null
Binary files differ
diff --git a/systemvm/agent/noVNC/docs/rfbproto-3.8.pdf b/systemvm/agent/noVNC/docs/rfbproto-3.8.pdf
deleted file mode 100644
index 8f0730f..0000000
--- a/systemvm/agent/noVNC/docs/rfbproto-3.8.pdf
+++ /dev/null
Binary files differ
diff --git a/systemvm/agent/noVNC/karma.conf.js b/systemvm/agent/noVNC/karma.conf.js
deleted file mode 100644
index 5cbd7a5..0000000
--- a/systemvm/agent/noVNC/karma.conf.js
+++ /dev/null
@@ -1,134 +0,0 @@
-// Karma configuration
-
-module.exports = (config) => {
- const customLaunchers = {};
- let browsers = [];
- let useSauce = false;
-
- // use Sauce when running on Travis
- if (process.env.TRAVIS_JOB_NUMBER) {
- useSauce = true;
- }
-
- if (useSauce && process.env.TEST_BROWSER_NAME && process.env.TEST_BROWSER_NAME != 'PhantomJS') {
- const names = process.env.TEST_BROWSER_NAME.split(',');
- const platforms = process.env.TEST_BROWSER_OS.split(',');
- const versions = process.env.TEST_BROWSER_VERSION
- ? process.env.TEST_BROWSER_VERSION.split(',')
- : [null];
-
- for (let i = 0; i < names.length; i++) {
- for (let j = 0; j < platforms.length; j++) {
- for (let k = 0; k < versions.length; k++) {
- let launcher_name = 'sl_' + platforms[j].replace(/[^a-zA-Z0-9]/g, '') + '_' + names[i];
- if (versions[k]) {
- launcher_name += '_' + versions[k];
- }
-
- customLaunchers[launcher_name] = {
- base: 'SauceLabs',
- browserName: names[i],
- platform: platforms[j],
- };
-
- if (versions[i]) {
- customLaunchers[launcher_name].version = versions[k];
- }
- }
- }
- }
-
- browsers = Object.keys(customLaunchers);
- } else {
- useSauce = false;
- //browsers = ['PhantomJS'];
- browsers = [];
- }
-
- const my_conf = {
-
- // base path that will be used to resolve all patterns (eg. files, exclude)
- basePath: '',
-
- // frameworks to use
- // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
- frameworks: ['mocha', 'sinon-chai'],
-
- // list of files / patterns to load in the browser (loaded in order)
- files: [
- { pattern: 'app/localization.js', included: false },
- { pattern: 'app/webutil.js', included: false },
- { pattern: 'core/**/*.js', included: false },
- { pattern: 'vendor/pako/**/*.js', included: false },
- { pattern: 'vendor/browser-es-module-loader/dist/*.js*', included: false },
- { pattern: 'tests/test.*.js', included: false },
- { pattern: 'tests/fake.*.js', included: false },
- { pattern: 'tests/assertions.js', included: false },
- 'vendor/promise.js',
- 'tests/karma-test-main.js',
- ],
-
- client: {
- mocha: {
- // replace Karma debug page with mocha display
- 'reporter': 'html',
- 'ui': 'bdd'
- }
- },
-
- // list of files to exclude
- exclude: [
- ],
-
- customLaunchers: customLaunchers,
-
- // start these browsers
- // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
- browsers: browsers,
-
- // test results reporter to use
- // possible values: 'dots', 'progress'
- // available reporters: https://npmjs.org/browse/keyword/karma-reporter
- reporters: ['mocha'],
-
-
- // web server port
- port: 9876,
-
-
- // enable / disable colors in the output (reporters and logs)
- colors: true,
-
-
- // level of logging
- // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
- logLevel: config.LOG_INFO,
-
-
- // enable / disable watching file and executing tests whenever any file changes
- autoWatch: false,
-
- // Continuous Integration mode
- // if true, Karma captures browsers, runs the tests and exits
- singleRun: true,
-
- // Increase timeout in case connection is slow/we run more browsers than possible
- // (we currently get 3 for free, and we try to run 7, so it can take a while)
- captureTimeout: 240000,
-
- // similarly to above
- browserNoActivityTimeout: 100000,
- };
-
- if (useSauce) {
- my_conf.reporters.push('saucelabs');
- my_conf.captureTimeout = 0; // use SL timeout
- my_conf.sauceLabs = {
- testName: 'noVNC Tests (all)',
- startConnect: false,
- tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
- };
- }
-
- config.set(my_conf);
-};
diff --git a/systemvm/agent/noVNC/package.json b/systemvm/agent/noVNC/package.json
index 2d84a5f..8fc04e5 100644
--- a/systemvm/agent/noVNC/package.json
+++ b/systemvm/agent/noVNC/package.json
@@ -1,6 +1,6 @@
{
"name": "@novnc/novnc",
- "version": "1.1.0",
+ "version": "1.2.0",
"description": "An HTML5 VNC client",
"browser": "lib/rfb",
"directories": {
@@ -19,7 +19,7 @@
"vendor/pako"
],
"scripts": {
- "lint": "eslint app core po tests utils",
+ "lint": "eslint app core po/po2js po/xgettext-html tests utils",
"test": "karma start karma.conf.js",
"prepublish": "node ./utils/use_require.js --as commonjs --clean"
},
@@ -40,36 +40,42 @@
},
"homepage": "https://github.com/novnc/noVNC",
"devDependencies": {
- "babel-core": "^6.22.1",
- "babel-plugin-add-module-exports": "^0.2.1",
+ "@babel/core": "*",
+ "@babel/plugin-syntax-dynamic-import": "*",
+ "@babel/plugin-transform-modules-amd": "*",
+ "@babel/plugin-transform-modules-commonjs": "*",
+ "@babel/plugin-transform-modules-systemjs": "*",
+ "@babel/plugin-transform-modules-umd": "*",
+ "@babel/preset-env": "*",
+ "@babel/cli": "*",
"babel-plugin-import-redirect": "*",
- "babel-plugin-syntax-dynamic-import": "^6.18.0",
- "babel-plugin-transform-es2015-modules-amd": "^6.22.0",
- "babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
- "babel-plugin-transform-es2015-modules-systemjs": "^6.22.0",
- "babel-plugin-transform-es2015-modules-umd": "^6.22.0",
- "babel-preset-es2015": "^6.24.1",
- "babelify": "^7.3.0",
- "browserify": "^13.1.0",
- "chai": "^3.5.0",
- "commander": "^2.9.0",
- "es-module-loader": "^2.1.0",
- "eslint": "^4.16.0",
- "fs-extra": "^1.0.0",
+ "browserify": "*",
+ "babelify": "*",
+ "core-js": "*",
+ "chai": "*",
+ "commander": "*",
+ "es-module-loader": "*",
+ "eslint": "*",
+ "fs-extra": "*",
"jsdom": "*",
- "karma": "^1.3.0",
- "karma-mocha": "^1.3.0",
- "karma-mocha-reporter": "^2.2.0",
- "karma-sauce-launcher": "^1.0.0",
- "karma-sinon-chai": "^2.0.0",
- "mocha": "^3.1.2",
+ "karma": "*",
+ "karma-mocha": "*",
+ "karma-chrome-launcher": "*",
+ "@chiragrupani/karma-chromium-edge-launcher": "*",
+ "karma-firefox-launcher": "*",
+ "karma-ie-launcher": "*",
+ "karma-mocha-reporter": "*",
+ "karma-safari-launcher": "*",
+ "karma-script-launcher": "*",
+ "karma-sinon-chai": "*",
+ "mocha": "*",
"node-getopt": "*",
"po2json": "*",
- "requirejs": "^2.3.2",
- "rollup": "^0.41.4",
- "rollup-plugin-node-resolve": "^2.0.0",
- "sinon": "^4.0.0",
- "sinon-chai": "^2.8.0"
+ "requirejs": "*",
+ "rollup": "*",
+ "rollup-plugin-node-resolve": "*",
+ "sinon": "*",
+ "sinon-chai": "*"
},
"dependencies": {},
"keywords": [
diff --git a/systemvm/agent/noVNC/po/Makefile b/systemvm/agent/noVNC/po/Makefile
deleted file mode 100644
index 6dbd830..0000000
--- a/systemvm/agent/noVNC/po/Makefile
+++ /dev/null
@@ -1,35 +0,0 @@
-all:
-.PHONY: update-po update-js update-pot
-
-LINGUAS := cs de el es ko nl pl ru sv tr zh_CN zh_TW
-
-VERSION := $(shell grep '"version"' ../package.json | cut -d '"' -f 4)
-
-POFILES := $(addsuffix .po,$(LINGUAS))
-JSONFILES := $(addprefix ../app/locale/,$(addsuffix .json,$(LINGUAS)))
-
-update-po: $(POFILES)
-update-js: $(JSONFILES)
-
-%.po: noVNC.pot
- msgmerge --update --lang=$* $@ $<
-../app/locale/%.json: %.po
- ./po2js $< $@
-
-update-pot:
- xgettext --output=noVNC.js.pot \
- --copyright-holder="The noVNC Authors" \
- --package-name="noVNC" \
- --package-version="$(VERSION)" \
- --msgid-bugs-address="novnc@googlegroups.com" \
- --add-comments=TRANSLATORS: \
- --from-code=UTF-8 \
- --sort-by-file \
- ../app/*.js \
- ../core/*.js \
- ../core/input/*.js
- ./xgettext-html --output=noVNC.html.pot \
- ../vnc.html
- msgcat --output-file=noVNC.pot \
- --sort-by-file noVNC.js.pot noVNC.html.pot
- rm -f noVNC.js.pot noVNC.html.pot
diff --git a/systemvm/agent/noVNC/po/cs.po b/systemvm/agent/noVNC/po/cs.po
deleted file mode 100644
index 2b1efd8..0000000
--- a/systemvm/agent/noVNC/po/cs.po
+++ /dev/null
@@ -1,294 +0,0 @@
-# Czech translations for noVNC package.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Petr <petr@kle.cz>, 2018.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.0.0-testing.2\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2018-10-19 12:00+0200\n"
-"PO-Revision-Date: 2018-10-19 12:00+0200\n"
-"Last-Translator: Petr <petr@kle.cz>\n"
-"Language-Team: Czech\n"
-"Language: cs\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-
-#: ../app/ui.js:389
-msgid "Connecting..."
-msgstr "Připojení..."
-
-#: ../app/ui.js:396
-msgid "Disconnecting..."
-msgstr "Odpojení..."
-
-#: ../app/ui.js:402
-msgid "Reconnecting..."
-msgstr "Obnova připojení..."
-
-#: ../app/ui.js:407
-msgid "Internal error"
-msgstr "Vnitřní chyba"
-
-#: ../app/ui.js:997
-msgid "Must set host"
-msgstr "Hostitel musí být nastavení"
-
-#: ../app/ui.js:1079
-msgid "Connected (encrypted) to "
-msgstr "Připojení (šifrované) k "
-
-#: ../app/ui.js:1081
-msgid "Connected (unencrypted) to "
-msgstr "Připojení (nešifrované) k "
-
-#: ../app/ui.js:1104
-msgid "Something went wrong, connection is closed"
-msgstr "Něco se pokazilo, odpojeno"
-
-#: ../app/ui.js:1107
-msgid "Failed to connect to server"
-msgstr "Chyba připojení k serveru"
-
-#: ../app/ui.js:1117
-msgid "Disconnected"
-msgstr "Odpojeno"
-
-#: ../app/ui.js:1130
-msgid "New connection has been rejected with reason: "
-msgstr "Nové připojení bylo odmítnuto s odůvodněním: "
-
-#: ../app/ui.js:1133
-msgid "New connection has been rejected"
-msgstr "Nové připojení bylo odmítnuto"
-
-#: ../app/ui.js:1153
-msgid "Password is required"
-msgstr "Je vyžadováno heslo"
-
-#: ../vnc.html:84
-msgid "noVNC encountered an error:"
-msgstr "noVNC narazilo na chybu:"
-
-#: ../vnc.html:94
-msgid "Hide/Show the control bar"
-msgstr "Skrýt/zobrazit ovládací panel"
-
-#: ../vnc.html:101
-msgid "Move/Drag Viewport"
-msgstr "Přesunout/přetáhnout výřez"
-
-#: ../vnc.html:101
-msgid "viewport drag"
-msgstr "přesun výřezu"
-
-#: ../vnc.html:107 ../vnc.html:110 ../vnc.html:113 ../vnc.html:116
-msgid "Active Mouse Button"
-msgstr "Aktivní tlačítka myši"
-
-#: ../vnc.html:107
-msgid "No mousebutton"
-msgstr "Žádné"
-
-#: ../vnc.html:110
-msgid "Left mousebutton"
-msgstr "Levé tlačítko myši"
-
-#: ../vnc.html:113
-msgid "Middle mousebutton"
-msgstr "Prostřední tlačítko myši"
-
-#: ../vnc.html:116
-msgid "Right mousebutton"
-msgstr "Pravé tlačítko myši"
-
-#: ../vnc.html:119
-msgid "Keyboard"
-msgstr "Klávesnice"
-
-#: ../vnc.html:119
-msgid "Show Keyboard"
-msgstr "Zobrazit klávesnici"
-
-#: ../vnc.html:126
-msgid "Extra keys"
-msgstr "Extra klávesy"
-
-#: ../vnc.html:126
-msgid "Show Extra Keys"
-msgstr "Zobrazit extra klávesy"
-
-#: ../vnc.html:131
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:131
-msgid "Toggle Ctrl"
-msgstr "Přepnout Ctrl"
-
-#: ../vnc.html:134
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:134
-msgid "Toggle Alt"
-msgstr "Přepnout Alt"
-
-#: ../vnc.html:137
-msgid "Send Tab"
-msgstr "Odeslat tabulátor"
-
-#: ../vnc.html:137
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:140
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:140
-msgid "Send Escape"
-msgstr "Odeslat Esc"
-
-#: ../vnc.html:143
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:143
-msgid "Send Ctrl-Alt-Del"
-msgstr "Poslat Ctrl-Alt-Del"
-
-#: ../vnc.html:151
-msgid "Shutdown/Reboot"
-msgstr "Vypnutí/Restart"
-
-#: ../vnc.html:151
-msgid "Shutdown/Reboot..."
-msgstr "Vypnutí/Restart..."
-
-#: ../vnc.html:157
-msgid "Power"
-msgstr "Napájení"
-
-#: ../vnc.html:159
-msgid "Shutdown"
-msgstr "Vypnout"
-
-#: ../vnc.html:160
-msgid "Reboot"
-msgstr "Restart"
-
-#: ../vnc.html:161
-msgid "Reset"
-msgstr "Reset"
-
-#: ../vnc.html:166 ../vnc.html:172
-msgid "Clipboard"
-msgstr "Schránka"
-
-#: ../vnc.html:176
-msgid "Clear"
-msgstr "Vymazat"
-
-#: ../vnc.html:182
-msgid "Fullscreen"
-msgstr "Celá obrazovka"
-
-#: ../vnc.html:187 ../vnc.html:194
-msgid "Settings"
-msgstr "Nastavení"
-
-#: ../vnc.html:197
-msgid "Shared Mode"
-msgstr "Sdílený režim"
-
-#: ../vnc.html:200
-msgid "View Only"
-msgstr "Pouze prohlížení"
-
-#: ../vnc.html:204
-msgid "Clip to Window"
-msgstr "Přizpůsobit oknu"
-
-#: ../vnc.html:207
-msgid "Scaling Mode:"
-msgstr "Přizpůsobení velikosti"
-
-#: ../vnc.html:209
-msgid "None"
-msgstr "Žádné"
-
-#: ../vnc.html:210
-msgid "Local Scaling"
-msgstr "Místní"
-
-#: ../vnc.html:211
-msgid "Remote Resizing"
-msgstr "Vzdálené"
-
-#: ../vnc.html:216
-msgid "Advanced"
-msgstr "Pokročilé"
-
-#: ../vnc.html:219
-msgid "Repeater ID:"
-msgstr "ID opakovače"
-
-#: ../vnc.html:223
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:226
-msgid "Encrypt"
-msgstr "Šifrování:"
-
-#: ../vnc.html:229
-msgid "Host:"
-msgstr "Hostitel:"
-
-#: ../vnc.html:233
-msgid "Port:"
-msgstr "Port:"
-
-#: ../vnc.html:237
-msgid "Path:"
-msgstr "Cesta"
-
-#: ../vnc.html:244
-msgid "Automatic Reconnect"
-msgstr "Automatická obnova připojení"
-
-#: ../vnc.html:247
-msgid "Reconnect Delay (ms):"
-msgstr "Zpoždění připojení (ms)"
-
-#: ../vnc.html:252
-msgid "Show Dot when No Cursor"
-msgstr "Tečka místo chybějícího kurzoru myši"
-
-#: ../vnc.html:257
-msgid "Logging:"
-msgstr "Logování:"
-
-#: ../vnc.html:269
-msgid "Disconnect"
-msgstr "Odpojit"
-
-#: ../vnc.html:288
-msgid "Connect"
-msgstr "Připojit"
-
-#: ../vnc.html:298
-msgid "Password:"
-msgstr "Heslo"
-
-#: ../vnc.html:302
-msgid "Send Password"
-msgstr "Odeslat heslo"
-
-#: ../vnc.html:312
-msgid "Cancel"
-msgstr "Zrušit"
diff --git a/systemvm/agent/noVNC/po/de.po b/systemvm/agent/noVNC/po/de.po
deleted file mode 100644
index 0c3fa0d..0000000
--- a/systemvm/agent/noVNC/po/de.po
+++ /dev/null
@@ -1,303 +0,0 @@
-# German translations for noVNC package
-# German translation for noVNC.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Loek Janssen <loekjanssen@gmail.com>, 2016.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 0.6.1\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2017-11-24 07:16+0000\n"
-"PO-Revision-Date: 2017-11-24 08:20+0100\n"
-"Last-Translator: Dominik Csapak <d.csapak@proxmox.com>\n"
-"Language-Team: none\n"
-"Language: de\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.8.11\n"
-
-#: ../app/ui.js:404
-msgid "Connecting..."
-msgstr "Verbinden..."
-
-#: ../app/ui.js:411
-msgid "Disconnecting..."
-msgstr "Verbindung trennen..."
-
-#: ../app/ui.js:417
-msgid "Reconnecting..."
-msgstr "Verbindung wiederherstellen..."
-
-#: ../app/ui.js:422
-msgid "Internal error"
-msgstr "Interner Fehler"
-
-#: ../app/ui.js:1019
-msgid "Must set host"
-msgstr "Richten Sie den Server ein"
-
-#: ../app/ui.js:1099
-msgid "Connected (encrypted) to "
-msgstr "Verbunden mit (verschlüsselt) "
-
-#: ../app/ui.js:1101
-msgid "Connected (unencrypted) to "
-msgstr "Verbunden mit (unverschlüsselt) "
-
-#: ../app/ui.js:1119
-msgid "Something went wrong, connection is closed"
-msgstr "Etwas lief schief, Verbindung wurde getrennt"
-
-#: ../app/ui.js:1129
-msgid "Disconnected"
-msgstr "Verbindung zum Server getrennt"
-
-#: ../app/ui.js:1142
-msgid "New connection has been rejected with reason: "
-msgstr "Verbindung wurde aus folgendem Grund abgelehnt: "
-
-#: ../app/ui.js:1145
-msgid "New connection has been rejected"
-msgstr "Verbindung wurde abgelehnt"
-
-#: ../app/ui.js:1166
-msgid "Password is required"
-msgstr "Passwort ist erforderlich"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "Ein Fehler ist aufgetreten:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "Kontrollleiste verstecken/anzeigen"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "Ansichtsfenster verschieben/ziehen"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "Ansichtsfenster ziehen"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "Aktive Maustaste"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "Keine Maustaste"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "Linke Maustaste"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "Mittlere Maustaste"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "Rechte Maustaste"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "Tastatur"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "Tastatur anzeigen"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "Zusatztasten"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "Zusatztasten anzeigen"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Strg"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "Strg umschalten"
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "Alt umschalten"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "Tab senden"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "Escape senden"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Strg+Alt+Entf"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "Strg+Alt+Entf senden"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "Herunterfahren/Neustarten"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "Herunterfahren/Neustarten..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "Energie"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "Herunterfahren"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "Neustarten"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "Zurücksetzen"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "Zwischenablage"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "Löschen"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "Vollbild"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "Einstellungen"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "Geteilter Modus"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "Nur betrachten"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "Auf Fenster begrenzen"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "Skalierungsmodus:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "Keiner"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "Lokales skalieren"
-
-#: ../vnc.html:216
-msgid "Remote Resizing"
-msgstr "Serverseitiges skalieren"
-
-#: ../vnc.html:221
-msgid "Advanced"
-msgstr "Erweitert"
-
-#: ../vnc.html:224
-msgid "Repeater ID:"
-msgstr "Repeater ID:"
-
-#: ../vnc.html:228
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:231
-msgid "Encrypt"
-msgstr "Verschlüsselt"
-
-#: ../vnc.html:234
-msgid "Host:"
-msgstr "Server:"
-
-#: ../vnc.html:238
-msgid "Port:"
-msgstr "Port:"
-
-#: ../vnc.html:242
-msgid "Path:"
-msgstr "Pfad:"
-
-#: ../vnc.html:249
-msgid "Automatic Reconnect"
-msgstr "Automatisch wiederverbinden"
-
-#: ../vnc.html:252
-msgid "Reconnect Delay (ms):"
-msgstr "Wiederverbindungsverzögerung (ms):"
-
-#: ../vnc.html:258
-msgid "Logging:"
-msgstr "Protokollierung:"
-
-#: ../vnc.html:270
-msgid "Disconnect"
-msgstr "Verbindung trennen"
-
-#: ../vnc.html:289
-msgid "Connect"
-msgstr "Verbinden"
-
-#: ../vnc.html:299
-msgid "Password:"
-msgstr "Passwort:"
-
-#: ../vnc.html:313
-msgid "Cancel"
-msgstr "Abbrechen"
-
-#: ../vnc.html:329
-msgid "Canvas not supported."
-msgstr "Canvas nicht unterstützt."
-
-#~ msgid "Disconnect timeout"
-#~ msgstr "Zeitüberschreitung beim Trennen"
-
-#~ msgid "Local Downscaling"
-#~ msgstr "Lokales herunterskalieren"
-
-#~ msgid "Local Cursor"
-#~ msgstr "Lokaler Mauszeiger"
-
-#~ msgid "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen"
-#~ msgstr "'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht unterstützt"
-
-#~ msgid "True Color"
-#~ msgstr "True Color"
diff --git a/systemvm/agent/noVNC/po/el.po b/systemvm/agent/noVNC/po/el.po
deleted file mode 100644
index 5213ae5..0000000
--- a/systemvm/agent/noVNC/po/el.po
+++ /dev/null
@@ -1,323 +0,0 @@
-# Greek translations for noVNC package.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Giannis Kosmas <kosmasgiannis@gmail.com>, 2016.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 0.6.1\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2017-11-17 21:40+0200\n"
-"PO-Revision-Date: 2017-10-11 16:16+0200\n"
-"Last-Translator: Giannis Kosmas <kosmasgiannis@gmail.com>\n"
-"Language-Team: none\n"
-"Language: el\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: ../app/ui.js:404
-msgid "Connecting..."
-msgstr "Συνδέεται..."
-
-#: ../app/ui.js:411
-msgid "Disconnecting..."
-msgstr "Aποσυνδέεται..."
-
-#: ../app/ui.js:417
-msgid "Reconnecting..."
-msgstr "Επανασυνδέεται..."
-
-#: ../app/ui.js:422
-msgid "Internal error"
-msgstr "Εσωτερικό σφάλμα"
-
-#: ../app/ui.js:1019
-msgid "Must set host"
-msgstr "Πρέπει να οριστεί ο διακομιστής"
-
-#: ../app/ui.js:1099
-msgid "Connected (encrypted) to "
-msgstr "Συνδέθηκε (κρυπτογραφημένα) με το "
-
-#: ../app/ui.js:1101
-msgid "Connected (unencrypted) to "
-msgstr "Συνδέθηκε (μη κρυπτογραφημένα) με το "
-
-#: ../app/ui.js:1119
-msgid "Something went wrong, connection is closed"
-msgstr "Κάτι πήγε στραβά, η σύνδεση διακόπηκε"
-
-#: ../app/ui.js:1129
-msgid "Disconnected"
-msgstr "Αποσυνδέθηκε"
-
-#: ../app/ui.js:1142
-msgid "New connection has been rejected with reason: "
-msgstr "Η νέα σύνδεση απορρίφθηκε διότι: "
-
-#: ../app/ui.js:1145
-msgid "New connection has been rejected"
-msgstr "Η νέα σύνδεση απορρίφθηκε "
-
-#: ../app/ui.js:1166
-msgid "Password is required"
-msgstr "Απαιτείται ο κωδικός πρόσβασης"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "το noVNC αντιμετώπισε ένα σφάλμα:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "Απόκρυψη/Εμφάνιση γραμμής ελέγχου"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "Μετακίνηση/Σύρσιμο Θεατού πεδίου"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "σύρσιμο θεατού πεδίου"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "Ενεργό Πλήκτρο Ποντικιού"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "Χωρίς Πλήκτρο Ποντικιού"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "Αριστερό Πλήκτρο Ποντικιού"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "Μεσαίο Πλήκτρο Ποντικιού"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "Δεξί Πλήκτρο Ποντικιού"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "Πληκτρολόγιο"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "Εμφάνιση Πληκτρολογίου"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "Επιπλέον πλήκτρα"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "Εμφάνιση Επιπλέον Πλήκτρων"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "Εναλλαγή Ctrl"
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "Εναλλαγή Alt"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "Αποστολή Tab"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "Αποστολή Escape"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "Αποστολή Ctrl-Alt-Del"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "Κλείσιμο/Επανεκκίνηση"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "Κλείσιμο/Επανεκκίνηση..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "Απενεργοποίηση"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "Κλείσιμο"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "Επανεκκίνηση"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "Επαναφορά"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "Πρόχειρο"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "Καθάρισμα"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "Πλήρης Οθόνη"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "Ρυθμίσεις"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "Κοινόχρηστη Λειτουργία"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "Μόνο Θέαση"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "Αποκοπή στο όριο του Παράθυρου"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "Λειτουργία Κλιμάκωσης:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "Καμία"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "Τοπική Κλιμάκωση"
-
-#: ../vnc.html:216
-msgid "Remote Resizing"
-msgstr "Απομακρυσμένη Αλλαγή μεγέθους"
-
-#: ../vnc.html:221
-msgid "Advanced"
-msgstr "Για προχωρημένους"
-
-#: ../vnc.html:224
-msgid "Repeater ID:"
-msgstr "Repeater ID:"
-
-#: ../vnc.html:228
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:231
-msgid "Encrypt"
-msgstr "Κρυπτογράφηση"
-
-#: ../vnc.html:234
-msgid "Host:"
-msgstr "Όνομα διακομιστή:"
-
-#: ../vnc.html:238
-msgid "Port:"
-msgstr "Πόρτα διακομιστή:"
-
-#: ../vnc.html:242
-msgid "Path:"
-msgstr "Διαδρομή:"
-
-#: ../vnc.html:249
-msgid "Automatic Reconnect"
-msgstr "Αυτόματη επανασύνδεση"
-
-#: ../vnc.html:252
-msgid "Reconnect Delay (ms):"
-msgstr "Καθυστέρηση επανασύνδεσης (ms):"
-
-#: ../vnc.html:258
-msgid "Logging:"
-msgstr "Καταγραφή:"
-
-#: ../vnc.html:270
-msgid "Disconnect"
-msgstr "Αποσύνδεση"
-
-#: ../vnc.html:289
-msgid "Connect"
-msgstr "Σύνδεση"
-
-#: ../vnc.html:299
-msgid "Password:"
-msgstr "Κωδικός Πρόσβασης:"
-
-#: ../vnc.html:313
-msgid "Cancel"
-msgstr "Ακύρωση"
-
-#: ../vnc.html:329
-msgid "Canvas not supported."
-msgstr "Δεν υποστηρίζεται το στοιχείο Canvas"
-
-#~ msgid "Disconnect timeout"
-#~ msgstr "Παρέλευση χρονικού ορίου αποσύνδεσης"
-
-#~ msgid "Local Downscaling"
-#~ msgstr "Τοπική Συρρίκνωση"
-
-#~ msgid "Local Cursor"
-#~ msgstr "Τοπικός Δρομέας"
-
-#~ msgid ""
-#~ "Forcing clipping mode since scrollbars aren't supported by IE in "
-#~ "fullscreen"
-#~ msgstr ""
-#~ "Εφαρμογή λειτουργίας αποκοπής αφού δεν υποστηρίζονται οι λωρίδες κύλισης "
-#~ "σε πλήρη οθόνη στον IE"
-
-#~ msgid "True Color"
-#~ msgstr "Πραγματικά Χρώματα"
-
-#~ msgid "Style:"
-#~ msgstr "Στυλ:"
-
-#~ msgid "default"
-#~ msgstr "προεπιλεγμένο"
-
-#~ msgid "Apply"
-#~ msgstr "Εφαρμογή"
-
-#~ msgid "Connection"
-#~ msgstr "Σύνδεση"
-
-#~ msgid "Token:"
-#~ msgstr "Διακριτικό:"
-
-#~ msgid "Send Password"
-#~ msgstr "Αποστολή Κωδικού Πρόσβασης"
diff --git a/systemvm/agent/noVNC/po/es.po b/systemvm/agent/noVNC/po/es.po
deleted file mode 100644
index e15655f..0000000
--- a/systemvm/agent/noVNC/po/es.po
+++ /dev/null
@@ -1,283 +0,0 @@
-# Spanish translations for noVNC package
-# Traducciones al español para el paquete noVNC.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Juanjo Diaz <juanjo.diazmo@gmail.com>, 2018.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.0.0-testing.2\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2017-10-06 10:07+0200\n"
-"PO-Revision-Date: 2018-01-30 19:14-0800\n"
-"Last-Translator: Juanjo Diaz <juanjo.diazmo@gmail.com>\n"
-"Language-Team: Spanish\n"
-"Language: es\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: ../app/ui.js:430
-msgid "Connecting..."
-msgstr "Conectando..."
-
-#: ../app/ui.js:438
-msgid "Connected (encrypted) to "
-msgstr "Conectado (con encriptación) a"
-
-#: ../app/ui.js:440
-msgid "Connected (unencrypted) to "
-msgstr "Conectado (sin encriptación) a"
-
-#: ../app/ui.js:446
-msgid "Disconnecting..."
-msgstr "Desconectando..."
-
-#: ../app/ui.js:450
-msgid "Disconnected"
-msgstr "Desconectado"
-
-#: ../app/ui.js:1052 ../core/rfb.js:248
-msgid "Must set host"
-msgstr "Debes configurar el host"
-
-#: ../app/ui.js:1101
-msgid "Reconnecting..."
-msgstr "Reconectando..."
-
-#: ../app/ui.js:1140
-msgid "Password is required"
-msgstr "Contraseña es obligatoria"
-
-#: ../core/rfb.js:548
-msgid "Disconnect timeout"
-msgstr "Tiempo de desconexión agotado"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "noVNC ha encontrado un error:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "Ocultar/Mostrar la barra de control"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "Mover/Arrastrar la ventana"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "Arrastrar la ventana"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "Botón activo del ratón"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "Ningún botón del ratón"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "Botón izquierdo del ratón"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "Botón central del ratón"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "Botón derecho del ratón"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "Teclado"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "Mostrar teclado"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "Teclas adicionales"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "Mostrar Teclas Adicionales"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "Pulsar/Soltar Ctrl"
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "Pulsar/Soltar Alt"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "Enviar Tabulación"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Tabulación"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "Enviar Escape"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "Enviar Ctrl+Alt+Del"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "Apagar/Reiniciar"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "Apagar/Reiniciar..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "Encender"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "Apagar"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "Reiniciar"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "Restablecer"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "Portapapeles"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "Vaciar"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "Pantalla Completa"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "Configuraciones"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "Modo Compartido"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "Solo visualización"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "Recortar al tamaño de la ventana"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "Modo de escalado:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "Ninguno"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "Escalado Local"
-
-#: ../vnc.html:216
-msgid "Local Downscaling"
-msgstr "Reducción de escala local"
-
-#: ../vnc.html:217
-msgid "Remote Resizing"
-msgstr "Cambio de tamaño remoto"
-
-#: ../vnc.html:222
-msgid "Advanced"
-msgstr "Avanzado"
-
-#: ../vnc.html:225
-msgid "Local Cursor"
-msgstr "Cursor Local"
-
-#: ../vnc.html:229
-msgid "Repeater ID:"
-msgstr "ID del Repetidor"
-
-#: ../vnc.html:233
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:236
-msgid "Encrypt"
-msgstr ""
-
-#: ../vnc.html:239
-msgid "Host:"
-msgstr "Host"
-
-#: ../vnc.html:243
-msgid "Port:"
-msgstr "Puesto"
-
-#: ../vnc.html:247
-msgid "Path:"
-msgstr "Ruta"
-
-#: ../vnc.html:254
-msgid "Automatic Reconnect"
-msgstr "Reconexión automática"
-
-#: ../vnc.html:257
-msgid "Reconnect Delay (ms):"
-msgstr "Retraso en la reconexión (ms)"
-
-#: ../vnc.html:263
-msgid "Logging:"
-msgstr "Logging"
-
-#: ../vnc.html:275
-msgid "Disconnect"
-msgstr "Desconectar"
-
-#: ../vnc.html:294
-msgid "Connect"
-msgstr "Conectar"
-
-#: ../vnc.html:304
-msgid "Password:"
-msgstr "Contraseña"
-
-#: ../vnc.html:318
-msgid "Cancel"
-msgstr "Cancelar"
-
-#: ../vnc.html:334
-msgid "Canvas not supported."
-msgstr "Canvas no está soportado"
diff --git a/systemvm/agent/noVNC/po/ko.po b/systemvm/agent/noVNC/po/ko.po
deleted file mode 100644
index 87ae106..0000000
--- a/systemvm/agent/noVNC/po/ko.po
+++ /dev/null
@@ -1,290 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Baw Appie <pp121324@gmail.com>, 2018.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.0.0-testing.2\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2018-01-31 16:29+0100\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: Baw Appie <pp121324@gmail.com>\n"
-"Language-Team: Korean\n"
-"Language: ko\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: ../app/ui.js:395
-msgid "Connecting..."
-msgstr "연결중..."
-
-#: ../app/ui.js:402
-msgid "Disconnecting..."
-msgstr "연결 해제중..."
-
-#: ../app/ui.js:408
-msgid "Reconnecting..."
-msgstr "재연결중..."
-
-#: ../app/ui.js:413
-msgid "Internal error"
-msgstr "내부 오류"
-
-#: ../app/ui.js:1002
-msgid "Must set host"
-msgstr "호스트는 설정되어야 합니다."
-
-#: ../app/ui.js:1083
-msgid "Connected (encrypted) to "
-msgstr "다음과 (암호화되어) 연결되었습니다:"
-
-#: ../app/ui.js:1085
-msgid "Connected (unencrypted) to "
-msgstr "다음과 (암호화 없이) 연결되었습니다:"
-
-#: ../app/ui.js:1108
-msgid "Something went wrong, connection is closed"
-msgstr "무언가 잘못되었습니다, 연결이 닫혔습니다."
-
-#: ../app/ui.js:1111
-msgid "Failed to connect to server"
-msgstr "서버에 연결하지 못했습니다."
-
-#: ../app/ui.js:1121
-msgid "Disconnected"
-msgstr "연결이 해제되었습니다."
-
-#: ../app/ui.js:1134
-msgid "New connection has been rejected with reason: "
-msgstr "새 연결이 다음 이유로 거부되었습니다:"
-
-#: ../app/ui.js:1137
-msgid "New connection has been rejected"
-msgstr "새 연결이 거부되었습니다."
-
-#: ../app/ui.js:1158
-msgid "Password is required"
-msgstr "비밀번호가 필요합니다."
-
-#: ../vnc.html:91
-msgid "noVNC encountered an error:"
-msgstr "noVNC에 오류가 발생했습니다:"
-
-#: ../vnc.html:101
-msgid "Hide/Show the control bar"
-msgstr "컨트롤 바 숨기기/보이기"
-
-#: ../vnc.html:108
-msgid "Move/Drag Viewport"
-msgstr "움직이기/드래그 뷰포트"
-
-#: ../vnc.html:108
-msgid "viewport drag"
-msgstr "뷰포트 드래그"
-
-#: ../vnc.html:114 ../vnc.html:117 ../vnc.html:120 ../vnc.html:123
-msgid "Active Mouse Button"
-msgstr "마우스 버튼 활성화"
-
-#: ../vnc.html:114
-msgid "No mousebutton"
-msgstr "마우스 버튼 없음"
-
-#: ../vnc.html:117
-msgid "Left mousebutton"
-msgstr "왼쪽 마우스 버튼"
-
-#: ../vnc.html:120
-msgid "Middle mousebutton"
-msgstr "중간 마우스 버튼"
-
-#: ../vnc.html:123
-msgid "Right mousebutton"
-msgstr "오른쪽 마우스 버튼"
-
-#: ../vnc.html:126
-msgid "Keyboard"
-msgstr "키보드"
-
-#: ../vnc.html:126
-msgid "Show Keyboard"
-msgstr "키보드 보이기"
-
-#: ../vnc.html:133
-msgid "Extra keys"
-msgstr "기타 키들"
-
-#: ../vnc.html:133
-msgid "Show Extra Keys"
-msgstr "기타 키들 보이기"
-
-#: ../vnc.html:138
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:138
-msgid "Toggle Ctrl"
-msgstr "Ctrl 켜기/끄기"
-
-#: ../vnc.html:141
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:141
-msgid "Toggle Alt"
-msgstr "Alt 켜기/끄기"
-
-#: ../vnc.html:144
-msgid "Send Tab"
-msgstr "Tab 보내기"
-
-#: ../vnc.html:144
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:147
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:147
-msgid "Send Escape"
-msgstr "Esc 보내기"
-
-#: ../vnc.html:150
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:150
-msgid "Send Ctrl-Alt-Del"
-msgstr "Ctrl+Alt+Del 보내기"
-
-#: ../vnc.html:158
-msgid "Shutdown/Reboot"
-msgstr "셧다운/리붓"
-
-#: ../vnc.html:158
-msgid "Shutdown/Reboot..."
-msgstr "셧다운/리붓..."
-
-#: ../vnc.html:164
-msgid "Power"
-msgstr "전원"
-
-#: ../vnc.html:166
-msgid "Shutdown"
-msgstr "셧다운"
-
-#: ../vnc.html:167
-msgid "Reboot"
-msgstr "리붓"
-
-#: ../vnc.html:168
-msgid "Reset"
-msgstr "리셋"
-
-#: ../vnc.html:173 ../vnc.html:179
-msgid "Clipboard"
-msgstr "클립보드"
-
-#: ../vnc.html:183
-msgid "Clear"
-msgstr "지우기"
-
-#: ../vnc.html:189
-msgid "Fullscreen"
-msgstr "전체화면"
-
-#: ../vnc.html:194 ../vnc.html:201
-msgid "Settings"
-msgstr "설정"
-
-#: ../vnc.html:204
-msgid "Shared Mode"
-msgstr "공유 모드"
-
-#: ../vnc.html:207
-msgid "View Only"
-msgstr "보기 전용"
-
-#: ../vnc.html:211
-msgid "Clip to Window"
-msgstr "창에 클립"
-
-#: ../vnc.html:214
-msgid "Scaling Mode:"
-msgstr "스케일링 모드:"
-
-#: ../vnc.html:216
-msgid "None"
-msgstr "없음"
-
-#: ../vnc.html:217
-msgid "Local Scaling"
-msgstr "로컬 스케일링"
-
-#: ../vnc.html:218
-msgid "Remote Resizing"
-msgstr "원격 크기 조절"
-
-#: ../vnc.html:223
-msgid "Advanced"
-msgstr "고급"
-
-#: ../vnc.html:226
-msgid "Repeater ID:"
-msgstr "중계 ID"
-
-#: ../vnc.html:230
-msgid "WebSocket"
-msgstr "웹소켓"
-
-#: ../vnc.html:233
-msgid "Encrypt"
-msgstr "암호화"
-
-#: ../vnc.html:236
-msgid "Host:"
-msgstr "호스트:"
-
-#: ../vnc.html:240
-msgid "Port:"
-msgstr "포트:"
-
-#: ../vnc.html:244
-msgid "Path:"
-msgstr "위치:"
-
-#: ../vnc.html:251
-msgid "Automatic Reconnect"
-msgstr "자동 재연결"
-
-#: ../vnc.html:254
-msgid "Reconnect Delay (ms):"
-msgstr "재연결 지연 시간 (ms)"
-
-#: ../vnc.html:260
-msgid "Logging:"
-msgstr "로깅"
-
-#: ../vnc.html:272
-msgid "Disconnect"
-msgstr "연결 해제"
-
-#: ../vnc.html:291
-msgid "Connect"
-msgstr "연결"
-
-#: ../vnc.html:301
-msgid "Password:"
-msgstr "비밀번호:"
-
-#: ../vnc.html:305
-msgid "Send Password"
-msgstr "비밀번호 전송"
-
-#: ../vnc.html:315
-msgid "Cancel"
-msgstr "취소"
diff --git a/systemvm/agent/noVNC/po/nl.po b/systemvm/agent/noVNC/po/nl.po
deleted file mode 100644
index 343204a..0000000
--- a/systemvm/agent/noVNC/po/nl.po
+++ /dev/null
@@ -1,322 +0,0 @@
-# Dutch translations for noVNC package
-# Nederlandse vertalingen voor het pakket noVNC.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Loek Janssen <loekjanssen@gmail.com>, 2016.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.1.0\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2019-04-09 11:06+0100\n"
-"PO-Revision-Date: 2019-04-09 17:17+0100\n"
-"Last-Translator: Arend Lapere <arend.lapere@gmail.com>\n"
-"Language-Team: none\n"
-"Language: nl\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: ../app/ui.js:383
-msgid "Connecting..."
-msgstr "Verbinden..."
-
-#: ../app/ui.js:390
-msgid "Disconnecting..."
-msgstr "Verbinding verbreken..."
-
-#: ../app/ui.js:396
-msgid "Reconnecting..."
-msgstr "Opnieuw verbinding maken..."
-
-#: ../app/ui.js:401
-msgid "Internal error"
-msgstr "Interne fout"
-
-#: ../app/ui.js:991
-msgid "Must set host"
-msgstr "Host moeten worden ingesteld"
-
-#: ../app/ui.js:1073
-msgid "Connected (encrypted) to "
-msgstr "Verbonden (versleuteld) met "
-
-#: ../app/ui.js:1075
-msgid "Connected (unencrypted) to "
-msgstr "Verbonden (onversleuteld) met "
-
-#: ../app/ui.js:1098
-msgid "Something went wrong, connection is closed"
-msgstr "Er iets fout gelopen, verbinding werd verbroken"
-
-#: ../app/ui.js:1101
-msgid "Failed to connect to server"
-msgstr "Verbinding maken met server is mislukt"
-
-#: ../app/ui.js:1111
-msgid "Disconnected"
-msgstr "Verbinding verbroken"
-
-#: ../app/ui.js:1124
-msgid "New connection has been rejected with reason: "
-msgstr "Nieuwe verbinding is geweigerd omwille van de volgende reden: "
-
-#: ../app/ui.js:1127
-msgid "New connection has been rejected"
-msgstr "Nieuwe verbinding is geweigerd"
-
-#: ../app/ui.js:1147
-msgid "Password is required"
-msgstr "Wachtwoord is vereist"
-
-#: ../vnc.html:80
-msgid "noVNC encountered an error:"
-msgstr "noVNC heeft een fout bemerkt:"
-
-#: ../vnc.html:90
-msgid "Hide/Show the control bar"
-msgstr "Verberg/Toon de bedieningsbalk"
-
-#: ../vnc.html:97
-msgid "Move/Drag Viewport"
-msgstr "Verplaats/Versleep Kijkvenster"
-
-#: ../vnc.html:97
-msgid "viewport drag"
-msgstr "kijkvenster slepen"
-
-#: ../vnc.html:103 ../vnc.html:106 ../vnc.html:109 ../vnc.html:112
-msgid "Active Mouse Button"
-msgstr "Actieve Muisknop"
-
-#: ../vnc.html:103
-msgid "No mousebutton"
-msgstr "Geen muisknop"
-
-#: ../vnc.html:106
-msgid "Left mousebutton"
-msgstr "Linker muisknop"
-
-#: ../vnc.html:109
-msgid "Middle mousebutton"
-msgstr "Middelste muisknop"
-
-#: ../vnc.html:112
-msgid "Right mousebutton"
-msgstr "Rechter muisknop"
-
-#: ../vnc.html:115
-msgid "Keyboard"
-msgstr "Toetsenbord"
-
-#: ../vnc.html:115
-msgid "Show Keyboard"
-msgstr "Toon Toetsenbord"
-
-#: ../vnc.html:121
-msgid "Extra keys"
-msgstr "Extra toetsen"
-
-#: ../vnc.html:121
-msgid "Show Extra Keys"
-msgstr "Toon Extra Toetsen"
-
-#: ../vnc.html:126
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:126
-msgid "Toggle Ctrl"
-msgstr "Ctrl omschakelen"
-
-#: ../vnc.html:129
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:129
-msgid "Toggle Alt"
-msgstr "Alt omschakelen"
-
-#: ../vnc.html:132
-msgid "Toggle Windows"
-msgstr "Windows omschakelen"
-
-#: ../vnc.html:132
-msgid "Windows"
-msgstr "Windows"
-
-#: ../vnc.html:135
-msgid "Send Tab"
-msgstr "Tab Sturen"
-
-#: ../vnc.html:135
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:138
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:138
-msgid "Send Escape"
-msgstr "Escape Sturen"
-
-#: ../vnc.html:141
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl-Alt-Del"
-
-#: ../vnc.html:141
-msgid "Send Ctrl-Alt-Del"
-msgstr "Ctrl-Alt-Del Sturen"
-
-#: ../vnc.html:149
-msgid "Shutdown/Reboot"
-msgstr "Uitschakelen/Herstarten"
-
-#: ../vnc.html:149
-msgid "Shutdown/Reboot..."
-msgstr "Uitschakelen/Herstarten..."
-
-#: ../vnc.html:155
-msgid "Power"
-msgstr "Systeem"
-
-#: ../vnc.html:157
-msgid "Shutdown"
-msgstr "Uitschakelen"
-
-#: ../vnc.html:158
-msgid "Reboot"
-msgstr "Herstarten"
-
-#: ../vnc.html:159
-msgid "Reset"
-msgstr "Resetten"
-
-#: ../vnc.html:164 ../vnc.html:170
-msgid "Clipboard"
-msgstr "Klembord"
-
-#: ../vnc.html:174
-msgid "Clear"
-msgstr "Wissen"
-
-#: ../vnc.html:180
-msgid "Fullscreen"
-msgstr "Volledig Scherm"
-
-#: ../vnc.html:185 ../vnc.html:192
-msgid "Settings"
-msgstr "Instellingen"
-
-#: ../vnc.html:195
-msgid "Shared Mode"
-msgstr "Gedeelde Modus"
-
-#: ../vnc.html:198
-msgid "View Only"
-msgstr "Alleen Kijken"
-
-#: ../vnc.html:202
-msgid "Clip to Window"
-msgstr "Randen buiten venster afsnijden"
-
-#: ../vnc.html:205
-msgid "Scaling Mode:"
-msgstr "Schaalmodus:"
-
-#: ../vnc.html:207
-msgid "None"
-msgstr "Geen"
-
-#: ../vnc.html:208
-msgid "Local Scaling"
-msgstr "Lokaal Schalen"
-
-#: ../vnc.html:209
-msgid "Remote Resizing"
-msgstr "Op Afstand Formaat Wijzigen"
-
-#: ../vnc.html:214
-msgid "Advanced"
-msgstr "Geavanceerd"
-
-#: ../vnc.html:217
-msgid "Repeater ID:"
-msgstr "Repeater ID:"
-
-#: ../vnc.html:221
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:224
-msgid "Encrypt"
-msgstr "Versleutelen"
-
-#: ../vnc.html:227
-msgid "Host:"
-msgstr "Host:"
-
-#: ../vnc.html:231
-msgid "Port:"
-msgstr "Poort:"
-
-#: ../vnc.html:235
-msgid "Path:"
-msgstr "Pad:"
-
-#: ../vnc.html:242
-msgid "Automatic Reconnect"
-msgstr "Automatisch Opnieuw Verbinden"
-
-#: ../vnc.html:245
-msgid "Reconnect Delay (ms):"
-msgstr "Vertraging voor Opnieuw Verbinden (ms):"
-
-#: ../vnc.html:250
-msgid "Show Dot when No Cursor"
-msgstr "Geef stip weer indien geen cursor"
-
-#: ../vnc.html:255
-msgid "Logging:"
-msgstr "Logmeldingen:"
-
-#: ../vnc.html:267
-msgid "Disconnect"
-msgstr "Verbinding verbreken"
-
-#: ../vnc.html:286
-msgid "Connect"
-msgstr "Verbinden"
-
-#: ../vnc.html:296
-msgid "Password:"
-msgstr "Wachtwoord:"
-
-#: ../vnc.html:300
-msgid "Send Password"
-msgstr "Verzend Wachtwoord:"
-
-#: ../vnc.html:310
-msgid "Cancel"
-msgstr "Annuleren"
-
-#~ msgid "Disconnect timeout"
-#~ msgstr "Timeout tijdens verbreken van verbinding"
-
-#~ msgid "Local Downscaling"
-#~ msgstr "Lokaal Neerschalen"
-
-#~ msgid "Local Cursor"
-#~ msgstr "Lokale Cursor"
-
-#~ msgid "Canvas not supported."
-#~ msgstr "Canvas wordt niet ondersteund."
-
-#~ msgid ""
-#~ "Forcing clipping mode since scrollbars aren't supported by IE in "
-#~ "fullscreen"
-#~ msgstr ""
-#~ "''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-"
-#~ "modus in IE niet worden ondersteund"
diff --git a/systemvm/agent/noVNC/po/noVNC.pot b/systemvm/agent/noVNC/po/noVNC.pot
deleted file mode 100644
index 200be01..0000000
--- a/systemvm/agent/noVNC/po/noVNC.pot
+++ /dev/null
@@ -1,302 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.1.0\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2019-01-16 11:06+0100\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: ../app/ui.js:387
-msgid "Connecting..."
-msgstr ""
-
-#: ../app/ui.js:394
-msgid "Disconnecting..."
-msgstr ""
-
-#: ../app/ui.js:400
-msgid "Reconnecting..."
-msgstr ""
-
-#: ../app/ui.js:405
-msgid "Internal error"
-msgstr ""
-
-#: ../app/ui.js:995
-msgid "Must set host"
-msgstr ""
-
-#: ../app/ui.js:1077
-msgid "Connected (encrypted) to "
-msgstr ""
-
-#: ../app/ui.js:1079
-msgid "Connected (unencrypted) to "
-msgstr ""
-
-#: ../app/ui.js:1102
-msgid "Something went wrong, connection is closed"
-msgstr ""
-
-#: ../app/ui.js:1105
-msgid "Failed to connect to server"
-msgstr ""
-
-#: ../app/ui.js:1115
-msgid "Disconnected"
-msgstr ""
-
-#: ../app/ui.js:1128
-msgid "New connection has been rejected with reason: "
-msgstr ""
-
-#: ../app/ui.js:1131
-msgid "New connection has been rejected"
-msgstr ""
-
-#: ../app/ui.js:1151
-msgid "Password is required"
-msgstr ""
-
-#: ../vnc.html:84
-msgid "noVNC encountered an error:"
-msgstr ""
-
-#: ../vnc.html:94
-msgid "Hide/Show the control bar"
-msgstr ""
-
-#: ../vnc.html:101
-msgid "Move/Drag Viewport"
-msgstr ""
-
-#: ../vnc.html:101
-msgid "viewport drag"
-msgstr ""
-
-#: ../vnc.html:107 ../vnc.html:110 ../vnc.html:113 ../vnc.html:116
-msgid "Active Mouse Button"
-msgstr ""
-
-#: ../vnc.html:107
-msgid "No mousebutton"
-msgstr ""
-
-#: ../vnc.html:110
-msgid "Left mousebutton"
-msgstr ""
-
-#: ../vnc.html:113
-msgid "Middle mousebutton"
-msgstr ""
-
-#: ../vnc.html:116
-msgid "Right mousebutton"
-msgstr ""
-
-#: ../vnc.html:119
-msgid "Keyboard"
-msgstr ""
-
-#: ../vnc.html:119
-msgid "Show Keyboard"
-msgstr ""
-
-#: ../vnc.html:126
-msgid "Extra keys"
-msgstr ""
-
-#: ../vnc.html:126
-msgid "Show Extra Keys"
-msgstr ""
-
-#: ../vnc.html:131
-msgid "Ctrl"
-msgstr ""
-
-#: ../vnc.html:131
-msgid "Toggle Ctrl"
-msgstr ""
-
-#: ../vnc.html:134
-msgid "Alt"
-msgstr ""
-
-#: ../vnc.html:134
-msgid "Toggle Alt"
-msgstr ""
-
-#: ../vnc.html:137
-msgid "Toggle Windows"
-msgstr ""
-
-#: ../vnc.html:137
-msgid "Windows"
-msgstr ""
-
-#: ../vnc.html:140
-msgid "Send Tab"
-msgstr ""
-
-#: ../vnc.html:140
-msgid "Tab"
-msgstr ""
-
-#: ../vnc.html:143
-msgid "Esc"
-msgstr ""
-
-#: ../vnc.html:143
-msgid "Send Escape"
-msgstr ""
-
-#: ../vnc.html:146
-msgid "Ctrl+Alt+Del"
-msgstr ""
-
-#: ../vnc.html:146
-msgid "Send Ctrl-Alt-Del"
-msgstr ""
-
-#: ../vnc.html:154
-msgid "Shutdown/Reboot"
-msgstr ""
-
-#: ../vnc.html:154
-msgid "Shutdown/Reboot..."
-msgstr ""
-
-#: ../vnc.html:160
-msgid "Power"
-msgstr ""
-
-#: ../vnc.html:162
-msgid "Shutdown"
-msgstr ""
-
-#: ../vnc.html:163
-msgid "Reboot"
-msgstr ""
-
-#: ../vnc.html:164
-msgid "Reset"
-msgstr ""
-
-#: ../vnc.html:169 ../vnc.html:175
-msgid "Clipboard"
-msgstr ""
-
-#: ../vnc.html:179
-msgid "Clear"
-msgstr ""
-
-#: ../vnc.html:185
-msgid "Fullscreen"
-msgstr ""
-
-#: ../vnc.html:190 ../vnc.html:197
-msgid "Settings"
-msgstr ""
-
-#: ../vnc.html:200
-msgid "Shared Mode"
-msgstr ""
-
-#: ../vnc.html:203
-msgid "View Only"
-msgstr ""
-
-#: ../vnc.html:207
-msgid "Clip to Window"
-msgstr ""
-
-#: ../vnc.html:210
-msgid "Scaling Mode:"
-msgstr ""
-
-#: ../vnc.html:212
-msgid "None"
-msgstr ""
-
-#: ../vnc.html:213
-msgid "Local Scaling"
-msgstr ""
-
-#: ../vnc.html:214
-msgid "Remote Resizing"
-msgstr ""
-
-#: ../vnc.html:219
-msgid "Advanced"
-msgstr ""
-
-#: ../vnc.html:222
-msgid "Repeater ID:"
-msgstr ""
-
-#: ../vnc.html:226
-msgid "WebSocket"
-msgstr ""
-
-#: ../vnc.html:229
-msgid "Encrypt"
-msgstr ""
-
-#: ../vnc.html:232
-msgid "Host:"
-msgstr ""
-
-#: ../vnc.html:236
-msgid "Port:"
-msgstr ""
-
-#: ../vnc.html:240
-msgid "Path:"
-msgstr ""
-
-#: ../vnc.html:247
-msgid "Automatic Reconnect"
-msgstr ""
-
-#: ../vnc.html:250
-msgid "Reconnect Delay (ms):"
-msgstr ""
-
-#: ../vnc.html:255
-msgid "Show Dot when No Cursor"
-msgstr ""
-
-#: ../vnc.html:260
-msgid "Logging:"
-msgstr ""
-
-#: ../vnc.html:272
-msgid "Disconnect"
-msgstr ""
-
-#: ../vnc.html:291
-msgid "Connect"
-msgstr ""
-
-#: ../vnc.html:301
-msgid "Password:"
-msgstr ""
-
-#: ../vnc.html:305
-msgid "Send Password"
-msgstr ""
-
-#: ../vnc.html:315
-msgid "Cancel"
-msgstr ""
diff --git a/systemvm/agent/noVNC/po/pl.po b/systemvm/agent/noVNC/po/pl.po
deleted file mode 100644
index 5acfdc4..0000000
--- a/systemvm/agent/noVNC/po/pl.po
+++ /dev/null
@@ -1,325 +0,0 @@
-# Polish translations for noVNC package.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Mariusz Jamro <mariusz.jamro@gmail.com>, 2017.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 0.6.1\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2017-11-21 19:53+0100\n"
-"PO-Revision-Date: 2017-11-21 19:54+0100\n"
-"Last-Translator: Mariusz Jamro <mariusz.jamro@gmail.com>\n"
-"Language-Team: Polish\n"
-"Language: pl\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
-"|| n%100>=20) ? 1 : 2);\n"
-"X-Generator: Poedit 2.0.1\n"
-
-#: ../app/ui.js:404
-msgid "Connecting..."
-msgstr "Łączenie..."
-
-#: ../app/ui.js:411
-msgid "Disconnecting..."
-msgstr "Rozłączanie..."
-
-#: ../app/ui.js:417
-msgid "Reconnecting..."
-msgstr "Łączenie..."
-
-#: ../app/ui.js:422
-msgid "Internal error"
-msgstr "Błąd wewnętrzny"
-
-#: ../app/ui.js:1019
-msgid "Must set host"
-msgstr "Host i port są wymagane"
-
-#: ../app/ui.js:1099
-msgid "Connected (encrypted) to "
-msgstr "Połączenie (szyfrowane) z "
-
-#: ../app/ui.js:1101
-msgid "Connected (unencrypted) to "
-msgstr "Połączenie (nieszyfrowane) z "
-
-#: ../app/ui.js:1119
-msgid "Something went wrong, connection is closed"
-msgstr "Coś poszło źle, połączenie zostało zamknięte"
-
-#: ../app/ui.js:1129
-msgid "Disconnected"
-msgstr "Rozłączony"
-
-#: ../app/ui.js:1142
-msgid "New connection has been rejected with reason: "
-msgstr "Nowe połączenie zostało odrzucone z powodu: "
-
-#: ../app/ui.js:1145
-msgid "New connection has been rejected"
-msgstr "Nowe połączenie zostało odrzucone"
-
-#: ../app/ui.js:1166
-msgid "Password is required"
-msgstr "Hasło jest wymagane"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "noVNC napotkało błąd:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "Pokaż/Ukryj pasek ustawień"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "Ruszaj/Przeciągaj Viewport"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "przeciągnij viewport"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "Aktywny Przycisk Myszy"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "Brak przycisku myszy"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "Lewy przycisk myszy"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "Środkowy przycisk myszy"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "Prawy przycisk myszy"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "Klawiatura"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "Pokaż klawiaturę"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "Przyciski dodatkowe"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "Pokaż przyciski dodatkowe"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "Przełącz Ctrl"
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "Przełącz Alt"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "Wyślij Tab"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "Wyślij Escape"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "Wyślij Ctrl-Alt-Del"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "Wyłącz/Uruchom ponownie"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "Wyłącz/Uruchom ponownie..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "Włączony"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "Wyłącz"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "Uruchom ponownie"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "Resetuj"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "Schowek"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "Wyczyść"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "Pełny ekran"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "Ustawienia"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "Tryb Współdzielenia"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "Tylko Podgląd"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "Przytnij do Okna"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "Tryb Skalowania:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "Brak"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "Skalowanie lokalne"
-
-#: ../vnc.html:216
-msgid "Remote Resizing"
-msgstr "Skalowanie zdalne"
-
-#: ../vnc.html:221
-msgid "Advanced"
-msgstr "Zaawansowane"
-
-#: ../vnc.html:224
-msgid "Repeater ID:"
-msgstr "ID Repeatera:"
-
-#: ../vnc.html:228
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:231
-msgid "Encrypt"
-msgstr "Szyfrowanie"
-
-#: ../vnc.html:234
-msgid "Host:"
-msgstr "Host:"
-
-#: ../vnc.html:238
-msgid "Port:"
-msgstr "Port:"
-
-#: ../vnc.html:242
-msgid "Path:"
-msgstr "Ścieżka:"
-
-#: ../vnc.html:249
-msgid "Automatic Reconnect"
-msgstr "Automatycznie wznawiaj połączenie"
-
-#: ../vnc.html:252
-msgid "Reconnect Delay (ms):"
-msgstr "Opóźnienie wznawiania (ms):"
-
-#: ../vnc.html:258
-msgid "Logging:"
-msgstr "Poziom logowania:"
-
-#: ../vnc.html:270
-msgid "Disconnect"
-msgstr "Rozłącz"
-
-#: ../vnc.html:289
-msgid "Connect"
-msgstr "Połącz"
-
-#: ../vnc.html:299
-msgid "Password:"
-msgstr "Hasło:"
-
-#: ../vnc.html:313
-msgid "Cancel"
-msgstr "Anuluj"
-
-#: ../vnc.html:329
-msgid "Canvas not supported."
-msgstr "Element Canvas nie jest wspierany."
-
-#~ msgid "Disconnect timeout"
-#~ msgstr "Timeout rozłączenia"
-
-#~ msgid "Local Downscaling"
-#~ msgstr "Downscaling lokalny"
-
-#~ msgid "Local Cursor"
-#~ msgstr "Lokalny kursor"
-
-#~ msgid ""
-#~ "Forcing clipping mode since scrollbars aren't supported by IE in "
-#~ "fullscreen"
-#~ msgstr ""
-#~ "Wymuszam clipping mode ponieważ paski przewijania nie są wspierane przez "
-#~ "IE w trybie pełnoekranowym"
-
-#~ msgid "True Color"
-#~ msgstr "True Color"
-
-#~ msgid "Style:"
-#~ msgstr "Styl:"
-
-#~ msgid "default"
-#~ msgstr "domyślny"
-
-#~ msgid "Apply"
-#~ msgstr "Zapisz"
-
-#~ msgid "Connection"
-#~ msgstr "Połączenie"
-
-#~ msgid "Token:"
-#~ msgstr "Token:"
-
-#~ msgid "Send Password"
-#~ msgstr "Wyślij Hasło"
diff --git a/systemvm/agent/noVNC/po/po2js b/systemvm/agent/noVNC/po/po2js
deleted file mode 100755
index 03c1490..0000000
--- a/systemvm/agent/noVNC/po/po2js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env node
-/*
- * ps2js: gettext .po to noVNC .js converter
- * Copyright (C) 2018 The noVNC Authors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-const getopt = require('node-getopt');
-const fs = require('fs');
-const po2json = require("po2json");
-
-const opt = getopt.create([
- ['h' , 'help' , 'display this help'],
-]).bindHelp().parseSystem();
-
-if (opt.argv.length != 2) {
- console.error("Incorrect number of arguments given");
- process.exit(1);
-}
-
-const data = po2json.parseFileSync(opt.argv[0]);
-
-const bodyPart = Object.keys(data).filter((msgid) => msgid !== "").map((msgid) => {
- if (msgid === "") return;
- const msgstr = data[msgid][1];
- return " " + JSON.stringify(msgid) + ": " + JSON.stringify(msgstr);
-}).join(",\n");
-
-const output = "{\n" + bodyPart + "\n}";
-
-fs.writeFileSync(opt.argv[1], output);
diff --git a/systemvm/agent/noVNC/po/ru.po b/systemvm/agent/noVNC/po/ru.po
deleted file mode 100644
index fb5d087..0000000
--- a/systemvm/agent/noVNC/po/ru.po
+++ /dev/null
@@ -1,306 +0,0 @@
-# Russian translations for noVNC package
-# Русский перевод для пакета noVNC.
-# Copyright (C) 2019 Dmitriy Shweew
-# This file is distributed under the same license as the noVNC package.
-# Dmitriy Shweew <shweew@it-advisor.ru>, 2019.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.1.0\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2019-02-26 14:53+0400\n"
-"PO-Revision-Date: 2019-02-17 17:29+0400\n"
-"Last-Translator: Dmitriy Shweew <shweew@it-advisor.ru>\n"
-"Language-Team: Russian\n"
-"Language: ru\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-"X-Generator: Poedit 2.2.1\n"
-"X-Poedit-Flags-xgettext: --add-comments\n"
-
-#: ../app/ui.js:387
-msgid "Connecting..."
-msgstr "Подключение..."
-
-#: ../app/ui.js:394
-msgid "Disconnecting..."
-msgstr "Отключение..."
-
-#: ../app/ui.js:400
-msgid "Reconnecting..."
-msgstr "Переподключение..."
-
-#: ../app/ui.js:405
-msgid "Internal error"
-msgstr "Внутренняя ошибка"
-
-#: ../app/ui.js:995
-msgid "Must set host"
-msgstr "Задайте имя сервера или IP"
-
-#: ../app/ui.js:1077
-msgid "Connected (encrypted) to "
-msgstr "Подключено (с шифрованием) к "
-
-#: ../app/ui.js:1079
-msgid "Connected (unencrypted) to "
-msgstr "Подключено (без шифрования) к "
-
-#: ../app/ui.js:1102
-msgid "Something went wrong, connection is closed"
-msgstr "Что-то пошло не так, подключение разорвано"
-
-#: ../app/ui.js:1105
-msgid "Failed to connect to server"
-msgstr "Ошибка подключения к серверу"
-
-#: ../app/ui.js:1115
-msgid "Disconnected"
-msgstr "Отключено"
-
-#: ../app/ui.js:1128
-msgid "New connection has been rejected with reason: "
-msgstr "Подключиться не удалось: "
-
-#: ../app/ui.js:1131
-msgid "New connection has been rejected"
-msgstr "Подключиться не удалось"
-
-#: ../app/ui.js:1151
-msgid "Password is required"
-msgstr "Требуется пароль"
-
-#: ../vnc.html:84
-msgid "noVNC encountered an error:"
-msgstr "Ошибка noVNC: "
-
-#: ../vnc.html:94
-msgid "Hide/Show the control bar"
-msgstr "Скрыть/Показать контрольную панель"
-
-#: ../vnc.html:101
-msgid "Move/Drag Viewport"
-msgstr "Переместить окно"
-
-#: ../vnc.html:101
-msgid "viewport drag"
-msgstr "Переместить окно"
-
-#: ../vnc.html:107 ../vnc.html:110 ../vnc.html:113 ../vnc.html:116
-msgid "Active Mouse Button"
-msgstr "Активировать кнопки мыши"
-
-#: ../vnc.html:107
-msgid "No mousebutton"
-msgstr "Отключить кнопки мыши"
-
-#: ../vnc.html:110
-msgid "Left mousebutton"
-msgstr "Левая кнопка мыши"
-
-#: ../vnc.html:113
-msgid "Middle mousebutton"
-msgstr "Средняя кнопка мыши"
-
-#: ../vnc.html:116
-msgid "Right mousebutton"
-msgstr "Правая кнопка мыши"
-
-#: ../vnc.html:119
-msgid "Keyboard"
-msgstr "Клавиатура"
-
-#: ../vnc.html:119
-msgid "Show Keyboard"
-msgstr "Показать клавиатуру"
-
-#: ../vnc.html:126
-msgid "Extra keys"
-msgstr "Доп. кнопки"
-
-#: ../vnc.html:126
-msgid "Show Extra Keys"
-msgstr "Показать дополнительные кнопки"
-
-#: ../vnc.html:131
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:131
-msgid "Toggle Ctrl"
-msgstr "Передать нажатие Ctrl"
-
-#: ../vnc.html:134
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:134
-msgid "Toggle Alt"
-msgstr "Передать нажатие Alt"
-
-#: ../vnc.html:137
-msgid "Toggle Windows"
-msgstr "Переключение вкладок"
-
-#: ../vnc.html:137
-msgid "Windows"
-msgstr "Вкладка"
-
-#: ../vnc.html:140
-msgid "Send Tab"
-msgstr "Передать нажатие Tab"
-
-#: ../vnc.html:140
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:143
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:143
-msgid "Send Escape"
-msgstr "Передать нажатие Escape"
-
-#: ../vnc.html:146
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:146
-msgid "Send Ctrl-Alt-Del"
-msgstr "Передать нажатие Ctrl-Alt-Del"
-
-#: ../vnc.html:154
-msgid "Shutdown/Reboot"
-msgstr "Выключить/Перезагрузить"
-
-#: ../vnc.html:154
-msgid "Shutdown/Reboot..."
-msgstr "Выключить/Перезагрузить..."
-
-#: ../vnc.html:160
-msgid "Power"
-msgstr "Питание"
-
-#: ../vnc.html:162
-msgid "Shutdown"
-msgstr "Выключить"
-
-#: ../vnc.html:163
-msgid "Reboot"
-msgstr "Перезагрузить"
-
-#: ../vnc.html:164
-msgid "Reset"
-msgstr "Сброс"
-
-#: ../vnc.html:169 ../vnc.html:175
-msgid "Clipboard"
-msgstr "Буфер обмена"
-
-#: ../vnc.html:179
-msgid "Clear"
-msgstr "Очистить"
-
-#: ../vnc.html:185
-msgid "Fullscreen"
-msgstr "Во весь экран"
-
-#: ../vnc.html:190 ../vnc.html:197
-msgid "Settings"
-msgstr "Настройки"
-
-#: ../vnc.html:200
-msgid "Shared Mode"
-msgstr "Общий режим"
-
-#: ../vnc.html:203
-msgid "View Only"
-msgstr "Просмотр"
-
-#: ../vnc.html:207
-msgid "Clip to Window"
-msgstr "В окно"
-
-#: ../vnc.html:210
-msgid "Scaling Mode:"
-msgstr "Масштаб:"
-
-#: ../vnc.html:212
-msgid "None"
-msgstr "Нет"
-
-#: ../vnc.html:213
-msgid "Local Scaling"
-msgstr "Локльный масштаб"
-
-#: ../vnc.html:214
-msgid "Remote Resizing"
-msgstr "Удаленный масштаб"
-
-#: ../vnc.html:219
-msgid "Advanced"
-msgstr "Дополнительно"
-
-#: ../vnc.html:222
-msgid "Repeater ID:"
-msgstr "Идентификатор ID:"
-
-#: ../vnc.html:226
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:229
-msgid "Encrypt"
-msgstr "Шифрование"
-
-#: ../vnc.html:232
-msgid "Host:"
-msgstr "Сервер:"
-
-#: ../vnc.html:236
-msgid "Port:"
-msgstr "Порт:"
-
-#: ../vnc.html:240
-msgid "Path:"
-msgstr "Путь:"
-
-#: ../vnc.html:247
-msgid "Automatic Reconnect"
-msgstr "Автоматическое переподключение"
-
-#: ../vnc.html:250
-msgid "Reconnect Delay (ms):"
-msgstr "Задержка переподключения (мс):"
-
-#: ../vnc.html:255
-msgid "Show Dot when No Cursor"
-msgstr "Показать точку вместо курсора"
-
-#: ../vnc.html:260
-msgid "Logging:"
-msgstr "Лог:"
-
-#: ../vnc.html:272
-msgid "Disconnect"
-msgstr "Отключение"
-
-#: ../vnc.html:291
-msgid "Connect"
-msgstr "Подключение"
-
-#: ../vnc.html:301
-msgid "Password:"
-msgstr "Пароль:"
-
-#: ../vnc.html:305
-msgid "Send Password"
-msgstr "Пароль: "
-
-#: ../vnc.html:315
-msgid "Cancel"
-msgstr "Выход"
diff --git a/systemvm/agent/noVNC/po/sv.po b/systemvm/agent/noVNC/po/sv.po
deleted file mode 100644
index f795566..0000000
--- a/systemvm/agent/noVNC/po/sv.po
+++ /dev/null
@@ -1,316 +0,0 @@
-# Swedish translations for noVNC package
-# Svenska översättningar för paket noVNC.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Samuel Mannehed <samuel@cendio.se>, 2019.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.1.0\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2019-01-16 11:06+0100\n"
-"PO-Revision-Date: 2019-04-08 10:18+0200\n"
-"Last-Translator: Samuel Mannehed <samuel@cendio.se>\n"
-"Language-Team: none\n"
-"Language: sv\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 2.0.3\n"
-
-#: ../app/ui.js:387
-msgid "Connecting..."
-msgstr "Ansluter..."
-
-#: ../app/ui.js:394
-msgid "Disconnecting..."
-msgstr "Kopplar ner..."
-
-#: ../app/ui.js:400
-msgid "Reconnecting..."
-msgstr "Återansluter..."
-
-#: ../app/ui.js:405
-msgid "Internal error"
-msgstr "Internt fel"
-
-#: ../app/ui.js:995
-msgid "Must set host"
-msgstr "Du måste specifiera en värd"
-
-#: ../app/ui.js:1077
-msgid "Connected (encrypted) to "
-msgstr "Ansluten (krypterat) till "
-
-#: ../app/ui.js:1079
-msgid "Connected (unencrypted) to "
-msgstr "Ansluten (okrypterat) till "
-
-#: ../app/ui.js:1102
-msgid "Something went wrong, connection is closed"
-msgstr "Något gick fel, anslutningen avslutades"
-
-#: ../app/ui.js:1105
-msgid "Failed to connect to server"
-msgstr "Misslyckades att ansluta till servern"
-
-#: ../app/ui.js:1115
-msgid "Disconnected"
-msgstr "Frånkopplad"
-
-#: ../app/ui.js:1128
-msgid "New connection has been rejected with reason: "
-msgstr "Ny anslutning har blivit nekad med följande skäl: "
-
-#: ../app/ui.js:1131
-msgid "New connection has been rejected"
-msgstr "Ny anslutning har blivit nekad"
-
-#: ../app/ui.js:1151
-msgid "Password is required"
-msgstr "Lösenord krävs"
-
-#: ../vnc.html:84
-msgid "noVNC encountered an error:"
-msgstr "noVNC stötte på ett problem:"
-
-#: ../vnc.html:94
-msgid "Hide/Show the control bar"
-msgstr "Göm/Visa kontrollbaren"
-
-#: ../vnc.html:101
-msgid "Move/Drag Viewport"
-msgstr "Flytta/Dra Vyn"
-
-#: ../vnc.html:101
-msgid "viewport drag"
-msgstr "dra vy"
-
-#: ../vnc.html:107 ../vnc.html:110 ../vnc.html:113 ../vnc.html:116
-msgid "Active Mouse Button"
-msgstr "Aktiv musknapp"
-
-#: ../vnc.html:107
-msgid "No mousebutton"
-msgstr "Ingen musknapp"
-
-#: ../vnc.html:110
-msgid "Left mousebutton"
-msgstr "Vänster musknapp"
-
-#: ../vnc.html:113
-msgid "Middle mousebutton"
-msgstr "Mitten-musknapp"
-
-#: ../vnc.html:116
-msgid "Right mousebutton"
-msgstr "Höger musknapp"
-
-#: ../vnc.html:119
-msgid "Keyboard"
-msgstr "Tangentbord"
-
-#: ../vnc.html:119
-msgid "Show Keyboard"
-msgstr "Visa Tangentbord"
-
-#: ../vnc.html:126
-msgid "Extra keys"
-msgstr "Extraknappar"
-
-#: ../vnc.html:126
-msgid "Show Extra Keys"
-msgstr "Visa Extraknappar"
-
-#: ../vnc.html:131
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:131
-msgid "Toggle Ctrl"
-msgstr "Växla Ctrl"
-
-#: ../vnc.html:134
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:134
-msgid "Toggle Alt"
-msgstr "Växla Alt"
-
-#: ../vnc.html:137
-msgid "Toggle Windows"
-msgstr "Växla Windows"
-
-#: ../vnc.html:137
-msgid "Windows"
-msgstr "Windows"
-
-#: ../vnc.html:140
-msgid "Send Tab"
-msgstr "Skicka Tab"
-
-#: ../vnc.html:140
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:143
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:143
-msgid "Send Escape"
-msgstr "Skicka Escape"
-
-#: ../vnc.html:146
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl+Alt+Del"
-
-#: ../vnc.html:146
-msgid "Send Ctrl-Alt-Del"
-msgstr "Skicka Ctrl-Alt-Del"
-
-#: ../vnc.html:154
-msgid "Shutdown/Reboot"
-msgstr "Stäng av/Boota om"
-
-#: ../vnc.html:154
-msgid "Shutdown/Reboot..."
-msgstr "Stäng av/Boota om..."
-
-#: ../vnc.html:160
-msgid "Power"
-msgstr "Ström"
-
-#: ../vnc.html:162
-msgid "Shutdown"
-msgstr "Stäng av"
-
-#: ../vnc.html:163
-msgid "Reboot"
-msgstr "Boota om"
-
-#: ../vnc.html:164
-msgid "Reset"
-msgstr "Återställ"
-
-#: ../vnc.html:169 ../vnc.html:175
-msgid "Clipboard"
-msgstr "Urklipp"
-
-#: ../vnc.html:179
-msgid "Clear"
-msgstr "Rensa"
-
-#: ../vnc.html:185
-msgid "Fullscreen"
-msgstr "Fullskärm"
-
-#: ../vnc.html:190 ../vnc.html:197
-msgid "Settings"
-msgstr "Inställningar"
-
-#: ../vnc.html:200
-msgid "Shared Mode"
-msgstr "Delat Läge"
-
-#: ../vnc.html:203
-msgid "View Only"
-msgstr "Endast Visning"
-
-#: ../vnc.html:207
-msgid "Clip to Window"
-msgstr "Begränsa till Fönster"
-
-#: ../vnc.html:210
-msgid "Scaling Mode:"
-msgstr "Skalningsläge:"
-
-#: ../vnc.html:212
-msgid "None"
-msgstr "Ingen"
-
-#: ../vnc.html:213
-msgid "Local Scaling"
-msgstr "Lokal Skalning"
-
-#: ../vnc.html:214
-msgid "Remote Resizing"
-msgstr "Ändra Storlek"
-
-#: ../vnc.html:219
-msgid "Advanced"
-msgstr "Avancerat"
-
-#: ../vnc.html:222
-msgid "Repeater ID:"
-msgstr "Repeater-ID:"
-
-#: ../vnc.html:226
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:229
-msgid "Encrypt"
-msgstr "Kryptera"
-
-#: ../vnc.html:232
-msgid "Host:"
-msgstr "Värd:"
-
-#: ../vnc.html:236
-msgid "Port:"
-msgstr "Port:"
-
-#: ../vnc.html:240
-msgid "Path:"
-msgstr "Sökväg:"
-
-#: ../vnc.html:247
-msgid "Automatic Reconnect"
-msgstr "Automatisk Återanslutning"
-
-#: ../vnc.html:250
-msgid "Reconnect Delay (ms):"
-msgstr "Fördröjning (ms):"
-
-#: ../vnc.html:255
-msgid "Show Dot when No Cursor"
-msgstr "Visa prick när ingen muspekare finns"
-
-#: ../vnc.html:260
-msgid "Logging:"
-msgstr "Loggning:"
-
-#: ../vnc.html:272
-msgid "Disconnect"
-msgstr "Koppla från"
-
-#: ../vnc.html:291
-msgid "Connect"
-msgstr "Anslut"
-
-#: ../vnc.html:301
-msgid "Password:"
-msgstr "Lösenord:"
-
-#: ../vnc.html:305
-msgid "Send Password"
-msgstr "Skicka lösenord"
-
-#: ../vnc.html:315
-msgid "Cancel"
-msgstr "Avbryt"
-
-#~ msgid "Disconnect timeout"
-#~ msgstr "Det tog för lång tid att koppla ner"
-
-#~ msgid "Local Downscaling"
-#~ msgstr "Lokal Nedskalning"
-
-#~ msgid "Local Cursor"
-#~ msgstr "Lokal Muspekare"
-
-#~ msgid "Canvas not supported."
-#~ msgstr "Canvas stöds ej"
diff --git a/systemvm/agent/noVNC/po/tr.po b/systemvm/agent/noVNC/po/tr.po
deleted file mode 100644
index 8b5c181..0000000
--- a/systemvm/agent/noVNC/po/tr.po
+++ /dev/null
@@ -1,288 +0,0 @@
-# Turkish translations for noVNC package
-# Turkish translation for noVNC.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Ömer ÇAKMAK <farukomercakmak@gmail.com>, 2018.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 0.6.1\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2017-11-24 07:16+0000\n"
-"PO-Revision-Date: 2018-01-05 19:07+0300\n"
-"Last-Translator: Ömer ÇAKMAK <farukomercakmak@gmail.com>\n"
-"Language-Team: Türkçe <gnome-turk@gnome.org>\n"
-"Language: tr\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Gtranslator 2.91.7\n"
-
-#: ../app/ui.js:404
-msgid "Connecting..."
-msgstr "Bağlanıyor..."
-
-#: ../app/ui.js:411
-msgid "Disconnecting..."
-msgstr "Bağlantı kesiliyor..."
-
-#: ../app/ui.js:417
-msgid "Reconnecting..."
-msgstr "Yeniden bağlantı kuruluyor..."
-
-#: ../app/ui.js:422
-msgid "Internal error"
-msgstr "İç hata"
-
-#: ../app/ui.js:1019
-msgid "Must set host"
-msgstr "Sunucuyu kur"
-
-#: ../app/ui.js:1099
-msgid "Connected (encrypted) to "
-msgstr "Bağlı (şifrelenmiş)"
-
-#: ../app/ui.js:1101
-msgid "Connected (unencrypted) to "
-msgstr "Bağlandı (şifrelenmemiş)"
-
-#: ../app/ui.js:1119
-msgid "Something went wrong, connection is closed"
-msgstr "Bir şeyler ters gitti, bağlantı kesildi"
-
-#: ../app/ui.js:1129
-msgid "Disconnected"
-msgstr "Bağlantı kesildi"
-
-#: ../app/ui.js:1142
-msgid "New connection has been rejected with reason: "
-msgstr "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: "
-
-#: ../app/ui.js:1145
-msgid "New connection has been rejected"
-msgstr "Bağlantı reddedildi"
-
-#: ../app/ui.js:1166
-msgid "Password is required"
-msgstr "Şifre gerekli"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "Bir hata oluştu:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "Denetim masasını Gizle/Göster"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "Görünümü Taşı/Sürükle"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "Görüntü penceresini sürükle"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "Aktif Fare Düğmesi"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "Fare düğmesi yok"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "Farenin sol düğmesi"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "Farenin orta düğmesi"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "Farenin sağ düğmesi"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "Klavye"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "Klavye Düzenini Göster"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "Ekstra tuşlar"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "Ekstra tuşları göster"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "Ctrl Değiştir "
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "Alt Değiştir"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "Sekme Gönder"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Sekme"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "Boşluk Gönder"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl + Alt + Del"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "Ctrl-Alt-Del Gönder"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "Kapat/Yeniden Başlat"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "Kapat/Yeniden Başlat..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "Güç"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "Kapat"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "Yeniden Başlat"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "Sıfırla"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "Pano"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "Temizle"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "Tam Ekran"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "Ayarlar"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "Paylaşım Modu"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "Sadece Görüntüle"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "Pencereye Tıkla"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "Ölçekleme Modu:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "Bilinmeyen"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "Yerel Ölçeklendirme"
-
-#: ../vnc.html:216
-msgid "Remote Resizing"
-msgstr "Uzaktan Yeniden Boyutlandırma"
-
-#: ../vnc.html:221
-msgid "Advanced"
-msgstr "Gelişmiş"
-
-#: ../vnc.html:224
-msgid "Repeater ID:"
-msgstr "Tekralayıcı ID:"
-
-#: ../vnc.html:228
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:231
-msgid "Encrypt"
-msgstr "Şifrele"
-
-#: ../vnc.html:234
-msgid "Host:"
-msgstr "Ana makine:"
-
-#: ../vnc.html:238
-msgid "Port:"
-msgstr "Port:"
-
-#: ../vnc.html:242
-msgid "Path:"
-msgstr "Yol:"
-
-#: ../vnc.html:249
-msgid "Automatic Reconnect"
-msgstr "Otomatik Yeniden Bağlan"
-
-#: ../vnc.html:252
-msgid "Reconnect Delay (ms):"
-msgstr "Yeniden Bağlanma Süreci (ms):"
-
-#: ../vnc.html:258
-msgid "Logging:"
-msgstr "Giriş yapılıyor:"
-
-#: ../vnc.html:270
-msgid "Disconnect"
-msgstr "Bağlantıyı Kes"
-
-#: ../vnc.html:289
-msgid "Connect"
-msgstr "Bağlan"
-
-#: ../vnc.html:299
-msgid "Password:"
-msgstr "Parola:"
-
-#: ../vnc.html:313
-msgid "Cancel"
-msgstr "Vazgeç"
-
-#: ../vnc.html:329
-msgid "Canvas not supported."
-msgstr "Tuval desteklenmiyor."
diff --git a/systemvm/agent/noVNC/po/xgettext-html b/systemvm/agent/noVNC/po/xgettext-html
deleted file mode 100755
index 547f568..0000000
--- a/systemvm/agent/noVNC/po/xgettext-html
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env node
-/*
- * xgettext-html: HTML gettext parser
- * Copyright (C) 2018 The noVNC Authors
- * Licensed under MPL 2.0 (see LICENSE.txt)
- */
-
-const getopt = require('node-getopt');
-const jsdom = require("jsdom");
-const fs = require("fs");
-
-const opt = getopt.create([
- ['o' , 'output=FILE' , 'write output to specified file'],
- ['h' , 'help' , 'display this help'],
-]).bindHelp().parseSystem();
-
-const strings = {};
-
-function addString(str, location) {
- if (str.length == 0) {
- return;
- }
-
- if (strings[str] === undefined) {
- strings[str] = {}
- }
- strings[str][location] = null;
-}
-
-// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate
-function process(elem, locator, enabled) {
- function isAnyOf(searchElement, items) {
- return items.indexOf(searchElement) !== -1;
- }
-
- if (elem.hasAttribute("translate")) {
- if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) {
- enabled = true;
- } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) {
- enabled = false;
- }
- }
-
- if (enabled) {
- if (elem.hasAttribute("abbr") &&
- elem.tagName === "TH") {
- addString(elem.getAttribute("abbr"), locator(elem));
- }
- if (elem.hasAttribute("alt") &&
- isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) {
- addString(elem.getAttribute("alt"), locator(elem));
- }
- if (elem.hasAttribute("download") &&
- isAnyOf(elem.tagName, ["A", "AREA"])) {
- addString(elem.getAttribute("download"), locator(elem));
- }
- if (elem.hasAttribute("label") &&
- isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP",
- "OPTION", "TRACK"])) {
- addString(elem.getAttribute("label"), locator(elem));
- }
- if (elem.hasAttribute("placeholder") &&
- isAnyOf(elem.tagName in ["INPUT", "TEXTAREA"])) {
- addString(elem.getAttribute("placeholder"), locator(elem));
- }
- if (elem.hasAttribute("title")) {
- addString(elem.getAttribute("title"), locator(elem));
- }
- if (elem.hasAttribute("value") &&
- elem.tagName === "INPUT" &&
- isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) {
- addString(elem.getAttribute("value"), locator(elem));
- }
- }
-
- for (let i = 0; i < elem.childNodes.length; i++) {
- node = elem.childNodes[i];
- if (node.nodeType === node.ELEMENT_NODE) {
- process(node, locator, enabled);
- } else if (node.nodeType === node.TEXT_NODE && enabled) {
- addString(node.data.trim(), locator(node));
- }
- }
-}
-
-for (let i = 0; i < opt.argv.length; i++) {
- const fn = opt.argv[i];
- const file = fs.readFileSync(fn, "utf8");
- const dom = new jsdom.JSDOM(file, { includeNodeLocations: true });
- const body = dom.window.document.body;
-
- function locator(elem) {
- const offset = dom.nodeLocation(elem).startOffset;
- const line = file.slice(0, offset).split("\n").length;
- return fn + ":" + line;
- }
-
- process(body, locator, true);
-}
-
-let output = "";
-
-for (str in strings) {
- output += "#:";
- for (location in strings[str]) {
- output += " " + location;
- }
- output += "\n";
-
- output += "msgid " + JSON.stringify(str) + "\n";
- output += "msgstr \"\"\n";
- output += "\n";
-}
-
-fs.writeFileSync(opt.options.output, output);
diff --git a/systemvm/agent/noVNC/po/zh_CN.po b/systemvm/agent/noVNC/po/zh_CN.po
deleted file mode 100644
index 78bfb95..0000000
--- a/systemvm/agent/noVNC/po/zh_CN.po
+++ /dev/null
@@ -1,284 +0,0 @@
-# Simplified Chinese translations for noVNC package.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Peter Dave Hello <hsu@peterdavehello.org>, 2018.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.0.0-testing.2\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2018-01-10 00:53+0800\n"
-"PO-Revision-Date: 2018-04-06 21:33+0800\n"
-"Last-Translator: CUI Wei <ghostplant@qq.com>\n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: ../app/ui.js:395
-msgid "Connecting..."
-msgstr "链接中..."
-
-#: ../app/ui.js:402
-msgid "Disconnecting..."
-msgstr "正在中断连接..."
-
-#: ../app/ui.js:408
-msgid "Reconnecting..."
-msgstr "重新链接中..."
-
-#: ../app/ui.js:413
-msgid "Internal error"
-msgstr "内部错误"
-
-#: ../app/ui.js:1015
-msgid "Must set host"
-msgstr "请提供主机名"
-
-#: ../app/ui.js:1097
-msgid "Connected (encrypted) to "
-msgstr "已加密链接到"
-
-#: ../app/ui.js:1099
-msgid "Connected (unencrypted) to "
-msgstr "未加密链接到"
-
-#: ../app/ui.js:1120
-msgid "Something went wrong, connection is closed"
-msgstr "发生错误,链接已关闭"
-
-#: ../app/ui.js:1123
-msgid "Failed to connect to server"
-msgstr "无法链接到服务器"
-
-#: ../app/ui.js:1133
-msgid "Disconnected"
-msgstr "链接已中断"
-
-#: ../app/ui.js:1146
-msgid "New connection has been rejected with reason: "
-msgstr "链接被拒绝,原因:"
-
-#: ../app/ui.js:1149
-msgid "New connection has been rejected"
-msgstr "链接被拒绝"
-
-#: ../app/ui.js:1170
-msgid "Password is required"
-msgstr "请提供密码"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "noVNC 遇到一个错误:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "显示/隐藏控制列"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "拖放显示范围"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "显示范围拖放"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "启动鼠标按鍵"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "禁用鼠标按鍵"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "鼠标左鍵"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "鼠标中鍵"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "鼠标右鍵"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "键盘"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "显示键盘"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "额外按键"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "显示额外按键"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "切换 Ctrl"
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "切换 Alt"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "发送 Tab 键"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "发送 Escape 键"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl-Alt-Del"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "发送 Ctrl-Alt-Del 键"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "关机/重新启动"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "关机/重新启动..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "电源"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "关机"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "重新启动"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "重置"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "剪贴板"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "清除"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "全屏幕"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "设置"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "分享模式"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "仅检视"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "限制/裁切窗口大小"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "缩放模式:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "无"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "本地缩放"
-
-#: ../vnc.html:216
-msgid "Remote Resizing"
-msgstr "远程调整大小"
-
-#: ../vnc.html:221
-msgid "Advanced"
-msgstr "高级"
-
-#: ../vnc.html:224
-msgid "Repeater ID:"
-msgstr "中继站 ID"
-
-#: ../vnc.html:228
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:231
-msgid "Encrypt"
-msgstr "加密"
-
-#: ../vnc.html:234
-msgid "Host:"
-msgstr "主机:"
-
-#: ../vnc.html:238
-msgid "Port:"
-msgstr "端口:"
-
-#: ../vnc.html:242
-msgid "Path:"
-msgstr "路径:"
-
-#: ../vnc.html:249
-msgid "Automatic Reconnect"
-msgstr "自动重新链接"
-
-#: ../vnc.html:252
-msgid "Reconnect Delay (ms):"
-msgstr "重新链接间隔 (ms):"
-
-#: ../vnc.html:258
-msgid "Logging:"
-msgstr "日志级别:"
-
-#: ../vnc.html:270
-msgid "Disconnect"
-msgstr "终端链接"
-
-#: ../vnc.html:289
-msgid "Connect"
-msgstr "链接"
-
-#: ../vnc.html:299
-msgid "Password:"
-msgstr "密码:"
-
-#: ../vnc.html:313
-msgid "Cancel"
-msgstr "取消"
diff --git a/systemvm/agent/noVNC/po/zh_TW.po b/systemvm/agent/noVNC/po/zh_TW.po
deleted file mode 100644
index 9ddf550..0000000
--- a/systemvm/agent/noVNC/po/zh_TW.po
+++ /dev/null
@@ -1,285 +0,0 @@
-# Traditional Chinese translations for noVNC package.
-# Copyright (C) 2018 The noVNC Authors
-# This file is distributed under the same license as the noVNC package.
-# Peter Dave Hello <hsu@peterdavehello.org>, 2018.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: noVNC 1.0.0-testing.2\n"
-"Report-Msgid-Bugs-To: novnc@googlegroups.com\n"
-"POT-Creation-Date: 2018-01-10 00:53+0800\n"
-"PO-Revision-Date: 2018-01-10 01:33+0800\n"
-"Last-Translator: Peter Dave Hello <hsu@peterdavehello.org>\n"
-"Language-Team: Peter Dave Hello <hsu@peterdavehello.org>\n"
-"Language: zh\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-
-#: ../app/ui.js:395
-msgid "Connecting..."
-msgstr "連線中..."
-
-#: ../app/ui.js:402
-msgid "Disconnecting..."
-msgstr "正在中斷連線..."
-
-#: ../app/ui.js:408
-msgid "Reconnecting..."
-msgstr "重新連線中..."
-
-#: ../app/ui.js:413
-msgid "Internal error"
-msgstr "內部錯誤"
-
-#: ../app/ui.js:1015
-msgid "Must set host"
-msgstr "請提供主機資訊"
-
-#: ../app/ui.js:1097
-msgid "Connected (encrypted) to "
-msgstr "已加密連線到"
-
-#: ../app/ui.js:1099
-msgid "Connected (unencrypted) to "
-msgstr "未加密連線到"
-
-#: ../app/ui.js:1120
-msgid "Something went wrong, connection is closed"
-msgstr "發生錯誤,連線已關閉"
-
-#: ../app/ui.js:1123
-msgid "Failed to connect to server"
-msgstr "無法連線到伺服器"
-
-#: ../app/ui.js:1133
-msgid "Disconnected"
-msgstr "連線已中斷"
-
-#: ../app/ui.js:1146
-msgid "New connection has been rejected with reason: "
-msgstr "連線被拒絕,原因:"
-
-#: ../app/ui.js:1149
-msgid "New connection has been rejected"
-msgstr "連線被拒絕"
-
-#: ../app/ui.js:1170
-msgid "Password is required"
-msgstr "請提供密碼"
-
-#: ../vnc.html:89
-msgid "noVNC encountered an error:"
-msgstr "noVNC 遇到一個錯誤:"
-
-#: ../vnc.html:99
-msgid "Hide/Show the control bar"
-msgstr "顯示/隱藏控制列"
-
-#: ../vnc.html:106
-msgid "Move/Drag Viewport"
-msgstr "拖放顯示範圍"
-
-#: ../vnc.html:106
-msgid "viewport drag"
-msgstr "顯示範圍拖放"
-
-#: ../vnc.html:112 ../vnc.html:115 ../vnc.html:118 ../vnc.html:121
-msgid "Active Mouse Button"
-msgstr "啟用滑鼠按鍵"
-
-#: ../vnc.html:112
-msgid "No mousebutton"
-msgstr "無滑鼠按鍵"
-
-#: ../vnc.html:115
-msgid "Left mousebutton"
-msgstr "滑鼠左鍵"
-
-#: ../vnc.html:118
-msgid "Middle mousebutton"
-msgstr "滑鼠中鍵"
-
-#: ../vnc.html:121
-msgid "Right mousebutton"
-msgstr "滑鼠右鍵"
-
-#: ../vnc.html:124
-msgid "Keyboard"
-msgstr "鍵盤"
-
-#: ../vnc.html:124
-msgid "Show Keyboard"
-msgstr "顯示鍵盤"
-
-#: ../vnc.html:131
-msgid "Extra keys"
-msgstr "額外按鍵"
-
-#: ../vnc.html:131
-msgid "Show Extra Keys"
-msgstr "顯示額外按鍵"
-
-#: ../vnc.html:136
-msgid "Ctrl"
-msgstr "Ctrl"
-
-#: ../vnc.html:136
-msgid "Toggle Ctrl"
-msgstr "切換 Ctrl"
-
-#: ../vnc.html:139
-msgid "Alt"
-msgstr "Alt"
-
-#: ../vnc.html:139
-msgid "Toggle Alt"
-msgstr "切換 Alt"
-
-#: ../vnc.html:142
-msgid "Send Tab"
-msgstr "送出 Tab 鍵"
-
-#: ../vnc.html:142
-msgid "Tab"
-msgstr "Tab"
-
-#: ../vnc.html:145
-msgid "Esc"
-msgstr "Esc"
-
-#: ../vnc.html:145
-msgid "Send Escape"
-msgstr "送出 Escape 鍵"
-
-#: ../vnc.html:148
-msgid "Ctrl+Alt+Del"
-msgstr "Ctrl-Alt-Del"
-
-#: ../vnc.html:148
-msgid "Send Ctrl-Alt-Del"
-msgstr "送出 Ctrl-Alt-Del 快捷鍵"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot"
-msgstr "關機/重新啟動"
-
-#: ../vnc.html:156
-msgid "Shutdown/Reboot..."
-msgstr "關機/重新啟動..."
-
-#: ../vnc.html:162
-msgid "Power"
-msgstr "電源"
-
-#: ../vnc.html:164
-msgid "Shutdown"
-msgstr "關機"
-
-#: ../vnc.html:165
-msgid "Reboot"
-msgstr "重新啟動"
-
-#: ../vnc.html:166
-msgid "Reset"
-msgstr "重設"
-
-#: ../vnc.html:171 ../vnc.html:177
-msgid "Clipboard"
-msgstr "剪貼簿"
-
-#: ../vnc.html:181
-msgid "Clear"
-msgstr "清除"
-
-#: ../vnc.html:187
-msgid "Fullscreen"
-msgstr "全螢幕"
-
-#: ../vnc.html:192 ../vnc.html:199
-msgid "Settings"
-msgstr "設定"
-
-#: ../vnc.html:202
-msgid "Shared Mode"
-msgstr "分享模式"
-
-#: ../vnc.html:205
-msgid "View Only"
-msgstr "僅檢視"
-
-#: ../vnc.html:209
-msgid "Clip to Window"
-msgstr "限制/裁切視窗大小"
-
-#: ../vnc.html:212
-msgid "Scaling Mode:"
-msgstr "縮放模式:"
-
-#: ../vnc.html:214
-msgid "None"
-msgstr "無"
-
-#: ../vnc.html:215
-msgid "Local Scaling"
-msgstr "本機縮放"
-
-#: ../vnc.html:216
-msgid "Remote Resizing"
-msgstr "遠端調整大小"
-
-#: ../vnc.html:221
-msgid "Advanced"
-msgstr "進階"
-
-#: ../vnc.html:224
-msgid "Repeater ID:"
-msgstr "中繼站 ID"
-
-#: ../vnc.html:228
-msgid "WebSocket"
-msgstr "WebSocket"
-
-#: ../vnc.html:231
-msgid "Encrypt"
-msgstr "加密"
-
-#: ../vnc.html:234
-msgid "Host:"
-msgstr "主機:"
-
-#: ../vnc.html:238
-msgid "Port:"
-msgstr "連接埠:"
-
-#: ../vnc.html:242
-msgid "Path:"
-msgstr "路徑:"
-
-#: ../vnc.html:249
-msgid "Automatic Reconnect"
-msgstr "自動重新連線"
-
-#: ../vnc.html:252
-msgid "Reconnect Delay (ms):"
-msgstr "重新連線間隔 (ms):"
-
-#: ../vnc.html:258
-msgid "Logging:"
-msgstr "日誌級別:"
-
-#: ../vnc.html:270
-msgid "Disconnect"
-msgstr "中斷連線"
-
-#: ../vnc.html:289
-msgid "Connect"
-msgstr "連線"
-
-#: ../vnc.html:299
-msgid "Password:"
-msgstr "密碼:"
-
-#: ../vnc.html:313
-msgid "Cancel"
-msgstr "取消"
diff --git a/systemvm/agent/noVNC/tests/.eslintrc b/systemvm/agent/noVNC/tests/.eslintrc
deleted file mode 100644
index 545fa2e..0000000
--- a/systemvm/agent/noVNC/tests/.eslintrc
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "env": {
- "node": true,
- "mocha": true
- },
- "globals": {
- "chai": false,
- "sinon": false
- },
- "rules": {
- "prefer-arrow-callback": 0,
- // Too many anonymous callbacks
- "func-names": "off",
- }
-}
diff --git a/systemvm/agent/noVNC/tests/assertions.js b/systemvm/agent/noVNC/tests/assertions.js
deleted file mode 100644
index 07a5c29..0000000
--- a/systemvm/agent/noVNC/tests/assertions.js
+++ /dev/null
@@ -1,101 +0,0 @@
-// noVNC specific assertions
-chai.use(function (_chai, utils) {
- _chai.Assertion.addMethod('displayed', function (target_data) {
- const obj = this._obj;
- const ctx = obj._target.getContext('2d');
- const data_cl = ctx.getImageData(0, 0, obj._target.width, obj._target.height).data;
- // NB(directxman12): PhantomJS 1.x doesn't implement Uint8ClampedArray, so work around that
- const data = new Uint8Array(data_cl);
- const len = data_cl.length;
- new chai.Assertion(len).to.be.equal(target_data.length, "unexpected display size");
- let same = true;
- for (let i = 0; i < len; i++) {
- if (data[i] != target_data[i]) {
- same = false;
- break;
- }
- }
- if (!same) {
- // eslint-disable-next-line no-console
- console.log("expected data: %o, actual data: %o", target_data, data);
- }
- this.assert(same,
- "expected #{this} to have displayed the image #{exp}, but instead it displayed #{act}",
- "expected #{this} not to have displayed the image #{act}",
- target_data,
- data);
- });
-
- _chai.Assertion.addMethod('sent', function (target_data) {
- const obj = this._obj;
- obj.inspect = () => {
- const res = { _websocket: obj._websocket, rQi: obj._rQi, _rQ: new Uint8Array(obj._rQ.buffer, 0, obj._rQlen),
- _sQ: new Uint8Array(obj._sQ.buffer, 0, obj._sQlen) };
- res.prototype = obj;
- return res;
- };
- const data = obj._websocket._get_sent_data();
- let same = true;
- if (data.length != target_data.length) {
- same = false;
- } else {
- for (let i = 0; i < data.length; i++) {
- if (data[i] != target_data[i]) {
- same = false;
- break;
- }
- }
- }
- if (!same) {
- // eslint-disable-next-line no-console
- console.log("expected data: %o, actual data: %o", target_data, data);
- }
- this.assert(same,
- "expected #{this} to have sent the data #{exp}, but it actually sent #{act}",
- "expected #{this} not to have sent the data #{act}",
- Array.prototype.slice.call(target_data),
- Array.prototype.slice.call(data));
- });
-
- _chai.Assertion.addProperty('array', function () {
- utils.flag(this, 'array', true);
- });
-
- _chai.Assertion.overwriteMethod('equal', function (_super) {
- return function assertArrayEqual(target) {
- if (utils.flag(this, 'array')) {
- const obj = this._obj;
-
- let same = true;
-
- if (utils.flag(this, 'deep')) {
- for (let i = 0; i < obj.length; i++) {
- if (!utils.eql(obj[i], target[i])) {
- same = false;
- break;
- }
- }
-
- this.assert(same,
- "expected #{this} to have elements deeply equal to #{exp}",
- "expected #{this} not to have elements deeply equal to #{exp}",
- Array.prototype.slice.call(target));
- } else {
- for (let i = 0; i < obj.length; i++) {
- if (obj[i] != target[i]) {
- same = false;
- break;
- }
- }
-
- this.assert(same,
- "expected #{this} to have elements equal to #{exp}",
- "expected #{this} not to have elements equal to #{exp}",
- Array.prototype.slice.call(target));
- }
- } else {
- _super.apply(this, arguments);
- }
- };
- });
-});
diff --git a/systemvm/agent/noVNC/tests/fake.websocket.js b/systemvm/agent/noVNC/tests/fake.websocket.js
deleted file mode 100644
index 68ab3f8..0000000
--- a/systemvm/agent/noVNC/tests/fake.websocket.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import Base64 from '../core/base64.js';
-
-// PhantomJS can't create Event objects directly, so we need to use this
-function make_event(name, props) {
- const evt = document.createEvent('Event');
- evt.initEvent(name, true, true);
- if (props) {
- for (let prop in props) {
- evt[prop] = props[prop];
- }
- }
- return evt;
-}
-
-export default class FakeWebSocket {
- constructor(uri, protocols) {
- this.url = uri;
- this.binaryType = "arraybuffer";
- this.extensions = "";
-
- if (!protocols || typeof protocols === 'string') {
- this.protocol = protocols;
- } else {
- this.protocol = protocols[0];
- }
-
- this._send_queue = new Uint8Array(20000);
-
- this.readyState = FakeWebSocket.CONNECTING;
- this.bufferedAmount = 0;
-
- this.__is_fake = true;
- }
-
- close(code, reason) {
- this.readyState = FakeWebSocket.CLOSED;
- if (this.onclose) {
- this.onclose(make_event("close", { 'code': code, 'reason': reason, 'wasClean': true }));
- }
- }
-
- send(data) {
- if (this.protocol == 'base64') {
- data = Base64.decode(data);
- } else {
- data = new Uint8Array(data);
- }
- this._send_queue.set(data, this.bufferedAmount);
- this.bufferedAmount += data.length;
- }
-
- _get_sent_data() {
- const res = new Uint8Array(this._send_queue.buffer, 0, this.bufferedAmount);
- this.bufferedAmount = 0;
- return res;
- }
-
- _open() {
- this.readyState = FakeWebSocket.OPEN;
- if (this.onopen) {
- this.onopen(make_event('open'));
- }
- }
-
- _receive_data(data) {
- // Break apart the data to expose bugs where we assume data is
- // neatly packaged
- for (let i = 0;i < data.length;i++) {
- let buf = data.subarray(i, i+1);
- this.onmessage(make_event("message", { 'data': buf }));
- }
- }
-}
-
-FakeWebSocket.OPEN = WebSocket.OPEN;
-FakeWebSocket.CONNECTING = WebSocket.CONNECTING;
-FakeWebSocket.CLOSING = WebSocket.CLOSING;
-FakeWebSocket.CLOSED = WebSocket.CLOSED;
-
-FakeWebSocket.__is_fake = true;
-
-FakeWebSocket.replace = () => {
- if (!WebSocket.__is_fake) {
- const real_version = WebSocket;
- // eslint-disable-next-line no-global-assign
- WebSocket = FakeWebSocket;
- FakeWebSocket.__real_version = real_version;
- }
-};
-
-FakeWebSocket.restore = () => {
- if (WebSocket.__is_fake) {
- // eslint-disable-next-line no-global-assign
- WebSocket = WebSocket.__real_version;
- }
-};
diff --git a/systemvm/agent/noVNC/tests/karma-test-main.js b/systemvm/agent/noVNC/tests/karma-test-main.js
deleted file mode 100644
index 2843666..0000000
--- a/systemvm/agent/noVNC/tests/karma-test-main.js
+++ /dev/null
@@ -1,48 +0,0 @@
-const TEST_REGEXP = /test\..*\.js/;
-const allTestFiles = [];
-const extraFiles = ['/base/tests/assertions.js'];
-
-Object.keys(window.__karma__.files).forEach(function (file) {
- if (TEST_REGEXP.test(file)) {
- // TODO: normalize?
- allTestFiles.push(file);
- }
-});
-
-// Stub out mocha's start function so we can run it once we're done loading
-mocha.origRun = mocha.run;
-mocha.run = function () {};
-
-let script;
-
-// Script to import all our tests
-script = document.createElement("script");
-script.type = "module";
-script.text = "";
-let allModules = allTestFiles.concat(extraFiles);
-allModules.forEach(function (file) {
- script.text += "import \"" + file + "\";\n";
-});
-script.text += "\nmocha.origRun();\n";
-document.body.appendChild(script);
-
-// Fallback code for browsers that don't support modules (IE)
-script = document.createElement("script");
-script.type = "module";
-script.text = "window._noVNC_has_module_support = true;\n";
-document.body.appendChild(script);
-
-function fallback() {
- if (!window._noVNC_has_module_support) {
- /* eslint-disable no-console */
- if (console) {
- console.log("No module support detected. Loading fallback...");
- }
- /* eslint-enable no-console */
- let loader = document.createElement("script");
- loader.src = "base/vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
- document.body.appendChild(loader);
- }
-}
-
-setTimeout(fallback, 500);
diff --git a/systemvm/agent/noVNC/tests/playback-ui.js b/systemvm/agent/noVNC/tests/playback-ui.js
deleted file mode 100644
index 65c715a..0000000
--- a/systemvm/agent/noVNC/tests/playback-ui.js
+++ /dev/null
@@ -1,210 +0,0 @@
-/* global VNC_frame_data, VNC_frame_encoding */
-
-import * as WebUtil from '../app/webutil.js';
-import RecordingPlayer from './playback.js';
-import Base64 from '../core/base64.js';
-
-let frames = null;
-
-function message(str) {
- const cell = document.getElementById('messages');
- cell.textContent += str + "\n";
- cell.scrollTop = cell.scrollHeight;
-}
-
-function loadFile() {
- const fname = WebUtil.getQueryVar('data', null);
-
- if (!fname) {
- return Promise.reject("Must specify data=FOO in query string.");
- }
-
- message("Loading " + fname + "...");
-
- return new Promise((resolve, reject) => {
- const script = document.createElement("script");
- script.onload = resolve;
- script.onerror = reject;
- document.body.appendChild(script);
- script.src = "../recordings/" + fname;
- });
-}
-
-function enableUI() {
- const iterations = WebUtil.getQueryVar('iterations', 3);
- document.getElementById('iterations').value = iterations;
-
- const mode = WebUtil.getQueryVar('mode', 3);
- if (mode === 'realtime') {
- document.getElementById('mode2').checked = true;
- } else {
- document.getElementById('mode1').checked = true;
- }
-
- message("Loaded " + VNC_frame_data.length + " frames");
-
- const startButton = document.getElementById('startButton');
- startButton.disabled = false;
- startButton.addEventListener('click', start);
-
- message("Converting...");
-
- frames = VNC_frame_data;
-
- let encoding;
- // Only present in older recordings
- if (window.VNC_frame_encoding) {
- encoding = VNC_frame_encoding;
- } else {
- let frame = frames[0];
- let start = frame.indexOf('{', 1) + 1;
- if (frame.slice(start, start+4) === 'UkZC') {
- encoding = 'base64';
- } else {
- encoding = 'binary';
- }
- }
-
- for (let i = 0;i < frames.length;i++) {
- let frame = frames[i];
-
- if (frame === "EOF") {
- frames.splice(i);
- break;
- }
-
- let dataIdx = frame.indexOf('{', 1) + 1;
-
- let time = parseInt(frame.slice(1, dataIdx - 1));
-
- let u8;
- if (encoding === 'base64') {
- u8 = Base64.decode(frame.slice(dataIdx));
- } else {
- u8 = new Uint8Array(frame.length - dataIdx);
- for (let j = 0; j < frame.length - dataIdx; j++) {
- u8[j] = frame.charCodeAt(dataIdx + j);
- }
- }
-
- frames[i] = { fromClient: frame[0] === '}',
- timestamp: time,
- data: u8 };
- }
-
- message("Ready");
-}
-
-class IterationPlayer {
- constructor(iterations, frames) {
- this._iterations = iterations;
-
- this._iteration = undefined;
- this._player = undefined;
-
- this._start_time = undefined;
-
- this._frames = frames;
-
- this._state = 'running';
-
- this.onfinish = () => {};
- this.oniterationfinish = () => {};
- this.rfbdisconnected = () => {};
- }
-
- start(realtime) {
- this._iteration = 0;
- this._start_time = (new Date()).getTime();
-
- this._realtime = realtime;
-
- this._nextIteration();
- }
-
- _nextIteration() {
- const player = new RecordingPlayer(this._frames, this._disconnected.bind(this));
- player.onfinish = this._iterationFinish.bind(this);
-
- if (this._state !== 'running') { return; }
-
- this._iteration++;
- if (this._iteration > this._iterations) {
- this._finish();
- return;
- }
-
- player.run(this._realtime, false);
- }
-
- _finish() {
- const endTime = (new Date()).getTime();
- const totalDuration = endTime - this._start_time;
-
- const evt = new CustomEvent('finish',
- { detail:
- { duration: totalDuration,
- iterations: this._iterations } } );
- this.onfinish(evt);
- }
-
- _iterationFinish(duration) {
- const evt = new CustomEvent('iterationfinish',
- { detail:
- { duration: duration,
- number: this._iteration } } );
- this.oniterationfinish(evt);
-
- this._nextIteration();
- }
-
- _disconnected(clean, frame) {
- if (!clean) {
- this._state = 'failed';
- }
-
- const evt = new CustomEvent('rfbdisconnected',
- { detail:
- { clean: clean,
- frame: frame,
- iteration: this._iteration } } );
- this.onrfbdisconnected(evt);
- }
-}
-
-function start() {
- document.getElementById('startButton').value = "Running";
- document.getElementById('startButton').disabled = true;
-
- const iterations = document.getElementById('iterations').value;
-
- let realtime;
-
- if (document.getElementById('mode1').checked) {
- message(`Starting performance playback (fullspeed) [${iterations} iteration(s)]`);
- realtime = false;
- } else {
- message(`Starting realtime playback [${iterations} iteration(s)]`);
- realtime = true;
- }
-
- const player = new IterationPlayer(iterations, frames);
- player.oniterationfinish = (evt) => {
- message(`Iteration ${evt.detail.number} took ${evt.detail.duration}ms`);
- };
- player.onrfbdisconnected = (evt) => {
- if (!evt.detail.clean) {
- message(`noVNC sent disconnected during iteration ${evt.detail.iteration} frame ${evt.detail.frame}`);
- }
- };
- player.onfinish = (evt) => {
- const iterTime = parseInt(evt.detail.duration / evt.detail.iterations, 10);
- message(`${evt.detail.iterations} iterations took ${evt.detail.duration}ms (average ${iterTime}ms / iteration)`);
-
- document.getElementById('startButton').disabled = false;
- document.getElementById('startButton').value = "Start";
- };
- player.start(realtime);
-}
-
-loadFile().then(enableUI).catch(e => message("Error loading recording: " + e));
diff --git a/systemvm/agent/noVNC/tests/playback.js b/systemvm/agent/noVNC/tests/playback.js
deleted file mode 100644
index 5bd8103..0000000
--- a/systemvm/agent/noVNC/tests/playback.js
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2018 The noVNC Authors
- * Licensed under MPL 2.0 (see LICENSE.txt)
- */
-
-import RFB from '../core/rfb.js';
-import * as Log from '../core/util/logging.js';
-
-// Immediate polyfill
-if (window.setImmediate === undefined) {
- let _immediateIdCounter = 1;
- const _immediateFuncs = {};
-
- window.setImmediate = (func) => {
- const index = _immediateIdCounter++;
- _immediateFuncs[index] = func;
- window.postMessage("noVNC immediate trigger:" + index, "*");
- return index;
- };
-
- window.clearImmediate = (id) => {
- _immediateFuncs[id];
- };
-
- window.addEventListener("message", (event) => {
- if ((typeof event.data !== "string") ||
- (event.data.indexOf("noVNC immediate trigger:") !== 0)) {
- return;
- }
-
- const index = event.data.slice("noVNC immediate trigger:".length);
-
- const callback = _immediateFuncs[index];
- if (callback === undefined) {
- return;
- }
-
- delete _immediateFuncs[index];
-
- callback();
- });
-}
-
-export default class RecordingPlayer {
- constructor(frames, disconnected) {
- this._frames = frames;
-
- this._disconnected = disconnected;
-
- this._rfb = undefined;
- this._frame_length = this._frames.length;
-
- this._frame_index = 0;
- this._start_time = undefined;
- this._realtime = true;
- this._trafficManagement = true;
-
- this._running = false;
-
- this.onfinish = () => {};
- }
-
- run(realtime, trafficManagement) {
- // initialize a new RFB
- this._rfb = new RFB(document.getElementById('VNC_screen'), 'wss://test');
- this._rfb.viewOnly = true;
- this._rfb.addEventListener("disconnect",
- this._handleDisconnect.bind(this));
- this._rfb.addEventListener("credentialsrequired",
- this._handleCredentials.bind(this));
- this._enablePlaybackMode();
-
- // reset the frame index and timer
- this._frame_index = 0;
- this._start_time = (new Date()).getTime();
-
- this._realtime = realtime;
- this._trafficManagement = (trafficManagement === undefined) ? !realtime : trafficManagement;
-
- this._running = true;
- }
-
- // _enablePlaybackMode mocks out things not required for running playback
- _enablePlaybackMode() {
- const self = this;
- this._rfb._sock.send = () => {};
- this._rfb._sock.close = () => {};
- this._rfb._sock.flush = () => {};
- this._rfb._sock.open = function () {
- this.init();
- this._eventHandlers.open();
- self._queueNextPacket();
- };
- }
-
- _queueNextPacket() {
- if (!this._running) { return; }
-
- let frame = this._frames[this._frame_index];
-
- // skip send frames
- while (this._frame_index < this._frame_length && frame.fromClient) {
- this._frame_index++;
- frame = this._frames[this._frame_index];
- }
-
- if (this._frame_index >= this._frame_length) {
- Log.Debug('Finished, no more frames');
- this._finish();
- return;
- }
-
- if (this._realtime) {
- const toffset = (new Date()).getTime() - this._start_time;
- let delay = frame.timestamp - toffset;
- if (delay < 1) delay = 1;
-
- setTimeout(this._doPacket.bind(this), delay);
- } else {
- setImmediate(this._doPacket.bind(this));
- }
- }
-
- _doPacket() {
- // Avoid having excessive queue buildup in non-realtime mode
- if (this._trafficManagement && this._rfb._flushing) {
- const orig = this._rfb._display.onflush;
- this._rfb._display.onflush = () => {
- this._rfb._display.onflush = orig;
- this._rfb._onFlush();
- this._doPacket();
- };
- return;
- }
-
- const frame = this._frames[this._frame_index];
-
- this._rfb._sock._recv_message({'data': frame.data});
- this._frame_index++;
-
- this._queueNextPacket();
- }
-
- _finish() {
- if (this._rfb._display.pending()) {
- this._rfb._display.onflush = () => {
- if (this._rfb._flushing) {
- this._rfb._onFlush();
- }
- this._finish();
- };
- this._rfb._display.flush();
- } else {
- this._running = false;
- this._rfb._sock._eventHandlers.close({code: 1000, reason: ""});
- delete this._rfb;
- this.onfinish((new Date()).getTime() - this._start_time);
- }
- }
-
- _handleDisconnect(evt) {
- this._running = false;
- this._disconnected(evt.detail.clean, this._frame_index);
- }
-
- _handleCredentials(evt) {
- this._rfb.sendCredentials({"username": "Foo",
- "password": "Bar",
- "target": "Baz"});
- }
-}
diff --git a/systemvm/agent/noVNC/tests/test.base64.js b/systemvm/agent/noVNC/tests/test.base64.js
deleted file mode 100644
index 04bd207..0000000
--- a/systemvm/agent/noVNC/tests/test.base64.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const expect = chai.expect;
-
-import Base64 from '../core/base64.js';
-
-describe('Base64 Tools', function () {
- "use strict";
-
- const BIN_ARR = new Array(256);
- for (let i = 0; i < 256; i++) {
- BIN_ARR[i] = i;
- }
-
- const B64_STR = "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==";
-
-
- describe('encode', function () {
- it('should encode a binary string into Base64', function () {
- const encoded = Base64.encode(BIN_ARR);
- expect(encoded).to.equal(B64_STR);
- });
- });
-
- describe('decode', function () {
- it('should decode a Base64 string into a normal string', function () {
- const decoded = Base64.decode(B64_STR);
- expect(decoded).to.deep.equal(BIN_ARR);
- });
-
- it('should throw an error if we have extra characters at the end of the string', function () {
- expect(() => Base64.decode(B64_STR+'abcdef')).to.throw(Error);
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.display.js b/systemvm/agent/noVNC/tests/test.display.js
deleted file mode 100644
index b359550..0000000
--- a/systemvm/agent/noVNC/tests/test.display.js
+++ /dev/null
@@ -1,486 +0,0 @@
-const expect = chai.expect;
-
-import Base64 from '../core/base64.js';
-import Display from '../core/display.js';
-
-describe('Display/Canvas Helper', function () {
- const checked_data = new Uint8Array([
- 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
- 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
- 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
- 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
- ]);
-
- const basic_data = new Uint8Array([0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0xff, 0xff, 0xff, 255]);
-
- function make_image_canvas(input_data) {
- const canvas = document.createElement('canvas');
- canvas.width = 4;
- canvas.height = 4;
- const ctx = canvas.getContext('2d');
- const data = ctx.createImageData(4, 4);
- for (let i = 0; i < checked_data.length; i++) { data.data[i] = input_data[i]; }
- ctx.putImageData(data, 0, 0);
- return canvas;
- }
-
- function make_image_png(input_data) {
- const canvas = make_image_canvas(input_data);
- const url = canvas.toDataURL();
- const data = url.split(",")[1];
- return Base64.decode(data);
- }
-
- describe('viewport handling', function () {
- let display;
- beforeEach(function () {
- display = new Display(document.createElement('canvas'));
- display.clipViewport = true;
- display.resize(5, 5);
- display.viewportChangeSize(3, 3);
- display.viewportChangePos(1, 1);
- });
-
- it('should take viewport location into consideration when drawing images', function () {
- display.resize(4, 4);
- display.viewportChangeSize(2, 2);
- display.drawImage(make_image_canvas(basic_data), 1, 1);
- display.flip();
-
- const expected = new Uint8Array(16);
- for (let i = 0; i < 8; i++) { expected[i] = basic_data[i]; }
- for (let i = 8; i < 16; i++) { expected[i] = 0; }
- expect(display).to.have.displayed(expected);
- });
-
- it('should resize the target canvas when resizing the viewport', function () {
- display.viewportChangeSize(2, 2);
- expect(display._target.width).to.equal(2);
- expect(display._target.height).to.equal(2);
- });
-
- it('should move the viewport if necessary', function () {
- display.viewportChangeSize(5, 5);
- expect(display.absX(0)).to.equal(0);
- expect(display.absY(0)).to.equal(0);
- expect(display._target.width).to.equal(5);
- expect(display._target.height).to.equal(5);
- });
-
- it('should limit the viewport to the framebuffer size', function () {
- display.viewportChangeSize(6, 6);
- expect(display._target.width).to.equal(5);
- expect(display._target.height).to.equal(5);
- });
-
- it('should redraw when moving the viewport', function () {
- display.flip = sinon.spy();
- display.viewportChangePos(-1, 1);
- expect(display.flip).to.have.been.calledOnce;
- });
-
- it('should redraw when resizing the viewport', function () {
- display.flip = sinon.spy();
- display.viewportChangeSize(2, 2);
- expect(display.flip).to.have.been.calledOnce;
- });
-
- it('should show the entire framebuffer when disabling the viewport', function () {
- display.clipViewport = false;
- expect(display.absX(0)).to.equal(0);
- expect(display.absY(0)).to.equal(0);
- expect(display._target.width).to.equal(5);
- expect(display._target.height).to.equal(5);
- });
-
- it('should ignore viewport changes when the viewport is disabled', function () {
- display.clipViewport = false;
- display.viewportChangeSize(2, 2);
- display.viewportChangePos(1, 1);
- expect(display.absX(0)).to.equal(0);
- expect(display.absY(0)).to.equal(0);
- expect(display._target.width).to.equal(5);
- expect(display._target.height).to.equal(5);
- });
-
- it('should show the entire framebuffer just after enabling the viewport', function () {
- display.clipViewport = false;
- display.clipViewport = true;
- expect(display.absX(0)).to.equal(0);
- expect(display.absY(0)).to.equal(0);
- expect(display._target.width).to.equal(5);
- expect(display._target.height).to.equal(5);
- });
- });
-
- describe('resizing', function () {
- let display;
- beforeEach(function () {
- display = new Display(document.createElement('canvas'));
- display.clipViewport = false;
- display.resize(4, 4);
- });
-
- it('should change the size of the logical canvas', function () {
- display.resize(5, 7);
- expect(display._fb_width).to.equal(5);
- expect(display._fb_height).to.equal(7);
- });
-
- it('should keep the framebuffer data', function () {
- display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
- display.resize(2, 2);
- display.flip();
- const expected = [];
- for (let i = 0; i < 4 * 2*2; i += 4) {
- expected[i] = 0xff;
- expected[i+1] = expected[i+2] = 0;
- expected[i+3] = 0xff;
- }
- expect(display).to.have.displayed(new Uint8Array(expected));
- });
-
- describe('viewport', function () {
- beforeEach(function () {
- display.clipViewport = true;
- display.viewportChangeSize(3, 3);
- display.viewportChangePos(1, 1);
- });
-
- it('should keep the viewport position and size if possible', function () {
- display.resize(6, 6);
- expect(display.absX(0)).to.equal(1);
- expect(display.absY(0)).to.equal(1);
- expect(display._target.width).to.equal(3);
- expect(display._target.height).to.equal(3);
- });
-
- it('should move the viewport if necessary', function () {
- display.resize(3, 3);
- expect(display.absX(0)).to.equal(0);
- expect(display.absY(0)).to.equal(0);
- expect(display._target.width).to.equal(3);
- expect(display._target.height).to.equal(3);
- });
-
- it('should shrink the viewport if necessary', function () {
- display.resize(2, 2);
- expect(display.absX(0)).to.equal(0);
- expect(display.absY(0)).to.equal(0);
- expect(display._target.width).to.equal(2);
- expect(display._target.height).to.equal(2);
- });
- });
- });
-
- describe('rescaling', function () {
- let display;
- let canvas;
-
- beforeEach(function () {
- canvas = document.createElement('canvas');
- display = new Display(canvas);
- display.clipViewport = true;
- display.resize(4, 4);
- display.viewportChangeSize(3, 3);
- display.viewportChangePos(1, 1);
- document.body.appendChild(canvas);
- });
-
- afterEach(function () {
- document.body.removeChild(canvas);
- });
-
- it('should not change the bitmap size of the canvas', function () {
- display.scale = 2.0;
- expect(canvas.width).to.equal(3);
- expect(canvas.height).to.equal(3);
- });
-
- it('should change the effective rendered size of the canvas', function () {
- display.scale = 2.0;
- expect(canvas.clientWidth).to.equal(6);
- expect(canvas.clientHeight).to.equal(6);
- });
-
- it('should not change when resizing', function () {
- display.scale = 2.0;
- display.resize(5, 5);
- expect(display.scale).to.equal(2.0);
- expect(canvas.width).to.equal(3);
- expect(canvas.height).to.equal(3);
- expect(canvas.clientWidth).to.equal(6);
- expect(canvas.clientHeight).to.equal(6);
- });
- });
-
- describe('autoscaling', function () {
- let display;
- let canvas;
-
- beforeEach(function () {
- canvas = document.createElement('canvas');
- display = new Display(canvas);
- display.clipViewport = true;
- display.resize(4, 3);
- document.body.appendChild(canvas);
- });
-
- afterEach(function () {
- document.body.removeChild(canvas);
- });
-
- it('should preserve aspect ratio while autoscaling', function () {
- display.autoscale(16, 9);
- expect(canvas.clientWidth / canvas.clientHeight).to.equal(4 / 3);
- });
-
- it('should use width to determine scale when the current aspect ratio is wider than the target', function () {
- display.autoscale(9, 16);
- expect(display.absX(9)).to.equal(4);
- expect(display.absY(18)).to.equal(8);
- expect(canvas.clientWidth).to.equal(9);
- expect(canvas.clientHeight).to.equal(7); // round 9 / (4 / 3)
- });
-
- it('should use height to determine scale when the current aspect ratio is taller than the target', function () {
- display.autoscale(16, 9);
- expect(display.absX(9)).to.equal(3);
- expect(display.absY(18)).to.equal(6);
- expect(canvas.clientWidth).to.equal(12); // 16 * (4 / 3)
- expect(canvas.clientHeight).to.equal(9);
-
- });
-
- it('should not change the bitmap size of the canvas', function () {
- display.autoscale(16, 9);
- expect(canvas.width).to.equal(4);
- expect(canvas.height).to.equal(3);
- });
- });
-
- describe('drawing', function () {
-
- // TODO(directxman12): improve the tests for each of the drawing functions to cover more than just the
- // basic cases
- let display;
- beforeEach(function () {
- display = new Display(document.createElement('canvas'));
- display.resize(4, 4);
- });
-
- it('should clear the screen on #clear without a logo set', function () {
- display.fillRect(0, 0, 4, 4, [0x00, 0x00, 0xff]);
- display._logo = null;
- display.clear();
- display.resize(4, 4);
- const empty = [];
- for (let i = 0; i < 4 * display._fb_width * display._fb_height; i++) { empty[i] = 0; }
- expect(display).to.have.displayed(new Uint8Array(empty));
- });
-
- it('should draw the logo on #clear with a logo set', function (done) {
- display._logo = { width: 4, height: 4, type: "image/png", data: make_image_png(checked_data) };
- display.clear();
- display.onflush = () => {
- expect(display).to.have.displayed(checked_data);
- expect(display._fb_width).to.equal(4);
- expect(display._fb_height).to.equal(4);
- done();
- };
- display.flush();
- });
-
- it('should not draw directly on the target canvas', function () {
- display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
- display.flip();
- display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
- const expected = [];
- for (let i = 0; i < 4 * display._fb_width * display._fb_height; i += 4) {
- expected[i] = 0xff;
- expected[i+1] = expected[i+2] = 0;
- expected[i+3] = 0xff;
- }
- expect(display).to.have.displayed(new Uint8Array(expected));
- });
-
- it('should support filling a rectangle with particular color via #fillRect', function () {
- display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
- display.fillRect(0, 0, 2, 2, [0xff, 0, 0]);
- display.fillRect(2, 2, 2, 2, [0xff, 0, 0]);
- display.flip();
- expect(display).to.have.displayed(checked_data);
- });
-
- it('should support copying an portion of the canvas via #copyImage', function () {
- display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
- display.fillRect(0, 0, 2, 2, [0xff, 0, 0x00]);
- display.copyImage(0, 0, 2, 2, 2, 2);
- display.flip();
- expect(display).to.have.displayed(checked_data);
- });
-
- it('should support drawing images via #imageRect', function (done) {
- display.imageRect(0, 0, "image/png", make_image_png(checked_data));
- display.flip();
- display.onflush = () => {
- expect(display).to.have.displayed(checked_data);
- done();
- };
- display.flush();
- });
-
- it('should support drawing tile data with a background color and sub tiles', function () {
- display.startTile(0, 0, 4, 4, [0, 0xff, 0]);
- display.subTile(0, 0, 2, 2, [0xff, 0, 0]);
- display.subTile(2, 2, 2, 2, [0xff, 0, 0]);
- display.finishTile();
- display.flip();
- expect(display).to.have.displayed(checked_data);
- });
-
- // We have a special cache for 16x16 tiles that we need to test
- it('should support drawing a 16x16 tile', function () {
- const large_checked_data = new Uint8Array(16*16*4);
- display.resize(16, 16);
-
- for (let y = 0;y < 16;y++) {
- for (let x = 0;x < 16;x++) {
- let pixel;
- if ((x < 4) && (y < 4)) {
- // NB: of course IE11 doesn't support #slice on ArrayBufferViews...
- pixel = Array.prototype.slice.call(checked_data, (y*4+x)*4, (y*4+x+1)*4);
- } else {
- pixel = [0, 0xff, 0, 255];
- }
- large_checked_data.set(pixel, (y*16+x)*4);
- }
- }
-
- display.startTile(0, 0, 16, 16, [0, 0xff, 0]);
- display.subTile(0, 0, 2, 2, [0xff, 0, 0]);
- display.subTile(2, 2, 2, 2, [0xff, 0, 0]);
- display.finishTile();
- display.flip();
- expect(display).to.have.displayed(large_checked_data);
- });
-
- it('should support drawing BGRX blit images with true color via #blitImage', function () {
- const data = [];
- for (let i = 0; i < 16; i++) {
- data[i * 4] = checked_data[i * 4 + 2];
- data[i * 4 + 1] = checked_data[i * 4 + 1];
- data[i * 4 + 2] = checked_data[i * 4];
- data[i * 4 + 3] = checked_data[i * 4 + 3];
- }
- display.blitImage(0, 0, 4, 4, data, 0);
- display.flip();
- expect(display).to.have.displayed(checked_data);
- });
-
- it('should support drawing RGB blit images with true color via #blitRgbImage', function () {
- const data = [];
- for (let i = 0; i < 16; i++) {
- data[i * 3] = checked_data[i * 4];
- data[i * 3 + 1] = checked_data[i * 4 + 1];
- data[i * 3 + 2] = checked_data[i * 4 + 2];
- }
- display.blitRgbImage(0, 0, 4, 4, data, 0);
- display.flip();
- expect(display).to.have.displayed(checked_data);
- });
-
- it('should support drawing an image object via #drawImage', function () {
- const img = make_image_canvas(checked_data);
- display.drawImage(img, 0, 0);
- display.flip();
- expect(display).to.have.displayed(checked_data);
- });
- });
-
- describe('the render queue processor', function () {
- let display;
- beforeEach(function () {
- display = new Display(document.createElement('canvas'));
- display.resize(4, 4);
- sinon.spy(display, '_scan_renderQ');
- });
-
- afterEach(function () {
- window.requestAnimationFrame = this.old_requestAnimationFrame;
- });
-
- it('should try to process an item when it is pushed on, if nothing else is on the queue', function () {
- display._renderQ_push({ type: 'noop' }); // does nothing
- expect(display._scan_renderQ).to.have.been.calledOnce;
- });
-
- it('should not try to process an item when it is pushed on if we are waiting for other items', function () {
- display._renderQ.length = 2;
- display._renderQ_push({ type: 'noop' });
- expect(display._scan_renderQ).to.not.have.been.called;
- });
-
- it('should wait until an image is loaded to attempt to draw it and the rest of the queue', function () {
- const img = { complete: false, addEventListener: sinon.spy() };
- display._renderQ = [{ type: 'img', x: 3, y: 4, img: img },
- { type: 'fill', x: 1, y: 2, width: 3, height: 4, color: 5 }];
- display.drawImage = sinon.spy();
- display.fillRect = sinon.spy();
-
- display._scan_renderQ();
- expect(display.drawImage).to.not.have.been.called;
- expect(display.fillRect).to.not.have.been.called;
- expect(img.addEventListener).to.have.been.calledOnce;
-
- display._renderQ[0].img.complete = true;
- display._scan_renderQ();
- expect(display.drawImage).to.have.been.calledOnce;
- expect(display.fillRect).to.have.been.calledOnce;
- expect(img.addEventListener).to.have.been.calledOnce;
- });
-
- it('should call callback when queue is flushed', function () {
- display.onflush = sinon.spy();
- display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
- expect(display.onflush).to.not.have.been.called;
- display.flush();
- expect(display.onflush).to.have.been.calledOnce;
- });
-
- it('should draw a blit image on type "blit"', function () {
- display.blitImage = sinon.spy();
- display._renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
- expect(display.blitImage).to.have.been.calledOnce;
- expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
- });
-
- it('should draw a blit RGB image on type "blitRgb"', function () {
- display.blitRgbImage = sinon.spy();
- display._renderQ_push({ type: 'blitRgb', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
- expect(display.blitRgbImage).to.have.been.calledOnce;
- expect(display.blitRgbImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
- });
-
- it('should copy a region on type "copy"', function () {
- display.copyImage = sinon.spy();
- display._renderQ_push({ type: 'copy', x: 3, y: 4, width: 5, height: 6, old_x: 7, old_y: 8 });
- expect(display.copyImage).to.have.been.calledOnce;
- expect(display.copyImage).to.have.been.calledWith(7, 8, 3, 4, 5, 6);
- });
-
- it('should fill a rect with a given color on type "fill"', function () {
- display.fillRect = sinon.spy();
- display._renderQ_push({ type: 'fill', x: 3, y: 4, width: 5, height: 6, color: [7, 8, 9]});
- expect(display.fillRect).to.have.been.calledOnce;
- expect(display.fillRect).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9]);
- });
-
- it('should draw an image from an image object on type "img" (if complete)', function () {
- display.drawImage = sinon.spy();
- display._renderQ_push({ type: 'img', x: 3, y: 4, img: { complete: true } });
- expect(display.drawImage).to.have.been.calledOnce;
- expect(display.drawImage).to.have.been.calledWith({ complete: true }, 3, 4);
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.helper.js b/systemvm/agent/noVNC/tests/test.helper.js
deleted file mode 100644
index d44bab0..0000000
--- a/systemvm/agent/noVNC/tests/test.helper.js
+++ /dev/null
@@ -1,223 +0,0 @@
-const expect = chai.expect;
-
-import keysyms from '../core/input/keysymdef.js';
-import * as KeyboardUtil from "../core/input/util.js";
-import * as browser from '../core/util/browser.js';
-
-describe('Helpers', function () {
- "use strict";
-
- describe('keysyms.lookup', function () {
- it('should map ASCII characters to keysyms', function () {
- expect(keysyms.lookup('a'.charCodeAt())).to.be.equal(0x61);
- expect(keysyms.lookup('A'.charCodeAt())).to.be.equal(0x41);
- });
- it('should map Latin-1 characters to keysyms', function () {
- expect(keysyms.lookup('ø'.charCodeAt())).to.be.equal(0xf8);
-
- expect(keysyms.lookup('é'.charCodeAt())).to.be.equal(0xe9);
- });
- it('should map characters that are in Windows-1252 but not in Latin-1 to keysyms', function () {
- expect(keysyms.lookup('Š'.charCodeAt())).to.be.equal(0x01a9);
- });
- it('should map characters which aren\'t in Latin1 *or* Windows-1252 to keysyms', function () {
- expect(keysyms.lookup('ũ'.charCodeAt())).to.be.equal(0x03fd);
- });
- it('should map unknown codepoints to the Unicode range', function () {
- expect(keysyms.lookup('\n'.charCodeAt())).to.be.equal(0x100000a);
- expect(keysyms.lookup('\u262D'.charCodeAt())).to.be.equal(0x100262d);
- });
- // This requires very recent versions of most browsers... skipping for now
- it.skip('should map UCS-4 codepoints to the Unicode range', function () {
- //expect(keysyms.lookup('\u{1F686}'.codePointAt())).to.be.equal(0x101f686);
- });
- });
-
- describe('getKeycode', function () {
- it('should pass through proper code', function () {
- expect(KeyboardUtil.getKeycode({code: 'Semicolon'})).to.be.equal('Semicolon');
- });
- it('should map legacy values', function () {
- expect(KeyboardUtil.getKeycode({code: ''})).to.be.equal('Unidentified');
- expect(KeyboardUtil.getKeycode({code: 'OSLeft'})).to.be.equal('MetaLeft');
- });
- it('should map keyCode to code when possible', function () {
- expect(KeyboardUtil.getKeycode({keyCode: 0x14})).to.be.equal('CapsLock');
- expect(KeyboardUtil.getKeycode({keyCode: 0x5b})).to.be.equal('MetaLeft');
- expect(KeyboardUtil.getKeycode({keyCode: 0x35})).to.be.equal('Digit5');
- expect(KeyboardUtil.getKeycode({keyCode: 0x65})).to.be.equal('Numpad5');
- });
- it('should map keyCode left/right side', function () {
- expect(KeyboardUtil.getKeycode({keyCode: 0x10, location: 1})).to.be.equal('ShiftLeft');
- expect(KeyboardUtil.getKeycode({keyCode: 0x10, location: 2})).to.be.equal('ShiftRight');
- expect(KeyboardUtil.getKeycode({keyCode: 0x11, location: 1})).to.be.equal('ControlLeft');
- expect(KeyboardUtil.getKeycode({keyCode: 0x11, location: 2})).to.be.equal('ControlRight');
- });
- it('should map keyCode on numpad', function () {
- expect(KeyboardUtil.getKeycode({keyCode: 0x0d, location: 0})).to.be.equal('Enter');
- expect(KeyboardUtil.getKeycode({keyCode: 0x0d, location: 3})).to.be.equal('NumpadEnter');
- expect(KeyboardUtil.getKeycode({keyCode: 0x23, location: 0})).to.be.equal('End');
- expect(KeyboardUtil.getKeycode({keyCode: 0x23, location: 3})).to.be.equal('Numpad1');
- });
- it('should return Unidentified when it cannot map the keyCode', function () {
- expect(KeyboardUtil.getKeycode({keycode: 0x42})).to.be.equal('Unidentified');
- });
-
- describe('Fix Meta on macOS', function () {
- let origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.platform !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.navigator.platform = "Mac x86_64";
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- });
-
- it('should respect ContextMenu on modern browser', function () {
- expect(KeyboardUtil.getKeycode({code: 'ContextMenu', keyCode: 0x5d})).to.be.equal('ContextMenu');
- });
- it('should translate legacy ContextMenu to MetaRight', function () {
- expect(KeyboardUtil.getKeycode({keyCode: 0x5d})).to.be.equal('MetaRight');
- });
- });
- });
-
- describe('getKey', function () {
- it('should prefer key', function () {
- if (browser.isIE() || browser.isEdge()) this.skip();
- expect(KeyboardUtil.getKey({key: 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal('a');
- });
- it('should map legacy values', function () {
- expect(KeyboardUtil.getKey({key: 'Spacebar'})).to.be.equal(' ');
- expect(KeyboardUtil.getKey({key: 'Left'})).to.be.equal('ArrowLeft');
- expect(KeyboardUtil.getKey({key: 'OS'})).to.be.equal('Meta');
- expect(KeyboardUtil.getKey({key: 'Win'})).to.be.equal('Meta');
- expect(KeyboardUtil.getKey({key: 'UIKeyInputLeftArrow'})).to.be.equal('ArrowLeft');
- });
- it('should use code if no key', function () {
- expect(KeyboardUtil.getKey({code: 'NumpadBackspace'})).to.be.equal('Backspace');
- });
- it('should not use code fallback for character keys', function () {
- expect(KeyboardUtil.getKey({code: 'KeyA'})).to.be.equal('Unidentified');
- expect(KeyboardUtil.getKey({code: 'Digit1'})).to.be.equal('Unidentified');
- expect(KeyboardUtil.getKey({code: 'Period'})).to.be.equal('Unidentified');
- expect(KeyboardUtil.getKey({code: 'Numpad1'})).to.be.equal('Unidentified');
- });
- it('should use charCode if no key', function () {
- expect(KeyboardUtil.getKey({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.be.equal('Š');
- });
- it('should return Unidentified when it cannot map the key', function () {
- expect(KeyboardUtil.getKey({keycode: 0x42})).to.be.equal('Unidentified');
- });
-
- describe('Broken key AltGraph on IE/Edge', function () {
- let origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.platform !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- });
-
- it('should ignore printable character key on IE', function () {
- window.navigator.userAgent = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
- expect(KeyboardUtil.getKey({key: 'a'})).to.be.equal('Unidentified');
- });
- it('should ignore printable character key on Edge', function () {
- window.navigator.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393";
- expect(KeyboardUtil.getKey({key: 'a'})).to.be.equal('Unidentified');
- });
- it('should allow non-printable character key on IE', function () {
- window.navigator.userAgent = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
- expect(KeyboardUtil.getKey({key: 'Shift'})).to.be.equal('Shift');
- });
- it('should allow non-printable character key on Edge', function () {
- window.navigator.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393";
- expect(KeyboardUtil.getKey({key: 'Shift'})).to.be.equal('Shift');
- });
- });
- });
-
- describe('getKeysym', function () {
- describe('Non-character keys', function () {
- it('should recognize the right keys', function () {
- expect(KeyboardUtil.getKeysym({key: 'Enter'})).to.be.equal(0xFF0D);
- expect(KeyboardUtil.getKeysym({key: 'Backspace'})).to.be.equal(0xFF08);
- expect(KeyboardUtil.getKeysym({key: 'Tab'})).to.be.equal(0xFF09);
- expect(KeyboardUtil.getKeysym({key: 'Shift'})).to.be.equal(0xFFE1);
- expect(KeyboardUtil.getKeysym({key: 'Control'})).to.be.equal(0xFFE3);
- expect(KeyboardUtil.getKeysym({key: 'Alt'})).to.be.equal(0xFFE9);
- expect(KeyboardUtil.getKeysym({key: 'Meta'})).to.be.equal(0xFFEB);
- expect(KeyboardUtil.getKeysym({key: 'Escape'})).to.be.equal(0xFF1B);
- expect(KeyboardUtil.getKeysym({key: 'ArrowUp'})).to.be.equal(0xFF52);
- });
- it('should map left/right side', function () {
- expect(KeyboardUtil.getKeysym({key: 'Shift', location: 1})).to.be.equal(0xFFE1);
- expect(KeyboardUtil.getKeysym({key: 'Shift', location: 2})).to.be.equal(0xFFE2);
- expect(KeyboardUtil.getKeysym({key: 'Control', location: 1})).to.be.equal(0xFFE3);
- expect(KeyboardUtil.getKeysym({key: 'Control', location: 2})).to.be.equal(0xFFE4);
- });
- it('should handle AltGraph', function () {
- expect(KeyboardUtil.getKeysym({code: 'AltRight', key: 'Alt', location: 2})).to.be.equal(0xFFEA);
- expect(KeyboardUtil.getKeysym({code: 'AltRight', key: 'AltGraph', location: 2})).to.be.equal(0xFE03);
- });
- it('should return null for unknown keys', function () {
- expect(KeyboardUtil.getKeysym({key: 'Semicolon'})).to.be.null;
- expect(KeyboardUtil.getKeysym({key: 'BracketRight'})).to.be.null;
- });
- it('should handle remappings', function () {
- expect(KeyboardUtil.getKeysym({code: 'ControlLeft', key: 'Tab'})).to.be.equal(0xFF09);
- });
- });
-
- describe('Numpad', function () {
- it('should handle Numpad numbers', function () {
- if (browser.isIE() || browser.isEdge()) this.skip();
- expect(KeyboardUtil.getKeysym({code: 'Digit5', key: '5', location: 0})).to.be.equal(0x0035);
- expect(KeyboardUtil.getKeysym({code: 'Numpad5', key: '5', location: 3})).to.be.equal(0xFFB5);
- });
- it('should handle Numpad non-character keys', function () {
- expect(KeyboardUtil.getKeysym({code: 'Home', key: 'Home', location: 0})).to.be.equal(0xFF50);
- expect(KeyboardUtil.getKeysym({code: 'Numpad5', key: 'Home', location: 3})).to.be.equal(0xFF95);
- expect(KeyboardUtil.getKeysym({code: 'Delete', key: 'Delete', location: 0})).to.be.equal(0xFFFF);
- expect(KeyboardUtil.getKeysym({code: 'NumpadDecimal', key: 'Delete', location: 3})).to.be.equal(0xFF9F);
- });
- it('should handle Numpad Decimal key', function () {
- if (browser.isIE() || browser.isEdge()) this.skip();
- expect(KeyboardUtil.getKeysym({code: 'NumpadDecimal', key: '.', location: 3})).to.be.equal(0xFFAE);
- expect(KeyboardUtil.getKeysym({code: 'NumpadDecimal', key: ',', location: 3})).to.be.equal(0xFFAC);
- });
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.keyboard.js b/systemvm/agent/noVNC/tests/test.keyboard.js
deleted file mode 100644
index 77fe3f6..0000000
--- a/systemvm/agent/noVNC/tests/test.keyboard.js
+++ /dev/null
@@ -1,510 +0,0 @@
-const expect = chai.expect;
-
-import Keyboard from '../core/input/keyboard.js';
-import * as browser from '../core/util/browser.js';
-
-describe('Key Event Handling', function () {
- "use strict";
-
- // The real KeyboardEvent constructor might not work everywhere we
- // want to run these tests
- function keyevent(typeArg, KeyboardEventInit) {
- const e = { type: typeArg };
- for (let key in KeyboardEventInit) {
- e[key] = KeyboardEventInit[key];
- }
- e.stopPropagation = sinon.spy();
- e.preventDefault = sinon.spy();
- return e;
- }
-
- describe('Decode Keyboard Events', function () {
- it('should decode keydown events', function (done) {
- if (browser.isIE() || browser.isEdge()) this.skip();
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- });
- it('should decode keyup events', function (done) {
- if (browser.isIE() || browser.isEdge()) this.skip();
- let calls = 0;
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- if (calls++ === 1) {
- expect(down).to.be.equal(false);
- done();
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
- });
-
- describe('Legacy keypress Events', function () {
- it('should wait for keypress when needed', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
- it('should decode keypress events', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
- kbd._handleKeyPress(keyevent('keypress', {code: 'KeyA', charCode: 0x61}));
- });
- it('should ignore keypress with different code', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
- kbd._handleKeyPress(keyevent('keypress', {code: 'KeyB', charCode: 0x61}));
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
- it('should handle keypress with missing code', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41}));
- kbd._handleKeyPress(keyevent('keypress', {charCode: 0x61}));
- });
- it('should guess key if no keypress and numeric key', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x32);
- expect(code).to.be.equal('Digit2');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'Digit2', keyCode: 0x32}));
- });
- it('should guess key if no keypress and alpha key', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41, shiftKey: false}));
- });
- it('should guess key if no keypress and alpha key (with shift)', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x41);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x41, shiftKey: true}));
- });
- it('should not guess key if no keypress and unknown key', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', keyCode: 0x09}));
- });
- });
-
- describe('suppress the right events at the right time', function () {
- beforeEach(function () {
- if (browser.isIE() || browser.isEdge()) this.skip();
- });
- it('should suppress anything with a valid key', function () {
- const kbd = new Keyboard(document, {});
- const evt1 = keyevent('keydown', {code: 'KeyA', key: 'a'});
- kbd._handleKeyDown(evt1);
- expect(evt1.preventDefault).to.have.been.called;
- const evt2 = keyevent('keyup', {code: 'KeyA', key: 'a'});
- kbd._handleKeyUp(evt2);
- expect(evt2.preventDefault).to.have.been.called;
- });
- it('should not suppress keys without key', function () {
- const kbd = new Keyboard(document, {});
- const evt = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
- kbd._handleKeyDown(evt);
- expect(evt.preventDefault).to.not.have.been.called;
- });
- it('should suppress the following keypress event', function () {
- const kbd = new Keyboard(document, {});
- const evt1 = keyevent('keydown', {code: 'KeyA', keyCode: 0x41});
- kbd._handleKeyDown(evt1);
- const evt2 = keyevent('keypress', {code: 'KeyA', charCode: 0x41});
- kbd._handleKeyPress(evt2);
- expect(evt2.preventDefault).to.have.been.called;
- });
- });
- });
-
- describe('Fake keyup', function () {
- it('should fake keyup events for virtual keyboards', function (done) {
- if (browser.isIE() || browser.isEdge()) this.skip();
- let count = 0;
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- switch (count++) {
- case 0:
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('Unidentified');
- expect(down).to.be.equal(true);
- break;
- case 1:
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('Unidentified');
- expect(down).to.be.equal(false);
- done();
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'Unidentified', key: 'a'}));
- });
-
- describe('iOS', function () {
- let origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.platform !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.navigator.platform = "iPhone 9.0";
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- });
-
- it('should fake keyup events on iOS', function (done) {
- if (browser.isIE() || browser.isEdge()) this.skip();
- let count = 0;
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- switch (count++) {
- case 0:
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- break;
- case 1:
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(false);
- done();
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- });
- });
- });
-
- describe('Track Key State', function () {
- beforeEach(function () {
- if (browser.isIE() || browser.isEdge()) this.skip();
- });
- it('should send release using the same keysym as the press', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- if (!down) {
- done();
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'b'}));
- });
- it('should send the same keysym for multiple presses', function () {
- let count = 0;
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('KeyA');
- expect(down).to.be.equal(true);
- count++;
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'}));
- expect(count).to.be.equal(2);
- });
- it('should do nothing on keyup events if no keys are down', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
-
- describe('Legacy Events', function () {
- it('should track keys using keyCode if no code', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('Platform65');
- if (!down) {
- done();
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {keyCode: 65, key: 'a'}));
- kbd._handleKeyUp(keyevent('keyup', {keyCode: 65, key: 'b'}));
- });
- it('should ignore compositing code', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('Unidentified');
- };
- kbd._handleKeyDown(keyevent('keydown', {keyCode: 229, key: 'a'}));
- });
- it('should track keys using keyIdentifier if no code', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0x61);
- expect(code).to.be.equal('Platform65');
- if (!down) {
- done();
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {keyIdentifier: 'U+0041', key: 'a'}));
- kbd._handleKeyUp(keyevent('keyup', {keyIdentifier: 'U+0041', key: 'b'}));
- });
- });
- });
-
- describe('Shuffle modifiers on macOS', function () {
- let origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.platform !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.navigator.platform = "Mac x86_64";
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- });
-
- it('should change Alt to AltGraph', function () {
- let count = 0;
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- switch (count++) {
- case 0:
- expect(keysym).to.be.equal(0xFF7E);
- expect(code).to.be.equal('AltLeft');
- break;
- case 1:
- expect(keysym).to.be.equal(0xFE03);
- expect(code).to.be.equal('AltRight');
- break;
- }
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1}));
- kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
- expect(count).to.be.equal(2);
- });
- it('should change left Super to Alt', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0xFFE9);
- expect(code).to.be.equal('MetaLeft');
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'MetaLeft', key: 'Meta', location: 1}));
- });
- it('should change right Super to left Super', function (done) {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = (keysym, code, down) => {
- expect(keysym).to.be.equal(0xFFEB);
- expect(code).to.be.equal('MetaRight');
- done();
- };
- kbd._handleKeyDown(keyevent('keydown', {code: 'MetaRight', key: 'Meta', location: 2}));
- });
- });
-
- describe('Escape AltGraph on Windows', function () {
- let origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.platform !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.navigator.platform = "Windows x86_64";
-
- this.clock = sinon.useFakeTimers();
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- this.clock.restore();
- });
-
- it('should supress ControlLeft until it knows if it is AltGr', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
-
- it('should not trigger on repeating ControlLeft', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
- expect(kbd.onkeyevent).to.have.been.calledTwice;
- expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
- expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
- });
-
- it('should not supress ControlRight', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlRight', key: 'Control', location: 2}));
- expect(kbd.onkeyevent).to.have.been.calledOnce;
- expect(kbd.onkeyevent).to.have.been.calledWith(0xffe4, "ControlRight", true);
- });
-
- it('should release ControlLeft after 100 ms', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
- expect(kbd.onkeyevent).to.not.have.been.called;
- this.clock.tick(100);
- expect(kbd.onkeyevent).to.have.been.calledOnce;
- expect(kbd.onkeyevent).to.have.been.calledWith(0xffe3, "ControlLeft", true);
- });
-
- it('should release ControlLeft on other key press', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
- expect(kbd.onkeyevent).to.not.have.been.called;
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- expect(kbd.onkeyevent).to.have.been.calledTwice;
- expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
- expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0x61, "KeyA", true);
-
- // Check that the timer is properly dead
- kbd.onkeyevent.reset();
- this.clock.tick(100);
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
-
- it('should release ControlLeft on other key release', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'}));
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1}));
- expect(kbd.onkeyevent).to.have.been.calledOnce;
- expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0x61, "KeyA", true);
- kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'}));
- expect(kbd.onkeyevent).to.have.been.calledThrice;
- expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
- expect(kbd.onkeyevent.thirdCall).to.have.been.calledWith(0x61, "KeyA", false);
-
- // Check that the timer is properly dead
- kbd.onkeyevent.reset();
- this.clock.tick(100);
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
-
- it('should generate AltGraph for quick Ctrl+Alt sequence', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()}));
- this.clock.tick(20);
- kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()}));
- expect(kbd.onkeyevent).to.have.been.calledOnce;
- expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true);
-
- // Check that the timer is properly dead
- kbd.onkeyevent.reset();
- this.clock.tick(100);
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
-
- it('should generate Ctrl, Alt for slow Ctrl+Alt sequence', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()}));
- this.clock.tick(60);
- kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()}));
- expect(kbd.onkeyevent).to.have.been.calledTwice;
- expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true);
- expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffea, "AltRight", true);
-
- // Check that the timer is properly dead
- kbd.onkeyevent.reset();
- this.clock.tick(100);
- expect(kbd.onkeyevent).to.not.have.been.called;
- });
-
- it('should pass through single Alt', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2}));
- expect(kbd.onkeyevent).to.have.been.calledOnce;
- expect(kbd.onkeyevent).to.have.been.calledWith(0xffea, 'AltRight', true);
- });
-
- it('should pass through single AltGr', function () {
- const kbd = new Keyboard(document);
- kbd.onkeyevent = sinon.spy();
- kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'AltGraph', location: 2}));
- expect(kbd.onkeyevent).to.have.been.calledOnce;
- expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true);
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.localization.js b/systemvm/agent/noVNC/tests/test.localization.js
deleted file mode 100644
index 9570c17..0000000
--- a/systemvm/agent/noVNC/tests/test.localization.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const expect = chai.expect;
-import { l10n } from '../app/localization.js';
-
-describe('Localization', function () {
- "use strict";
-
- describe('language selection', function () {
- let origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.languages !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.navigator.languages = [];
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- });
-
- it('should use English by default', function () {
- expect(l10n.language).to.equal('en');
- });
- it('should use English if no user language matches', function () {
- window.navigator.languages = ["nl", "de"];
- l10n.setup(["es", "fr"]);
- expect(l10n.language).to.equal('en');
- });
- it('should use the most preferred user language', function () {
- window.navigator.languages = ["nl", "de", "fr"];
- l10n.setup(["es", "fr", "de"]);
- expect(l10n.language).to.equal('de');
- });
- it('should prefer sub-languages languages', function () {
- window.navigator.languages = ["pt-BR"];
- l10n.setup(["pt", "pt-BR"]);
- expect(l10n.language).to.equal('pt-BR');
- });
- it('should fall back to language "parents"', function () {
- window.navigator.languages = ["pt-BR"];
- l10n.setup(["fr", "pt", "de"]);
- expect(l10n.language).to.equal('pt');
- });
- it('should not use specific language when user asks for a generic language', function () {
- window.navigator.languages = ["pt", "de"];
- l10n.setup(["fr", "pt-BR", "de"]);
- expect(l10n.language).to.equal('de');
- });
- it('should handle underscore as a separator', function () {
- window.navigator.languages = ["pt-BR"];
- l10n.setup(["pt_BR"]);
- expect(l10n.language).to.equal('pt_BR');
- });
- it('should handle difference in case', function () {
- window.navigator.languages = ["pt-br"];
- l10n.setup(["pt-BR"]);
- expect(l10n.language).to.equal('pt-BR');
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.mouse.js b/systemvm/agent/noVNC/tests/test.mouse.js
deleted file mode 100644
index 78c74f1..0000000
--- a/systemvm/agent/noVNC/tests/test.mouse.js
+++ /dev/null
@@ -1,304 +0,0 @@
-const expect = chai.expect;
-
-import Mouse from '../core/input/mouse.js';
-
-describe('Mouse Event Handling', function () {
- "use strict";
-
- let target;
-
- beforeEach(function () {
- // For these tests we can assume that the canvas is 100x100
- // located at coordinates 10x10
- target = document.createElement('canvas');
- target.style.position = "absolute";
- target.style.top = "10px";
- target.style.left = "10px";
- target.style.width = "100px";
- target.style.height = "100px";
- document.body.appendChild(target);
- });
- afterEach(function () {
- document.body.removeChild(target);
- target = null;
- });
-
- // The real constructors might not work everywhere we
- // want to run these tests
- const mouseevent = (typeArg, MouseEventInit) => {
- const e = { type: typeArg };
- for (let key in MouseEventInit) {
- e[key] = MouseEventInit[key];
- }
- e.stopPropagation = sinon.spy();
- e.preventDefault = sinon.spy();
- return e;
- };
- const touchevent = mouseevent;
-
- describe('Decode Mouse Events', function () {
- it('should decode mousedown events', function (done) {
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- expect(bmask).to.be.equal(0x01);
- expect(down).to.be.equal(1);
- done();
- };
- mouse._handleMouseDown(mouseevent('mousedown', { button: '0x01' }));
- });
- it('should decode mouseup events', function (done) {
- let calls = 0;
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- expect(bmask).to.be.equal(0x01);
- if (calls++ === 1) {
- expect(down).to.not.be.equal(1);
- done();
- }
- };
- mouse._handleMouseDown(mouseevent('mousedown', { button: '0x01' }));
- mouse._handleMouseUp(mouseevent('mouseup', { button: '0x01' }));
- });
- it('should decode mousemove events', function (done) {
- const mouse = new Mouse(target);
- mouse.onmousemove = (x, y) => {
- // Note that target relative coordinates are sent
- expect(x).to.be.equal(40);
- expect(y).to.be.equal(10);
- done();
- };
- mouse._handleMouseMove(mouseevent('mousemove',
- { clientX: 50, clientY: 20 }));
- });
- it('should decode mousewheel events', function (done) {
- let calls = 0;
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- calls++;
- expect(bmask).to.be.equal(1<<6);
- if (calls === 1) {
- expect(down).to.be.equal(1);
- } else if (calls === 2) {
- expect(down).to.not.be.equal(1);
- done();
- }
- };
- mouse._handleMouseWheel(mouseevent('mousewheel',
- { deltaX: 50, deltaY: 0,
- deltaMode: 0}));
- });
- });
-
- describe('Double-click for Touch', function () {
-
- beforeEach(function () { this.clock = sinon.useFakeTimers(); });
- afterEach(function () { this.clock.restore(); });
-
- it('should use same pos for 2nd tap if close enough', function (done) {
- let calls = 0;
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- calls++;
- if (calls === 1) {
- expect(down).to.be.equal(1);
- expect(x).to.be.equal(68);
- expect(y).to.be.equal(36);
- } else if (calls === 3) {
- expect(down).to.be.equal(1);
- expect(x).to.be.equal(68);
- expect(y).to.be.equal(36);
- done();
- }
- };
- // touch events are sent in an array of events
- // with one item for each touch point
- mouse._handleMouseDown(touchevent(
- 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]}));
- this.clock.tick(10);
- mouse._handleMouseUp(touchevent(
- 'touchend', { touches: [{ clientX: 79, clientY: 45 }]}));
- this.clock.tick(200);
- mouse._handleMouseDown(touchevent(
- 'touchstart', { touches: [{ clientX: 67, clientY: 35 }]}));
- this.clock.tick(10);
- mouse._handleMouseUp(touchevent(
- 'touchend', { touches: [{ clientX: 66, clientY: 36 }]}));
- });
-
- it('should not modify 2nd tap pos if far apart', function (done) {
- let calls = 0;
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- calls++;
- if (calls === 1) {
- expect(down).to.be.equal(1);
- expect(x).to.be.equal(68);
- expect(y).to.be.equal(36);
- } else if (calls === 3) {
- expect(down).to.be.equal(1);
- expect(x).to.not.be.equal(68);
- expect(y).to.not.be.equal(36);
- done();
- }
- };
- mouse._handleMouseDown(touchevent(
- 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]}));
- this.clock.tick(10);
- mouse._handleMouseUp(touchevent(
- 'touchend', { touches: [{ clientX: 79, clientY: 45 }]}));
- this.clock.tick(200);
- mouse._handleMouseDown(touchevent(
- 'touchstart', { touches: [{ clientX: 57, clientY: 35 }]}));
- this.clock.tick(10);
- mouse._handleMouseUp(touchevent(
- 'touchend', { touches: [{ clientX: 56, clientY: 36 }]}));
- });
-
- it('should not modify 2nd tap pos if not soon enough', function (done) {
- let calls = 0;
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- calls++;
- if (calls === 1) {
- expect(down).to.be.equal(1);
- expect(x).to.be.equal(68);
- expect(y).to.be.equal(36);
- } else if (calls === 3) {
- expect(down).to.be.equal(1);
- expect(x).to.not.be.equal(68);
- expect(y).to.not.be.equal(36);
- done();
- }
- };
- mouse._handleMouseDown(touchevent(
- 'touchstart', { touches: [{ clientX: 78, clientY: 46 }]}));
- this.clock.tick(10);
- mouse._handleMouseUp(touchevent(
- 'touchend', { touches: [{ clientX: 79, clientY: 45 }]}));
- this.clock.tick(500);
- mouse._handleMouseDown(touchevent(
- 'touchstart', { touches: [{ clientX: 67, clientY: 35 }]}));
- this.clock.tick(10);
- mouse._handleMouseUp(touchevent(
- 'touchend', { touches: [{ clientX: 66, clientY: 36 }]}));
- });
-
- it('should not modify 2nd tap pos if not touch', function (done) {
- let calls = 0;
- const mouse = new Mouse(target);
- mouse.onmousebutton = (x, y, down, bmask) => {
- calls++;
- if (calls === 1) {
- expect(down).to.be.equal(1);
- expect(x).to.be.equal(68);
- expect(y).to.be.equal(36);
- } else if (calls === 3) {
- expect(down).to.be.equal(1);
- expect(x).to.not.be.equal(68);
- expect(y).to.not.be.equal(36);
- done();
- }
- };
- mouse._handleMouseDown(mouseevent(
- 'mousedown', { button: '0x01', clientX: 78, clientY: 46 }));
- this.clock.tick(10);
- mouse._handleMouseUp(mouseevent(
- 'mouseup', { button: '0x01', clientX: 79, clientY: 45 }));
- this.clock.tick(200);
- mouse._handleMouseDown(mouseevent(
- 'mousedown', { button: '0x01', clientX: 67, clientY: 35 }));
- this.clock.tick(10);
- mouse._handleMouseUp(mouseevent(
- 'mouseup', { button: '0x01', clientX: 66, clientY: 36 }));
- });
-
- });
-
- describe('Accumulate mouse wheel events with small delta', function () {
-
- beforeEach(function () { this.clock = sinon.useFakeTimers(); });
- afterEach(function () { this.clock.restore(); });
-
- it('should accumulate wheel events if small enough', function () {
- const mouse = new Mouse(target);
- mouse.onmousebutton = sinon.spy();
-
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 4, deltaY: 0, deltaMode: 0 }));
- this.clock.tick(10);
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 4, deltaY: 0, deltaMode: 0 }));
-
- // threshold is 10
- expect(mouse._accumulatedWheelDeltaX).to.be.equal(8);
-
- this.clock.tick(10);
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 4, deltaY: 0, deltaMode: 0 }));
-
- expect(mouse.onmousebutton).to.have.callCount(2); // mouse down and up
-
- this.clock.tick(10);
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 4, deltaY: 9, deltaMode: 0 }));
-
- expect(mouse._accumulatedWheelDeltaX).to.be.equal(4);
- expect(mouse._accumulatedWheelDeltaY).to.be.equal(9);
-
- expect(mouse.onmousebutton).to.have.callCount(2); // still
- });
-
- it('should not accumulate large wheel events', function () {
- const mouse = new Mouse(target);
- mouse.onmousebutton = sinon.spy();
-
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 11, deltaY: 0, deltaMode: 0 }));
- this.clock.tick(10);
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 0, deltaY: 70, deltaMode: 0 }));
- this.clock.tick(10);
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 400, deltaY: 400, deltaMode: 0 }));
-
- expect(mouse.onmousebutton).to.have.callCount(8); // mouse down and up
- });
-
- it('should send even small wheel events after a timeout', function () {
- const mouse = new Mouse(target);
- mouse.onmousebutton = sinon.spy();
-
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 1, deltaY: 0, deltaMode: 0 }));
- this.clock.tick(51); // timeout on 50 ms
-
- expect(mouse.onmousebutton).to.have.callCount(2); // mouse down and up
- });
-
- it('should account for non-zero deltaMode', function () {
- const mouse = new Mouse(target);
- mouse.onmousebutton = sinon.spy();
-
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 0, deltaY: 2, deltaMode: 1 }));
-
- this.clock.tick(10);
-
- mouse._handleMouseWheel(mouseevent(
- 'mousewheel', { clientX: 18, clientY: 40,
- deltaX: 1, deltaY: 0, deltaMode: 2 }));
-
- expect(mouse.onmousebutton).to.have.callCount(4); // mouse down and up
- });
- });
-
-});
diff --git a/systemvm/agent/noVNC/tests/test.rfb.js b/systemvm/agent/noVNC/tests/test.rfb.js
deleted file mode 100644
index 99c9c90..0000000
--- a/systemvm/agent/noVNC/tests/test.rfb.js
+++ /dev/null
@@ -1,2389 +0,0 @@
-const expect = chai.expect;
-
-import RFB from '../core/rfb.js';
-import Websock from '../core/websock.js';
-import { encodings } from '../core/encodings.js';
-
-import FakeWebSocket from './fake.websocket.js';
-
-/* UIEvent constructor polyfill for IE */
-(() => {
- if (typeof window.UIEvent === "function") return;
-
- function UIEvent( event, params ) {
- params = params || { bubbles: false, cancelable: false, view: window, detail: undefined };
- const evt = document.createEvent( 'UIEvent' );
- evt.initUIEvent( event, params.bubbles, params.cancelable, params.view, params.detail );
- return evt;
- }
-
- UIEvent.prototype = window.UIEvent.prototype;
-
- window.UIEvent = UIEvent;
-})();
-
-function push8(arr, num) {
- "use strict";
- arr.push(num & 0xFF);
-}
-
-function push16(arr, num) {
- "use strict";
- arr.push((num >> 8) & 0xFF,
- num & 0xFF);
-}
-
-function push32(arr, num) {
- "use strict";
- arr.push((num >> 24) & 0xFF,
- (num >> 16) & 0xFF,
- (num >> 8) & 0xFF,
- num & 0xFF);
-}
-
-describe('Remote Frame Buffer Protocol Client', function () {
- let clock;
- let raf;
-
- before(FakeWebSocket.replace);
- after(FakeWebSocket.restore);
-
- before(function () {
- this.clock = clock = sinon.useFakeTimers();
- // sinon doesn't support this yet
- raf = window.requestAnimationFrame;
- window.requestAnimationFrame = setTimeout;
- // Use a single set of buffers instead of reallocating to
- // speed up tests
- const sock = new Websock();
- const _sQ = new Uint8Array(sock._sQbufferSize);
- const rQ = new Uint8Array(sock._rQbufferSize);
-
- Websock.prototype._old_allocate_buffers = Websock.prototype._allocate_buffers;
- Websock.prototype._allocate_buffers = function () {
- this._sQ = _sQ;
- this._rQ = rQ;
- };
-
- });
-
- after(function () {
- Websock.prototype._allocate_buffers = Websock.prototype._old_allocate_buffers;
- this.clock.restore();
- window.requestAnimationFrame = raf;
- });
-
- let container;
- let rfbs;
-
- beforeEach(function () {
- // Create a container element for all RFB objects to attach to
- container = document.createElement('div');
- container.style.width = "100%";
- container.style.height = "100%";
- document.body.appendChild(container);
-
- // And track all created RFB objects
- rfbs = [];
- });
- afterEach(function () {
- // Make sure every created RFB object is properly cleaned up
- // or they might affect subsequent tests
- rfbs.forEach(function (rfb) {
- rfb.disconnect();
- expect(rfb._disconnect).to.have.been.called;
- });
- rfbs = [];
-
- document.body.removeChild(container);
- container = null;
- });
-
- function make_rfb(url, options) {
- url = url || 'wss://host:8675';
- const rfb = new RFB(container, url, options);
- clock.tick();
- rfb._sock._websocket._open();
- rfb._rfb_connection_state = 'connected';
- sinon.spy(rfb, "_disconnect");
- rfbs.push(rfb);
- return rfb;
- }
-
- describe('Connecting/Disconnecting', function () {
- describe('#RFB', function () {
- it('should set the current state to "connecting"', function () {
- const client = new RFB(document.createElement('div'), 'wss://host:8675');
- client._rfb_connection_state = '';
- this.clock.tick();
- expect(client._rfb_connection_state).to.equal('connecting');
- });
-
- it('should actually connect to the websocket', function () {
- const client = new RFB(document.createElement('div'), 'ws://HOST:8675/PATH');
- sinon.spy(client._sock, 'open');
- this.clock.tick();
- expect(client._sock.open).to.have.been.calledOnce;
- expect(client._sock.open).to.have.been.calledWith('ws://HOST:8675/PATH');
- });
- });
-
- describe('#disconnect', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- it('should go to state "disconnecting" before "disconnected"', function () {
- sinon.spy(client, '_updateConnectionState');
- client.disconnect();
- expect(client._updateConnectionState).to.have.been.calledTwice;
- expect(client._updateConnectionState.getCall(0).args[0])
- .to.equal('disconnecting');
- expect(client._updateConnectionState.getCall(1).args[0])
- .to.equal('disconnected');
- expect(client._rfb_connection_state).to.equal('disconnected');
- });
-
- it('should unregister error event handler', function () {
- sinon.spy(client._sock, 'off');
- client.disconnect();
- expect(client._sock.off).to.have.been.calledWith('error');
- });
-
- it('should unregister message event handler', function () {
- sinon.spy(client._sock, 'off');
- client.disconnect();
- expect(client._sock.off).to.have.been.calledWith('message');
- });
-
- it('should unregister open event handler', function () {
- sinon.spy(client._sock, 'off');
- client.disconnect();
- expect(client._sock.off).to.have.been.calledWith('open');
- });
- });
-
- describe('#sendCredentials', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- client._rfb_connection_state = 'connecting';
- });
-
- it('should set the rfb credentials properly"', function () {
- client.sendCredentials({ password: 'pass' });
- expect(client._rfb_credentials).to.deep.equal({ password: 'pass' });
- });
-
- it('should call init_msg "soon"', function () {
- client._init_msg = sinon.spy();
- client.sendCredentials({ password: 'pass' });
- this.clock.tick(5);
- expect(client._init_msg).to.have.been.calledOnce;
- });
- });
- });
-
- describe('Public API Basic Behavior', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- describe('#sendCtrlAlDel', function () {
- it('should sent ctrl[down]-alt[down]-del[down] then del[up]-alt[up]-ctrl[up]', function () {
- const expected = {_sQ: new Uint8Array(48), _sQlen: 0, flush: () => {}};
- RFB.messages.keyEvent(expected, 0xFFE3, 1);
- RFB.messages.keyEvent(expected, 0xFFE9, 1);
- RFB.messages.keyEvent(expected, 0xFFFF, 1);
- RFB.messages.keyEvent(expected, 0xFFFF, 0);
- RFB.messages.keyEvent(expected, 0xFFE9, 0);
- RFB.messages.keyEvent(expected, 0xFFE3, 0);
-
- client.sendCtrlAltDel();
- expect(client._sock).to.have.sent(expected._sQ);
- });
-
- it('should not send the keys if we are not in a normal state', function () {
- sinon.spy(client._sock, 'flush');
- client._rfb_connection_state = "connecting";
- client.sendCtrlAltDel();
- expect(client._sock.flush).to.not.have.been.called;
- });
-
- it('should not send the keys if we are set as view_only', function () {
- sinon.spy(client._sock, 'flush');
- client._viewOnly = true;
- client.sendCtrlAltDel();
- expect(client._sock.flush).to.not.have.been.called;
- });
- });
-
- describe('#sendKey', function () {
- it('should send a single key with the given code and state (down = true)', function () {
- const expected = {_sQ: new Uint8Array(8), _sQlen: 0, flush: () => {}};
- RFB.messages.keyEvent(expected, 123, 1);
- client.sendKey(123, 'Key123', true);
- expect(client._sock).to.have.sent(expected._sQ);
- });
-
- it('should send both a down and up event if the state is not specified', function () {
- const expected = {_sQ: new Uint8Array(16), _sQlen: 0, flush: () => {}};
- RFB.messages.keyEvent(expected, 123, 1);
- RFB.messages.keyEvent(expected, 123, 0);
- client.sendKey(123, 'Key123');
- expect(client._sock).to.have.sent(expected._sQ);
- });
-
- it('should not send the key if we are not in a normal state', function () {
- sinon.spy(client._sock, 'flush');
- client._rfb_connection_state = "connecting";
- client.sendKey(123, 'Key123');
- expect(client._sock.flush).to.not.have.been.called;
- });
-
- it('should not send the key if we are set as view_only', function () {
- sinon.spy(client._sock, 'flush');
- client._viewOnly = true;
- client.sendKey(123, 'Key123');
- expect(client._sock.flush).to.not.have.been.called;
- });
-
- it('should send QEMU extended events if supported', function () {
- client._qemuExtKeyEventSupported = true;
- const expected = {_sQ: new Uint8Array(12), _sQlen: 0, flush: () => {}};
- RFB.messages.QEMUExtendedKeyEvent(expected, 0x20, true, 0x0039);
- client.sendKey(0x20, 'Space', true);
- expect(client._sock).to.have.sent(expected._sQ);
- });
-
- it('should not send QEMU extended events if unknown key code', function () {
- client._qemuExtKeyEventSupported = true;
- const expected = {_sQ: new Uint8Array(8), _sQlen: 0, flush: () => {}};
- RFB.messages.keyEvent(expected, 123, 1);
- client.sendKey(123, 'FooBar', true);
- expect(client._sock).to.have.sent(expected._sQ);
- });
- });
-
- describe('#focus', function () {
- it('should move focus to canvas object', function () {
- client._canvas.focus = sinon.spy();
- client.focus();
- expect(client._canvas.focus).to.have.been.called.once;
- });
- });
-
- describe('#blur', function () {
- it('should remove focus from canvas object', function () {
- client._canvas.blur = sinon.spy();
- client.blur();
- expect(client._canvas.blur).to.have.been.called.once;
- });
- });
-
- describe('#clipboardPasteFrom', function () {
- it('should send the given text in a paste event', function () {
- const expected = {_sQ: new Uint8Array(11), _sQlen: 0,
- _sQbufferSize: 11, flush: () => {}};
- RFB.messages.clientCutText(expected, 'abc');
- client.clipboardPasteFrom('abc');
- expect(client._sock).to.have.sent(expected._sQ);
- });
-
- it('should flush multiple times for large clipboards', function () {
- sinon.spy(client._sock, 'flush');
- let long_text = "";
- for (let i = 0; i < client._sock._sQbufferSize + 100; i++) {
- long_text += 'a';
- }
- client.clipboardPasteFrom(long_text);
- expect(client._sock.flush).to.have.been.calledTwice;
- });
-
- it('should not send the text if we are not in a normal state', function () {
- sinon.spy(client._sock, 'flush');
- client._rfb_connection_state = "connecting";
- client.clipboardPasteFrom('abc');
- expect(client._sock.flush).to.not.have.been.called;
- });
- });
-
- describe("XVP operations", function () {
- beforeEach(function () {
- client._rfb_xvp_ver = 1;
- });
-
- it('should send the shutdown signal on #machineShutdown', function () {
- client.machineShutdown();
- expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x02]));
- });
-
- it('should send the reboot signal on #machineReboot', function () {
- client.machineReboot();
- expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x03]));
- });
-
- it('should send the reset signal on #machineReset', function () {
- client.machineReset();
- expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x04]));
- });
-
- it('should not send XVP operations with higher versions than we support', function () {
- sinon.spy(client._sock, 'flush');
- client._xvpOp(2, 7);
- expect(client._sock.flush).to.not.have.been.called;
- });
- });
- });
-
- describe('Clipping', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- container.style.width = '70px';
- container.style.height = '80px';
- client.clipViewport = true;
- });
-
- it('should update display clip state when changing the property', function () {
- const spy = sinon.spy(client._display, "clipViewport", ["set"]);
-
- client.clipViewport = false;
- expect(spy.set).to.have.been.calledOnce;
- expect(spy.set).to.have.been.calledWith(false);
- spy.set.reset();
-
- client.clipViewport = true;
- expect(spy.set).to.have.been.calledOnce;
- expect(spy.set).to.have.been.calledWith(true);
- });
-
- it('should update the viewport when the container size changes', function () {
- sinon.spy(client._display, "viewportChangeSize");
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick();
-
- expect(client._display.viewportChangeSize).to.have.been.calledOnce;
- expect(client._display.viewportChangeSize).to.have.been.calledWith(40, 50);
- });
-
- it('should update the viewport when the remote session resizes', function () {
- // Simple ExtendedDesktopSize FBU message
- const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0x00 ];
-
- sinon.spy(client._display, "viewportChangeSize");
-
- client._sock._websocket._receive_data(new Uint8Array(incoming));
-
- // FIXME: Display implicitly calls viewportChangeSize() when
- // resizing the framebuffer, hence calledTwice.
- expect(client._display.viewportChangeSize).to.have.been.calledTwice;
- expect(client._display.viewportChangeSize).to.have.been.calledWith(70, 80);
- });
-
- it('should not update the viewport if not clipping', function () {
- client.clipViewport = false;
- sinon.spy(client._display, "viewportChangeSize");
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick();
-
- expect(client._display.viewportChangeSize).to.not.have.been.called;
- });
-
- it('should not update the viewport if scaling', function () {
- client.scaleViewport = true;
- sinon.spy(client._display, "viewportChangeSize");
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick();
-
- expect(client._display.viewportChangeSize).to.not.have.been.called;
- });
-
- describe('Dragging', function () {
- beforeEach(function () {
- client.dragViewport = true;
- sinon.spy(RFB.messages, "pointerEvent");
- });
-
- afterEach(function () {
- RFB.messages.pointerEvent.restore();
- });
-
- it('should not send button messages when initiating viewport dragging', function () {
- client._handleMouseButton(13, 9, 0x001);
- expect(RFB.messages.pointerEvent).to.not.have.been.called;
- });
-
- it('should send button messages when release without movement', function () {
- // Just up and down
- client._handleMouseButton(13, 9, 0x001);
- client._handleMouseButton(13, 9, 0x000);
- expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
-
- RFB.messages.pointerEvent.reset();
-
- // Small movement
- client._handleMouseButton(13, 9, 0x001);
- client._handleMouseMove(15, 14);
- client._handleMouseButton(15, 14, 0x000);
- expect(RFB.messages.pointerEvent).to.have.been.calledTwice;
- });
-
- it('should send button message directly when drag is disabled', function () {
- client.dragViewport = false;
- client._handleMouseButton(13, 9, 0x001);
- expect(RFB.messages.pointerEvent).to.have.been.calledOnce;
- });
-
- it('should be initiate viewport dragging on sufficient movement', function () {
- sinon.spy(client._display, "viewportChangePos");
-
- // Too small movement
-
- client._handleMouseButton(13, 9, 0x001);
- client._handleMouseMove(18, 9);
-
- expect(RFB.messages.pointerEvent).to.not.have.been.called;
- expect(client._display.viewportChangePos).to.not.have.been.called;
-
- // Sufficient movement
-
- client._handleMouseMove(43, 9);
-
- expect(RFB.messages.pointerEvent).to.not.have.been.called;
- expect(client._display.viewportChangePos).to.have.been.calledOnce;
- expect(client._display.viewportChangePos).to.have.been.calledWith(-30, 0);
-
- client._display.viewportChangePos.reset();
-
- // Now a small movement should move right away
-
- client._handleMouseMove(43, 14);
-
- expect(RFB.messages.pointerEvent).to.not.have.been.called;
- expect(client._display.viewportChangePos).to.have.been.calledOnce;
- expect(client._display.viewportChangePos).to.have.been.calledWith(0, -5);
- });
-
- it('should not send button messages when dragging ends', function () {
- // First the movement
-
- client._handleMouseButton(13, 9, 0x001);
- client._handleMouseMove(43, 9);
- client._handleMouseButton(43, 9, 0x000);
-
- expect(RFB.messages.pointerEvent).to.not.have.been.called;
- });
-
- it('should terminate viewport dragging on a button up event', function () {
- // First the dragging movement
-
- client._handleMouseButton(13, 9, 0x001);
- client._handleMouseMove(43, 9);
- client._handleMouseButton(43, 9, 0x000);
-
- // Another movement now should not move the viewport
-
- sinon.spy(client._display, "viewportChangePos");
-
- client._handleMouseMove(43, 59);
-
- expect(client._display.viewportChangePos).to.not.have.been.called;
- });
- });
- });
-
- describe('Scaling', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- container.style.width = '70px';
- container.style.height = '80px';
- client.scaleViewport = true;
- });
-
- it('should update display scale factor when changing the property', function () {
- const spy = sinon.spy(client._display, "scale", ["set"]);
- sinon.spy(client._display, "autoscale");
-
- client.scaleViewport = false;
- expect(spy.set).to.have.been.calledOnce;
- expect(spy.set).to.have.been.calledWith(1.0);
- expect(client._display.autoscale).to.not.have.been.called;
-
- client.scaleViewport = true;
- expect(client._display.autoscale).to.have.been.calledOnce;
- expect(client._display.autoscale).to.have.been.calledWith(70, 80);
- });
-
- it('should update the clipping setting when changing the property', function () {
- client.clipViewport = true;
-
- const spy = sinon.spy(client._display, "clipViewport", ["set"]);
-
- client.scaleViewport = false;
- expect(spy.set).to.have.been.calledOnce;
- expect(spy.set).to.have.been.calledWith(true);
-
- spy.set.reset();
-
- client.scaleViewport = true;
- expect(spy.set).to.have.been.calledOnce;
- expect(spy.set).to.have.been.calledWith(false);
- });
-
- it('should update the scaling when the container size changes', function () {
- sinon.spy(client._display, "autoscale");
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick();
-
- expect(client._display.autoscale).to.have.been.calledOnce;
- expect(client._display.autoscale).to.have.been.calledWith(40, 50);
- });
-
- it('should update the scaling when the remote session resizes', function () {
- // Simple ExtendedDesktopSize FBU message
- const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0x00 ];
-
- sinon.spy(client._display, "autoscale");
-
- client._sock._websocket._receive_data(new Uint8Array(incoming));
-
- expect(client._display.autoscale).to.have.been.calledOnce;
- expect(client._display.autoscale).to.have.been.calledWith(70, 80);
- });
-
- it('should not update the display scale factor if not scaling', function () {
- client.scaleViewport = false;
-
- sinon.spy(client._display, "autoscale");
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick();
-
- expect(client._display.autoscale).to.not.have.been.called;
- });
- });
-
- describe('Remote resize', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- client._supportsSetDesktopSize = true;
- client.resizeSession = true;
- container.style.width = '70px';
- container.style.height = '80px';
- sinon.spy(RFB.messages, "setDesktopSize");
- });
-
- afterEach(function () {
- RFB.messages.setDesktopSize.restore();
- });
-
- it('should only request a resize when turned on', function () {
- client.resizeSession = false;
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
- client.resizeSession = true;
- expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
- });
-
- it('should request a resize when initially connecting', function () {
- // Simple ExtendedDesktopSize FBU message
- const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
- 0x00, 0x00, 0x00, 0x00 ];
-
- // First message should trigger a resize
-
- client._supportsSetDesktopSize = false;
-
- client._sock._websocket._receive_data(new Uint8Array(incoming));
-
- expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
- expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 70, 80, 0, 0);
-
- RFB.messages.setDesktopSize.reset();
-
- // Second message should not trigger a resize
-
- client._sock._websocket._receive_data(new Uint8Array(incoming));
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
- });
-
- it('should request a resize when the container resizes', function () {
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick(1000);
-
- expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
- expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 40, 50, 0, 0);
- });
-
- it('should not resize until the container size is stable', function () {
- container.style.width = '20px';
- container.style.height = '30px';
- const event1 = new UIEvent('resize');
- window.dispatchEvent(event1);
- clock.tick(400);
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event2 = new UIEvent('resize');
- window.dispatchEvent(event2);
- clock.tick(400);
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
-
- clock.tick(200);
-
- expect(RFB.messages.setDesktopSize).to.have.been.calledOnce;
- expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 40, 50, 0, 0);
- });
-
- it('should not resize when resize is disabled', function () {
- client._resizeSession = false;
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick(1000);
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
- });
-
- it('should not resize when resize is not supported', function () {
- client._supportsSetDesktopSize = false;
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick(1000);
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
- });
-
- it('should not resize when in view only mode', function () {
- client._viewOnly = true;
-
- container.style.width = '40px';
- container.style.height = '50px';
- const event = new UIEvent('resize');
- window.dispatchEvent(event);
- clock.tick(1000);
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
- });
-
- it('should not try to override a server resize', function () {
- // Simple ExtendedDesktopSize FBU message
- const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xfe, 0xcc,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
- 0x00, 0x00, 0x00, 0x00 ];
-
- client._sock._websocket._receive_data(new Uint8Array(incoming));
-
- expect(RFB.messages.setDesktopSize).to.not.have.been.called;
- });
- });
-
- describe('Misc Internals', function () {
- describe('#_updateConnectionState', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- it('should clear the disconnect timer if the state is not "disconnecting"', function () {
- const spy = sinon.spy();
- client._disconnTimer = setTimeout(spy, 50);
- client._rfb_connection_state = 'connecting';
- client._updateConnectionState('connected');
- this.clock.tick(51);
- expect(spy).to.not.have.been.called;
- expect(client._disconnTimer).to.be.null;
- });
-
- it('should set the rfb_connection_state', function () {
- client._rfb_connection_state = 'connecting';
- client._updateConnectionState('connected');
- expect(client._rfb_connection_state).to.equal('connected');
- });
-
- it('should not change the state when we are disconnected', function () {
- client.disconnect();
- expect(client._rfb_connection_state).to.equal('disconnected');
- client._updateConnectionState('connecting');
- expect(client._rfb_connection_state).to.not.equal('connecting');
- });
-
- it('should ignore state changes to the same state', function () {
- const connectSpy = sinon.spy();
- client.addEventListener("connect", connectSpy);
-
- expect(client._rfb_connection_state).to.equal('connected');
- client._updateConnectionState('connected');
- expect(connectSpy).to.not.have.been.called;
-
- client.disconnect();
-
- const disconnectSpy = sinon.spy();
- client.addEventListener("disconnect", disconnectSpy);
-
- expect(client._rfb_connection_state).to.equal('disconnected');
- client._updateConnectionState('disconnected');
- expect(disconnectSpy).to.not.have.been.called;
- });
-
- it('should ignore illegal state changes', function () {
- const spy = sinon.spy();
- client.addEventListener("disconnect", spy);
- client._updateConnectionState('disconnected');
- expect(client._rfb_connection_state).to.not.equal('disconnected');
- expect(spy).to.not.have.been.called;
- });
- });
-
- describe('#_fail', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- it('should close the WebSocket connection', function () {
- sinon.spy(client._sock, 'close');
- client._fail();
- expect(client._sock.close).to.have.been.calledOnce;
- });
-
- it('should transition to disconnected', function () {
- sinon.spy(client, '_updateConnectionState');
- client._fail();
- this.clock.tick(2000);
- expect(client._updateConnectionState).to.have.been.called;
- expect(client._rfb_connection_state).to.equal('disconnected');
- });
-
- it('should set clean_disconnect variable', function () {
- client._rfb_clean_disconnect = true;
- client._rfb_connection_state = 'connected';
- client._fail();
- expect(client._rfb_clean_disconnect).to.be.false;
- });
-
- it('should result in disconnect event with clean set to false', function () {
- client._rfb_connection_state = 'connected';
- const spy = sinon.spy();
- client.addEventListener("disconnect", spy);
- client._fail();
- this.clock.tick(2000);
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.clean).to.be.false;
- });
-
- });
- });
-
- describe('Connection States', function () {
- describe('connecting', function () {
- it('should open the websocket connection', function () {
- const client = new RFB(document.createElement('div'),
- 'ws://HOST:8675/PATH');
- sinon.spy(client._sock, 'open');
- this.clock.tick();
- expect(client._sock.open).to.have.been.calledOnce;
- });
- });
-
- describe('connected', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- it('should result in a connect event if state becomes connected', function () {
- const spy = sinon.spy();
- client.addEventListener("connect", spy);
- client._rfb_connection_state = 'connecting';
- client._updateConnectionState('connected');
- expect(spy).to.have.been.calledOnce;
- });
-
- it('should not result in a connect event if the state is not "connected"', function () {
- const spy = sinon.spy();
- client.addEventListener("connect", spy);
- client._sock._websocket.open = () => {}; // explicitly don't call onopen
- client._updateConnectionState('connecting');
- expect(spy).to.not.have.been.called;
- });
- });
-
- describe('disconnecting', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- it('should force disconnect if we do not call Websock.onclose within the disconnection timeout', function () {
- sinon.spy(client, '_updateConnectionState');
- client._sock._websocket.close = () => {}; // explicitly don't call onclose
- client._updateConnectionState('disconnecting');
- this.clock.tick(3 * 1000);
- expect(client._updateConnectionState).to.have.been.calledTwice;
- expect(client._rfb_disconnect_reason).to.not.equal("");
- expect(client._rfb_connection_state).to.equal("disconnected");
- });
-
- it('should not fail if Websock.onclose gets called within the disconnection timeout', function () {
- client._updateConnectionState('disconnecting');
- this.clock.tick(3 * 1000 / 2);
- client._sock._websocket.close();
- this.clock.tick(3 * 1000 / 2 + 1);
- expect(client._rfb_connection_state).to.equal('disconnected');
- });
-
- it('should close the WebSocket connection', function () {
- sinon.spy(client._sock, 'close');
- client._updateConnectionState('disconnecting');
- expect(client._sock.close).to.have.been.calledOnce;
- });
-
- it('should not result in a disconnect event', function () {
- const spy = sinon.spy();
- client.addEventListener("disconnect", spy);
- client._sock._websocket.close = () => {}; // explicitly don't call onclose
- client._updateConnectionState('disconnecting');
- expect(spy).to.not.have.been.called;
- });
- });
-
- describe('disconnected', function () {
- let client;
- beforeEach(function () {
- client = new RFB(document.createElement('div'), 'ws://HOST:8675/PATH');
- });
-
- it('should result in a disconnect event if state becomes "disconnected"', function () {
- const spy = sinon.spy();
- client.addEventListener("disconnect", spy);
- client._rfb_connection_state = 'disconnecting';
- client._updateConnectionState('disconnected');
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.clean).to.be.true;
- });
-
- it('should result in a disconnect event without msg when no reason given', function () {
- const spy = sinon.spy();
- client.addEventListener("disconnect", spy);
- client._rfb_connection_state = 'disconnecting';
- client._rfb_disconnect_reason = "";
- client._updateConnectionState('disconnected');
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0].length).to.equal(1);
- });
- });
- });
-
- describe('Protocol Initialization States', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- client._rfb_connection_state = 'connecting';
- });
-
- describe('ProtocolVersion', function () {
- function send_ver(ver, client) {
- const arr = new Uint8Array(12);
- for (let i = 0; i < ver.length; i++) {
- arr[i+4] = ver.charCodeAt(i);
- }
- arr[0] = 'R'; arr[1] = 'F'; arr[2] = 'B'; arr[3] = ' ';
- arr[11] = '\n';
- client._sock._websocket._receive_data(arr);
- }
-
- describe('version parsing', function () {
- it('should interpret version 003.003 as version 3.3', function () {
- send_ver('003.003', client);
- expect(client._rfb_version).to.equal(3.3);
- });
-
- it('should interpret version 003.006 as version 3.3', function () {
- send_ver('003.006', client);
- expect(client._rfb_version).to.equal(3.3);
- });
-
- it('should interpret version 003.889 as version 3.3', function () {
- send_ver('003.889', client);
- expect(client._rfb_version).to.equal(3.3);
- });
-
- it('should interpret version 003.007 as version 3.7', function () {
- send_ver('003.007', client);
- expect(client._rfb_version).to.equal(3.7);
- });
-
- it('should interpret version 003.008 as version 3.8', function () {
- send_ver('003.008', client);
- expect(client._rfb_version).to.equal(3.8);
- });
-
- it('should interpret version 004.000 as version 3.8', function () {
- send_ver('004.000', client);
- expect(client._rfb_version).to.equal(3.8);
- });
-
- it('should interpret version 004.001 as version 3.8', function () {
- send_ver('004.001', client);
- expect(client._rfb_version).to.equal(3.8);
- });
-
- it('should interpret version 005.000 as version 3.8', function () {
- send_ver('005.000', client);
- expect(client._rfb_version).to.equal(3.8);
- });
-
- it('should fail on an invalid version', function () {
- sinon.spy(client, "_fail");
- send_ver('002.000', client);
- expect(client._fail).to.have.been.calledOnce;
- });
- });
-
- it('should send back the interpreted version', function () {
- send_ver('004.000', client);
-
- const expected_str = 'RFB 003.008\n';
- const expected = [];
- for (let i = 0; i < expected_str.length; i++) {
- expected[i] = expected_str.charCodeAt(i);
- }
-
- expect(client._sock).to.have.sent(new Uint8Array(expected));
- });
-
- it('should transition to the Security state on successful negotiation', function () {
- send_ver('003.008', client);
- expect(client._rfb_init_state).to.equal('Security');
- });
-
- describe('Repeater', function () {
- beforeEach(function () {
- client = make_rfb('wss://host:8675', { repeaterID: "12345" });
- client._rfb_connection_state = 'connecting';
- });
-
- it('should interpret version 000.000 as a repeater', function () {
- send_ver('000.000', client);
- expect(client._rfb_version).to.equal(0);
-
- const sent_data = client._sock._websocket._get_sent_data();
- expect(new Uint8Array(sent_data.buffer, 0, 9)).to.array.equal(new Uint8Array([73, 68, 58, 49, 50, 51, 52, 53, 0]));
- expect(sent_data).to.have.length(250);
- });
-
- it('should handle two step repeater negotiation', function () {
- send_ver('000.000', client);
- send_ver('003.008', client);
- expect(client._rfb_version).to.equal(3.8);
- });
- });
- });
-
- describe('Security', function () {
- beforeEach(function () {
- client._rfb_init_state = 'Security';
- });
-
- it('should simply receive the auth scheme when for versions < 3.7', function () {
- client._rfb_version = 3.6;
- const auth_scheme_raw = [1, 2, 3, 4];
- const auth_scheme = (auth_scheme_raw[0] << 24) + (auth_scheme_raw[1] << 16) +
- (auth_scheme_raw[2] << 8) + auth_scheme_raw[3];
- client._sock._websocket._receive_data(new Uint8Array(auth_scheme_raw));
- expect(client._rfb_auth_scheme).to.equal(auth_scheme);
- });
-
- it('should prefer no authentication is possible', function () {
- client._rfb_version = 3.7;
- const auth_schemes = [2, 1, 3];
- client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
- expect(client._rfb_auth_scheme).to.equal(1);
- expect(client._sock).to.have.sent(new Uint8Array([1, 1]));
- });
-
- it('should choose for the most prefered scheme possible for versions >= 3.7', function () {
- client._rfb_version = 3.7;
- const auth_schemes = [2, 22, 16];
- client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
- expect(client._rfb_auth_scheme).to.equal(22);
- expect(client._sock).to.have.sent(new Uint8Array([22]));
- });
-
- it('should fail if there are no supported schemes for versions >= 3.7', function () {
- sinon.spy(client, "_fail");
- client._rfb_version = 3.7;
- const auth_schemes = [1, 32];
- client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
- expect(client._fail).to.have.been.calledOnce;
- });
-
- it('should fail with the appropriate message if no types are sent for versions >= 3.7', function () {
- client._rfb_version = 3.7;
- const failure_data = [0, 0, 0, 0, 6, 119, 104, 111, 111, 112, 115];
- sinon.spy(client, '_fail');
- client._sock._websocket._receive_data(new Uint8Array(failure_data));
-
- expect(client._fail).to.have.been.calledOnce;
- expect(client._fail).to.have.been.calledWith(
- 'Security negotiation failed on no security types (reason: whoops)');
- });
-
- it('should transition to the Authentication state and continue on successful negotiation', function () {
- client._rfb_version = 3.7;
- const auth_schemes = [1, 1];
- client._negotiate_authentication = sinon.spy();
- client._sock._websocket._receive_data(new Uint8Array(auth_schemes));
- expect(client._rfb_init_state).to.equal('Authentication');
- expect(client._negotiate_authentication).to.have.been.calledOnce;
- });
- });
-
- describe('Authentication', function () {
- beforeEach(function () {
- client._rfb_init_state = 'Security';
- });
-
- function send_security(type, cl) {
- cl._sock._websocket._receive_data(new Uint8Array([1, type]));
- }
-
- it('should fail on auth scheme 0 (pre 3.7) with the given message', function () {
- client._rfb_version = 3.6;
- const err_msg = "Whoopsies";
- const data = [0, 0, 0, 0];
- const err_len = err_msg.length;
- push32(data, err_len);
- for (let i = 0; i < err_len; i++) {
- data.push(err_msg.charCodeAt(i));
- }
-
- sinon.spy(client, '_fail');
- client._sock._websocket._receive_data(new Uint8Array(data));
- expect(client._fail).to.have.been.calledWith(
- 'Security negotiation failed on authentication scheme (reason: Whoopsies)');
- });
-
- it('should transition straight to SecurityResult on "no auth" (1) for versions >= 3.8', function () {
- client._rfb_version = 3.8;
- send_security(1, client);
- expect(client._rfb_init_state).to.equal('SecurityResult');
- });
-
- it('should transition straight to ServerInitialisation on "no auth" for versions < 3.8', function () {
- client._rfb_version = 3.7;
- send_security(1, client);
- expect(client._rfb_init_state).to.equal('ServerInitialisation');
- });
-
- it('should fail on an unknown auth scheme', function () {
- sinon.spy(client, "_fail");
- client._rfb_version = 3.8;
- send_security(57, client);
- expect(client._fail).to.have.been.calledOnce;
- });
-
- describe('VNC Authentication (type 2) Handler', function () {
- beforeEach(function () {
- client._rfb_init_state = 'Security';
- client._rfb_version = 3.8;
- });
-
- it('should fire the credentialsrequired event if missing a password', function () {
- const spy = sinon.spy();
- client.addEventListener("credentialsrequired", spy);
- send_security(2, client);
-
- const challenge = [];
- for (let i = 0; i < 16; i++) { challenge[i] = i; }
- client._sock._websocket._receive_data(new Uint8Array(challenge));
-
- expect(client._rfb_credentials).to.be.empty;
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.types).to.have.members(["password"]);
- });
-
- it('should encrypt the password with DES and then send it back', function () {
- client._rfb_credentials = { password: 'passwd' };
- send_security(2, client);
- client._sock._websocket._get_sent_data(); // skip the choice of auth reply
-
- const challenge = [];
- for (let i = 0; i < 16; i++) { challenge[i] = i; }
- client._sock._websocket._receive_data(new Uint8Array(challenge));
-
- const des_pass = RFB.genDES('passwd', challenge);
- expect(client._sock).to.have.sent(new Uint8Array(des_pass));
- });
-
- it('should transition to SecurityResult immediately after sending the password', function () {
- client._rfb_credentials = { password: 'passwd' };
- send_security(2, client);
-
- const challenge = [];
- for (let i = 0; i < 16; i++) { challenge[i] = i; }
- client._sock._websocket._receive_data(new Uint8Array(challenge));
-
- expect(client._rfb_init_state).to.equal('SecurityResult');
- });
- });
-
- describe('XVP Authentication (type 22) Handler', function () {
- beforeEach(function () {
- client._rfb_init_state = 'Security';
- client._rfb_version = 3.8;
- });
-
- it('should fall through to standard VNC authentication upon completion', function () {
- client._rfb_credentials = { username: 'user',
- target: 'target',
- password: 'password' };
- client._negotiate_std_vnc_auth = sinon.spy();
- send_security(22, client);
- expect(client._negotiate_std_vnc_auth).to.have.been.calledOnce;
- });
-
- it('should fire the credentialsrequired event if all credentials are missing', function () {
- const spy = sinon.spy();
- client.addEventListener("credentialsrequired", spy);
- client._rfb_credentials = {};
- send_security(22, client);
-
- expect(client._rfb_credentials).to.be.empty;
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.types).to.have.members(["username", "password", "target"]);
- });
-
- it('should fire the credentialsrequired event if some credentials are missing', function () {
- const spy = sinon.spy();
- client.addEventListener("credentialsrequired", spy);
- client._rfb_credentials = { username: 'user',
- target: 'target' };
- send_security(22, client);
-
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.types).to.have.members(["username", "password", "target"]);
- });
-
- it('should send user and target separately', function () {
- client._rfb_credentials = { username: 'user',
- target: 'target',
- password: 'password' };
- client._negotiate_std_vnc_auth = sinon.spy();
-
- send_security(22, client);
-
- const expected = [22, 4, 6]; // auth selection, len user, len target
- for (let i = 0; i < 10; i++) { expected[i+3] = 'usertarget'.charCodeAt(i); }
-
- expect(client._sock).to.have.sent(new Uint8Array(expected));
- });
- });
-
- describe('TightVNC Authentication (type 16) Handler', function () {
- beforeEach(function () {
- client._rfb_init_state = 'Security';
- client._rfb_version = 3.8;
- send_security(16, client);
- client._sock._websocket._get_sent_data(); // skip the security reply
- });
-
- function send_num_str_pairs(pairs, client) {
- const data = [];
- push32(data, pairs.length);
-
- for (let i = 0; i < pairs.length; i++) {
- push32(data, pairs[i][0]);
- for (let j = 0; j < 4; j++) {
- data.push(pairs[i][1].charCodeAt(j));
- }
- for (let j = 0; j < 8; j++) {
- data.push(pairs[i][2].charCodeAt(j));
- }
- }
-
- client._sock._websocket._receive_data(new Uint8Array(data));
- }
-
- it('should skip tunnel negotiation if no tunnels are requested', function () {
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
- expect(client._rfb_tightvnc).to.be.true;
- });
-
- it('should fail if no supported tunnels are listed', function () {
- sinon.spy(client, "_fail");
- send_num_str_pairs([[123, 'OTHR', 'SOMETHNG']], client);
- expect(client._fail).to.have.been.calledOnce;
- });
-
- it('should choose the notunnel tunnel type', function () {
- send_num_str_pairs([[0, 'TGHT', 'NOTUNNEL'], [123, 'OTHR', 'SOMETHNG']], client);
- expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 0]));
- });
-
- it('should choose the notunnel tunnel type for Siemens devices', function () {
- send_num_str_pairs([[1, 'SICR', 'SCHANNEL'], [2, 'SICR', 'SCHANLPW']], client);
- expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 0]));
- });
-
- it('should continue to sub-auth negotiation after tunnel negotiation', function () {
- send_num_str_pairs([[0, 'TGHT', 'NOTUNNEL']], client);
- client._sock._websocket._get_sent_data(); // skip the tunnel choice here
- send_num_str_pairs([[1, 'STDV', 'NOAUTH__']], client);
- expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 1]));
- expect(client._rfb_init_state).to.equal('SecurityResult');
- });
-
- /*it('should attempt to use VNC auth over no auth when possible', function () {
- client._rfb_tightvnc = true;
- client._negotiate_std_vnc_auth = sinon.spy();
- send_num_str_pairs([[1, 'STDV', 'NOAUTH__'], [2, 'STDV', 'VNCAUTH_']], client);
- expect(client._sock).to.have.sent([0, 0, 0, 1]);
- expect(client._negotiate_std_vnc_auth).to.have.been.calledOnce;
- expect(client._rfb_auth_scheme).to.equal(2);
- });*/ // while this would make sense, the original code doesn't actually do this
-
- it('should accept the "no auth" auth type and transition to SecurityResult', function () {
- client._rfb_tightvnc = true;
- send_num_str_pairs([[1, 'STDV', 'NOAUTH__']], client);
- expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 1]));
- expect(client._rfb_init_state).to.equal('SecurityResult');
- });
-
- it('should accept VNC authentication and transition to that', function () {
- client._rfb_tightvnc = true;
- client._negotiate_std_vnc_auth = sinon.spy();
- send_num_str_pairs([[2, 'STDV', 'VNCAUTH__']], client);
- expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 2]));
- expect(client._negotiate_std_vnc_auth).to.have.been.calledOnce;
- expect(client._rfb_auth_scheme).to.equal(2);
- });
-
- it('should fail if there are no supported auth types', function () {
- sinon.spy(client, "_fail");
- client._rfb_tightvnc = true;
- send_num_str_pairs([[23, 'stdv', 'badval__']], client);
- expect(client._fail).to.have.been.calledOnce;
- });
- });
- });
-
- describe('SecurityResult', function () {
- beforeEach(function () {
- client._rfb_init_state = 'SecurityResult';
- });
-
- it('should fall through to ServerInitialisation on a response code of 0', function () {
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
- expect(client._rfb_init_state).to.equal('ServerInitialisation');
- });
-
- it('should fail on an error code of 1 with the given message for versions >= 3.8', function () {
- client._rfb_version = 3.8;
- sinon.spy(client, '_fail');
- const failure_data = [0, 0, 0, 1, 0, 0, 0, 6, 119, 104, 111, 111, 112, 115];
- client._sock._websocket._receive_data(new Uint8Array(failure_data));
- expect(client._fail).to.have.been.calledWith(
- 'Security negotiation failed on security result (reason: whoops)');
- });
-
- it('should fail on an error code of 1 with a standard message for version < 3.8', function () {
- sinon.spy(client, '_fail');
- client._rfb_version = 3.7;
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 1]));
- expect(client._fail).to.have.been.calledWith(
- 'Security handshake failed');
- });
-
- it('should result in securityfailure event when receiving a non zero status', function () {
- const spy = sinon.spy();
- client.addEventListener("securityfailure", spy);
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 2]));
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.status).to.equal(2);
- });
-
- it('should include reason when provided in securityfailure event', function () {
- client._rfb_version = 3.8;
- const spy = sinon.spy();
- client.addEventListener("securityfailure", spy);
- const failure_data = [0, 0, 0, 1, 0, 0, 0, 12, 115, 117, 99, 104,
- 32, 102, 97, 105, 108, 117, 114, 101];
- client._sock._websocket._receive_data(new Uint8Array(failure_data));
- expect(spy.args[0][0].detail.status).to.equal(1);
- expect(spy.args[0][0].detail.reason).to.equal('such failure');
- });
-
- it('should not include reason when length is zero in securityfailure event', function () {
- client._rfb_version = 3.9;
- const spy = sinon.spy();
- client.addEventListener("securityfailure", spy);
- const failure_data = [0, 0, 0, 1, 0, 0, 0, 0];
- client._sock._websocket._receive_data(new Uint8Array(failure_data));
- expect(spy.args[0][0].detail.status).to.equal(1);
- expect('reason' in spy.args[0][0].detail).to.be.false;
- });
-
- it('should not include reason in securityfailure event for version < 3.8', function () {
- client._rfb_version = 3.6;
- const spy = sinon.spy();
- client.addEventListener("securityfailure", spy);
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 2]));
- expect(spy.args[0][0].detail.status).to.equal(2);
- expect('reason' in spy.args[0][0].detail).to.be.false;
- });
- });
-
- describe('ClientInitialisation', function () {
- it('should transition to the ServerInitialisation state', function () {
- const client = make_rfb();
- client._rfb_connection_state = 'connecting';
- client._rfb_init_state = 'SecurityResult';
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
- expect(client._rfb_init_state).to.equal('ServerInitialisation');
- });
-
- it('should send 1 if we are in shared mode', function () {
- const client = make_rfb('wss://host:8675', { shared: true });
- client._rfb_connection_state = 'connecting';
- client._rfb_init_state = 'SecurityResult';
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
- expect(client._sock).to.have.sent(new Uint8Array([1]));
- });
-
- it('should send 0 if we are not in shared mode', function () {
- const client = make_rfb('wss://host:8675', { shared: false });
- client._rfb_connection_state = 'connecting';
- client._rfb_init_state = 'SecurityResult';
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0]));
- expect(client._sock).to.have.sent(new Uint8Array([0]));
- });
- });
-
- describe('ServerInitialisation', function () {
- beforeEach(function () {
- client._rfb_init_state = 'ServerInitialisation';
- });
-
- function send_server_init(opts, client) {
- const full_opts = { width: 10, height: 12, bpp: 24, depth: 24, big_endian: 0,
- true_color: 1, red_max: 255, green_max: 255, blue_max: 255,
- red_shift: 16, green_shift: 8, blue_shift: 0, name: 'a name' };
- for (let opt in opts) {
- full_opts[opt] = opts[opt];
- }
- const data = [];
-
- push16(data, full_opts.width);
- push16(data, full_opts.height);
-
- data.push(full_opts.bpp);
- data.push(full_opts.depth);
- data.push(full_opts.big_endian);
- data.push(full_opts.true_color);
-
- push16(data, full_opts.red_max);
- push16(data, full_opts.green_max);
- push16(data, full_opts.blue_max);
- push8(data, full_opts.red_shift);
- push8(data, full_opts.green_shift);
- push8(data, full_opts.blue_shift);
-
- // padding
- push8(data, 0);
- push8(data, 0);
- push8(data, 0);
-
- client._sock._websocket._receive_data(new Uint8Array(data));
-
- const name_data = [];
- push32(name_data, full_opts.name.length);
- for (let i = 0; i < full_opts.name.length; i++) {
- name_data.push(full_opts.name.charCodeAt(i));
- }
- client._sock._websocket._receive_data(new Uint8Array(name_data));
- }
-
- it('should set the framebuffer width and height', function () {
- send_server_init({ width: 32, height: 84 }, client);
- expect(client._fb_width).to.equal(32);
- expect(client._fb_height).to.equal(84);
- });
-
- // NB(sross): we just warn, not fail, for endian-ness and shifts, so we don't test them
-
- it('should set the framebuffer name and call the callback', function () {
- const spy = sinon.spy();
- client.addEventListener("desktopname", spy);
- send_server_init({ name: 'some name' }, client);
-
- expect(client._fb_name).to.equal('some name');
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.name).to.equal('some name');
- });
-
- it('should handle the extended init message of the tight encoding', function () {
- // NB(sross): we don't actually do anything with it, so just test that we can
- // read it w/o throwing an error
- client._rfb_tightvnc = true;
- send_server_init({}, client);
-
- const tight_data = [];
- push16(tight_data, 1);
- push16(tight_data, 2);
- push16(tight_data, 3);
- push16(tight_data, 0);
- for (let i = 0; i < 16 + 32 + 48; i++) {
- tight_data.push(i);
- }
- client._sock._websocket._receive_data(new Uint8Array(tight_data));
-
- expect(client._rfb_connection_state).to.equal('connected');
- });
-
- it('should resize the display', function () {
- sinon.spy(client._display, 'resize');
- send_server_init({ width: 27, height: 32 }, client);
-
- expect(client._display.resize).to.have.been.calledOnce;
- expect(client._display.resize).to.have.been.calledWith(27, 32);
- });
-
- it('should grab the mouse and keyboard', function () {
- sinon.spy(client._keyboard, 'grab');
- sinon.spy(client._mouse, 'grab');
- send_server_init({}, client);
- expect(client._keyboard.grab).to.have.been.calledOnce;
- expect(client._mouse.grab).to.have.been.calledOnce;
- });
-
- describe('Initial Update Request', function () {
- beforeEach(function () {
- sinon.spy(RFB.messages, "pixelFormat");
- sinon.spy(RFB.messages, "clientEncodings");
- sinon.spy(RFB.messages, "fbUpdateRequest");
- });
-
- afterEach(function () {
- RFB.messages.pixelFormat.restore();
- RFB.messages.clientEncodings.restore();
- RFB.messages.fbUpdateRequest.restore();
- });
-
- // TODO(directxman12): test the various options in this configuration matrix
- it('should reply with the pixel format, client encodings, and initial update request', function () {
- send_server_init({ width: 27, height: 32 }, client);
-
- expect(RFB.messages.pixelFormat).to.have.been.calledOnce;
- expect(RFB.messages.pixelFormat).to.have.been.calledWith(client._sock, 24, true);
- expect(RFB.messages.pixelFormat).to.have.been.calledBefore(RFB.messages.clientEncodings);
- expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
- expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.encodingTight);
- expect(RFB.messages.clientEncodings).to.have.been.calledBefore(RFB.messages.fbUpdateRequest);
- expect(RFB.messages.fbUpdateRequest).to.have.been.calledOnce;
- expect(RFB.messages.fbUpdateRequest).to.have.been.calledWith(client._sock, false, 0, 0, 27, 32);
- });
-
- it('should reply with restricted settings for Intel AMT servers', function () {
- send_server_init({ width: 27, height: 32, name: "Intel(r) AMT KVM"}, client);
-
- expect(RFB.messages.pixelFormat).to.have.been.calledOnce;
- expect(RFB.messages.pixelFormat).to.have.been.calledWith(client._sock, 8, true);
- expect(RFB.messages.pixelFormat).to.have.been.calledBefore(RFB.messages.clientEncodings);
- expect(RFB.messages.clientEncodings).to.have.been.calledOnce;
- expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.not.include(encodings.encodingTight);
- expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.not.include(encodings.encodingHextile);
- expect(RFB.messages.clientEncodings).to.have.been.calledBefore(RFB.messages.fbUpdateRequest);
- expect(RFB.messages.fbUpdateRequest).to.have.been.calledOnce;
- expect(RFB.messages.fbUpdateRequest).to.have.been.calledWith(client._sock, false, 0, 0, 27, 32);
- });
- });
-
- it('should transition to the "connected" state', function () {
- send_server_init({}, client);
- expect(client._rfb_connection_state).to.equal('connected');
- });
- });
- });
-
- describe('Protocol Message Processing After Completing Initialization', function () {
- let client;
-
- beforeEach(function () {
- client = make_rfb();
- client._fb_name = 'some device';
- client._fb_width = 640;
- client._fb_height = 20;
- });
-
- describe('Framebuffer Update Handling', function () {
- const target_data_arr = [
- 0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
- 0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
- 0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255,
- 0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255
- ];
- let target_data;
-
- const target_data_check_arr = [
- 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
- 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255,
- 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255,
- 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255
- ];
- let target_data_check;
-
- before(function () {
- // NB(directxman12): PhantomJS 1.x doesn't implement Uint8ClampedArray
- target_data = new Uint8Array(target_data_arr);
- target_data_check = new Uint8Array(target_data_check_arr);
- });
-
- function send_fbu_msg(rect_info, rect_data, client, rect_cnt) {
- let data = [];
-
- if (!rect_cnt || rect_cnt > -1) {
- // header
- data.push(0); // msg type
- data.push(0); // padding
- push16(data, rect_cnt || rect_data.length);
- }
-
- for (let i = 0; i < rect_data.length; i++) {
- if (rect_info[i]) {
- push16(data, rect_info[i].x);
- push16(data, rect_info[i].y);
- push16(data, rect_info[i].width);
- push16(data, rect_info[i].height);
- push32(data, rect_info[i].encoding);
- }
- data = data.concat(rect_data[i]);
- }
-
- client._sock._websocket._receive_data(new Uint8Array(data));
- }
-
- it('should send an update request if there is sufficient data', function () {
- const expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}};
- RFB.messages.fbUpdateRequest(expected_msg, true, 0, 0, 640, 20);
-
- client._framebufferUpdate = () => true;
- client._sock._websocket._receive_data(new Uint8Array([0]));
-
- expect(client._sock).to.have.sent(expected_msg._sQ);
- });
-
- it('should not send an update request if we need more data', function () {
- client._sock._websocket._receive_data(new Uint8Array([0]));
- expect(client._sock._websocket._get_sent_data()).to.have.length(0);
- });
-
- it('should resume receiving an update if we previously did not have enough data', function () {
- const expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}};
- RFB.messages.fbUpdateRequest(expected_msg, true, 0, 0, 640, 20);
-
- // just enough to set FBU.rects
- client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 3]));
- expect(client._sock._websocket._get_sent_data()).to.have.length(0);
-
- client._framebufferUpdate = function () { this._sock.rQskipBytes(1); return true; }; // we magically have enough data
- // 247 should *not* be used as the message type here
- client._sock._websocket._receive_data(new Uint8Array([247]));
- expect(client._sock).to.have.sent(expected_msg._sQ);
- });
-
- it('should not send a request in continuous updates mode', function () {
- client._enabledContinuousUpdates = true;
- client._framebufferUpdate = () => true;
- client._sock._websocket._receive_data(new Uint8Array([0]));
-
- expect(client._sock._websocket._get_sent_data()).to.have.length(0);
- });
-
- it('should fail on an unsupported encoding', function () {
- sinon.spy(client, "_fail");
- const rect_info = { x: 8, y: 11, width: 27, height: 32, encoding: 234 };
- send_fbu_msg([rect_info], [[]], client);
- expect(client._fail).to.have.been.calledOnce;
- });
-
- it('should be able to pause and resume receiving rects if not enought data', function () {
- // seed some initial data to copy
- client._fb_width = 4;
- client._fb_height = 4;
- client._display.resize(4, 4);
- client._display.blitRgbxImage(0, 0, 4, 2, new Uint8Array(target_data_check_arr.slice(0, 32)), 0);
-
- const info = [{ x: 0, y: 2, width: 2, height: 2, encoding: 0x01},
- { x: 2, y: 2, width: 2, height: 2, encoding: 0x01}];
- // data says [{ old_x: 2, old_y: 0 }, { old_x: 0, old_y: 0 }]
- const rects = [[0, 2, 0, 0], [0, 0, 0, 0]];
- send_fbu_msg([info[0]], [rects[0]], client, 2);
- send_fbu_msg([info[1]], [rects[1]], client, -1);
- expect(client._display).to.have.displayed(target_data_check);
- });
-
- describe('Message Encoding Handlers', function () {
- beforeEach(function () {
- // a really small frame
- client._fb_width = 4;
- client._fb_height = 4;
- client._fb_depth = 24;
- client._display.resize(4, 4);
- });
-
- it('should handle the RAW encoding', function () {
- const info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
- { x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
- { x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
- { x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
- // data is in bgrx
- const rects = [
- [0x00, 0x00, 0xff, 0, 0x00, 0xff, 0x00, 0, 0x00, 0xff, 0x00, 0, 0x00, 0x00, 0xff, 0],
- [0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0, 0xff, 0x00, 0x00, 0],
- [0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0, 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0],
- [0xff, 0x00, 0xee, 0, 0xff, 0xee, 0x00, 0, 0xff, 0xee, 0xaa, 0, 0xff, 0xee, 0xab, 0]];
- send_fbu_msg(info, rects, client);
- expect(client._display).to.have.displayed(target_data);
- });
-
- it('should handle the RAW encoding in low colour mode', function () {
- const info = [{ x: 0, y: 0, width: 2, height: 2, encoding: 0x00 },
- { x: 2, y: 0, width: 2, height: 2, encoding: 0x00 },
- { x: 0, y: 2, width: 4, height: 1, encoding: 0x00 },
- { x: 0, y: 3, width: 4, height: 1, encoding: 0x00 }];
- const rects = [
- [0x03, 0x03, 0x03, 0x03],
- [0x0c, 0x0c, 0x0c, 0x0c],
- [0x0c, 0x0c, 0x03, 0x03],
- [0x0c, 0x0c, 0x03, 0x03]];
- client._fb_depth = 8;
- send_fbu_msg(info, rects, client);
- expect(client._display).to.have.displayed(target_data_check);
- });
-
- it('should handle the COPYRECT encoding', function () {
- // seed some initial data to copy
- client._display.blitRgbxImage(0, 0, 4, 2, new Uint8Array(target_data_check_arr.slice(0, 32)), 0);
-
- const info = [{ x: 0, y: 2, width: 2, height: 2, encoding: 0x01},
- { x: 2, y: 2, width: 2, height: 2, encoding: 0x01}];
- // data says [{ old_x: 0, old_y: 0 }, { old_x: 0, old_y: 0 }]
- const rects = [[0, 2, 0, 0], [0, 0, 0, 0]];
- send_fbu_msg(info, rects, client);
- expect(client._display).to.have.displayed(target_data_check);
- });
-
- // TODO(directxman12): for encodings with subrects, test resuming on partial send?
- // TODO(directxman12): test rre_chunk_sz (related to above about subrects)?
-
- it('should handle the RRE encoding', function () {
- const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x02 }];
- const rect = [];
- push32(rect, 2); // 2 subrects
- push32(rect, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
- rect.push(0xff); // becomes ff0000ff --> #0000FF color
- rect.push(0x00);
- rect.push(0x00);
- rect.push(0xff);
- push16(rect, 0); // x: 0
- push16(rect, 0); // y: 0
- push16(rect, 2); // width: 2
- push16(rect, 2); // height: 2
- rect.push(0xff); // becomes ff0000ff --> #0000FF color
- rect.push(0x00);
- rect.push(0x00);
- rect.push(0xff);
- push16(rect, 2); // x: 2
- push16(rect, 2); // y: 2
- push16(rect, 2); // width: 2
- push16(rect, 2); // height: 2
-
- send_fbu_msg(info, [rect], client);
- expect(client._display).to.have.displayed(target_data_check);
- });
-
- describe('the HEXTILE encoding handler', function () {
- it('should handle a tile with fg, bg specified, normal subrects', function () {
- const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x05 }];
- const rect = [];
- rect.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
- push32(rect, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
- rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
- rect.push(0x00);
- rect.push(0x00);
- rect.push(0xff);
- rect.push(2); // 2 subrects
- rect.push(0); // x: 0, y: 0
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- rect.push(2 | (2 << 4)); // x: 2, y: 2
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- send_fbu_msg(info, [rect], client);
- expect(client._display).to.have.displayed(target_data_check);
- });
-
- it('should handle a raw tile', function () {
- const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x05 }];
- const rect = [];
- rect.push(0x01); // raw
- for (let i = 0; i < target_data.length; i += 4) {
- rect.push(target_data[i + 2]);
- rect.push(target_data[i + 1]);
- rect.push(target_data[i]);
- rect.push(target_data[i + 3]);
- }
- send_fbu_msg(info, [rect], client);
- expect(client._display).to.have.displayed(target_data);
- });
-
- it('should handle a tile with only bg specified (solid bg)', function () {
- const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x05 }];
- const rect = [];
- rect.push(0x02);
- push32(rect, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
- send_fbu_msg(info, [rect], client);
-
- const expected = [];
- for (let i = 0; i < 16; i++) { push32(expected, 0xff00ff); }
- expect(client._display).to.have.displayed(new Uint8Array(expected));
- });
-
- it('should handle a tile with only bg specified and an empty frame afterwards', function () {
- // set the width so we can have two tiles
- client._fb_width = 8;
- client._display.resize(8, 4);
-
- const info = [{ x: 0, y: 0, width: 32, height: 4, encoding: 0x05 }];
-
- const rect = [];
-
- // send a bg frame
- rect.push(0x02);
- push32(rect, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
-
- // send an empty frame
- rect.push(0x00);
-
- send_fbu_msg(info, [rect], client);
-
- const expected = [];
- for (let i = 0; i < 16; i++) { push32(expected, 0xff00ff); } // rect 1: solid
- for (let i = 0; i < 16; i++) { push32(expected, 0xff00ff); } // rect 2: same bkground color
- expect(client._display).to.have.displayed(new Uint8Array(expected));
- });
-
- it('should handle a tile with bg and coloured subrects', function () {
- const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x05 }];
- const rect = [];
- rect.push(0x02 | 0x08 | 0x10); // bg spec, anysubrects, colouredsubrects
- push32(rect, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
- rect.push(2); // 2 subrects
- rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
- rect.push(0x00);
- rect.push(0x00);
- rect.push(0xff);
- rect.push(0); // x: 0, y: 0
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
- rect.push(0x00);
- rect.push(0x00);
- rect.push(0xff);
- rect.push(2 | (2 << 4)); // x: 2, y: 2
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- send_fbu_msg(info, [rect], client);
- expect(client._display).to.have.displayed(target_data_check);
- });
-
- it('should carry over fg and bg colors from the previous tile if not specified', function () {
- client._fb_width = 4;
- client._fb_height = 17;
- client._display.resize(4, 17);
-
- const info = [{ x: 0, y: 0, width: 4, height: 17, encoding: 0x05}];
- const rect = [];
- rect.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects
- push32(rect, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color
- rect.push(0xff); // becomes ff0000ff --> #0000FF fg color
- rect.push(0x00);
- rect.push(0x00);
- rect.push(0xff);
- rect.push(8); // 8 subrects
- for (let i = 0; i < 4; i++) {
- rect.push((0 << 4) | (i * 4)); // x: 0, y: i*4
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- rect.push((2 << 4) | (i * 4 + 2)); // x: 2, y: i * 4 + 2
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- }
- rect.push(0x08); // anysubrects
- rect.push(1); // 1 subrect
- rect.push(0); // x: 0, y: 0
- rect.push(1 | (1 << 4)); // width: 2, height: 2
- send_fbu_msg(info, [rect], client);
-
- let expected = [];
- for (let i = 0; i < 4; i++) { expected = expected.concat(target_data_check_arr); }
- expected = expected.concat(target_data_check_arr.slice(0, 16));
- expect(client._display).to.have.displayed(new Uint8Array(expected));
- });
-
- it('should fail on an invalid subencoding', function () {
- sinon.spy(client, "_fail");
- const info = [{ x: 0, y: 0, width: 4, height: 4, encoding: 0x05 }];
- const rects = [[45]]; // an invalid subencoding
- send_fbu_msg(info, rects, client);
- expect(client._fail).to.have.been.calledOnce;
- });
- });
-
- it.skip('should handle the TIGHT encoding', function () {
- // TODO(directxman12): test this
- });
-
- it.skip('should handle the TIGHT_PNG encoding', function () {
- // TODO(directxman12): test this
- });
-
- it('should handle the DesktopSize pseduo-encoding', function () {
- sinon.spy(client._display, 'resize');
- send_fbu_msg([{ x: 0, y: 0, width: 20, height: 50, encoding: -223 }], [[]], client);
-
- expect(client._fb_width).to.equal(20);
- expect(client._fb_height).to.equal(50);
-
- expect(client._display.resize).to.have.been.calledOnce;
- expect(client._display.resize).to.have.been.calledWith(20, 50);
- });
-
- describe('the ExtendedDesktopSize pseudo-encoding handler', function () {
- beforeEach(function () {
- // a really small frame
- client._fb_width = 4;
- client._fb_height = 4;
- client._display.resize(4, 4);
- sinon.spy(client._display, 'resize');
- });
-
- function make_screen_data(nr_of_screens) {
- const data = [];
- push8(data, nr_of_screens); // number-of-screens
- push8(data, 0); // padding
- push16(data, 0); // padding
- for (let i=0; i<nr_of_screens; i += 1) {
- push32(data, 0); // id
- push16(data, 0); // x-position
- push16(data, 0); // y-position
- push16(data, 20); // width
- push16(data, 50); // height
- push32(data, 0); // flags
- }
- return data;
- }
-
- it('should handle a resize requested by this client', function () {
- const reason_for_change = 1; // requested by this client
- const status_code = 0; // No error
-
- send_fbu_msg([{ x: reason_for_change, y: status_code,
- width: 20, height: 50, encoding: -308 }],
- make_screen_data(1), client);
-
- expect(client._fb_width).to.equal(20);
- expect(client._fb_height).to.equal(50);
-
- expect(client._display.resize).to.have.been.calledOnce;
- expect(client._display.resize).to.have.been.calledWith(20, 50);
- });
-
- it('should handle a resize requested by another client', function () {
- const reason_for_change = 2; // requested by another client
- const status_code = 0; // No error
-
- send_fbu_msg([{ x: reason_for_change, y: status_code,
- width: 20, height: 50, encoding: -308 }],
- make_screen_data(1), client);
-
- expect(client._fb_width).to.equal(20);
- expect(client._fb_height).to.equal(50);
-
- expect(client._display.resize).to.have.been.calledOnce;
- expect(client._display.resize).to.have.been.calledWith(20, 50);
- });
-
- it('should be able to recieve requests which contain data for multiple screens', function () {
- const reason_for_change = 2; // requested by another client
- const status_code = 0; // No error
-
- send_fbu_msg([{ x: reason_for_change, y: status_code,
- width: 60, height: 50, encoding: -308 }],
- make_screen_data(3), client);
-
- expect(client._fb_width).to.equal(60);
- expect(client._fb_height).to.equal(50);
-
- expect(client._display.resize).to.have.been.calledOnce;
- expect(client._display.resize).to.have.been.calledWith(60, 50);
- });
-
- it('should not handle a failed request', function () {
- const reason_for_change = 1; // requested by this client
- const status_code = 1; // Resize is administratively prohibited
-
- send_fbu_msg([{ x: reason_for_change, y: status_code,
- width: 20, height: 50, encoding: -308 }],
- make_screen_data(1), client);
-
- expect(client._fb_width).to.equal(4);
- expect(client._fb_height).to.equal(4);
-
- expect(client._display.resize).to.not.have.been.called;
- });
- });
-
- describe('the Cursor pseudo-encoding handler', function () {
- beforeEach(function () {
- sinon.spy(client._cursor, 'change');
- });
-
- it('should handle a standard cursor', function () {
- const info = { x: 5, y: 7,
- width: 4, height: 4,
- encoding: -239};
- let rect = [];
- let expected = [];
-
- for (let i = 0;i < info.width*info.height;i++) {
- push32(rect, 0x11223300);
- }
- push32(rect, 0xa0a0a0a0);
-
- for (let i = 0;i < info.width*info.height/2;i++) {
- push32(expected, 0x332211ff);
- push32(expected, 0x33221100);
- }
- expected = new Uint8Array(expected);
-
- send_fbu_msg([info], [rect], client);
-
- expect(client._cursor.change).to.have.been.calledOnce;
- expect(client._cursor.change).to.have.been.calledWith(expected, 5, 7, 4, 4);
- });
-
- it('should handle an empty cursor', function () {
- const info = { x: 0, y: 0,
- width: 0, height: 0,
- encoding: -239};
- const rect = [];
-
- send_fbu_msg([info], [rect], client);
-
- expect(client._cursor.change).to.have.been.calledOnce;
- expect(client._cursor.change).to.have.been.calledWith(new Uint8Array, 0, 0, 0, 0);
- });
-
- it('should handle a transparent cursor', function () {
- const info = { x: 5, y: 7,
- width: 4, height: 4,
- encoding: -239};
- let rect = [];
- let expected = [];
-
- for (let i = 0;i < info.width*info.height;i++) {
- push32(rect, 0x11223300);
- }
- push32(rect, 0x00000000);
-
- for (let i = 0;i < info.width*info.height;i++) {
- push32(expected, 0x33221100);
- }
- expected = new Uint8Array(expected);
-
- send_fbu_msg([info], [rect], client);
-
- expect(client._cursor.change).to.have.been.calledOnce;
- expect(client._cursor.change).to.have.been.calledWith(expected, 5, 7, 4, 4);
- });
-
- describe('dot for empty cursor', function () {
- beforeEach(function () {
- client.showDotCursor = true;
- // Was called when we enabled dot cursor
- client._cursor.change.reset();
- });
-
- it('should show a standard cursor', function () {
- const info = { x: 5, y: 7,
- width: 4, height: 4,
- encoding: -239};
- let rect = [];
- let expected = [];
-
- for (let i = 0;i < info.width*info.height;i++) {
- push32(rect, 0x11223300);
- }
- push32(rect, 0xa0a0a0a0);
-
- for (let i = 0;i < info.width*info.height/2;i++) {
- push32(expected, 0x332211ff);
- push32(expected, 0x33221100);
- }
- expected = new Uint8Array(expected);
-
- send_fbu_msg([info], [rect], client);
-
- expect(client._cursor.change).to.have.been.calledOnce;
- expect(client._cursor.change).to.have.been.calledWith(expected, 5, 7, 4, 4);
- });
-
- it('should handle an empty cursor', function () {
- const info = { x: 0, y: 0,
- width: 0, height: 0,
- encoding: -239};
- const rect = [];
- const dot = RFB.cursors.dot;
-
- send_fbu_msg([info], [rect], client);
-
- expect(client._cursor.change).to.have.been.calledOnce;
- expect(client._cursor.change).to.have.been.calledWith(dot.rgbaPixels,
- dot.hotx,
- dot.hoty,
- dot.w,
- dot.h);
- });
-
- it('should handle a transparent cursor', function () {
- const info = { x: 5, y: 7,
- width: 4, height: 4,
- encoding: -239};
- let rect = [];
- const dot = RFB.cursors.dot;
-
- for (let i = 0;i < info.width*info.height;i++) {
- push32(rect, 0x11223300);
- }
- push32(rect, 0x00000000);
-
- send_fbu_msg([info], [rect], client);
-
- expect(client._cursor.change).to.have.been.calledOnce;
- expect(client._cursor.change).to.have.been.calledWith(dot.rgbaPixels,
- dot.hotx,
- dot.hoty,
- dot.w,
- dot.h);
- });
- });
- });
-
- it('should handle the last_rect pseudo-encoding', function () {
- send_fbu_msg([{ x: 0, y: 0, width: 0, height: 0, encoding: -224}], [[]], client, 100);
- expect(client._FBU.rects).to.equal(0);
- });
- });
- });
-
- describe('XVP Message Handling', function () {
- it('should set the XVP version and fire the callback with the version on XVP_INIT', function () {
- const spy = sinon.spy();
- client.addEventListener("capabilities", spy);
- client._sock._websocket._receive_data(new Uint8Array([250, 0, 10, 1]));
- expect(client._rfb_xvp_ver).to.equal(10);
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.capabilities.power).to.be.true;
- expect(client.capabilities.power).to.be.true;
- });
-
- it('should fail on unknown XVP message types', function () {
- sinon.spy(client, "_fail");
- client._sock._websocket._receive_data(new Uint8Array([250, 0, 10, 237]));
- expect(client._fail).to.have.been.calledOnce;
- });
- });
-
- it('should fire the clipboard callback with the retrieved text on ServerCutText', function () {
- const expected_str = 'cheese!';
- const data = [3, 0, 0, 0];
- push32(data, expected_str.length);
- for (let i = 0; i < expected_str.length; i++) { data.push(expected_str.charCodeAt(i)); }
- const spy = sinon.spy();
- client.addEventListener("clipboard", spy);
-
- client._sock._websocket._receive_data(new Uint8Array(data));
- expect(spy).to.have.been.calledOnce;
- expect(spy.args[0][0].detail.text).to.equal(expected_str);
- });
-
- it('should fire the bell callback on Bell', function () {
- const spy = sinon.spy();
- client.addEventListener("bell", spy);
- client._sock._websocket._receive_data(new Uint8Array([2]));
- expect(spy).to.have.been.calledOnce;
- });
-
- it('should respond correctly to ServerFence', function () {
- const expected_msg = {_sQ: new Uint8Array(16), _sQlen: 0, flush: () => {}};
- const incoming_msg = {_sQ: new Uint8Array(16), _sQlen: 0, flush: () => {}};
-
- const payload = "foo\x00ab9";
-
- // ClientFence and ServerFence are identical in structure
- RFB.messages.clientFence(expected_msg, (1<<0) | (1<<1), payload);
- RFB.messages.clientFence(incoming_msg, 0xffffffff, payload);
-
- client._sock._websocket._receive_data(incoming_msg._sQ);
-
- expect(client._sock).to.have.sent(expected_msg._sQ);
-
- expected_msg._sQlen = 0;
- incoming_msg._sQlen = 0;
-
- RFB.messages.clientFence(expected_msg, (1<<0), payload);
- RFB.messages.clientFence(incoming_msg, (1<<0) | (1<<31), payload);
-
- client._sock._websocket._receive_data(incoming_msg._sQ);
-
- expect(client._sock).to.have.sent(expected_msg._sQ);
- });
-
- it('should enable continuous updates on first EndOfContinousUpdates', function () {
- const expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}};
-
- RFB.messages.enableContinuousUpdates(expected_msg, true, 0, 0, 640, 20);
-
- expect(client._enabledContinuousUpdates).to.be.false;
-
- client._sock._websocket._receive_data(new Uint8Array([150]));
-
- expect(client._enabledContinuousUpdates).to.be.true;
- expect(client._sock).to.have.sent(expected_msg._sQ);
- });
-
- it('should disable continuous updates on subsequent EndOfContinousUpdates', function () {
- client._enabledContinuousUpdates = true;
- client._supportsContinuousUpdates = true;
-
- client._sock._websocket._receive_data(new Uint8Array([150]));
-
- expect(client._enabledContinuousUpdates).to.be.false;
- });
-
- it('should update continuous updates on resize', function () {
- const expected_msg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}};
- RFB.messages.enableContinuousUpdates(expected_msg, true, 0, 0, 90, 700);
-
- client._resize(450, 160);
-
- expect(client._sock._websocket._get_sent_data()).to.have.length(0);
-
- client._enabledContinuousUpdates = true;
-
- client._resize(90, 700);
-
- expect(client._sock).to.have.sent(expected_msg._sQ);
- });
-
- it('should fail on an unknown message type', function () {
- sinon.spy(client, "_fail");
- client._sock._websocket._receive_data(new Uint8Array([87]));
- expect(client._fail).to.have.been.calledOnce;
- });
- });
-
- describe('Asynchronous Events', function () {
- let client;
- beforeEach(function () {
- client = make_rfb();
- });
-
- describe('Mouse event handlers', function () {
- it('should not send button messages in view-only mode', function () {
- client._viewOnly = true;
- sinon.spy(client._sock, 'flush');
- client._handleMouseButton(0, 0, 1, 0x001);
- expect(client._sock.flush).to.not.have.been.called;
- });
-
- it('should not send movement messages in view-only mode', function () {
- client._viewOnly = true;
- sinon.spy(client._sock, 'flush');
- client._handleMouseMove(0, 0);
- expect(client._sock.flush).to.not.have.been.called;
- });
-
- it('should send a pointer event on mouse button presses', function () {
- client._handleMouseButton(10, 12, 1, 0x001);
- const pointer_msg = {_sQ: new Uint8Array(6), _sQlen: 0, flush: () => {}};
- RFB.messages.pointerEvent(pointer_msg, 10, 12, 0x001);
- expect(client._sock).to.have.sent(pointer_msg._sQ);
- });
-
- it('should send a mask of 1 on mousedown', function () {
- client._handleMouseButton(10, 12, 1, 0x001);
- const pointer_msg = {_sQ: new Uint8Array(6), _sQlen: 0, flush: () => {}};
- RFB.messages.pointerEvent(pointer_msg, 10, 12, 0x001);
- expect(client._sock).to.have.sent(pointer_msg._sQ);
- });
-
- it('should send a mask of 0 on mouseup', function () {
- client._mouse_buttonMask = 0x001;
- client._handleMouseButton(10, 12, 0, 0x001);
- const pointer_msg = {_sQ: new Uint8Array(6), _sQlen: 0, flush: () => {}};
- RFB.messages.pointerEvent(pointer_msg, 10, 12, 0x000);
- expect(client._sock).to.have.sent(pointer_msg._sQ);
- });
-
- it('should send a pointer event on mouse movement', function () {
- client._handleMouseMove(10, 12);
- const pointer_msg = {_sQ: new Uint8Array(6), _sQlen: 0, flush: () => {}};
- RFB.messages.pointerEvent(pointer_msg, 10, 12, 0x000);
- expect(client._sock).to.have.sent(pointer_msg._sQ);
- });
-
- it('should set the button mask so that future mouse movements use it', function () {
- client._handleMouseButton(10, 12, 1, 0x010);
- client._handleMouseMove(13, 9);
- const pointer_msg = {_sQ: new Uint8Array(12), _sQlen: 0, flush: () => {}};
- RFB.messages.pointerEvent(pointer_msg, 10, 12, 0x010);
- RFB.messages.pointerEvent(pointer_msg, 13, 9, 0x010);
- expect(client._sock).to.have.sent(pointer_msg._sQ);
- });
- });
-
- describe('Keyboard Event Handlers', function () {
- it('should send a key message on a key press', function () {
- client._handleKeyEvent(0x41, 'KeyA', true);
- const key_msg = {_sQ: new Uint8Array(8), _sQlen: 0, flush: () => {}};
- RFB.messages.keyEvent(key_msg, 0x41, 1);
- expect(client._sock).to.have.sent(key_msg._sQ);
- });
-
- it('should not send messages in view-only mode', function () {
- client._viewOnly = true;
- sinon.spy(client._sock, 'flush');
- client._handleKeyEvent('a', 'KeyA', true);
- expect(client._sock.flush).to.not.have.been.called;
- });
- });
-
- describe('WebSocket event handlers', function () {
- // message events
- it('should do nothing if we receive an empty message and have nothing in the queue', function () {
- client._normal_msg = sinon.spy();
- client._sock._websocket._receive_data(new Uint8Array([]));
- expect(client._normal_msg).to.not.have.been.called;
- });
-
- it('should handle a message in the connected state as a normal message', function () {
- client._normal_msg = sinon.spy();
- client._sock._websocket._receive_data(new Uint8Array([1, 2, 3]));
- expect(client._normal_msg).to.have.been.called;
- });
-
- it('should handle a message in any non-disconnected/failed state like an init message', function () {
- client._rfb_connection_state = 'connecting';
- client._rfb_init_state = 'ProtocolVersion';
- client._init_msg = sinon.spy();
- client._sock._websocket._receive_data(new Uint8Array([1, 2, 3]));
- expect(client._init_msg).to.have.been.called;
- });
-
- it('should process all normal messages directly', function () {
- const spy = sinon.spy();
- client.addEventListener("bell", spy);
- client._sock._websocket._receive_data(new Uint8Array([0x02, 0x02]));
- expect(spy).to.have.been.calledTwice;
- });
-
- // open events
- it('should update the state to ProtocolVersion on open (if the state is "connecting")', function () {
- client = new RFB(document.createElement('div'), 'wss://host:8675');
- this.clock.tick();
- client._sock._websocket._open();
- expect(client._rfb_init_state).to.equal('ProtocolVersion');
- });
-
- it('should fail if we are not currently ready to connect and we get an "open" event', function () {
- sinon.spy(client, "_fail");
- client._rfb_connection_state = 'connected';
- client._sock._websocket._open();
- expect(client._fail).to.have.been.calledOnce;
- });
-
- // close events
- it('should transition to "disconnected" from "disconnecting" on a close event', function () {
- const real = client._sock._websocket.close;
- client._sock._websocket.close = () => {};
- client.disconnect();
- expect(client._rfb_connection_state).to.equal('disconnecting');
- client._sock._websocket.close = real;
- client._sock._websocket.close();
- expect(client._rfb_connection_state).to.equal('disconnected');
- });
-
- it('should fail if we get a close event while connecting', function () {
- sinon.spy(client, "_fail");
- client._rfb_connection_state = 'connecting';
- client._sock._websocket.close();
- expect(client._fail).to.have.been.calledOnce;
- });
-
- it('should unregister close event handler', function () {
- sinon.spy(client._sock, 'off');
- client.disconnect();
- client._sock._websocket.close();
- expect(client._sock.off).to.have.been.calledWith('close');
- });
-
- // error events do nothing
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.util.js b/systemvm/agent/noVNC/tests/test.util.js
deleted file mode 100644
index 201acc8..0000000
--- a/systemvm/agent/noVNC/tests/test.util.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* eslint-disable no-console */
-const expect = chai.expect;
-
-import * as Log from '../core/util/logging.js';
-
-describe('Utils', function () {
- "use strict";
-
- describe('logging functions', function () {
- beforeEach(function () {
- sinon.spy(console, 'log');
- sinon.spy(console, 'debug');
- sinon.spy(console, 'warn');
- sinon.spy(console, 'error');
- sinon.spy(console, 'info');
- });
-
- afterEach(function () {
- console.log.restore();
- console.debug.restore();
- console.warn.restore();
- console.error.restore();
- console.info.restore();
- Log.init_logging();
- });
-
- it('should use noop for levels lower than the min level', function () {
- Log.init_logging('warn');
- Log.Debug('hi');
- Log.Info('hello');
- expect(console.log).to.not.have.been.called;
- });
-
- it('should use console.debug for Debug', function () {
- Log.init_logging('debug');
- Log.Debug('dbg');
- expect(console.debug).to.have.been.calledWith('dbg');
- });
-
- it('should use console.info for Info', function () {
- Log.init_logging('debug');
- Log.Info('inf');
- expect(console.info).to.have.been.calledWith('inf');
- });
-
- it('should use console.warn for Warn', function () {
- Log.init_logging('warn');
- Log.Warn('wrn');
- expect(console.warn).to.have.been.called;
- expect(console.warn).to.have.been.calledWith('wrn');
- });
-
- it('should use console.error for Error', function () {
- Log.init_logging('error');
- Log.Error('err');
- expect(console.error).to.have.been.called;
- expect(console.error).to.have.been.calledWith('err');
- });
- });
-
- // TODO(directxman12): test the conf_default and conf_defaults methods
- // TODO(directxman12): test decodeUTF8
- // TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent)
- // TODO(directxman12): figure out a good way to test getPosition and getEventPosition
- // TODO(directxman12): figure out how to test the browser detection functions properly
- // (we can't really test them against the browsers, except for Gecko
- // via PhantomJS, the default test driver)
-});
-/* eslint-enable no-console */
diff --git a/systemvm/agent/noVNC/tests/test.websock.js b/systemvm/agent/noVNC/tests/test.websock.js
deleted file mode 100644
index 30e19e9..0000000
--- a/systemvm/agent/noVNC/tests/test.websock.js
+++ /dev/null
@@ -1,441 +0,0 @@
-const expect = chai.expect;
-
-import Websock from '../core/websock.js';
-import FakeWebSocket from './fake.websocket.js';
-
-describe('Websock', function () {
- "use strict";
-
- describe('Queue methods', function () {
- let sock;
- const RQ_TEMPLATE = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]);
-
- beforeEach(function () {
- sock = new Websock();
- // skip init
- sock._allocate_buffers();
- sock._rQ.set(RQ_TEMPLATE);
- sock._rQlen = RQ_TEMPLATE.length;
- });
- describe('rQlen', function () {
- it('should return the length of the receive queue', function () {
- sock.rQi = 0;
-
- expect(sock.rQlen).to.equal(RQ_TEMPLATE.length);
- });
-
- it("should return the proper length if we read some from the receive queue", function () {
- sock.rQi = 1;
-
- expect(sock.rQlen).to.equal(RQ_TEMPLATE.length - 1);
- });
- });
-
- describe('rQpeek8', function () {
- it('should peek at the next byte without poping it off the queue', function () {
- const bef_len = sock.rQlen;
- const peek = sock.rQpeek8();
- expect(sock.rQpeek8()).to.equal(peek);
- expect(sock.rQlen).to.equal(bef_len);
- });
- });
-
- describe('rQshift8()', function () {
- it('should pop a single byte from the receive queue', function () {
- const peek = sock.rQpeek8();
- const bef_len = sock.rQlen;
- expect(sock.rQshift8()).to.equal(peek);
- expect(sock.rQlen).to.equal(bef_len - 1);
- });
- });
-
- describe('rQshift16()', function () {
- it('should pop two bytes from the receive queue and return a single number', function () {
- const bef_len = sock.rQlen;
- const expected = (RQ_TEMPLATE[0] << 8) + RQ_TEMPLATE[1];
- expect(sock.rQshift16()).to.equal(expected);
- expect(sock.rQlen).to.equal(bef_len - 2);
- });
- });
-
- describe('rQshift32()', function () {
- it('should pop four bytes from the receive queue and return a single number', function () {
- const bef_len = sock.rQlen;
- const expected = (RQ_TEMPLATE[0] << 24) +
- (RQ_TEMPLATE[1] << 16) +
- (RQ_TEMPLATE[2] << 8) +
- RQ_TEMPLATE[3];
- expect(sock.rQshift32()).to.equal(expected);
- expect(sock.rQlen).to.equal(bef_len - 4);
- });
- });
-
- describe('rQshiftStr', function () {
- it('should shift the given number of bytes off of the receive queue and return a string', function () {
- const bef_len = sock.rQlen;
- const bef_rQi = sock.rQi;
- const shifted = sock.rQshiftStr(3);
- expect(shifted).to.be.a('string');
- expect(shifted).to.equal(String.fromCharCode.apply(null, Array.prototype.slice.call(new Uint8Array(RQ_TEMPLATE.buffer, bef_rQi, 3))));
- expect(sock.rQlen).to.equal(bef_len - 3);
- });
-
- it('should shift the entire rest of the queue off if no length is given', function () {
- sock.rQshiftStr();
- expect(sock.rQlen).to.equal(0);
- });
-
- it('should be able to handle very large strings', function () {
- const BIG_LEN = 500000;
- const RQ_BIG = new Uint8Array(BIG_LEN);
- let expected = "";
- let letterCode = 'a'.charCodeAt(0);
- for (let i = 0; i < BIG_LEN; i++) {
- RQ_BIG[i] = letterCode;
- expected += String.fromCharCode(letterCode);
-
- if (letterCode < 'z'.charCodeAt(0)) {
- letterCode++;
- } else {
- letterCode = 'a'.charCodeAt(0);
- }
- }
- sock._rQ.set(RQ_BIG);
- sock._rQlen = RQ_BIG.length;
-
- const shifted = sock.rQshiftStr();
-
- expect(shifted).to.be.equal(expected);
- expect(sock.rQlen).to.equal(0);
- });
- });
-
- describe('rQshiftBytes', function () {
- it('should shift the given number of bytes of the receive queue and return an array', function () {
- const bef_len = sock.rQlen;
- const bef_rQi = sock.rQi;
- const shifted = sock.rQshiftBytes(3);
- expect(shifted).to.be.an.instanceof(Uint8Array);
- expect(shifted).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, bef_rQi, 3));
- expect(sock.rQlen).to.equal(bef_len - 3);
- });
-
- it('should shift the entire rest of the queue off if no length is given', function () {
- sock.rQshiftBytes();
- expect(sock.rQlen).to.equal(0);
- });
- });
-
- describe('rQslice', function () {
- beforeEach(function () {
- sock.rQi = 0;
- });
-
- it('should not modify the receive queue', function () {
- const bef_len = sock.rQlen;
- sock.rQslice(0, 2);
- expect(sock.rQlen).to.equal(bef_len);
- });
-
- it('should return an array containing the given slice of the receive queue', function () {
- const sl = sock.rQslice(0, 2);
- expect(sl).to.be.an.instanceof(Uint8Array);
- expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 0, 2));
- });
-
- it('should use the rest of the receive queue if no end is given', function () {
- const sl = sock.rQslice(1);
- expect(sl).to.have.length(RQ_TEMPLATE.length - 1);
- expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1));
- });
-
- it('should take the current rQi in to account', function () {
- sock.rQi = 1;
- expect(sock.rQslice(0, 2)).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1, 2));
- });
- });
-
- describe('rQwait', function () {
- beforeEach(function () {
- sock.rQi = 0;
- });
-
- it('should return true if there are not enough bytes in the receive queue', function () {
- expect(sock.rQwait('hi', RQ_TEMPLATE.length + 1)).to.be.true;
- });
-
- it('should return false if there are enough bytes in the receive queue', function () {
- expect(sock.rQwait('hi', RQ_TEMPLATE.length)).to.be.false;
- });
-
- it('should return true and reduce rQi by "goback" if there are not enough bytes', function () {
- sock.rQi = 5;
- expect(sock.rQwait('hi', RQ_TEMPLATE.length, 4)).to.be.true;
- expect(sock.rQi).to.equal(1);
- });
-
- it('should raise an error if we try to go back more than possible', function () {
- sock.rQi = 5;
- expect(() => sock.rQwait('hi', RQ_TEMPLATE.length, 6)).to.throw(Error);
- });
-
- it('should not reduce rQi if there are enough bytes', function () {
- sock.rQi = 5;
- sock.rQwait('hi', 1, 6);
- expect(sock.rQi).to.equal(5);
- });
- });
-
- describe('flush', function () {
- beforeEach(function () {
- sock._websocket = {
- send: sinon.spy()
- };
- });
-
- it('should actually send on the websocket', function () {
- sock._websocket.bufferedAmount = 8;
- sock._websocket.readyState = WebSocket.OPEN;
- sock._sQ = new Uint8Array([1, 2, 3]);
- sock._sQlen = 3;
- const encoded = sock._encode_message();
-
- sock.flush();
- expect(sock._websocket.send).to.have.been.calledOnce;
- expect(sock._websocket.send).to.have.been.calledWith(encoded);
- });
-
- it('should not call send if we do not have anything queued up', function () {
- sock._sQlen = 0;
- sock._websocket.bufferedAmount = 8;
-
- sock.flush();
-
- expect(sock._websocket.send).not.to.have.been.called;
- });
- });
-
- describe('send', function () {
- beforeEach(function () {
- sock.flush = sinon.spy();
- });
-
- it('should add to the send queue', function () {
- sock.send([1, 2, 3]);
- const sq = sock.sQ;
- expect(new Uint8Array(sq.buffer, sock._sQlen - 3, 3)).to.array.equal(new Uint8Array([1, 2, 3]));
- });
-
- it('should call flush', function () {
- sock.send([1, 2, 3]);
- expect(sock.flush).to.have.been.calledOnce;
- });
- });
-
- describe('send_string', function () {
- beforeEach(function () {
- sock.send = sinon.spy();
- });
-
- it('should call send after converting the string to an array', function () {
- sock.send_string("\x01\x02\x03");
- expect(sock.send).to.have.been.calledWith([1, 2, 3]);
- });
- });
- });
-
- describe('lifecycle methods', function () {
- let old_WS;
- before(function () {
- old_WS = WebSocket;
- });
-
- let sock;
- beforeEach(function () {
- sock = new Websock();
- // eslint-disable-next-line no-global-assign
- WebSocket = sinon.spy();
- WebSocket.OPEN = old_WS.OPEN;
- WebSocket.CONNECTING = old_WS.CONNECTING;
- WebSocket.CLOSING = old_WS.CLOSING;
- WebSocket.CLOSED = old_WS.CLOSED;
-
- WebSocket.prototype.binaryType = 'arraybuffer';
- });
-
- describe('opening', function () {
- it('should pick the correct protocols if none are given', function () {
-
- });
-
- it('should open the actual websocket', function () {
- sock.open('ws://localhost:8675', 'binary');
- expect(WebSocket).to.have.been.calledWith('ws://localhost:8675', 'binary');
- });
-
- // it('should initialize the event handlers')?
- });
-
- describe('closing', function () {
- beforeEach(function () {
- sock.open('ws://');
- sock._websocket.close = sinon.spy();
- });
-
- it('should close the actual websocket if it is open', function () {
- sock._websocket.readyState = WebSocket.OPEN;
- sock.close();
- expect(sock._websocket.close).to.have.been.calledOnce;
- });
-
- it('should close the actual websocket if it is connecting', function () {
- sock._websocket.readyState = WebSocket.CONNECTING;
- sock.close();
- expect(sock._websocket.close).to.have.been.calledOnce;
- });
-
- it('should not try to close the actual websocket if closing', function () {
- sock._websocket.readyState = WebSocket.CLOSING;
- sock.close();
- expect(sock._websocket.close).not.to.have.been.called;
- });
-
- it('should not try to close the actual websocket if closed', function () {
- sock._websocket.readyState = WebSocket.CLOSED;
- sock.close();
- expect(sock._websocket.close).not.to.have.been.called;
- });
-
- it('should reset onmessage to not call _recv_message', function () {
- sinon.spy(sock, '_recv_message');
- sock.close();
- sock._websocket.onmessage(null);
- try {
- expect(sock._recv_message).not.to.have.been.called;
- } finally {
- sock._recv_message.restore();
- }
- });
- });
-
- describe('event handlers', function () {
- beforeEach(function () {
- sock._recv_message = sinon.spy();
- sock.on('open', sinon.spy());
- sock.on('close', sinon.spy());
- sock.on('error', sinon.spy());
- sock.open('ws://');
- });
-
- it('should call _recv_message on a message', function () {
- sock._websocket.onmessage(null);
- expect(sock._recv_message).to.have.been.calledOnce;
- });
-
- it('should call the open event handler on opening', function () {
- sock._websocket.onopen();
- expect(sock._eventHandlers.open).to.have.been.calledOnce;
- });
-
- it('should call the close event handler on closing', function () {
- sock._websocket.onclose();
- expect(sock._eventHandlers.close).to.have.been.calledOnce;
- });
-
- it('should call the error event handler on error', function () {
- sock._websocket.onerror();
- expect(sock._eventHandlers.error).to.have.been.calledOnce;
- });
- });
-
- after(function () {
- // eslint-disable-next-line no-global-assign
- WebSocket = old_WS;
- });
- });
-
- describe('WebSocket Receiving', function () {
- let sock;
- beforeEach(function () {
- sock = new Websock();
- sock._allocate_buffers();
- });
-
- it('should support adding binary Uint8Array data to the receive queue', function () {
- const msg = { data: new Uint8Array([1, 2, 3]) };
- sock._mode = 'binary';
- sock._recv_message(msg);
- expect(sock.rQshiftStr(3)).to.equal('\x01\x02\x03');
- });
-
- it('should call the message event handler if present', function () {
- sock._eventHandlers.message = sinon.spy();
- const msg = { data: new Uint8Array([1, 2, 3]).buffer };
- sock._mode = 'binary';
- sock._recv_message(msg);
- expect(sock._eventHandlers.message).to.have.been.calledOnce;
- });
-
- it('should not call the message event handler if there is nothing in the receive queue', function () {
- sock._eventHandlers.message = sinon.spy();
- const msg = { data: new Uint8Array([]).buffer };
- sock._mode = 'binary';
- sock._recv_message(msg);
- expect(sock._eventHandlers.message).not.to.have.been.called;
- });
-
- it('should compact the receive queue', function () {
- // NB(sross): while this is an internal implementation detail, it's important to
- // test, otherwise the receive queue could become very large very quickly
- sock._rQ = new Uint8Array([0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
- sock._rQlen = 6;
- sock.rQi = 6;
- sock._rQmax = 3;
- const msg = { data: new Uint8Array([1, 2, 3]).buffer };
- sock._mode = 'binary';
- sock._recv_message(msg);
- expect(sock._rQlen).to.equal(3);
- expect(sock.rQi).to.equal(0);
- });
-
- it('should automatically resize the receive queue if the incoming message is too large', function () {
- sock._rQ = new Uint8Array(20);
- sock._rQlen = 0;
- sock.rQi = 0;
- sock._rQbufferSize = 20;
- sock._rQmax = 2;
- const msg = { data: new Uint8Array(30).buffer };
- sock._mode = 'binary';
- sock._recv_message(msg);
- expect(sock._rQlen).to.equal(30);
- expect(sock.rQi).to.equal(0);
- expect(sock._rQ.length).to.equal(240); // keep the invariant that rQbufferSize / 8 >= rQlen
- });
- });
-
- describe('Data encoding', function () {
- before(function () { FakeWebSocket.replace(); });
- after(function () { FakeWebSocket.restore(); });
-
- describe('as binary data', function () {
- let sock;
- beforeEach(function () {
- sock = new Websock();
- sock.open('ws://', 'binary');
- sock._websocket._open();
- });
-
- it('should only send the send queue up to the send queue length', function () {
- sock._sQ = new Uint8Array([1, 2, 3, 4, 5]);
- sock._sQlen = 3;
- const res = sock._encode_message();
- expect(res).to.array.equal(new Uint8Array([1, 2, 3]));
- });
-
- it('should properly pass the encoded data off to the actual WebSocket', function () {
- sock.send([1, 2, 3]);
- expect(sock._websocket._get_sent_data()).to.array.equal(new Uint8Array([1, 2, 3]));
- });
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/test.webutil.js b/systemvm/agent/noVNC/tests/test.webutil.js
deleted file mode 100644
index 72e1942..0000000
--- a/systemvm/agent/noVNC/tests/test.webutil.js
+++ /dev/null
@@ -1,184 +0,0 @@
-/* jshint expr: true */
-
-const expect = chai.expect;
-
-import * as WebUtil from '../app/webutil.js';
-
-describe('WebUtil', function () {
- "use strict";
-
- describe('settings', function () {
-
- describe('localStorage', function () {
- let chrome = window.chrome;
- before(function () {
- chrome = window.chrome;
- window.chrome = null;
- });
- after(function () {
- window.chrome = chrome;
- });
-
- let origLocalStorage;
- beforeEach(function () {
- origLocalStorage = Object.getOwnPropertyDescriptor(window, "localStorage");
- if (origLocalStorage === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "localStorage", {value: {}});
- if (window.localStorage.setItem !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.localStorage.setItem = sinon.stub();
- window.localStorage.getItem = sinon.stub();
- window.localStorage.removeItem = sinon.stub();
-
- return WebUtil.initSettings();
- });
- afterEach(function () {
- Object.defineProperty(window, "localStorage", origLocalStorage);
- });
-
- describe('writeSetting', function () {
- it('should save the setting value to local storage', function () {
- WebUtil.writeSetting('test', 'value');
- expect(window.localStorage.setItem).to.have.been.calledWithExactly('test', 'value');
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
- });
-
- describe('setSetting', function () {
- it('should update the setting but not save to local storage', function () {
- WebUtil.setSetting('test', 'value');
- expect(window.localStorage.setItem).to.not.have.been.called;
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
- });
-
- describe('readSetting', function () {
- it('should read the setting value from local storage', function () {
- localStorage.getItem.returns('value');
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
-
- it('should return the default value when not in local storage', function () {
- expect(WebUtil.readSetting('test', 'default')).to.equal('default');
- });
-
- it('should return the cached value even if local storage changed', function () {
- localStorage.getItem.returns('value');
- expect(WebUtil.readSetting('test')).to.equal('value');
- localStorage.getItem.returns('something else');
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
-
- it('should cache the value even if it is not initially in local storage', function () {
- expect(WebUtil.readSetting('test')).to.be.null;
- localStorage.getItem.returns('value');
- expect(WebUtil.readSetting('test')).to.be.null;
- });
-
- it('should return the default value always if the first read was not in local storage', function () {
- expect(WebUtil.readSetting('test', 'default')).to.equal('default');
- localStorage.getItem.returns('value');
- expect(WebUtil.readSetting('test', 'another default')).to.equal('another default');
- });
-
- it('should return the last local written value', function () {
- localStorage.getItem.returns('value');
- expect(WebUtil.readSetting('test')).to.equal('value');
- WebUtil.writeSetting('test', 'something else');
- expect(WebUtil.readSetting('test')).to.equal('something else');
- });
- });
-
- // this doesn't appear to be used anywhere
- describe('eraseSetting', function () {
- it('should remove the setting from local storage', function () {
- WebUtil.eraseSetting('test');
- expect(window.localStorage.removeItem).to.have.been.calledWithExactly('test');
- });
- });
- });
-
- describe('chrome.storage', function () {
- let chrome = window.chrome;
- let settings = {};
- before(function () {
- chrome = window.chrome;
- window.chrome = {
- storage: {
- sync: {
- get(cb) { cb(settings); },
- set() {},
- remove() {}
- }
- }
- };
- });
- after(function () {
- window.chrome = chrome;
- });
-
- const csSandbox = sinon.createSandbox();
-
- beforeEach(function () {
- settings = {};
- csSandbox.spy(window.chrome.storage.sync, 'set');
- csSandbox.spy(window.chrome.storage.sync, 'remove');
- return WebUtil.initSettings();
- });
- afterEach(function () {
- csSandbox.restore();
- });
-
- describe('writeSetting', function () {
- it('should save the setting value to chrome storage', function () {
- WebUtil.writeSetting('test', 'value');
- expect(window.chrome.storage.sync.set).to.have.been.calledWithExactly(sinon.match({ test: 'value' }));
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
- });
-
- describe('setSetting', function () {
- it('should update the setting but not save to chrome storage', function () {
- WebUtil.setSetting('test', 'value');
- expect(window.chrome.storage.sync.set).to.not.have.been.called;
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
- });
-
- describe('readSetting', function () {
- it('should read the setting value from chrome storage', function () {
- settings.test = 'value';
- expect(WebUtil.readSetting('test')).to.equal('value');
- });
-
- it('should return the default value when not in chrome storage', function () {
- expect(WebUtil.readSetting('test', 'default')).to.equal('default');
- });
-
- it('should return the last local written value', function () {
- settings.test = 'value';
- expect(WebUtil.readSetting('test')).to.equal('value');
- WebUtil.writeSetting('test', 'something else');
- expect(WebUtil.readSetting('test')).to.equal('something else');
- });
- });
-
- // this doesn't appear to be used anywhere
- describe('eraseSetting', function () {
- it('should remove the setting from chrome storage', function () {
- WebUtil.eraseSetting('test');
- expect(window.chrome.storage.sync.remove).to.have.been.calledWithExactly('test');
- });
- });
- });
- });
-});
diff --git a/systemvm/agent/noVNC/tests/vnc_playback.html b/systemvm/agent/noVNC/tests/vnc_playback.html
deleted file mode 100644
index 4fd7465..0000000
--- a/systemvm/agent/noVNC/tests/vnc_playback.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <title>VNC Playback</title>
- <!-- promise polyfills promises for IE11 -->
- <script src="../vendor/promise.js"></script>
- <!-- ES2015/ES6 modules polyfill -->
- <script type="module">
- window._noVNC_has_module_support = true;
- </script>
- <script>
- window.addEventListener("load", function() {
- if (window._noVNC_has_module_support) return;
- var loader = document.createElement("script");
- loader.src = "../vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
- document.head.appendChild(loader);
- });
- </script>
- <!-- actual script modules -->
- <script type="module" src="./playback-ui.js"></script>
- </head>
- <body>
-
- Iterations: <input id='iterations'>
- Perftest:<input type='radio' id='mode1' name='mode' checked>
- Realtime:<input type='radio' id='mode2' name='mode'>
-
- <input id='startButton' type='button' value='Start' disabled>
-
- <br><br>
-
- Results:<br>
- <textarea id="messages" cols=80 rows=25></textarea>
-
- <br><br>
-
- <div id="VNC_screen">
- <div id="VNC_status">Loading</div>
- </div>
-
- <script type="module" src="./playback-ui.js"></script>
- </body>
-</html>
diff --git a/systemvm/agent/noVNC/utils/.eslintrc b/systemvm/agent/noVNC/utils/.eslintrc
deleted file mode 100644
index b7dc129..0000000
--- a/systemvm/agent/noVNC/utils/.eslintrc
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "env": {
- "node": true
- },
- "rules": {
- "no-console": 0
- }
-}
\ No newline at end of file
diff --git a/systemvm/agent/noVNC/utils/README.md b/systemvm/agent/noVNC/utils/README.md
deleted file mode 100644
index 32582e6..0000000
--- a/systemvm/agent/noVNC/utils/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-## WebSockets Proxy/Bridge
-
-Websockify has been forked out into its own project. `launch.sh` wil
-automatically download it here if it is not already present and not
-installed as system-wide.
-
-For more detailed description and usage information please refer to
-the [websockify README](https://github.com/novnc/websockify/blob/master/README.md).
-
-The other versions of websockify (C, Node.js) and the associated test
-programs have been moved to
-[websockify](https://github.com/novnc/websockify). Websockify was
-formerly named wsproxy.
-
diff --git a/systemvm/agent/noVNC/utils/b64-to-binary.pl b/systemvm/agent/noVNC/utils/b64-to-binary.pl
deleted file mode 100755
index 280e28c..0000000
--- a/systemvm/agent/noVNC/utils/b64-to-binary.pl
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env perl
-use MIME::Base64;
-
-for (<>) {
- unless (/^'([{}])(\d+)\1(.+?)',$/) {
- print;
- next;
- }
-
- my ($dir, $amt, $b64) = ($1, $2, $3);
-
- my $decoded = MIME::Base64::decode($b64) or die "Could not base64-decode line `$_`";
-
- my $decoded_escaped = join "", map { "\\x$_" } unpack("(H2)*", $decoded);
-
- print "'${dir}${amt}${dir}${decoded_escaped}',\n";
-}
diff --git a/systemvm/agent/noVNC/utils/genkeysymdef.js b/systemvm/agent/noVNC/utils/genkeysymdef.js
deleted file mode 100755
index d21773f..0000000
--- a/systemvm/agent/noVNC/utils/genkeysymdef.js
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env node
-/*
- * genkeysymdef: X11 keysymdef.h to JavaScript converter
- * Copyright (C) 2018 The noVNC Authors
- * Licensed under MPL 2.0 (see LICENSE.txt)
- */
-
-"use strict";
-
-const fs = require('fs');
-
-let show_help = process.argv.length === 2;
-let filename;
-
-for (let i = 2; i < process.argv.length; ++i) {
- switch (process.argv[i]) {
- case "--help":
- case "-h":
- show_help = true;
- break;
- case "--file":
- case "-f":
- default:
- filename = process.argv[i];
- }
-}
-
-if (!filename) {
- show_help = true;
- console.log("Error: No filename specified\n");
-}
-
-if (show_help) {
- console.log("Parses a *nix keysymdef.h to generate Unicode code point mappings");
- console.log("Usage: node parse.js [options] filename:");
- console.log(" -h [ --help ] Produce this help message");
- console.log(" filename The keysymdef.h file to parse");
- process.exit(0);
-}
-
-const buf = fs.readFileSync(filename);
-const str = buf.toString('utf8');
-
-const re = /^#define XK_([a-zA-Z_0-9]+)\s+0x([0-9a-fA-F]+)\s*(\/\*\s*(.*)\s*\*\/)?\s*$/m;
-
-const arr = str.split('\n');
-
-const codepoints = {};
-
-for (let i = 0; i < arr.length; ++i) {
- const result = re.exec(arr[i]);
- if (result) {
- const keyname = result[1];
- const keysym = parseInt(result[2], 16);
- const remainder = result[3];
-
- const unicodeRes = /U\+([0-9a-fA-F]+)/.exec(remainder);
- if (unicodeRes) {
- const unicode = parseInt(unicodeRes[1], 16);
- // The first entry is the preferred one
- if (!codepoints[unicode]) {
- codepoints[unicode] = { keysym: keysym, name: keyname };
- }
- }
- }
-}
-
-let out =
-"/*\n" +
-" * Mapping from Unicode codepoints to X11/RFB keysyms\n" +
-" *\n" +
-" * This file was automatically generated from keysymdef.h\n" +
-" * DO NOT EDIT!\n" +
-" */\n" +
-"\n" +
-"/* Functions at the bottom */\n" +
-"\n" +
-"const codepoints = {\n";
-
-function toHex(num) {
- let s = num.toString(16);
- if (s.length < 4) {
- s = ("0000" + s).slice(-4);
- }
- return "0x" + s;
-}
-
-for (let codepoint in codepoints) {
- codepoint = parseInt(codepoint);
-
- // Latin-1?
- if ((codepoint >= 0x20) && (codepoint <= 0xff)) {
- continue;
- }
-
- // Handled by the general Unicode mapping?
- if ((codepoint | 0x01000000) === codepoints[codepoint].keysym) {
- continue;
- }
-
- out += " " + toHex(codepoint) + ": " +
- toHex(codepoints[codepoint].keysym) +
- ", // XK_" + codepoints[codepoint].name + "\n";
-}
-
-out +=
-"};\n" +
-"\n" +
-"export default {\n" +
-" lookup(u) {\n" +
-" // Latin-1 is one-to-one mapping\n" +
-" if ((u >= 0x20) && (u <= 0xff)) {\n" +
-" return u;\n" +
-" }\n" +
-"\n" +
-" // Lookup table (fairly random)\n" +
-" const keysym = codepoints[u];\n" +
-" if (keysym !== undefined) {\n" +
-" return keysym;\n" +
-" }\n" +
-"\n" +
-" // General mapping as final fallback\n" +
-" return 0x01000000 | u;\n" +
-" },\n" +
-"};";
-
-console.log(out);
diff --git a/systemvm/agent/noVNC/utils/img2js.py b/systemvm/agent/noVNC/utils/img2js.py
deleted file mode 100755
index ceab6bf..0000000
--- a/systemvm/agent/noVNC/utils/img2js.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Convert image to Javascript compatible base64 Data URI
-# Copyright (C) 2018 The noVNC Authors
-# Licensed under MPL 2.0 (see docs/LICENSE.MPL-2.0)
-#
-
-import sys, base64
-
-try:
- from PIL import Image
-except:
- print "python PIL module required (python-imaging package)"
- sys.exit(1)
-
-
-if len(sys.argv) < 3:
- print "Usage: %s IMAGE JS_VARIABLE" % sys.argv[0]
- sys.exit(1)
-
-fname = sys.argv[1]
-var = sys.argv[2]
-
-ext = fname.lower().split('.')[-1]
-if ext == "png": mime = "image/png"
-elif ext in ["jpg", "jpeg"]: mime = "image/jpeg"
-elif ext == "gif": mime = "image/gif"
-else:
- print "Only PNG, JPEG and GIF images are supported"
- sys.exit(1)
-uri = "data:%s;base64," % mime
-
-im = Image.open(fname)
-w, h = im.size
-
-raw = open(fname).read()
-
-print '%s = {"width": %s, "height": %s, "data": "%s%s"};' % (
- var, w, h, uri, base64.b64encode(raw))
diff --git a/systemvm/agent/noVNC/utils/json2graph.py b/systemvm/agent/noVNC/utils/json2graph.py
deleted file mode 100755
index bdaeecc..0000000
--- a/systemvm/agent/noVNC/utils/json2graph.py
+++ /dev/null
@@ -1,206 +0,0 @@
-#!/usr/bin/env python
-
-'''
-Use matplotlib to generate performance charts
-Copyright (C) 2018 The noVNC Authors
-Licensed under MPL-2.0 (see docs/LICENSE.MPL-2.0)
-'''
-
-# a bar plot with errorbars
-import sys, json
-import numpy as np
-import matplotlib.pyplot as plt
-from matplotlib.font_manager import FontProperties
-
-def usage():
- print "%s json_file level1 level2 level3 [legend_height]\n\n" % sys.argv[0]
- print "Description:\n"
- print "level1, level2, and level3 are one each of the following:\n";
- print " select=ITEM - select only ITEM at this level";
- print " bar - each item on this level becomes a graph bar";
- print " group - items on this level become groups of bars";
- print "\n";
- print "json_file is a file containing json data in the following format:\n"
- print ' {';
- print ' "conf": {';
- print ' "order_l1": [';
- print ' "level1_label1",';
- print ' "level1_label2",';
- print ' ...';
- print ' ],';
- print ' "order_l2": [';
- print ' "level2_label1",';
- print ' "level2_label2",';
- print ' ...';
- print ' ],';
- print ' "order_l3": [';
- print ' "level3_label1",';
- print ' "level3_label2",';
- print ' ...';
- print ' ]';
- print ' },';
- print ' "stats": {';
- print ' "level1_label1": {';
- print ' "level2_label1": {';
- print ' "level3_label1": [val1, val2, val3],';
- print ' "level3_label2": [val1, val2, val3],';
- print ' ...';
- print ' },';
- print ' "level2_label2": {';
- print ' ...';
- print ' },';
- print ' },';
- print ' "level1_label2": {';
- print ' ...';
- print ' },';
- print ' ...';
- print ' },';
- print ' }';
- sys.exit(2)
-
-def error(msg):
- print msg
- sys.exit(1)
-
-
-#colors = ['#ff0000', '#0863e9', '#00f200', '#ffa100',
-# '#800000', '#805100', '#013075', '#007900']
-colors = ['#ff0000', '#00ff00', '#0000ff',
- '#dddd00', '#dd00dd', '#00dddd',
- '#dd6622', '#dd2266', '#66dd22',
- '#8844dd', '#44dd88', '#4488dd']
-
-if len(sys.argv) < 5:
- usage()
-
-filename = sys.argv[1]
-L1 = sys.argv[2]
-L2 = sys.argv[3]
-L3 = sys.argv[4]
-if len(sys.argv) > 5:
- legendHeight = float(sys.argv[5])
-else:
- legendHeight = 0.75
-
-# Load the JSON data from the file
-data = json.loads(file(filename).read())
-conf = data['conf']
-stats = data['stats']
-
-# Sanity check data hierarchy
-if len(conf['order_l1']) != len(stats.keys()):
- error("conf.order_l1 does not match stats level 1")
-for l1 in stats.keys():
- if len(conf['order_l2']) != len(stats[l1].keys()):
- error("conf.order_l2 does not match stats level 2 for %s" % l1)
- if conf['order_l1'].count(l1) < 1:
- error("%s not found in conf.order_l1" % l1)
- for l2 in stats[l1].keys():
- if len(conf['order_l3']) != len(stats[l1][l2].keys()):
- error("conf.order_l3 does not match stats level 3")
- if conf['order_l2'].count(l2) < 1:
- error("%s not found in conf.order_l2" % l2)
- for l3 in stats[l1][l2].keys():
- if conf['order_l3'].count(l3) < 1:
- error("%s not found in conf.order_l3" % l3)
-
-#
-# Generate the data based on the level specifications
-#
-bar_labels = None
-group_labels = None
-bar_vals = []
-bar_sdvs = []
-if L3.startswith("select="):
- select_label = l3 = L3.split("=")[1]
- bar_labels = conf['order_l1']
- group_labels = conf['order_l2']
- bar_vals = [[0]*len(group_labels) for i in bar_labels]
- bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
- for b in range(len(bar_labels)):
- l1 = bar_labels[b]
- for g in range(len(group_labels)):
- l2 = group_labels[g]
- bar_vals[b][g] = np.mean(stats[l1][l2][l3])
- bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
-elif L2.startswith("select="):
- select_label = l2 = L2.split("=")[1]
- bar_labels = conf['order_l1']
- group_labels = conf['order_l3']
- bar_vals = [[0]*len(group_labels) for i in bar_labels]
- bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
- for b in range(len(bar_labels)):
- l1 = bar_labels[b]
- for g in range(len(group_labels)):
- l3 = group_labels[g]
- bar_vals[b][g] = np.mean(stats[l1][l2][l3])
- bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
-elif L1.startswith("select="):
- select_label = l1 = L1.split("=")[1]
- bar_labels = conf['order_l2']
- group_labels = conf['order_l3']
- bar_vals = [[0]*len(group_labels) for i in bar_labels]
- bar_sdvs = [[0]*len(group_labels) for i in bar_labels]
- for b in range(len(bar_labels)):
- l2 = bar_labels[b]
- for g in range(len(group_labels)):
- l3 = group_labels[g]
- bar_vals[b][g] = np.mean(stats[l1][l2][l3])
- bar_sdvs[b][g] = np.std(stats[l1][l2][l3])
-else:
- usage()
-
-# If group is before bar then flip (zip) the data
-if [L1, L2, L3].index("group") < [L1, L2, L3].index("bar"):
- bar_labels, group_labels = group_labels, bar_labels
- bar_vals = zip(*bar_vals)
- bar_sdvs = zip(*bar_sdvs)
-
-print "bar_vals:", bar_vals
-
-#
-# Now render the bar graph
-#
-ind = np.arange(len(group_labels)) # the x locations for the groups
-width = 0.8 * (1.0/len(bar_labels)) # the width of the bars
-
-fig = plt.figure(figsize=(10,6), dpi=80)
-plot = fig.add_subplot(1, 1, 1)
-
-rects = []
-for i in range(len(bar_vals)):
- rects.append(plot.bar(ind+width*i, bar_vals[i], width, color=colors[i],
- yerr=bar_sdvs[i], align='center'))
-
-# add some
-plot.set_ylabel('Milliseconds (less is better)')
-plot.set_title("Javascript array test: %s" % select_label)
-plot.set_xticks(ind+width)
-plot.set_xticklabels( group_labels )
-
-fontP = FontProperties()
-fontP.set_size('small')
-plot.legend( [r[0] for r in rects], bar_labels, prop=fontP,
- loc = 'center right', bbox_to_anchor = (1.0, legendHeight))
-
-def autolabel(rects):
- # attach some text labels
- for rect in rects:
- height = rect.get_height()
- if np.isnan(height):
- height = 0.0
- plot.text(rect.get_x()+rect.get_width()/2., height+20, '%d'%int(height),
- ha='center', va='bottom', size='7')
-
-for rect in rects:
- autolabel(rect)
-
-# Adjust axis sizes
-axis = list(plot.axis())
-axis[0] = -width # Make sure left side has enough for bar
-#axis[1] = axis[1] * 1.20 # Add 20% to the right to make sure it fits
-axis[2] = 0 # Make y-axis start at 0
-axis[3] = axis[3] * 1.10 # Add 10% to the top
-plot.axis(axis)
-
-plt.show()
diff --git a/systemvm/agent/noVNC/utils/launch.sh b/systemvm/agent/noVNC/utils/launch.sh
deleted file mode 100755
index 162607e..0000000
--- a/systemvm/agent/noVNC/utils/launch.sh
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (C) 2018 The noVNC Authors
-# Licensed under MPL 2.0 or any later version (see LICENSE.txt)
-
-usage() {
- if [ "$*" ]; then
- echo "$*"
- echo
- fi
- echo "Usage: ${NAME} [--listen PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only]"
- echo
- echo "Starts the WebSockets proxy and a mini-webserver and "
- echo "provides a cut-and-paste URL to go to."
- echo
- echo " --listen PORT Port for proxy/webserver to listen on"
- echo " Default: 6080"
- echo " --vnc VNC_HOST:PORT VNC server host:port proxy target"
- echo " Default: localhost:5900"
- echo " --cert CERT Path to combined cert/key file"
- echo " Default: self.pem"
- echo " --web WEB Path to web files (e.g. vnc.html)"
- echo " Default: ./"
- echo " --ssl-only Disable non-https connections."
- echo " "
- echo " --record FILE Record traffic to FILE.session.js"
- echo " "
- exit 2
-}
-
-NAME="$(basename $0)"
-REAL_NAME="$(readlink -f $0)"
-HERE="$(cd "$(dirname "$REAL_NAME")" && pwd)"
-PORT="6080"
-VNC_DEST="localhost:5900"
-CERT=""
-WEB=""
-proxy_pid=""
-SSLONLY=""
-RECORD_ARG=""
-
-die() {
- echo "$*"
- exit 1
-}
-
-cleanup() {
- trap - TERM QUIT INT EXIT
- trap "true" CHLD # Ignore cleanup messages
- echo
- if [ -n "${proxy_pid}" ]; then
- echo "Terminating WebSockets proxy (${proxy_pid})"
- kill ${proxy_pid}
- fi
-}
-
-# Process Arguments
-
-# Arguments that only apply to chrooter itself
-while [ "$*" ]; do
- param=$1; shift; OPTARG=$1
- case $param in
- --listen) PORT="${OPTARG}"; shift ;;
- --vnc) VNC_DEST="${OPTARG}"; shift ;;
- --cert) CERT="${OPTARG}"; shift ;;
- --web) WEB="${OPTARG}"; shift ;;
- --ssl-only) SSLONLY="--ssl-only" ;;
- --record) RECORD_ARG="--record ${OPTARG}"; shift ;;
- -h|--help) usage ;;
- -*) usage "Unknown chrooter option: ${param}" ;;
- *) break ;;
- esac
-done
-
-# Sanity checks
-if bash -c "exec 7<>/dev/tcp/localhost/${PORT}" &> /dev/null; then
- exec 7<&-
- exec 7>&-
- die "Port ${PORT} in use. Try --listen PORT"
-else
- exec 7<&-
- exec 7>&-
-fi
-
-trap "cleanup" TERM QUIT INT EXIT
-
-# Find vnc.html
-if [ -n "${WEB}" ]; then
- if [ ! -e "${WEB}/vnc.html" ]; then
- die "Could not find ${WEB}/vnc.html"
- fi
-elif [ -e "$(pwd)/vnc.html" ]; then
- WEB=$(pwd)
-elif [ -e "${HERE}/../vnc.html" ]; then
- WEB=${HERE}/../
-elif [ -e "${HERE}/vnc.html" ]; then
- WEB=${HERE}
-elif [ -e "${HERE}/../share/novnc/vnc.html" ]; then
- WEB=${HERE}/../share/novnc/
-else
- die "Could not find vnc.html"
-fi
-
-# Find self.pem
-if [ -n "${CERT}" ]; then
- if [ ! -e "${CERT}" ]; then
- die "Could not find ${CERT}"
- fi
-elif [ -e "$(pwd)/self.pem" ]; then
- CERT="$(pwd)/self.pem"
-elif [ -e "${HERE}/../self.pem" ]; then
- CERT="${HERE}/../self.pem"
-elif [ -e "${HERE}/self.pem" ]; then
- CERT="${HERE}/self.pem"
-else
- echo "Warning: could not find self.pem"
-fi
-
-# try to find websockify (prefer local, try global, then download local)
-if [[ -e ${HERE}/websockify ]]; then
- WEBSOCKIFY=${HERE}/websockify/run
-
- if [[ ! -x $WEBSOCKIFY ]]; then
- echo "The path ${HERE}/websockify exists, but $WEBSOCKIFY either does not exist or is not executable."
- echo "If you intended to use an installed websockify package, please remove ${HERE}/websockify."
- exit 1
- fi
-
- echo "Using local websockify at $WEBSOCKIFY"
-else
- WEBSOCKIFY=$(which websockify 2>/dev/null)
-
- if [[ $? -ne 0 ]]; then
- echo "No installed websockify, attempting to clone websockify..."
- WEBSOCKIFY=${HERE}/websockify/run
- git clone https://github.com/novnc/websockify ${HERE}/websockify
-
- if [[ ! -e $WEBSOCKIFY ]]; then
- echo "Unable to locate ${HERE}/websockify/run after downloading"
- exit 1
- fi
-
- echo "Using local websockify at $WEBSOCKIFY"
- else
- echo "Using installed websockify at $WEBSOCKIFY"
- fi
-fi
-
-echo "Starting webserver and WebSockets proxy on port ${PORT}"
-#${HERE}/websockify --web ${WEB} ${CERT:+--cert ${CERT}} ${PORT} ${VNC_DEST} &
-${WEBSOCKIFY} ${SSLONLY} --web ${WEB} ${CERT:+--cert ${CERT}} ${PORT} ${VNC_DEST} ${RECORD_ARG} &
-proxy_pid="$!"
-sleep 1
-if ! ps -p ${proxy_pid} >/dev/null; then
- proxy_pid=
- echo "Failed to start WebSockets proxy"
- exit 1
-fi
-
-echo -e "\n\nNavigate to this URL:\n"
-if [ "x$SSLONLY" == "x" ]; then
- echo -e " http://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n"
-else
- echo -e " https://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n"
-fi
-
-echo -e "Press Ctrl-C to exit\n\n"
-
-wait ${proxy_pid}
diff --git a/systemvm/agent/noVNC/utils/u2x11 b/systemvm/agent/noVNC/utils/u2x11
deleted file mode 100755
index fd3e4ba..0000000
--- a/systemvm/agent/noVNC/utils/u2x11
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-#
-# Convert "U+..." commented entries in /usr/include/X11/keysymdef.h
-# into JavaScript for use by noVNC. Note this is likely to produce
-# a few duplicate properties with clashing values, that will need
-# resolving manually.
-#
-# Colin Dean <colin@xvpsource.org>
-#
-
-regex="^#define[ \t]+XK_[A-Za-z0-9_]+[ \t]+0x([0-9a-fA-F]+)[ \t]+\/\*[ \t]+U\+([0-9a-fA-F]+)[ \t]+[^*]+.[ \t]+\*\/[ \t]*$"
-echo "unicodeTable = {"
-while read line; do
- if echo "${line}" | egrep -qs "${regex}"; then
-
- x11=$(echo "${line}" | sed -r "s/${regex}/\1/")
- vnc=$(echo "${line}" | sed -r "s/${regex}/\2/")
-
- if echo "${vnc}" | egrep -qs "^00[2-9A-F][0-9A-F]$"; then
- : # skip ISO Latin-1 (U+0020 to U+00FF) as 1-to-1 mapping
- else
- # note 1-to-1 is possible (e.g. for Euro symbol, U+20AC)
- echo " 0x${vnc} : 0x${x11},"
- fi
- fi
-done < /usr/include/X11/keysymdef.h | uniq
-echo "};"
-
diff --git a/systemvm/agent/noVNC/utils/use_require.js b/systemvm/agent/noVNC/utils/use_require.js
deleted file mode 100755
index 2487927..0000000
--- a/systemvm/agent/noVNC/utils/use_require.js
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/usr/bin/env node
-
-const path = require('path');
-const program = require('commander');
-const fs = require('fs');
-const fse = require('fs-extra');
-const babel = require('babel-core');
-
-const SUPPORTED_FORMATS = new Set(['amd', 'commonjs', 'systemjs', 'umd']);
-
-program
- .option('--as [format]', `output files using various import formats instead of ES6 import and export. Supports ${Array.from(SUPPORTED_FORMATS)}.`)
- .option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ')
- .option('--with-app', 'process app files as well as core files')
- .option('--only-legacy', 'only output legacy files (no ES6 modules) for the app')
- .option('--clean', 'clear the lib folder before building')
- .parse(process.argv);
-
-// the various important paths
-const paths = {
- main: path.resolve(__dirname, '..'),
- core: path.resolve(__dirname, '..', 'core'),
- app: path.resolve(__dirname, '..', 'app'),
- vendor: path.resolve(__dirname, '..', 'vendor'),
- out_dir_base: path.resolve(__dirname, '..', 'build'),
- lib_dir_base: path.resolve(__dirname, '..', 'lib'),
-};
-
-const no_copy_files = new Set([
- // skip these -- they don't belong in the processed application
- path.join(paths.vendor, 'sinon.js'),
- path.join(paths.vendor, 'browser-es-module-loader'),
- path.join(paths.vendor, 'promise.js'),
- path.join(paths.app, 'images', 'icons', 'Makefile'),
-]);
-
-const no_transform_files = new Set([
- // don't transform this -- we want it imported as-is to properly catch loading errors
- path.join(paths.app, 'error-handler.js'),
-]);
-
-no_copy_files.forEach(file => no_transform_files.add(file));
-
-// util.promisify requires Node.js 8.x, so we have our own
-function promisify(original) {
- return function promise_wrap() {
- const args = Array.prototype.slice.call(arguments);
- return new Promise((resolve, reject) => {
- original.apply(this, args.concat((err, value) => {
- if (err) return reject(err);
- resolve(value);
- }));
- });
- };
-}
-
-const readFile = promisify(fs.readFile);
-const writeFile = promisify(fs.writeFile);
-
-const readdir = promisify(fs.readdir);
-const lstat = promisify(fs.lstat);
-
-const copy = promisify(fse.copy);
-const unlink = promisify(fse.unlink);
-const ensureDir = promisify(fse.ensureDir);
-const rmdir = promisify(fse.rmdir);
-
-const babelTransformFile = promisify(babel.transformFile);
-
-// walkDir *recursively* walks directories trees,
-// calling the callback for all normal files found.
-function walkDir(base_path, cb, filter) {
- return readdir(base_path)
- .then((files) => {
- const paths = files.map(filename => path.join(base_path, filename));
- return Promise.all(paths.map(filepath => lstat(filepath)
- .then((stats) => {
- if (filter !== undefined && !filter(filepath, stats)) return;
-
- if (stats.isSymbolicLink()) return;
- if (stats.isFile()) return cb(filepath);
- if (stats.isDirectory()) return walkDir(filepath, cb, filter);
- })));
- });
-}
-
-function transform_html(legacy_scripts, only_legacy) {
- // write out the modified vnc.html file that works with the bundle
- const src_html_path = path.resolve(__dirname, '..', 'vnc.html');
- const out_html_path = path.resolve(paths.out_dir_base, 'vnc.html');
- return readFile(src_html_path)
- .then((contents_raw) => {
- let contents = contents_raw.toString();
-
- const start_marker = '<!-- begin scripts -->\n';
- const end_marker = '<!-- end scripts -->';
- const start_ind = contents.indexOf(start_marker) + start_marker.length;
- const end_ind = contents.indexOf(end_marker, start_ind);
-
- let new_script = '';
-
- if (only_legacy) {
- // Only legacy version, so include things directly
- for (let i = 0;i < legacy_scripts.length;i++) {
- new_script += ` <script src="${legacy_scripts[i]}"></script>\n`;
- }
- } else {
- // Otherwise detect if it's a modern browser and select
- // variant accordingly
- new_script += `\
- <script type="module">\n\
- window._noVNC_has_module_support = true;\n\
- </script>\n\
- <script>\n\
- window.addEventListener("load", function() {\n\
- if (window._noVNC_has_module_support) return;\n\
- let legacy_scripts = ${JSON.stringify(legacy_scripts)};\n\
- for (let i = 0;i < legacy_scripts.length;i++) {\n\
- let script = document.createElement("script");\n\
- script.src = legacy_scripts[i];\n\
- script.async = false;\n\
- document.head.appendChild(script);\n\
- }\n\
- });\n\
- </script>\n`;
-
- // Original, ES6 modules
- new_script += ' <script type="module" crossorigin="anonymous" src="app/ui.js"></script>\n';
- }
-
- contents = contents.slice(0, start_ind) + `${new_script}\n` + contents.slice(end_ind);
-
- return contents;
- })
- .then((contents) => {
- console.log(`Writing ${out_html_path}`);
- return writeFile(out_html_path, contents);
- });
-}
-
-function make_lib_files(import_format, source_maps, with_app_dir, only_legacy) {
- if (!import_format) {
- throw new Error("you must specify an import format to generate compiled noVNC libraries");
- } else if (!SUPPORTED_FORMATS.has(import_format)) {
- throw new Error(`unsupported output format "${import_format}" for import/export -- only ${Array.from(SUPPORTED_FORMATS)} are supported`);
- }
-
- // NB: we need to make a copy of babel_opts, since babel sets some defaults on it
- const babel_opts = () => ({
- plugins: [`transform-es2015-modules-${import_format}`],
- presets: ['es2015'],
- ast: false,
- sourceMaps: source_maps,
- });
-
- // No point in duplicate files without the app, so force only converted files
- if (!with_app_dir) {
- only_legacy = true;
- }
-
- let in_path;
- let out_path_base;
- if (with_app_dir) {
- out_path_base = paths.out_dir_base;
- in_path = paths.main;
- } else {
- out_path_base = paths.lib_dir_base;
- }
- const legacy_path_base = only_legacy ? out_path_base : path.join(out_path_base, 'legacy');
-
- fse.ensureDirSync(out_path_base);
-
- const helpers = require('./use_require_helpers');
- const helper = helpers[import_format];
-
- const outFiles = [];
-
- const handleDir = (js_only, vendor_rewrite, in_path_base, filename) => Promise.resolve()
- .then(() => {
- if (no_copy_files.has(filename)) return;
-
- const out_path = path.join(out_path_base, path.relative(in_path_base, filename));
- const legacy_path = path.join(legacy_path_base, path.relative(in_path_base, filename));
-
- if (path.extname(filename) !== '.js') {
- if (!js_only) {
- console.log(`Writing ${out_path}`);
- return copy(filename, out_path);
- }
- return; // skip non-javascript files
- }
-
- return Promise.resolve()
- .then(() => {
- if (only_legacy && !no_transform_files.has(filename)) {
- return;
- }
- return ensureDir(path.dirname(out_path))
- .then(() => {
- console.log(`Writing ${out_path}`);
- return copy(filename, out_path);
- });
- })
- .then(() => ensureDir(path.dirname(legacy_path)))
- .then(() => {
- if (no_transform_files.has(filename)) {
- return;
- }
-
- const opts = babel_opts();
- if (helper && helpers.optionsOverride) {
- helper.optionsOverride(opts);
- }
- // Adjust for the fact that we move the core files relative
- // to the vendor directory
- if (vendor_rewrite) {
- opts.plugins.push(["import-redirect",
- {"root": legacy_path_base,
- "redirect": { "vendor/(.+)": "./vendor/$1"}}]);
- }
-
- return babelTransformFile(filename, opts)
- .then((res) => {
- console.log(`Writing ${legacy_path}`);
- const {map} = res;
- let {code} = res;
- if (source_maps === true) {
- // append URL for external source map
- code += `\n//# sourceMappingURL=${path.basename(legacy_path)}.map\n`;
- }
- outFiles.push(`${legacy_path}`);
- return writeFile(legacy_path, code)
- .then(() => {
- if (source_maps === true || source_maps === 'both') {
- console.log(` and ${legacy_path}.map`);
- outFiles.push(`${legacy_path}.map`);
- return writeFile(`${legacy_path}.map`, JSON.stringify(map));
- }
- });
- });
- });
- });
-
- if (with_app_dir && helper && helper.noCopyOverride) {
- helper.noCopyOverride(paths, no_copy_files);
- }
-
- Promise.resolve()
- .then(() => {
- const handler = handleDir.bind(null, true, false, in_path || paths.main);
- const filter = (filename, stats) => !no_copy_files.has(filename);
- return walkDir(paths.vendor, handler, filter);
- })
- .then(() => {
- const handler = handleDir.bind(null, true, !in_path, in_path || paths.core);
- const filter = (filename, stats) => !no_copy_files.has(filename);
- return walkDir(paths.core, handler, filter);
- })
- .then(() => {
- if (!with_app_dir) return;
- const handler = handleDir.bind(null, false, false, in_path);
- const filter = (filename, stats) => !no_copy_files.has(filename);
- return walkDir(paths.app, handler, filter);
- })
- .then(() => {
- if (!with_app_dir) return;
-
- if (!helper || !helper.appWriter) {
- throw new Error(`Unable to generate app for the ${import_format} format!`);
- }
-
- const out_app_path = path.join(legacy_path_base, 'app.js');
- console.log(`Writing ${out_app_path}`);
- return helper.appWriter(out_path_base, legacy_path_base, out_app_path)
- .then((extra_scripts) => {
- const rel_app_path = path.relative(out_path_base, out_app_path);
- const legacy_scripts = extra_scripts.concat([rel_app_path]);
- transform_html(legacy_scripts, only_legacy);
- })
- .then(() => {
- if (!helper.removeModules) return;
- console.log(`Cleaning up temporary files...`);
- return Promise.all(outFiles.map((filepath) => {
- unlink(filepath)
- .then(() => {
- // Try to clean up any empty directories if this
- // was the last file in there
- const rmdir_r = dir =>
- rmdir(dir)
- .then(() => rmdir_r(path.dirname(dir)))
- .catch(() => {
- // Assume the error was ENOTEMPTY and ignore it
- });
- return rmdir_r(path.dirname(filepath));
- });
- }));
- });
- })
- .catch((err) => {
- console.error(`Failure converting modules: ${err}`);
- process.exit(1);
- });
-}
-
-if (program.clean) {
- console.log(`Removing ${paths.lib_dir_base}`);
- fse.removeSync(paths.lib_dir_base);
-
- console.log(`Removing ${paths.out_dir_base}`);
- fse.removeSync(paths.out_dir_base);
-}
-
-make_lib_files(program.as, program.withSourceMaps, program.withApp, program.onlyLegacy);
diff --git a/systemvm/agent/noVNC/utils/use_require_helpers.js b/systemvm/agent/noVNC/utils/use_require_helpers.js
deleted file mode 100644
index a4f99c7..0000000
--- a/systemvm/agent/noVNC/utils/use_require_helpers.js
+++ /dev/null
@@ -1,76 +0,0 @@
-// writes helpers require for vnc.html (they should output app.js)
-const fs = require('fs');
-const path = require('path');
-
-// util.promisify requires Node.js 8.x, so we have our own
-function promisify(original) {
- return function promise_wrap() {
- const args = Array.prototype.slice.call(arguments);
- return new Promise((resolve, reject) => {
- original.apply(this, args.concat((err, value) => {
- if (err) return reject(err);
- resolve(value);
- }));
- });
- };
-}
-
-const writeFile = promisify(fs.writeFile);
-
-module.exports = {
- 'amd': {
- appWriter: (base_out_path, script_base_path, out_path) => {
- // setup for requirejs
- const ui_path = path.relative(base_out_path,
- path.join(script_base_path, 'app', 'ui'));
- return writeFile(out_path, `requirejs(["${ui_path}"], (ui) => {});`)
- .then(() => {
- console.log(`Please place RequireJS in ${path.join(script_base_path, 'require.js')}`);
- const require_path = path.relative(base_out_path,
- path.join(script_base_path, 'require.js'));
- return [ require_path ];
- });
- },
- noCopyOverride: () => {},
- },
- 'commonjs': {
- optionsOverride: (opts) => {
- // CommonJS supports properly shifting the default export to work as normal
- opts.plugins.unshift("add-module-exports");
- },
- appWriter: (base_out_path, script_base_path, out_path) => {
- const browserify = require('browserify');
- const b = browserify(path.join(script_base_path, 'app/ui.js'), {});
- return promisify(b.bundle).call(b)
- .then(buf => writeFile(out_path, buf))
- .then(() => []);
- },
- noCopyOverride: () => {},
- removeModules: true,
- },
- 'systemjs': {
- appWriter: (base_out_path, script_base_path, out_path) => {
- const ui_path = path.relative(base_out_path,
- path.join(script_base_path, 'app', 'ui.js'));
- return writeFile(out_path, `SystemJS.import("${ui_path}");`)
- .then(() => {
- console.log(`Please place SystemJS in ${path.join(script_base_path, 'system-production.js')}`);
- // FIXME: Should probably be in the legacy directory
- const promise_path = path.relative(base_out_path,
- path.join(base_out_path, 'vendor', 'promise.js'));
- const systemjs_path = path.relative(base_out_path,
- path.join(script_base_path, 'system-production.js'));
- return [ promise_path, systemjs_path ];
- });
- },
- noCopyOverride: (paths, no_copy_files) => {
- no_copy_files.delete(path.join(paths.vendor, 'promise.js'));
- },
- },
- 'umd': {
- optionsOverride: (opts) => {
- // umd supports properly shifting the default export to work as normal
- opts.plugins.unshift("add-module-exports");
- },
- },
-};
diff --git a/systemvm/agent/noVNC/utils/validate b/systemvm/agent/noVNC/utils/validate
deleted file mode 100755
index a6b5507..0000000
--- a/systemvm/agent/noVNC/utils/validate
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/bin/bash
-
-set -e
-
-RET=0
-
-OUT=`mktemp`
-
-for fn in "$@"; do
- echo "Validating $fn..."
- echo
-
- case $fn in
- *.html)
- type="text/html"
- ;;
- *.css)
- type="text/css"
- ;;
- *)
- echo "Unknown format!"
- echo
- RET=1
- continue
- ;;
- esac
-
- curl --silent \
- --header "Content-Type: ${type}; charset=utf-8" \
- --data-binary @${fn} \
- https://validator.w3.org/nu/?out=text > $OUT
- cat $OUT
- echo
-
- # We don't fail the check for warnings as some warnings are
- # not relevant for us, and we don't currently have a way to
- # ignore just those
- if grep -q -s -E "^Error:" $OUT; then
- RET=1
- fi
-done
-
-rm $OUT
-
-exit $RET
diff --git a/systemvm/agent/noVNC/vendor/browser-es-module-loader/README.md b/systemvm/agent/noVNC/vendor/browser-es-module-loader/README.md
index c26867f..a50cc37 100644
--- a/systemvm/agent/noVNC/vendor/browser-es-module-loader/README.md
+++ b/systemvm/agent/noVNC/vendor/browser-es-module-loader/README.md
@@ -6,8 +6,8 @@
https://github.com/ModuleLoader/browser-es-module-loader, but uses
WebWorkers to compile the modules in the background.
-To generate, run `rollup -c` in this directory, and then run `browserify
-src/babel-worker.js > dist/babel-worker.js`.
+To generate, run `npx rollup -c` in this directory, and then run
+`./genworker.js`.
LICENSE
-------
diff --git a/systemvm/agent/noVNC/vendor/browser-es-module-loader/genworker.js b/systemvm/agent/noVNC/vendor/browser-es-module-loader/genworker.js
new file mode 100755
index 0000000..dbf5d2f
--- /dev/null
+++ b/systemvm/agent/noVNC/vendor/browser-es-module-loader/genworker.js
@@ -0,0 +1,13 @@
+#!/usr/bin/env node
+
+var fs = require("fs");
+var browserify = require("browserify");
+
+browserify("src/babel-worker.js")
+ .transform("babelify", {
+ presets: [ [ "@babel/preset-env", { targets: "ie >= 11" } ] ],
+ global: true,
+ ignore: [ "../../node_modules/core-js" ]
+ })
+ .bundle()
+ .pipe(fs.createWriteStream("dist/babel-worker.js"));
diff --git a/systemvm/agent/noVNC/vendor/browser-es-module-loader/rollup.config.js b/systemvm/agent/noVNC/vendor/browser-es-module-loader/rollup.config.js
index 4bf4a5f..33a4a24 100644
--- a/systemvm/agent/noVNC/vendor/browser-es-module-loader/rollup.config.js
+++ b/systemvm/agent/noVNC/vendor/browser-es-module-loader/rollup.config.js
@@ -1,16 +1,15 @@
import nodeResolve from 'rollup-plugin-node-resolve';
export default {
- entry: 'src/browser-es-module-loader.js',
- dest: 'dist/browser-es-module-loader.js',
- format: 'umd',
- moduleName: 'BrowserESModuleLoader',
- sourceMap: true,
+ input: 'src/browser-es-module-loader.js',
+ output: {
+ file: 'dist/browser-es-module-loader.js',
+ format: 'umd',
+ name: 'BrowserESModuleLoader',
+ sourcemap: true,
+ },
plugins: [
nodeResolve(),
],
-
- // skip rollup warnings (specifically the eval warning)
- onwarn: function() {}
};
diff --git a/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/babel-worker.js b/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/babel-worker.js
index 007bd68..19e23bf 100644
--- a/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/babel-worker.js
+++ b/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/babel-worker.js
@@ -1,12 +1,10 @@
-/*import { transform as babelTransform } from 'babel-core';
-import babelTransformDynamicImport from 'babel-plugin-syntax-dynamic-import';
-import babelTransformES2015ModulesSystemJS from 'babel-plugin-transform-es2015-modules-systemjs';*/
+// Polyfills needed for Babel to function
+require("core-js");
-// sadly, due to how rollup works, we can't use es6 imports here
-var babelTransform = require('babel-core').transform;
-var babelTransformDynamicImport = require('babel-plugin-syntax-dynamic-import');
-var babelTransformES2015ModulesSystemJS = require('babel-plugin-transform-es2015-modules-systemjs');
-var babelPresetES2015 = require('babel-preset-es2015');
+var babelTransform = require('@babel/core').transform;
+var babelTransformDynamicImport = require('@babel/plugin-syntax-dynamic-import');
+var babelTransformModulesSystemJS = require('@babel/plugin-transform-modules-systemjs');
+var babelPresetEnv = require('@babel/preset-env');
self.onmessage = function (evt) {
// transform source with Babel
@@ -17,8 +15,8 @@
moduleIds: false,
sourceMaps: 'inline',
babelrc: false,
- plugins: [babelTransformDynamicImport, babelTransformES2015ModulesSystemJS],
- presets: [babelPresetES2015],
+ plugins: [babelTransformDynamicImport, babelTransformModulesSystemJS],
+ presets: [ [ babelPresetEnv, { targets: 'ie >= 11' } ] ],
});
self.postMessage({key: evt.data.key, code: output.code, source: evt.data.source});
diff --git a/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/browser-es-module-loader.js b/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/browser-es-module-loader.js
index efae617..9e50b8b 100644
--- a/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/browser-es-module-loader.js
+++ b/systemvm/agent/noVNC/vendor/browser-es-module-loader/src/browser-es-module-loader.js
@@ -1,5 +1,4 @@
import RegisterLoader from 'es-module-loader/core/register-loader.js';
-import { InternalModuleNamespace as ModuleNamespace } from 'es-module-loader/core/loader-polyfill.js';
import { baseURI, global, isBrowser } from 'es-module-loader/core/common.js';
import { resolveIfNotPlain } from 'es-module-loader/core/resolve.js';
diff --git a/systemvm/agent/noVNC/vendor/pako/lib/zlib/deflate.js b/systemvm/agent/noVNC/vendor/pako/lib/zlib/deflate.js
index c51915e..c3a5ba4 100644
--- a/systemvm/agent/noVNC/vendor/pako/lib/zlib/deflate.js
+++ b/systemvm/agent/noVNC/vendor/pako/lib/zlib/deflate.js
@@ -9,51 +9,51 @@
/* Allowed flush values; see deflate() and inflate() below for details */
-var Z_NO_FLUSH = 0;
-var Z_PARTIAL_FLUSH = 1;
-//var Z_SYNC_FLUSH = 2;
-var Z_FULL_FLUSH = 3;
-var Z_FINISH = 4;
-var Z_BLOCK = 5;
-//var Z_TREES = 6;
+export const Z_NO_FLUSH = 0;
+export const Z_PARTIAL_FLUSH = 1;
+//export const Z_SYNC_FLUSH = 2;
+export const Z_FULL_FLUSH = 3;
+export const Z_FINISH = 4;
+export const Z_BLOCK = 5;
+//export const Z_TREES = 6;
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
-var Z_OK = 0;
-var Z_STREAM_END = 1;
-//var Z_NEED_DICT = 2;
-//var Z_ERRNO = -1;
-var Z_STREAM_ERROR = -2;
-var Z_DATA_ERROR = -3;
-//var Z_MEM_ERROR = -4;
-var Z_BUF_ERROR = -5;
-//var Z_VERSION_ERROR = -6;
+export const Z_OK = 0;
+export const Z_STREAM_END = 1;
+//export const Z_NEED_DICT = 2;
+//export const Z_ERRNO = -1;
+export const Z_STREAM_ERROR = -2;
+export const Z_DATA_ERROR = -3;
+//export const Z_MEM_ERROR = -4;
+export const Z_BUF_ERROR = -5;
+//export const Z_VERSION_ERROR = -6;
/* compression levels */
-//var Z_NO_COMPRESSION = 0;
-//var Z_BEST_SPEED = 1;
-//var Z_BEST_COMPRESSION = 9;
-var Z_DEFAULT_COMPRESSION = -1;
+//export const Z_NO_COMPRESSION = 0;
+//export const Z_BEST_SPEED = 1;
+//export const Z_BEST_COMPRESSION = 9;
+export const Z_DEFAULT_COMPRESSION = -1;
-var Z_FILTERED = 1;
-var Z_HUFFMAN_ONLY = 2;
-var Z_RLE = 3;
-var Z_FIXED = 4;
-var Z_DEFAULT_STRATEGY = 0;
+export const Z_FILTERED = 1;
+export const Z_HUFFMAN_ONLY = 2;
+export const Z_RLE = 3;
+export const Z_FIXED = 4;
+export const Z_DEFAULT_STRATEGY = 0;
/* Possible values of the data_type field (though see inflate()) */
-//var Z_BINARY = 0;
-//var Z_TEXT = 1;
-//var Z_ASCII = 1; // = Z_TEXT
-var Z_UNKNOWN = 2;
+//export const Z_BINARY = 0;
+//export const Z_TEXT = 1;
+//export const Z_ASCII = 1; // = Z_TEXT
+export const Z_UNKNOWN = 2;
/* The deflate compression method */
-var Z_DEFLATED = 8;
+export const Z_DEFLATED = 8;
/*============================================================================*/
diff --git a/systemvm/agent/noVNC/vendor/pako/lib/zlib/inflate.js b/systemvm/agent/noVNC/vendor/pako/lib/zlib/inflate.js
index b79b396..1d2063b 100644
--- a/systemvm/agent/noVNC/vendor/pako/lib/zlib/inflate.js
+++ b/systemvm/agent/noVNC/vendor/pako/lib/zlib/inflate.js
@@ -13,30 +13,30 @@
/* Allowed flush values; see deflate() and inflate() below for details */
-//var Z_NO_FLUSH = 0;
-//var Z_PARTIAL_FLUSH = 1;
-//var Z_SYNC_FLUSH = 2;
-//var Z_FULL_FLUSH = 3;
-var Z_FINISH = 4;
-var Z_BLOCK = 5;
-var Z_TREES = 6;
+//export const Z_NO_FLUSH = 0;
+//export const Z_PARTIAL_FLUSH = 1;
+//export const Z_SYNC_FLUSH = 2;
+//export const Z_FULL_FLUSH = 3;
+export const Z_FINISH = 4;
+export const Z_BLOCK = 5;
+export const Z_TREES = 6;
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
-var Z_OK = 0;
-var Z_STREAM_END = 1;
-var Z_NEED_DICT = 2;
-//var Z_ERRNO = -1;
-var Z_STREAM_ERROR = -2;
-var Z_DATA_ERROR = -3;
-var Z_MEM_ERROR = -4;
-var Z_BUF_ERROR = -5;
-//var Z_VERSION_ERROR = -6;
+export const Z_OK = 0;
+export const Z_STREAM_END = 1;
+export const Z_NEED_DICT = 2;
+//export const Z_ERRNO = -1;
+export const Z_STREAM_ERROR = -2;
+export const Z_DATA_ERROR = -3;
+export const Z_MEM_ERROR = -4;
+export const Z_BUF_ERROR = -5;
+//export const Z_VERSION_ERROR = -6;
/* The deflate compression method */
-var Z_DEFLATED = 8;
+export const Z_DEFLATED = 8;
/* STATES ====================================================================*/
diff --git a/systemvm/agent/noVNC/vnc.html b/systemvm/agent/noVNC/vnc.html
index 212321b..a244a7d 100644
--- a/systemvm/agent/noVNC/vnc.html
+++ b/systemvm/agent/noVNC/vnc.html
@@ -4,7 +4,7 @@
<!--
noVNC example: simple example using default UI
- 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).
@@ -17,6 +17,10 @@
<meta charset="utf-8">
+ <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
+ Remove this if you use the .htaccess -->
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+
<!-- Icons (see app/images/icons/Makefile for what the sizes are for) -->
<link rel="icon" sizes="16x16" type="image/png" href="app/images/icons/novnc-16x16.png">
<link rel="icon" sizes="24x24" type="image/png" href="app/images/icons/novnc-24x24.png">
@@ -57,23 +61,13 @@
<!-- promise polyfills promises for IE11 -->
<script src="vendor/promise.js"></script>
<!-- ES2015/ES6 modules polyfill -->
- <script type="module">
- window._noVNC_has_module_support = true;
- </script>
- <script>
- window.addEventListener("load", function() {
- if (window._noVNC_has_module_support) return;
- var loader = document.createElement("script");
- loader.src = "vendor/browser-es-module-loader/dist/browser-es-module-loader.js";
- document.head.appendChild(loader);
- });
- </script>
+ <script nomodule src="vendor/browser-es-module-loader/dist/browser-es-module-loader.js"></script>
<!-- actual script modules -->
<script type="module" crossorigin="anonymous" src="app/ui.js"></script>
<!-- end scripts -->
</head>
-<body>
+<body id="body">
<div id="noVNC_fallback_error" class="noVNC_center">
<div>
@@ -91,68 +85,54 @@
<div class="noVNC_scroll">
- <h1 class="noVNC_logo" translate="no"><span>no</span><br>VNC</h1>
+ <h1 class="noVNC_logo" translate="no" style="display: none;"><span>no</span><br>VNC</h1>
<!-- Drag/Pan the viewport -->
- <input type="image" alt="viewport drag" src="app/images/drag.svg"
+ <input type="image" alt="Drag" src="app/images/drag.png"
id="noVNC_view_drag_button" class="noVNC_button noVNC_hidden"
title="Move/Drag Viewport">
<!--noVNC Touch Device only buttons-->
- <div id="noVNC_mobile_buttons">
- <input type="image" alt="No mousebutton" src="app/images/mouse_none.svg"
- id="noVNC_mouse_button0" class="noVNC_button"
- title="Active Mouse Button">
- <input type="image" alt="Left mousebutton" src="app/images/mouse_left.svg"
- id="noVNC_mouse_button1" class="noVNC_button"
- title="Active Mouse Button">
- <input type="image" alt="Middle mousebutton" src="app/images/mouse_middle.svg"
- id="noVNC_mouse_button2" class="noVNC_button"
- title="Active Mouse Button">
- <input type="image" alt="Right mousebutton" src="app/images/mouse_right.svg"
- id="noVNC_mouse_button4" class="noVNC_button"
- title="Active Mouse Button">
- <input type="image" alt="Keyboard" src="app/images/keyboard.svg"
+ <div id="noVNC_mobile_buttons" style="display: none;">
+ <input type="image" alt="Keyboard" src="app/images/keyboard.png"
id="noVNC_keyboard_button" class="noVNC_button" title="Show Keyboard">
</div>
<!-- Extra manual keys -->
- <div id="noVNC_extra_keys">
- <input type="image" alt="Extra keys" src="app/images/toggleextrakeys.svg"
- id="noVNC_toggle_extra_keys_button" class="noVNC_button"
- title="Show Extra Keys">
- <div class="noVNC_vcenter">
- <div id="noVNC_modifiers" class="noVNC_panel">
- <input type="image" alt="Ctrl" src="app/images/ctrl.svg"
- id="noVNC_toggle_ctrl_button" class="noVNC_button"
- title="Toggle Ctrl">
- <input type="image" alt="Alt" src="app/images/alt.svg"
- id="noVNC_toggle_alt_button" class="noVNC_button"
- title="Toggle Alt">
- <input type="image" alt="Windows" src="app/images/windows.svg"
- id="noVNC_toggle_windows_button" class="noVNC_button"
- title="Toggle Windows">
- <input type="image" alt="Tab" src="app/images/tab.svg"
- id="noVNC_send_tab_button" class="noVNC_button"
- title="Send Tab">
- <input type="image" alt="Esc" src="app/images/esc.svg"
- id="noVNC_send_esc_button" class="noVNC_button"
- title="Send Escape">
- <input type="image" alt="Ctrl+Alt+Del" src="app/images/ctrlaltdel.svg"
- id="noVNC_send_ctrl_alt_del_button" class="noVNC_button"
- title="Send Ctrl-Alt-Del">
- </div>
- </div>
+ <input type="image" alt="Extra keys" src="app/images/toggleextrakeys.png"
+ id="noVNC_toggle_extra_keys_button" class="noVNC_button"
+ title="Show Extra Keys">
+ <div class="noVNC_vcenter">
+ <div id="noVNC_modifiers" class="noVNC_panel">
+ <input type="image" alt="Ctrl" src="app/images/ctrl.png"
+ id="noVNC_toggle_ctrl_button" class="noVNC_button"
+ title="Toggle Ctrl">
+ <input type="image" alt="Alt" src="app/images/alt.png"
+ id="noVNC_toggle_alt_button" class="noVNC_button"
+ title="Toggle Alt">
+ <input type="image" alt="Windows" src="app/images/windows.png"
+ id="noVNC_toggle_windows_button" class="noVNC_button"
+ title="Toggle Windows">
+ <input type="image" alt="Tab" src="app/images/tab.png"
+ id="noVNC_send_tab_button" class="noVNC_button"
+ title="Send Tab">
+ <input type="image" alt="Esc" src="app/images/esc.png"
+ id="noVNC_send_esc_button" class="noVNC_button"
+ title="Send Escape">
+ <input type="image" alt="Ctrl+Alt+Del" src="app/images/ctrlaltdel.png"
+ id="noVNC_send_ctrl_alt_del_button" class="noVNC_button"
+ title="Send Ctrl-Alt-Del">
+ </div>
</div>
<!-- Shutdown/Reboot -->
- <input type="image" alt="Shutdown/Reboot" src="app/images/power.svg"
+ <input type="image" alt="Shutdown/Reboot" src="app/images/power.png"
id="noVNC_power_button" class="noVNC_button"
title="Shutdown/Reboot...">
<div class="noVNC_vcenter">
<div id="noVNC_power" class="noVNC_panel">
<div class="noVNC_heading">
- <img alt="" src="app/images/power.svg"> Power
+ <img alt="" src="app/images/power.png"> Power
</div>
<input type="button" id="noVNC_shutdown_button" value="Shutdown">
<input type="button" id="noVNC_reboot_button" value="Reboot">
@@ -161,110 +141,132 @@
</div>
<!-- Clipboard -->
- <input type="image" alt="Clipboard" src="app/images/clipboard.svg"
+ <input type="image" alt="Clipboard" src="app/images/clipboard.png"
id="noVNC_clipboard_button" class="noVNC_button"
title="Clipboard">
<div class="noVNC_vcenter">
<div id="noVNC_clipboard" class="noVNC_panel">
<div class="noVNC_heading">
- <img alt="" src="app/images/clipboard.svg"> Clipboard
+ <img alt="" src="app/images/clipboard.png"> Clipboard
</div>
<textarea id="noVNC_clipboard_text" rows=5></textarea>
<br>
+ <input id="noVNC_clipboard_send_button" type="button"
+ value="Send" style="color: white; background: rgb(75, 93, 118);" class="noVNC_submit">
<input id="noVNC_clipboard_clear_button" type="button"
value="Clear" class="noVNC_submit">
</div>
</div>
<!-- Toggle fullscreen -->
- <input type="image" alt="Fullscreen" src="app/images/fullscreen.svg"
+ <input type="image" alt="Fullscreen" src="app/images/fullscreen.png"
id="noVNC_fullscreen_button" class="noVNC_button noVNC_hidden"
title="Fullscreen">
<!-- Settings -->
- <input type="image" alt="Settings" src="app/images/settings.svg"
- id="noVNC_settings_button" class="noVNC_button"
- title="Settings">
- <div class="noVNC_vcenter">
- <div id="noVNC_settings" class="noVNC_panel">
- <ul>
- <li class="noVNC_heading">
- <img alt="" src="app/images/settings.svg"> Settings
- </li>
- <li>
- <label><input id="noVNC_setting_shared" type="checkbox"> Shared Mode</label>
- </li>
- <li>
- <label><input id="noVNC_setting_view_only" type="checkbox"> View Only</label>
- </li>
- <li><hr></li>
- <li>
- <label><input id="noVNC_setting_view_clip" type="checkbox"> Clip to Window</label>
- </li>
- <li>
- <label for="noVNC_setting_resize">Scaling Mode:</label>
- <select id="noVNC_setting_resize" name="vncResize">
- <option value="off">None</option>
- <option value="scale">Local Scaling</option>
- <option value="remote">Remote Resizing</option>
- </select>
- </li>
- <li><hr></li>
- <li>
- <div class="noVNC_expander">Advanced</div>
- <div><ul>
- <li>
- <label for="noVNC_setting_repeaterID">Repeater ID:</label>
- <input id="noVNC_setting_repeaterID" type="text" value="">
- </li>
- <li>
- <div class="noVNC_expander">WebSocket</div>
- <div><ul>
- <li>
- <label><input id="noVNC_setting_encrypt" type="checkbox"> Encrypt</label>
- </li>
- <li>
- <label for="noVNC_setting_host">Host:</label>
- <input id="noVNC_setting_host">
- </li>
- <li>
- <label for="noVNC_setting_port">Port:</label>
- <input id="noVNC_setting_port" type="number">
- </li>
- <li>
- <label for="noVNC_setting_path">Path:</label>
- <input id="noVNC_setting_path" type="text" value="websockify">
- </li>
- </ul></div>
- </li>
- <li><hr></li>
- <li>
- <label><input id="noVNC_setting_reconnect" type="checkbox"> Automatic Reconnect</label>
- </li>
- <li>
- <label for="noVNC_setting_reconnect_delay">Reconnect Delay (ms):</label>
- <input id="noVNC_setting_reconnect_delay" type="number">
- </li>
- <li><hr></li>
- <li>
- <label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label>
- </li>
- <li><hr></li>
- <!-- Logging selection dropdown -->
- <li>
- <label>Logging:
- <select id="noVNC_setting_logging" name="vncLogging">
- </select>
- </label>
- </li>
- </ul></div>
- </li>
- </ul>
- </div>
- </div>
+ <span style="display: none;">
+ <input type="image" alt="Settings" src="app/images/settings.png"
+ id="noVNC_settings_button" class="noVNC_button"
+ title="Settings">
+ <div class="noVNC_vcenter">
+ <div id="noVNC_settings" class="noVNC_panel">
+ <ul>
+ <li class="noVNC_heading">
+ <img alt="" src="app/images/settings.png"> Settings
+ </li>
+ <li>
+ <label><input id="noVNC_setting_shared" type="checkbox"> Shared Mode</label>
+ </li>
+ <li>
+ <label><input id="noVNC_setting_view_only" type="checkbox"> View Only</label>
+ </li>
+ <li><hr></li>
+ <li>
+ <label><input id="noVNC_setting_view_clip" type="checkbox"> Clip to Window</label>
+ </li>
+ <li>
+ <label for="noVNC_setting_resize">Scaling Mode:</label>
+ <select id="noVNC_setting_resize" name="vncResize">
+ <option value="off">None</option>
+ <option value="scale">Local Scaling</option>
+ <option value="remote">Remote Resizing</option>
+ </select>
+ </li>
+ <li><hr></li>
+ <li>
+ <div class="noVNC_expander">Advanced</div>
+ <div><ul>
+ <li>
+ <label for="noVNC_setting_quality">Quality:</label>
+ <input id="noVNC_setting_quality" type="range" min="0" max="9" value="6">
+ </li>
+ <li>
+ <label for="noVNC_setting_compression">Compression level:</label>
+ <input id="noVNC_setting_compression" type="range" min="0" max="9" value="2">
+ </li>
+ <li><hr></li>
+ <li>
+ <label for="noVNC_setting_repeaterID">Repeater ID:</label>
+ <input id="noVNC_setting_repeaterID" type="text" value="">
+ </li>
+ <li>
+ <div class="noVNC_expander">WebSocket</div>
+ <div><ul>
+ <li>
+ <label><input id="noVNC_setting_encrypt" type="checkbox"> Encrypt</label>
+ </li>
+ <li>
+ <label for="noVNC_setting_host">Host:</label>
+ <input id="noVNC_setting_host">
+ </li>
+ <li>
+ <label for="noVNC_setting_port">Port:</label>
+ <input id="noVNC_setting_port" type="number">
+ </li>
+ <li>
+ <label for="noVNC_setting_path">Path:</label>
+ <input id="noVNC_setting_path" type="text" value="websockify">
+ </li>
+ <li>
+ <label for="noVNC_setting_token">Token:</label>
+ <input id="noVNC_setting_token" type="text">
+ </li>
+ </ul></div>
+ </li>
+ <li><hr></li>
+ <li>
+ <label><input id="noVNC_setting_reconnect" type="checkbox"> Automatic Reconnect</label>
+ </li>
+ <li>
+ <label for="noVNC_setting_reconnect_delay">Reconnect Delay (ms):</label>
+ <input id="noVNC_setting_reconnect_delay" type="number">
+ </li>
+ <li><hr></li>
+ <li>
+ <label><input id="noVNC_setting_show_dot" type="checkbox"> Show Dot when No Cursor</label>
+ </li>
+ <li><hr></li>
+ <!-- Logging selection dropdown -->
+ <li>
+ <label>Logging:
+ <select id="noVNC_setting_logging" name="vncLogging">
+ </select>
+ </label>
+ </li>
+ </ul></div>
+ </li>
+ <li class="noVNC_version_separator"><hr></li>
+ <li class="noVNC_version_wrapper">
+ <span>Version:</span>
+ <span class="noVNC_version"></span>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </span>
<!-- Connection Controls -->
- <input type="image" alt="Disconnect" src="app/images/disconnect.svg"
+ <input style="display: none;" type="image" alt="Disconnect" src="app/images/disconnect.png"
id="noVNC_disconnect_button" class="noVNC_button"
title="Disconnect">
@@ -279,25 +281,29 @@
<div id="noVNC_status"></div>
<!-- Connect button -->
- <div class="noVNC_center">
+ <div class="noVNC_center" style="display: none;">
<div id="noVNC_connect_dlg">
<div class="noVNC_logo" translate="no"><span>no</span>VNC</div>
<div id="noVNC_connect_button"><div>
- <img alt="" src="app/images/connect.svg"> Connect
+ <img alt="" src="app/images/connect.png"> Connect
</div></div>
</div>
</div>
<!-- Password Dialog -->
<div class="noVNC_center noVNC_connect_layer">
- <div id="noVNC_password_dlg" class="noVNC_panel"><form>
+ <div id="noVNC_credentials_dlg" class="noVNC_panel"><form>
<ul>
- <li>
+ <li id="noVNC_username_block">
+ <label>Username:</label>
+ <input id="noVNC_username_input">
+ </li>
+ <li id="noVNC_password_block">
<label>Password:</label>
<input id="noVNC_password_input" type="password">
</li>
<li>
- <input id="noVNC_password_button" type="submit" value="Send Password" class="noVNC_submit">
+ <input id="noVNC_credentials_button" type="submit" value="Send Credentials" class="noVNC_submit">
</li>
</ul>
</form></div>
@@ -327,4 +333,9 @@
<source src="app/sounds/bell.mp3" type="audio/mpeg">
</audio>
</body>
+ <script type="application/javascript">
+ window.onload = function() {
+ document.getElementById("noVNC_connect_button").click();
+ }
+ </script>
</html>
diff --git a/systemvm/agent/noVNC/vnc_lite.html b/systemvm/agent/noVNC/vnc_lite.html
index 12ac1d5..0be2b53 100644
--- a/systemvm/agent/noVNC/vnc_lite.html
+++ b/systemvm/agent/noVNC/vnc_lite.html
@@ -7,7 +7,7 @@
This is a self-contained file which doesn't import WebUtil or external 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).
@@ -18,6 +18,10 @@
<meta charset="utf-8">
+ <!-- Always force latest IE rendering engine (even in intranet) &
+ Chrome Frame. Remove this if you use the .htaccess -->
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+
<style>
body {
@@ -68,18 +72,7 @@
<script src="vendor/promise.js"></script>
<!-- ES2015/ES6 modules polyfill -->
- <script type="module">
- window._noVNC_has_module_support = true;
- </script>
- <script>
- window.addEventListener("load", function() {
- if (window._noVNC_has_module_support) return;
- const loader = document.createElement("script");
- loader.src = "vendor/browser-es-module-loader/dist/" +
- "browser-es-module-loader.js";
- document.head.appendChild(loader);
- });
- </script>
+ <script nomodule src="vendor/browser-es-module-loader/dist/browser-es-module-loader.js"></script>
<!-- actual script modules -->
<script type="module" crossorigin="anonymous">