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
|
|
|
|
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
|
|
|
v8::Local<v8::Value> value;
|
2021-09-06 07:59:09 +00:00
|
|
|
bool transparent = false;
|
2021-10-21 19:53:52 +00:00
|
|
|
options.Get(options::kTransparent, &transparent);
|
|
|
|
|
|
|
|
std::string vibrancy_type;
|
|
|
|
#if defined(OS_MAC)
|
|
|
|
options.Get(options::kVibrancyType, &vibrancy_type);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Copy the backgroundColor to webContents.
|
2021-09-06 07:59:09 +00:00
|
|
|
if (options.Get(options::kBackgroundColor, &value)) {
|
|
|
|
web_preferences.SetHidden(options::kBackgroundColor, value);
|
2021-10-21 19:53:52 +00:00
|
|
|
} else if (!vibrancy_type.empty() || transparent) {
|
|
|
|
// If the BrowserWindow is transparent or a vibrancy type has been set,
|
|
|
|
// also propagate transparency to the WebContents unless a separate
|
|
|
|
// backgroundColor has been set.
|
2021-09-06 07:59:09 +00:00
|
|
|
web_preferences.SetHidden(options::kBackgroundColor,
|
|
|
|
ToRGBAHex(SK_ColorTRANSPARENT));
|
|
|
|
}
|
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);
|
|
|
|
}
|
|
|
|
|
2021-07-01 19:25:40 +00:00
|
|
|
bool titleBarOverlay = false;
|
|
|
|
options.Get(options::ktitleBarOverlay, &titleBarOverlay);
|
|
|
|
if (titleBarOverlay) {
|
|
|
|
std::string enabled_features = "";
|
|
|
|
if (web_preferences.Get(options::kEnableBlinkFeatures, &enabled_features)) {
|
|
|
|
enabled_features += ",";
|
|
|
|
}
|
|
|
|
enabled_features += features::kWebAppWindowControlsOverlay.name;
|
|
|
|
web_preferences.Set(options::kEnableBlinkFeatures, enabled_features);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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() {
|
2021-03-15 22:43:25 +00:00
|
|
|
if (api_web_contents_) {
|
|
|
|
// Cleanup the observers if user destroyed this instance directly instead of
|
|
|
|
// gracefully closing content::WebContents.
|
|
|
|
auto* host = web_contents()->GetRenderViewHost();
|
|
|
|
if (host)
|
|
|
|
host->GetWidget()->RemoveInputEventObserver(this);
|
2019-06-14 02:44:36 +00:00
|
|
|
api_web_contents_->RemoveObserver(this);
|
2021-03-15 22:43:25 +00:00
|
|
|
// Destroy the WebContents.
|
|
|
|
OnCloseContents();
|
|
|
|
}
|
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() {
|
2021-07-22 13:38:11 +00:00
|
|
|
if (window()->IsClosed() || 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);
|
|
|
|
}
|
|
|
|
|
2021-03-15 22:43:25 +00:00
|
|
|
void BrowserWindow::WebContentsDestroyed() {
|
|
|
|
api_web_contents_ = nullptr;
|
|
|
|
CloseImmediately();
|
|
|
|
}
|
2018-02-22 07:52:08 +00:00
|
|
|
|
2021-03-15 22:43:25 +00:00
|
|
|
void BrowserWindow::OnCloseContents() {
|
|
|
|
BaseWindow::ResetBrowserViews();
|
|
|
|
api_web_contents_->Destroy();
|
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
|
|
|
|
}
|
|
|
|
|
2021-03-16 16:18:45 +00:00
|
|
|
void BrowserWindow::OnPageTitleUpdated(const std::u16string& title,
|
2020-02-11 00:37:46 +00:00
|
|
|
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);
|
|
|
|
|
2021-04-07 07:16:10 +00:00
|
|
|
// Already closed by renderer.
|
2021-11-01 04:32:54 +00:00
|
|
|
if (!web_contents() || !api_web_contents_)
|
2018-02-22 07:52:08 +00:00
|
|
|
return;
|
|
|
|
|
2020-05-26 13:21:38 +00:00
|
|
|
// Required to make beforeunload handler work.
|
|
|
|
api_web_contents_->NotifyUserActivation();
|
|
|
|
|
2021-04-07 07:16:10 +00:00
|
|
|
// Trigger beforeunload events for associated BrowserViews.
|
|
|
|
for (NativeBrowserView* view : window_->browser_views()) {
|
|
|
|
auto* vwc = view->web_contents();
|
|
|
|
auto* api_web_contents = api::WebContents::From(vwc);
|
|
|
|
|
|
|
|
// Required to make beforeunload handler work.
|
|
|
|
if (api_web_contents)
|
|
|
|
api_web_contents->NotifyUserActivation();
|
|
|
|
|
|
|
|
if (vwc) {
|
|
|
|
if (vwc->NeedToFireBeforeUnloadOrUnloadEvents()) {
|
|
|
|
vwc->DispatchBeforeUnload(false /* auto_cancel */);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (web_contents()->NeedToFireBeforeUnloadOrUnloadEvents()) {
|
2019-01-12 01:00:43 +00:00
|
|
|
web_contents()->DispatchBeforeUnload(false /* auto_cancel */);
|
2021-04-07 07:16:10 +00:00
|
|
|
} else {
|
2018-02-22 07:52:08 +00:00
|
|
|
web_contents()->Close();
|
2021-04-07 07:16:10 +00:00
|
|
|
}
|
|
|
|
} // namespace api
|
2018-02-22 07:15:21 +00:00
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::OnWindowBlur() {
|
2021-03-15 22:43:25 +00:00
|
|
|
if (api_web_contents_)
|
|
|
|
web_contents()->StoreFocus();
|
2018-03-06 04:13:50 +00:00
|
|
|
|
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() {
|
2021-03-15 22:43:25 +00:00
|
|
|
// focus/blur events might be emitted while closing window.
|
|
|
|
if (api_web_contents_) {
|
|
|
|
web_contents()->RestoreFocus();
|
2020-08-12 18:33:58 +00:00
|
|
|
#if !defined(OS_MAC)
|
2021-03-15 22:43:25 +00:00
|
|
|
if (!api_web_contents_->IsDevToolsOpened())
|
|
|
|
web_contents()->Focus();
|
2018-03-06 04:32:56 +00:00
|
|
|
#endif
|
2021-03-15 22:43:25 +00:00
|
|
|
}
|
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);
|
2021-05-19 09:27:35 +00:00
|
|
|
window()->SetActive(is_key);
|
2020-06-29 20:15:28 +00:00
|
|
|
#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
|
|
|
}
|
|
|
|
|
2021-07-01 19:25:40 +00:00
|
|
|
void BrowserWindow::UpdateWindowControlsOverlay(
|
|
|
|
const gfx::Rect& bounding_rect) {
|
|
|
|
web_contents()->UpdateWindowControlsOverlay(bounding_rect);
|
|
|
|
}
|
|
|
|
|
2021-03-15 22:43:25 +00:00
|
|
|
void BrowserWindow::CloseImmediately() {
|
|
|
|
// 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())) {
|
|
|
|
gin::Handle<BrowserWindow> child;
|
|
|
|
if (gin::ConvertFromV8(isolate(), value, &child) && !child.IsEmpty())
|
|
|
|
child->window()->CloseImmediately();
|
|
|
|
}
|
|
|
|
|
|
|
|
BaseWindow::CloseImmediately();
|
|
|
|
|
|
|
|
// Do not sent "unresponsive" event after window is closed.
|
|
|
|
window_unresponsive_closure_.Cancel();
|
|
|
|
}
|
|
|
|
|
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);
|
2021-09-21 00:20:54 +00:00
|
|
|
SkColor color = ParseHexColor(color_name);
|
|
|
|
web_contents()->SetPageBaseBackgroundColor(color);
|
|
|
|
auto* rwhv = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (rwhv)
|
|
|
|
rwhv->SetBackgroundColor(color);
|
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) {
|
2021-07-26 16:04:09 +00:00
|
|
|
web_preferences->SetBackgroundColor(ParseHexColor(color_name));
|
2019-08-27 06:14:23 +00:00
|
|
|
}
|
|
|
|
}
|
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);
|
2021-03-15 22:43:25 +00:00
|
|
|
#if defined(OS_MAC)
|
2021-02-10 07:23:35 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-06-16 16:58:30 +00:00
|
|
|
void BrowserWindow::OnDevToolsResized() {
|
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
|
|
|
}
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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)
|