mac: Simplify frameless window dragging code

This commit is contained in:
Cheng Zhao 2014-12-23 15:50:42 -08:00
parent 4ca0458b37
commit 85685feff4
2 changed files with 45 additions and 75 deletions

View file

@ -83,8 +83,6 @@ class NativeWindowMac : public NativeWindow {
// Clip web view to rounded corner. // Clip web view to rounded corner.
void ClipWebView(); void ClipWebView();
SkRegion* draggable_region() const { return draggable_region_.get(); }
protected: protected:
void UpdateDraggableRegions( void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override; const std::vector<DraggableRegion>& regions) override;
@ -97,9 +95,10 @@ class NativeWindowMac : public NativeWindow {
private: private:
void InstallView(); void InstallView();
void UninstallView(); void UninstallView();
void InstallDraggableRegionViews();
void UpdateDraggableRegionsForCustomDrag( // Install the drag view, which will cover the whole window and decides
const std::vector<DraggableRegion>& regions); // whehter we can drag.
void InstallDraggableRegionView();
base::scoped_nsobject<NSWindow> window_; base::scoped_nsobject<NSWindow> window_;
@ -113,10 +112,6 @@ class NativeWindowMac : public NativeWindow {
// The presentation options before entering kiosk mode. // The presentation options before entering kiosk mode.
NSApplicationPresentationOptions kiosk_options_; NSApplicationPresentationOptions kiosk_options_;
// For system drag, the whole window is draggable and the non-draggable areas
// have to been explicitly excluded.
std::vector<gfx::Rect> system_drag_exclude_areas_;
// For custom drag, the whole window is non-draggable and the draggable region // For custom drag, the whole window is non-draggable and the draggable region
// has to been explicitly provided. // has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag. scoped_ptr<SkRegion> draggable_region_; // used in custom drag.

View file

@ -101,7 +101,7 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
shell_->NotifyWindowBlur(); shell_->NotifyWindowBlur();
} }
- (void)windowDidResize:(NSNotification*)otification { - (void)windowDidResize:(NSNotification*)notification {
if (!shell_->has_frame()) if (!shell_->has_frame())
shell_->ClipWebView(); shell_->ClipWebView();
} }
@ -280,6 +280,29 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
namespace atom { namespace atom {
namespace {
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
SkRegion* DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
SkRegion* sk_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
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
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents, NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
const mate::Dictionary& options) const mate::Dictionary& options)
: NativeWindow(web_contents, options), : NativeWindow(web_contents, options),
@ -680,7 +703,6 @@ void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)]; NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)];
NSPoint current_mouse_location = mouseRect.origin; NSPoint current_mouse_location = mouseRect.origin;
if ([event type] == NSLeftMouseDown) { if ([event type] == NSLeftMouseDown) {
NSPoint frame_origin = [window_ frame].origin; NSPoint frame_origin = [window_ frame].origin;
last_mouse_offset_ = NSMakePoint( last_mouse_offset_ = NSMakePoint(
@ -699,8 +721,7 @@ void NativeWindowMac::UpdateDraggableRegions(
if (has_frame_) if (has_frame_)
return; return;
UpdateDraggableRegionsForCustomDrag(regions); draggable_region_.reset(DraggableRegionsToSkRegion(regions));
InstallDraggableRegionViews();
} }
void NativeWindowMac::HandleKeyboardEvent( void NativeWindowMac::HandleKeyboardEvent(
@ -757,11 +778,16 @@ void NativeWindowMac::InstallView() {
} }
ClipWebView(); ClipWebView();
InstallDraggableRegionView();
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
// Some third-party OS X utilities check the zoom button's enabled state to
// determine whether to show custom UI on hover, so we disable it here to
// prevent them from doing so in a frameless app window.
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
} }
} }
@ -771,70 +797,19 @@ void NativeWindowMac::UninstallView() {
} }
void NativeWindowMac::ClipWebView() { void NativeWindowMac::ClipWebView() {
NSView* view = GetWebContents()->GetNativeView();
view.layer.masksToBounds = YES;
view.layer.cornerRadius = kAtomWindowCornerRadius;
}
void NativeWindowMac::InstallDraggableRegionViews() {
DCHECK(!has_frame_);
// 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 = GetWebContents()->GetNativeView(); NSView* webView = GetWebContents()->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]); webView.layer.masksToBounds = YES;
webView.layer.cornerRadius = kAtomWindowCornerRadius;
// 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<NSArray> subviews([[webView subviews] copy]);
for (NSView* subview in subviews.get())
if ([subview isKindOfClass:[ControlRegionView class]])
[subview removeFromSuperview];
// Create and add ControlRegionView for each region that needs to be excluded
// from the dragging.
for (std::vector<gfx::Rect>::const_iterator iter =
system_drag_exclude_areas_.begin();
iter != system_drag_exclude_areas_.end();
++iter) {
base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithShellWindow:this]);
[controlRegion setFrame:NSMakeRect(iter->x(),
webViewHeight - iter->bottom(),
iter->width(),
iter->height())];
[webView addSubview:controlRegion];
}
} }
void NativeWindowMac::UpdateDraggableRegionsForCustomDrag( void NativeWindowMac::InstallDraggableRegionView() {
const std::vector<DraggableRegion>& regions) { NSView* webView = GetWebContents()->GetNativeView();
// We still need one ControlRegionView to cover the whole window such that base::scoped_nsobject<NSView> controlRegion(
// mouse events could be captured. [[ControlRegionView alloc] initWithShellWindow:this]);
NSView* web_view = GetWebContents()->GetNativeView(); [controlRegion setFrame:NSMakeRect(0, 0,
gfx::Rect window_bounds( NSWidth([webView bounds]),
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds])); NSHeight([webView bounds]))];
system_drag_exclude_areas_.clear(); [webView addSubview:controlRegion];
system_drag_exclude_areas_.push_back(window_bounds);
// Aggregate the draggable areas and non-draggable areas such that hit test
// could be performed easily.
SkRegion* draggable_region = new SkRegion;
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
iter != regions.end();
++iter) {
const DraggableRegion& region = *iter;
draggable_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
draggable_region_.reset(draggable_region);
} }
// static // static