123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- // Copyright (c) 2017 GitHub, Inc.
- // Use of this source code is governed by the MIT license that can be
- // found in the LICENSE file.
- #include "atom/browser/native_browser_view_mac.h"
- #include "atom/browser/ui/inspectable_web_contents.h"
- #include "atom/browser/ui/inspectable_web_contents_view.h"
- #include "skia/ext/skia_utils_mac.h"
- #include "ui/gfx/geometry/rect.h"
- // Match view::Views behavior where the view sticks to the top-left origin.
- const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
- NSViewMaxXMargin | NSViewMinYMargin;
- @interface DragRegionView : NSView
- @property(assign) NSPoint initialLocation;
- @end
- @interface NSWindow ()
- - (void)performWindowDragWithEvent:(NSEvent*)event;
- @end
- @implementation DragRegionView
- @synthesize initialLocation;
- - (BOOL)mouseDownCanMoveWindow {
- return NO;
- }
- - (NSView*)hitTest:(NSPoint)aPoint {
- // Pass-through events that don't hit one of the exclusion zones
- for (NSView* exlusion_zones in [self subviews]) {
- if ([exlusion_zones hitTest:aPoint])
- return nil;
- }
- return self;
- }
- - (void)mouseDown:(NSEvent*)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];
- if (@available(macOS 10.11, *)) {
- [self.window performWindowDragWithEvent:event];
- }
- return;
- }
- if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
- return;
- }
- self.initialLocation = [event locationInWindow];
- }
- - (void)mouseDragged:(NSEvent*)theEvent {
- 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];
- }
- // Debugging tips:
- // Uncomment the following four lines to color DragRegionView bright red
- // #ifdef DEBUG_DRAG_REGIONS
- // - (void)drawRect:(NSRect)aRect
- // {
- // [[NSColor redColor] set];
- // NSRectFill([self bounds]);
- // }
- // #endif
- @end
- @interface ExcludeDragRegionView : NSView
- @end
- @implementation ExcludeDragRegionView
- - (BOOL)mouseDownCanMoveWindow {
- return NO;
- }
- // Debugging tips:
- // Uncomment the following four lines to color ExcludeDragRegionView bright red
- // #ifdef DEBUG_DRAG_REGIONS
- // - (void)drawRect:(NSRect)aRect
- // {
- // [[NSColor greenColor] set];
- // NSRectFill([self bounds]);
- // }
- // #endif
- @end
- namespace atom {
- NativeBrowserViewMac::NativeBrowserViewMac(
- InspectableWebContents* inspectable_web_contents)
- : NativeBrowserView(inspectable_web_contents) {
- auto* view =
- GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
- view.autoresizingMask = kDefaultAutoResizingMask;
- }
- NativeBrowserViewMac::~NativeBrowserViewMac() {}
- void NativeBrowserViewMac::SetAutoResizeFlags(uint8_t flags) {
- NSAutoresizingMaskOptions autoresizing_mask = kDefaultAutoResizingMask;
- if (flags & kAutoResizeWidth) {
- autoresizing_mask |= NSViewWidthSizable;
- }
- if (flags & kAutoResizeHeight) {
- autoresizing_mask |= NSViewHeightSizable;
- }
- auto* view =
- GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
- view.autoresizingMask = autoresizing_mask;
- }
- void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) {
- auto* view =
- GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
- auto* superview = view.superview;
- const auto superview_height = superview ? superview.frame.size.height : 0;
- view.frame =
- NSMakeRect(bounds.x(), superview_height - bounds.y() - bounds.height(),
- bounds.width(), bounds.height());
- }
- void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
- auto* view =
- GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
- view.wantsLayer = YES;
- view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
- }
- void NativeBrowserViewMac::UpdateDraggableRegions(
- const std::vector<gfx::Rect>& drag_exclude_rects) {
- NSView* web_view = GetWebContents()->GetNativeView().GetNativeNSView();
- NSView* inspectable_view =
- GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
- NSView* window_content_view = inspectable_view.superview;
- const auto window_content_view_height = NSHeight(window_content_view.bounds);
- // 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"
- for (const auto& rect : drag_exclude_rects) {
- const auto window_content_view_exclude_rect =
- NSMakeRect(rect.x(), window_content_view_height - rect.bottom(),
- rect.width(), rect.height());
- const auto drag_region_view_exclude_rect =
- [window_content_view convertRect:window_content_view_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];
- }
- }
- // static
- NativeBrowserView* NativeBrowserView::Create(
- InspectableWebContents* inspectable_web_contents) {
- return new NativeBrowserViewMac(inspectable_web_contents);
- }
- } // namespace atom
|