From a7af6057213a275b0141d76a25f53db5cc8bf507 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 2 Sep 2020 17:02:26 +0900 Subject: [PATCH 1/2] fix: mulitple dock icons when calling dock.show/hide --- shell/browser/browser.h | 1 + shell/browser/browser_mac.mm | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/shell/browser/browser.h b/shell/browser/browser.h index cf4bbfd373835..a8490049eaa63 100644 --- a/shell/browser/browser.h +++ b/shell/browser/browser.h @@ -355,6 +355,7 @@ class Browser : public WindowListObserver { #if defined(OS_MAC) std::unique_ptr password_input_enabler_; + base::Time last_dock_show_; #endif #if defined(OS_LINUX) || defined(OS_WIN) diff --git a/shell/browser/browser_mac.mm b/shell/browser/browser_mac.mm index 346fd0e659d9a..fd34c034fb974 100644 --- a/shell/browser/browser_mac.mm +++ b/shell/browser/browser_mac.mm @@ -383,6 +383,20 @@ void RemoveFromLoginItems() { } void Browser::DockHide() { + // Transforming application state from UIElement to Foreground is an + // asyncronous operation, and unfortunately there is currently no way to know + // when it is finished. + // So if we call DockHide => DockShow => DockHide => DockShow in a very short + // time, we would triger a bug of macOS that, there would be multiple dock + // icons of the app left in system. + // To work around this, we make sure DockHide does nothing if it is called + // immediately after DockShow. After some experiments, 1 second seems to be + // a proper interval. + if (!last_dock_show_.is_null() && + base::Time::Now() - last_dock_show_ < base::TimeDelta::FromSeconds(1)) { + return; + } + for (auto* const& window : WindowList::GetWindows()) [window->GetNativeWindow().GetNativeNSWindow() setCanHide:NO]; @@ -398,6 +412,7 @@ void RemoveFromLoginItems() { } v8::Local Browser::DockShow(v8::Isolate* isolate) { + last_dock_show_ = base::Time::Now(); gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); From 7c4cccc41d42b4d5aaeefd63069088b39bb7ce18 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 3 Sep 2020 10:22:43 +0900 Subject: [PATCH 2/2] test: run dock.show tests after dock.hide tests --- spec-main/api-app-spec.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/spec-main/api-app-spec.ts b/spec-main/api-app-spec.ts index 11dab023be47d..b2b78d87f2a80 100644 --- a/spec-main/api-app-spec.ts +++ b/spec-main/api-app-spec.ts @@ -1437,6 +1437,16 @@ describe('app module', () => { }); }); + describe('dock.hide', () => { + it('should not throw', () => { + app.dock.hide(); + expect(app.dock.isVisible()).to.equal(false); + }); + }); + + // Note that dock.show tests should run after dock.hide tests, to work + // around a bug of macOS. + // See https://github.com/electron/electron/pull/25269 for more. describe('dock.show', () => { it('should not throw', () => { return app.dock.show().then(() => { @@ -1452,13 +1462,6 @@ describe('app module', () => { await expect(app.dock.show()).to.eventually.be.fulfilled.equal(undefined); }); }); - - describe('dock.hide', () => { - it('should not throw', () => { - app.dock.hide(); - expect(app.dock.isVisible()).to.equal(false); - }); - }); }); describe('whenReady', () => {