From a9c2ff30b636cf5bb0c5f183302646a5b6ec8481 Mon Sep 17 00:00:00 2001 From: Benjamin Leeds Date: Fri, 7 Feb 2020 09:59:58 -0500 Subject: [PATCH 1/3] Replace window.onresize with ResizeObserver Fixes an issue where if the screen div resizes for a reason other than window resize, the canvas wouldn't redraw. --- core/rfb.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/rfb.js b/core/rfb.js index 228aeca4..ea3bf58a 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -134,6 +134,7 @@ export default class RFB extends EventTargetMixin { this._flushing = false; // Display flushing state this._keyboard = null; // Keyboard input handler object this._gestures = null; // Gesture input handler object + this._resizeObserver = null; // Resize observer object // Timers this._disconnTimer = null; // disconnection timer @@ -171,7 +172,7 @@ export default class RFB extends EventTargetMixin { // Bound event handlers this._eventHandlers = { focusCanvas: this._focusCanvas.bind(this), - windowResize: this._windowResize.bind(this), + handleResize: this._handleResize.bind(this), handleMouse: this._handleMouse.bind(this), handleWheel: this._handleWheel.bind(this), handleGesture: this._handleGesture.bind(this), @@ -239,6 +240,8 @@ export default class RFB extends EventTargetMixin { this._sock.on('message', this._handleMessage.bind(this)); this._sock.on('error', this._socketError.bind(this)); + this._resizeObserver = new ResizeObserver(this._eventHandlers.handleResize); + // All prepared, kick off the connection this._updateConnectionState('connecting'); @@ -488,9 +491,8 @@ export default class RFB extends EventTargetMixin { this._cursor.attach(this._canvas); this._refreshCursor(); - // Monitor size changes of the screen - // FIXME: Use ResizeObserver, or hidden overflow - window.addEventListener('resize', this._eventHandlers.windowResize); + // Monitor size changes of the screen element + this._resizeObserver.observe(this._screen); // Always grab focus on some kind of click event this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas); @@ -531,7 +533,7 @@ export default class RFB extends EventTargetMixin { 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._resizeObserver.disconnect(); this._keyboard.ungrab(); this._gestures.detach(); this._sock.close(); @@ -617,7 +619,7 @@ export default class RFB extends EventTargetMixin { { detail: { name: this._fbName } })); } - _windowResize(event) { + _handleResize() { // If the window resized then our screen element might have // as well. Update the viewport dimensions. window.requestAnimationFrame(() => { From 375f36c57544dd89c042a6beceff93a2430f2358 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Fri, 3 Sep 2021 16:51:36 +0200 Subject: [PATCH 2/3] Modify unit tests to work with ResizeObserver --- tests/test.rfb.js | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/tests/test.rfb.js b/tests/test.rfb.js index 404f7db1..5f505818 100644 --- a/tests/test.rfb.js +++ b/tests/test.rfb.js @@ -71,6 +71,18 @@ function deflateWithSize(data) { describe('Remote Frame Buffer Protocol Client', function () { let clock; let raf; + let fakeResizeObserver = null; + const realObserver = window.ResizeObserver; + + class FakeResizeObserver { + constructor(handler) { + this.fire = handler; + fakeResizeObserver = this; + } + disconnect() {} + observe(target, options) {} + unobserve(target) {} + } before(FakeWebSocket.replace); after(FakeWebSocket.restore); @@ -80,6 +92,9 @@ describe('Remote Frame Buffer Protocol Client', function () { // sinon doesn't support this yet raf = window.requestAnimationFrame; window.requestAnimationFrame = setTimeout; + // We must do this in a 'before' since it needs to be set before + // the RFB constructor, which runs in beforeEach further down + window.ResizeObserver = FakeResizeObserver; // Use a single set of buffers instead of reallocating to // speed up tests const sock = new Websock(); @@ -100,6 +115,7 @@ describe('Remote Frame Buffer Protocol Client', function () { delete Websock.prototype.toString; this.clock.restore(); window.requestAnimationFrame = raf; + window.ResizeObserver = realObserver; }); let container; @@ -470,6 +486,7 @@ describe('Remote Frame Buffer Protocol Client', function () { describe('Clipping', function () { let client; + beforeEach(function () { client = makeRFB(); container.style.width = '70px'; @@ -495,8 +512,7 @@ describe('Remote Frame Buffer Protocol Client', function () { container.style.width = '40px'; container.style.height = '50px'; - const event = new UIEvent('resize'); - window.dispatchEvent(event); + fakeResizeObserver.fire(); clock.tick(); expect(client._display.viewportChangeSize).to.have.been.calledOnce; @@ -692,8 +708,7 @@ describe('Remote Frame Buffer Protocol Client', function () { container.style.width = '40px'; container.style.height = '50px'; - const event = new UIEvent('resize'); - window.dispatchEvent(event); + fakeResizeObserver.fire(); clock.tick(); expect(client._display.autoscale).to.have.been.calledOnce; @@ -782,8 +797,7 @@ describe('Remote Frame Buffer Protocol Client', function () { 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); + fakeResizeObserver.fire(); clock.tick(1000); expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; @@ -793,16 +807,14 @@ describe('Remote Frame Buffer Protocol Client', function () { 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); + fakeResizeObserver.fire(); 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); + fakeResizeObserver.fire(); clock.tick(400); expect(RFB.messages.setDesktopSize).to.not.have.been.called; From 1afa18f09ee407fb8856ba28a3fc8f59021f7b23 Mon Sep 17 00:00:00 2001 From: Samuel Mannehed Date: Wed, 14 Apr 2021 10:57:11 +0200 Subject: [PATCH 3/3] Increase browser version requirements Now that we use ResizeObserver we know that we require more modern browsers. The most notable ones here are Firefox and Safari. With regards to Firefox, while the desktop version has had support since 69, the Android app requires 79. At the time of writing the current ESR of Firefox is 78, but the concept of ESR doesn't seem to exist for Android. The Safari 13 requirement means we no longer support for example iPhone 5S or the 4th generation of the iPad. These are devices from 2013~2014. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bcb52ac..3f8abf85 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ 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 11, Opera 36, Edge 79 +* Chrome 64, Firefox 79, Safari 13.4, Opera 51, Edge 79 ### Server Requirements