Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 : #include "nsCOMPtr.h"
6 : #include "nsButtonBoxFrame.h"
7 : #include "nsIContent.h"
8 : #include "nsIDOMEvent.h"
9 : #include "nsIDOMNodeList.h"
10 : #include "nsIDOMXULButtonElement.h"
11 : #include "nsGkAtoms.h"
12 : #include "nsNameSpaceManager.h"
13 : #include "nsPresContext.h"
14 : #include "nsIPresShell.h"
15 : #include "nsIDOMElement.h"
16 : #include "nsDisplayList.h"
17 : #include "nsContentUtils.h"
18 : #include "mozilla/dom/Element.h"
19 : #include "mozilla/EventStateManager.h"
20 : #include "mozilla/EventStates.h"
21 : #include "mozilla/MouseEvents.h"
22 : #include "mozilla/TextEvents.h"
23 :
24 : using namespace mozilla;
25 :
26 :
27 156 : NS_IMPL_ISUPPORTS(nsButtonBoxFrame::nsButtonBoxListener, nsIDOMEventListener)
28 :
29 : nsresult
30 0 : nsButtonBoxFrame::nsButtonBoxListener::HandleEvent(nsIDOMEvent* aEvent)
31 : {
32 0 : if (!mButtonBoxFrame) {
33 0 : return NS_OK;
34 : }
35 :
36 0 : nsAutoString eventType;
37 0 : aEvent->GetType(eventType);
38 :
39 0 : if (eventType.EqualsLiteral("blur")) {
40 0 : mButtonBoxFrame->Blurred();
41 0 : return NS_OK;
42 : }
43 :
44 0 : NS_ABORT();
45 :
46 0 : return NS_OK;
47 : }
48 :
49 : //
50 : // NS_NewXULButtonFrame
51 : //
52 : // Creates a new Button frame and returns it
53 : //
54 : nsIFrame*
55 32 : NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
56 : {
57 32 : return new (aPresShell) nsButtonBoxFrame(aContext);
58 : }
59 :
60 32 : NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame)
61 :
62 32 : nsButtonBoxFrame::nsButtonBoxFrame(nsStyleContext* aContext, ClassID aID) :
63 : nsBoxFrame(aContext, aID, false),
64 : mButtonBoxListener(nullptr),
65 32 : mIsHandlingKeyEvent(false)
66 : {
67 32 : UpdateMouseThrough();
68 32 : }
69 :
70 : void
71 32 : nsButtonBoxFrame::Init(nsIContent* aContent,
72 : nsContainerFrame* aParent,
73 : nsIFrame* aPrevInFlow)
74 : {
75 32 : nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
76 :
77 32 : mButtonBoxListener = new nsButtonBoxListener(this);
78 :
79 32 : mContent->AddSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false);
80 32 : }
81 :
82 : void
83 15 : nsButtonBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
84 : {
85 15 : mContent->RemoveSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false);
86 :
87 15 : mButtonBoxListener->mButtonBoxFrame = nullptr;
88 15 : mButtonBoxListener = nullptr;
89 :
90 15 : nsBoxFrame::DestroyFrom(aDestructRoot);
91 15 : }
92 :
93 : void
94 247 : nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
95 : const nsRect& aDirtyRect,
96 : const nsDisplayListSet& aLists)
97 : {
98 : // override, since we don't want children to get events
99 247 : if (aBuilder->IsForEventDelivery())
100 0 : return;
101 247 : nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
102 : }
103 :
104 : nsresult
105 0 : nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext,
106 : WidgetGUIEvent* aEvent,
107 : nsEventStatus* aEventStatus)
108 : {
109 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
110 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
111 0 : return NS_OK;
112 : }
113 :
114 0 : switch (aEvent->mMessage) {
115 : case eKeyDown: {
116 0 : WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
117 0 : if (!keyEvent) {
118 0 : break;
119 : }
120 0 : if (NS_VK_SPACE == keyEvent->mKeyCode) {
121 0 : EventStateManager* esm = aPresContext->EventStateManager();
122 : // :hover:active state
123 0 : esm->SetContentState(mContent, NS_EVENT_STATE_HOVER);
124 0 : esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE);
125 0 : mIsHandlingKeyEvent = true;
126 : }
127 0 : break;
128 : }
129 :
130 : // On mac, Return fires the default button, not the focused one.
131 : #ifndef XP_MACOSX
132 : case eKeyPress: {
133 0 : WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
134 0 : if (!keyEvent) {
135 0 : break;
136 : }
137 0 : if (NS_VK_RETURN == keyEvent->mKeyCode) {
138 0 : nsCOMPtr<nsIDOMXULButtonElement> buttonEl(do_QueryInterface(mContent));
139 0 : if (buttonEl) {
140 0 : MouseClicked(aEvent);
141 0 : *aEventStatus = nsEventStatus_eConsumeNoDefault;
142 : }
143 : }
144 0 : break;
145 : }
146 : #endif
147 :
148 : case eKeyUp: {
149 0 : WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
150 0 : if (!keyEvent) {
151 0 : break;
152 : }
153 0 : if (NS_VK_SPACE == keyEvent->mKeyCode) {
154 0 : mIsHandlingKeyEvent = false;
155 : // only activate on keyup if we're already in the :hover:active state
156 0 : NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
157 0 : EventStates buttonState = mContent->AsElement()->State();
158 0 : if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE |
159 0 : NS_EVENT_STATE_HOVER)) {
160 : // return to normal state
161 0 : EventStateManager* esm = aPresContext->EventStateManager();
162 0 : esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
163 0 : esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
164 0 : MouseClicked(aEvent);
165 : }
166 : }
167 0 : break;
168 : }
169 :
170 : case eMouseClick: {
171 0 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
172 0 : if (mouseEvent->IsLeftClickEvent()) {
173 0 : MouseClicked(mouseEvent);
174 : }
175 0 : break;
176 : }
177 :
178 : default:
179 0 : break;
180 : }
181 :
182 0 : return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
183 : }
184 :
185 : void
186 0 : nsButtonBoxFrame::Blurred()
187 : {
188 0 : NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
189 0 : EventStates buttonState = mContent->AsElement()->State();
190 0 : if (mIsHandlingKeyEvent &&
191 0 : buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE |
192 0 : NS_EVENT_STATE_HOVER)) {
193 : // return to normal state
194 0 : EventStateManager* esm = PresContext()->EventStateManager();
195 0 : esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
196 0 : esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
197 : }
198 0 : mIsHandlingKeyEvent = false;
199 0 : }
200 :
201 : void
202 0 : nsButtonBoxFrame::DoMouseClick(WidgetGUIEvent* aEvent, bool aTrustEvent)
203 : {
204 : // Don't execute if we're disabled.
205 0 : if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
206 : nsGkAtoms::_true, eCaseMatters))
207 0 : return;
208 :
209 : // Execute the oncommand event handler.
210 0 : bool isShift = false;
211 0 : bool isControl = false;
212 0 : bool isAlt = false;
213 0 : bool isMeta = false;
214 0 : if(aEvent) {
215 0 : WidgetInputEvent* inputEvent = aEvent->AsInputEvent();
216 0 : isShift = inputEvent->IsShift();
217 0 : isControl = inputEvent->IsControl();
218 0 : isAlt = inputEvent->IsAlt();
219 0 : isMeta = inputEvent->IsMeta();
220 : }
221 :
222 : // Have the content handle the event, propagating it according to normal DOM rules.
223 0 : nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
224 0 : if (shell) {
225 0 : nsContentUtils::DispatchXULCommand(mContent,
226 : aEvent ?
227 0 : aEvent->IsTrusted() : aTrustEvent,
228 : nullptr, shell,
229 0 : isControl, isAlt, isShift, isMeta);
230 : }
231 : }
|