Bug 868648: Make window overlay scrollbars appear/disappear when 2 fingers down/up trackpad. Credits to Markus for his help getting this right. r=mstange,masayuki,smichaud

This commit is contained in:
André Reinald 2013-08-16 23:17:40 +02:00
parent 8e7e13c21d
commit 9ded7a778d
10 changed files with 405 additions and 43 deletions

View File

@ -269,6 +269,56 @@ struct DeltaValues
double deltaY;
};
/******************************************************************/
/* nsScrollbarsForWheel */
/******************************************************************/
class nsScrollbarsForWheel {
public:
static void PrepareToScrollText(nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent);
static void SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget);
// Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
static void MayInactivate();
static void Inactivate();
static bool IsActive();
static void OwnWheelTransaction(bool aOwn);
protected:
static const size_t kNumberOfTargets = 4;
static const DeltaValues directions[kNumberOfTargets];
static nsWeakFrame sActiveOwner;
static nsWeakFrame sActivatedScrollTargets[kNumberOfTargets];
static bool sHadWheelStart;
static bool sOwnWheelTransaction;
/**
* These two methods are called upon NS_WHEEL_START/NS_WHEEL_STOP events
* to show/hide the right scrollbars.
*/
static void TemporarilyActivateAllPossibleScrollTargets(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent);
static void DeactivateAllTemporarilyActivatedScrollTargets();
};
const DeltaValues nsScrollbarsForWheel::directions[kNumberOfTargets] = {
DeltaValues(-1, 0), DeltaValues(+1, 0), DeltaValues(0, -1), DeltaValues(0, +1)
};
nsWeakFrame nsScrollbarsForWheel::sActiveOwner = nullptr;
nsWeakFrame nsScrollbarsForWheel::sActivatedScrollTargets[kNumberOfTargets] = {
nullptr, nullptr, nullptr, nullptr
};
bool nsScrollbarsForWheel::sHadWheelStart = false;
bool nsScrollbarsForWheel::sOwnWheelTransaction = false;
/******************************************************************/
/* nsMouseWheelTransaction */
/******************************************************************/
class nsMouseWheelTransaction {
public:
static nsIFrame* GetTargetFrame() { return sTargetFrame; }
@ -277,11 +327,13 @@ public:
// Be careful, UpdateTransaction may fire a DOM event, therefore, the target
// frame might be destroyed in the event handler.
static bool UpdateTransaction(WheelEvent* aEvent);
static void MayEndTransaction();
static void EndTransaction();
static void OnEvent(WidgetEvent* aEvent);
static void Shutdown();
static uint32_t GetTimeoutTime();
static void OwnScrollbars(bool aOwn);
static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent,
bool aAllowScrollSpeedOverride);
@ -299,12 +351,14 @@ protected:
static int32_t GetAccelerationFactor();
static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent);
static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
static bool OutOfTime(uint32_t aBaseTime, uint32_t aThreshold);
static nsWeakFrame sTargetFrame;
static uint32_t sTime; // in milliseconds
static uint32_t sMouseMoved; // in milliseconds
static nsITimer* sTimer;
static int32_t sScrollSeriesCounter;
static bool sOwnScrollbars;
};
nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nullptr);
@ -312,13 +366,7 @@ uint32_t nsMouseWheelTransaction::sTime = 0;
uint32_t nsMouseWheelTransaction::sMouseMoved = 0;
nsITimer* nsMouseWheelTransaction::sTimer = nullptr;
int32_t nsMouseWheelTransaction::sScrollSeriesCounter = 0;
static bool
OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
{
uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
return (now - aBaseTime > aThreshold);
}
bool nsMouseWheelTransaction::sOwnScrollbars = false;
static bool
CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
@ -328,20 +376,33 @@ CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
}
static bool
CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDeltaX, double aDeltaY)
CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDirectionX, double aDirectionY)
{
MOZ_ASSERT(aScrollFrame);
NS_ASSERTION(aDeltaX || aDeltaY,
NS_ASSERTION(aDirectionX || aDirectionY,
"One of the delta values must be non-zero at least");
nsPoint scrollPt = aScrollFrame->GetScrollPosition();
nsRect scrollRange = aScrollFrame->GetScrollRange();
uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections();
return (aDeltaX && (directions & nsIScrollableFrame::HORIZONTAL) &&
CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDeltaX)) ||
(aDeltaY && (directions & nsIScrollableFrame::VERTICAL) &&
CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDeltaY));
return (aDirectionX && (directions & nsIScrollableFrame::HORIZONTAL) &&
CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDirectionX)) ||
(aDirectionY && (directions & nsIScrollableFrame::VERTICAL) &&
CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDirectionY));
}
bool
nsMouseWheelTransaction::OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
{
uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
return (now - aBaseTime > aThreshold);
}
void
nsMouseWheelTransaction::OwnScrollbars(bool aOwn)
{
sOwnScrollbars = aOwn;
}
void
@ -349,6 +410,9 @@ nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
MOZ_ASSERT(aEvent->message == NS_WHEEL_WHEEL,
"Transaction must be started with a wheel event");
nsScrollbarsForWheel::OwnWheelTransaction(false);
sTargetFrame = aTargetFrame;
sScrollSeriesCounter = 0;
if (!UpdateTransaction(aEvent)) {
@ -385,6 +449,16 @@ nsMouseWheelTransaction::UpdateTransaction(WheelEvent* aEvent)
return true;
}
void
nsMouseWheelTransaction::MayEndTransaction()
{
if (!sOwnScrollbars && nsScrollbarsForWheel::IsActive()) {
nsScrollbarsForWheel::OwnWheelTransaction(true);
} else {
EndTransaction();
}
}
void
nsMouseWheelTransaction::EndTransaction()
{
@ -392,6 +466,11 @@ nsMouseWheelTransaction::EndTransaction()
sTimer->Cancel();
sTargetFrame = nullptr;
sScrollSeriesCounter = 0;
if (sOwnScrollbars) {
sOwnScrollbars = false;
nsScrollbarsForWheel::OwnWheelTransaction(false);
nsScrollbarsForWheel::Inactivate();
}
}
void
@ -415,7 +494,7 @@ nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
// Terminate the current mousewheel transaction if the mouse moved more
// than ignoremovedelay milliseconds ago
EndTransaction();
MayEndTransaction();
}
return;
case NS_MOUSE_MOVE:
@ -426,7 +505,7 @@ nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
nsIntPoint pt = GetScreenPoint(static_cast<WidgetGUIEvent*>(aEvent));
nsIntRect r = sTargetFrame->GetScreenRectExternal();
if (!r.Contains(pt)) {
EndTransaction();
MayEndTransaction();
return;
}
@ -475,8 +554,9 @@ nsMouseWheelTransaction::OnFailToScrollTarget()
}
// The target frame might be destroyed in the event handler, at that time,
// we need to finish the current transaction
if (!sTargetFrame)
if (!sTargetFrame) {
EndTransaction();
}
}
void
@ -491,7 +571,7 @@ nsMouseWheelTransaction::OnTimeout(nsITimer* aTimer, void* aClosure)
nsIFrame* frame = sTargetFrame;
// We need to finish current transaction before DOM event firing. Because
// the next DOM event might create strange situation for us.
EndTransaction();
MayEndTransaction();
if (Preferences::GetBool("test.mousescroll", false)) {
// This event is used for automated tests, see bug 442774.
@ -625,6 +705,127 @@ nsMouseWheelTransaction::OverrideSystemScrollSpeed(WheelEvent* aEvent)
return NS_FAILED(rv) ? DeltaValues(aEvent) : overriddenDeltaValues;
}
/******************************************************************/
/* nsScrollbarsForWheel */
/******************************************************************/
void
nsScrollbarsForWheel::PrepareToScrollText(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
if (aEvent->message == NS_WHEEL_START) {
nsMouseWheelTransaction::OwnScrollbars(false);
if (!IsActive()) {
TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
sHadWheelStart = true;
}
} else {
DeactivateAllTemporarilyActivatedScrollTargets();
}
}
void
nsScrollbarsForWheel::SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget)
{
if (!sHadWheelStart) {
return;
}
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(aScrollTarget);
if (!scrollbarOwner) {
return;
}
sHadWheelStart = false;
sActiveOwner = do_QueryFrame(aScrollTarget);
scrollbarOwner->ScrollbarActivityStarted();
}
void
nsScrollbarsForWheel::MayInactivate()
{
if (!sOwnWheelTransaction && nsMouseWheelTransaction::GetTargetFrame()) {
nsMouseWheelTransaction::OwnScrollbars(true);
} else {
Inactivate();
}
}
void
nsScrollbarsForWheel::Inactivate()
{
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sActiveOwner);
if (scrollbarOwner) {
scrollbarOwner->ScrollbarActivityStopped();
}
sActiveOwner = nullptr;
DeactivateAllTemporarilyActivatedScrollTargets();
if (sOwnWheelTransaction) {
sOwnWheelTransaction = false;
nsMouseWheelTransaction::OwnScrollbars(false);
nsMouseWheelTransaction::EndTransaction();
}
}
bool
nsScrollbarsForWheel::IsActive()
{
if (sActiveOwner) {
return true;
}
for (size_t i = 0; i < kNumberOfTargets; ++i) {
if (sActivatedScrollTargets[i]) {
return true;
}
}
return false;
}
void
nsScrollbarsForWheel::OwnWheelTransaction(bool aOwn)
{
sOwnWheelTransaction = aOwn;
}
void
nsScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
for (size_t i = 0; i < kNumberOfTargets; i++) {
const DeltaValues *dir = &directions[i];
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
nsIScrollableFrame* target =
aESM->ComputeScrollTarget(aTargetFrame, dir->deltaX, dir->deltaY, aEvent,
nsEventStateManager::COMPUTE_DEFAULT_ACTION_TARGET);
if (target) {
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(target);
if (scrollbarOwner) {
nsIFrame* targetFrame = do_QueryFrame(target);
*scrollTarget = targetFrame;
scrollbarOwner->ScrollbarActivityStarted();
}
}
}
}
void
nsScrollbarsForWheel::DeactivateAllTemporarilyActivatedScrollTargets()
{
for (size_t i = 0; i < kNumberOfTargets; i++) {
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
if (*scrollTarget) {
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(*scrollTarget);
if (scrollbarOwner) {
scrollbarOwner->ScrollbarActivityStopped();
}
*scrollTarget = nullptr;
}
}
}
/******************************************************************/
/* nsEventStateManager */
/******************************************************************/
@ -977,13 +1178,20 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
break;
case NS_WHEEL_WHEEL:
case NS_WHEEL_START:
case NS_WHEEL_STOP:
{
NS_ASSERTION(aEvent->mFlags.mIsTrusted,
"Untrusted wheel event shouldn't be here");
nsIContent* content = GetFocusedContent();
if (content)
if (content) {
mCurrentTargetContent = content;
}
if (aEvent->message != NS_WHEEL_WHEEL) {
break;
}
WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
@ -2545,6 +2753,20 @@ nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions)
{
return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
aEvent, aOptions);
}
// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
// for which scrollbarowners to activate when two finger down on trackpad
// and before any actual motion
nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions)
{
if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
// If the user recently scrolled with the mousewheel, then they probably
@ -2569,14 +2791,14 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// If the event doesn't cause scroll actually, we cannot find scroll target
// because we check if the event can cause scroll actually on each found
// scrollable frame.
if (!aEvent->deltaX && !aEvent->deltaY) {
if (!aDirectionX && !aDirectionY) {
return nullptr;
}
bool checkIfScrollableX =
aEvent->deltaX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
bool checkIfScrollableY =
aEvent->deltaY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
nsIScrollableFrame* frameToScroll = nullptr;
nsIFrame* scrollFrame =
@ -2604,8 +2826,7 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// For default action, we should climb up the tree if cannot scroll it
// by the event actually.
bool canScroll = CanScrollOn(frameToScroll,
aEvent->deltaX, aEvent->deltaY);
bool canScroll = CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
// Comboboxes need special care.
nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
if (comboBox) {
@ -3170,25 +3391,41 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
}
break;
case NS_WHEEL_STOP:
{
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
nsScrollbarsForWheel::MayInactivate();
}
break;
case NS_WHEEL_WHEEL:
case NS_WHEEL_START:
{
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
if (*aStatus == nsEventStatus_eConsumeNoDefault) {
nsScrollbarsForWheel::Inactivate();
break;
}
WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
case WheelPrefs::ACTION_SCROLL: {
if (!wheelEvent->deltaX && !wheelEvent->deltaY) {
break;
}
// For scrolling of default action, we should honor the mouse wheel
// transaction.
nsScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
if (aEvent->message != NS_WHEEL_WHEEL ||
(!wheelEvent->deltaX && !wheelEvent->deltaY)) {
break;
}
nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
nsScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
if (!scrollTarget) {
wheelEvent->mViewPortIsOverscrolled = true;
}
@ -3200,6 +3437,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
DoScrollText(scrollTarget, wheelEvent);
} else {
nsMouseWheelTransaction::EndTransaction();
nsScrollbarsForWheel::Inactivate();
}
break;
}

View File

@ -46,6 +46,7 @@ class nsEventStateManager : public nsSupportsWeakReference,
public nsIObserver
{
friend class nsMouseWheelTransaction;
friend class nsScrollbarsForWheel;
public:
typedef mozilla::TimeStamp TimeStamp;
@ -557,6 +558,12 @@ protected:
mozilla::WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
mozilla::WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
/**
* GetScrollAmount() returns the scroll amount in app uints of one line or
* one page. If the wheel event scrolls a page, returns the page width and

View File

@ -77,6 +77,22 @@ nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aCont
{
}
void
nsHTMLScrollFrame::ScrollbarActivityStarted() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStarted();
}
}
void
nsHTMLScrollFrame::ScrollbarActivityStopped() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStopped();
}
}
nsresult
nsHTMLScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
@ -902,6 +918,22 @@ nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContex
mInner.mClipAllDescendants = aClipAllDescendants;
}
void
nsXULScrollFrame::ScrollbarActivityStarted() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStarted();
}
}
void
nsXULScrollFrame::ScrollbarActivityStopped() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStopped();
}
}
nsMargin
nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState)
{

View File

@ -520,6 +520,9 @@ public:
return mInner.GetScrollbarBox(aVertical);
}
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
// nsIScrollableFrame
virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
return mInner.GetScrolledFrame();
@ -810,6 +813,9 @@ public:
return mInner.GetScrollbarBox(aVertical);
}
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
// nsIScrollableFrame
virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
return mInner.GetScrolledFrame();

View File

@ -23,6 +23,13 @@ public:
* if there is no such box.
*/
virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0;
/**
* Show or hide scrollbars on 2 fingers touch.
* Subclasses should call their ScrollbarActivity's corresponding methods.
*/
virtual void ScrollbarActivityStarted() const = 0;
virtual void ScrollbarActivityStopped() const = 0;
};
#endif

View File

@ -4495,6 +4495,22 @@ nsTreeBodyFrame::PostScrollEvent()
}
}
void
nsTreeBodyFrame::ScrollbarActivityStarted() const
{
if (mScrollbarActivity) {
mScrollbarActivity->ActivityStarted();
}
}
void
nsTreeBodyFrame::ScrollbarActivityStopped() const
{
if (mScrollbarActivity) {
mScrollbarActivity->ActivityStopped();
}
}
void
nsTreeBodyFrame::DetachImageListeners()
{

View File

@ -465,6 +465,9 @@ protected:
void PostScrollEvent();
void FireScrollEvent();
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
/**
* Clear the pointer to this frame for all nsTreeImageListeners that were
* created by this frame.

View File

@ -429,6 +429,8 @@ enum nsEventStructType
#define NS_WHEEL_EVENT_START 5400
#define NS_WHEEL_WHEEL (NS_WHEEL_EVENT_START)
#define NS_WHEEL_START (NS_WHEEL_EVENT_START + 1)
#define NS_WHEEL_STOP (NS_WHEEL_EVENT_START + 2)
//System time is changed
#define NS_MOZ_TIME_CHANGE_EVENT 5500

View File

@ -205,6 +205,12 @@ typedef NSInteger NSEventGestureAxis;
#endif // #ifdef __LP64__
#endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
enum {
NSEventPhaseMayBegin = 0x1 << 5
};
#endif // #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
// Undocumented scrollPhase flag that lets us discern between real scrolls and
// automatically firing momentum scroll events.
@interface NSEvent (ScrollPhase)
@ -252,6 +258,11 @@ typedef NSInteger NSEventGestureAxis;
BOOL mPendingFullDisplay;
BOOL mPendingDisplay;
// WheelStart/Stop events should always come in pairs. This BOOL records the
// last received event so that, when we receive one of the events, we make sure
// to send its pair event first, in case we didn't yet for any reason.
BOOL mExpectingWheelStop;
// Holds our drag service across multiple drag calls. The reference to the
// service is obtained when the mouse enters the view and is released when
// the mouse exits or there is a drop. This prevents us from having to
@ -355,6 +366,8 @@ typedef NSInteger NSEventGestureAxis;
- (void)rotateWithEvent:(NSEvent *)anEvent;
- (void)endGestureWithEvent:(NSEvent *)anEvent;
- (void)scrollWheel:(NSEvent *)anEvent;
// Helper function for Lion smart magnify events
+ (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent;

View File

@ -140,6 +140,8 @@ uint32_t nsChildView::sLastInputEventCount = 0;
- (void)forceRefreshOpenGL;
// set up a gecko mouse event based on a cocoa mouse event
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent;
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent;
@ -2777,6 +2779,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
#endif
mPendingDisplay = NO;
mBlockedLastMouseDown = NO;
mExpectingWheelStop = NO;
mLastMouseDownEvent = nil;
mClickThroughMouseDownEvent = nil;
@ -4752,6 +4755,22 @@ static int32_t RoundUp(double aDouble)
static_cast<int32_t>(ceil(aDouble));
}
- (void)sendWheelStartOrStop:(uint32_t)msg forEvent:(NSEvent *)theEvent
{
WidgetWheelEvent wheelEvent(true, msg, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
mExpectingWheelStop = (msg == NS_WHEEL_START);
mGeckoChild->DispatchWindowEvent(wheelEvent);
}
- (void)sendWheelCondition:(BOOL)condition first:(uint32_t)first second:(uint32_t)second forEvent:(NSEvent *)theEvent
{
if (mExpectingWheelStop == condition) {
[self sendWheelStartOrStop:first forEvent:theEvent];
}
[self sendWheelStartOrStop:second forEvent:theEvent];
}
- (void)scrollWheel:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -4768,25 +4787,23 @@ static int32_t RoundUp(double aDouble)
return;
}
WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&wheelEvent];
wheelEvent.deltaMode =
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
if (nsCocoaFeatures::OnLionOrLater()) {
NSEventPhase phase = [theEvent phase];
// Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
if (phase & NSEventPhaseMayBegin) {
[self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
return;
}
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
// assertion and an Objective-C NSInternalInconsistencyException if the
// underlying "Carbon" event doesn't contain pixel scrolling information.
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
// kEventMouseScroll.
if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
EventRef theCarbonEvent = [theEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
if (carbonEventKind != kEventMouseScroll) {
wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
[self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
return;
}
}
WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
@ -4817,8 +4834,6 @@ static int32_t RoundUp(double aDouble)
return;
}
wheelEvent.isMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
NPCocoaEvent cocoaEvent;
ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent,
NPCocoaEventScrollWheel,
@ -4907,6 +4922,29 @@ static int32_t RoundUp(double aDouble)
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent
{
[self convertCocoaMouseEvent:aMouseEvent toGeckoEvent:outWheelEvent];
outWheelEvent->deltaMode =
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
// assertion and an Objective-C NSInternalInconsistencyException if the
// underlying "Carbon" event doesn't contain pixel scrolling information.
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
// kEventMouseScroll.
if (outWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
EventRef theCarbonEvent = [aMouseEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
if (carbonEventKind != kEventMouseScroll) {
outWheelEvent->deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
}
}
outWheelEvent->isMomentum = nsCocoaUtils::IsMomentumScrollEvent(aMouseEvent);
}
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent
{