commit 8b1f07f31cd04fb157bf99a9e2e600b4422f277f Author: Markus Stange mstange@themasta.com Date: Mon Jul 11 16:15:07 2016 -0400
Bug 1070710 - Use ViewRegion for window dragging. r=spohl
MozReview-Commit-ID: 5x2XHl20P6a
--HG-- extra : histedit_source : 56b671bffe9e6cd497ade61ff9beed2e3bf98e14 --- widget/cocoa/nsChildView.h | 5 +- widget/cocoa/nsChildView.mm | 117 ++++++++++++++------------------------------ 2 files changed, 40 insertions(+), 82 deletions(-)
diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index 8f07c70..e7bd6b0 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -28,6 +28,7 @@
#include "nsString.h" #include "nsIDragService.h" +#include "ViewRegion.h"
#import <Carbon/Carbon.h> #import <Cocoa/Cocoa.h> @@ -493,7 +494,7 @@ public: virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) override;
virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override; - const LayoutDeviceIntRegion& GetDraggableRegion() { return mDraggableRegion; } + LayoutDeviceIntRegion GetNonDraggableRegion() { return mNonDraggableRegion.Region(); }
virtual void ReportSwipeStarted(uint64_t aInputBlockId, bool aStartSwipe) override;
@@ -659,7 +660,7 @@ protected: // uploaded to to mTitlebarImage. Main thread only. nsIntRegion mDirtyTitlebarRegion;
- LayoutDeviceIntRegion mDraggableRegion; + mozilla::ViewRegion mNonDraggableRegion;
// Cached value of [mView backingScaleFactor], to avoid sending two obj-c // messages (respondsToSelector, backingScaleFactor) every time we need to diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 8dbeacc..1415664 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2720,12 +2720,41 @@ nsChildView::DoRemoteComposition(const LayoutDeviceIntRect& aRenderRect) [(ChildView*)mView postRender:mGLPresenter->GetNSOpenGLContext()]; }
+@interface NonDraggableView : NSView +@end + +@implementation NonDraggableView +- (BOOL)mouseDownCanMoveWindow { return NO; } +- (NSView*)hitTest:(NSPoint)aPoint { return nil; } +@end + void nsChildView::UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) { - if (mDraggableRegion != aRegion) { - mDraggableRegion = aRegion; - [(ChildView*)mView updateWindowDraggableState]; + // mView returns YES from mouseDownCanMoveWindow, so we need to put NSViews + // that return NO from mouseDownCanMoveWindow in the places that shouldn't + // be draggable. We can't do it the other way round because returning + // YES from mouseDownCanMoveWindow doesn't have any effect if there's a + // superview that returns NO. + LayoutDeviceIntRegion nonDraggable; + nonDraggable.Sub(LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height), aRegion); + + __block bool changed = false; + + // Suppress calls to setNeedsDisplay during NSView geometry changes. + ManipulateViewWithoutNeedingDisplay(mView, ^() { + changed = mNonDraggableRegion.UpdateRegion(nonDraggable, *this, mView, ^() { + return [[NonDraggableView alloc] initWithFrame:NSZeroRect]; + }); + }); + + if (changed) { + // Trigger an update to the window server. This will call + // mouseDownCanMoveWindow. + // Doing this manually is only necessary because we're suppressing + // setNeedsDisplay calls above. + [[mView window] setMovableByWindowBackground:NO]; + [[mView window] setMovableByWindowBackground:YES]; } }
@@ -3566,8 +3595,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
- (BOOL)mouseDownCanMoveWindow { - // Return YES so that _regionForOpaqueDescendants gets called, where the - // actual draggable region will be assembled. + // Return YES so that parts of this view can be draggable. The non-draggable + // parts will be covered by NSViews that return NO from + // mouseDownCanMoveWindow and thus override draggability from the inside. + // These views are assembled in nsChildView::UpdateWindowDraggingRegion. return YES; }
@@ -4572,7 +4603,7 @@ NSEvent* gLastDragMouseDownEvent = nil; CGFloat locationInTitlebar = [[self window] frame].size.height - [theEvent locationInWindow].y; LayoutDeviceIntPoint pos = geckoEvent.refPoint; if (!defaultPrevented && [theEvent clickCount] == 2 && - mGeckoChild->GetDraggableRegion().Contains(pos.x, pos.y) && + !mGeckoChild->GetNonDraggableRegion().Contains(pos.x, pos.y) && [[self window] isKindOfClass:[ToolbarWindow class]] && (locationInTitlebar < [(ToolbarWindow*)[self window] titlebarHeight] || locationInTitlebar < [(ToolbarWindow*)[self window] unifiedToolbarHeight])) { @@ -4607,80 +4638,6 @@ NSEvent* gLastDragMouseDownEvent = nil; mGeckoChild->DispatchEvent(&event, status); }
-- (void)updateWindowDraggableState -{ - // Trigger update to the window server. - [[self window] setMovableByWindowBackground:NO]; - [[self window] setMovableByWindowBackground:YES]; -} - -// aRect is in view coordinates relative to this NSView. -- (CGRect)convertToFlippedWindowCoordinates:(NSRect)aRect -{ - // First, convert the rect to regular window coordinates... - NSRect inWindowCoords = [self convertRect:aRect toView:nil]; - // ... and then flip it again because window coordinates have their origin - // in the bottom left corner, and we need it to be in the top left corner. - inWindowCoords.origin.y = [[self window] frame].size.height - NSMaxY(inWindowCoords); - return NSRectToCGRect(inWindowCoords); -} - -static CGSRegionObj -NewCGSRegionFromRegion(const LayoutDeviceIntRegion& aRegion, - CGRect (^aRectConverter)(const LayoutDeviceIntRect&)) -{ - nsTArray<CGRect> rects; - LayoutDeviceIntRegion::RectIterator iter(aRegion); - for (;;) { - const LayoutDeviceIntRect* r = iter.Next(); - if (!r) { - break; - } - rects.AppendElement(aRectConverter(*r)); - } - - CGSRegionObj region; - CGSNewRegionWithRectList(rects.Elements(), rects.Length(), ®ion); - return region; -} - -// This function is called with forMove:YES to calculate the draggable region -// of the window which will be submitted to the window server. Window dragging -// is handled on the window server without calling back into our process, so it -// also works while our app is unresponsive. -- (CGSRegionObj)_regionForOpaqueDescendants:(NSRect)aRect forMove:(BOOL)aForMove -{ - if (!aForMove || !mGeckoChild) { - return [super _regionForOpaqueDescendants:aRect forMove:aForMove]; - } - - LayoutDeviceIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect); - - LayoutDeviceIntRegion opaqueRegion; - opaqueRegion.Sub(boundingRect, mGeckoChild->GetDraggableRegion()); - - return NewCGSRegionFromRegion(opaqueRegion, ^(const LayoutDeviceIntRect& r) { - return [self convertToFlippedWindowCoordinates:mGeckoChild->DevPixelsToCocoaPoints(r)]; - }); -} - -// Starting with 10.10, in addition to the traditional -// -[NSView _regionForOpaqueDescendants:forMove:] method, there's a new form with -// an additional forUnderTitlebar argument, which is sometimes called instead of -// the old form. We need to override the new variant as well. -- (CGSRegionObj)_regionForOpaqueDescendants:(NSRect)aRect - forMove:(BOOL)aForMove - forUnderTitlebar:(BOOL)aForUnderTitlebar -{ - if (!aForMove || !mGeckoChild) { - return [super _regionForOpaqueDescendants:aRect - forMove:aForMove - forUnderTitlebar:aForUnderTitlebar]; - } - - return [self _regionForOpaqueDescendants:aRect forMove:aForMove]; -} - - (void)handleMouseMoved:(NSEvent*)theEvent { NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
tbb-commits@lists.torproject.org