diff --git a/filenames.gni b/filenames.gni index 99c80b915a02..9a950d0e1955 100644 --- a/filenames.gni +++ b/filenames.gni @@ -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", diff --git a/patches/chromium/.patches b/patches/chromium/.patches index dc0578753584..939c67537716 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -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 diff --git a/patches/chromium/fix_add_method_which_disables_headless_mode_on_native_widget.patch b/patches/chromium/fix_add_method_which_disables_headless_mode_on_native_widget.patch new file mode 100644 index 000000000000..95d22359148d --- /dev/null +++ b/patches/chromium/fix_add_method_which_disables_headless_mode_on_native_widget.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Cezary Kulakowski +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_; } + diff --git a/patches/chromium/fix_put_nsvisualeffectview_before_viewscompositorsuperview.patch b/patches/chromium/fix_put_nsvisualeffectview_before_viewscompositorsuperview.patch new file mode 100644 index 000000000000..d7e097794419 --- /dev/null +++ b/patches/chromium/fix_put_nsvisualeffectview_before_viewscompositorsuperview.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20Pichli=C5=84ski?= + +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(rank_as_void); + auto left_rank = rank->find(lhs); diff --git a/shell/browser/api/electron_api_web_contents_view.cc b/shell/browser/api/electron_api_web_contents_view.cc index 644ea373a728..f76209fbdf5b 100644 --- a/shell/browser/api/electron_api_web_contents_view.cc +++ b/shell/browser/api/electron_api_web_contents_view.cc @@ -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 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, diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index d153dec7f87d..c49cdc963593 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -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 CreateNonClientFrameView( views::Widget* widget) override; diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index dc483ee3fd3a..2acea0428068 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -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 { diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 1f6c3957c45e..d5118ec346a8 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -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" diff --git a/shell/browser/ui/cocoa/delayed_native_view_host.h b/shell/browser/ui/cocoa/delayed_native_view_host.h deleted file mode 100644 index e7020dba6071..000000000000 --- a/shell/browser/ui/cocoa/delayed_native_view_host.h +++ /dev/null @@ -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_ diff --git a/shell/browser/ui/cocoa/delayed_native_view_host.mm b/shell/browser/ui/cocoa/delayed_native_view_host.mm deleted file mode 100644 index 38b0796555e1..000000000000 --- a/shell/browser/ui/cocoa/delayed_native_view_host.mm +++ /dev/null @@ -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 diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h deleted file mode 100644 index 4286312573aa..000000000000 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h +++ /dev/null @@ -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 - -#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 { - @private - raw_ptr 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_ diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm deleted file mode 100644 index d719fc164e47..000000000000 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm +++ /dev/null @@ -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 diff --git a/shell/browser/ui/cocoa/electron_ns_window.h b/shell/browser/ui/cocoa/electron_ns_window.h index 502592313c15..63ea5355467d 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.h +++ b/shell/browser/ui/cocoa/electron_ns_window.h @@ -29,6 +29,8 @@ class ScopedDisableResize { } // namespace electron +class ElectronNativeWindowObserver; + @interface ElectronNSWindow : NativeWidgetMacNSWindow { @private raw_ptr 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; diff --git a/shell/browser/ui/cocoa/electron_ns_window.mm b/shell/browser/ui/cocoa/electron_ns_window.mm index 5c5f1512f4a3..30780277d3a5 100644 --- a/shell/browser/ui/cocoa/electron_ns_window.mm +++ b/shell/browser/ui/cocoa/electron_ns_window.mm @@ -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]; diff --git a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm index d6af0ac6d9bb..3f7c689bfc8b 100644 --- a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm +++ b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm @@ -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(shell_)->GetContentsView(); + if (contents_view) { + auto* parent = contents_view->parent(); + if (parent) { + parent->RemoveChildView(contents_view); + } + } } - (BOOL)windowShouldClose:(id)window { diff --git a/shell/browser/ui/inspectable_web_contents.cc b/shell/browser/ui/inspectable_web_contents.cc index ea02168ef559..75ebdd644142 100644 --- a/shell/browser/ui/inspectable_web_contents.cc +++ b/shell/browser/ui/inspectable_web_contents.cc @@ -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()) { diff --git a/shell/browser/ui/inspectable_web_contents_view.cc b/shell/browser/ui/inspectable_web_contents_view.cc index 946b5071bcc8..e61f008414df 100644 --- a/shell/browser/ui/inspectable_web_contents_view.cc +++ b/shell/browser/ui/inspectable_web_contents_view.cc @@ -5,12 +5,250 @@ #include "shell/browser/ui/inspectable_web_contents_view.h" +#include +#include + +#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 shell_; + raw_ptr view_; + raw_ptr 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(); + 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(¶ms.wm_class_name, + ¶ms.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(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(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 diff --git a/shell/browser/ui/inspectable_web_contents_view.h b/shell/browser/ui/inspectable_web_contents_view.h index a9c95d477e00..282d3bf805a9 100644 --- a/shell/browser/ui/inspectable_web_contents_view.h +++ b/shell/browser/ui/inspectable_web_contents_view.h @@ -9,13 +9,9 @@ #include #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 inspectable_web_contents_; - private: raw_ptr delegate_ = nullptr; // weak references. + + std::unique_ptr devtools_window_; + raw_ptr devtools_window_web_view_ = nullptr; + raw_ptr contents_web_view_ = nullptr; + raw_ptr no_contents_view_ = nullptr; + raw_ptr devtools_web_view_ = nullptr; + + DevToolsContentsResizingStrategy strategy_; + bool devtools_visible_ = false; + raw_ptr devtools_window_delegate_ = nullptr; + std::u16string title_; }; } // namespace electron diff --git a/shell/browser/ui/inspectable_web_contents_view_mac.h b/shell/browser/ui/inspectable_web_contents_view_mac.h deleted file mode 100644 index 88b4078614f4..000000000000 --- a/shell/browser/ui/inspectable_web_contents_view_mac.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Copyright (c) 2013 Adam Roben . 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_ diff --git a/shell/browser/ui/inspectable_web_contents_view_mac.mm b/shell/browser/ui/inspectable_web_contents_view_mac.mm deleted file mode 100644 index a3789e09a8fb..000000000000 --- a/shell/browser/ui/inspectable_web_contents_view_mac.mm +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Copyright (c) 2013 Adam Roben . 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 diff --git a/shell/browser/ui/views/frameless_view.cc b/shell/browser/ui/views/frameless_view.cc index c963d1731093..dcfed5ef695f 100644 --- a/shell/browser/ui/views/frameless_view.cc +++ b/shell/browser/ui/views/frameless_view.cc @@ -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" diff --git a/shell/browser/ui/views/inspectable_web_contents_view_views.cc b/shell/browser/ui/views/inspectable_web_contents_view_views.cc deleted file mode 100644 index 61a5b013ecb1..000000000000 --- a/shell/browser/ui/views/inspectable_web_contents_view_views.cc +++ /dev/null @@ -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 -#include - -#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 shell_; - raw_ptr view_; - raw_ptr 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(); - 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(¶ms.wm_class_name, - ¶ms.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(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(this); - - if (GetDelegate()) - GetDelegate()->DevToolsResized(); -} - -} // namespace electron diff --git a/shell/browser/ui/views/inspectable_web_contents_view_views.h b/shell/browser/ui/views/inspectable_web_contents_view_views.h deleted file mode 100644 index 36554a497d6f..000000000000 --- a/shell/browser/ui/views/inspectable_web_contents_view_views.h +++ /dev/null @@ -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 - -#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 devtools_window_; - raw_ptr devtools_window_web_view_ = nullptr; - raw_ptr contents_web_view_ = nullptr; - raw_ptr contents_view_ = nullptr; - raw_ptr devtools_web_view_ = nullptr; - - DevToolsContentsResizingStrategy strategy_; - bool devtools_visible_ = false; - raw_ptr devtools_window_delegate_ = nullptr; - std::u16string title_; -}; - -} // namespace electron - -#endif // ELECTRON_SHELL_BROWSER_UI_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_