Browse Source

fix: make draggable regions work when devtools is opened on macOS (#26361)

* fix: make draggable region work when devtools is open

* fix: update draggable regions when resizing
Cheng Zhao 4 years ago
parent
commit
02a8c0a640

+ 3 - 0
shell/browser/api/electron_api_browser_window.h

@@ -63,6 +63,9 @@ class BrowserWindow : public BaseWindow,
   void OnActivateContents() override;
   void OnPageTitleUpdated(const base::string16& title,
                           bool explicit_set) override;
+#if defined(OS_MAC)
+  void OnDevToolsResized() override;
+#endif
 
   // NativeWindowObserver:
   void RequestPreferredWidth(int* width) override;

+ 5 - 19
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 @@ void BrowserWindow::OverrideNSWindowContentView(InspectableWebContents* iwc) {
   [contentView viewDidMoveToWindow];
 }
 
+void BrowserWindow::OnDevToolsResized() {
+  UpdateDraggableRegions(draggable_regions_);
+}
+
 void BrowserWindow::UpdateDraggableRegions(
     const std::vector<mojom::DraggableRegionPtr>& regions) {
   if (window_->has_frame())

+ 5 - 0
shell/browser/api/electron_api_web_contents.cc

@@ -1481,6 +1481,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)

+ 1 - 0
shell/browser/api/electron_api_web_contents.h

@@ -590,6 +590,7 @@ class WebContents : public gin::Wrappable<WebContents>,
   void DevToolsFocused() override;
   void DevToolsOpened() override;
   void DevToolsClosed() override;
+  void DevToolsResized() override;
 
  private:
   ElectronBrowserContext* GetBrowserContext() const;

+ 1 - 0
shell/browser/extended_web_contents_observer.h

@@ -25,6 +25,7 @@ class ExtendedWebContentsObserver : public base::CheckedObserver {
   virtual void OnActivateContents() {}
   virtual void OnPageTitleUpdated(const base::string16& title,
                                   bool explicit_set) {}
+  virtual void OnDevToolsResized() {}
 
  protected:
   ~ExtendedWebContentsObserver() override {}

+ 8 - 0
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 <NSWindowDelegate> {
  @private
   electron::InspectableWebContentsViewMac* inspectableWebContentsView_;
 
   base::scoped_nsobject<NSView> fake_view_;
   base::scoped_nsobject<NSWindow> devtools_window_;
+  base::scoped_nsobject<ControlRegionView> devtools_mask_;
   BOOL devtools_visible_;
   BOOL devtools_docked_;
   BOOL devtools_is_first_responder_;

+ 54 - 1
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 @@
     [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 @@
     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 @@
   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 @@
     } else {
       gfx::ScopedCocoaDisableScreenUpdates disabler;
       [devToolsView removeFromSuperview];
+      [devtools_mask_ removeFromSuperview];
       [self adjustSubviews];
+      [self notifyDevToolsResized];
     }
   } else {
     if (visible) {
@@ -182,7 +213,7 @@
   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 @@
       &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 {

+ 1 - 0
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();