diff options
Diffstat (limited to 'layout/xul/nsScrollBoxFrame.cpp')
-rw-r--r-- | layout/xul/nsScrollBoxFrame.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/layout/xul/nsScrollBoxFrame.cpp b/layout/xul/nsScrollBoxFrame.cpp new file mode 100644 index 000000000..4a6c9c2a8 --- /dev/null +++ b/layout/xul/nsScrollBoxFrame.cpp @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsCOMPtr.h" +#include "nsPresContext.h" +#include "nsGkAtoms.h" +#include "nsButtonBoxFrame.h" +#include "nsITimer.h" +#include "nsRepeatService.h" +#include "mozilla/MouseEvents.h" +#include "nsIContent.h" + +using namespace mozilla; + +class nsAutoRepeatBoxFrame : public nsButtonBoxFrame +{ +public: + NS_DECL_FRAMEARENA_HELPERS + + friend nsIFrame* NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext); + + virtual void DestroyFrom(nsIFrame* aDestructRoot) override; + + virtual nsresult AttributeChanged(int32_t aNameSpaceID, + nsIAtom* aAttribute, + int32_t aModType) override; + + virtual nsresult HandleEvent(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) override; + + NS_IMETHOD HandlePress(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) override; + + NS_IMETHOD HandleRelease(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) override; + +protected: + explicit nsAutoRepeatBoxFrame(nsStyleContext* aContext): + nsButtonBoxFrame(aContext) {} + + void StartRepeat() { + if (IsActivatedOnHover()) { + // No initial delay on hover. + nsRepeatService::GetInstance()->Start(Notify, this, 0); + } else { + nsRepeatService::GetInstance()->Start(Notify, this); + } + } + void StopRepeat() { + nsRepeatService::GetInstance()->Stop(Notify, this); + } + void Notify(); + static void Notify(void* aData) { + static_cast<nsAutoRepeatBoxFrame*>(aData)->Notify(); + } + + bool mTrustedEvent; + + bool IsActivatedOnHover(); +}; + +nsIFrame* +NS_NewAutoRepeatBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) +{ + return new (aPresShell) nsAutoRepeatBoxFrame(aContext); +} + +NS_IMPL_FRAMEARENA_HELPERS(nsAutoRepeatBoxFrame) + +nsresult +nsAutoRepeatBoxFrame::HandleEvent(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) +{ + NS_ENSURE_ARG_POINTER(aEventStatus); + if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { + return NS_OK; + } + + switch(aEvent->mMessage) { + // repeat mode may be "hover" for repeating while the mouse is hovering + // over the element, otherwise repetition is done while the element is + // active (pressed). + case eMouseEnterIntoWidget: + case eMouseOver: + if (IsActivatedOnHover()) { + StartRepeat(); + mTrustedEvent = aEvent->IsTrusted(); + } + break; + + case eMouseExitFromWidget: + case eMouseOut: + // always stop on mouse exit + StopRepeat(); + // Not really necessary but do this to be safe + mTrustedEvent = false; + break; + + case eMouseClick: { + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); + if (mouseEvent->IsLeftClickEvent()) { + // skip button frame handling to prevent click handling + return nsBoxFrame::HandleEvent(aPresContext, mouseEvent, aEventStatus); + } + break; + } + + default: + break; + } + + return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); +} + +NS_IMETHODIMP +nsAutoRepeatBoxFrame::HandlePress(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) +{ + if (!IsActivatedOnHover()) { + StartRepeat(); + mTrustedEvent = aEvent->IsTrusted(); + DoMouseClick(aEvent, mTrustedEvent); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsAutoRepeatBoxFrame::HandleRelease(nsPresContext* aPresContext, + WidgetGUIEvent* aEvent, + nsEventStatus* aEventStatus) +{ + if (!IsActivatedOnHover()) { + StopRepeat(); + } + return NS_OK; +} + +nsresult +nsAutoRepeatBoxFrame::AttributeChanged(int32_t aNameSpaceID, + nsIAtom* aAttribute, + int32_t aModType) +{ + if (aAttribute == nsGkAtoms::type) { + StopRepeat(); + } + return NS_OK; +} + +void +nsAutoRepeatBoxFrame::Notify() +{ + DoMouseClick(nullptr, mTrustedEvent); +} + +void +nsAutoRepeatBoxFrame::DestroyFrom(nsIFrame* aDestructRoot) +{ + // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out + // from under you while you're in the process of scrolling. + StopRepeat(); + nsButtonBoxFrame::DestroyFrom(aDestructRoot); +} + +bool +nsAutoRepeatBoxFrame::IsActivatedOnHover() +{ + return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::repeat, + nsGkAtoms::hover, eCaseMatters); +} |