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