atom_api_browser_window_mac.mm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // Copyright (c) 2018 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/api/atom_api_browser_window.h"
  5. #import <Cocoa/Cocoa.h>
  6. #include "atom/browser/native_browser_view.h"
  7. #include "atom/common/draggable_region.h"
  8. #include "base/mac/scoped_nsobject.h"
  9. @interface NSView (WebContentsView)
  10. - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
  11. @end
  12. @interface ControlRegionView : NSView
  13. @end
  14. @implementation ControlRegionView
  15. - (BOOL)mouseDownCanMoveWindow {
  16. return NO;
  17. }
  18. - (NSView*)hitTest:(NSPoint)aPoint {
  19. return nil;
  20. }
  21. @end
  22. namespace atom {
  23. namespace api {
  24. namespace {
  25. // Return a vector of non-draggable regions that fill a window of size
  26. // |width| by |height|, but leave gaps where the window should be draggable.
  27. std::vector<gfx::Rect> CalculateNonDraggableRegions(
  28. std::unique_ptr<SkRegion> draggable,
  29. int width,
  30. int height) {
  31. std::vector<gfx::Rect> result;
  32. std::unique_ptr<SkRegion> non_draggable(new SkRegion);
  33. non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op);
  34. non_draggable->op(*draggable, SkRegion::kDifference_Op);
  35. for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) {
  36. result.push_back(gfx::SkIRectToRect(it.rect()));
  37. }
  38. return result;
  39. }
  40. } // namespace
  41. void BrowserWindow::UpdateDraggableRegions(
  42. content::RenderFrameHost* rfh,
  43. const std::vector<DraggableRegion>& regions) {
  44. if (window_->has_frame())
  45. return;
  46. // All ControlRegionViews should be added as children of the WebContentsView,
  47. // because WebContentsView will be removed and re-added when entering and
  48. // leaving fullscreen mode.
  49. NSView* webView = web_contents()->GetNativeView();
  50. NSInteger webViewWidth = NSWidth([webView bounds]);
  51. NSInteger webViewHeight = NSHeight([webView bounds]);
  52. if ([webView respondsToSelector:@selector(setMouseDownCanMoveWindow:)]) {
  53. [webView setMouseDownCanMoveWindow:YES];
  54. }
  55. // Remove all ControlRegionViews that are added last time.
  56. // Note that [webView subviews] returns the view's mutable internal array and
  57. // it should be copied to avoid mutating the original array while enumerating
  58. // it.
  59. base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
  60. for (NSView* subview in subviews.get())
  61. if ([subview isKindOfClass:[ControlRegionView class]])
  62. [subview removeFromSuperview];
  63. // Draggable regions is implemented by having the whole web view draggable
  64. // (mouseDownCanMoveWindow) and overlaying regions that are not draggable.
  65. draggable_regions_ = regions;
  66. std::vector<gfx::Rect> drag_exclude_rects;
  67. if (regions.empty()) {
  68. drag_exclude_rects.push_back(gfx::Rect(0, 0, webViewWidth, webViewHeight));
  69. } else {
  70. drag_exclude_rects = CalculateNonDraggableRegions(
  71. DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight);
  72. }
  73. if (window_->browser_view())
  74. window_->browser_view()->UpdateDraggableRegions(drag_exclude_rects);
  75. // Create and add a ControlRegionView for each region that needs to be
  76. // excluded from the dragging.
  77. for (const auto& rect : drag_exclude_rects) {
  78. base::scoped_nsobject<NSView> controlRegion(
  79. [[ControlRegionView alloc] initWithFrame:NSZeroRect]);
  80. [controlRegion setFrame:NSMakeRect(rect.x(), webViewHeight - rect.bottom(),
  81. rect.width(), rect.height())];
  82. [webView addSubview:controlRegion];
  83. }
  84. // AppKit will not update its cache of mouseDownCanMoveWindow unless something
  85. // changes. Previously we tried adding an NSView and removing it, but for some
  86. // reason it required reposting the mouse-down event, and didn't always work.
  87. // Calling the below seems to be an effective solution.
  88. [[webView window] setMovableByWindowBackground:NO];
  89. [[webView window] setMovableByWindowBackground:YES];
  90. }
  91. } // namespace api
  92. } // namespace atom