From 503b0ba1b17f8e6c40b36ceb0dfed9b6e430a96a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 6 Mar 2018 14:44:36 +0900 Subject: [PATCH] mac: Move draggable region code to BrowserWindow On macOS current draggable region implementation highly relies on WebContents, the code is only meaningful for BrowserWindow. --- atom/browser/api/atom_api_browser_window.cc | 19 ++++ atom/browser/api/atom_api_browser_window.h | 8 ++ .../api/atom_api_browser_window_mac.mm | 93 ++++++++++++++++++- .../api/atom_api_browser_window_views.cc | 4 +- atom/browser/native_window.cc | 16 ---- atom/browser/native_window.h | 9 -- atom/browser/native_window_mac.h | 14 +-- atom/browser/native_window_mac.mm | 85 ----------------- atom/browser/native_window_views.cc | 7 +- atom/browser/native_window_views.h | 4 +- 10 files changed, 127 insertions(+), 132 deletions(-) diff --git a/atom/browser/api/atom_api_browser_window.cc b/atom/browser/api/atom_api_browser_window.cc index 92647e8086..5c21634b1d 100644 --- a/atom/browser/api/atom_api_browser_window.cc +++ b/atom/browser/api/atom_api_browser_window.cc @@ -409,6 +409,10 @@ void BrowserWindow::OnWindowRestore() { } void BrowserWindow::OnWindowResize() { +#if defined(OS_MACOSX) + if (!draggable_regions_.empty()) + UpdateDraggableRegions(nullptr, draggable_regions_); +#endif Emit("resize"); } @@ -1169,6 +1173,21 @@ void BrowserWindow::RemoveFromParentChildWindows() { parent->child_windows_.Remove(ID()); } +// Convert draggable regions in raw format to SkRegion format. +std::unique_ptr BrowserWindow::DraggableRegionsToSkRegion( + const std::vector& regions) { + std::unique_ptr sk_region(new SkRegion); + for (const DraggableRegion& region : regions) { + sk_region->op( + region.bounds.x(), + region.bounds.y(), + region.bounds.right(), + region.bounds.bottom(), + region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op); + } + return sk_region; +} + void BrowserWindow::ScheduleUnresponsiveEvent(int ms) { if (!window_unresponsive_closure_.IsCancelled()) return; diff --git a/atom/browser/api/atom_api_browser_window.h b/atom/browser/api/atom_api_browser_window.h index 8d0a31b6ee..82c2c01780 100644 --- a/atom/browser/api/atom_api_browser_window.h +++ b/atom/browser/api/atom_api_browser_window.h @@ -261,6 +261,10 @@ class BrowserWindow : public mate::TrackableObject, content::RenderFrameHost* rfh, const std::vector& regions); + // Convert draggable regions in raw format to SkRegion format. + std::unique_ptr DraggableRegionsToSkRegion( + const std::vector& regions); + // Schedule a notification unresponsive event. void ScheduleUnresponsiveEvent(int ms); @@ -272,6 +276,10 @@ class BrowserWindow : public mate::TrackableObject, MessageCallbackMap messages_callback_map_; #endif +#if defined(OS_MACOSX) + std::vector draggable_regions_; +#endif + // Closure that would be called when window is unresponsive when closing, // it should be cancelled when we can prove that the window is responsive. base::CancelableClosure window_unresponsive_closure_; diff --git a/atom/browser/api/atom_api_browser_window_mac.mm b/atom/browser/api/atom_api_browser_window_mac.mm index 00fa4436c8..5c55f64a83 100644 --- a/atom/browser/api/atom_api_browser_window_mac.mm +++ b/atom/browser/api/atom_api_browser_window_mac.mm @@ -6,24 +6,115 @@ #import +#include "atom/browser/native_browser_view_mac.h" +#include "atom/browser/native_window_mac.h" +#include "atom/common/draggable_region.h" +#include "base/mac/scoped_nsobject.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 atom { namespace api { +namespace { + +// Return a vector of non-draggable regions that fill a window of size +// |width| by |height|, but leave gaps where the window should be draggable. +std::vector CalculateNonDraggableRegions( + std::unique_ptr draggable, int width, int height) { + std::vector result; + std::unique_ptr non_draggable(new SkRegion); + non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); + non_draggable->op(*draggable, SkRegion::kDifference_Op); + for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { + result.push_back(gfx::SkIRectToRect(it.rect())); + } + return result; +} + +} // namespace + void BrowserWindow::UpdateDraggableRegions( content::RenderFrameHost* rfh, const std::vector& regions) { if (window_->has_frame()) return; + + // All ControlRegionViews should be added as children of the WebContentsView, + // because WebContentsView will be removed and re-added when entering and + // leaving fullscreen mode. NSView* webView = web_contents()->GetNativeView(); + NSInteger webViewWidth = NSWidth([webView bounds]); + NSInteger webViewHeight = NSHeight([webView bounds]); + if ([webView respondsToSelector:@selector(setMouseDownCanMoveWindow:)]) { [webView setMouseDownCanMoveWindow:YES]; } - window_->UpdateDraggableRegions(regions); + + // Remove all ControlRegionViews that are added last time. + // Note that [webView subviews] returns the view's mutable internal array and + // it should be copied to avoid mutating the original array while enumerating + // it. + base::scoped_nsobject subviews([[webView subviews] copy]); + for (NSView* subview in subviews.get()) + if ([subview isKindOfClass:[ControlRegionView class]]) + [subview removeFromSuperview]; + + // Draggable regions is implemented by having the whole web view draggable + // (mouseDownCanMoveWindow) and overlaying regions that are not draggable. + draggable_regions_ = regions; + std::vector system_drag_exclude_areas; + if (regions.empty()) { + system_drag_exclude_areas.push_back( + gfx::Rect(0, 0, webViewWidth, webViewHeight)); + } else { + CalculateNonDraggableRegions( + DraggableRegionsToSkRegion(regions), webViewWidth, webViewHeight); + } + + NativeWindowMac* window = static_cast(window_.get()); + if (window->browser_view()) + window->browser_view()->UpdateDraggableRegions(system_drag_exclude_areas); + + // Create and add a ControlRegionView for each region that needs to be + // excluded from the dragging. + for (std::vector::const_iterator iter = + system_drag_exclude_areas.begin(); + iter != system_drag_exclude_areas.end(); + ++iter) { + base::scoped_nsobject controlRegion( + [[ControlRegionView alloc] initWithFrame:NSZeroRect]); + [controlRegion setFrame:NSMakeRect(iter->x(), + webViewHeight - iter->bottom(), + iter->width(), + iter->height())]; + [webView addSubview:controlRegion]; + } + + // AppKit will not update its cache of mouseDownCanMoveWindow unless something + // changes. Previously we tried adding an NSView and removing it, but for some + // reason it required reposting the mouse-down event, and didn't always work. + // Calling the below seems to be an effective solution. + [[webView window] setMovableByWindowBackground:NO]; + [[webView window] setMovableByWindowBackground:YES]; } } // namespace api diff --git a/atom/browser/api/atom_api_browser_window_views.cc b/atom/browser/api/atom_api_browser_window_views.cc index 23982281f4..66a1c8861d 100644 --- a/atom/browser/api/atom_api_browser_window_views.cc +++ b/atom/browser/api/atom_api_browser_window_views.cc @@ -11,7 +11,9 @@ namespace api { void BrowserWindow::UpdateDraggableRegions( content::RenderFrameHost* rfh, const std::vector& regions) { - window_->UpdateDraggableRegions(regions); + if (window_->has_frame()) + return; + window_->UpdateDraggableRegions(DraggableRegionsToSkRegion(regions)); } } // namespace api diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index e1d9748af4..e85e136edf 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -13,7 +13,6 @@ #include "atom/browser/browser.h" #include "atom/browser/window_list.h" #include "atom/common/color_util.h" -#include "atom/common/draggable_region.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/options_switches.h" #include "base/files/file_util.h" @@ -33,7 +32,6 @@ #include "content/public/common/content_switches.h" #include "ipc/ipc_message_macros.h" #include "native_mate/dictionary.h" -#include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" @@ -569,18 +567,4 @@ void NativeWindow::NotifyWindowMessage( } #endif -std::unique_ptr NativeWindow::DraggableRegionsToSkRegion( - const std::vector& regions) { - std::unique_ptr sk_region(new SkRegion); - for (const DraggableRegion& region : regions) { - sk_region->op( - region.bounds.x(), - region.bounds.y(), - region.bounds.right(), - region.bounds.bottom(), - region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op); - } - return sk_region; -} - } // namespace atom diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 32aef493c3..0882667008 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -221,10 +221,6 @@ class NativeWindow : public base::SupportsUserData, virtual gfx::Rect WindowBoundsToContentBounds( const gfx::Rect& bounds) const = 0; - // Called when the window needs to update its draggable region. - virtual void UpdateDraggableRegions( - const std::vector& regions) = 0; - base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } @@ -304,11 +300,6 @@ class NativeWindow : public base::SupportsUserData, const mate::Dictionary& options, NativeWindow* parent); - // Convert draggable regions in raw format to SkRegion format. Caller is - // responsible for deleting the returned SkRegion instance. - std::unique_ptr DraggableRegionsToSkRegion( - const std::vector& regions); - private: // Whether window has standard frame. bool has_frame_; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index aa47ca07b3..b36bdf338b 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -119,8 +119,6 @@ class NativeWindowMac : public NativeWindow { gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const; gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const; - void UpdateDraggableRegions( - const std::vector& regions) override; // Set the attribute of NSWindow while work around a bug of zoom button. void SetStyleMask(bool on, NSUInteger flag); @@ -137,15 +135,7 @@ class NativeWindowMac : public NativeWindow { bool zoom_to_page_width() const { return zoom_to_page_width_; } bool fullscreen_window_title() const { return fullscreen_window_title_; } bool simple_fullscreen() const { return always_simple_fullscreen_; } - const std::vector& draggable_regions() const { - return draggable_regions_; - } - - protected: - // Return a vector of non-draggable regions that fill a window of size - // |width| by |height|, but leave gaps where the window should be draggable. - std::vector CalculateNonDraggableRegions( - const std::vector& regions, int width, int height); + NativeBrowserView* browser_view() const { return browser_view_; } private: void InternalSetParentWindow(NativeWindow* parent, bool attach); @@ -165,8 +155,6 @@ class NativeWindowMac : public NativeWindow { NativeBrowserView* browser_view_; - std::vector draggable_regions_; - bool is_kiosk_; bool was_fullscreen_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index d3b1db60ac..0308a7c3ed 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -12,7 +12,6 @@ #include "atom/browser/native_browser_view_mac.h" #include "atom/browser/ui/cocoa/atom_touch_bar.h" #include "atom/browser/window_list.h" -#include "atom/common/draggable_region.h" #include "atom/common/options_switches.h" #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" @@ -23,7 +22,6 @@ #include "content/public/browser/browser_accessibility_state.h" #include "native_mate/dictionary.h" #include "skia/ext/skia_utils_mac.h" -#include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/skia_util.h" namespace { @@ -270,7 +268,6 @@ bool ScopedDisableResize::disable_resize_ = false; } - (void)windowDidResize:(NSNotification*)notification { - shell_->UpdateDraggableRegions(shell_->draggable_regions()); shell_->NotifyWindowResize(); } @@ -721,21 +718,6 @@ enum { @end -@interface ControlRegionView : NSView -@end - -@implementation ControlRegionView - -- (BOOL)mouseDownCanMoveWindow { - return NO; -} - -- (NSView*)hitTest:(NSPoint)aPoint { - return nil; -} - -@end - @interface AtomProgressBar : NSProgressIndicator @end @@ -1759,73 +1741,6 @@ gfx::Rect NativeWindowMac::WindowBoundsToContentBounds( } } -void NativeWindowMac::UpdateDraggableRegions( - const std::vector& regions) { - // All ControlRegionViews should be added as children of the WebContentsView, - // because WebContentsView will be removed and re-added when entering and - // leaving fullscreen mode. - NSView* webView = web_contents()->GetNativeView(); - NSInteger webViewWidth = NSWidth([webView bounds]); - NSInteger webViewHeight = NSHeight([webView bounds]); - - // Remove all ControlRegionViews that are added last time. - // Note that [webView subviews] returns the view's mutable internal array and - // it should be copied to avoid mutating the original array while enumerating - // it. - base::scoped_nsobject subviews([[webView subviews] copy]); - for (NSView* subview in subviews.get()) - if ([subview isKindOfClass:[ControlRegionView class]]) - [subview removeFromSuperview]; - - // Draggable regions is implemented by having the whole web view draggable - // (mouseDownCanMoveWindow) and overlaying regions that are not draggable. - draggable_regions_ = regions; - std::vector system_drag_exclude_areas = - CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight); - - if (browser_view_) - browser_view_->UpdateDraggableRegions(system_drag_exclude_areas); - - // Create and add a ControlRegionView for each region that needs to be - // excluded from the dragging. - for (std::vector::const_iterator iter = - system_drag_exclude_areas.begin(); - iter != system_drag_exclude_areas.end(); - ++iter) { - base::scoped_nsobject controlRegion( - [[ControlRegionView alloc] initWithFrame:NSZeroRect]); - [controlRegion setFrame:NSMakeRect(iter->x(), - webViewHeight - iter->bottom(), - iter->width(), - iter->height())]; - [webView addSubview:controlRegion]; - } - - // AppKit will not update its cache of mouseDownCanMoveWindow unless something - // changes. Previously we tried adding an NSView and removing it, but for some - // reason it required reposting the mouse-down event, and didn't always work. - // Calling the below seems to be an effective solution. - [window_ setMovableByWindowBackground:NO]; - [window_ setMovableByWindowBackground:YES]; -} - -std::vector NativeWindowMac::CalculateNonDraggableRegions( - const std::vector& regions, int width, int height) { - std::vector result; - if (regions.empty()) { - result.push_back(gfx::Rect(0, 0, width, height)); - } else { - std::unique_ptr draggable(DraggableRegionsToSkRegion(regions)); - std::unique_ptr non_draggable(new SkRegion); - non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); - non_draggable->op(*draggable, SkRegion::kDifference_Op); - for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { - result.push_back(gfx::SkIRectToRect(it.rect())); - } - } - return result; -} - void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent, bool attach) { if (is_modal()) return; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 9d7f2ba195..1789167645 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -1121,11 +1121,8 @@ gfx::Rect NativeWindowViews::WindowBoundsToContentBounds( } void NativeWindowViews::UpdateDraggableRegions( - const std::vector& regions) { - // Draggable region is not supported for non-frameless window. - if (has_frame()) - return; - draggable_region_ = DraggableRegionsToSkRegion(regions); + std::unique_ptr region) { + draggable_region_ = std::move(region); } #if defined(OS_WIN) diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 1d6fad7d26..11f530b2ca 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -128,8 +128,8 @@ class NativeWindowViews : public NativeWindow, gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override; gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override; - void UpdateDraggableRegions( - const std::vector& regions) override; + + void UpdateDraggableRegions(std::unique_ptr region); #if defined(OS_WIN) void SetIcon(HICON small_icon, HICON app_icon);