diff --git a/layout/xul/nsButtonBoxFrame.cpp b/layout/xul/nsButtonBoxFrame.cpp index c3777c070cf..3259e597f57 100644 --- a/layout/xul/nsButtonBoxFrame.cpp +++ b/layout/xul/nsButtonBoxFrame.cpp @@ -22,6 +22,29 @@ using namespace mozilla; + +NS_IMPL_ISUPPORTS(nsButtonBoxFrame::nsButtonBoxListener, nsIDOMEventListener) + +nsresult +nsButtonBoxFrame::nsButtonBoxListener::HandleEvent(nsIDOMEvent* aEvent) +{ + if (!mButtonBoxFrame) { + return NS_OK; + } + + nsAutoString eventType; + aEvent->GetType(eventType); + + if (eventType.EqualsLiteral("blur")) { + mButtonBoxFrame->Blurred(); + return NS_OK; + } + + NS_ABORT(); + + return NS_OK; +} + // // NS_NewXULButtonFrame // @@ -35,6 +58,37 @@ NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame) +nsButtonBoxFrame::nsButtonBoxFrame(nsStyleContext* aContext) : + nsBoxFrame(aContext, false), + mButtonBoxListener(nullptr), + mIsHandlingKeyEvent(false) +{ + UpdateMouseThrough(); +} + +void +nsButtonBoxFrame::Init(nsIContent* aContent, + nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) +{ + nsBoxFrame::Init(aContent, aParent, aPrevInFlow); + + mButtonBoxListener = new nsButtonBoxListener(this); + + mContent->AddSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false); +} + +void +nsButtonBoxFrame::DestroyFrom(nsIFrame* aDestructRoot) +{ + mContent->RemoveSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false); + + mButtonBoxListener->mButtonBoxFrame = nullptr; + mButtonBoxListener = nullptr; + + nsBoxFrame::DestroyFrom(aDestructRoot); +} + void nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, @@ -67,6 +121,7 @@ nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, // :hover:active state esm->SetContentState(mContent, NS_EVENT_STATE_HOVER); esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE); + mIsHandlingKeyEvent = true; } break; } @@ -95,6 +150,7 @@ nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, break; } if (NS_VK_SPACE == keyEvent->keyCode) { + mIsHandlingKeyEvent = false; // only activate on keyup if we're already in the :hover:active state NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?"); EventStates buttonState = mContent->AsElement()->State(); @@ -122,7 +178,23 @@ nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext, return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } -void +void +nsButtonBoxFrame::Blurred() +{ + NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?"); + EventStates buttonState = mContent->AsElement()->State(); + if (mIsHandlingKeyEvent && + buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE | + NS_EVENT_STATE_HOVER)) { + // return to normal state + EventStateManager* esm = PresContext()->EventStateManager(); + esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE); + esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER); + } + mIsHandlingKeyEvent = false; +} + +void nsButtonBoxFrame::DoMouseClick(WidgetGUIEvent* aEvent, bool aTrustEvent) { // Don't execute if we're disabled. diff --git a/layout/xul/nsButtonBoxFrame.h b/layout/xul/nsButtonBoxFrame.h index 05a1d3b6711..478077942df 100644 --- a/layout/xul/nsButtonBoxFrame.h +++ b/layout/xul/nsButtonBoxFrame.h @@ -15,15 +15,18 @@ public: friend nsIFrame* NS_NewButtonBoxFrame(nsIPresShell* aPresShell); - explicit nsButtonBoxFrame(nsStyleContext* aContext) - :nsBoxFrame(aContext, false) { - UpdateMouseThrough(); - } + explicit nsButtonBoxFrame(nsStyleContext* aContext); + + virtual void Init(nsIContent* aContent, + nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) override; virtual void BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists) override; + virtual void DestroyFrom(nsIFrame* aDestructRoot) override; + virtual nsresult HandleEvent(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) override; @@ -32,6 +35,8 @@ public: mozilla::WidgetGUIEvent* aEvent) { DoMouseClick(aEvent, false); } + void Blurred(); + #ifdef DEBUG_FRAME_DUMP virtual nsresult GetFrameName(nsAString& aResult) const override { return MakeFrameName(NS_LITERAL_STRING("ButtonBoxFrame"), aResult); @@ -44,6 +49,27 @@ public: */ void DoMouseClick(mozilla::WidgetGUIEvent* aEvent, bool aTrustEvent); void UpdateMouseThrough() override { AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); } + +private: + class nsButtonBoxListener final : public nsIDOMEventListener + { + public: + explicit nsButtonBoxListener(nsButtonBoxFrame* aButtonBoxFrame) : + mButtonBoxFrame(aButtonBoxFrame) + { } + + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override; + + NS_DECL_ISUPPORTS + + private: + friend class nsButtonBoxFrame; + virtual ~nsButtonBoxListener() { } + nsButtonBoxFrame* mButtonBoxFrame; + }; + + nsRefPtr mButtonBoxListener; + bool mIsHandlingKeyEvent; }; // class nsButtonBoxFrame #endif /* nsButtonBoxFrame_h___ */