From 4d65af3c60e1b977938afccaf76546b56368084b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 13 Jun 2016 21:19:56 +0900 Subject: [PATCH 1/4] Add ready-to-show event --- atom/browser/api/atom_api_window.cc | 4 ++++ atom/browser/api/atom_api_window.h | 1 + atom/browser/native_window.cc | 17 +++++++++++++++++ atom/browser/native_window.h | 4 ++++ atom/browser/native_window_observer.h | 3 +++ 5 files changed, 29 insertions(+) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 5a93f27d2de0..0d72a74f7d5a 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -156,6 +156,10 @@ void Window::OnWindowHide() { Emit("hide"); } +void Window::OnReadyToShow() { + Emit("ready-to-show"); +} + void Window::OnWindowMaximize() { Emit("maximize"); } diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 286b47262159..9d3f7ef2402e 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -61,6 +61,7 @@ class Window : public mate::TrackableObject, void OnWindowFocus() override; void OnWindowShow() override; void OnWindowHide() override; + void OnReadyToShow() override; void OnWindowMaximize() override; void OnWindowUnmaximize() override; void OnWindowMinimize() override; diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 8a00a88d5470..ab8b4f97b200 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -560,6 +560,19 @@ void NativeWindow::BeforeUnloadDialogCancelled() { window_unresposive_closure_.Cancel(); } +void NativeWindow::DidFirstVisuallyNonEmptyPaint() { + // When there is a non-empty first paint, resize the RenderWidget to force + // Chromium to draw. + const auto view = web_contents()->GetRenderWidgetHostView(); + view->Show(); + view->SetSize(GetContentSize()); + + // Emit the ReadyToShow event in next tick in case of pending drawing work. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&NativeWindow::NotifyReadyToShow, GetWeakPtr())); +} + bool NativeWindow::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(NativeWindow, message) @@ -601,6 +614,10 @@ void NativeWindow::NotifyWindowUnresponsive() { OnRendererUnresponsive()); } +void NativeWindow::NotifyReadyToShow() { + FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnReadyToShow()); +} + void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback, const SkBitmap& bitmap, content::ReadbackResponse response) { diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index ffcdcc4da277..796cf21326af 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -275,6 +275,7 @@ class NativeWindow : public base::SupportsUserData, // content::WebContentsObserver: void RenderViewCreated(content::RenderViewHost* render_view_host) override; void BeforeUnloadDialogCancelled() override; + void DidFirstVisuallyNonEmptyPaint() override; bool OnMessageReceived(const IPC::Message& message) override; private: @@ -284,6 +285,9 @@ class NativeWindow : public base::SupportsUserData, // Dispatch unresponsive event to observers. void NotifyWindowUnresponsive(); + // Dispatch ReadyToShow event to observers. + void NotifyReadyToShow(); + // Called when CapturePage has done. void OnCapturePageDone(const CapturePageCallback& callback, const SkBitmap& bitmap, diff --git a/atom/browser/native_window_observer.h b/atom/browser/native_window_observer.h index cfbae95bda16..73bf4362f57f 100644 --- a/atom/browser/native_window_observer.h +++ b/atom/browser/native_window_observer.h @@ -48,6 +48,9 @@ class NativeWindowObserver { // Called when window is hidden. virtual void OnWindowHide() {} + // Called when window is ready to show. + virtual void OnReadyToShow() {} + // Called when window state changed. virtual void OnWindowMaximize() {} virtual void OnWindowUnmaximize() {} From 8a50a1b9d31e93ed0e3b29563954a3c1adb3844c Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 13 Jun 2016 22:11:40 +0900 Subject: [PATCH 2/4] docs: Showing window gracefully --- docs/api/browser-window.md | 61 ++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 7f6c69673977..d369d034401b 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -4,22 +4,60 @@ ```javascript // In the main process. -const {BrowserWindow} = require('electron'); +const {BrowserWindow} = require('electron') // Or in the renderer process. -const {BrowserWindow} = require('electron').remote; +const {BrowserWindow} = require('electron').remote -let win = new BrowserWindow({width: 800, height: 600, show: false}); +let win = new BrowserWindow({width: 800, height: 600}) win.on('closed', () => { - win = null; -}); + win = null +}) -win.loadURL('https://github.com'); -win.show(); +win.loadURL('https://github.com') ``` -You can also create a window without chrome by using -[Frameless Window](frameless-window.md) API. +## Frameless window + +To create a window without chrome, or a transparent window in arbitrary shape, +you can use the [Frameless Window](frameless-window.md) API. + +## Showing window gracefully + +When loading a page in window directly, users will see the progress of loading +page, which is not good experience for native app. To make the window display +without visual flash, there are two solutions for different situations. + +### Using `ready-to-show` event + +While loading the page, the `ready-to-show` event will be emitted when renderer +process has done drawing for the first time, showing window after this event +will have no visual flash: + +```javascript +let win = new BrowserWindow({show: false}) +win.on('ready-to-show', () => { + win.show() +}) +``` + +This is event is usually emitted after the `did-finish-load` event, but for +pages with many remote resources, it may be emitted before the `did-finish-load` +event. + +### Setting `backgroundColor` + +For a complex app, the `ready-to-show` event could be emitted too late, making +the app feel slow. In this case, it is recommended to show the window +immediately, and use a `backgroundColor` close to your app's background: + +```javascript +let win = new BrowserWindow({backgroundColor: '#2e2c29'}) +win.loadURL('https://github.com') +``` + +Note that even for apps that use `ready-to-show` event, it is still recommended +to set `backgroundColor` to make app feel more native. ## Class: BrowserWindow @@ -271,6 +309,11 @@ Emitted when the window is shown. Emitted when the window is hidden. +### Event: 'ready-to-show' + +Emitted when the web page has been rendered and window can be displayed without +visual flash. + ### Event: 'maximize' Emitted when window is maximized. From f7f86160c18a6a85d6ea9cc7e28919e0d7ec4b9d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 13 Jun 2016 22:18:57 +0900 Subject: [PATCH 3/4] Only do the trick when window is hidden --- atom/browser/native_window.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index ab8b4f97b200..844bbefa9e24 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -561,6 +561,9 @@ void NativeWindow::BeforeUnloadDialogCancelled() { } void NativeWindow::DidFirstVisuallyNonEmptyPaint() { + if (IsVisible()) + return; + // When there is a non-empty first paint, resize the RenderWidget to force // Chromium to draw. const auto view = web_contents()->GetRenderWidgetHostView(); From fc09c98bec9396ceae95abafa6e605f5c1e559ef Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 13 Jun 2016 22:19:44 +0900 Subject: [PATCH 4/4] Use once for 'ready-to-show' --- docs/api/browser-window.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index d369d034401b..eaa074e846c1 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -36,7 +36,7 @@ will have no visual flash: ```javascript let win = new BrowserWindow({show: false}) -win.on('ready-to-show', () => { +win.once('ready-to-show', () => { win.show() }) ```