diff --git a/widget/src/cocoa/nsChildView.h b/widget/src/cocoa/nsChildView.h index 11a1449bf52a..276632ee3e59 100644 --- a/widget/src/cocoa/nsChildView.h +++ b/widget/src/cocoa/nsChildView.h @@ -357,6 +357,7 @@ class ChildViewMouseTracker { public: static void MouseMoved(NSEvent* aEvent); + static void MouseScrolled(NSEvent* aEvent); static void OnDestroyView(ChildView* aView); static void OnDestroyWindow(NSWindow* aWindow); static BOOL WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent, @@ -370,6 +371,7 @@ public: static ChildView* sLastMouseEventView; static NSEvent* sLastMouseMoveEvent; static NSWindow* sWindowUnderMouse; + static NSPoint sLastScrollEventScreenLocation; }; //------------------------------------------------------------------------- diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 8b50f1236933..4baf54cfc3b2 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -128,6 +128,7 @@ extern nsISupportsArray *gDraggedTransferables; ChildView* ChildViewMouseTracker::sLastMouseEventView = nil; NSEvent* ChildViewMouseTracker::sLastMouseMoveEvent = nil; NSWindow* ChildViewMouseTracker::sWindowUnderMouse = nil; +NSPoint ChildViewMouseTracker::sLastScrollEventScreenLocation = NSZeroPoint; #ifdef INVALIDATE_DEBUGGING static void blinkRect(Rect* r); @@ -3691,8 +3692,7 @@ NSEvent* gLastDragMouseDownEvent = nil; // No sense in firing off a Gecko event. return; - BOOL isMomentumScroll = [theEvent respondsToSelector:@selector(_scrollPhase)] && - [theEvent _scrollPhase] != 0; + BOOL isMomentumScroll = nsCocoaUtils::IsMomentumScrollEvent(theEvent); if (scrollDelta != 0) { // Send the line scroll event. @@ -3814,14 +3814,11 @@ NSEvent* gLastDragMouseDownEvent = nil; -(void)scrollWheel:(NSEvent*)theEvent { - NS_OBJC_BEGIN_TRY_ABORT_BLOCK; - nsAutoRetainCocoaObject kungFuDeathGrip(self); - if ([self maybeRollup:theEvent]) - return; + ChildViewMouseTracker::MouseScrolled(theEvent); - if (!mGeckoChild) + if ([self maybeRollup:theEvent]) return; // It's possible for a single NSScrollWheel event to carry both useful @@ -3829,11 +3826,7 @@ NSEvent* gLastDragMouseDownEvent = nil; // NSMouseScrollEvent can only carry one axis at a time, so the system // event will be split into two Gecko events if necessary. [self scrollWheel:theEvent forAxis:nsMouseScrollEvent::kIsVertical]; - if (!mGeckoChild) - return; [self scrollWheel:theEvent forAxis:nsMouseScrollEvent::kIsHorizontal]; - - NS_OBJC_END_TRY_ABORT_BLOCK; } -(NSMenu*)menuForEvent:(NSEvent*)theEvent @@ -4967,6 +4960,15 @@ ChildViewMouseTracker::MouseMoved(NSEvent* aEvent) } } +void +ChildViewMouseTracker::MouseScrolled(NSEvent* aEvent) +{ + if (!nsCocoaUtils::IsMomentumScrollEvent(aEvent)) { + // Store the position so we can pin future momentum scroll events. + sLastScrollEventScreenLocation = nsCocoaUtils::ScreenLocationForEvent(aEvent); + } +} + ChildView* ChildViewMouseTracker::ViewForEvent(NSEvent* aEvent) { diff --git a/widget/src/cocoa/nsCocoaUtils.h b/widget/src/cocoa/nsCocoaUtils.h index 2460ce13a3a2..713e66b3025c 100644 --- a/widget/src/cocoa/nsCocoaUtils.h +++ b/widget/src/cocoa/nsCocoaUtils.h @@ -141,6 +141,8 @@ class nsCocoaUtils // the event was originally targeted at is still alive! static NSPoint EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow); + static BOOL IsMomentumScrollEvent(NSEvent* aEvent); + // Hides the Menu bar and the Dock. Multiple hide/show requests can be nested. static void HideOSChromeOnScreen(PRBool aShouldHide, NSScreen* aScreen); diff --git a/widget/src/cocoa/nsCocoaUtils.mm b/widget/src/cocoa/nsCocoaUtils.mm index 95a89c2a7feb..2d9df4b9c71d 100644 --- a/widget/src/cocoa/nsCocoaUtils.mm +++ b/widget/src/cocoa/nsCocoaUtils.mm @@ -40,6 +40,7 @@ #include "gfxImageSurface.h" #include "nsCocoaUtils.h" +#include "nsChildView.h" #include "nsMenuBarX.h" #include "nsCocoaWindow.h" #include "nsCOMPtr.h" @@ -105,6 +106,11 @@ NSPoint nsCocoaUtils::ScreenLocationForEvent(NSEvent* anEvent) if (!anEvent || [anEvent type] == NSMouseMoved) return [NSEvent mouseLocation]; + // Pin momentum scroll events to the location of the last user-controlled + // scroll event. + if (IsMomentumScrollEvent(anEvent)) + return ChildViewMouseTracker::sLastScrollEventScreenLocation; + return [[anEvent window] convertBaseToScreen:[anEvent locationInWindow]]; NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0)); @@ -128,6 +134,13 @@ NSPoint nsCocoaUtils::EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0)); } +BOOL nsCocoaUtils::IsMomentumScrollEvent(NSEvent* aEvent) +{ + return [aEvent type] == NSScrollWheel && + [aEvent respondsToSelector:@selector(_scrollPhase)] && + [aEvent _scrollPhase] != 0; +} + void nsCocoaUtils::HideOSChromeOnScreen(PRBool aShouldHide, NSScreen* aScreen) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK;