2014-10-31 18:17:05 +00:00
|
|
|
// Copyright (c) 2013 GitHub, Inc.
|
2014-04-25 09:49:37 +00:00
|
|
|
// Use of this source code is governed by the MIT license that can be
|
2013-04-14 07:36:48 +00:00
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2020-02-04 20:19:40 +00:00
|
|
|
#include "shell/browser/api/electron_api_browser_window.h"
|
2017-09-02 16:15:46 +00:00
|
|
|
|
2018-09-13 00:25:56 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2016-11-30 07:30:03 +00:00
|
|
|
#include "base/threading/thread_task_runner_handle.h"
|
2019-03-05 05:08:55 +00:00
|
|
|
#include "content/browser/renderer_host/render_widget_host_impl.h" // nogncheck
|
|
|
|
#include "content/browser/renderer_host/render_widget_host_owner_delegate.h" // nogncheck
|
2019-09-05 17:56:06 +00:00
|
|
|
#include "content/browser/web_contents/web_contents_impl.h" // nogncheck
|
2013-04-23 09:21:34 +00:00
|
|
|
#include "content/public/browser/render_process_host.h"
|
2018-02-22 06:04:32 +00:00
|
|
|
#include "content/public/browser/render_view_host.h"
|
2020-04-09 07:01:16 +00:00
|
|
|
#include "shell/browser/api/electron_api_web_contents_view.h"
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/browser.h"
|
2020-10-29 19:51:56 +00:00
|
|
|
#include "shell/browser/native_browser_view.h"
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/unresponsive_suppressor.h"
|
|
|
|
#include "shell/browser/web_contents_preferences.h"
|
|
|
|
#include "shell/browser/window_list.h"
|
|
|
|
#include "shell/common/color_util.h"
|
2019-12-05 09:46:34 +00:00
|
|
|
#include "shell/common/gin_helper/constructor.h"
|
2019-10-25 13:03:28 +00:00
|
|
|
#include "shell/common/gin_helper/dictionary.h"
|
|
|
|
#include "shell/common/gin_helper/object_template_builder.h"
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/common/node_includes.h"
|
|
|
|
#include "shell/common/options_switches.h"
|
2018-02-22 08:54:38 +00:00
|
|
|
#include "ui/gl/gpu_switching_manager.h"
|
2013-04-15 16:25:08 +00:00
|
|
|
|
2019-06-19 21:23:04 +00:00
|
|
|
namespace electron {
|
2013-04-14 07:36:48 +00:00
|
|
|
|
2013-04-15 16:25:08 +00:00
|
|
|
namespace api {
|
|
|
|
|
2019-10-15 01:15:23 +00:00
|
|
|
BrowserWindow::BrowserWindow(gin::Arguments* args,
|
2019-10-25 13:03:28 +00:00
|
|
|
const gin_helper::Dictionary& options)
|
2021-01-26 18:16:21 +00:00
|
|
|
: BaseWindow(args->isolate(), options) {
|
2017-07-10 22:45:48 +00:00
|
|
|
// Use options.webPreferences in WebContents.
|
2019-10-15 01:15:23 +00:00
|
|
|
v8::Isolate* isolate = args->isolate();
|
2019-10-25 13:03:28 +00:00
|
|
|
gin_helper::Dictionary web_preferences =
|
|
|
|
gin::Dictionary::CreateEmpty(isolate);
|
2017-07-10 22:45:48 +00:00
|
|
|
options.Get(options::kWebPreferences, &web_preferences);
|
2016-08-16 00:13:18 +00:00
|
|
|
|
2017-07-10 22:45:48 +00:00
|
|
|
// Copy the backgroundColor to webContents.
|
|
|
|
v8::Local<v8::Value> value;
|
|
|
|
if (options.Get(options::kBackgroundColor, &value))
|
|
|
|
web_preferences.Set(options::kBackgroundColor, value);
|
|
|
|
|
2019-09-05 17:56:06 +00:00
|
|
|
// Copy the transparent setting to webContents
|
2017-07-10 22:45:48 +00:00
|
|
|
v8::Local<v8::Value> transparent;
|
|
|
|
if (options.Get("transparent", &transparent))
|
|
|
|
web_preferences.Set("transparent", transparent);
|
2016-08-16 00:13:18 +00:00
|
|
|
|
2019-09-05 17:56:06 +00:00
|
|
|
// Copy the show setting to webContents, but only if we don't want to paint
|
|
|
|
// when initially hidden
|
|
|
|
bool paint_when_initially_hidden = true;
|
|
|
|
options.Get("paintWhenInitiallyHidden", &paint_when_initially_hidden);
|
|
|
|
if (!paint_when_initially_hidden) {
|
|
|
|
bool show = true;
|
|
|
|
options.Get(options::kShow, &show);
|
|
|
|
web_preferences.Set(options::kShow, show);
|
|
|
|
}
|
|
|
|
|
2020-04-09 07:01:16 +00:00
|
|
|
// Copy the webContents option to webPreferences. This is only used internally
|
|
|
|
// to implement nativeWindowOpen option.
|
|
|
|
if (options.Get("webContents", &value)) {
|
|
|
|
web_preferences.SetHidden("webContents", value);
|
2016-08-16 00:13:18 +00:00
|
|
|
}
|
2016-08-15 23:58:07 +00:00
|
|
|
|
2020-04-09 07:01:16 +00:00
|
|
|
// Creates the WebContentsView.
|
|
|
|
gin::Handle<WebContentsView> web_contents_view =
|
|
|
|
WebContentsView::Create(isolate, web_preferences);
|
|
|
|
DCHECK(web_contents_view.get());
|
|
|
|
|
|
|
|
// Save a reference of the WebContents.
|
|
|
|
gin::Handle<WebContents> web_contents =
|
|
|
|
web_contents_view->GetWebContents(isolate);
|
2015-06-25 01:47:57 +00:00
|
|
|
web_contents_.Reset(isolate, web_contents.ToV8());
|
2019-06-14 02:44:36 +00:00
|
|
|
api_web_contents_ = web_contents->GetWeakPtr();
|
2018-02-22 06:57:03 +00:00
|
|
|
api_web_contents_->AddObserver(this);
|
2018-02-23 00:15:13 +00:00
|
|
|
Observe(api_web_contents_->web_contents());
|
2015-06-25 01:47:57 +00:00
|
|
|
|
2015-09-22 13:56:56 +00:00
|
|
|
// Keep a copy of the options for later use.
|
2020-07-30 16:17:57 +00:00
|
|
|
gin_helper::Dictionary(isolate, web_contents.ToV8().As<v8::Object>())
|
2018-04-18 01:55:30 +00:00
|
|
|
.Set("browserWindowOptions", options);
|
2015-09-22 13:56:56 +00:00
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
// Associate with BrowserWindow.
|
|
|
|
web_contents->SetOwnerWindow(window());
|
2018-02-22 08:07:08 +00:00
|
|
|
|
|
|
|
auto* host = web_contents->web_contents()->GetRenderViewHost();
|
|
|
|
if (host)
|
|
|
|
host->GetWidget()->AddInputEventObserver(this);
|
2018-04-14 02:04:23 +00:00
|
|
|
|
2019-10-15 01:15:23 +00:00
|
|
|
InitWithArgs(args);
|
2018-04-14 02:04:23 +00:00
|
|
|
|
2020-06-29 07:06:20 +00:00
|
|
|
// Install the content view after BaseWindow's JS code is initialized.
|
2020-04-09 07:01:16 +00:00
|
|
|
SetContentView(gin::CreateHandle<View>(isolate, web_contents_view.get()));
|
|
|
|
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2020-11-17 22:15:20 +00:00
|
|
|
OverrideNSWindowContentView(
|
|
|
|
web_contents->inspectable_web_contents()->GetView());
|
2018-07-10 01:43:42 +00:00
|
|
|
#endif
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
// Init window after everything has been setup.
|
|
|
|
window()->InitFromOptions(options);
|
2013-04-15 16:25:08 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
BrowserWindow::~BrowserWindow() {
|
2019-06-14 02:44:36 +00:00
|
|
|
// FIXME This is a hack rather than a proper fix preventing shutdown crashes.
|
|
|
|
if (api_web_contents_)
|
|
|
|
api_web_contents_->RemoveObserver(this);
|
2018-04-14 02:04:23 +00:00
|
|
|
// Note that the OnWindowClosed will not be called after the destructor runs,
|
2020-06-29 07:06:20 +00:00
|
|
|
// since the window object is managed by the BaseWindow class.
|
2018-04-14 02:04:23 +00:00
|
|
|
if (web_contents())
|
|
|
|
Cleanup();
|
2013-04-15 16:25:08 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 08:07:08 +00:00
|
|
|
void BrowserWindow::OnInputEvent(const blink::WebInputEvent& event) {
|
|
|
|
switch (event.GetType()) {
|
2020-05-26 20:06:26 +00:00
|
|
|
case blink::WebInputEvent::Type::kGestureScrollBegin:
|
|
|
|
case blink::WebInputEvent::Type::kGestureScrollUpdate:
|
|
|
|
case blink::WebInputEvent::Type::kGestureScrollEnd:
|
2018-02-22 08:07:08 +00:00
|
|
|
Emit("scroll-touch-edge");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::RenderViewHostChanged(content::RenderViewHost* old_host,
|
|
|
|
content::RenderViewHost* new_host) {
|
|
|
|
if (old_host)
|
|
|
|
old_host->GetWidget()->RemoveInputEventObserver(this);
|
|
|
|
if (new_host)
|
|
|
|
new_host->GetWidget()->AddInputEventObserver(this);
|
|
|
|
}
|
|
|
|
|
2021-03-04 17:27:05 +00:00
|
|
|
void BrowserWindow::RenderFrameCreated(
|
|
|
|
content::RenderFrameHost* render_frame_host) {
|
2018-04-14 02:04:23 +00:00
|
|
|
if (!window()->transparent())
|
2018-02-22 06:04:32 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
content::RenderWidgetHostImpl* impl = content::RenderWidgetHostImpl::FromID(
|
2021-03-04 17:27:05 +00:00
|
|
|
render_frame_host->GetProcess()->GetID(),
|
|
|
|
render_frame_host->GetRoutingID());
|
2018-02-22 06:04:32 +00:00
|
|
|
if (impl)
|
2019-01-21 20:43:17 +00:00
|
|
|
impl->owner_delegate()->SetBackgroundOpaque(false);
|
2018-02-22 06:04:32 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 05:59:39 +00:00
|
|
|
void BrowserWindow::DidFirstVisuallyNonEmptyPaint() {
|
2018-04-14 02:04:23 +00:00
|
|
|
if (window()->IsVisible())
|
2018-02-22 05:59:39 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// When there is a non-empty first paint, resize the RenderWidget to force
|
|
|
|
// Chromium to draw.
|
2018-04-17 22:41:47 +00:00
|
|
|
auto* const view = web_contents()->GetRenderWidgetHostView();
|
2018-02-22 05:59:39 +00:00
|
|
|
view->Show();
|
2018-04-14 02:04:23 +00:00
|
|
|
view->SetSize(window()->GetContentSize());
|
2020-09-15 18:48:39 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 07:52:08 +00:00
|
|
|
void BrowserWindow::BeforeUnloadDialogCancelled() {
|
2018-04-14 02:04:23 +00:00
|
|
|
WindowList::WindowCloseCancelled(window());
|
2018-02-22 07:52:08 +00:00
|
|
|
// Cancel unresponsive event when window close is cancelled.
|
2018-02-23 00:15:13 +00:00
|
|
|
window_unresponsive_closure_.Cancel();
|
2018-02-22 07:52:08 +00:00
|
|
|
}
|
|
|
|
|
2018-04-11 15:23:16 +00:00
|
|
|
void BrowserWindow::OnRendererUnresponsive(content::RenderProcessHost*) {
|
2018-02-22 07:52:08 +00:00
|
|
|
// Schedule the unresponsive shortly later, since we may receive the
|
|
|
|
// responsive event soon. This could happen after the whole application had
|
|
|
|
// blocked for a while.
|
|
|
|
// Also notice that when closing this event would be ignored because we have
|
|
|
|
// explicitly started a close timeout counter. This is on purpose because we
|
|
|
|
// don't want the unresponsive event to be sent too early when user is closing
|
|
|
|
// the window.
|
|
|
|
ScheduleUnresponsiveEvent(50);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::OnCloseContents() {
|
2019-01-21 22:56:30 +00:00
|
|
|
// On some machines it may happen that the window gets destroyed for twice,
|
|
|
|
// checking web_contents() can effectively guard against that.
|
|
|
|
// https://github.com/electron/electron/issues/16202.
|
|
|
|
//
|
|
|
|
// TODO(zcbenz): We should find out the root cause and improve the closing
|
|
|
|
// procedure of BrowserWindow.
|
|
|
|
if (!web_contents())
|
|
|
|
return;
|
2013-05-01 15:28:01 +00:00
|
|
|
|
2016-06-19 06:47:27 +00:00
|
|
|
// Close all child windows before closing current window.
|
|
|
|
v8::Locker locker(isolate());
|
|
|
|
v8::HandleScope handle_scope(isolate());
|
|
|
|
for (v8::Local<v8::Value> value : child_windows_.Values(isolate())) {
|
2019-10-25 13:03:28 +00:00
|
|
|
gin::Handle<BrowserWindow> child;
|
|
|
|
if (gin::ConvertFromV8(isolate(), value, &child) && !child.IsEmpty())
|
2018-04-14 02:04:23 +00:00
|
|
|
child->window()->CloseImmediately();
|
2016-06-19 06:47:27 +00:00
|
|
|
}
|
2018-02-22 07:52:08 +00:00
|
|
|
|
|
|
|
// When the web contents is gone, close the window immediately, but the
|
|
|
|
// memory will not be freed until you call delete.
|
|
|
|
// In this way, it would be safe to manage windows via smart pointers. If you
|
|
|
|
// want to free memory when the window is closed, you can do deleting by
|
|
|
|
// overriding the OnWindowClosed method in the observer.
|
2018-04-14 02:04:23 +00:00
|
|
|
window()->CloseImmediately();
|
2018-02-22 07:52:08 +00:00
|
|
|
|
|
|
|
// Do not sent "unresponsive" event after window is closed.
|
2018-02-23 00:15:13 +00:00
|
|
|
window_unresponsive_closure_.Cancel();
|
2018-02-22 07:52:08 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 20:34:34 +00:00
|
|
|
void BrowserWindow::OnRendererResponsive(content::RenderProcessHost*) {
|
2018-02-23 00:15:13 +00:00
|
|
|
window_unresponsive_closure_.Cancel();
|
2018-02-22 07:52:08 +00:00
|
|
|
Emit("responsive");
|
|
|
|
}
|
|
|
|
|
2019-06-03 17:43:04 +00:00
|
|
|
void BrowserWindow::OnDraggableRegionsUpdated(
|
|
|
|
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
|
|
|
UpdateDraggableRegions(regions);
|
|
|
|
}
|
|
|
|
|
2020-02-11 00:37:46 +00:00
|
|
|
void BrowserWindow::OnSetContentBounds(const gfx::Rect& rect) {
|
|
|
|
// window.resizeTo(...)
|
|
|
|
// window.moveTo(...)
|
|
|
|
window()->SetBounds(rect, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::OnActivateContents() {
|
|
|
|
// Hide the auto-hide menu when webContents is focused.
|
2020-08-12 18:33:58 +00:00
|
|
|
#if !defined(OS_MAC)
|
2020-02-11 00:37:46 +00:00
|
|
|
if (IsMenuBarAutoHide() && IsMenuBarVisible())
|
|
|
|
window()->SetMenuBarVisibility(false);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::OnPageTitleUpdated(const base::string16& title,
|
|
|
|
bool explicit_set) {
|
|
|
|
// Change window title to page title.
|
|
|
|
auto self = GetWeakPtr();
|
|
|
|
if (!Emit("page-title-updated", title, explicit_set)) {
|
|
|
|
// |this| might be deleted, or marked as destroyed by close().
|
|
|
|
if (self && !IsDestroyed())
|
|
|
|
SetTitle(base::UTF16ToUTF8(title));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-06 03:03:12 +00:00
|
|
|
void BrowserWindow::RequestPreferredWidth(int* width) {
|
|
|
|
*width = web_contents()->GetPreferredSize().width();
|
|
|
|
}
|
|
|
|
|
2018-02-22 07:15:21 +00:00
|
|
|
void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
|
|
|
// When user tries to close the window by clicking the close button, we do
|
|
|
|
// not close the window immediately, instead we try to close the web page
|
|
|
|
// first, and when the web page is closed the window will also be closed.
|
|
|
|
*prevent_default = true;
|
2018-02-22 07:52:08 +00:00
|
|
|
|
|
|
|
// Assume the window is not responding if it doesn't cancel the close and is
|
|
|
|
// not closed in 5s, in this way we can quickly show the unresponsive
|
2020-10-13 17:25:21 +00:00
|
|
|
// dialog when the window is busy executing some script without waiting for
|
2018-02-22 07:52:08 +00:00
|
|
|
// the unresponsive timeout.
|
2018-02-23 00:15:13 +00:00
|
|
|
if (window_unresponsive_closure_.IsCancelled())
|
2018-02-22 07:52:08 +00:00
|
|
|
ScheduleUnresponsiveEvent(5000);
|
|
|
|
|
|
|
|
if (!web_contents())
|
|
|
|
// Already closed by renderer
|
|
|
|
return;
|
|
|
|
|
2020-05-26 13:21:38 +00:00
|
|
|
// Required to make beforeunload handler work.
|
|
|
|
api_web_contents_->NotifyUserActivation();
|
|
|
|
|
2020-08-12 18:33:58 +00:00
|
|
|
if (web_contents()->NeedToFireBeforeUnloadOrUnloadEvents())
|
2019-01-12 01:00:43 +00:00
|
|
|
web_contents()->DispatchBeforeUnload(false /* auto_cancel */);
|
2018-02-22 07:52:08 +00:00
|
|
|
else
|
|
|
|
web_contents()->Close();
|
2018-02-22 07:15:21 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::OnWindowClosed() {
|
2020-07-09 15:48:39 +00:00
|
|
|
// We need to reset the browser views before we call Cleanup, because the
|
|
|
|
// browser views are child views of the main web contents view, which will be
|
|
|
|
// deleted by Cleanup.
|
|
|
|
BaseWindow::ResetBrowserViews();
|
2018-04-14 02:04:23 +00:00
|
|
|
Cleanup();
|
2020-06-29 07:06:20 +00:00
|
|
|
// See BaseWindow::OnWindowClosed on why calling InvalidateWeakPtrs.
|
2020-02-11 00:37:46 +00:00
|
|
|
weak_factory_.InvalidateWeakPtrs();
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::OnWindowClosed();
|
2017-04-21 20:45:30 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::OnWindowBlur() {
|
2018-03-06 04:13:50 +00:00
|
|
|
web_contents()->StoreFocus();
|
|
|
|
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::OnWindowBlur();
|
2013-05-24 09:58:39 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::OnWindowFocus() {
|
2018-03-06 04:13:50 +00:00
|
|
|
web_contents()->RestoreFocus();
|
2020-06-29 20:15:28 +00:00
|
|
|
|
2020-08-12 18:33:58 +00:00
|
|
|
#if !defined(OS_MAC)
|
2018-03-06 06:17:42 +00:00
|
|
|
if (!api_web_contents_->IsDevToolsOpened())
|
|
|
|
web_contents()->Focus();
|
2018-03-06 04:32:56 +00:00
|
|
|
#endif
|
2018-03-06 04:13:50 +00:00
|
|
|
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::OnWindowFocus();
|
2014-11-25 04:43:25 +00:00
|
|
|
}
|
|
|
|
|
2020-06-29 20:15:28 +00:00
|
|
|
void BrowserWindow::OnWindowIsKeyChanged(bool is_key) {
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2020-06-29 20:15:28 +00:00
|
|
|
auto* rwhv = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (rwhv)
|
|
|
|
rwhv->SetActive(is_key);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::OnWindowResize() {
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2020-10-29 19:51:56 +00:00
|
|
|
if (!draggable_regions_.empty()) {
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2020-10-29 19:51:56 +00:00
|
|
|
} else {
|
2020-12-01 05:02:04 +00:00
|
|
|
for (NativeBrowserView* view : window_->browser_views()) {
|
|
|
|
view->UpdateDraggableRegions(view->GetDraggableRegions());
|
2020-10-29 19:51:56 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-06 05:44:36 +00:00
|
|
|
#endif
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::OnWindowResize();
|
2013-04-17 14:49:49 +00:00
|
|
|
}
|
|
|
|
|
2018-06-18 07:48:20 +00:00
|
|
|
void BrowserWindow::OnWindowLeaveFullScreen() {
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2020-07-14 01:13:34 +00:00
|
|
|
if (web_contents()->IsFullscreen())
|
2018-06-18 07:48:20 +00:00
|
|
|
web_contents()->ExitFullscreen(true);
|
|
|
|
#endif
|
2020-09-17 23:40:07 +00:00
|
|
|
BaseWindow::OnWindowLeaveFullScreen();
|
2018-06-18 07:48:20 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::Focus() {
|
2018-04-14 02:04:23 +00:00
|
|
|
if (api_web_contents_->IsOffScreen())
|
2018-04-05 06:14:42 +00:00
|
|
|
FocusOnWebView();
|
2018-04-14 02:04:23 +00:00
|
|
|
else
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::Focus();
|
2013-05-16 14:56:52 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::Blur() {
|
2018-04-14 02:04:23 +00:00
|
|
|
if (api_web_contents_->IsOffScreen())
|
2018-04-05 06:14:42 +00:00
|
|
|
BlurWebView();
|
2018-04-14 02:04:23 +00:00
|
|
|
else
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::Blur();
|
2013-04-17 14:49:49 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::SetBackgroundColor(color_name);
|
2018-03-06 04:21:47 +00:00
|
|
|
auto* view = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (view)
|
2018-04-14 02:04:23 +00:00
|
|
|
view->SetBackgroundColor(ParseHexColor(color_name));
|
2019-08-27 06:14:23 +00:00
|
|
|
// Also update the web preferences object otherwise the view will be reset on
|
|
|
|
// the next load URL call
|
|
|
|
if (api_web_contents_) {
|
|
|
|
auto* web_preferences =
|
|
|
|
WebContentsPreferences::From(api_web_contents_->web_contents());
|
|
|
|
if (web_preferences) {
|
|
|
|
web_preferences->preference()->SetStringKey(options::kBackgroundColor,
|
|
|
|
color_name);
|
|
|
|
}
|
|
|
|
}
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::SetBrowserView(v8::Local<v8::Value> value) {
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::ResetBrowserViews();
|
|
|
|
BaseWindow::AddBrowserView(value);
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2018-12-22 01:49:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::AddBrowserView(v8::Local<v8::Value> value) {
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::AddBrowserView(value);
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2018-12-22 01:49:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::RemoveBrowserView(value);
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2018-12-22 01:49:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-02-10 07:23:35 +00:00
|
|
|
void BrowserWindow::SetTopBrowserView(v8::Local<v8::Value> value,
|
|
|
|
gin_helper::Arguments* args) {
|
|
|
|
BaseWindow::SetTopBrowserView(value, args);
|
|
|
|
#if defined(OS_MACOSX)
|
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-12-22 01:49:26 +00:00
|
|
|
void BrowserWindow::ResetBrowserViews() {
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::ResetBrowserViews();
|
2020-08-12 18:33:58 +00:00
|
|
|
#if defined(OS_MAC)
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2018-03-19 18:45:42 +00:00
|
|
|
#endif
|
2017-09-13 19:15:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-30 01:29:18 +00:00
|
|
|
void BrowserWindow::SetVibrancy(v8::Isolate* isolate,
|
|
|
|
v8::Local<v8::Value> value) {
|
2018-11-29 01:55:03 +00:00
|
|
|
std::string type = gin::V8ToString(isolate, value);
|
2018-03-06 04:47:21 +00:00
|
|
|
|
|
|
|
auto* render_view_host = web_contents()->GetRenderViewHost();
|
|
|
|
if (render_view_host) {
|
|
|
|
auto* impl = content::RenderWidgetHostImpl::FromID(
|
|
|
|
render_view_host->GetProcess()->GetID(),
|
|
|
|
render_view_host->GetRoutingID());
|
|
|
|
if (impl)
|
2019-01-21 20:43:17 +00:00
|
|
|
impl->owner_delegate()->SetBackgroundOpaque(
|
|
|
|
type.empty() ? !window_->transparent() : false);
|
2018-03-06 04:47:21 +00:00
|
|
|
}
|
|
|
|
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::SetVibrancy(isolate, value);
|
2016-11-27 05:57:01 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
void BrowserWindow::FocusOnWebView() {
|
|
|
|
web_contents()->GetRenderViewHost()->GetWidget()->Focus();
|
2016-12-16 06:24:51 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
void BrowserWindow::BlurWebView() {
|
|
|
|
web_contents()->GetRenderViewHost()->GetWidget()->Blur();
|
2017-03-27 00:22:52 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
bool BrowserWindow::IsWebViewFocused() {
|
2018-05-04 06:45:12 +00:00
|
|
|
auto* host_view = web_contents()->GetRenderViewHost()->GetWidget()->GetView();
|
2018-04-14 02:04:23 +00:00
|
|
|
return host_view && host_view->HasFocus();
|
2015-06-24 08:37:48 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
v8::Local<v8::Value> BrowserWindow::GetWebContents(v8::Isolate* isolate) {
|
|
|
|
if (web_contents_.IsEmpty())
|
2015-06-24 11:04:08 +00:00
|
|
|
return v8::Null(isolate);
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
return v8::Local<v8::Value>::New(isolate, web_contents_);
|
2014-04-24 08:45:25 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 07:52:08 +00:00
|
|
|
void BrowserWindow::ScheduleUnresponsiveEvent(int ms) {
|
2018-02-23 00:15:13 +00:00
|
|
|
if (!window_unresponsive_closure_.IsCancelled())
|
2018-02-22 07:52:08 +00:00
|
|
|
return;
|
|
|
|
|
2019-04-28 01:03:06 +00:00
|
|
|
window_unresponsive_closure_.Reset(base::BindRepeating(
|
|
|
|
&BrowserWindow::NotifyWindowUnresponsive, GetWeakPtr()));
|
2018-02-22 07:52:08 +00:00
|
|
|
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
2018-04-18 01:55:30 +00:00
|
|
|
FROM_HERE, window_unresponsive_closure_.callback(),
|
2018-02-22 07:52:08 +00:00
|
|
|
base::TimeDelta::FromMilliseconds(ms));
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::NotifyWindowUnresponsive() {
|
2018-02-23 00:15:13 +00:00
|
|
|
window_unresponsive_closure_.Cancel();
|
2018-02-22 07:52:08 +00:00
|
|
|
if (!window_->IsClosed() && window_->IsEnabled() &&
|
|
|
|
!IsUnresponsiveEventSuppressed()) {
|
|
|
|
Emit("unresponsive");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
void BrowserWindow::Cleanup() {
|
|
|
|
auto* host = web_contents()->GetRenderViewHost();
|
|
|
|
if (host)
|
|
|
|
host->GetWidget()->RemoveInputEventObserver(this);
|
|
|
|
|
2018-11-08 15:57:28 +00:00
|
|
|
// Destroy WebContents asynchronously unless app is shutting down,
|
|
|
|
// because destroy() might be called inside WebContents's event handler.
|
|
|
|
api_web_contents_->DestroyWebContents(!Browser::Get()->is_shutting_down());
|
2018-04-14 02:04:23 +00:00
|
|
|
Observe(nullptr);
|
|
|
|
}
|
|
|
|
|
2019-09-05 17:56:06 +00:00
|
|
|
void BrowserWindow::OnWindowShow() {
|
|
|
|
web_contents()->WasShown();
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::OnWindowShow();
|
2019-09-05 17:56:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::OnWindowHide() {
|
2020-01-13 00:56:49 +00:00
|
|
|
web_contents()->WasOccluded();
|
2020-06-29 07:06:20 +00:00
|
|
|
BaseWindow::OnWindowHide();
|
2019-09-05 17:56:06 +00:00
|
|
|
}
|
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
// static
|
2019-12-05 09:46:34 +00:00
|
|
|
gin_helper::WrappableBase* BrowserWindow::New(gin_helper::ErrorThrower thrower,
|
|
|
|
gin::Arguments* args) {
|
2018-04-14 02:04:23 +00:00
|
|
|
if (!Browser::Get()->is_ready()) {
|
2019-10-15 01:15:23 +00:00
|
|
|
thrower.ThrowError("Cannot create BrowserWindow before app is ready");
|
2018-04-14 02:04:23 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args->Length() > 1) {
|
|
|
|
args->ThrowError();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-10-25 13:03:28 +00:00
|
|
|
gin_helper::Dictionary options;
|
2018-04-14 02:04:23 +00:00
|
|
|
if (!(args->Length() == 1 && args->GetNext(&options))) {
|
2019-10-25 13:03:28 +00:00
|
|
|
options = gin::Dictionary::CreateEmpty(args->isolate());
|
2018-04-14 02:04:23 +00:00
|
|
|
}
|
|
|
|
|
2019-10-15 01:15:23 +00:00
|
|
|
return new BrowserWindow(args, options);
|
2018-04-14 02:04:23 +00:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:07:21 +00:00
|
|
|
// static
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::BuildPrototype(v8::Isolate* isolate,
|
|
|
|
v8::Local<v8::FunctionTemplate> prototype) {
|
2019-10-25 13:03:28 +00:00
|
|
|
prototype->SetClassName(gin::StringToV8(isolate, "BrowserWindow"));
|
|
|
|
gin_helper::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
2018-02-22 03:49:17 +00:00
|
|
|
.SetMethod("focusOnWebView", &BrowserWindow::FocusOnWebView)
|
|
|
|
.SetMethod("blurWebView", &BrowserWindow::BlurWebView)
|
|
|
|
.SetMethod("isWebViewFocused", &BrowserWindow::IsWebViewFocused)
|
2018-04-14 02:04:23 +00:00
|
|
|
.SetProperty("webContents", &BrowserWindow::GetWebContents);
|
2013-04-18 16:06:10 +00:00
|
|
|
}
|
|
|
|
|
2015-10-01 05:45:59 +00:00
|
|
|
// static
|
2018-02-22 03:49:17 +00:00
|
|
|
v8::Local<v8::Value> BrowserWindow::From(v8::Isolate* isolate,
|
|
|
|
NativeWindow* native_window) {
|
2018-04-17 22:41:47 +00:00
|
|
|
auto* existing = TrackableObject::FromWrappedClass(isolate, native_window);
|
2015-10-01 05:45:59 +00:00
|
|
|
if (existing)
|
2016-04-25 01:19:25 +00:00
|
|
|
return existing->GetWrapper();
|
2015-10-01 05:45:59 +00:00
|
|
|
else
|
|
|
|
return v8::Null(isolate);
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:07:21 +00:00
|
|
|
} // namespace api
|
2013-04-18 07:09:53 +00:00
|
|
|
|
2019-06-19 21:23:04 +00:00
|
|
|
} // namespace electron
|
2013-04-18 07:09:53 +00:00
|
|
|
|
2014-04-22 15:07:21 +00:00
|
|
|
namespace {
|
2013-04-18 07:09:53 +00:00
|
|
|
|
2020-06-29 07:06:20 +00:00
|
|
|
using electron::api::BaseWindow;
|
2019-06-19 21:23:04 +00:00
|
|
|
using electron::api::BrowserWindow;
|
2015-06-24 08:37:48 +00:00
|
|
|
|
2018-04-18 01:55:30 +00:00
|
|
|
void Initialize(v8::Local<v8::Object> exports,
|
|
|
|
v8::Local<v8::Value> unused,
|
|
|
|
v8::Local<v8::Context> context,
|
|
|
|
void* priv) {
|
2014-06-29 12:48:44 +00:00
|
|
|
v8::Isolate* isolate = context->GetIsolate();
|
2019-10-25 13:03:28 +00:00
|
|
|
gin_helper::Dictionary dict(isolate, exports);
|
2019-04-28 01:03:06 +00:00
|
|
|
dict.Set("BrowserWindow",
|
2019-12-05 09:46:34 +00:00
|
|
|
gin_helper::CreateConstructor<BrowserWindow>(
|
2019-04-28 01:03:06 +00:00
|
|
|
isolate, base::BindRepeating(&BrowserWindow::New)));
|
2013-04-15 16:25:08 +00:00
|
|
|
}
|
|
|
|
|
2014-04-22 15:07:21 +00:00
|
|
|
} // namespace
|
2013-04-14 07:36:48 +00:00
|
|
|
|
2020-02-14 11:25:39 +00:00
|
|
|
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_window, Initialize)
|