|
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 |
|
6 #include "mozilla/BasicEvents.h" |
|
7 #include "mozilla/EventDispatcher.h" |
|
8 #include "mozilla/EventListenerManager.h" |
|
9 #include "nsCOMPtr.h" |
|
10 #include "nsWindowRoot.h" |
|
11 #include "nsPIDOMWindow.h" |
|
12 #include "nsPresContext.h" |
|
13 #include "nsLayoutCID.h" |
|
14 #include "nsContentCID.h" |
|
15 #include "nsString.h" |
|
16 #include "nsGlobalWindow.h" |
|
17 #include "nsFocusManager.h" |
|
18 #include "nsIContent.h" |
|
19 #include "nsIDOMHTMLInputElement.h" |
|
20 #include "nsIDOMHTMLTextAreaElement.h" |
|
21 #include "nsIControllers.h" |
|
22 #include "nsIController.h" |
|
23 |
|
24 #include "nsCycleCollectionParticipant.h" |
|
25 |
|
26 #ifdef MOZ_XUL |
|
27 #include "nsIDOMXULElement.h" |
|
28 #endif |
|
29 |
|
30 using namespace mozilla; |
|
31 using namespace mozilla::dom; |
|
32 |
|
33 nsWindowRoot::nsWindowRoot(nsPIDOMWindow* aWindow) |
|
34 { |
|
35 mWindow = aWindow; |
|
36 } |
|
37 |
|
38 nsWindowRoot::~nsWindowRoot() |
|
39 { |
|
40 if (mListenerManager) { |
|
41 mListenerManager->Disconnect(); |
|
42 } |
|
43 } |
|
44 |
|
45 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(nsWindowRoot, |
|
46 mWindow, |
|
47 mListenerManager, |
|
48 mPopupNode, |
|
49 mParent) |
|
50 |
|
51 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot) |
|
52 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
|
53 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventTarget) |
|
54 NS_INTERFACE_MAP_ENTRY(nsPIWindowRoot) |
|
55 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) |
|
56 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget) |
|
57 NS_INTERFACE_MAP_END |
|
58 |
|
59 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWindowRoot) |
|
60 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWindowRoot) |
|
61 |
|
62 NS_IMPL_DOMTARGET_DEFAULTS(nsWindowRoot) |
|
63 |
|
64 NS_IMETHODIMP |
|
65 nsWindowRoot::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture) |
|
66 { |
|
67 if (nsRefPtr<EventListenerManager> elm = GetExistingListenerManager()) { |
|
68 elm->RemoveEventListener(aType, aListener, aUseCapture); |
|
69 } |
|
70 return NS_OK; |
|
71 } |
|
72 |
|
73 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsWindowRoot) |
|
74 |
|
75 NS_IMETHODIMP |
|
76 nsWindowRoot::DispatchEvent(nsIDOMEvent* aEvt, bool *aRetVal) |
|
77 { |
|
78 nsEventStatus status = nsEventStatus_eIgnore; |
|
79 nsresult rv = EventDispatcher::DispatchDOMEvent( |
|
80 static_cast<EventTarget*>(this), nullptr, aEvt, nullptr, &status); |
|
81 *aRetVal = (status != nsEventStatus_eConsumeNoDefault); |
|
82 return rv; |
|
83 } |
|
84 |
|
85 nsresult |
|
86 nsWindowRoot::DispatchDOMEvent(WidgetEvent* aEvent, |
|
87 nsIDOMEvent* aDOMEvent, |
|
88 nsPresContext* aPresContext, |
|
89 nsEventStatus* aEventStatus) |
|
90 { |
|
91 return EventDispatcher::DispatchDOMEvent(static_cast<EventTarget*>(this), |
|
92 aEvent, aDOMEvent, |
|
93 aPresContext, aEventStatus); |
|
94 } |
|
95 |
|
96 NS_IMETHODIMP |
|
97 nsWindowRoot::AddEventListener(const nsAString& aType, |
|
98 nsIDOMEventListener *aListener, |
|
99 bool aUseCapture, bool aWantsUntrusted, |
|
100 uint8_t aOptionalArgc) |
|
101 { |
|
102 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, |
|
103 "Won't check if this is chrome, you want to set " |
|
104 "aWantsUntrusted to false or make the aWantsUntrusted " |
|
105 "explicit by making optional_argc non-zero."); |
|
106 |
|
107 EventListenerManager* elm = GetOrCreateListenerManager(); |
|
108 NS_ENSURE_STATE(elm); |
|
109 elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); |
|
110 return NS_OK; |
|
111 } |
|
112 |
|
113 void |
|
114 nsWindowRoot::AddEventListener(const nsAString& aType, |
|
115 EventListener* aListener, |
|
116 bool aUseCapture, |
|
117 const Nullable<bool>& aWantsUntrusted, |
|
118 ErrorResult& aRv) |
|
119 { |
|
120 bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value(); |
|
121 EventListenerManager* elm = GetOrCreateListenerManager(); |
|
122 if (!elm) { |
|
123 aRv.Throw(NS_ERROR_UNEXPECTED); |
|
124 return; |
|
125 } |
|
126 elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted); |
|
127 } |
|
128 |
|
129 |
|
130 NS_IMETHODIMP |
|
131 nsWindowRoot::AddSystemEventListener(const nsAString& aType, |
|
132 nsIDOMEventListener *aListener, |
|
133 bool aUseCapture, |
|
134 bool aWantsUntrusted, |
|
135 uint8_t aOptionalArgc) |
|
136 { |
|
137 NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, |
|
138 "Won't check if this is chrome, you want to set " |
|
139 "aWantsUntrusted to false or make the aWantsUntrusted " |
|
140 "explicit by making optional_argc non-zero."); |
|
141 |
|
142 return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, |
|
143 aWantsUntrusted); |
|
144 } |
|
145 |
|
146 EventListenerManager* |
|
147 nsWindowRoot::GetOrCreateListenerManager() |
|
148 { |
|
149 if (!mListenerManager) { |
|
150 mListenerManager = |
|
151 new EventListenerManager(static_cast<EventTarget*>(this)); |
|
152 } |
|
153 |
|
154 return mListenerManager; |
|
155 } |
|
156 |
|
157 EventListenerManager* |
|
158 nsWindowRoot::GetExistingListenerManager() const |
|
159 { |
|
160 return mListenerManager; |
|
161 } |
|
162 |
|
163 nsIScriptContext* |
|
164 nsWindowRoot::GetContextForEventHandlers(nsresult* aRv) |
|
165 { |
|
166 *aRv = NS_OK; |
|
167 return nullptr; |
|
168 } |
|
169 |
|
170 nsresult |
|
171 nsWindowRoot::PreHandleEvent(EventChainPreVisitor& aVisitor) |
|
172 { |
|
173 aVisitor.mCanHandle = true; |
|
174 aVisitor.mForceContentDispatch = true; //FIXME! Bug 329119 |
|
175 // To keep mWindow alive |
|
176 aVisitor.mItemData = static_cast<nsISupports *>(mWindow); |
|
177 aVisitor.mParentTarget = mParent; |
|
178 return NS_OK; |
|
179 } |
|
180 |
|
181 nsresult |
|
182 nsWindowRoot::PostHandleEvent(EventChainPostVisitor& aVisitor) |
|
183 { |
|
184 return NS_OK; |
|
185 } |
|
186 |
|
187 nsIDOMWindow* |
|
188 nsWindowRoot::GetOwnerGlobal() |
|
189 { |
|
190 return GetWindow(); |
|
191 } |
|
192 |
|
193 nsPIDOMWindow* |
|
194 nsWindowRoot::GetWindow() |
|
195 { |
|
196 return mWindow; |
|
197 } |
|
198 |
|
199 nsresult |
|
200 nsWindowRoot::GetControllers(nsIControllers** aResult) |
|
201 { |
|
202 *aResult = nullptr; |
|
203 |
|
204 // XXX: we should fix this so there's a generic interface that |
|
205 // describes controllers, so this code would have no special |
|
206 // knowledge of what object might have controllers. |
|
207 |
|
208 nsCOMPtr<nsPIDOMWindow> focusedWindow; |
|
209 nsIContent* focusedContent = |
|
210 nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); |
|
211 if (focusedContent) { |
|
212 #ifdef MOZ_XUL |
|
213 nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(focusedContent)); |
|
214 if (xulElement) |
|
215 return xulElement->GetControllers(aResult); |
|
216 #endif |
|
217 |
|
218 nsCOMPtr<nsIDOMHTMLTextAreaElement> htmlTextArea = |
|
219 do_QueryInterface(focusedContent); |
|
220 if (htmlTextArea) |
|
221 return htmlTextArea->GetControllers(aResult); |
|
222 |
|
223 nsCOMPtr<nsIDOMHTMLInputElement> htmlInputElement = |
|
224 do_QueryInterface(focusedContent); |
|
225 if (htmlInputElement) |
|
226 return htmlInputElement->GetControllers(aResult); |
|
227 |
|
228 if (focusedContent->IsEditable() && focusedWindow) |
|
229 return focusedWindow->GetControllers(aResult); |
|
230 } |
|
231 else { |
|
232 nsCOMPtr<nsIDOMWindow> domWindow = do_QueryInterface(focusedWindow); |
|
233 if (domWindow) |
|
234 return domWindow->GetControllers(aResult); |
|
235 } |
|
236 |
|
237 return NS_OK; |
|
238 } |
|
239 |
|
240 nsresult |
|
241 nsWindowRoot::GetControllerForCommand(const char * aCommand, |
|
242 nsIController** _retval) |
|
243 { |
|
244 NS_ENSURE_ARG_POINTER(_retval); |
|
245 *_retval = nullptr; |
|
246 |
|
247 { |
|
248 nsCOMPtr<nsIControllers> controllers; |
|
249 GetControllers(getter_AddRefs(controllers)); |
|
250 if (controllers) { |
|
251 nsCOMPtr<nsIController> controller; |
|
252 controllers->GetControllerForCommand(aCommand, getter_AddRefs(controller)); |
|
253 if (controller) { |
|
254 controller.forget(_retval); |
|
255 return NS_OK; |
|
256 } |
|
257 } |
|
258 } |
|
259 |
|
260 nsCOMPtr<nsPIDOMWindow> focusedWindow; |
|
261 nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); |
|
262 while (focusedWindow) { |
|
263 nsCOMPtr<nsIControllers> controllers; |
|
264 focusedWindow->GetControllers(getter_AddRefs(controllers)); |
|
265 if (controllers) { |
|
266 nsCOMPtr<nsIController> controller; |
|
267 controllers->GetControllerForCommand(aCommand, |
|
268 getter_AddRefs(controller)); |
|
269 if (controller) { |
|
270 controller.forget(_retval); |
|
271 return NS_OK; |
|
272 } |
|
273 } |
|
274 |
|
275 // XXXndeakin P3 is this casting safe? |
|
276 nsGlobalWindow *win = static_cast<nsGlobalWindow*>(focusedWindow.get()); |
|
277 focusedWindow = win->GetPrivateParent(); |
|
278 } |
|
279 |
|
280 return NS_OK; |
|
281 } |
|
282 |
|
283 nsIDOMNode* |
|
284 nsWindowRoot::GetPopupNode() |
|
285 { |
|
286 return mPopupNode; |
|
287 } |
|
288 |
|
289 void |
|
290 nsWindowRoot::SetPopupNode(nsIDOMNode* aNode) |
|
291 { |
|
292 mPopupNode = aNode; |
|
293 } |
|
294 |
|
295 /////////////////////////////////////////////////////////////////////////////////// |
|
296 |
|
297 already_AddRefed<EventTarget> |
|
298 NS_NewWindowRoot(nsPIDOMWindow* aWindow) |
|
299 { |
|
300 nsCOMPtr<EventTarget> result = new nsWindowRoot(aWindow); |
|
301 return result.forget(); |
|
302 } |