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.
|
|
|
|
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/api/atom_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
|
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"
|
2018-11-29 01:55:03 +00:00
|
|
|
#include "gin/converter.h"
|
2014-04-22 15:07:21 +00:00
|
|
|
#include "native_mate/dictionary.h"
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/browser.h"
|
|
|
|
#include "shell/browser/unresponsive_suppressor.h"
|
|
|
|
#include "shell/browser/web_contents_preferences.h"
|
|
|
|
#include "shell/browser/window_list.h"
|
|
|
|
#include "shell/common/api/constructor.h"
|
|
|
|
#include "shell/common/color_util.h"
|
|
|
|
#include "shell/common/native_mate_converters/callback.h"
|
|
|
|
#include "shell/common/native_mate_converters/value_converter.h"
|
|
|
|
#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 {
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
BrowserWindow::BrowserWindow(v8::Isolate* isolate,
|
|
|
|
v8::Local<v8::Object> wrapper,
|
2018-02-22 05:59:39 +00:00
|
|
|
const mate::Dictionary& options)
|
2018-04-17 07:29:16 +00:00
|
|
|
: TopLevelWindow(isolate, options), weak_factory_(this) {
|
2016-08-16 00:13:18 +00:00
|
|
|
mate::Handle<class WebContents> web_contents;
|
|
|
|
|
2017-07-10 22:45:48 +00:00
|
|
|
// Use options.webPreferences in WebContents.
|
|
|
|
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
|
|
|
|
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);
|
|
|
|
|
|
|
|
v8::Local<v8::Value> transparent;
|
|
|
|
if (options.Get("transparent", &transparent))
|
|
|
|
web_preferences.Set("transparent", transparent);
|
2016-08-16 00:13:18 +00:00
|
|
|
|
2018-02-12 19:46:29 +00:00
|
|
|
if (options.Get("webContents", &web_contents) && !web_contents.IsEmpty()) {
|
2017-07-11 00:04:07 +00:00
|
|
|
// Set webPreferences from options if using an existing webContents.
|
|
|
|
// These preferences will be used when the webContent launches new
|
|
|
|
// render processes.
|
2017-07-10 22:45:48 +00:00
|
|
|
auto* existing_preferences =
|
2018-03-08 07:12:45 +00:00
|
|
|
WebContentsPreferences::From(web_contents->web_contents());
|
2017-07-10 22:45:48 +00:00
|
|
|
base::DictionaryValue web_preferences_dict;
|
2017-07-11 00:04:07 +00:00
|
|
|
if (mate::ConvertFromV8(isolate, web_preferences.GetHandle(),
|
2018-03-08 07:05:12 +00:00
|
|
|
&web_preferences_dict)) {
|
2018-08-03 21:23:07 +00:00
|
|
|
existing_preferences->Clear();
|
2017-07-11 00:04:07 +00:00
|
|
|
existing_preferences->Merge(web_preferences_dict);
|
|
|
|
}
|
2017-07-10 22:45:48 +00:00
|
|
|
} else {
|
2016-08-16 00:13:18 +00:00
|
|
|
// Creates the WebContents used by BrowserWindow.
|
|
|
|
web_contents = WebContents::Create(isolate, web_preferences);
|
|
|
|
}
|
2016-08-15 23:58:07 +00:00
|
|
|
|
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.
|
2018-04-18 01:55:30 +00:00
|
|
|
mate::Dictionary(isolate, web_contents->GetWrapper())
|
|
|
|
.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
|
|
|
|
|
|
|
InitWith(isolate, wrapper);
|
|
|
|
|
2018-07-10 01:43:42 +00:00
|
|
|
#if defined(OS_MACOSX)
|
|
|
|
if (!window()->has_frame())
|
2018-07-16 01:20:35 +00:00
|
|
|
OverrideNSWindowContentView(web_contents->managed_web_contents());
|
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,
|
|
|
|
// since the window object is managed by the TopLevelWindow class.
|
|
|
|
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()) {
|
|
|
|
case blink::WebInputEvent::kGestureScrollBegin:
|
|
|
|
case blink::WebInputEvent::kGestureScrollUpdate:
|
|
|
|
case blink::WebInputEvent::kGestureScrollEnd:
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-02-22 06:04:32 +00:00
|
|
|
void BrowserWindow::RenderViewCreated(
|
|
|
|
content::RenderViewHost* render_view_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(
|
|
|
|
render_view_host->GetProcess()->GetID(),
|
|
|
|
render_view_host->GetRoutingID());
|
|
|
|
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());
|
2018-02-22 05:59:39 +00:00
|
|
|
|
|
|
|
// Emit the ReadyToShow event in next tick in case of pending drawing work.
|
|
|
|
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
2018-04-20 10:55:05 +00:00
|
|
|
FROM_HERE, base::BindOnce(
|
2018-04-18 01:55:30 +00:00
|
|
|
[](base::WeakPtr<BrowserWindow> self) {
|
|
|
|
if (self)
|
|
|
|
self->Emit("ready-to-show");
|
|
|
|
},
|
|
|
|
GetWeakPtr()));
|
2018-02-22 05:59: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())) {
|
2018-02-22 03:49:17 +00:00
|
|
|
mate::Handle<BrowserWindow> child;
|
2018-02-12 19:46:29 +00:00
|
|
|
if (mate::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
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::OnRendererResponsive() {
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
// dialog when the window is busy executing some script withouth waiting for
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
if (web_contents()->NeedToFireBeforeUnload())
|
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() {
|
2018-04-14 02:04:23 +00:00
|
|
|
Cleanup();
|
|
|
|
TopLevelWindow::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();
|
2018-03-06 04:32:56 +00:00
|
|
|
#if defined(OS_MACOSX)
|
2018-03-06 04:13:50 +00:00
|
|
|
auto* rwhv = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (rwhv)
|
|
|
|
rwhv->SetActive(false);
|
2018-03-06 04:32:56 +00:00
|
|
|
#endif
|
2018-03-06 04:13:50 +00:00
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
TopLevelWindow::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();
|
2018-03-06 04:32:56 +00:00
|
|
|
#if defined(OS_MACOSX)
|
2018-03-06 04:13:50 +00:00
|
|
|
auto* rwhv = web_contents()->GetRenderWidgetHostView();
|
|
|
|
if (rwhv)
|
|
|
|
rwhv->SetActive(true);
|
2018-03-06 06:17:42 +00:00
|
|
|
#else
|
|
|
|
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
|
|
|
|
2018-04-14 02:04:23 +00:00
|
|
|
TopLevelWindow::OnWindowFocus();
|
2014-11-25 04:43:25 +00:00
|
|
|
}
|
|
|
|
|
2018-02-22 03:49:17 +00:00
|
|
|
void BrowserWindow::OnWindowResize() {
|
2018-03-06 05:44:36 +00:00
|
|
|
#if defined(OS_MACOSX)
|
|
|
|
if (!draggable_regions_.empty())
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2018-03-06 05:44:36 +00:00
|
|
|
#endif
|
2018-04-14 02:04:23 +00:00
|
|
|
TopLevelWindow::OnWindowResize();
|
2013-04-17 14:49:49 +00:00
|
|
|
}
|
|
|
|
|
2018-06-18 07:48:20 +00:00
|
|
|
void BrowserWindow::OnWindowLeaveFullScreen() {
|
|
|
|
TopLevelWindow::OnWindowLeaveFullScreen();
|
|
|
|
#if defined(OS_MACOSX)
|
|
|
|
if (web_contents()->IsFullscreenForCurrentTab())
|
|
|
|
web_contents()->ExitFullscreen(true);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
TopLevelWindow::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
|
|
|
|
TopLevelWindow::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) {
|
2018-04-14 02:04:23 +00:00
|
|
|
TopLevelWindow::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));
|
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) {
|
2018-12-22 01:49:26 +00:00
|
|
|
TopLevelWindow::ResetBrowserViews();
|
|
|
|
TopLevelWindow::AddBrowserView(value);
|
|
|
|
#if defined(OS_MACOSX)
|
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) {
|
|
|
|
TopLevelWindow::AddBrowserView(value);
|
|
|
|
#if defined(OS_MACOSX)
|
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) {
|
|
|
|
TopLevelWindow::RemoveBrowserView(value);
|
|
|
|
#if defined(OS_MACOSX)
|
2019-06-03 17:43:04 +00:00
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
2018-12-22 01:49:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::ResetBrowserViews() {
|
|
|
|
TopLevelWindow::ResetBrowserViews();
|
2018-03-19 18:45:42 +00:00
|
|
|
#if defined(OS_MACOSX)
|
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
|
|
|
}
|
|
|
|
|
2018-07-30 01:29:18 +00:00
|
|
|
TopLevelWindow::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-03-06 05:44:36 +00:00
|
|
|
// Convert draggable regions in raw format to SkRegion format.
|
|
|
|
std::unique_ptr<SkRegion> BrowserWindow::DraggableRegionsToSkRegion(
|
2019-06-03 17:43:04 +00:00
|
|
|
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
2018-06-18 07:32:55 +00:00
|
|
|
auto sk_region = std::make_unique<SkRegion>();
|
2019-06-03 17:43:04 +00:00
|
|
|
for (const auto& region : regions) {
|
2018-03-06 05:44:36 +00:00
|
|
|
sk_region->op(
|
2019-06-03 17:43:04 +00:00
|
|
|
region->bounds.x(), region->bounds.y(), region->bounds.right(),
|
|
|
|
region->bounds.bottom(),
|
|
|
|
region->draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
2018-03-06 05:44:36 +00:00
|
|
|
}
|
|
|
|
return sk_region;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
mate::WrappableBase* BrowserWindow::New(mate::Arguments* args) {
|
|
|
|
if (!Browser::Get()->is_ready()) {
|
|
|
|
args->ThrowError("Cannot create BrowserWindow before app is ready");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args->Length() > 1) {
|
|
|
|
args->ThrowError();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mate::Dictionary options;
|
|
|
|
if (!(args->Length() == 1 && args->GetNext(&options))) {
|
|
|
|
options = mate::Dictionary::CreateEmpty(args->isolate());
|
|
|
|
}
|
|
|
|
|
|
|
|
return new BrowserWindow(args->isolate(), args->GetThis(), options);
|
|
|
|
}
|
|
|
|
|
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) {
|
2016-08-02 10:28:12 +00:00
|
|
|
prototype->SetClassName(mate::StringToV8(isolate, "BrowserWindow"));
|
2016-08-02 09:08:12 +00:00
|
|
|
mate::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;
|
|
|
|
using electron::api::TopLevelWindow;
|
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();
|
2014-06-28 11:49:55 +00:00
|
|
|
mate::Dictionary dict(isolate, exports);
|
2019-04-28 01:03:06 +00:00
|
|
|
dict.Set("BrowserWindow",
|
|
|
|
mate::CreateConstructor<BrowserWindow>(
|
|
|
|
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
|
|
|
|
2019-03-08 18:29:52 +00:00
|
|
|
NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_window, Initialize)
|