WIP - computer acting odd, committing code
This commit is contained in:
parent
419a3a70e9
commit
96001175a6
206
app/ui_screen.js
206
app/ui_screen.js
|
@ -1,13 +1,15 @@
|
||||||
|
import RFB from "../core/rfb.js";
|
||||||
|
import * as WebUtil from "./webutil.js";
|
||||||
|
import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold, supportsBinaryClipboard, isFirefox, isWindows, isIOS, supportsPointerLock }
|
||||||
|
from '../core/util/browser.js';
|
||||||
|
import { MouseButtonMapper, XVNC_BUTTONS } from "../core/mousebuttonmapper.js";
|
||||||
|
|
||||||
const UI = {
|
const UI = {
|
||||||
connected: false,
|
connected: false,
|
||||||
|
|
||||||
//Initial Loading of the UI
|
//Initial Loading of the UI
|
||||||
prime() {
|
prime() {
|
||||||
|
this.start();
|
||||||
},
|
},
|
||||||
|
|
||||||
//Render default UI
|
//Render default UI
|
||||||
|
@ -20,19 +22,209 @@ const UI = {
|
||||||
|
|
||||||
|
|
||||||
UI.addDefaultHandlers();
|
UI.addDefaultHandlers();
|
||||||
|
UI.updateVisualState('disconnected');
|
||||||
},
|
},
|
||||||
|
|
||||||
addDefaultHandlers() {
|
addDefaultHandlers() {
|
||||||
document.getElementById('noVNC_connect_button', UI.connect);
|
document.getElementById('noVNC_connect_button').addEventListener('click', UI.connect);;
|
||||||
|
},
|
||||||
|
|
||||||
|
getSetting(name, isBool) {
|
||||||
|
const ctrl = document.getElementById('noVNC_setting_' + name);
|
||||||
|
let val = WebUtil.readSetting(name);
|
||||||
|
if (typeof val !== 'undefined' && val !== null && isBool) {
|
||||||
|
if (val.toString().toLowerCase() in {'0': 1, 'no': 1, 'false': 1}) {
|
||||||
|
val = false;
|
||||||
|
} else {
|
||||||
|
val = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
},
|
},
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
|
UI.rfb = new RFB(document.getElementById('noVNC_container'),
|
||||||
|
document.getElementById('noVNC_keyboardinput'),
|
||||||
|
"", //URL
|
||||||
|
{
|
||||||
|
shared: UI.getSetting('shared', true),
|
||||||
|
repeaterID: UI.getSetting('repeaterID', false),
|
||||||
|
credentials: { password: null }
|
||||||
|
},
|
||||||
|
false // Not a primary display
|
||||||
|
);
|
||||||
|
UI.rfb.addEventListener("connect", UI.connectFinished);
|
||||||
|
//UI.rfb.addEventListener("disconnect", UI.disconnectFinished);
|
||||||
|
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.dynamicQualityMin = parseInt(UI.getSetting('dynamic_quality_min'));
|
||||||
|
UI.rfb.dynamicQualityMax = parseInt(UI.getSetting('dynamic_quality_max'));
|
||||||
|
UI.rfb.jpegVideoQuality = parseInt(UI.getSetting('jpeg_video_quality'));
|
||||||
|
UI.rfb.webpVideoQuality = parseInt(UI.getSetting('webp_video_quality'));
|
||||||
|
UI.rfb.videoArea = parseInt(UI.getSetting('video_area'));
|
||||||
|
UI.rfb.videoTime = parseInt(UI.getSetting('video_time'));
|
||||||
|
UI.rfb.videoOutTime = parseInt(UI.getSetting('video_out_time'));
|
||||||
|
UI.rfb.videoScaling = parseInt(UI.getSetting('video_scaling'));
|
||||||
|
UI.rfb.treatLossless = parseInt(UI.getSetting('treat_lossless'));
|
||||||
|
UI.rfb.maxVideoResolutionX = parseInt(UI.getSetting('max_video_resolution_x'));
|
||||||
|
UI.rfb.maxVideoResolutionY = parseInt(UI.getSetting('max_video_resolution_y'));
|
||||||
|
UI.rfb.frameRate = parseInt(UI.getSetting('framerate'));
|
||||||
|
UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
|
||||||
|
UI.rfb.showDotCursor = UI.getSetting('show_dot');
|
||||||
|
UI.rfb.idleDisconnect = UI.getSetting('idle_disconnect');
|
||||||
|
UI.rfb.pointerRelative = UI.getSetting('pointer_relative');
|
||||||
|
UI.rfb.videoQuality = parseInt(UI.getSetting('video_quality'));
|
||||||
|
UI.rfb.antiAliasing = UI.getSetting('anti_aliasing');
|
||||||
|
UI.rfb.clipboardUp = UI.getSetting('clipboard_up');
|
||||||
|
UI.rfb.clipboardDown = UI.getSetting('clipboard_down');
|
||||||
|
UI.rfb.clipboardSeamless = UI.getSetting('clipboard_seamless');
|
||||||
|
UI.rfb.keyboard.enableIME = UI.getSetting('enable_ime');
|
||||||
|
UI.rfb.clipboardBinary = supportsBinaryClipboard() && UI.rfb.clipboardSeamless;
|
||||||
|
UI.rfb.enableWebRTC = UI.getSetting('enable_webrtc');
|
||||||
|
UI.rfb.enableHiDpi = UI.getSetting('enable_hidpi');
|
||||||
|
UI.rfb.mouseButtonMapper = UI.initMouseButtonMapper();
|
||||||
|
if (UI.rfb.videoQuality === 5) {
|
||||||
|
UI.rfb.enableQOI = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateVisualState(state) {
|
||||||
|
document.documentElement.classList.remove("noVNC_connecting");
|
||||||
|
document.documentElement.classList.remove("noVNC_connected");
|
||||||
|
document.documentElement.classList.remove("noVNC_disconnecting");
|
||||||
|
document.documentElement.classList.remove("noVNC_reconnecting");
|
||||||
|
document.documentElement.classList.remove("noVNC_disconnected");
|
||||||
|
|
||||||
|
const transitionElem = document.getElementById("noVNC_transition_text");
|
||||||
|
if (WebUtil.isInsideKasmVDI())
|
||||||
|
{
|
||||||
|
parent.postMessage({ action: 'connection_state', value: state}, '*' );
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case 'init':
|
||||||
|
break;
|
||||||
|
case 'connecting':
|
||||||
|
transitionElem.textContent = _("Connecting...");
|
||||||
|
document.documentElement.classList.add("noVNC_connecting");
|
||||||
|
break;
|
||||||
|
case 'connected':
|
||||||
|
document.documentElement.classList.add("noVNC_connected");
|
||||||
|
break;
|
||||||
|
case 'disconnecting':
|
||||||
|
transitionElem.textContent = _("Disconnecting...");
|
||||||
|
document.documentElement.classList.add("noVNC_disconnecting");
|
||||||
|
break;
|
||||||
|
case 'disconnected':
|
||||||
|
document.documentElement.classList.add("noVNC_disconnected");
|
||||||
|
break;
|
||||||
|
case 'reconnecting':
|
||||||
|
transitionElem.textContent = _("Reconnecting...");
|
||||||
|
document.documentElement.classList.add("noVNC_reconnecting");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.Error("Invalid visual state: " + state);
|
||||||
|
UI.showStatus(_("Internal error"), 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showStatus(text, statusType, time, kasm = false) {
|
||||||
|
// If inside the full Kasm CDI framework, don't show messages unless explicitly told to
|
||||||
|
if (WebUtil.isInsideKasmVDI() && !kasm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusElem = document.getElementById('noVNC_status');
|
||||||
|
|
||||||
|
if (typeof statusType === 'undefined') {
|
||||||
|
statusType = 'normal';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't overwrite more severe visible statuses and never
|
||||||
|
// errors. Only shows the first error.
|
||||||
|
if (statusElem.classList.contains("noVNC_open")) {
|
||||||
|
if (statusElem.classList.contains("noVNC_status_error")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (statusElem.classList.contains("noVNC_status_warn") &&
|
||||||
|
statusType === 'normal') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(UI.statusTimeout);
|
||||||
|
|
||||||
|
switch (statusType) {
|
||||||
|
case 'error':
|
||||||
|
statusElem.classList.remove("noVNC_status_warn");
|
||||||
|
statusElem.classList.remove("noVNC_status_normal");
|
||||||
|
statusElem.classList.add("noVNC_status_error");
|
||||||
|
break;
|
||||||
|
case 'warning':
|
||||||
|
case 'warn':
|
||||||
|
statusElem.classList.remove("noVNC_status_error");
|
||||||
|
statusElem.classList.remove("noVNC_status_normal");
|
||||||
|
statusElem.classList.add("noVNC_status_warn");
|
||||||
|
break;
|
||||||
|
case 'normal':
|
||||||
|
case 'info':
|
||||||
|
default:
|
||||||
|
statusElem.classList.remove("noVNC_status_error");
|
||||||
|
statusElem.classList.remove("noVNC_status_warn");
|
||||||
|
statusElem.classList.add("noVNC_status_normal");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
statusElem.textContent = text;
|
||||||
|
statusElem.classList.add("noVNC_open");
|
||||||
|
|
||||||
|
// If no time was specified, show the status for 1.5 seconds
|
||||||
|
if (typeof time === 'undefined') {
|
||||||
|
time = 1500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error messages do not timeout
|
||||||
|
if (statusType !== 'error') {
|
||||||
|
UI.statusTimeout = window.setTimeout(UI.hideStatus, time);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
disconnect() {
|
disconnect() {
|
||||||
|
|
||||||
}
|
},
|
||||||
|
|
||||||
|
connectFinished(e) {
|
||||||
|
UI.connected = true;
|
||||||
|
UI.inhibitReconnect = false;
|
||||||
|
|
||||||
|
UI.showStatus("Secondary Screen Connected");
|
||||||
|
UI.updateVisualState('connected');
|
||||||
|
|
||||||
|
// Do this last because it can only be used on rendered elements
|
||||||
|
UI.rfb.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
initMouseButtonMapper() {
|
||||||
|
const mouseButtonMapper = new MouseButtonMapper();
|
||||||
|
|
||||||
|
const settings = WebUtil.readSetting("mouseButtonMapper");
|
||||||
|
if (settings) {
|
||||||
|
mouseButtonMapper.load(settings);
|
||||||
|
return mouseButtonMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseButtonMapper.set(0, XVNC_BUTTONS.LEFT_BUTTON);
|
||||||
|
mouseButtonMapper.set(1, XVNC_BUTTONS.MIDDLE_BUTTON);
|
||||||
|
mouseButtonMapper.set(2, XVNC_BUTTONS.RIGHT_BUTTON);
|
||||||
|
mouseButtonMapper.set(3, XVNC_BUTTONS.BACK_BUTTON);
|
||||||
|
mouseButtonMapper.set(4, XVNC_BUTTONS.FORWARD_BUTTON);
|
||||||
|
WebUtil.writeSetting("mouseButtonMapper", mouseButtonMapper.dump());
|
||||||
|
|
||||||
|
return mouseButtonMapper;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
UI.prime();
|
UI.prime();
|
||||||
|
|
322
core/display.js
322
core/display.js
|
@ -14,7 +14,7 @@ import { isWindows } from './util/browser.js';
|
||||||
import { uuidv4 } from './util/strings.js'
|
import { uuidv4 } from './util/strings.js'
|
||||||
|
|
||||||
export default class Display {
|
export default class Display {
|
||||||
constructor(target) {
|
constructor(target, isPrimaryDisplay) {
|
||||||
Log.Debug(">> Display.constructor");
|
Log.Debug(">> Display.constructor");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,8 +85,10 @@ export default class Display {
|
||||||
this._clipViewport = false;
|
this._clipViewport = false;
|
||||||
this._antiAliasing = 0;
|
this._antiAliasing = 0;
|
||||||
this._fps = 0;
|
this._fps = 0;
|
||||||
|
this._isPrimaryDisplay = isPrimaryDisplay;
|
||||||
|
this._screenID = uuidv4();
|
||||||
this._screens = [{
|
this._screens = [{
|
||||||
screenID: uuidv4(),
|
screenID: this._screenID,
|
||||||
screenIndex: 0,
|
screenIndex: 0,
|
||||||
width: this._target.width, //client
|
width: this._target.width, //client
|
||||||
height: this._target.height, //client
|
height: this._target.height, //client
|
||||||
|
@ -108,6 +110,11 @@ export default class Display {
|
||||||
// Use requestAnimationFrame to write to canvas, to match display refresh rate
|
// Use requestAnimationFrame to write to canvas, to match display refresh rate
|
||||||
this._animationFrameID = window.requestAnimationFrame( () => { this._pushAsyncFrame(); });
|
this._animationFrameID = window.requestAnimationFrame( () => { this._pushAsyncFrame(); });
|
||||||
|
|
||||||
|
if (!this._isPrimaryDisplay) {
|
||||||
|
this._screens[0].channel = new BroadcastChannel(`screen_${this._screenID}_channel`);
|
||||||
|
this._screens[0].channel.addEventListener('message', this._handleSecondaryDisplayMessage.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
Log.Debug("<< Display.constructor");
|
Log.Debug("<< Display.constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +173,8 @@ export default class Display {
|
||||||
//recalculate primary display container size
|
//recalculate primary display container size
|
||||||
this._screens[0].containerHeight = this._target.parentNode.offsetHeight;
|
this._screens[0].containerHeight = this._target.parentNode.offsetHeight;
|
||||||
this._screens[0].containerWidth = this._target.parentNode.offsetWidth;
|
this._screens[0].containerWidth = this._target.parentNode.offsetWidth;
|
||||||
|
this._screens[0].width = this._target.width;
|
||||||
|
this._screens[0].height = this._target.height;
|
||||||
|
|
||||||
//calculate server-side resolution of each screen
|
//calculate server-side resolution of each screen
|
||||||
for (let i=0; i<this._screens.length; i++) {
|
for (let i=0; i<this._screens.length; i++) {
|
||||||
|
@ -218,6 +227,9 @@ export default class Display {
|
||||||
if (this._screens.length > 1) {
|
if (this._screens.length > 1) {
|
||||||
const primary_screen = this._screens[0];
|
const primary_screen = this._screens[0];
|
||||||
const secondary_screen = this._screens[1];
|
const secondary_screen = this._screens[1];
|
||||||
|
let total_width = 0;
|
||||||
|
let total_height = 0;
|
||||||
|
|
||||||
switch (this._screens[1].relativePosition) {
|
switch (this._screens[1].relativePosition) {
|
||||||
case 0:
|
case 0:
|
||||||
//primary screen is to left
|
//primary screen is to left
|
||||||
|
@ -257,50 +269,59 @@ export default class Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.screens = structuredClone(this._screens);
|
data.screens = this._screens;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
addScreen(screenID, width, height, relativePosition, pixelRatio, containerHeight, containerWidth) {
|
addScreen(screenID, width, height, relativePosition, pixelRatio, containerHeight, containerWidth) {
|
||||||
//currently only support one secondary screen
|
if (this._isPrimaryDisplay) {
|
||||||
if (this._screens.length > 1) {
|
//currently only support one secondary screen
|
||||||
this._screens[1].channel.close();
|
if (this._screens.length > 1) {
|
||||||
this._screens.pop()
|
this._screens[1].channel.close();
|
||||||
}
|
this._screens.pop()
|
||||||
screenIdx = this.screens.length;
|
}
|
||||||
new_screen = {
|
|
||||||
screenID: screenID,
|
|
||||||
screenIndex: screenIdx,
|
|
||||||
width: width, //client
|
|
||||||
height: height, //client
|
|
||||||
serverWidth: 0, //calculated
|
|
||||||
serverHeight: 0, //calculated
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
relativePosition: relativePosition,
|
|
||||||
pixelRatio: pixelRatio,
|
|
||||||
containerHeight: containerHeight,
|
|
||||||
containerWidth: containerWidth,
|
|
||||||
channel: null,
|
|
||||||
scale: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
new_screen.channel = new BroadcastChannel(`screen_${screenID}_channel`);
|
var new_screen = {
|
||||||
//new_screen.channel.message = this._handleSecondaryDisplayMessage().bind(this);
|
screenID: screenID,
|
||||||
|
screenIndex: this.screens.length,
|
||||||
|
width: width, //client
|
||||||
|
height: height, //client
|
||||||
|
serverWidth: 0, //calculated
|
||||||
|
serverHeight: 0, //calculated
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
relativePosition: relativePosition,
|
||||||
|
pixelRatio: pixelRatio,
|
||||||
|
containerHeight: containerHeight,
|
||||||
|
containerWidth: containerWidth,
|
||||||
|
channel: null,
|
||||||
|
scale: 0
|
||||||
|
}
|
||||||
|
|
||||||
this._screens.push(new_screen);
|
new_screen.channel = new BroadcastChannel(`screen_${screenID}_channel`);
|
||||||
new_screen.channel.postMessage({ eventType: "registered", screenIndex: screenIdx });
|
//new_screen.channel.message = this._handleSecondaryDisplayMessage().bind(this);
|
||||||
|
|
||||||
|
this._screens.push(new_screen);
|
||||||
|
new_screen.channel.postMessage({ eventType: "registered", screenIndex: new_screen.screenIndex });
|
||||||
|
} else {
|
||||||
|
throw new Error("Cannot add a screen to a secondary display.")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeScreen(screenID) {
|
removeScreen(screenID) {
|
||||||
for (let i=1; i<this._screens.length; i++) {
|
if (this.isPrimaryDisplay) {
|
||||||
if (this._screens[i].screenID == screenID) {
|
for (let i=1; i<this._screens.length; i++) {
|
||||||
this._screens.splice(i, 1);
|
if (this._screens[i].screenID == screenID) {
|
||||||
return true;
|
this._screens.splice(i, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
throw new Error("Secondary screens only allowed on primary display.")
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
viewportChangePos(deltaX, deltaY) {
|
viewportChangePos(deltaX, deltaY) {
|
||||||
|
@ -340,7 +361,7 @@ export default class Display {
|
||||||
|
|
||||||
viewportChangeSize(width, height) {
|
viewportChangeSize(width, height) {
|
||||||
|
|
||||||
if (!this._clipViewport ||
|
if ((!this._clipViewport && this._screens.length === 1 ) ||
|
||||||
typeof(width) === "undefined" ||
|
typeof(width) === "undefined" ||
|
||||||
typeof(height) === "undefined") {
|
typeof(height) === "undefined") {
|
||||||
|
|
||||||
|
@ -398,6 +419,10 @@ export default class Display {
|
||||||
|
|
||||||
const canvas = this._target;
|
const canvas = this._target;
|
||||||
if (canvas == undefined) { return; }
|
if (canvas == undefined) { return; }
|
||||||
|
if (this._screens.length > 0) {
|
||||||
|
width = this._screens[0].serverWidth;
|
||||||
|
height = this._screens[0].serverHeight;
|
||||||
|
}
|
||||||
if (canvas.width !== width || canvas.height !== height) {
|
if (canvas.width !== width || canvas.height !== height) {
|
||||||
|
|
||||||
// We have to save the canvas data since changing the size will clear it
|
// We have to save the canvas data since changing the size will clear it
|
||||||
|
@ -434,7 +459,8 @@ export default class Display {
|
||||||
this._asyncRenderQPush({
|
this._asyncRenderQPush({
|
||||||
'type': 'flip',
|
'type': 'flip',
|
||||||
'frame_id': frame_id,
|
'frame_id': frame_id,
|
||||||
'rect_cnt': rect_cnt
|
'rect_cnt': rect_cnt,
|
||||||
|
'screenLocations': [ { screenIndex: 0, x: 0, y: 0 } ]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,15 +506,17 @@ export default class Display {
|
||||||
|
|
||||||
fillRect(x, y, width, height, color, frame_id, fromQueue) {
|
fillRect(x, y, width, height, color, frame_id, fromQueue) {
|
||||||
if (!fromQueue) {
|
if (!fromQueue) {
|
||||||
this._asyncRenderQPush({
|
let rect = {
|
||||||
'type': 'fill',
|
type: 'fill',
|
||||||
'x': x,
|
x: x,
|
||||||
'y': y,
|
y: y,
|
||||||
'width': width,
|
width: width,
|
||||||
'height': height,
|
height: height,
|
||||||
'color': color,
|
color: color,
|
||||||
'frame_id': frame_id
|
frame_id: frame_id
|
||||||
});
|
}
|
||||||
|
this._processRectScreens(rect);
|
||||||
|
this._asyncRenderQPush(rect);
|
||||||
} else {
|
} else {
|
||||||
this._setFillColor(color);
|
this._setFillColor(color);
|
||||||
this._targetCtx.fillRect(x, y, width, height);
|
this._targetCtx.fillRect(x, y, width, height);
|
||||||
|
@ -497,7 +525,7 @@ export default class Display {
|
||||||
|
|
||||||
copyImage(oldX, oldY, newX, newY, w, h, frame_id, fromQueue) {
|
copyImage(oldX, oldY, newX, newY, w, h, frame_id, fromQueue) {
|
||||||
if (!fromQueue) {
|
if (!fromQueue) {
|
||||||
this._asyncRenderQPush({
|
let rect = {
|
||||||
'type': 'copy',
|
'type': 'copy',
|
||||||
'oldX': oldX,
|
'oldX': oldX,
|
||||||
'oldY': oldY,
|
'oldY': oldY,
|
||||||
|
@ -506,7 +534,9 @@ export default class Display {
|
||||||
'width': w,
|
'width': w,
|
||||||
'height': h,
|
'height': h,
|
||||||
'frame_id': frame_id
|
'frame_id': frame_id
|
||||||
});
|
}
|
||||||
|
this._processRectScreens(rect);
|
||||||
|
this._asyncRenderQPush(rect);
|
||||||
} else {
|
} else {
|
||||||
// Due to this bug among others [1] we need to disable the image-smoothing to
|
// Due to this bug among others [1] we need to disable the image-smoothing to
|
||||||
// avoid getting a blur effect when copying data.
|
// avoid getting a blur effect when copying data.
|
||||||
|
@ -531,18 +561,31 @@ export default class Display {
|
||||||
if ((width === 0) || (height === 0)) {
|
if ((width === 0) || (height === 0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const img = new Image();
|
|
||||||
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
let rect = {
|
||||||
|
|
||||||
this._asyncRenderQPush({
|
|
||||||
'type': 'img',
|
'type': 'img',
|
||||||
'img': img,
|
'img': null,
|
||||||
'x': x,
|
'x': x,
|
||||||
'y': y,
|
'y': y,
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': height,
|
'height': height,
|
||||||
'frame_id': frame_id
|
'frame_id': frame_id
|
||||||
});
|
}
|
||||||
|
this._processRectScreens(rect);
|
||||||
|
|
||||||
|
if (rect.inPrimary) {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = "data: " + mime + ";base64," + Base64.encode(arr);
|
||||||
|
rect.img = img;
|
||||||
|
} else {
|
||||||
|
rect.type = 'img_array'
|
||||||
|
}
|
||||||
|
if (rect.inSecondary) {
|
||||||
|
rect.mime = mime;
|
||||||
|
rect.arr = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._asyncRenderQPush(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
transparentRect(x, y, width, height, img, frame_id) {
|
transparentRect(x, y, width, height, img, frame_id) {
|
||||||
|
@ -560,12 +603,18 @@ export default class Display {
|
||||||
'height': height,
|
'height': height,
|
||||||
'frame_id': frame_id
|
'frame_id': frame_id
|
||||||
}
|
}
|
||||||
|
this._processRectScreens(rect);
|
||||||
|
|
||||||
let imageBmpPromise = createImageBitmap(img);
|
if (rect.inPrimary) {
|
||||||
imageBmpPromise.then( function(img) {
|
let imageBmpPromise = createImageBitmap(img);
|
||||||
rect.img = img;
|
imageBmpPromise.then( function(img) {
|
||||||
rect.img.complete = true;
|
rect.img = img;
|
||||||
}.bind(rect) );
|
rect.img.complete = true;
|
||||||
|
}.bind(rect) );
|
||||||
|
}
|
||||||
|
if (rect.inSecondary) {
|
||||||
|
rect.arr = img;
|
||||||
|
}
|
||||||
|
|
||||||
this._asyncRenderQPush(rect);
|
this._asyncRenderQPush(rect);
|
||||||
}
|
}
|
||||||
|
@ -577,7 +626,7 @@ export default class Display {
|
||||||
// this probably isn't getting called *nearly* as much
|
// this probably isn't getting called *nearly* as much
|
||||||
const newArr = new Uint8Array(width * height * 4);
|
const newArr = new Uint8Array(width * height * 4);
|
||||||
newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
|
newArr.set(new Uint8Array(arr.buffer, 0, newArr.length));
|
||||||
this._asyncRenderQPush({
|
let rect = {
|
||||||
'type': 'blit',
|
'type': 'blit',
|
||||||
'data': newArr,
|
'data': newArr,
|
||||||
'x': x,
|
'x': x,
|
||||||
|
@ -585,7 +634,9 @@ export default class Display {
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': height,
|
'height': height,
|
||||||
'frame_id': frame_id
|
'frame_id': frame_id
|
||||||
});
|
}
|
||||||
|
this._processRectScreens(rect);
|
||||||
|
this._asyncRenderQPush(rect);
|
||||||
} else {
|
} else {
|
||||||
// NB(directxman12): arr must be an Type Array view
|
// NB(directxman12): arr must be an Type Array view
|
||||||
let data = new Uint8ClampedArray(arr.buffer,
|
let data = new Uint8ClampedArray(arr.buffer,
|
||||||
|
@ -598,7 +649,7 @@ export default class Display {
|
||||||
|
|
||||||
blitQoi(x, y, width, height, arr, offset, frame_id, fromQueue) {
|
blitQoi(x, y, width, height, arr, offset, frame_id, fromQueue) {
|
||||||
if (!fromQueue) {
|
if (!fromQueue) {
|
||||||
this._asyncRenderQPush({
|
let rect = {
|
||||||
'type': 'blitQ',
|
'type': 'blitQ',
|
||||||
'data': arr,
|
'data': arr,
|
||||||
'x': x,
|
'x': x,
|
||||||
|
@ -606,7 +657,9 @@ export default class Display {
|
||||||
'width': width,
|
'width': width,
|
||||||
'height': height,
|
'height': height,
|
||||||
'frame_id': frame_id
|
'frame_id': frame_id
|
||||||
});
|
}
|
||||||
|
this._processRectScreens(rect);
|
||||||
|
this._asyncRenderQPush(rect);
|
||||||
} else {
|
} else {
|
||||||
this._targetCtx.putImageData(arr, x, y);
|
this._targetCtx.putImageData(arr, x, y);
|
||||||
}
|
}
|
||||||
|
@ -647,6 +700,53 @@ export default class Display {
|
||||||
|
|
||||||
// ===== PRIVATE METHODS =====
|
// ===== PRIVATE METHODS =====
|
||||||
|
|
||||||
|
_handleSecondaryDisplayMessage(event) {
|
||||||
|
if (!this._isPrimaryDisplay && event.data) {
|
||||||
|
|
||||||
|
switch (event.data.eventType) {
|
||||||
|
case 'rect':
|
||||||
|
let rect = event.data.rect;
|
||||||
|
let pos = rect.screenLocations[event.data.screenLocationIndex];
|
||||||
|
if (!pos) {
|
||||||
|
console.log('wtf');
|
||||||
|
}
|
||||||
|
switch (rect.type) {
|
||||||
|
case 'copy':
|
||||||
|
this.copyImage(rect.oldX, rect.oldY, pos.x, pos.y, rect.width, rect.height, rect.frame_id, true);
|
||||||
|
break;
|
||||||
|
case 'fill':
|
||||||
|
this.fillRect(pos.x, pos.y, rect.width, rect.height, rect.color, rect.frame_id, true);
|
||||||
|
break;
|
||||||
|
case 'blit':
|
||||||
|
this.blitImage(pos.x, pos.y, rect.width, rect.height, rect.data, 0, rect.frame_id, true);
|
||||||
|
break;
|
||||||
|
case 'blitQ':
|
||||||
|
this.blitQoi(pos.x, pos.y, rect.width, rect.height, rect.data, 0, rect.frame_id, true);
|
||||||
|
break;
|
||||||
|
case 'img':
|
||||||
|
case 'img_arr':
|
||||||
|
rect.img = new Image();
|
||||||
|
rect.img.src = "data: " + rect.mime + ";base64," + Base64.encode(rect.arr);
|
||||||
|
if (!rect.img.complete) {
|
||||||
|
rect.img.addEventListener('load', function (rect) {
|
||||||
|
this.drawImage(rect.img, pos.x, pos.y, rect.width, rect.height);
|
||||||
|
}.bind(this, rect));
|
||||||
|
} else {
|
||||||
|
this.drawImage(rect.img, pos.x, pos.y, rect.width, rect.height);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'transparent':
|
||||||
|
let imageBmpPromise = createImageBitmap(rect.arr);
|
||||||
|
imageBmpPromise.then(function(rect, img) {
|
||||||
|
this.drawImage(img, pos.x, pos.y, rect.width, rect.height);
|
||||||
|
}).bind(this, rect);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Process incoming rects into a frame buffer, assume rects are out of order due to either UDP or parallel processing of decoding
|
Process incoming rects into a frame buffer, assume rects are out of order due to either UDP or parallel processing of decoding
|
||||||
*/
|
*/
|
||||||
|
@ -772,34 +872,53 @@ export default class Display {
|
||||||
for (let i = 0; i < frame.length; i++) {
|
for (let i = 0; i < frame.length; i++) {
|
||||||
|
|
||||||
const a = frame[i];
|
const a = frame[i];
|
||||||
switch (a.type) {
|
|
||||||
case 'copy':
|
for (let sI = 0; sI < a.screenLocations.length; sI++) {
|
||||||
this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, a.frame_id, true);
|
let screenLocation = a.screenLocations[sI];
|
||||||
break;
|
if (screenLocation.screenIndex == 0) {
|
||||||
case 'fill':
|
switch (a.type) {
|
||||||
this.fillRect(a.x, a.y, a.width, a.height, a.color, a.frame_id, true);
|
case 'copy':
|
||||||
break;
|
this.copyImage(screenLocation.oldX, screenLocation.oldY, screenLocation.x, screenLocation.y, a.width, a.height, a.frame_id, true);
|
||||||
case 'blit':
|
break;
|
||||||
this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, a.frame_id, true);
|
case 'fill':
|
||||||
break;
|
this.fillRect(screenLocation.x, screenLocation.y, a.width, a.height, a.color, a.frame_id, true);
|
||||||
case 'blitQ':
|
break;
|
||||||
this.blitQoi(a.x, a.y, a.width, a.height, a.data, 0, a.frame_id, true);
|
case 'blit':
|
||||||
break;
|
this.blitImage(screenLocation.x, screenLocation.y, a.width, a.height, a.data, 0, a.frame_id, true);
|
||||||
case 'img':
|
break;
|
||||||
this.drawImage(a.img, a.x, a.y, a.width, a.height);
|
case 'blitQ':
|
||||||
break;
|
this.blitQoi(screenLocation.x, screenLocation.y, a.width, a.height, a.data, 0, a.frame_id, true);
|
||||||
case 'transparent':
|
break;
|
||||||
transparent_rects.push(a);
|
case 'img':
|
||||||
break;
|
this.drawImage(a.img, screenLocation.x, screenLocation.y, a.width, a.height);
|
||||||
|
break;
|
||||||
|
case 'transparent':
|
||||||
|
transparent_rects.push(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (a.img) {
|
||||||
|
a.img = null;
|
||||||
|
}
|
||||||
|
this._screens[screenLocation.screenIndex].channel.postMessage({ eventType: 'rect', rect: a, screenLocationIndex: sI });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//rects with transparency get applied last
|
//rects with transparency get applied last
|
||||||
for (let i = 0; i < transparent_rects.length; i++) {
|
for (let i = 0; i < transparent_rects.length; i++) {
|
||||||
const a = transparent_rects[i];
|
const a = transparent_rects[i];
|
||||||
|
let screenIndexes = this._getRectScreenIndexes(a);
|
||||||
if (a.img) {
|
|
||||||
this.drawImage(a.img, a.x, a.y, a.width, a.height);
|
for (let sI = 0; sI < screenLocations.length; sI++) {
|
||||||
|
let screenLocation = a.screenLocations[sI];
|
||||||
|
if (sI == 0) {
|
||||||
|
if (a.img) {
|
||||||
|
this.drawImage(a.img, a.x, a.y, a.width, a.height);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._screens[screenLocation.screenIndex].channel.postMessage({ eventType: 'rect', rect: a, screenLocationIndex: sI });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,6 +942,41 @@ export default class Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_processRectScreens(rect) {
|
||||||
|
|
||||||
|
//find which screen this rect belongs to and adjust its x and y to be relative to the destination
|
||||||
|
let indexes = [];
|
||||||
|
rect.inPrimary = false;
|
||||||
|
rect.inSecondary = false;
|
||||||
|
for (let i=0; i < this._screens.length; i++) {
|
||||||
|
let screen = this._screens[i];
|
||||||
|
if (
|
||||||
|
((rect.x >= screen.x && rect.x < screen.x + screen.width) &&
|
||||||
|
(rect.y >= screen.y && rect.y < screen.y + screen.height)) ||
|
||||||
|
((rect.x+rect.width >= screen.x && rect.x+rect.width < screen.x + screen.width) &&
|
||||||
|
(rect.y+rect.height >= screen.y && rect.y+rect.height < screen.y + screen.height))
|
||||||
|
) {
|
||||||
|
let screenPosition = {
|
||||||
|
x: 0 - (screen.x - rect.x), //rect.x - screen.x,
|
||||||
|
y: 0 - (screen.y - rect.y), //rect.y - screen.y,
|
||||||
|
screenIndex: i
|
||||||
|
}
|
||||||
|
if (rect.type === 'copy') {
|
||||||
|
screenPosition.oldX = 0 - (screen.x - rect.oldX); //rect.oldX - screen.x;
|
||||||
|
screenPosition.oldY = 0 - (screen.y - rect.oldY); //rect.oldY - screen.y;
|
||||||
|
}
|
||||||
|
indexes.push(screenPosition);
|
||||||
|
if (i == 0) {
|
||||||
|
rect.inPrimary = true;
|
||||||
|
} else {
|
||||||
|
rect.inSecondary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.screenLocations = indexes;
|
||||||
|
}
|
||||||
|
|
||||||
_rescale(factor) {
|
_rescale(factor) {
|
||||||
this._scale = factor;
|
this._scale = factor;
|
||||||
const vp = this._screens[0];
|
const vp = this._screens[0];
|
||||||
|
|
|
@ -11,7 +11,6 @@ import KeyTable from "./keysym.js";
|
||||||
import keysyms from "./keysymdef.js";
|
import keysyms from "./keysymdef.js";
|
||||||
import imekeys from "./imekeys.js";
|
import imekeys from "./imekeys.js";
|
||||||
import * as browser from "../util/browser.js";
|
import * as browser from "../util/browser.js";
|
||||||
import UI from '../../app/ui.js';
|
|
||||||
import { isChromiumBased } from '../util/browser.js';
|
import { isChromiumBased } from '../util/browser.js';
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -46,6 +45,7 @@ export default class Keyboard {
|
||||||
this._lastKeyboardInput = null;
|
this._lastKeyboardInput = null;
|
||||||
this._defaultKeyboardInputLen = 100;
|
this._defaultKeyboardInputLen = 100;
|
||||||
this._keyboardInputReset();
|
this._keyboardInputReset();
|
||||||
|
this._translateShortcuts = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== PUBLIC METHODS =====
|
// ===== PUBLIC METHODS =====
|
||||||
|
@ -56,6 +56,9 @@ export default class Keyboard {
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get translateShortcuts() { return this._translateShortcuts; }
|
||||||
|
set translateShortcuts(value) { this._translateShortcuts = value; }
|
||||||
|
|
||||||
// ===== PRIVATE METHODS =====
|
// ===== PRIVATE METHODS =====
|
||||||
|
|
||||||
clearKeysDown(event) {
|
clearKeysDown(event) {
|
||||||
|
@ -319,7 +322,7 @@ export default class Keyboard {
|
||||||
// Translate MacOs CMD based shortcuts to their CTRL based counterpart
|
// Translate MacOs CMD based shortcuts to their CTRL based counterpart
|
||||||
if (
|
if (
|
||||||
browser.isMac() &&
|
browser.isMac() &&
|
||||||
UI.rfb && UI.rfb.translateShortcuts &&
|
this._translateShortcuts &&
|
||||||
code !== "MetaLeft" && code !== "MetaRight" &&
|
code !== "MetaLeft" && code !== "MetaRight" &&
|
||||||
e.metaKey && !e.ctrlKey && !e.altKey
|
e.metaKey && !e.ctrlKey && !e.altKey
|
||||||
) {
|
) {
|
||||||
|
|
94
core/rfb.js
94
core/rfb.js
|
@ -80,7 +80,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
if (!target) {
|
if (!target) {
|
||||||
throw new Error("Must specify target");
|
throw new Error("Must specify target");
|
||||||
}
|
}
|
||||||
if (!urlOrChannel) {
|
if (!urlOrChannel && isPrimaryDisplay) {
|
||||||
throw new Error("Must specify URL, WebSocket or RTCDataChannel");
|
throw new Error("Must specify URL, WebSocket or RTCDataChannel");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
this._supportsBroadcastChannel = (typeof BroadcastChannel !== "undefined");
|
this._supportsBroadcastChannel = (typeof BroadcastChannel !== "undefined");
|
||||||
if (this._supportsBroadcastChannel) {
|
if (this._supportsBroadcastChannel) {
|
||||||
this._controlChannel = new BroadcastChannel("registrationChannel");
|
this._controlChannel = new BroadcastChannel("registrationChannel");
|
||||||
this._controlChannel.message = this._handleControlMessage.bind(this);
|
this._controlChannel.addEventListener('message', this._handleControlMessage.bind(this));
|
||||||
Log.Debug("Attached to registrationChannel for secondary displays.")
|
Log.Debug("Attached to registrationChannel for secondary displays.")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ export default class RFB extends EventTargetMixin {
|
||||||
// NB: nothing that needs explicit teardown should be done
|
// NB: nothing that needs explicit teardown should be done
|
||||||
// before this point, since this can throw an exception
|
// before this point, since this can throw an exception
|
||||||
try {
|
try {
|
||||||
this._display = new Display(this._canvas);
|
this._display = new Display(this._canvas, this._isPrimaryDisplay);
|
||||||
} catch (exc) {
|
} catch (exc) {
|
||||||
Log.Error("Display exception: " + exc);
|
Log.Error("Display exception: " + exc);
|
||||||
throw exc;
|
throw exc;
|
||||||
|
@ -300,6 +300,10 @@ export default class RFB extends EventTargetMixin {
|
||||||
|
|
||||||
if (this._isPrimaryDisplay) {
|
if (this._isPrimaryDisplay) {
|
||||||
this._setupWebSocket();
|
this._setupWebSocket();
|
||||||
|
} else {
|
||||||
|
this._updateConnectionState('connecting');
|
||||||
|
this._registerSecondaryDisplay();
|
||||||
|
this._updateConnectionState('connected');
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Debug("<< RFB.constructor");
|
Log.Debug("<< RFB.constructor");
|
||||||
|
@ -327,6 +331,11 @@ export default class RFB extends EventTargetMixin {
|
||||||
|
|
||||||
// ===== PROPERTIES =====
|
// ===== PROPERTIES =====
|
||||||
|
|
||||||
|
get translateShortcuts() { return this._keyboard.translateShortcuts; }
|
||||||
|
set translateShortcuts(value) {
|
||||||
|
this._keyboard.translateShortcuts = value;
|
||||||
|
}
|
||||||
|
|
||||||
get pointerLock() { return this._pointerLock; }
|
get pointerLock() { return this._pointerLock; }
|
||||||
set pointerLock(value) {
|
set pointerLock(value) {
|
||||||
if (!this._pointerLock) {
|
if (!this._pointerLock) {
|
||||||
|
@ -1065,8 +1074,6 @@ export default class RFB extends EventTargetMixin {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._fail("Error attaching channel (" + e + ")");
|
this._fail("Error attaching channel (" + e + ")");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this._registerSecondaryDisplay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make our elements part of the page
|
// Make our elements part of the page
|
||||||
|
@ -1608,30 +1615,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
{ detail: { capabilities: this._capabilities } }));
|
{ detail: { capabilities: this._capabilities } }));
|
||||||
}
|
}
|
||||||
|
|
||||||
_registerSecondaryDisplay() {
|
|
||||||
this._primaryDisplayChannel = new BroadcastChannel(`screen_${this._screenID}_channel`);
|
|
||||||
this._primaryDisplayChannel.message = this._handleSecondaryDisplayMessage.bind(this);
|
|
||||||
const size = this._screenSize();
|
|
||||||
|
|
||||||
message = {
|
|
||||||
eventType: 'register',
|
|
||||||
screenID: this._screenID,
|
|
||||||
screenIndex: this._screenIndex,
|
|
||||||
width: size.w,
|
|
||||||
height: size.h,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
relativePosition: 0,
|
|
||||||
pixelRatio: window.devicePixelRatio,
|
|
||||||
containerWidth: this._screen.offsetWidth,
|
|
||||||
containerHeight: this._screen.offsetWidth,
|
|
||||||
channel: null
|
|
||||||
}
|
|
||||||
this._controlChannel.postMessage(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
_proxyRFBMessage(messageType, data) {
|
_proxyRFBMessage(messageType, data) {
|
||||||
message = {
|
let message = {
|
||||||
messageType: messageType,
|
messageType: messageType,
|
||||||
data: data
|
data: data
|
||||||
}
|
}
|
||||||
|
@ -1641,19 +1626,50 @@ export default class RFB extends EventTargetMixin {
|
||||||
_handleControlMessage(event) {
|
_handleControlMessage(event) {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
|
|
||||||
switch (event.eventType) {
|
if (this._isPrimaryDisplay) {
|
||||||
case 'register':
|
switch (event.data.eventType) {
|
||||||
this._display.addScreen(event.screenID, event.width, event.height, event.relativePosition, event.pixelRatio, event.containerHeight, event.containerWidth);
|
case 'register':
|
||||||
Log.Info(`Secondary monitor (${event.screenID}) has been registered.`);
|
this._display.addScreen(event.data.screenID, event.data.width, event.data.height, event.data.relativePosition, event.data.pixelRatio, event.data.containerHeight, event.data.containerWidth);
|
||||||
break;
|
const size = this._screenSize();
|
||||||
case 'unregister':
|
RFB.messages.setDesktopSize(this._sock, size, this._screenFlags);
|
||||||
if (this._display.removeScreen(event.screenID)) {
|
Log.Info(`Secondary monitor (${event.data.screenID}) has been registered.`);
|
||||||
Log.Info(`Secondary monitor (${event.screenID}) has been removed.`);
|
break;
|
||||||
} else {
|
case 'unregister':
|
||||||
Log.Info(`Secondary monitor (${event.screenID}) not found.`);
|
if (this._display.removeScreen(event.data.screenID)) {
|
||||||
}
|
Log.Info(`Secondary monitor (${event.data.screenID}) has been removed.`);
|
||||||
|
const size = this._screenSize();
|
||||||
|
RFB.messages.setDesktopSize(this._sock, size, this._screenFlags);
|
||||||
|
} else {
|
||||||
|
Log.Info(`Secondary monitor (${event.data.screenID}) not found.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_registerSecondaryDisplay() {
|
||||||
|
if (!this._isPrimaryDisplay) {
|
||||||
|
let screen = this._screenSize().screens[0];
|
||||||
|
this._display.resize(screen.containerWidth, screen.containerWidth);
|
||||||
|
screen = this._screenSize().screens[0];
|
||||||
|
|
||||||
|
|
||||||
|
let message = {
|
||||||
|
eventType: 'register',
|
||||||
|
screenID: screen.screenID,
|
||||||
|
screenIndex: 1,
|
||||||
|
width: screen.width,
|
||||||
|
height: screen.height,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
relativePosition: 0,
|
||||||
|
pixelRatio: screen.pixelRatio,
|
||||||
|
containerWidth: screen.containerWidth,
|
||||||
|
containerHeight: screen.containerHeight,
|
||||||
|
channel: null
|
||||||
|
}
|
||||||
|
this._controlChannel.postMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue