@novnc/novnc 1.3.0-g7ad4e60 → 1.3.0-g80a7c1d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/core/decoders/jpeg.js +141 -0
- package/core/decoders/zrle.js +185 -0
- package/core/encodings.js +4 -0
- package/core/rfb.js +42 -4
- package/lib/base64.js +1 -1
- package/lib/decoders/copyrect.js +1 -1
- package/lib/decoders/hextile.js +2 -2
- package/lib/decoders/jpeg.js +188 -0
- package/lib/decoders/raw.js +1 -1
- package/lib/decoders/rre.js +1 -1
- package/lib/decoders/tight.js +2 -2
- package/lib/decoders/tightpng.js +3 -3
- package/lib/decoders/zrle.js +234 -0
- package/lib/deflator.js +1 -1
- package/lib/des.js +1 -1
- package/lib/display.js +2 -2
- package/lib/encodings.js +8 -0
- package/lib/inflator.js +1 -1
- package/lib/input/gesturehandler.js +1 -1
- package/lib/input/keyboard.js +2 -2
- package/lib/input/util.js +1 -1
- package/lib/rfb.js +76 -18
- package/lib/util/browser.js +1 -1
- package/lib/util/cursor.js +1 -1
- package/lib/util/eventtarget.js +1 -1
- package/lib/vendor/pako/lib/zlib/deflate.js +1 -1
- package/lib/vendor/pako/lib/zlib/inflate.js +1 -1
- package/lib/vendor/pako/lib/zlib/inftrees.js +1 -1
- package/lib/vendor/pako/lib/zlib/trees.js +1 -1
- package/lib/websock.js +2 -2
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -113,6 +113,11 @@ proxy.
|
|
|
113
113
|
used to specify the location of a running VNC server:
|
|
114
114
|
|
|
115
115
|
`./utils/novnc_proxy --vnc localhost:5901`
|
|
116
|
+
|
|
117
|
+
* If you don't need to expose the web server to public internet, you can
|
|
118
|
+
bind to localhost:
|
|
119
|
+
|
|
120
|
+
`./utils/novnc_proxy --vnc localhost:5901 --listen localhost:6081`
|
|
116
121
|
|
|
117
122
|
* Point your browser to the cut-and-paste URL that is output by the `novnc_proxy`
|
|
118
123
|
script. Hit the Connect button, enter a password if the VNC server has one
|
|
@@ -123,13 +128,17 @@ Running the command below will install the latest release of noVNC from Snap:
|
|
|
123
128
|
|
|
124
129
|
`sudo snap install novnc`
|
|
125
130
|
|
|
126
|
-
#### Running noVNC
|
|
131
|
+
#### Running noVNC from Snap Directly
|
|
127
132
|
|
|
128
133
|
You can run the Snap-package installed novnc directly with, for example:
|
|
129
134
|
|
|
130
135
|
`novnc --listen 6081 --vnc localhost:5901 # /snap/bin/novnc if /snap/bin is not in your PATH`
|
|
131
136
|
|
|
132
|
-
|
|
137
|
+
If you want to use certificate files, due to standard Snap confinement restrictions you need to have them in the /home/\<user\>/snap/novnc/current/ directory. If your username is jsmith an example command would be:
|
|
138
|
+
|
|
139
|
+
`novnc --listen 8443 --cert ~jsmith/snap/novnc/current/self.crt --key ~jsmith/snap/novnc/current/self.key --vnc ubuntu.example.com:5901`
|
|
140
|
+
|
|
141
|
+
#### Running noVNC from Snap as a Service (Daemon)
|
|
133
142
|
The Snap package also has the capability to run a 'novnc' service which can be
|
|
134
143
|
configured to listen on multiple ports connecting to multiple VNC servers
|
|
135
144
|
(effectively a service runing multiple instances of novnc).
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* noVNC: HTML5 VNC client
|
|
3
|
+
* Copyright (C) 2019 The noVNC Authors
|
|
4
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
5
|
+
*
|
|
6
|
+
* See README.md for usage and integration instructions.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export default class JPEGDecoder {
|
|
11
|
+
constructor() {
|
|
12
|
+
// RealVNC will reuse the quantization tables
|
|
13
|
+
// and Huffman tables, so we need to cache them.
|
|
14
|
+
this._quantTables = [];
|
|
15
|
+
this._huffmanTables = [];
|
|
16
|
+
this._cachedQuantTables = [];
|
|
17
|
+
this._cachedHuffmanTables = [];
|
|
18
|
+
|
|
19
|
+
this._jpegLength = 0;
|
|
20
|
+
this._segments = [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
decodeRect(x, y, width, height, sock, display, depth) {
|
|
24
|
+
// A rect of JPEG encodings is simply a JPEG file
|
|
25
|
+
if (!this._parseJPEG(sock.rQslice(0))) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const data = sock.rQshiftBytes(this._jpegLength);
|
|
29
|
+
if (this._quantTables.length != 0 && this._huffmanTables.length != 0) {
|
|
30
|
+
// If there are quantization tables and Huffman tables in the JPEG
|
|
31
|
+
// image, we can directly render it.
|
|
32
|
+
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
33
|
+
return true;
|
|
34
|
+
} else {
|
|
35
|
+
// Otherwise we need to insert cached tables.
|
|
36
|
+
const sofIndex = this._segments.findIndex(
|
|
37
|
+
x => x[1] == 0xC0 || x[1] == 0xC2
|
|
38
|
+
);
|
|
39
|
+
if (sofIndex == -1) {
|
|
40
|
+
throw new Error("Illegal JPEG image without SOF");
|
|
41
|
+
}
|
|
42
|
+
let segments = this._segments.slice(0, sofIndex);
|
|
43
|
+
segments = segments.concat(this._quantTables.length ?
|
|
44
|
+
this._quantTables :
|
|
45
|
+
this._cachedQuantTables);
|
|
46
|
+
segments.push(this._segments[sofIndex]);
|
|
47
|
+
segments = segments.concat(this._huffmanTables.length ?
|
|
48
|
+
this._huffmanTables :
|
|
49
|
+
this._cachedHuffmanTables,
|
|
50
|
+
this._segments.slice(sofIndex + 1));
|
|
51
|
+
let length = 0;
|
|
52
|
+
for (let i = 0; i < segments.length; i++) {
|
|
53
|
+
length += segments[i].length;
|
|
54
|
+
}
|
|
55
|
+
const data = new Uint8Array(length);
|
|
56
|
+
length = 0;
|
|
57
|
+
for (let i = 0; i < segments.length; i++) {
|
|
58
|
+
data.set(segments[i], length);
|
|
59
|
+
length += segments[i].length;
|
|
60
|
+
}
|
|
61
|
+
display.imageRect(x, y, width, height, "image/jpeg", data);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_parseJPEG(buffer) {
|
|
67
|
+
if (this._quantTables.length != 0) {
|
|
68
|
+
this._cachedQuantTables = this._quantTables;
|
|
69
|
+
}
|
|
70
|
+
if (this._huffmanTables.length != 0) {
|
|
71
|
+
this._cachedHuffmanTables = this._huffmanTables;
|
|
72
|
+
}
|
|
73
|
+
this._quantTables = [];
|
|
74
|
+
this._huffmanTables = [];
|
|
75
|
+
this._segments = [];
|
|
76
|
+
let i = 0;
|
|
77
|
+
let bufferLength = buffer.length;
|
|
78
|
+
while (true) {
|
|
79
|
+
let j = i;
|
|
80
|
+
if (j + 2 > bufferLength) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
if (buffer[j] != 0xFF) {
|
|
84
|
+
throw new Error("Illegal JPEG marker received (byte: " +
|
|
85
|
+
buffer[j] + ")");
|
|
86
|
+
}
|
|
87
|
+
const type = buffer[j+1];
|
|
88
|
+
j += 2;
|
|
89
|
+
if (type == 0xD9) {
|
|
90
|
+
this._jpegLength = j;
|
|
91
|
+
this._segments.push(buffer.slice(i, j));
|
|
92
|
+
return true;
|
|
93
|
+
} else if (type == 0xDA) {
|
|
94
|
+
// start of scan
|
|
95
|
+
let hasFoundEndOfScan = false;
|
|
96
|
+
for (let k = j + 3; k + 1 < bufferLength; k++) {
|
|
97
|
+
if (buffer[k] == 0xFF && buffer[k+1] != 0x00 &&
|
|
98
|
+
!(buffer[k+1] >= 0xD0 && buffer[k+1] <= 0xD7)) {
|
|
99
|
+
j = k;
|
|
100
|
+
hasFoundEndOfScan = true;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (!hasFoundEndOfScan) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
this._segments.push(buffer.slice(i, j));
|
|
108
|
+
i = j;
|
|
109
|
+
continue;
|
|
110
|
+
} else if (type >= 0xD0 && type < 0xD9 || type == 0x01) {
|
|
111
|
+
// No length after marker
|
|
112
|
+
this._segments.push(buffer.slice(i, j));
|
|
113
|
+
i = j;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (j + 2 > bufferLength) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
const length = (buffer[j] << 8) + buffer[j+1] - 2;
|
|
120
|
+
if (length < 0) {
|
|
121
|
+
throw new Error("Illegal JPEG length received (length: " +
|
|
122
|
+
length + ")");
|
|
123
|
+
}
|
|
124
|
+
j += 2;
|
|
125
|
+
if (j + length > bufferLength) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
j += length;
|
|
129
|
+
const segment = buffer.slice(i, j);
|
|
130
|
+
if (type == 0xC4) {
|
|
131
|
+
// Huffman tables
|
|
132
|
+
this._huffmanTables.push(segment);
|
|
133
|
+
} else if (type == 0xDB) {
|
|
134
|
+
// Quantization tables
|
|
135
|
+
this._quantTables.push(segment);
|
|
136
|
+
}
|
|
137
|
+
this._segments.push(segment);
|
|
138
|
+
i = j;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* noVNC: HTML5 VNC client
|
|
3
|
+
* Copyright (C) 2021 The noVNC Authors
|
|
4
|
+
* Licensed under MPL 2.0 (see LICENSE.txt)
|
|
5
|
+
*
|
|
6
|
+
* See README.md for usage and integration instructions.
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import Inflate from "../inflator.js";
|
|
11
|
+
|
|
12
|
+
const ZRLE_TILE_WIDTH = 64;
|
|
13
|
+
const ZRLE_TILE_HEIGHT = 64;
|
|
14
|
+
|
|
15
|
+
export default class ZRLEDecoder {
|
|
16
|
+
constructor() {
|
|
17
|
+
this._length = 0;
|
|
18
|
+
this._inflator = new Inflate();
|
|
19
|
+
|
|
20
|
+
this._pixelBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
|
|
21
|
+
this._tileBuffer = new Uint8Array(ZRLE_TILE_WIDTH * ZRLE_TILE_HEIGHT * 4);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
decodeRect(x, y, width, height, sock, display, depth) {
|
|
25
|
+
if (this._length === 0) {
|
|
26
|
+
if (sock.rQwait("ZLib data length", 4)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
this._length = sock.rQshift32();
|
|
30
|
+
}
|
|
31
|
+
if (sock.rQwait("Zlib data", this._length)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const data = sock.rQshiftBytes(this._length);
|
|
36
|
+
|
|
37
|
+
this._inflator.setInput(data);
|
|
38
|
+
|
|
39
|
+
for (let ty = y; ty < y + height; ty += ZRLE_TILE_HEIGHT) {
|
|
40
|
+
let th = Math.min(ZRLE_TILE_HEIGHT, y + height - ty);
|
|
41
|
+
|
|
42
|
+
for (let tx = x; tx < x + width; tx += ZRLE_TILE_WIDTH) {
|
|
43
|
+
let tw = Math.min(ZRLE_TILE_WIDTH, x + width - tx);
|
|
44
|
+
|
|
45
|
+
const tileSize = tw * th;
|
|
46
|
+
const subencoding = this._inflator.inflate(1)[0];
|
|
47
|
+
if (subencoding === 0) {
|
|
48
|
+
// raw data
|
|
49
|
+
const data = this._readPixels(tileSize);
|
|
50
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
51
|
+
} else if (subencoding === 1) {
|
|
52
|
+
// solid
|
|
53
|
+
const background = this._readPixels(1);
|
|
54
|
+
display.fillRect(tx, ty, tw, th, [background[0], background[1], background[2]]);
|
|
55
|
+
} else if (subencoding >= 2 && subencoding <= 16) {
|
|
56
|
+
const data = this._decodePaletteTile(subencoding, tileSize, tw, th);
|
|
57
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
58
|
+
} else if (subencoding === 128) {
|
|
59
|
+
const data = this._decodeRLETile(tileSize);
|
|
60
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
61
|
+
} else if (subencoding >= 130 && subencoding <= 255) {
|
|
62
|
+
const data = this._decodeRLEPaletteTile(subencoding - 128, tileSize);
|
|
63
|
+
display.blitImage(tx, ty, tw, th, data, 0, false);
|
|
64
|
+
} else {
|
|
65
|
+
throw new Error('Unknown subencoding: ' + subencoding);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
this._length = 0;
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_getBitsPerPixelInPalette(paletteSize) {
|
|
74
|
+
if (paletteSize <= 2) {
|
|
75
|
+
return 1;
|
|
76
|
+
} else if (paletteSize <= 4) {
|
|
77
|
+
return 2;
|
|
78
|
+
} else if (paletteSize <= 16) {
|
|
79
|
+
return 4;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
_readPixels(pixels) {
|
|
84
|
+
let data = this._pixelBuffer;
|
|
85
|
+
const buffer = this._inflator.inflate(3*pixels);
|
|
86
|
+
for (let i = 0, j = 0; i < pixels*4; i += 4, j += 3) {
|
|
87
|
+
data[i] = buffer[j];
|
|
88
|
+
data[i + 1] = buffer[j + 1];
|
|
89
|
+
data[i + 2] = buffer[j + 2];
|
|
90
|
+
data[i + 3] = 255; // Add the Alpha
|
|
91
|
+
}
|
|
92
|
+
return data;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
_decodePaletteTile(paletteSize, tileSize, tilew, tileh) {
|
|
96
|
+
const data = this._tileBuffer;
|
|
97
|
+
const palette = this._readPixels(paletteSize);
|
|
98
|
+
const bitsPerPixel = this._getBitsPerPixelInPalette(paletteSize);
|
|
99
|
+
const mask = (1 << bitsPerPixel) - 1;
|
|
100
|
+
|
|
101
|
+
let offset = 0;
|
|
102
|
+
let encoded = this._inflator.inflate(1)[0];
|
|
103
|
+
|
|
104
|
+
for (let y=0; y<tileh; y++) {
|
|
105
|
+
let shift = 8-bitsPerPixel;
|
|
106
|
+
for (let x=0; x<tilew; x++) {
|
|
107
|
+
if (shift<0) {
|
|
108
|
+
shift=8-bitsPerPixel;
|
|
109
|
+
encoded = this._inflator.inflate(1)[0];
|
|
110
|
+
}
|
|
111
|
+
let indexInPalette = (encoded>>shift) & mask;
|
|
112
|
+
|
|
113
|
+
data[offset] = palette[indexInPalette * 4];
|
|
114
|
+
data[offset + 1] = palette[indexInPalette * 4 + 1];
|
|
115
|
+
data[offset + 2] = palette[indexInPalette * 4 + 2];
|
|
116
|
+
data[offset + 3] = palette[indexInPalette * 4 + 3];
|
|
117
|
+
offset += 4;
|
|
118
|
+
shift-=bitsPerPixel;
|
|
119
|
+
}
|
|
120
|
+
if (shift<8-bitsPerPixel && y<tileh-1) {
|
|
121
|
+
encoded = this._inflator.inflate(1)[0];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return data;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_decodeRLETile(tileSize) {
|
|
128
|
+
const data = this._tileBuffer;
|
|
129
|
+
let i = 0;
|
|
130
|
+
while (i < tileSize) {
|
|
131
|
+
const pixel = this._readPixels(1);
|
|
132
|
+
const length = this._readRLELength();
|
|
133
|
+
for (let j = 0; j < length; j++) {
|
|
134
|
+
data[i * 4] = pixel[0];
|
|
135
|
+
data[i * 4 + 1] = pixel[1];
|
|
136
|
+
data[i * 4 + 2] = pixel[2];
|
|
137
|
+
data[i * 4 + 3] = pixel[3];
|
|
138
|
+
i++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return data;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
_decodeRLEPaletteTile(paletteSize, tileSize) {
|
|
145
|
+
const data = this._tileBuffer;
|
|
146
|
+
|
|
147
|
+
// palette
|
|
148
|
+
const palette = this._readPixels(paletteSize);
|
|
149
|
+
|
|
150
|
+
let offset = 0;
|
|
151
|
+
while (offset < tileSize) {
|
|
152
|
+
let indexInPalette = this._inflator.inflate(1)[0];
|
|
153
|
+
let length = 1;
|
|
154
|
+
if (indexInPalette >= 128) {
|
|
155
|
+
indexInPalette -= 128;
|
|
156
|
+
length = this._readRLELength();
|
|
157
|
+
}
|
|
158
|
+
if (indexInPalette > paletteSize) {
|
|
159
|
+
throw new Error('Too big index in palette: ' + indexInPalette + ', palette size: ' + paletteSize);
|
|
160
|
+
}
|
|
161
|
+
if (offset + length > tileSize) {
|
|
162
|
+
throw new Error('Too big rle length in palette mode: ' + length + ', allowed length is: ' + (tileSize - offset));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
for (let j = 0; j < length; j++) {
|
|
166
|
+
data[offset * 4] = palette[indexInPalette * 4];
|
|
167
|
+
data[offset * 4 + 1] = palette[indexInPalette * 4 + 1];
|
|
168
|
+
data[offset * 4 + 2] = palette[indexInPalette * 4 + 2];
|
|
169
|
+
data[offset * 4 + 3] = palette[indexInPalette * 4 + 3];
|
|
170
|
+
offset++;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return data;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_readRLELength() {
|
|
177
|
+
let length = 0;
|
|
178
|
+
let current = 0;
|
|
179
|
+
do {
|
|
180
|
+
current = this._inflator.inflate(1)[0];
|
|
181
|
+
length += current;
|
|
182
|
+
} while (current === 255);
|
|
183
|
+
return length + 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
package/core/encodings.js
CHANGED
|
@@ -12,7 +12,9 @@ export const encodings = {
|
|
|
12
12
|
encodingRRE: 2,
|
|
13
13
|
encodingHextile: 5,
|
|
14
14
|
encodingTight: 7,
|
|
15
|
+
encodingZRLE: 16,
|
|
15
16
|
encodingTightPNG: -260,
|
|
17
|
+
encodingJPEG: 21,
|
|
16
18
|
|
|
17
19
|
pseudoEncodingQualityLevel9: -23,
|
|
18
20
|
pseudoEncodingQualityLevel0: -32,
|
|
@@ -38,7 +40,9 @@ export function encodingName(num) {
|
|
|
38
40
|
case encodings.encodingRRE: return "RRE";
|
|
39
41
|
case encodings.encodingHextile: return "Hextile";
|
|
40
42
|
case encodings.encodingTight: return "Tight";
|
|
43
|
+
case encodings.encodingZRLE: return "ZRLE";
|
|
41
44
|
case encodings.encodingTightPNG: return "TightPNG";
|
|
45
|
+
case encodings.encodingJPEG: return "JPEG";
|
|
42
46
|
default: return "[unknown encoding " + num + "]";
|
|
43
47
|
}
|
|
44
48
|
}
|
package/core/rfb.js
CHANGED
|
@@ -32,6 +32,8 @@ import RREDecoder from "./decoders/rre.js";
|
|
|
32
32
|
import HextileDecoder from "./decoders/hextile.js";
|
|
33
33
|
import TightDecoder from "./decoders/tight.js";
|
|
34
34
|
import TightPNGDecoder from "./decoders/tightpng.js";
|
|
35
|
+
import ZRLEDecoder from "./decoders/zrle.js";
|
|
36
|
+
import JPEGDecoder from "./decoders/jpeg.js";
|
|
35
37
|
|
|
36
38
|
// How many seconds to wait for a disconnect to finish
|
|
37
39
|
const DISCONNECT_TIMEOUT = 3;
|
|
@@ -218,6 +220,8 @@ export default class RFB extends EventTargetMixin {
|
|
|
218
220
|
this._decoders[encodings.encodingHextile] = new HextileDecoder();
|
|
219
221
|
this._decoders[encodings.encodingTight] = new TightDecoder();
|
|
220
222
|
this._decoders[encodings.encodingTightPNG] = new TightPNGDecoder();
|
|
223
|
+
this._decoders[encodings.encodingZRLE] = new ZRLEDecoder();
|
|
224
|
+
this._decoders[encodings.encodingJPEG] = new JPEGDecoder();
|
|
221
225
|
|
|
222
226
|
// NB: nothing that needs explicit teardown should be done
|
|
223
227
|
// before this point, since this can throw an exception
|
|
@@ -240,6 +244,8 @@ export default class RFB extends EventTargetMixin {
|
|
|
240
244
|
this._sock.on('message', this._handleMessage.bind(this));
|
|
241
245
|
this._sock.on('error', this._socketError.bind(this));
|
|
242
246
|
|
|
247
|
+
this._expectedClientWidth = null;
|
|
248
|
+
this._expectedClientHeight = null;
|
|
243
249
|
this._resizeObserver = new ResizeObserver(this._eventHandlers.handleResize);
|
|
244
250
|
|
|
245
251
|
// All prepared, kick off the connection
|
|
@@ -619,7 +625,26 @@ export default class RFB extends EventTargetMixin {
|
|
|
619
625
|
{ detail: { name: this._fbName } }));
|
|
620
626
|
}
|
|
621
627
|
|
|
628
|
+
_saveExpectedClientSize() {
|
|
629
|
+
this._expectedClientWidth = this._screen.clientWidth;
|
|
630
|
+
this._expectedClientHeight = this._screen.clientHeight;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
_currentClientSize() {
|
|
634
|
+
return [this._screen.clientWidth, this._screen.clientHeight];
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
_clientHasExpectedSize() {
|
|
638
|
+
const [currentWidth, currentHeight] = this._currentClientSize();
|
|
639
|
+
return currentWidth == this._expectedClientWidth &&
|
|
640
|
+
currentHeight == this._expectedClientHeight;
|
|
641
|
+
}
|
|
642
|
+
|
|
622
643
|
_handleResize() {
|
|
644
|
+
// Don't change anything if the client size is already as expected
|
|
645
|
+
if (this._clientHasExpectedSize()) {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
623
648
|
// If the window resized then our screen element might have
|
|
624
649
|
// as well. Update the viewport dimensions.
|
|
625
650
|
window.requestAnimationFrame(() => {
|
|
@@ -660,6 +685,12 @@ export default class RFB extends EventTargetMixin {
|
|
|
660
685
|
this._display.viewportChangeSize(size.w, size.h);
|
|
661
686
|
this._fixScrollbars();
|
|
662
687
|
}
|
|
688
|
+
|
|
689
|
+
// When changing clipping we might show or hide scrollbars.
|
|
690
|
+
// This causes the expected client dimensions to change.
|
|
691
|
+
if (curClip !== newClip) {
|
|
692
|
+
this._saveExpectedClientSize();
|
|
693
|
+
}
|
|
663
694
|
}
|
|
664
695
|
|
|
665
696
|
_updateScale() {
|
|
@@ -684,6 +715,7 @@ export default class RFB extends EventTargetMixin {
|
|
|
684
715
|
}
|
|
685
716
|
|
|
686
717
|
const size = this._screenSize();
|
|
718
|
+
|
|
687
719
|
RFB.messages.setDesktopSize(this._sock,
|
|
688
720
|
Math.floor(size.w), Math.floor(size.h),
|
|
689
721
|
this._screenID, this._screenFlags);
|
|
@@ -699,12 +731,13 @@ export default class RFB extends EventTargetMixin {
|
|
|
699
731
|
}
|
|
700
732
|
|
|
701
733
|
_fixScrollbars() {
|
|
702
|
-
// This is a hack because
|
|
703
|
-
// for when scrollbars are needed.
|
|
704
|
-
//
|
|
734
|
+
// This is a hack because Safari on macOS screws up the calculation
|
|
735
|
+
// for when scrollbars are needed. We get scrollbars when making the
|
|
736
|
+
// browser smaller, despite remote resize being enabled. So to fix it
|
|
737
|
+
// we temporarily toggle them off and on.
|
|
705
738
|
const orig = this._screen.style.overflow;
|
|
706
739
|
this._screen.style.overflow = 'hidden';
|
|
707
|
-
// Force
|
|
740
|
+
// Force Safari to recalculate the layout by asking for
|
|
708
741
|
// an element's dimensions
|
|
709
742
|
this._screen.getBoundingClientRect();
|
|
710
743
|
this._screen.style.overflow = orig;
|
|
@@ -1772,6 +1805,8 @@ export default class RFB extends EventTargetMixin {
|
|
|
1772
1805
|
if (this._fbDepth == 24) {
|
|
1773
1806
|
encs.push(encodings.encodingTight);
|
|
1774
1807
|
encs.push(encodings.encodingTightPNG);
|
|
1808
|
+
encs.push(encodings.encodingZRLE);
|
|
1809
|
+
encs.push(encodings.encodingJPEG);
|
|
1775
1810
|
encs.push(encodings.encodingHextile);
|
|
1776
1811
|
encs.push(encodings.encodingRRE);
|
|
1777
1812
|
}
|
|
@@ -2500,6 +2535,9 @@ export default class RFB extends EventTargetMixin {
|
|
|
2500
2535
|
this._updateScale();
|
|
2501
2536
|
|
|
2502
2537
|
this._updateContinuousUpdates();
|
|
2538
|
+
|
|
2539
|
+
// Keep this size until browser client size changes
|
|
2540
|
+
this._saveExpectedClientSize();
|
|
2503
2541
|
}
|
|
2504
2542
|
|
|
2505
2543
|
_xvpOp(ver, op) {
|
package/lib/base64.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _typeof(obj) { "@babel/helpers - typeof";
|
|
3
|
+
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
4
4
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
package/lib/decoders/copyrect.js
CHANGED
|
@@ -9,7 +9,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
|
9
9
|
|
|
10
10
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
11
11
|
|
|
12
|
-
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
12
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
13
13
|
|
|
14
14
|
/*
|
|
15
15
|
* noVNC: HTML5 VNC client
|
package/lib/decoders/hextile.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
function _typeof(obj) { "@babel/helpers - typeof";
|
|
3
|
+
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
4
4
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", {
|
|
6
6
|
value: true
|
|
@@ -17,7 +17,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
|
|
|
17
17
|
|
|
18
18
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
19
19
|
|
|
20
|
-
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
20
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
21
21
|
|
|
22
22
|
var HextileDecoder = /*#__PURE__*/function () {
|
|
23
23
|
function HextileDecoder() {
|