diff --git a/app/ui.js b/app/ui.js index 2542e0591..62c80ff7d 100644 --- a/app/ui.js +++ b/app/ui.js @@ -189,6 +189,7 @@ const UI = { UI.initSetting('repeaterID', ''); UI.initSetting('reconnect', false); UI.initSetting('reconnect_delay', 5000); + UI.initSetting('incfbureq_delay', 0); }, // Adds a link to the label elements on the corresponding input elements setupSettingLabels() { @@ -379,6 +380,8 @@ const UI = { UI.addSettingChangeHandler('logging', UI.updateLogging); UI.addSettingChangeHandler('reconnect'); UI.addSettingChangeHandler('reconnect_delay'); + UI.addSettingChangeHandler('incfbureq_delay'); + UI.addSettingChangeHandler('incfbureq_delay', UI.updateIncrementalFBUpdateReqDelay); }, addFullscreenHandlers() { @@ -892,6 +895,7 @@ const UI = { UI.updateSetting('logging'); UI.updateSetting('reconnect'); UI.updateSetting('reconnect_delay'); + UI.updateSetting('incfbureq_delay'); document.getElementById('noVNC_settings') .classList.add("noVNC_open"); @@ -1100,6 +1104,7 @@ const UI = { UI.rfb.resizeSession = UI.getSetting('resize') === 'remote'; UI.rfb.qualityLevel = parseInt(UI.getSetting('quality')); UI.rfb.compressionLevel = parseInt(UI.getSetting('compression')); + UI.rfb.incfbureqDelay = parseInt(UI.getSetting('incfbureq_delay')); UI.rfb.showDotCursor = UI.getSetting('show_dot'); UI.updateViewOnly(); // requires UI.rfb @@ -1763,6 +1768,10 @@ const UI = { WebUtil.initLogging(UI.getSetting('logging')); }, + updateIncrementalFBUpdateReqDelay() { + UI.connected && (UI.rfb.incfbureqDelay = parseInt(UI.getSetting('incfbureq_delay'))); + }, + updateDesktopName(e) { UI.desktopName = e.detail.name; // Display the desktop name in the document title diff --git a/core/rfb.js b/core/rfb.js index 80011e4a1..7ce9f1949 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -173,6 +173,10 @@ export default class RFB extends EventTargetMixin { this._resizeTimeout = null; // resize rate limiting this._mouseMoveTimer = null; + this._incfbureqDelay = 0; // delay incremental FBU requests, + this._incfbureqTimer = false; // disabled until first FBU + this._incfbureq = null; + // Decoder states this._decoders = {}; @@ -413,6 +417,18 @@ export default class RFB extends EventTargetMixin { } } + get incfbureqDelay() { + return this._incfbureqDelay; + } + set incfbureqDelay(delay) { + if (delay < this._incfbureqDelay && this._incfbureq ) { + clearTimeout(this._incfbureqTimer); + typeof this._incfbureq === 'function' && (this._incfbureq()); + } + this._incfbureq = null; + this._incfbureqDelay = delay; + } + // ===== PUBLIC METHODS ===== disconnect() { @@ -2570,7 +2586,8 @@ export default class RFB extends EventTargetMixin { ret = this._framebufferUpdate(); if (ret && !this._enabledContinuousUpdates) { RFB.messages.fbUpdateRequest(this._sock, true, 0, 0, - this._fbWidth, this._fbHeight); + this._fbWidth, this._fbHeight, + { rfb: this, delay: this._incfbureqDelay }); } return ret; @@ -2980,6 +2997,9 @@ export default class RFB extends EventTargetMixin { this._FBU.encoding + ")"); return false; } + if (this._incfbureqTimer === false) { + this._incfbureqTimer = null; + } try { return decoder.decodeRect(this._FBU.x, this._FBU.y, @@ -3362,7 +3382,25 @@ RFB.messages = { sock.flush(); }, - fbUpdateRequest(sock, incremental, x, y, w, h) { + fbUpdateRequest(sock, incremental, x, y, w, h, { rfb, delay } = {}) { + if (incremental && delay !== 0 && rfb?._incfbureqTimer !== false ) { + if (delay !== undefined) { + if (rfb._incfbureqTimer === null) { + // save bound function for calling in incfbureqDelay setter + // if value is changed while request is delayed + rfb._incfbureq = RFB.messages.fbUpdateRequest.bind( + null, + sock, incremental, x, y, w, h, + { rfb, delay: undefined } + ); + rfb._incfbureqTimer = setTimeout(rfb._incfbureq, delay); + } + return; + } else { + rfb._incfbureq = null; + rfb._incfbureqTimer = null; + } + } if (typeof(x) === "undefined") { x = 0; } if (typeof(y) === "undefined") { y = 0; } diff --git a/vnc.html b/vnc.html index 82cacd580..c20fac1fc 100644 --- a/vnc.html +++ b/vnc.html @@ -288,6 +288,10 @@

no
VNC

+
  • + + +