diff --git a/src/core/main.js b/src/core/main.js index 743cc473b8..31126e659b 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -126,11 +126,11 @@ class p5 { }; if (typeof window !== 'undefined') { - window.addEventListener('focus', focusHandler); - window.addEventListener('blur', blurHandler); - p5.lifecycleHooks.remove.push(function () { - window.removeEventListener('focus', focusHandler); - window.removeEventListener('blur', blurHandler); + window.addEventListener('focus', focusHandler, { + signal: this._removeSignal + }); + window.addEventListener('blur', blurHandler, { + signal: this._removeSignal }); // Initialization complete, start runtime diff --git a/test/unit/core/environment.js b/test/unit/core/environment.js index 9438e5c9e3..cd08da0a7e 100644 --- a/test/unit/core/environment.js +++ b/test/unit/core/environment.js @@ -81,6 +81,78 @@ suite('Environment', function () { }); }); + suite('p5.prototype.focused with multiple instances', function () { + test('removing one instance should not remove another instance focus listeners', async function () { + let instance1; + let instance2; + + await Promise.all([ + new Promise(function (resolve) { + new p5(function (p) { + p.setup = function () { + instance1 = p; + resolve(); + }; + }); + }), + new Promise(function (resolve) { + new p5(function (p) { + p.setup = function () { + instance2 = p; + resolve(); + }; + }); + }) + ]); + + window.dispatchEvent(new Event('blur')); + assert.strictEqual(instance2.focused, false); + + await instance1.remove(); + + window.dispatchEvent(new Event('focus')); + assert.strictEqual(instance2.focused, true); + + await instance2.remove(); + }); + }); + + suite('p5.lifecycleHooks.remove cleanup', function () { + test('remove hooks should not accumulate after instances are removed', async function () { + const before = p5.lifecycleHooks.remove.length; + + let instance1; + let instance2; + + await Promise.all([ + new Promise(function (resolve) { + new p5(function (p) { + p.setup = function () { + instance1 = p; + resolve(); + }; + }); + }), + new Promise(function (resolve) { + new p5(function (p) { + p.setup = function () { + instance2 = p; + resolve(); + }; + }); + }) + ]); + + await instance1.remove(); + await instance2.remove(); + + assert.strictEqual( + p5.lifecycleHooks.remove.length, + before + ); + }); + }); + suite('p5.prototype.cursor', function () { test('should change cursor to cross', function () { myp5.cursor(myp5.CROSS);