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..844bbefa9e24 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -560,6 +560,22 @@ void NativeWindow::BeforeUnloadDialogCancelled() { window_unresposive_closure_.Cancel(); } +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(); + 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 +617,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() {} diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 7f6c69673977..eaa074e846c1 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.once('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.