From b67d029c4e1d7b9328a38f2e630fc247e9d097ab Mon Sep 17 00:00:00 2001 From: Raymond Zhao Date: Wed, 12 May 2021 11:42:22 -0700 Subject: [PATCH 1/4] fix: adjust initial webContents focus calculation --- lib/browser/api/browser-window.ts | 14 --------- .../browser/api/electron_api_web_contents.cc | 31 ++++++++++++++----- shell/browser/api/electron_api_web_contents.h | 5 ++- typings/internal-electron.d.ts | 1 - 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/lib/browser/api/browser-window.ts b/lib/browser/api/browser-window.ts index d01be9c795f0f..62630bfffb2f5 100644 --- a/lib/browser/api/browser-window.ts +++ b/lib/browser/api/browser-window.ts @@ -20,20 +20,6 @@ BrowserWindow.prototype._init = function (this: BWT) { nativeSetBounds.call(this, bounds, ...opts); }; - // Sometimes the webContents doesn't get focus when window is shown, so we - // have to force focusing on webContents in this case. The safest way is to - // focus it when we first start to load URL, if we do it earlier it won't - // have effect, if we do it later we might move focus in the page. - // - // Though this hack is only needed on macOS when the app is launched from - // Finder, we still do it on all platforms in case of other bugs we don't - // know. - if (this.webContents._initiallyShown) { - this.webContents.once('load-url' as any, function (this: WebContents) { - this.focus(); - }); - } - // Redirect focus/blur event to app instance too. this.on('blur', (event: Event) => { app.emit('browser-window-blur', event, this); diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 64cd68e0784de..ac5039f86ded0 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -701,8 +701,8 @@ WebContents::WebContents(v8::Isolate* isolate, // BrowserViews are not attached to a window initially so they should start // off as hidden. This is also important for compositor recycling. See: // https://github.com/electron/electron/pull/21372 - initially_shown_ = type_ != Type::kBrowserView; - options.Get(options::kShow, &initially_shown_); + bool initially_shown = type_ != Type::kBrowserView; + options.Get(options::kShow, &initially_shown); // Obtain the session. std::string partition; @@ -758,7 +758,7 @@ WebContents::WebContents(v8::Isolate* isolate, #endif } else { content::WebContents::CreateParams params(session->browser_context()); - params.initially_hidden = !initially_shown_; + params.initially_hidden = !initially_shown; web_contents = content::WebContents::Create(params); } @@ -1650,6 +1650,26 @@ void WebContents::DidRedirectNavigation( EmitNavigationEvent("did-redirect-navigation", navigation_handle); } +void WebContents::ReadyToCommitNavigation( + content::NavigationHandle* navigation_handle) { + // Don't focus content in an inactive window. + if (!owner_window()) + return; + if (!owner_window()->widget()->IsActive()) + return; + // Don't focus content after subframe navigations. + if (!navigation_handle->IsInMainFrame()) + return; + // Only focus for top-level contents. + if (type_ != Type::kBrowserWindow) + return; + // Only set the initial focus when navigating away from the + // blank page. + if (web_contents()->GetLastCommittedURL() != "about:blank") + return; + web_contents()->SetInitialFocus(); +} + void WebContents::DidFinishNavigation( content::NavigationHandle* navigation_handle) { if (!navigation_handle->HasCommitted()) @@ -3110,10 +3130,6 @@ v8::Local WebContents::Debugger(v8::Isolate* isolate) { return v8::Local::New(isolate, debugger_); } -bool WebContents::WasInitiallyShown() { - return initially_shown_; -} - content::RenderFrameHost* WebContents::MainFrame() { return web_contents()->GetMainFrame(); } @@ -3683,7 +3699,6 @@ v8::Local WebContents::FillObjectTemplate( .SetProperty("hostWebContents", &WebContents::HostWebContents) .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents) .SetProperty("debugger", &WebContents::Debugger) - .SetProperty("_initiallyShown", &WebContents::WasInitiallyShown) .SetProperty("mainFrame", &WebContents::MainFrame) .Build(); } diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index 10b3915ddb6ad..2b9fe3b662f15 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -324,7 +324,6 @@ class WebContents : public gin::Wrappable, content::WebContents* HostWebContents() const; v8::Local DevToolsWebContents(v8::Isolate* isolate); v8::Local Debugger(v8::Isolate* isolate); - bool WasInitiallyShown(); content::RenderFrameHost* MainFrame(); WebContentsZoomController* GetZoomController() { return zoom_controller_; } @@ -559,6 +558,8 @@ class WebContents : public gin::Wrappable, content::NavigationHandle* navigation_handle) override; void DidRedirectNavigation( content::NavigationHandle* navigation_handle) override; + void ReadyToCommitNavigation( + content::NavigationHandle* navigation_handle) override; void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; bool OnMessageReceived(const IPC::Message& message) override; @@ -722,8 +723,6 @@ class WebContents : public gin::Wrappable, v8::Global pending_child_web_preferences_; - bool initially_shown_ = true; - // The window that this WebContents belongs to. base::WeakPtr owner_window_; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 5cc680b7a4ad1..bf7f79127206f 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -67,7 +67,6 @@ declare namespace Electron { getLastWebPreferences(): Electron.WebPreferences; _getPreloadPaths(): string[]; equal(other: WebContents): boolean; - _initiallyShown: boolean; browserWindowOptions: BrowserWindowConstructorOptions; _windowOpenHandler: ((details: Electron.HandlerDetails) => any) | null; _callWindowOpenHandler(event: any, details: Electron.HandlerDetails): Electron.BrowserWindowConstructorOptions | null; From 5c9a587da0883f65781bf7d7935a5cddfc038b3f Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 18 May 2021 07:47:28 -0700 Subject: [PATCH 2/4] fix: active window check on mac --- shell/browser/api/electron_api_browser_window.cc | 1 + shell/browser/api/electron_api_web_contents.cc | 9 +++++---- shell/browser/native_window.h | 4 ++++ shell/browser/native_window_mac.h | 3 +++ shell/browser/native_window_mac.mm | 10 ++++++++++ spec-main/chromium-spec.ts | 1 - 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/shell/browser/api/electron_api_browser_window.cc b/shell/browser/api/electron_api_browser_window.cc index 11438528160fc..c19544ec44b92 100644 --- a/shell/browser/api/electron_api_browser_window.cc +++ b/shell/browser/api/electron_api_browser_window.cc @@ -289,6 +289,7 @@ void BrowserWindow::OnWindowIsKeyChanged(bool is_key) { auto* rwhv = web_contents()->GetRenderWidgetHostView(); if (rwhv) rwhv->SetActive(is_key); + window()->SetActive(is_key); #endif } diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index ac5039f86ded0..f18930f0e993a 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -1655,18 +1655,19 @@ void WebContents::ReadyToCommitNavigation( // Don't focus content in an inactive window. if (!owner_window()) return; +#if defined(OS_MAC) + if (!owner_window()->IsActive()) + return; +#else if (!owner_window()->widget()->IsActive()) return; +#endif // Don't focus content after subframe navigations. if (!navigation_handle->IsInMainFrame()) return; // Only focus for top-level contents. if (type_ != Type::kBrowserWindow) return; - // Only set the initial focus when navigating away from the - // blank page. - if (web_contents()->GetLastCommittedURL() != "about:blank") - return; web_contents()->SetInitialFocus(); } diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index fd0c0675db906..c1bb7ba28a3fc 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -135,6 +135,10 @@ class NativeWindow : public base::SupportsUserData, virtual void Invalidate() = 0; virtual void SetTitle(const std::string& title) = 0; virtual std::string GetTitle() = 0; +#if defined(OS_MAC) + virtual void SetActive(bool is_key) = 0; + virtual bool IsActive() const = 0; +#endif // Ability to augment the window title for the screen readers. void SetAccessibleTitle(const std::string& title); diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index 65fe746a58e16..c02d923084baa 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -149,6 +149,8 @@ class NativeWindowMac : public NativeWindow, gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override; void NotifyWindowEnterFullScreen() override; void NotifyWindowLeaveFullScreen() override; + void SetActive(bool is_key) override; + bool IsActive() const override; void NotifyWindowWillEnterFullScreen(); void NotifyWindowWillLeaveFullScreen(); @@ -267,6 +269,7 @@ class NativeWindowMac : public NativeWindow, bool is_simple_fullscreen_ = false; bool was_maximizable_ = false; bool was_movable_ = false; + bool is_active_ = false; NSRect original_frame_; NSInteger original_level_; NSUInteger simple_fullscreen_mask_; diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index f6867beb87976..247ae20ab100e 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -1640,6 +1640,16 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { UpdateVibrancyRadii(false); } +void NativeWindowMac::SetActive(bool is_key) { + if (is_key) + widget()->Activate(); + is_active_ = is_key; +} + +bool NativeWindowMac::IsActive() const { + return is_active_; +} + void NativeWindowMac::Cleanup() { DCHECK(!IsClosed()); ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this); diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index 40d9de0739fc0..dbb72ef59a217 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -1617,7 +1617,6 @@ describe('navigator.clipboard', () => { let w: BrowserWindow; before(async () => { w = new BrowserWindow({ - show: false, webPreferences: { enableBlinkFeatures: 'Serial' } From 2fe95f752deff2dd3ee4bad646eff81d2a4c7842 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 18 May 2021 22:45:03 -0700 Subject: [PATCH 3/4] fix: about:blank focus behavior --- spec-main/api-web-contents-spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index d9042fffb8d2c..31cb8769d5021 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -419,7 +419,7 @@ describe('webContents module', () => { const testFn = (process.platform === 'win32' && process.arch === 'arm64' ? it.skip : it); testFn('returns the focused web contents', async () => { const w = new BrowserWindow({ show: true }); - await w.loadURL('about:blank'); + await w.loadFile(path.join(__dirname, 'fixtures', 'blank.html')); expect(webContents.getFocusedWebContents().id).to.equal(w.webContents.id); const devToolsOpened = emittedOnce(w.webContents, 'devtools-opened'); From c7225f239367eda0dc42786b37e4f04038253523 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 18 May 2021 22:45:23 -0700 Subject: [PATCH 4/4] chore: add spec --- spec-main/chromium-spec.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index dbb72ef59a217..5b6bf61373e74 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -1433,6 +1433,31 @@ describe('chromium features', () => { expect(pageExists).to.be.true(); }); }); + + describe('document.hasFocus', () => { + it('has correct value when multiple windows are opened', async () => { + const w1 = new BrowserWindow({ show: true }); + const w2 = new BrowserWindow({ show: true }); + const w3 = new BrowserWindow({ show: false }); + await w1.loadFile(path.join(__dirname, 'fixtures', 'blank.html')); + await w2.loadFile(path.join(__dirname, 'fixtures', 'blank.html')); + await w3.loadFile(path.join(__dirname, 'fixtures', 'blank.html')); + expect(webContents.getFocusedWebContents().id).to.equal(w2.webContents.id); + let focus = false; + focus = await w1.webContents.executeJavaScript( + 'document.hasFocus()' + ); + expect(focus).to.be.false(); + focus = await w2.webContents.executeJavaScript( + 'document.hasFocus()' + ); + expect(focus).to.be.true(); + focus = await w3.webContents.executeJavaScript( + 'document.hasFocus()' + ); + expect(focus).to.be.false(); + }); + }); }); describe('font fallback', () => {