From fc7083cd84df3a09c748527bbecc61703aa514d8 Mon Sep 17 00:00:00 2001 From: Darshan Sen Date: Tue, 12 Apr 2022 16:19:55 +0530 Subject: [PATCH] fix: make BrowserWindow#isFocused() return false when blur() is called on macOS The isFocused() method on macOS works by checking if the selected BrowserWindow is a key window. Unfortunately doesn't work well with focus() and blur() because these weren't calling any macOS APIs that would change the key status of the window. Hence, this changes the implementation of blur() to call orderOut first, which removes the key status of the window. Then when the orderBack function is called, it moves the window to the back of its level in the screen list, without changing the key window. Fixes: https://github.com/electron/electron/issues/33732 Signed-off-by: Darshan Sen --- shell/browser/native_window_mac.mm | 1 + spec-main/api-browser-window-spec.ts | 116 ++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index 7ed794206322e..ad67b1259c5ad 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -506,6 +506,7 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { [[NSApplication sharedApplication] activateIgnoringOtherApps:NO]; [window_ makeKeyAndOrderFront:nil]; } else { + [window_ orderOut:nil]; [window_ orderBack:nil]; } } diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts index d783cde6b8883..30b58e8f21122 100644 --- a/spec-main/api-browser-window-spec.ts +++ b/spec-main/api-browser-window-spec.ts @@ -760,13 +760,125 @@ describe('BrowserWindow module', () => { w.focus(); expect(w.isVisible()).to.equal(false); }); + + ifit(process.platform !== 'win32')('focuses a blurred window', async () => { + { + const blur = emittedOnce(w, 'blur'); + const show = emittedOnce(w, 'show'); + w.show(); + w.blur(); + await show; + await blur; + } + expect(w.isFocused()).to.equal(false); + w.focus(); + expect(w.isFocused()).to.equal(true); + }); + + it('aquires focus status from the other windows', async () => { + let w1 = new BrowserWindow({ show: false }); + let w2 = new BrowserWindow({ show: false }); + let w3 = new BrowserWindow({ show: false }); + { + const focus = emittedOnce(w3, 'focus'); + const show1 = emittedOnce(w1, 'show'); + const show2 = emittedOnce(w2, 'show'); + const show3 = emittedOnce(w3, 'show'); + w1.show(); + w2.show(); + w3.show(); + await show1; + await show2; + await show3; + await focus; + } + expect(w1.isFocused()).to.equal(false); + expect(w2.isFocused()).to.equal(false); + expect(w3.isFocused()).to.equal(true); + + w1.focus(); + expect(w1.isFocused()).to.equal(true); + expect(w2.isFocused()).to.equal(false); + expect(w3.isFocused()).to.equal(false); + + w2.focus(); + expect(w1.isFocused()).to.equal(false); + expect(w2.isFocused()).to.equal(true); + expect(w3.isFocused()).to.equal(false); + + w3.focus(); + expect(w1.isFocused()).to.equal(false); + expect(w2.isFocused()).to.equal(false); + expect(w3.isFocused()).to.equal(true); + + await closeWindow(w1); + w1 = null as unknown as BrowserWindow; + await closeWindow(w2); + w2 = null as unknown as BrowserWindow; + await closeWindow(w3); + w3 = null as unknown as BrowserWindow; + }); }); - describe('BrowserWindow.blur()', () => { - it('removes focus from window', () => { + // TODO(RaisinTen): Make this work on Windows too. + // Refs: https://github.com/electron/electron/issues/20464. + ifdescribe(process.platform !== 'win32')('BrowserWindow.blur()', () => { + it('removes focus from window', async () => { + { + const focus = emittedOnce(w, 'focus'); + const show = emittedOnce(w, 'show'); + w.show(); + await show; + await focus; + } + expect(w.isFocused()).to.equal(true); w.blur(); expect(w.isFocused()).to.equal(false); }); + + it('transfers focus status to the next window', async () => { + let w1 = new BrowserWindow({ show: false }); + let w2 = new BrowserWindow({ show: false }); + let w3 = new BrowserWindow({ show: false }); + { + const focus = emittedOnce(w3, 'focus'); + const show1 = emittedOnce(w1, 'show'); + const show2 = emittedOnce(w2, 'show'); + const show3 = emittedOnce(w3, 'show'); + w1.show(); + w2.show(); + w3.show(); + await show1; + await show2; + await show3; + await focus; + } + expect(w1.isFocused()).to.equal(false); + expect(w2.isFocused()).to.equal(false); + expect(w3.isFocused()).to.equal(true); + + w3.blur(); + expect(w1.isFocused()).to.equal(false); + expect(w2.isFocused()).to.equal(true); + expect(w3.isFocused()).to.equal(false); + + w2.blur(); + expect(w1.isFocused()).to.equal(true); + expect(w2.isFocused()).to.equal(false); + expect(w3.isFocused()).to.equal(false); + + w1.blur(); + expect(w1.isFocused()).to.equal(false); + expect(w2.isFocused()).to.equal(false); + expect(w3.isFocused()).to.equal(true); + + await closeWindow(w1); + w1 = null as unknown as BrowserWindow; + await closeWindow(w2); + w2 = null as unknown as BrowserWindow; + await closeWindow(w3); + w3 = null as unknown as BrowserWindow; + }); }); describe('BrowserWindow.getFocusedWindow()', () => {