refactor: remove InspectableWebContentsViewMac in favor of the Views version (#45238)

* refactor: remove InspectableWebContentsViewMac in favor of the Views version

* cherry-pick: refactor: remove InspectableWebContentsViewMac in favor of the Views version (#41326)

commit e67ab9a93d

Confilcts not resolved, except removal of the files removed
by the original commit.

* resolved conflicts and build issues after cherry-pick

* cherry-picked: fix: add method allowing to disable headless mode in native widget

https://github.com/electron/electron/pull/42996
fixing
https://github.com/electron/electron/issues/42995

* fix: displaying select popup in window created as fullscreen window

`constrainFrameRect:toScreen:` is not being call for windows created
with `fullscreen: true` therefore `headless` mode was not being removed
and `RenderWidgetHostNSViewBridge::DisplayPopupMenu` ignored displaying
popup.

Issue could be fixed by placing additional removal of `headless` mode
in the `toggleFullScreen:`, but `orderWindow:relativeTo:` is called
both for a regular and a fullscreen window, therefore there will be
a single place fixing both cases.

Because `electron::NativeWindowMac` lifetime may be shorter than
`ElectronNSWindow` on which macOS may execute `orderWindow:relativeTo:`
we need to clear `shell_` when `NativeWindow` is being closed.

Fixes #43010.

* fix: Content visibility when using `vibrancy`

We need to put `NSVisualEffectView` before `ViewsCompositorSuperview`
otherwise when using `vibrancy` in `BrowserWindow` `NSVisualEffectView`
will hide content displayed by the compositor.

Fixes #43003
Fixes #42336

In fact main issues reported in these tickets were not present after
cherry-picking original refactor switching to `views::WebView`, so
text could be selected and click event was properly generated. However
both issues testcases were using `vibrancy` and actual content was
invisible, because it was covered by the `NSVisualEffectView`.

* fix: EXCEPTION_ACCESS_VIOLATION crash on BrowserWindow.destroy()

Restored postponed deletion of the `NativeWindow`.

Restoration caused `DCHECK(new_parent_ui_layer->GetCompositor());` failure
in `BrowserCompositorMac::SetParentUiLayer` after the spec test:
`chrome extensions chrome.webRequest does not take precedence over Electron webRequest - http`
with stack:
```
7   Electron Framework 0x000000011fe07830 content::BrowserCompositorMac::SetParentUiLayer(ui::Layer*) + 628
8   Electron Framework 0x000000011fe0c154 content::RenderWidgetHostViewMac::SetParentUiLayer(ui::Layer*) + 220
9   Electron Framework 0x000000011fe226a8 content::WebContentsViewMac::CreateViewForWidget(content::RenderWidgetHost*) + 600
10  Electron Framework 0x000000011fd37e4c content::WebContentsImpl::CreateRenderWidgetHostViewForRenderManager(content::RenderViewHost*) + 164
11  Electron Framework 0x000000011fb32278 content::RenderFrameHostManager::CreateSpeculativeRenderFrame(content::SiteInstanceImpl*, bool, scoped_refptr<content::BrowsingContextState> const&) + 816
12  Electron Framework 0x000000011fb2ab8c content::RenderFrameHostManager::CreateSpeculativeRenderFrameHost(content::SiteInstanceImpl*, content::SiteInstanceImpl*, bool) + 1308
13  Electron Framework 0x000000011fb28598 content::RenderFrameHostManager::GetFrameHostForNavigation(content::NavigationRequest*, content::BrowsingContextGroupSwap*, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*) + 1796
14  Electron Framework 0x000000011fa78660 content::NavigationRequest::SelectFrameHostForOnRequestFailedInternal(bool, bool, std::__Cr::optional<std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>> const&) + 280
15  Electron Framework 0x000000011fa6a994 content::NavigationRequest::OnRequestFailedInternal(network::URLLoaderCompletionStatus const&, bool, std::__Cr::optional<std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>> const&, bo
+ 1008
16  Electron Framework 0x000000011fa7772c content::NavigationRequest::OnRequestFailed(network::URLLoaderCompletionStatus const&) + 72
17  Electron Framework 0x000000011f8554ac content::NavigationURLLoaderImpl::NotifyRequestFailed(network::URLLoaderCompletionStatus const&) + 248
```
This was probably the reason of removing `NativeWindow` immediately
in order to cleanup `views_host_` in `WebContentsViewMac` to prevent
using layer without compositor in `WebContentsViewMac::CreateViewForWidget`.

`[ElectronNSWindowDelegate windowWillClose:]` is deleting window host
and the compositor used by the `NativeWindow` therefore detach `NativeWindow`
contents from parent. This will clear `views_host_` and prevent failing
mentioned `DCHECK`.

Fixes #42975

* chore: Applied review suggestions

Co-authored-by: Michał Pichliński <michal.pichlinski@here.io>

* refactor: directly cleanup shell

Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Michał Pichliński <michal.pichlinski@here.io>
Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>
This commit is contained in:
trop[bot] 2025-01-23 11:54:15 +01:00 committed by GitHub
parent d77c2d75ed
commit 91bb748eaa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 378 additions and 951 deletions

View file

@ -159,12 +159,8 @@ filenames = {
"shell/browser/osr/osr_web_contents_view_mac.mm",
"shell/browser/relauncher_mac.cc",
"shell/browser/ui/certificate_trust_mac.mm",
"shell/browser/ui/cocoa/delayed_native_view_host.h",
"shell/browser/ui/cocoa/delayed_native_view_host.mm",
"shell/browser/ui/cocoa/electron_bundle_mover.h",
"shell/browser/ui/cocoa/electron_bundle_mover.mm",
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h",
"shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm",
"shell/browser/ui/cocoa/electron_menu_controller.h",
"shell/browser/ui/cocoa/electron_menu_controller.mm",
"shell/browser/ui/cocoa/electron_native_widget_mac.h",
@ -191,8 +187,6 @@ filenames = {
"shell/browser/ui/cocoa/window_buttons_proxy.mm",
"shell/browser/ui/drag_util_mac.mm",
"shell/browser/ui/file_dialog_mac.mm",
"shell/browser/ui/inspectable_web_contents_view_mac.h",
"shell/browser/ui/inspectable_web_contents_view_mac.mm",
"shell/browser/ui/message_box_mac.mm",
"shell/browser/ui/tray_icon_cocoa.h",
"shell/browser/ui/tray_icon_cocoa.mm",
@ -224,8 +218,6 @@ filenames = {
"shell/browser/ui/views/electron_views_delegate.h",
"shell/browser/ui/views/frameless_view.cc",
"shell/browser/ui/views/frameless_view.h",
"shell/browser/ui/views/inspectable_web_contents_view_views.cc",
"shell/browser/ui/views/inspectable_web_contents_view_views.h",
"shell/browser/ui/views/menu_bar.cc",
"shell/browser/ui/views/menu_bar.h",
"shell/browser/ui/views/menu_delegate.cc",

View file

@ -133,6 +133,8 @@ osr_shared_texture_remove_keyed_mutex_on_win_dxgi.patch
feat_allow_usage_of_sccontentsharingpicker_on_supported_platforms.patch
chore_partial_revert_of.patch
fix_software_compositing_infinite_loop.patch
fix_add_method_which_disables_headless_mode_on_native_widget.patch
fix_put_nsvisualeffectview_before_viewscompositorsuperview.patch
refactor_unfilter_unresponsive_events.patch
build_disable_thin_lto_mac.patch
build_add_public_config_simdutf_config.patch

View file

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cezary Kulakowski <cezary@openfin.co>
Date: Mon, 22 Jul 2024 16:23:13 +0200
Subject: fix: add method which disables headless mode on native widget
We need this method as we create window in headless mode and we
switch it back to normal mode only after inital paint is done in
order to get some events like WebContents.beginFrameSubscription.
If we don't set `is_headless_` to false then some child windows
e.g. autofill popups will be created in headless mode leading to
ui problems (like dissapearing popup during typing in html's
input list.
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index 30d0ea6633cb0f7f9aab37951a38be9b0482a12a..734e91e6d50c8d3afd20b39167c6254e934e7c1e 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -1144,6 +1144,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
// True if widget was created in headless mode.
bool is_headless() const { return is_headless_; }
+ void DisableHeadlessMode() { is_headless_ = false; }
+
// True if the window size will follow the content preferred size.
bool is_autosized() const { return is_autosized_; }

View file

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Pichli=C5=84ski?=
<michal.pichlinski@openfin.co>
Date: Tue, 29 Oct 2024 21:16:29 +0100
Subject: fix: Put NSVisualEffectView before ViewsCompositorSuperview
Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/6030552
Otherwise when using `vibrancy` in `BrowserWindow` NSVisualEffectView
will hide content displayed by the compositor.
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
index 07c3997e6565cf77362ee73959c4d21da4fefe96..3353a7847df90b58eec34ea4d6ff8fb19617f5cc 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -223,8 +223,19 @@ NSComparisonResult SubviewSorter(__kindof NSView* lhs,
void* rank_as_void) {
DCHECK_NE(lhs, rhs);
- if ([lhs isKindOfClass:[ViewsCompositorSuperview class]])
+
+ // Put NSVisualEffectView before ViewsCompositorSuperview otherwise when using
+ // `vibrancy` in `BrowserWindow` NSVisualEffectView will hide content
+ // displayed by the compositor.
+ if ([lhs isKindOfClass:[NSVisualEffectView class]]) {
return NSOrderedAscending;
+ }
+ if ([lhs isKindOfClass:[ViewsCompositorSuperview class]]) {
+ if ([rhs isKindOfClass:[NSVisualEffectView class]]) {
+ return NSOrderedDescending;
+ }
+ return NSOrderedAscending;
+ }
const RankMap* rank = static_cast<const RankMap*>(rank_as_void);
auto left_rank = rank->find(lhs);

View file

@ -27,29 +27,14 @@
#include "ui/views/view_class_properties.h"
#include "ui/views/widget/widget.h"
#if BUILDFLAG(IS_MAC)
#include "shell/browser/ui/cocoa/delayed_native_view_host.h"
#endif
namespace electron::api {
WebContentsView::WebContentsView(v8::Isolate* isolate,
gin::Handle<WebContents> web_contents)
#if BUILDFLAG(IS_MAC)
: View(new DelayedNativeViewHost(web_contents->inspectable_web_contents()
->GetView()
->GetNativeView())),
#else
: View(web_contents->inspectable_web_contents()->GetView()->GetView()),
#endif
: View(web_contents->inspectable_web_contents()->GetView()),
web_contents_(isolate, web_contents.ToV8()),
api_web_contents_(web_contents.get()) {
#if !BUILDFLAG(IS_MAC)
// On macOS the View is a newly-created |DelayedNativeViewHost| and it is our
// responsibility to delete it. On other platforms the View is created and
// managed by InspectableWebContents.
set_delete_view(false);
#endif
view()->SetProperty(
views::kFlexBehaviorKey,
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,

View file

@ -169,9 +169,6 @@ class NativeWindowMac : public NativeWindow,
void NotifyWindowDidFailToEnterFullScreen();
void NotifyWindowWillLeaveFullScreen();
// views::WidgetDelegate:
views::View* GetContentsView() override;
// Cleanup observers when window is getting closed. Note that the destructor
// can be called much later after window gets closed, so we should not do
// cleanup in destructor.
@ -223,6 +220,7 @@ class NativeWindowMac : public NativeWindow,
protected:
// views::WidgetDelegate:
views::View* GetContentsView() override;
bool CanMaximize() const override;
std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
views::Widget* widget) override;

View file

@ -194,6 +194,8 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
// Allow painting before shown, to be later disabled in ElectronNSWindow.
params.headless_mode = true;
params.native_widget =
new ElectronNativeWidgetMac(this, windowType, styleMask, widget());
widget()->Init(std::move(params));
@ -1674,6 +1676,7 @@ void NativeWindowMac::Cleanup() {
DCHECK(!IsClosed());
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
display::Screen::GetScreen()->RemoveObserver(this);
[window_ cleanup];
}
class NativeAppWindowFrameViewMac : public views::NativeFrameViewMac {

View file

@ -27,6 +27,7 @@
#include "content/public/browser/desktop_media_id.h"
#include "content/public/common/color_parser.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include "shell/browser/ui/views/root_view.h"
#include "shell/browser/web_contents_preferences.h"
#include "shell/browser/web_view_manager.h"

View file

@ -1,33 +0,0 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_BROWSER_UI_COCOA_DELAYED_NATIVE_VIEW_HOST_H_
#define ELECTRON_SHELL_BROWSER_UI_COCOA_DELAYED_NATIVE_VIEW_HOST_H_
#include "ui/views/controls/native/native_view_host.h"
namespace electron {
// Automatically attach the native view after the NativeViewHost is attached to
// a widget. (Attaching it directly would cause crash.)
class DelayedNativeViewHost : public views::NativeViewHost {
public:
explicit DelayedNativeViewHost(gfx::NativeView native_view);
~DelayedNativeViewHost() override;
// disable copy
DelayedNativeViewHost(const DelayedNativeViewHost&) = delete;
DelayedNativeViewHost& operator=(const DelayedNativeViewHost&) = delete;
// views::View:
void ViewHierarchyChanged(
const views::ViewHierarchyChangedDetails& details) override;
private:
gfx::NativeView native_view_;
};
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_UI_COCOA_DELAYED_NATIVE_VIEW_HOST_H_

View file

@ -1,23 +0,0 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/ui/cocoa/delayed_native_view_host.h"
namespace electron {
DelayedNativeViewHost::DelayedNativeViewHost(gfx::NativeView native_view)
: native_view_(native_view) {}
DelayedNativeViewHost::~DelayedNativeViewHost() = default;
void DelayedNativeViewHost::ViewHierarchyChanged(
const views::ViewHierarchyChangedDetails& details) {
if (!details.is_add && native_view())
Detach();
NativeViewHost::ViewHierarchyChanged(details);
if (details.is_add && GetWidget() && !native_view())
Attach(native_view_);
}
} // namespace electron

View file

@ -1,54 +0,0 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#define ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#import <AppKit/AppKit.h>
#include "base/apple/owned_objc.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
#include "ui/base/cocoa/base_view.h"
namespace electron {
class InspectableWebContentsViewMac;
}
using electron::InspectableWebContentsViewMac;
@interface NSView (WebContentsView)
- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
@end
@interface ElectronInspectableWebContentsView : BaseView <NSWindowDelegate> {
@private
raw_ptr<electron::InspectableWebContentsViewMac> inspectableWebContentsView_;
NSView* __strong fake_view_;
NSWindow* __strong devtools_window_;
BOOL devtools_visible_;
BOOL devtools_docked_;
BOOL devtools_is_first_responder_;
BOOL attached_to_window_;
DevToolsContentsResizingStrategy strategy_;
}
- (instancetype)initWithInspectableWebContentsViewMac:
(InspectableWebContentsViewMac*)view;
- (void)notifyDevToolsFocused;
- (void)setCornerRadii:(CGFloat)cornerRadius;
- (void)setDevToolsVisible:(BOOL)visible activate:(BOOL)activate;
- (BOOL)isDevToolsVisible;
- (BOOL)isDevToolsFocused;
- (void)setIsDocked:(BOOL)docked activate:(BOOL)activate;
- (void)setContentsResizingStrategy:
(const DevToolsContentsResizingStrategy&)strategy;
- (void)setTitle:(NSString*)title;
- (NSString*)getTitle;
@end
#endif // ELECTRON_SHELL_BROWSER_UI_COCOA_ELECTRON_INSPECTABLE_WEB_CONTENTS_VIEW_H_

View file

@ -1,337 +0,0 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
#include "content/public/browser/render_widget_host_view.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/ui/cocoa/event_dispatching_window.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
#include "shell/browser/ui/inspectable_web_contents_view_mac.h"
#include "ui/base/cocoa/base_view.h"
#include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
@implementation ElectronInspectableWebContentsView
- (instancetype)initWithInspectableWebContentsViewMac:
(InspectableWebContentsViewMac*)view {
self = [super init];
if (!self)
return nil;
inspectableWebContentsView_ = view;
devtools_visible_ = NO;
devtools_docked_ = NO;
devtools_is_first_responder_ = NO;
attached_to_window_ = NO;
if (inspectableWebContentsView_->inspectable_web_contents()->is_guest()) {
fake_view_ = [[NSView alloc] init];
[fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:fake_view_];
} else {
auto* contents = inspectableWebContentsView_->inspectable_web_contents()
->GetWebContents();
auto* contentsView = contents->GetNativeView().GetNativeNSView();
[contentsView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:contentsView];
}
// See https://code.google.com/p/chromium/issues/detail?id=348490.
[self setWantsLayer:YES];
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
[self adjustSubviews];
}
- (void)viewDidMoveToWindow {
if (attached_to_window_ && !self.window) {
attached_to_window_ = NO;
[[NSNotificationCenter defaultCenter] removeObserver:self];
} else if (!attached_to_window_ && self.window) {
attached_to_window_ = YES;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(viewDidBecomeFirstResponder:)
name:kViewDidBecomeFirstResponder
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(parentWindowBecameMain:)
name:NSWindowDidBecomeMainNotification
object:nil];
}
}
- (IBAction)showDevTools:(id)sender {
inspectableWebContentsView_->inspectable_web_contents()->ShowDevTools(true);
}
- (void)notifyDevToolsFocused {
if (inspectableWebContentsView_->GetDelegate())
inspectableWebContentsView_->GetDelegate()->DevToolsFocused();
}
- (void)setCornerRadii:(CGFloat)cornerRadius {
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
DCHECK(inspectable_web_contents);
auto* webContents = inspectable_web_contents->GetWebContents();
if (!webContents)
return;
auto* webContentsView = webContents->GetNativeView().GetNativeNSView();
webContentsView.wantsLayer = YES;
webContentsView.layer.cornerRadius = cornerRadius;
}
- (void)notifyDevToolsResized {
// When devtools is opened, resizing devtools would not trigger
// UpdateDraggableRegions for WebContents, so we have to notify the window
// to do an update of draggable regions.
if (inspectableWebContentsView_->GetDelegate())
inspectableWebContentsView_->GetDelegate()->DevToolsResized();
}
- (void)setDevToolsVisible:(BOOL)visible activate:(BOOL)activate {
if (visible == devtools_visible_)
return;
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
auto* devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
devtools_visible_ = visible;
if (devtools_docked_) {
if (visible) {
// Place the devToolsView under contentsView, notice that we didn't set
// sizes for them until the setContentsResizingStrategy message.
[self addSubview:devToolsView positioned:NSWindowBelow relativeTo:nil];
[self adjustSubviews];
// Focus on web view.
devToolsWebContents->RestoreFocus();
} else {
gfx::ScopedCocoaDisableScreenUpdates disabler;
[devToolsView removeFromSuperview];
[self adjustSubviews];
[self notifyDevToolsResized];
}
} else {
if (visible) {
if (activate) {
[devtools_window_ makeKeyAndOrderFront:nil];
} else {
[devtools_window_ orderBack:nil];
}
} else {
[devtools_window_ setDelegate:nil];
[devtools_window_ close];
devtools_window_ = nil;
}
}
}
- (BOOL)isDevToolsVisible {
return devtools_visible_;
}
- (BOOL)isDevToolsFocused {
if (devtools_docked_) {
return [[self window] isKeyWindow] && devtools_is_first_responder_;
} else {
return [devtools_window_ isKeyWindow];
}
}
// TODO: remove NSWindowStyleMaskTexturedBackground.
// https://github.com/electron/electron/issues/43125
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (void)setIsDocked:(BOOL)docked activate:(BOOL)activate {
// Revert to no-devtools state.
[self setDevToolsVisible:NO activate:NO];
// Switch to new state.
devtools_docked_ = docked;
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
if (!docked) {
auto styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskResizable |
NSWindowStyleMaskTexturedBackground |
NSWindowStyleMaskUnifiedTitleAndToolbar;
devtools_window_ = [[EventDispatchingWindow alloc]
initWithContentRect:NSMakeRect(0, 0, 800, 600)
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:YES];
[devtools_window_ setDelegate:self];
[devtools_window_ setFrameAutosaveName:@"electron.devtools"];
[devtools_window_ setTitle:@"Developer Tools"];
[devtools_window_ setReleasedWhenClosed:NO];
[devtools_window_ setAutorecalculatesContentBorderThickness:NO
forEdge:NSMaxYEdge];
[devtools_window_ setContentBorderThickness:24 forEdge:NSMaxYEdge];
NSView* contentView = [devtools_window_ contentView];
devToolsView.frame = contentView.bounds;
devToolsView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[contentView addSubview:devToolsView];
[devToolsView setMouseDownCanMoveWindow:NO];
} else {
[devToolsView setMouseDownCanMoveWindow:YES];
}
[self setDevToolsVisible:YES activate:activate];
}
// -Wdeprecated-declarations
#pragma clang diagnostic pop
- (void)setContentsResizingStrategy:
(const DevToolsContentsResizingStrategy&)strategy {
strategy_.CopyFrom(strategy);
[self adjustSubviews];
}
- (void)adjustSubviews {
if (![[self subviews] count])
return;
if (![self isDevToolsVisible] || devtools_window_) {
DCHECK_EQ(1u, [[self subviews] count]);
NSView* contents = [[self subviews] objectAtIndex:0];
[contents setFrame:[self bounds]];
return;
}
NSView* devToolsView = [[self subviews] objectAtIndex:0];
NSView* contentsView = [[self subviews] objectAtIndex:1];
DCHECK_EQ(2u, [[self subviews] count]);
gfx::Rect new_devtools_bounds;
gfx::Rect new_contents_bounds;
ApplyDevToolsContentsResizingStrategy(
strategy_, gfx::Size(NSSizeToCGSize([self bounds].size)),
&new_devtools_bounds, &new_contents_bounds);
[devToolsView setFrame:[self flipRectToNSRect:new_devtools_bounds]];
[contentsView setFrame:[self flipRectToNSRect:new_contents_bounds]];
// Move mask to the devtools area to exclude it from dragging.
NSRect cf = contentsView.frame;
NSRect sb = [self bounds];
NSRect devtools_frame;
if (cf.size.height < sb.size.height) { // bottom docked
devtools_frame.origin.x = 0;
devtools_frame.origin.y = 0;
devtools_frame.size.width = sb.size.width;
devtools_frame.size.height = sb.size.height - cf.size.height;
} else { // left or right docked
if (cf.origin.x > 0) // left docked
devtools_frame.origin.x = 0;
else // right docked.
devtools_frame.origin.x = cf.size.width;
devtools_frame.origin.y = 0;
devtools_frame.size.width = sb.size.width - cf.size.width;
devtools_frame.size.height = sb.size.height;
}
[self notifyDevToolsResized];
}
- (void)setTitle:(NSString*)title {
[devtools_window_ setTitle:title];
}
- (NSString*)getTitle {
return [devtools_window_ title];
}
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification {
auto* inspectable_web_contents =
inspectableWebContentsView_->inspectable_web_contents();
DCHECK(inspectable_web_contents);
auto* webContents = inspectable_web_contents->GetWebContents();
if (!webContents)
return;
auto* webContentsView = webContents->GetNativeView().GetNativeNSView();
NSView* view = [notification object];
if ([[webContentsView subviews] containsObject:view]) {
devtools_is_first_responder_ = NO;
return;
}
auto* devToolsWebContents =
inspectable_web_contents->GetDevToolsWebContents();
if (!devToolsWebContents)
return;
auto devToolsView = devToolsWebContents->GetNativeView().GetNativeNSView();
if ([[devToolsView subviews] containsObject:view]) {
devtools_is_first_responder_ = YES;
[self notifyDevToolsFocused];
}
}
- (void)parentWindowBecameMain:(NSNotification*)notification {
NSWindow* parentWindow = [notification object];
if ([self window] == parentWindow && devtools_docked_ &&
devtools_is_first_responder_)
[self notifyDevToolsFocused];
}
#pragma mark - NSWindowDelegate
- (void)windowWillClose:(NSNotification*)notification {
inspectableWebContentsView_->inspectable_web_contents()->CloseDevTools();
}
- (void)windowDidBecomeMain:(NSNotification*)notification {
content::WebContents* web_contents =
inspectableWebContentsView_->inspectable_web_contents()
->GetDevToolsWebContents();
if (!web_contents)
return;
web_contents->RestoreFocus();
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
if (rwhv)
rwhv->SetActive(true);
[self notifyDevToolsFocused];
}
- (void)windowDidResignMain:(NSNotification*)notification {
content::WebContents* web_contents =
inspectableWebContentsView_->inspectable_web_contents()
->GetDevToolsWebContents();
if (!web_contents)
return;
web_contents->StoreFocus();
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
if (rwhv)
rwhv->SetActive(false);
}
@end

View file

@ -29,6 +29,8 @@ class ScopedDisableResize {
} // namespace electron
class ElectronNativeWindowObserver;
@interface ElectronNSWindow : NativeWidgetMacNSWindow {
@private
raw_ptr<electron::NativeWindowMac> shell_;
@ -41,6 +43,7 @@ class ScopedDisableResize {
@property(nonatomic, retain) NSImage* cornerMask;
- (id)initWithShell:(electron::NativeWindowMac*)shell
styleMask:(NSUInteger)styleMask;
- (void)cleanup;
- (electron::NativeWindowMac*)shell;
- (id)accessibilityFocusedUIElement;
- (NSRect)originalContentRectForFrameRect:(NSRect)frameRect;

View file

@ -8,8 +8,6 @@
#include "electron/mas.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/native_window_mac.h"
#include "shell/browser/ui/cocoa/delayed_native_view_host.h"
#include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
#include "shell/browser/ui/cocoa/electron_preview_item.h"
#include "shell/browser/ui/cocoa/electron_touch_bar.h"
#include "shell/browser/ui/cocoa/root_view_mac.h"
@ -113,6 +111,7 @@ void SwizzleSwipeWithEvent(NSView* view, SEL swiz_selector) {
method_getImplementation(new_swipe_with_event));
}
#endif
} // namespace
@implementation ElectronNSWindow
@ -168,6 +167,10 @@ void SwizzleSwipeWithEvent(NSView* view, SEL swiz_selector) {
return self;
}
- (void)cleanup {
shell_ = nullptr;
}
- (electron::NativeWindowMac*)shell {
return shell_;
}
@ -255,6 +258,17 @@ void SwizzleSwipeWithEvent(NSView* view, SEL swiz_selector) {
[super setFrame:windowFrame display:displayViews];
}
- (void)orderWindow:(NSWindowOrderingMode)place relativeTo:(NSInteger)otherWin {
if (shell_) {
// We initialize the window in headless mode to allow painting before it is
// shown, but we don't want the headless behavior of allowing the window to
// be placed unconstrained.
self.isHeadless = false;
shell_->widget()->DisableHeadlessMode();
}
[super orderWindow:place relativeTo:otherWin];
}
- (id)accessibilityAttributeValue:(NSString*)attribute {
if ([attribute isEqual:NSAccessibilityEnabledAttribute])
return [NSNumber numberWithBool:YES];

View file

@ -365,6 +365,19 @@ using FullScreenTransitionState =
shell_->GetNativeWindow());
auto* bridged_view = bridge_host->GetInProcessNSWindowBridge();
bridged_view->OnWindowWillClose();
// Native widget and its compositor have been destroyed upon close. We need
// to detach contents view in order to prevent reusing its layer without
// compositor in the `WebContentsViewMac::CreateViewForWidget`, leading to
// `DCHECK` failure in `BrowserCompositorMac::SetParentUiLayer`.
auto* contents_view =
static_cast<views::WidgetDelegate*>(shell_)->GetContentsView();
if (contents_view) {
auto* parent = contents_view->parent();
if (parent) {
parent->RemoveChildView(contents_view);
}
}
}
- (BOOL)windowShouldClose:(id)window {

View file

@ -297,11 +297,6 @@ class InspectableWebContents::NetworkResourceLoader
base::TimeDelta retry_delay_;
};
// Implemented separately on each platform.
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContents* inspectable_web_contents);
// static
// static
void InspectableWebContents::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(kDevToolsBoundsPref,
@ -317,7 +312,7 @@ InspectableWebContents::InspectableWebContents(
: pref_service_(pref_service),
web_contents_(std::move(web_contents)),
is_guest_(is_guest),
view_(CreateInspectableContentsView(this)) {
view_(new InspectableWebContentsView(this)) {
const base::Value* bounds_dict =
&pref_service_->GetValue(kDevToolsBoundsPref);
if (bounds_dict->is_dict()) {

View file

@ -5,12 +5,250 @@
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include <memory>
#include <utility>
#include "base/memory/raw_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "shell/browser/ui/drag_util.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_delegate.h"
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
#include "ui/base/models/image_model.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
namespace electron {
namespace {
class DevToolsWindowDelegate : public views::ClientView,
public views::WidgetDelegate {
public:
DevToolsWindowDelegate(InspectableWebContentsView* shell,
views::View* view,
views::Widget* widget)
: views::ClientView(widget, view),
shell_(shell),
view_(view),
widget_(widget) {
SetOwnedByWidget(true);
set_owned_by_client();
if (shell->GetDelegate())
icon_ = shell->GetDelegate()->GetDevToolsWindowIcon();
}
~DevToolsWindowDelegate() override = default;
// disable copy
DevToolsWindowDelegate(const DevToolsWindowDelegate&) = delete;
DevToolsWindowDelegate& operator=(const DevToolsWindowDelegate&) = delete;
// views::WidgetDelegate:
views::View* GetInitiallyFocusedView() override { return view_; }
std::u16string GetWindowTitle() const override { return shell_->GetTitle(); }
ui::ImageModel GetWindowAppIcon() override { return GetWindowIcon(); }
ui::ImageModel GetWindowIcon() override { return icon_; }
views::Widget* GetWidget() override { return widget_; }
const views::Widget* GetWidget() const override { return widget_; }
views::View* GetContentsView() override { return view_; }
views::ClientView* CreateClientView(views::Widget* widget) override {
return this;
}
// views::ClientView:
views::CloseRequestResult OnWindowCloseRequested() override {
shell_->inspectable_web_contents()->CloseDevTools();
return views::CloseRequestResult::kCannotClose;
}
private:
raw_ptr<InspectableWebContentsView> shell_;
raw_ptr<views::View> view_;
raw_ptr<views::Widget> widget_;
ui::ImageModel icon_;
};
} // namespace
InspectableWebContentsView::InspectableWebContentsView(
InspectableWebContents* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents) {}
: inspectable_web_contents_(inspectable_web_contents),
devtools_web_view_(new views::WebView(nullptr)),
title_(u"Developer Tools") {
if (!inspectable_web_contents_->is_guest() &&
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
auto* contents_web_view = new views::WebView(nullptr);
contents_web_view->SetWebContents(
inspectable_web_contents_->GetWebContents());
contents_web_view_ = contents_web_view;
} else {
no_contents_view_ = new views::Label(u"No content under offscreen mode");
}
InspectableWebContentsView::~InspectableWebContentsView() = default;
devtools_web_view_->SetVisible(false);
AddChildView(devtools_web_view_.get());
AddChildView(GetContentsView());
}
InspectableWebContentsView::~InspectableWebContentsView() {
if (devtools_window_)
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());
}
void InspectableWebContentsView::SetCornerRadii(
const gfx::RoundedCornersF& corner_radii) {
// WebView won't exist for offscreen rendering.
if (contents_web_view_) {
contents_web_view_->holder()->SetCornerRadii(corner_radii);
}
}
void InspectableWebContentsView::ShowDevTools(bool activate) {
if (devtools_visible_)
return;
devtools_visible_ = true;
if (devtools_window_) {
devtools_window_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_window_->SetBounds(inspectable_web_contents()->dev_tools_bounds());
if (activate) {
devtools_window_->Show();
} else {
devtools_window_->ShowInactive();
}
// Update draggable regions to account for the new dock position.
if (GetDelegate())
GetDelegate()->DevToolsResized();
} else {
devtools_web_view_->SetVisible(true);
devtools_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_web_view_->RequestFocus();
DeprecatedLayoutImmediately();
}
}
void InspectableWebContentsView::CloseDevTools() {
if (!devtools_visible_)
return;
devtools_visible_ = false;
if (devtools_window_) {
auto save_bounds = devtools_window_->IsMinimized()
? devtools_window_->GetRestoredBounds()
: devtools_window_->GetWindowBoundsInScreen();
inspectable_web_contents()->SaveDevToolsBounds(save_bounds);
devtools_window_.reset();
devtools_window_web_view_ = nullptr;
devtools_window_delegate_ = nullptr;
} else {
devtools_web_view_->SetVisible(false);
devtools_web_view_->SetWebContents(nullptr);
DeprecatedLayoutImmediately();
}
}
bool InspectableWebContentsView::IsDevToolsViewShowing() {
return devtools_visible_;
}
bool InspectableWebContentsView::IsDevToolsViewFocused() {
if (devtools_window_web_view_)
return devtools_window_web_view_->HasFocus();
else if (devtools_web_view_)
return devtools_web_view_->HasFocus();
else
return false;
}
void InspectableWebContentsView::SetIsDocked(bool docked, bool activate) {
CloseDevTools();
if (!docked) {
devtools_window_ = std::make_unique<views::Widget>();
devtools_window_web_view_ = new views::WebView(nullptr);
devtools_window_delegate_ = new DevToolsWindowDelegate(
this, devtools_window_web_view_, devtools_window_.get());
views::Widget::InitParams params(
views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET,
views::Widget::InitParams::TYPE_WINDOW);
params.delegate = devtools_window_delegate_;
params.bounds = inspectable_web_contents()->dev_tools_bounds();
#if BUILDFLAG(IS_LINUX)
params.wm_role_name = "devtools";
if (GetDelegate())
GetDelegate()->GetDevToolsWindowWMClass(&params.wm_class_name,
&params.wm_class_class);
#endif
devtools_window_->Init(std::move(params));
devtools_window_->UpdateWindowIcon();
devtools_window_->widget_delegate()->SetHasWindowSizeControls(true);
}
ShowDevTools(activate);
}
void InspectableWebContentsView::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
strategy_.CopyFrom(strategy);
DeprecatedLayoutImmediately();
}
void InspectableWebContentsView::SetTitle(const std::u16string& title) {
if (devtools_window_) {
title_ = title;
devtools_window_->UpdateWindowTitle();
}
}
const std::u16string InspectableWebContentsView::GetTitle() {
return title_;
}
void InspectableWebContentsView::Layout(PassKey) {
if (!devtools_web_view_->GetVisible()) {
GetContentsView()->SetBoundsRect(GetContentsBounds());
// Propagate layout call to all children, for example browser views.
LayoutSuperclass<View>(this);
return;
}
gfx::Size container_size(width(), height());
gfx::Rect new_devtools_bounds;
gfx::Rect new_contents_bounds;
ApplyDevToolsContentsResizingStrategy(
strategy_, container_size, &new_devtools_bounds, &new_contents_bounds);
// DevTools cares about the specific position, so we have to compensate RTL
// layout here.
new_devtools_bounds.set_x(GetMirroredXForRect(new_devtools_bounds));
new_contents_bounds.set_x(GetMirroredXForRect(new_contents_bounds));
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
GetContentsView()->SetBoundsRect(new_contents_bounds);
// Propagate layout call to all children, for example browser views.
LayoutSuperclass<View>(this);
if (GetDelegate())
GetDelegate()->DevToolsResized();
}
views::View* InspectableWebContentsView::GetContentsView() const {
DCHECK(contents_web_view_ || no_contents_view_);
return contents_web_view_ ? contents_web_view_ : no_contents_view_;
}
} // namespace electron

View file

@ -9,13 +9,9 @@
#include <string>
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_MAC)
#include "ui/views/view.h"
#else
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
#include "ui/gfx/native_widget_types.h"
#endif
#include "ui/views/view.h"
class DevToolsContentsResizingStrategy;
@ -23,23 +19,22 @@ namespace gfx {
class RoundedCornersF;
} // namespace gfx
#if defined(TOOLKIT_VIEWS)
namespace views {
class View;
class WebView;
class Widget;
class WidgetDelegate;
} // namespace views
#endif
namespace electron {
class InspectableWebContents;
class InspectableWebContentsViewDelegate;
class InspectableWebContentsView {
class InspectableWebContentsView : public views::View {
public:
explicit InspectableWebContentsView(
InspectableWebContents* inspectable_web_contents);
virtual ~InspectableWebContentsView();
~InspectableWebContentsView() override;
InspectableWebContents* inspectable_web_contents() {
return inspectable_web_contents_;
@ -51,32 +46,40 @@ class InspectableWebContentsView {
}
InspectableWebContentsViewDelegate* GetDelegate() const { return delegate_; }
#if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_MAC)
// Returns the container control, which has devtools view attached.
virtual views::View* GetView() = 0;
#else
virtual gfx::NativeView GetNativeView() const = 0;
#endif
void SetCornerRadii(const gfx::RoundedCornersF& corner_radii);
virtual void ShowDevTools(bool activate) = 0;
virtual void SetCornerRadii(const gfx::RoundedCornersF& corner_radii) = 0;
// Hide the DevTools view.
virtual void CloseDevTools() = 0;
virtual bool IsDevToolsViewShowing() = 0;
virtual bool IsDevToolsViewFocused() = 0;
virtual void SetIsDocked(bool docked, bool activate) = 0;
virtual void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) = 0;
virtual void SetTitle(const std::u16string& title) = 0;
virtual const std::u16string GetTitle() = 0;
void ShowDevTools(bool activate);
void CloseDevTools();
bool IsDevToolsViewShowing();
bool IsDevToolsViewFocused();
void SetIsDocked(bool docked, bool activate);
void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy);
void SetTitle(const std::u16string& title);
const std::u16string GetTitle();
// views::View:
void Layout(PassKey) override;
private:
views::View* GetContentsView() const;
protected:
// Owns us.
raw_ptr<InspectableWebContents> inspectable_web_contents_;
private:
raw_ptr<InspectableWebContentsViewDelegate> delegate_ =
nullptr; // weak references.
std::unique_ptr<views::Widget> devtools_window_;
raw_ptr<views::WebView> devtools_window_web_view_ = nullptr;
raw_ptr<views::WebView> contents_web_view_ = nullptr;
raw_ptr<views::View> no_contents_view_ = nullptr;
raw_ptr<views::WebView> devtools_web_view_ = nullptr;
DevToolsContentsResizingStrategy strategy_;
bool devtools_visible_ = false;
raw_ptr<views::WidgetDelegate> devtools_window_delegate_ = nullptr;
std::u16string title_;
};
} // namespace electron

View file

@ -1,42 +0,0 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ELECTRON_SHELL_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_
#define ELECTRON_SHELL_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_
#include "shell/browser/ui/inspectable_web_contents_view.h"
@class ElectronInspectableWebContentsView;
namespace electron {
class InspectableWebContentsViewMac : public InspectableWebContentsView {
public:
explicit InspectableWebContentsViewMac(
InspectableWebContents* inspectable_web_contents);
InspectableWebContentsViewMac(const InspectableWebContentsViewMac&) = delete;
InspectableWebContentsViewMac& operator=(
const InspectableWebContentsViewMac&) = delete;
~InspectableWebContentsViewMac() override;
gfx::NativeView GetNativeView() const override;
void SetCornerRadii(const gfx::RoundedCornersF& corner_radii) override;
void ShowDevTools(bool activate) override;
void CloseDevTools() override;
bool IsDevToolsViewShowing() override;
bool IsDevToolsViewFocused() override;
void SetIsDocked(bool docked, bool activate) override;
void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) override;
void SetTitle(const std::u16string& title) override;
const std::u16string GetTitle() override;
private:
ElectronInspectableWebContentsView* __strong view_;
};
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_

View file

@ -1,75 +0,0 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#include "shell/browser/ui/inspectable_web_contents_view_mac.h"
#include "base/strings/sys_string_conversions.h"
#import "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
namespace electron {
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContents* inspectable_web_contents) {
return new InspectableWebContentsViewMac(inspectable_web_contents);
}
InspectableWebContentsViewMac::InspectableWebContentsViewMac(
InspectableWebContents* inspectable_web_contents)
: InspectableWebContentsView(inspectable_web_contents),
view_([[ElectronInspectableWebContentsView alloc]
initWithInspectableWebContentsViewMac:this]) {}
InspectableWebContentsViewMac::~InspectableWebContentsViewMac() {
[[NSNotificationCenter defaultCenter] removeObserver:view_];
CloseDevTools();
}
gfx::NativeView InspectableWebContentsViewMac::GetNativeView() const {
return view_;
}
void InspectableWebContentsViewMac::SetCornerRadii(
const gfx::RoundedCornersF& corner_radii) {
// We can assume all four values are identical.
[view_ setCornerRadii:corner_radii.upper_left()];
}
void InspectableWebContentsViewMac::ShowDevTools(bool activate) {
[view_ setDevToolsVisible:YES activate:activate];
}
void InspectableWebContentsViewMac::CloseDevTools() {
[view_ setDevToolsVisible:NO activate:NO];
}
bool InspectableWebContentsViewMac::IsDevToolsViewShowing() {
return [view_ isDevToolsVisible];
}
bool InspectableWebContentsViewMac::IsDevToolsViewFocused() {
return [view_ isDevToolsFocused];
}
void InspectableWebContentsViewMac::SetIsDocked(bool docked, bool activate) {
[view_ setIsDocked:docked activate:activate];
}
void InspectableWebContentsViewMac::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
[view_ setContentsResizingStrategy:strategy];
}
void InspectableWebContentsViewMac::SetTitle(const std::u16string& title) {
[view_ setTitle:base::SysUTF16ToNSString(title)];
}
const std::u16string InspectableWebContentsViewMac::GetTitle() {
return base::SysNSStringToUTF16([view_ getTitle]);
}
} // namespace electron

View file

@ -5,6 +5,8 @@
#include "shell/browser/ui/views/frameless_view.h"
#include "shell/browser/native_window_views.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include "ui/aura/window.h"
#include "ui/base/hit_test.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/views/widget/widget.h"

View file

@ -1,257 +0,0 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#include "shell/browser/ui/views/inspectable_web_contents_view_views.h"
#include <memory>
#include <utility>
#include "base/memory/raw_ptr.h"
#include "shell/browser/ui/drag_util.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_delegate.h"
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
#include "ui/base/models/image_model.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
namespace electron {
namespace {
class DevToolsWindowDelegate : public views::ClientView,
public views::WidgetDelegate {
public:
DevToolsWindowDelegate(InspectableWebContentsViewViews* shell,
views::View* view,
views::Widget* widget)
: views::ClientView(widget, view),
shell_(shell),
view_(view),
widget_(widget) {
SetOwnedByWidget(true);
set_owned_by_client();
if (shell->GetDelegate())
icon_ = shell->GetDelegate()->GetDevToolsWindowIcon();
}
~DevToolsWindowDelegate() override = default;
// disable copy
DevToolsWindowDelegate(const DevToolsWindowDelegate&) = delete;
DevToolsWindowDelegate& operator=(const DevToolsWindowDelegate&) = delete;
// views::WidgetDelegate:
views::View* GetInitiallyFocusedView() override { return view_; }
std::u16string GetWindowTitle() const override { return shell_->GetTitle(); }
ui::ImageModel GetWindowAppIcon() override { return GetWindowIcon(); }
ui::ImageModel GetWindowIcon() override { return icon_; }
views::Widget* GetWidget() override { return widget_; }
const views::Widget* GetWidget() const override { return widget_; }
views::View* GetContentsView() override { return view_; }
views::ClientView* CreateClientView(views::Widget* widget) override {
return this;
}
// views::ClientView:
views::CloseRequestResult OnWindowCloseRequested() override {
shell_->inspectable_web_contents()->CloseDevTools();
return views::CloseRequestResult::kCannotClose;
}
private:
raw_ptr<InspectableWebContentsViewViews> shell_;
raw_ptr<views::View> view_;
raw_ptr<views::Widget> widget_;
ui::ImageModel icon_;
};
} // namespace
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContents* inspectable_web_contents) {
return new InspectableWebContentsViewViews(inspectable_web_contents);
}
InspectableWebContentsViewViews::InspectableWebContentsViewViews(
InspectableWebContents* inspectable_web_contents)
: InspectableWebContentsView(inspectable_web_contents),
devtools_web_view_(new views::WebView(nullptr)),
title_(u"Developer Tools") {
if (!inspectable_web_contents_->is_guest() &&
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
auto* contents_web_view = new views::WebView(nullptr);
contents_web_view->SetWebContents(
inspectable_web_contents_->GetWebContents());
contents_view_ = contents_web_view_ = contents_web_view;
} else {
contents_view_ = new views::Label(u"No content under offscreen mode");
}
devtools_web_view_->SetVisible(false);
AddChildView(devtools_web_view_.get());
AddChildView(contents_view_.get());
}
InspectableWebContentsViewViews::~InspectableWebContentsViewViews() {
if (devtools_window_)
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());
}
views::View* InspectableWebContentsViewViews::GetView() {
return this;
}
void InspectableWebContentsViewViews::SetCornerRadii(
const gfx::RoundedCornersF& corner_radii) {
// WebView won't exist for offscreen rendering.
if (contents_web_view_) {
contents_web_view_->holder()->SetCornerRadii(
gfx::RoundedCornersF(corner_radii));
}
}
void InspectableWebContentsViewViews::ShowDevTools(bool activate) {
if (devtools_visible_)
return;
devtools_visible_ = true;
if (devtools_window_) {
devtools_window_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_window_->SetBounds(inspectable_web_contents()->dev_tools_bounds());
if (activate) {
devtools_window_->Show();
} else {
devtools_window_->ShowInactive();
}
// Update draggable regions to account for the new dock position.
if (GetDelegate())
GetDelegate()->DevToolsResized();
} else {
devtools_web_view_->SetVisible(true);
devtools_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_web_view_->RequestFocus();
DeprecatedLayoutImmediately();
}
}
void InspectableWebContentsViewViews::CloseDevTools() {
if (!devtools_visible_)
return;
devtools_visible_ = false;
if (devtools_window_) {
auto save_bounds = devtools_window_->IsMinimized()
? devtools_window_->GetRestoredBounds()
: devtools_window_->GetWindowBoundsInScreen();
inspectable_web_contents()->SaveDevToolsBounds(save_bounds);
devtools_window_.reset();
devtools_window_web_view_ = nullptr;
devtools_window_delegate_ = nullptr;
} else {
devtools_web_view_->SetVisible(false);
devtools_web_view_->SetWebContents(nullptr);
DeprecatedLayoutImmediately();
}
}
bool InspectableWebContentsViewViews::IsDevToolsViewShowing() {
return devtools_visible_;
}
bool InspectableWebContentsViewViews::IsDevToolsViewFocused() {
if (devtools_window_web_view_)
return devtools_window_web_view_->HasFocus();
else if (devtools_web_view_)
return devtools_web_view_->HasFocus();
else
return false;
}
void InspectableWebContentsViewViews::SetIsDocked(bool docked, bool activate) {
CloseDevTools();
if (!docked) {
devtools_window_ = std::make_unique<views::Widget>();
devtools_window_web_view_ = new views::WebView(nullptr);
devtools_window_delegate_ = new DevToolsWindowDelegate(
this, devtools_window_web_view_, devtools_window_.get());
views::Widget::InitParams params{
views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET};
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = devtools_window_delegate_;
params.bounds = inspectable_web_contents()->dev_tools_bounds();
#if BUILDFLAG(IS_LINUX)
params.wm_role_name = "devtools";
if (GetDelegate())
GetDelegate()->GetDevToolsWindowWMClass(&params.wm_class_name,
&params.wm_class_class);
#endif
devtools_window_->Init(std::move(params));
devtools_window_->UpdateWindowIcon();
devtools_window_->widget_delegate()->SetHasWindowSizeControls(true);
}
ShowDevTools(activate);
}
void InspectableWebContentsViewViews::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
strategy_.CopyFrom(strategy);
DeprecatedLayoutImmediately();
}
void InspectableWebContentsViewViews::SetTitle(const std::u16string& title) {
if (devtools_window_) {
title_ = title;
devtools_window_->UpdateWindowTitle();
}
}
const std::u16string InspectableWebContentsViewViews::GetTitle() {
return title_;
}
void InspectableWebContentsViewViews::Layout(PassKey) {
if (!devtools_web_view_->GetVisible()) {
contents_view_->SetBoundsRect(GetContentsBounds());
// Propagate layout call to all children, for example browser views.
LayoutSuperclass<View>(this);
return;
}
gfx::Size container_size(width(), height());
gfx::Rect new_devtools_bounds;
gfx::Rect new_contents_bounds;
ApplyDevToolsContentsResizingStrategy(
strategy_, container_size, &new_devtools_bounds, &new_contents_bounds);
// DevTools cares about the specific position, so we have to compensate RTL
// layout here.
new_devtools_bounds.set_x(GetMirroredXForRect(new_devtools_bounds));
new_contents_bounds.set_x(GetMirroredXForRect(new_contents_bounds));
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
contents_view_->SetBoundsRect(new_contents_bounds);
// Propagate layout call to all children, for example browser views.
LayoutSuperclass<View>(this);
if (GetDelegate())
GetDelegate()->DevToolsResized();
}
} // namespace electron

View file

@ -1,63 +0,0 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef ELECTRON_SHELL_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_
#define ELECTRON_SHELL_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_
#include <memory>
#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/views/view.h"
namespace views {
class WebView;
class Widget;
class WidgetDelegate;
} // namespace views
namespace electron {
class InspectableWebContentsViewViews : public InspectableWebContentsView,
public views::View {
public:
explicit InspectableWebContentsViewViews(
InspectableWebContents* inspectable_web_contents);
~InspectableWebContentsViewViews() override;
// InspectableWebContentsView:
views::View* GetView() override;
void ShowDevTools(bool activate) override;
void SetCornerRadii(const gfx::RoundedCornersF& corner_radii) override;
void CloseDevTools() override;
bool IsDevToolsViewShowing() override;
bool IsDevToolsViewFocused() override;
void SetIsDocked(bool docked, bool activate) override;
void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) override;
void SetTitle(const std::u16string& title) override;
const std::u16string GetTitle() override;
// views::View:
void Layout(PassKey) override;
private:
std::unique_ptr<views::Widget> devtools_window_;
raw_ptr<views::WebView> devtools_window_web_view_ = nullptr;
raw_ptr<views::WebView> contents_web_view_ = nullptr;
raw_ptr<views::View> contents_view_ = nullptr;
raw_ptr<views::WebView> devtools_web_view_ = nullptr;
DevToolsContentsResizingStrategy strategy_;
bool devtools_visible_ = false;
raw_ptr<views::WidgetDelegate> devtools_window_delegate_ = nullptr;
std::u16string title_;
};
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_