From d28a7b15a2e70b2dfc6d07e2e8b6efac542e0088 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 16 Nov 2020 11:11:18 +0900 Subject: [PATCH] fix: make draggable regions work when devtools is opened on macOS (#26506) * fix: make draggable region work when devtools is open * fix: update draggable regions when resizing --- .../browser/api/electron_api_browser_window.h | 3 + .../api/electron_api_browser_window_mac.mm | 24 ++------ .../browser/api/electron_api_web_contents.cc | 5 ++ shell/browser/api/electron_api_web_contents.h | 1 + .../browser/extended_web_contents_observer.h | 1 + .../electron_inspectable_web_contents_view.h | 8 +++ .../electron_inspectable_web_contents_view.mm | 55 ++++++++++++++++++- .../inspectable_web_contents_view_delegate.h | 1 + 8 files changed, 78 insertions(+), 20 deletions(-) diff --git a/shell/browser/api/electron_api_browser_window.h b/shell/browser/api/electron_api_browser_window.h index 47af4175e3aa1..e08d334b9c096 100644 --- a/shell/browser/api/electron_api_browser_window.h +++ b/shell/browser/api/electron_api_browser_window.h @@ -60,6 +60,9 @@ class BrowserWindow : public TopLevelWindow, void OnRendererResponsive() override; void OnDraggableRegionsUpdated( const std::vector& regions) override; +#if defined(OS_MACOSX) + void OnDevToolsResized() override; +#endif // NativeWindowObserver: void RequestPreferredWidth(int* width) override; diff --git a/shell/browser/api/electron_api_browser_window_mac.mm b/shell/browser/api/electron_api_browser_window_mac.mm index 4f043931ec7fe..15eb63c3ae394 100644 --- a/shell/browser/api/electron_api_browser_window_mac.mm +++ b/shell/browser/api/electron_api_browser_window_mac.mm @@ -12,27 +12,9 @@ #include "base/mac/scoped_nsobject.h" #include "shell/browser/native_browser_view.h" #include "shell/browser/native_window_mac.h" +#include "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h" #include "shell/browser/ui/inspectable_web_contents_view.h" -@interface NSView (WebContentsView) -- (void)setMouseDownCanMoveWindow:(BOOL)can_move; -@end - -@interface ControlRegionView : NSView -@end - -@implementation ControlRegionView - -- (BOOL)mouseDownCanMoveWindow { - return NO; -} - -- (NSView*)hitTest:(NSPoint)aPoint { - return nil; -} - -@end - namespace electron { namespace api { @@ -54,6 +36,10 @@ - (NSView*)hitTest:(NSPoint)aPoint { [contentView viewDidMoveToWindow]; } +void BrowserWindow::OnDevToolsResized() { + UpdateDraggableRegions(draggable_regions_); +} + void BrowserWindow::UpdateDraggableRegions( const std::vector& regions) { if (window_->has_frame()) diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index e10c573f10148..d3e9c2dc285b1 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -1448,6 +1448,11 @@ void WebContents::DevToolsClosed() { Emit("devtools-closed"); } +void WebContents::DevToolsResized() { + for (ExtendedWebContentsObserver& observer : observers_) + observer.OnDevToolsResized(); +} + bool WebContents::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(WebContents, message) diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index 2bf9845990476..fd5093a175011 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -548,6 +548,7 @@ class WebContents : public gin_helper::TrackableObject, void DevToolsFocused() override; void DevToolsOpened() override; void DevToolsClosed() override; + void DevToolsResized() override; private: ElectronBrowserContext* GetBrowserContext() const; diff --git a/shell/browser/extended_web_contents_observer.h b/shell/browser/extended_web_contents_observer.h index aaf24d117d0a0..ffd984011476e 100644 --- a/shell/browser/extended_web_contents_observer.h +++ b/shell/browser/extended_web_contents_observer.h @@ -20,6 +20,7 @@ class ExtendedWebContentsObserver : public base::CheckedObserver { virtual void OnRendererResponsive() {} virtual void OnDraggableRegionsUpdated( const std::vector& regions) {} + virtual void OnDevToolsResized() {} protected: ~ExtendedWebContentsObserver() override {} diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h index 691c25f639332..ba247812bb8b1 100644 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h +++ b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h @@ -17,12 +17,20 @@ class InspectableWebContentsViewMac; using electron::InspectableWebContentsViewMac; +@interface NSView (WebContentsView) +- (void)setMouseDownCanMoveWindow:(BOOL)can_move; +@end + +@interface ControlRegionView : NSView +@end + @interface ElectronInspectableWebContentsView : BaseView { @private electron::InspectableWebContentsViewMac* inspectableWebContentsView_; base::scoped_nsobject fake_view_; base::scoped_nsobject devtools_window_; + base::scoped_nsobject devtools_mask_; BOOL devtools_visible_; BOOL devtools_docked_; BOOL devtools_is_first_responder_; diff --git a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm index 0b25862211bd3..4f932e7efcc8e 100644 --- a/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm +++ b/shell/browser/ui/cocoa/electron_inspectable_web_contents_view.mm @@ -11,6 +11,18 @@ #include "shell/browser/ui/inspectable_web_contents_view_mac.h" #include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h" +@implementation ControlRegionView + +- (BOOL)mouseDownCanMoveWindow { + return NO; +} + +- (NSView*)hitTest:(NSPoint)aPoint { + return nil; +} + +@end + @implementation ElectronInspectableWebContentsView - (instancetype)initWithInspectableWebContentsViewMac: @@ -48,6 +60,9 @@ - (instancetype)initWithInspectableWebContentsViewMac: [self addSubview:contentsView]; } + // This will float above devtools to exclude it from dragging. + devtools_mask_.reset([[ControlRegionView alloc] initWithFrame:NSZeroRect]); + // See https://code.google.com/p/chromium/issues/detail?id=348490. [self setWantsLayer:YES]; @@ -71,6 +86,14 @@ - (void)notifyDevToolsFocused { inspectableWebContentsView_->GetDelegate()->DevToolsFocused(); } +- (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; @@ -84,6 +107,12 @@ - (void)setDevToolsVisible:(BOOL)visible activate:(BOOL)activate { devtools_visible_ = visible; if (devtools_docked_) { if (visible) { + // The devToolsView is placed under the contentsView, so it has to be + // draggable to make draggable region of contentsView work. + [devToolsView setMouseDownCanMoveWindow:YES]; + // This view will exclude the actual devtools part from dragging. + [self addSubview:devtools_mask_.get()]; + // 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]; @@ -94,7 +123,9 @@ - (void)setDevToolsVisible:(BOOL)visible activate:(BOOL)activate { } else { gfx::ScopedCocoaDisableScreenUpdates disabler; [devToolsView removeFromSuperview]; + [devtools_mask_ removeFromSuperview]; [self adjustSubviews]; + [self notifyDevToolsResized]; } } else { if (visible) { @@ -182,7 +213,7 @@ - (void)adjustSubviews { NSView* devToolsView = [[self subviews] objectAtIndex:0]; NSView* contentsView = [[self subviews] objectAtIndex:1]; - DCHECK_EQ(2u, [[self subviews] count]); + DCHECK_EQ(3u, [[self subviews] count]); gfx::Rect new_devtools_bounds; gfx::Rect new_contents_bounds; @@ -191,6 +222,28 @@ - (void)adjustSubviews { &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; + } + [devtools_mask_ setFrame:devtools_frame]; + + [self notifyDevToolsResized]; } - (void)setTitle:(NSString*)title { diff --git a/shell/browser/ui/inspectable_web_contents_view_delegate.h b/shell/browser/ui/inspectable_web_contents_view_delegate.h index 73c4214d3874b..a93a17bce75aa 100644 --- a/shell/browser/ui/inspectable_web_contents_view_delegate.h +++ b/shell/browser/ui/inspectable_web_contents_view_delegate.h @@ -19,6 +19,7 @@ class InspectableWebContentsViewDelegate { virtual void DevToolsFocused() {} virtual void DevToolsOpened() {} virtual void DevToolsClosed() {} + virtual void DevToolsResized() {} // Returns the icon of devtools window. virtual gfx::ImageSkia GetDevToolsWindowIcon();