chore: Move draggable regions implementation from NativeBrowserView into InspectableWebContentsView (#35007)
* hore: Move draggable regions implementation from NativeBrowserView into InspectableWebContentsView The draggable regions implementation is related to WebView, so InspectableWebContentsView is a more appropriate place to put it there. Also, this refactoring will allow the subsequent extension of the WebContentsView API, which will eventually replace BrowserView API. * fix: Lint error * fix: Adjusted owner-window
This commit is contained in:
parent
f2c341b655
commit
23d4a252c6
18 changed files with 397 additions and 360 deletions
|
@ -494,6 +494,7 @@ filenames = {
|
||||||
"shell/browser/ui/inspectable_web_contents.cc",
|
"shell/browser/ui/inspectable_web_contents.cc",
|
||||||
"shell/browser/ui/inspectable_web_contents.h",
|
"shell/browser/ui/inspectable_web_contents.h",
|
||||||
"shell/browser/ui/inspectable_web_contents_delegate.h",
|
"shell/browser/ui/inspectable_web_contents_delegate.h",
|
||||||
|
"shell/browser/ui/inspectable_web_contents_view.cc",
|
||||||
"shell/browser/ui/inspectable_web_contents_view.h",
|
"shell/browser/ui/inspectable_web_contents_view.h",
|
||||||
"shell/browser/ui/inspectable_web_contents_view_delegate.cc",
|
"shell/browser/ui/inspectable_web_contents_view_delegate.cc",
|
||||||
"shell/browser/ui/inspectable_web_contents_view_delegate.h",
|
"shell/browser/ui/inspectable_web_contents_view_delegate.h",
|
||||||
|
|
|
@ -105,7 +105,16 @@ void BrowserView::SetOwnerWindow(BaseWindow* window) {
|
||||||
if (web_contents())
|
if (web_contents())
|
||||||
web_contents()->SetOwnerWindow(window ? window->window() : nullptr);
|
web_contents()->SetOwnerWindow(window ? window->window() : nullptr);
|
||||||
|
|
||||||
|
if (owner_window_.get()) {
|
||||||
|
owner_window_->window()->remove_inspectable_view(
|
||||||
|
view_->GetInspectableWebContentsView());
|
||||||
|
}
|
||||||
|
|
||||||
owner_window_ = window ? window->GetWeakPtr() : nullptr;
|
owner_window_ = window ? window->GetWeakPtr() : nullptr;
|
||||||
|
|
||||||
|
if (owner_window_.get() && view_->GetInspectableWebContentsView())
|
||||||
|
owner_window_->window()->add_inspectable_view(
|
||||||
|
view_->GetInspectableWebContentsView());
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserView::~BrowserView() {
|
BrowserView::~BrowserView() {
|
||||||
|
@ -123,7 +132,10 @@ void BrowserView::WebContentsDestroyed() {
|
||||||
|
|
||||||
void BrowserView::OnDraggableRegionsUpdated(
|
void BrowserView::OnDraggableRegionsUpdated(
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
||||||
view_->UpdateDraggableRegions(regions);
|
InspectableWebContentsView* iwc_view = view_->GetInspectableWebContentsView();
|
||||||
|
if (!iwc_view)
|
||||||
|
return;
|
||||||
|
iwc_view->UpdateDraggableRegions(regions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
|
@ -215,8 +215,8 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
||||||
api_web_contents_->NotifyUserActivation();
|
api_web_contents_->NotifyUserActivation();
|
||||||
|
|
||||||
// Trigger beforeunload events for associated BrowserViews.
|
// Trigger beforeunload events for associated BrowserViews.
|
||||||
for (NativeBrowserView* view : window_->browser_views()) {
|
for (InspectableWebContentsView* view : window_->inspectable_views()) {
|
||||||
auto* vwc = view->web_contents();
|
auto* vwc = view->inspectable_web_contents()->GetWebContents();
|
||||||
auto* api_web_contents = api::WebContents::From(vwc);
|
auto* api_web_contents = api::WebContents::From(vwc);
|
||||||
|
|
||||||
// Required to make beforeunload handler work.
|
// Required to make beforeunload handler work.
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include "content/public/browser/web_contents.h"
|
#include "content/public/browser/web_contents.h"
|
||||||
#include "content/public/browser/web_contents_observer.h"
|
#include "content/public/browser/web_contents_observer.h"
|
||||||
#include "shell/common/api/api.mojom.h"
|
|
||||||
#include "third_party/skia/include/core/SkColor.h"
|
#include "third_party/skia/include/core/SkColor.h"
|
||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
|
@ -43,10 +42,6 @@ class NativeBrowserView : public content::WebContentsObserver {
|
||||||
return inspectable_web_contents_;
|
return inspectable_web_contents_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<mojom::DraggableRegionPtr>& GetDraggableRegions() const {
|
|
||||||
return draggable_regions_;
|
|
||||||
}
|
|
||||||
|
|
||||||
InspectableWebContentsView* GetInspectableWebContentsView();
|
InspectableWebContentsView* GetInspectableWebContentsView();
|
||||||
|
|
||||||
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
|
virtual void SetAutoResizeFlags(uint8_t flags) = 0;
|
||||||
|
@ -54,20 +49,12 @@ class NativeBrowserView : public content::WebContentsObserver {
|
||||||
virtual gfx::Rect GetBounds() = 0;
|
virtual gfx::Rect GetBounds() = 0;
|
||||||
virtual void SetBackgroundColor(SkColor color) = 0;
|
virtual void SetBackgroundColor(SkColor color) = 0;
|
||||||
|
|
||||||
virtual void UpdateDraggableRegions(
|
|
||||||
const std::vector<gfx::Rect>& drag_exclude_rects) {}
|
|
||||||
|
|
||||||
// Called when the window needs to update its draggable region.
|
|
||||||
virtual void UpdateDraggableRegions(
|
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit NativeBrowserView(InspectableWebContents* inspectable_web_contents);
|
explicit NativeBrowserView(InspectableWebContents* inspectable_web_contents);
|
||||||
// content::WebContentsObserver:
|
// content::WebContentsObserver:
|
||||||
void WebContentsDestroyed() override;
|
void WebContentsDestroyed() override;
|
||||||
|
|
||||||
InspectableWebContents* inspectable_web_contents_;
|
InspectableWebContents* inspectable_web_contents_;
|
||||||
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
|
@ -23,12 +23,6 @@ class NativeBrowserViewMac : public NativeBrowserView {
|
||||||
void SetBounds(const gfx::Rect& bounds) override;
|
void SetBounds(const gfx::Rect& bounds) override;
|
||||||
gfx::Rect GetBounds() override;
|
gfx::Rect GetBounds() override;
|
||||||
void SetBackgroundColor(SkColor color) override;
|
void SetBackgroundColor(SkColor color) override;
|
||||||
|
|
||||||
void UpdateDraggableRegions(
|
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
|
||||||
|
|
||||||
void UpdateDraggableRegions(
|
|
||||||
const std::vector<gfx::Rect>& drag_exclude_rects) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
|
@ -4,10 +4,6 @@
|
||||||
|
|
||||||
#include "shell/browser/native_browser_view_mac.h"
|
#include "shell/browser/native_browser_view_mac.h"
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "shell/browser/ui/drag_util.h"
|
|
||||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
||||||
#include "skia/ext/skia_utils_mac.h"
|
#include "skia/ext/skia_utils_mac.h"
|
||||||
|
@ -17,206 +13,6 @@
|
||||||
const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
||||||
NSViewMaxXMargin | NSViewMinYMargin;
|
NSViewMaxXMargin | NSViewMinYMargin;
|
||||||
|
|
||||||
@interface DragRegionView : NSView
|
|
||||||
|
|
||||||
@property(assign) NSPoint initialLocation;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface NSWindow ()
|
|
||||||
- (void)performWindowDragWithEvent:(NSEvent*)event;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation DragRegionView
|
|
||||||
|
|
||||||
@synthesize initialLocation;
|
|
||||||
|
|
||||||
+ (void)load {
|
|
||||||
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
SEL originalSelector = @selector(drawRect:);
|
|
||||||
SEL swizzledSelector = @selector(drawDebugRect:);
|
|
||||||
|
|
||||||
Method originalMethod =
|
|
||||||
class_getInstanceMethod([self class], originalSelector);
|
|
||||||
Method swizzledMethod =
|
|
||||||
class_getInstanceMethod([self class], swizzledSelector);
|
|
||||||
BOOL didAddMethod =
|
|
||||||
class_addMethod([self class], originalSelector,
|
|
||||||
method_getImplementation(swizzledMethod),
|
|
||||||
method_getTypeEncoding(swizzledMethod));
|
|
||||||
|
|
||||||
if (didAddMethod) {
|
|
||||||
class_replaceMethod([self class], swizzledSelector,
|
|
||||||
method_getImplementation(originalMethod),
|
|
||||||
method_getTypeEncoding(originalMethod));
|
|
||||||
} else {
|
|
||||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)mouseDownCanMoveWindow {
|
|
||||||
return
|
|
||||||
[self.window respondsToSelector:@selector(performWindowDragWithEvent:)];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)shouldIgnoreMouseEvent {
|
|
||||||
NSEventType type = [[NSApp currentEvent] type];
|
|
||||||
return type != NSEventTypeLeftMouseDragged &&
|
|
||||||
type != NSEventTypeLeftMouseDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSView*)hitTest:(NSPoint)point {
|
|
||||||
// Pass-through events that hit one of the exclusion zones
|
|
||||||
for (NSView* exclusion_zones in [self subviews]) {
|
|
||||||
if ([exclusion_zones hitTest:point])
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseDown:(NSEvent*)event {
|
|
||||||
[super mouseDown:event];
|
|
||||||
|
|
||||||
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent:)]) {
|
|
||||||
// According to Google, using performWindowDragWithEvent:
|
|
||||||
// does not generate a NSWindowWillMoveNotification. Hence post one.
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
postNotificationName:NSWindowWillMoveNotification
|
|
||||||
object:self];
|
|
||||||
|
|
||||||
[self.window performWindowDragWithEvent:event];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.initialLocation = [event locationInWindow];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)mouseDragged:(NSEvent*)event {
|
|
||||||
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent:)]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSPoint currentLocation = [NSEvent mouseLocation];
|
|
||||||
NSPoint newOrigin;
|
|
||||||
|
|
||||||
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
|
||||||
NSSize screenSize = screenFrame.size;
|
|
||||||
NSRect windowFrame = [self.window frame];
|
|
||||||
NSSize windowSize = windowFrame.size;
|
|
||||||
|
|
||||||
newOrigin.x = currentLocation.x - self.initialLocation.x;
|
|
||||||
newOrigin.y = currentLocation.y - self.initialLocation.y;
|
|
||||||
|
|
||||||
BOOL inMenuBar = (newOrigin.y + windowSize.height) >
|
|
||||||
(screenFrame.origin.y + screenSize.height);
|
|
||||||
BOOL screenAboveMainScreen = false;
|
|
||||||
|
|
||||||
if (inMenuBar) {
|
|
||||||
for (NSScreen* screen in [NSScreen screens]) {
|
|
||||||
NSRect currentScreenFrame = [screen frame];
|
|
||||||
BOOL isHigher = currentScreenFrame.origin.y > screenFrame.origin.y;
|
|
||||||
|
|
||||||
// If there's another screen that is generally above the current screen,
|
|
||||||
// we'll draw a new rectangle that is just above the current screen. If
|
|
||||||
// the "higher" screen intersects with this rectangle, we'll allow drawing
|
|
||||||
// above the menubar.
|
|
||||||
if (isHigher) {
|
|
||||||
NSRect aboveScreenRect =
|
|
||||||
NSMakeRect(screenFrame.origin.x,
|
|
||||||
screenFrame.origin.y + screenFrame.size.height - 10,
|
|
||||||
screenFrame.size.width, 200);
|
|
||||||
|
|
||||||
BOOL screenAboveIntersects =
|
|
||||||
NSIntersectsRect(currentScreenFrame, aboveScreenRect);
|
|
||||||
|
|
||||||
if (screenAboveIntersects) {
|
|
||||||
screenAboveMainScreen = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't let window get dragged up under the menu bar
|
|
||||||
if (inMenuBar && !screenAboveMainScreen) {
|
|
||||||
newOrigin.y = screenFrame.origin.y +
|
|
||||||
(screenFrame.size.height - windowFrame.size.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the window to the new location
|
|
||||||
[self.window setFrameOrigin:newOrigin];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For debugging purposes only.
|
|
||||||
- (void)drawDebugRect:(NSRect)aRect {
|
|
||||||
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
|
|
||||||
NSRectFill([self bounds]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface ExcludeDragRegionView : NSView
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation ExcludeDragRegionView
|
|
||||||
|
|
||||||
+ (void)load {
|
|
||||||
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
SEL originalSelector = @selector(drawRect:);
|
|
||||||
SEL swizzledSelector = @selector(drawDebugRect:);
|
|
||||||
|
|
||||||
Method originalMethod =
|
|
||||||
class_getInstanceMethod([self class], originalSelector);
|
|
||||||
Method swizzledMethod =
|
|
||||||
class_getInstanceMethod([self class], swizzledSelector);
|
|
||||||
BOOL didAddMethod =
|
|
||||||
class_addMethod([self class], originalSelector,
|
|
||||||
method_getImplementation(swizzledMethod),
|
|
||||||
method_getTypeEncoding(swizzledMethod));
|
|
||||||
|
|
||||||
if (didAddMethod) {
|
|
||||||
class_replaceMethod([self class], swizzledSelector,
|
|
||||||
method_getImplementation(originalMethod),
|
|
||||||
method_getTypeEncoding(originalMethod));
|
|
||||||
} else {
|
|
||||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)mouseDownCanMoveWindow {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For debugging purposes only.
|
|
||||||
- (void)drawDebugRect:(NSRect)aRect {
|
|
||||||
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
|
|
||||||
NSRectFill([self bounds]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
NativeBrowserViewMac::NativeBrowserViewMac(
|
NativeBrowserViewMac::NativeBrowserViewMac(
|
||||||
|
@ -279,7 +75,7 @@ void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) {
|
||||||
NSMakeRect(bounds.x(), new_height, bounds.width(), bounds.height());
|
NSMakeRect(bounds.x(), new_height, bounds.width(), bounds.height());
|
||||||
|
|
||||||
// Ensure draggable regions are properly updated to reflect new bounds.
|
// Ensure draggable regions are properly updated to reflect new bounds.
|
||||||
UpdateDraggableRegions(draggable_regions_);
|
iwc_view->UpdateDraggableRegions(iwc_view->GetDraggableRegions());
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect NativeBrowserViewMac::GetBounds() {
|
gfx::Rect NativeBrowserViewMac::GetBounds() {
|
||||||
|
@ -315,75 +111,6 @@ void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
|
||||||
view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
|
view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeBrowserViewMac::UpdateDraggableRegions(
|
|
||||||
const std::vector<gfx::Rect>& drag_exclude_rects) {
|
|
||||||
if (!inspectable_web_contents_)
|
|
||||||
return;
|
|
||||||
auto* web_contents = inspectable_web_contents_->GetWebContents();
|
|
||||||
auto* iwc_view = GetInspectableWebContentsView();
|
|
||||||
NSView* web_view = web_contents->GetNativeView().GetNativeNSView();
|
|
||||||
NSView* inspectable_view = iwc_view->GetNativeView().GetNativeNSView();
|
|
||||||
NSView* window_content_view = inspectable_view.superview;
|
|
||||||
|
|
||||||
// Remove all DragRegionViews that were added last time. Note that we need
|
|
||||||
// to copy the `subviews` array to avoid mutation during iteration.
|
|
||||||
base::scoped_nsobject<NSArray> subviews([[web_view subviews] copy]);
|
|
||||||
for (NSView* subview in subviews.get()) {
|
|
||||||
if ([subview isKindOfClass:[DragRegionView class]]) {
|
|
||||||
[subview removeFromSuperview];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create one giant NSView that is draggable.
|
|
||||||
base::scoped_nsobject<NSView> drag_region_view(
|
|
||||||
[[DragRegionView alloc] initWithFrame:web_view.bounds]);
|
|
||||||
[web_view addSubview:drag_region_view];
|
|
||||||
|
|
||||||
// Then, on top of that, add "exclusion zones".
|
|
||||||
auto const offset = GetBounds().OffsetFromOrigin();
|
|
||||||
const auto window_content_view_height = NSHeight(window_content_view.bounds);
|
|
||||||
for (const auto& rect : drag_exclude_rects) {
|
|
||||||
const auto x = rect.x() + offset.x();
|
|
||||||
const auto y = window_content_view_height - (rect.bottom() + offset.y());
|
|
||||||
const auto exclude_rect = NSMakeRect(x, y, rect.width(), rect.height());
|
|
||||||
|
|
||||||
const auto drag_region_view_exclude_rect =
|
|
||||||
[window_content_view convertRect:exclude_rect toView:drag_region_view];
|
|
||||||
|
|
||||||
base::scoped_nsobject<NSView> exclude_drag_region_view(
|
|
||||||
[[ExcludeDragRegionView alloc]
|
|
||||||
initWithFrame:drag_region_view_exclude_rect]);
|
|
||||||
[drag_region_view addSubview:exclude_drag_region_view];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeBrowserViewMac::UpdateDraggableRegions(
|
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
|
||||||
if (!inspectable_web_contents_)
|
|
||||||
return;
|
|
||||||
auto* web_contents = inspectable_web_contents_->GetWebContents();
|
|
||||||
NSView* web_view = web_contents->GetNativeView().GetNativeNSView();
|
|
||||||
|
|
||||||
NSInteger webViewWidth = NSWidth([web_view bounds]);
|
|
||||||
NSInteger webViewHeight = NSHeight([web_view bounds]);
|
|
||||||
|
|
||||||
// Draggable regions are implemented by having the whole web view draggable
|
|
||||||
// and overlaying regions that are not draggable.
|
|
||||||
if (&draggable_regions_ != ®ions)
|
|
||||||
draggable_regions_ = mojo::Clone(regions);
|
|
||||||
|
|
||||||
std::vector<gfx::Rect> drag_exclude_rects;
|
|
||||||
if (draggable_regions_.empty()) {
|
|
||||||
drag_exclude_rects.emplace_back(0, 0, webViewWidth, webViewHeight);
|
|
||||||
} else {
|
|
||||||
drag_exclude_rects = CalculateNonDraggableRegions(
|
|
||||||
DraggableRegionsToSkRegion(draggable_regions_), webViewWidth,
|
|
||||||
webViewHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateDraggableRegions(drag_exclude_rects);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
NativeBrowserView* NativeBrowserView::Create(
|
NativeBrowserView* NativeBrowserView::Create(
|
||||||
InspectableWebContents* inspectable_web_contents) {
|
InspectableWebContents* inspectable_web_contents) {
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "shell/browser/ui/drag_util.h"
|
|
||||||
#include "shell/browser/ui/views/inspectable_web_contents_view_views.h"
|
#include "shell/browser/ui/views/inspectable_web_contents_view_views.h"
|
||||||
#include "ui/gfx/geometry/rect.h"
|
#include "ui/gfx/geometry/rect.h"
|
||||||
#include "ui/views/background.h"
|
#include "ui/views/background.h"
|
||||||
|
@ -25,25 +24,6 @@ void NativeBrowserViewViews::SetAutoResizeFlags(uint8_t flags) {
|
||||||
ResetAutoResizeProportions();
|
ResetAutoResizeProportions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeBrowserViewViews::UpdateDraggableRegions(
|
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
|
||||||
if (&draggable_regions_ != ®ions)
|
|
||||||
draggable_regions_ = mojo::Clone(regions);
|
|
||||||
|
|
||||||
// We need to snap the regions to the bounds of the current BrowserView.
|
|
||||||
// For example, if an attached BrowserView is draggable but its bounds are
|
|
||||||
// { x: 200, y: 100, width: 300, height: 300 }
|
|
||||||
// then we need to add 200 to the x-value and 100 to the
|
|
||||||
// y-value of each of the passed regions or it will be incorrectly
|
|
||||||
// assumed that the regions begin in the top left corner as they
|
|
||||||
// would for the main client window.
|
|
||||||
auto const offset = GetBounds().OffsetFromOrigin();
|
|
||||||
for (auto& snapped_region : draggable_regions_) {
|
|
||||||
snapped_region->bounds.Offset(offset);
|
|
||||||
}
|
|
||||||
draggable_region_ = DraggableRegionsToSkRegion(draggable_regions_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NativeBrowserViewViews::SetAutoResizeProportions(
|
void NativeBrowserViewViews::SetAutoResizeProportions(
|
||||||
const gfx::Size& window_size) {
|
const gfx::Size& window_size) {
|
||||||
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
|
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
|
||||||
|
@ -132,9 +112,6 @@ void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) {
|
||||||
|
|
||||||
view->InvalidateLayout();
|
view->InvalidateLayout();
|
||||||
view->SchedulePaint();
|
view->SchedulePaint();
|
||||||
|
|
||||||
// Ensure draggable regions are properly updated to reflect new bounds.
|
|
||||||
UpdateDraggableRegions(draggable_regions_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Rect NativeBrowserViewViews::GetBounds() {
|
gfx::Rect NativeBrowserViewViews::GetBounds() {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "shell/browser/native_browser_view.h"
|
#include "shell/browser/native_browser_view.h"
|
||||||
#include "third_party/skia/include/core/SkRegion.h"
|
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
|
@ -30,14 +29,10 @@ class NativeBrowserViewViews : public NativeBrowserView {
|
||||||
void SetBounds(const gfx::Rect& bounds) override;
|
void SetBounds(const gfx::Rect& bounds) override;
|
||||||
gfx::Rect GetBounds() override;
|
gfx::Rect GetBounds() override;
|
||||||
void SetBackgroundColor(SkColor color) override;
|
void SetBackgroundColor(SkColor color) override;
|
||||||
void UpdateDraggableRegions(
|
|
||||||
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
|
||||||
|
|
||||||
// WebContentsObserver:
|
// WebContentsObserver:
|
||||||
void RenderViewReady() override;
|
void RenderViewReady() override;
|
||||||
|
|
||||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ResetAutoResizeProportions();
|
void ResetAutoResizeProportions();
|
||||||
|
|
||||||
|
@ -50,8 +45,6 @@ class NativeBrowserViewViews : public NativeBrowserView {
|
||||||
bool auto_vertical_proportion_set_ = false;
|
bool auto_vertical_proportion_set_ = false;
|
||||||
float auto_vertical_proportion_height_ = 0.;
|
float auto_vertical_proportion_height_ = 0.;
|
||||||
float auto_vertical_proportion_top_ = 0.;
|
float auto_vertical_proportion_top_ = 0.;
|
||||||
|
|
||||||
std::unique_ptr<SkRegion> draggable_region_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "content/public/browser/web_contents_user_data.h"
|
#include "content/public/browser/web_contents_user_data.h"
|
||||||
#include "extensions/browser/app_window/size_constraints.h"
|
#include "extensions/browser/app_window/size_constraints.h"
|
||||||
#include "shell/browser/native_window_observer.h"
|
#include "shell/browser/native_window_observer.h"
|
||||||
|
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
||||||
#include "shell/common/api/api.mojom.h"
|
#include "shell/common/api/api.mojom.h"
|
||||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||||
#include "ui/views/widget/widget_delegate.h"
|
#include "ui/views/widget/widget_delegate.h"
|
||||||
|
@ -50,6 +51,10 @@ namespace electron {
|
||||||
class ElectronMenuModel;
|
class ElectronMenuModel;
|
||||||
class NativeBrowserView;
|
class NativeBrowserView;
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
class BrowserView;
|
||||||
|
}
|
||||||
|
|
||||||
#if BUILDFLAG(IS_MAC)
|
#if BUILDFLAG(IS_MAC)
|
||||||
typedef NSView* NativeWindowHandle;
|
typedef NSView* NativeWindowHandle;
|
||||||
#else
|
#else
|
||||||
|
@ -373,9 +378,15 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
|
|
||||||
std::list<NativeBrowserView*> browser_views() const { return browser_views_; }
|
std::list<NativeBrowserView*> browser_views() const { return browser_views_; }
|
||||||
|
|
||||||
|
std::list<InspectableWebContentsView*> inspectable_views() const {
|
||||||
|
return inspectable_views_;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t window_id() const { return next_id_; }
|
int32_t window_id() const { return next_id_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class api::BrowserView;
|
||||||
|
|
||||||
NativeWindow(const gin_helper::Dictionary& options, NativeWindow* parent);
|
NativeWindow(const gin_helper::Dictionary& options, NativeWindow* parent);
|
||||||
|
|
||||||
// views::WidgetDelegate:
|
// views::WidgetDelegate:
|
||||||
|
@ -393,6 +404,16 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
[&browser_view](NativeBrowserView* n) { return (n == browser_view); });
|
[&browser_view](NativeBrowserView* n) { return (n == browser_view); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_inspectable_view(InspectableWebContentsView* inspectable_view) {
|
||||||
|
inspectable_views_.push_back(inspectable_view);
|
||||||
|
}
|
||||||
|
void remove_inspectable_view(InspectableWebContentsView* inspectable_view) {
|
||||||
|
inspectable_views_.remove_if(
|
||||||
|
[&inspectable_view](InspectableWebContentsView* n) {
|
||||||
|
return (n == inspectable_view);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// The boolean parsing of the "titleBarOverlay" option
|
// The boolean parsing of the "titleBarOverlay" option
|
||||||
bool titlebar_overlay_ = false;
|
bool titlebar_overlay_ = false;
|
||||||
|
|
||||||
|
@ -456,6 +477,9 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
// The browser view layer.
|
// The browser view layer.
|
||||||
std::list<NativeBrowserView*> browser_views_;
|
std::list<NativeBrowserView*> browser_views_;
|
||||||
|
|
||||||
|
// The inspectable webContents views.
|
||||||
|
std::list<InspectableWebContentsView*> inspectable_views_;
|
||||||
|
|
||||||
// Observers of this window.
|
// Observers of this window.
|
||||||
base::ObserverList<NativeWindowObserver> observers_;
|
base::ObserverList<NativeWindowObserver> observers_;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include "shell/browser/ui/cocoa/window_buttons_proxy.h"
|
#include "shell/browser/ui/cocoa/window_buttons_proxy.h"
|
||||||
#include "shell/browser/ui/drag_util.h"
|
#include "shell/browser/ui/drag_util.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
|
||||||
#include "shell/browser/window_list.h"
|
#include "shell/browser/window_list.h"
|
||||||
#include "shell/common/gin_converters/gfx_converter.h"
|
#include "shell/common/gin_converters/gfx_converter.h"
|
||||||
#include "shell/common/gin_helper/dictionary.h"
|
#include "shell/common/gin_helper/dictionary.h"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "shell/browser/api/electron_api_web_contents.h"
|
#include "shell/browser/api/electron_api_web_contents.h"
|
||||||
#include "shell/browser/native_browser_view_views.h"
|
#include "shell/browser/native_browser_view_views.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
#include "shell/browser/ui/views/inspectable_web_contents_view_views.h"
|
||||||
#include "shell/browser/ui/views/root_view.h"
|
#include "shell/browser/ui/views/root_view.h"
|
||||||
#include "shell/browser/web_contents_preferences.h"
|
#include "shell/browser/web_contents_preferences.h"
|
||||||
#include "shell/browser/web_view_manager.h"
|
#include "shell/browser/web_view_manager.h"
|
||||||
|
@ -1594,11 +1594,11 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
||||||
const gfx::Point& location) {
|
const gfx::Point& location) {
|
||||||
// App window should claim mouse events that fall within any BrowserViews'
|
// App window should claim mouse events that fall within any BrowserViews'
|
||||||
// draggable region.
|
// draggable region.
|
||||||
for (auto* view : browser_views()) {
|
for (auto* view : inspectable_views()) {
|
||||||
auto* native_view = static_cast<NativeBrowserViewViews*>(view);
|
auto* inspectable_view =
|
||||||
auto* view_draggable_region = native_view->draggable_region();
|
static_cast<InspectableWebContentsViewViews*>(view);
|
||||||
if (view_draggable_region &&
|
if (inspectable_view->IsContainedInDraggableRegion(content_view(),
|
||||||
view_draggable_region->contains(location.x(), location.y()))
|
location))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
shell/browser/ui/inspectable_web_contents_view.cc
Normal file
16
shell/browser/ui/inspectable_web_contents_view.cc
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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.h"
|
||||||
|
|
||||||
|
namespace electron {
|
||||||
|
|
||||||
|
InspectableWebContentsView::InspectableWebContentsView(
|
||||||
|
InspectableWebContents* inspectable_web_contents)
|
||||||
|
: inspectable_web_contents_(inspectable_web_contents) {}
|
||||||
|
|
||||||
|
InspectableWebContentsView::~InspectableWebContentsView() = default;
|
||||||
|
|
||||||
|
} // namespace electron
|
|
@ -7,7 +7,9 @@
|
||||||
#define ELECTRON_SHELL_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_H_
|
#define ELECTRON_SHELL_BROWSER_UI_INSPECTABLE_WEB_CONTENTS_VIEW_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "shell/common/api/api.mojom.h"
|
||||||
#include "ui/gfx/native_widget_types.h"
|
#include "ui/gfx/native_widget_types.h"
|
||||||
|
|
||||||
class DevToolsContentsResizingStrategy;
|
class DevToolsContentsResizingStrategy;
|
||||||
|
@ -20,12 +22,18 @@ class View;
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
|
class InspectableWebContents;
|
||||||
class InspectableWebContentsViewDelegate;
|
class InspectableWebContentsViewDelegate;
|
||||||
|
|
||||||
class InspectableWebContentsView {
|
class InspectableWebContentsView {
|
||||||
public:
|
public:
|
||||||
InspectableWebContentsView() {}
|
explicit InspectableWebContentsView(
|
||||||
virtual ~InspectableWebContentsView() {}
|
InspectableWebContents* inspectable_web_contents);
|
||||||
|
virtual ~InspectableWebContentsView();
|
||||||
|
|
||||||
|
InspectableWebContents* inspectable_web_contents() {
|
||||||
|
return inspectable_web_contents_;
|
||||||
|
}
|
||||||
|
|
||||||
// The delegate manages its own life.
|
// The delegate manages its own life.
|
||||||
void SetDelegate(InspectableWebContentsViewDelegate* delegate) {
|
void SetDelegate(InspectableWebContentsViewDelegate* delegate) {
|
||||||
|
@ -33,6 +41,10 @@ class InspectableWebContentsView {
|
||||||
}
|
}
|
||||||
InspectableWebContentsViewDelegate* GetDelegate() const { return delegate_; }
|
InspectableWebContentsViewDelegate* GetDelegate() const { return delegate_; }
|
||||||
|
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& GetDraggableRegions() const {
|
||||||
|
return draggable_regions_;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_MAC)
|
#if defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_MAC)
|
||||||
// Returns the container control, which has devtools view attached.
|
// Returns the container control, which has devtools view attached.
|
||||||
virtual views::View* GetView() = 0;
|
virtual views::View* GetView() = 0;
|
||||||
|
@ -54,6 +66,16 @@ class InspectableWebContentsView {
|
||||||
const DevToolsContentsResizingStrategy& strategy) = 0;
|
const DevToolsContentsResizingStrategy& strategy) = 0;
|
||||||
virtual void SetTitle(const std::u16string& title) = 0;
|
virtual void SetTitle(const std::u16string& title) = 0;
|
||||||
|
|
||||||
|
// Called when the window needs to update its draggable region.
|
||||||
|
virtual void UpdateDraggableRegions(
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& regions) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Owns us.
|
||||||
|
InspectableWebContents* inspectable_web_contents_;
|
||||||
|
|
||||||
|
std::vector<mojom::DraggableRegionPtr> draggable_regions_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InspectableWebContentsViewDelegate* delegate_ = nullptr; // weak references.
|
InspectableWebContentsViewDelegate* delegate_ = nullptr; // weak references.
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
|
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/mac/scoped_nsobject.h"
|
#include "base/mac/scoped_nsobject.h"
|
||||||
|
|
||||||
@class ElectronInspectableWebContentsView;
|
@class ElectronInspectableWebContentsView;
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
class InspectableWebContents;
|
|
||||||
|
|
||||||
class InspectableWebContentsViewMac : public InspectableWebContentsView {
|
class InspectableWebContentsViewMac : public InspectableWebContentsView {
|
||||||
public:
|
public:
|
||||||
explicit InspectableWebContentsViewMac(
|
explicit InspectableWebContentsViewMac(
|
||||||
|
@ -34,15 +34,10 @@ class InspectableWebContentsViewMac : public InspectableWebContentsView {
|
||||||
void SetContentsResizingStrategy(
|
void SetContentsResizingStrategy(
|
||||||
const DevToolsContentsResizingStrategy& strategy) override;
|
const DevToolsContentsResizingStrategy& strategy) override;
|
||||||
void SetTitle(const std::u16string& title) override;
|
void SetTitle(const std::u16string& title) override;
|
||||||
|
void UpdateDraggableRegions(
|
||||||
InspectableWebContents* inspectable_web_contents() {
|
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
||||||
return inspectable_web_contents_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Owns us.
|
|
||||||
InspectableWebContents* inspectable_web_contents_;
|
|
||||||
|
|
||||||
base::scoped_nsobject<ElectronInspectableWebContentsView> view_;
|
base::scoped_nsobject<ElectronInspectableWebContentsView> view_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,216 @@
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view_mac.h"
|
#include "shell/browser/ui/inspectable_web_contents_view_mac.h"
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
#import <AppKit/AppKit.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/strings/sys_string_conversions.h"
|
#include "base/strings/sys_string_conversions.h"
|
||||||
#import "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
|
#import "shell/browser/ui/cocoa/electron_inspectable_web_contents_view.h"
|
||||||
|
#include "shell/browser/ui/drag_util.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents.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_delegate.h"
|
||||||
|
#include "ui/gfx/geometry/rect.h"
|
||||||
|
|
||||||
|
@interface DragRegionView : NSView
|
||||||
|
|
||||||
|
@property(assign) NSPoint initialLocation;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSWindow ()
|
||||||
|
- (void)performWindowDragWithEvent:(NSEvent*)event;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation DragRegionView
|
||||||
|
|
||||||
|
@synthesize initialLocation;
|
||||||
|
|
||||||
|
+ (void)load {
|
||||||
|
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
SEL originalSelector = @selector(drawRect:);
|
||||||
|
SEL swizzledSelector = @selector(drawDebugRect:);
|
||||||
|
|
||||||
|
Method originalMethod =
|
||||||
|
class_getInstanceMethod([self class], originalSelector);
|
||||||
|
Method swizzledMethod =
|
||||||
|
class_getInstanceMethod([self class], swizzledSelector);
|
||||||
|
BOOL didAddMethod =
|
||||||
|
class_addMethod([self class], originalSelector,
|
||||||
|
method_getImplementation(swizzledMethod),
|
||||||
|
method_getTypeEncoding(swizzledMethod));
|
||||||
|
|
||||||
|
if (didAddMethod) {
|
||||||
|
class_replaceMethod([self class], swizzledSelector,
|
||||||
|
method_getImplementation(originalMethod),
|
||||||
|
method_getTypeEncoding(originalMethod));
|
||||||
|
} else {
|
||||||
|
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)mouseDownCanMoveWindow {
|
||||||
|
return
|
||||||
|
[self.window respondsToSelector:@selector(performWindowDragWithEvent:)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)shouldIgnoreMouseEvent {
|
||||||
|
NSEventType type = [[NSApp currentEvent] type];
|
||||||
|
return type != NSEventTypeLeftMouseDragged &&
|
||||||
|
type != NSEventTypeLeftMouseDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSView*)hitTest:(NSPoint)point {
|
||||||
|
// Pass-through events that hit one of the exclusion zones
|
||||||
|
for (NSView* exclusion_zones in [self subviews]) {
|
||||||
|
if ([exclusion_zones hitTest:point])
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(NSEvent*)event {
|
||||||
|
[super mouseDown:event];
|
||||||
|
|
||||||
|
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent:)]) {
|
||||||
|
// According to Google, using performWindowDragWithEvent:
|
||||||
|
// does not generate a NSWindowWillMoveNotification. Hence post one.
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
postNotificationName:NSWindowWillMoveNotification
|
||||||
|
object:self];
|
||||||
|
|
||||||
|
[self.window performWindowDragWithEvent:event];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.initialLocation = [event locationInWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(NSEvent*)event {
|
||||||
|
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent:)]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSPoint currentLocation = [NSEvent mouseLocation];
|
||||||
|
NSPoint newOrigin;
|
||||||
|
|
||||||
|
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
||||||
|
NSSize screenSize = screenFrame.size;
|
||||||
|
NSRect windowFrame = [self.window frame];
|
||||||
|
NSSize windowSize = windowFrame.size;
|
||||||
|
|
||||||
|
newOrigin.x = currentLocation.x - self.initialLocation.x;
|
||||||
|
newOrigin.y = currentLocation.y - self.initialLocation.y;
|
||||||
|
|
||||||
|
BOOL inMenuBar = (newOrigin.y + windowSize.height) >
|
||||||
|
(screenFrame.origin.y + screenSize.height);
|
||||||
|
BOOL screenAboveMainScreen = false;
|
||||||
|
|
||||||
|
if (inMenuBar) {
|
||||||
|
for (NSScreen* screen in [NSScreen screens]) {
|
||||||
|
NSRect currentScreenFrame = [screen frame];
|
||||||
|
BOOL isHigher = currentScreenFrame.origin.y > screenFrame.origin.y;
|
||||||
|
|
||||||
|
// If there's another screen that is generally above the current screen,
|
||||||
|
// we'll draw a new rectangle that is just above the current screen. If
|
||||||
|
// the "higher" screen intersects with this rectangle, we'll allow drawing
|
||||||
|
// above the menubar.
|
||||||
|
if (isHigher) {
|
||||||
|
NSRect aboveScreenRect =
|
||||||
|
NSMakeRect(screenFrame.origin.x,
|
||||||
|
screenFrame.origin.y + screenFrame.size.height - 10,
|
||||||
|
screenFrame.size.width, 200);
|
||||||
|
|
||||||
|
BOOL screenAboveIntersects =
|
||||||
|
NSIntersectsRect(currentScreenFrame, aboveScreenRect);
|
||||||
|
|
||||||
|
if (screenAboveIntersects) {
|
||||||
|
screenAboveMainScreen = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't let window get dragged up under the menu bar
|
||||||
|
if (inMenuBar && !screenAboveMainScreen) {
|
||||||
|
newOrigin.y = screenFrame.origin.y +
|
||||||
|
(screenFrame.size.height - windowFrame.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the window to the new location
|
||||||
|
[self.window setFrameOrigin:newOrigin];
|
||||||
|
}
|
||||||
|
|
||||||
|
// For debugging purposes only.
|
||||||
|
- (void)drawDebugRect:(NSRect)aRect {
|
||||||
|
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
|
||||||
|
NSRectFill([self bounds]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface ExcludeDragRegionView : NSView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ExcludeDragRegionView
|
||||||
|
|
||||||
|
+ (void)load {
|
||||||
|
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
SEL originalSelector = @selector(drawRect:);
|
||||||
|
SEL swizzledSelector = @selector(drawDebugRect:);
|
||||||
|
|
||||||
|
Method originalMethod =
|
||||||
|
class_getInstanceMethod([self class], originalSelector);
|
||||||
|
Method swizzledMethod =
|
||||||
|
class_getInstanceMethod([self class], swizzledSelector);
|
||||||
|
BOOL didAddMethod =
|
||||||
|
class_addMethod([self class], originalSelector,
|
||||||
|
method_getImplementation(swizzledMethod),
|
||||||
|
method_getTypeEncoding(swizzledMethod));
|
||||||
|
|
||||||
|
if (didAddMethod) {
|
||||||
|
class_replaceMethod([self class], swizzledSelector,
|
||||||
|
method_getImplementation(originalMethod),
|
||||||
|
method_getTypeEncoding(originalMethod));
|
||||||
|
} else {
|
||||||
|
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)mouseDownCanMoveWindow {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For debugging purposes only.
|
||||||
|
- (void)drawDebugRect:(NSRect)aRect {
|
||||||
|
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
|
||||||
|
NSRectFill([self bounds]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
|
@ -21,7 +226,7 @@ InspectableWebContentsView* CreateInspectableContentsView(
|
||||||
|
|
||||||
InspectableWebContentsViewMac::InspectableWebContentsViewMac(
|
InspectableWebContentsViewMac::InspectableWebContentsViewMac(
|
||||||
InspectableWebContents* inspectable_web_contents)
|
InspectableWebContents* inspectable_web_contents)
|
||||||
: inspectable_web_contents_(inspectable_web_contents),
|
: InspectableWebContentsView(inspectable_web_contents),
|
||||||
view_([[ElectronInspectableWebContentsView alloc]
|
view_([[ElectronInspectableWebContentsView alloc]
|
||||||
initWithInspectableWebContentsViewMac:this]) {}
|
initWithInspectableWebContentsViewMac:this]) {}
|
||||||
|
|
||||||
|
@ -62,4 +267,65 @@ void InspectableWebContentsViewMac::SetTitle(const std::u16string& title) {
|
||||||
[view_ setTitle:base::SysUTF16ToNSString(title)];
|
[view_ setTitle:base::SysUTF16ToNSString(title)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InspectableWebContentsViewMac::UpdateDraggableRegions(
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
||||||
|
auto* web_contents = inspectable_web_contents()->GetWebContents();
|
||||||
|
NSView* web_view = web_contents->GetNativeView().GetNativeNSView();
|
||||||
|
NSView* inspectable_view = GetNativeView().GetNativeNSView();
|
||||||
|
NSView* inspectable_superview = inspectable_view.superview;
|
||||||
|
|
||||||
|
NSInteger webViewWidth = NSWidth([web_view bounds]);
|
||||||
|
NSInteger webViewHeight = NSHeight([web_view bounds]);
|
||||||
|
|
||||||
|
// Draggable regions are implemented by having the whole web view draggable
|
||||||
|
// and overlaying regions that are not draggable.
|
||||||
|
if (&draggable_regions_ != ®ions)
|
||||||
|
draggable_regions_ = mojo::Clone(regions);
|
||||||
|
|
||||||
|
std::vector<gfx::Rect> drag_exclude_rects;
|
||||||
|
if (draggable_regions_.empty()) {
|
||||||
|
drag_exclude_rects.emplace_back(0, 0, webViewWidth, webViewHeight);
|
||||||
|
} else {
|
||||||
|
drag_exclude_rects = CalculateNonDraggableRegions(
|
||||||
|
DraggableRegionsToSkRegion(draggable_regions_), webViewWidth,
|
||||||
|
webViewHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all DragRegionViews that were added last time. Note that we need
|
||||||
|
// to copy the `subviews` array to avoid mutation during iteration.
|
||||||
|
base::scoped_nsobject<NSArray> subviews([[web_view subviews] copy]);
|
||||||
|
for (NSView* subview in subviews.get()) {
|
||||||
|
if ([subview isKindOfClass:[DragRegionView class]])
|
||||||
|
[subview removeFromSuperview];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create one giant NSView that is draggable.
|
||||||
|
base::scoped_nsobject<NSView> drag_region_view(
|
||||||
|
[[DragRegionView alloc] initWithFrame:web_view.bounds]);
|
||||||
|
[web_view addSubview:drag_region_view];
|
||||||
|
|
||||||
|
// Then, on top of that, add "exclusion zones".
|
||||||
|
const int superview_height =
|
||||||
|
(inspectable_superview) ? inspectable_superview.frame.size.height : 0;
|
||||||
|
if (!inspectable_superview)
|
||||||
|
inspectable_superview = inspectable_view;
|
||||||
|
const int offset_x = inspectable_view.frame.origin.x;
|
||||||
|
const int offset_y = superview_height - inspectable_view.frame.origin.y -
|
||||||
|
inspectable_view.frame.size.height;
|
||||||
|
for (const auto& rect : drag_exclude_rects) {
|
||||||
|
const auto x = rect.x() + offset_x;
|
||||||
|
const auto y = superview_height - (rect.bottom() + offset_y);
|
||||||
|
const auto exclude_rect = NSMakeRect(x, y, rect.width(), rect.height());
|
||||||
|
|
||||||
|
const auto drag_region_view_exclude_rect =
|
||||||
|
[inspectable_superview convertRect:exclude_rect
|
||||||
|
toView:drag_region_view];
|
||||||
|
|
||||||
|
base::scoped_nsobject<NSView> exclude_drag_region_view(
|
||||||
|
[[ExcludeDragRegionView alloc]
|
||||||
|
initWithFrame:drag_region_view_exclude_rect]);
|
||||||
|
[drag_region_view addSubview:exclude_drag_region_view];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "shell/browser/native_browser_view_views.h"
|
#include "shell/browser/native_browser_view_views.h"
|
||||||
#include "shell/browser/native_window_views.h"
|
#include "shell/browser/native_window_views.h"
|
||||||
|
#include "shell/browser/ui/views/inspectable_web_contents_view_views.h"
|
||||||
#include "ui/aura/window.h"
|
#include "ui/aura/window.h"
|
||||||
#include "ui/base/hit_test.h"
|
#include "ui/base/hit_test.h"
|
||||||
#include "ui/views/widget/widget.h"
|
#include "ui/views/widget/widget.h"
|
||||||
|
@ -80,11 +81,11 @@ int FramelessView::NonClientHitTest(const gfx::Point& cursor) {
|
||||||
return HTCLIENT;
|
return HTCLIENT;
|
||||||
|
|
||||||
// Check attached BrowserViews for potential draggable areas.
|
// Check attached BrowserViews for potential draggable areas.
|
||||||
for (auto* view : window_->browser_views()) {
|
for (auto* view : window_->inspectable_views()) {
|
||||||
auto* native_view = static_cast<NativeBrowserViewViews*>(view);
|
auto* inspectable_view =
|
||||||
auto* view_draggable_region = native_view->draggable_region();
|
static_cast<InspectableWebContentsViewViews*>(view);
|
||||||
if (view_draggable_region &&
|
if (inspectable_view->IsContainedInDraggableRegion(window_->content_view(),
|
||||||
view_draggable_region->contains(cursor.x(), cursor.y()))
|
cursor))
|
||||||
return HTCAPTION;
|
return HTCAPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/strings/utf_string_conversions.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.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents_delegate.h"
|
#include "shell/browser/ui/inspectable_web_contents_delegate.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
|
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
|
||||||
|
@ -79,7 +81,7 @@ InspectableWebContentsView* CreateInspectableContentsView(
|
||||||
|
|
||||||
InspectableWebContentsViewViews::InspectableWebContentsViewViews(
|
InspectableWebContentsViewViews::InspectableWebContentsViewViews(
|
||||||
InspectableWebContents* inspectable_web_contents)
|
InspectableWebContents* inspectable_web_contents)
|
||||||
: inspectable_web_contents_(inspectable_web_contents),
|
: InspectableWebContentsView(inspectable_web_contents),
|
||||||
devtools_web_view_(new views::WebView(nullptr)),
|
devtools_web_view_(new views::WebView(nullptr)),
|
||||||
title_(u"Developer Tools") {
|
title_(u"Developer Tools") {
|
||||||
if (!inspectable_web_contents_->IsGuest() &&
|
if (!inspectable_web_contents_->IsGuest() &&
|
||||||
|
@ -103,6 +105,19 @@ InspectableWebContentsViewViews::~InspectableWebContentsViewViews() {
|
||||||
devtools_window_->GetWindowBoundsInScreen());
|
devtools_window_->GetWindowBoundsInScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InspectableWebContentsViewViews::IsContainedInDraggableRegion(
|
||||||
|
views::View* root_view,
|
||||||
|
const gfx::Point& location) {
|
||||||
|
if (!draggable_region_.get())
|
||||||
|
return false;
|
||||||
|
// Draggable regions are defined relative to the web contents.
|
||||||
|
gfx::Point point_in_contents_web_view_coords(location);
|
||||||
|
views::View::ConvertPointToTarget(root_view, this,
|
||||||
|
&point_in_contents_web_view_coords);
|
||||||
|
return draggable_region_->contains(point_in_contents_web_view_coords.x(),
|
||||||
|
point_in_contents_web_view_coords.y());
|
||||||
|
}
|
||||||
|
|
||||||
views::View* InspectableWebContentsViewViews::GetView() {
|
views::View* InspectableWebContentsViewViews::GetView() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -212,6 +227,14 @@ void InspectableWebContentsViewViews::SetTitle(const std::u16string& title) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InspectableWebContentsViewViews::UpdateDraggableRegions(
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
||||||
|
if (&draggable_regions_ == ®ions)
|
||||||
|
return;
|
||||||
|
draggable_regions_ = mojo::Clone(regions);
|
||||||
|
draggable_region_ = DraggableRegionsToSkRegion(draggable_regions_);
|
||||||
|
}
|
||||||
|
|
||||||
void InspectableWebContentsViewViews::Layout() {
|
void InspectableWebContentsViewViews::Layout() {
|
||||||
if (!devtools_web_view_->GetVisible()) {
|
if (!devtools_web_view_->GetVisible()) {
|
||||||
contents_web_view_->SetBoundsRect(GetContentsBounds());
|
contents_web_view_->SetBoundsRect(GetContentsBounds());
|
||||||
|
|
|
@ -6,10 +6,12 @@
|
||||||
#define 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 <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/compiler_specific.h"
|
#include "base/compiler_specific.h"
|
||||||
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
|
#include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
|
||||||
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
||||||
|
#include "third_party/skia/include/core/SkRegion.h"
|
||||||
#include "ui/views/view.h"
|
#include "ui/views/view.h"
|
||||||
|
|
||||||
namespace views {
|
namespace views {
|
||||||
|
@ -20,8 +22,6 @@ class WidgetDelegate;
|
||||||
|
|
||||||
namespace electron {
|
namespace electron {
|
||||||
|
|
||||||
class InspectableWebContents;
|
|
||||||
|
|
||||||
class InspectableWebContentsViewViews : public InspectableWebContentsView,
|
class InspectableWebContentsViewViews : public InspectableWebContentsView,
|
||||||
public views::View {
|
public views::View {
|
||||||
public:
|
public:
|
||||||
|
@ -29,6 +29,9 @@ class InspectableWebContentsViewViews : public InspectableWebContentsView,
|
||||||
InspectableWebContents* inspectable_web_contents);
|
InspectableWebContents* inspectable_web_contents);
|
||||||
~InspectableWebContentsViewViews() override;
|
~InspectableWebContentsViewViews() override;
|
||||||
|
|
||||||
|
bool IsContainedInDraggableRegion(views::View* root_view,
|
||||||
|
const gfx::Point& location);
|
||||||
|
|
||||||
// InspectableWebContentsView:
|
// InspectableWebContentsView:
|
||||||
views::View* GetView() override;
|
views::View* GetView() override;
|
||||||
views::View* GetWebView() override;
|
views::View* GetWebView() override;
|
||||||
|
@ -40,20 +43,15 @@ class InspectableWebContentsViewViews : public InspectableWebContentsView,
|
||||||
void SetContentsResizingStrategy(
|
void SetContentsResizingStrategy(
|
||||||
const DevToolsContentsResizingStrategy& strategy) override;
|
const DevToolsContentsResizingStrategy& strategy) override;
|
||||||
void SetTitle(const std::u16string& title) override;
|
void SetTitle(const std::u16string& title) override;
|
||||||
|
void UpdateDraggableRegions(
|
||||||
|
const std::vector<mojom::DraggableRegionPtr>& regions) override;
|
||||||
|
|
||||||
// views::View:
|
// views::View:
|
||||||
void Layout() override;
|
void Layout() override;
|
||||||
|
|
||||||
InspectableWebContents* inspectable_web_contents() {
|
|
||||||
return inspectable_web_contents_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::u16string& GetTitle() const { return title_; }
|
const std::u16string& GetTitle() const { return title_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Owns us.
|
|
||||||
InspectableWebContents* inspectable_web_contents_;
|
|
||||||
|
|
||||||
std::unique_ptr<views::Widget> devtools_window_;
|
std::unique_ptr<views::Widget> devtools_window_;
|
||||||
views::WebView* devtools_window_web_view_ = nullptr;
|
views::WebView* devtools_window_web_view_ = nullptr;
|
||||||
views::View* contents_web_view_ = nullptr;
|
views::View* contents_web_view_ = nullptr;
|
||||||
|
@ -63,6 +61,8 @@ class InspectableWebContentsViewViews : public InspectableWebContentsView,
|
||||||
bool devtools_visible_ = false;
|
bool devtools_visible_ = false;
|
||||||
views::WidgetDelegate* devtools_window_delegate_ = nullptr;
|
views::WidgetDelegate* devtools_window_delegate_ = nullptr;
|
||||||
std::u16string title_;
|
std::u16string title_;
|
||||||
|
|
||||||
|
std::unique_ptr<SkRegion> draggable_region_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
Loading…
Reference in a new issue