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,71 +797,20 @@ void NativeWindowMac::UninstallView() {
} }
void NativeWindowMac::ClipWebView() { void NativeWindowMac::ClipWebView() {
NSView* view = GetWebContents()->GetNativeView(); NSView* webView = GetWebContents()->GetNativeView();
view.layer.masksToBounds = YES; webView.layer.masksToBounds = YES;
view.layer.cornerRadius = kAtomWindowCornerRadius; webView.layer.cornerRadius = kAtomWindowCornerRadius;
} }
void NativeWindowMac::InstallDraggableRegionViews() { void NativeWindowMac::InstallDraggableRegionView() {
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]);
// 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( base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithShellWindow:this]); [[ControlRegionView alloc] initWithShellWindow:this]);
[controlRegion setFrame:NSMakeRect(iter->x(), [controlRegion setFrame:NSMakeRect(0, 0,
webViewHeight - iter->bottom(), NSWidth([webView bounds]),
iter->width(), NSHeight([webView bounds]))];
iter->height())];
[webView addSubview:controlRegion]; [webView addSubview:controlRegion];
} }
}
void NativeWindowMac::UpdateDraggableRegionsForCustomDrag(
const std::vector<DraggableRegion>& regions) {
// We still need one ControlRegionView to cover the whole window such that
// mouse events could be captured.
NSView* web_view = GetWebContents()->GetNativeView();
gfx::Rect window_bounds(
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
system_drag_exclude_areas_.clear();
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
NativeWindow* NativeWindow::Create(content::WebContents* web_contents, NativeWindow* NativeWindow::Create(content::WebContents* web_contents,