1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Olli Pettay <Olli.Pettay@helsinki.fi> (Original Author)
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #include "nsEventListenerService.h"
38 : #include "nsCOMArray.h"
39 : #include "nsEventListenerManager.h"
40 : #include "nsIVariant.h"
41 : #include "nsIServiceManager.h"
42 : #include "nsMemory.h"
43 : #include "nsContentUtils.h"
44 : #include "nsIXPConnect.h"
45 : #include "nsIDOMWindow.h"
46 : #include "nsPIDOMWindow.h"
47 : #include "nsJSUtils.h"
48 : #include "nsIPrivateDOMEvent.h"
49 : #include "nsIJSContextStack.h"
50 : #include "nsGUIEvent.h"
51 : #include "nsEventDispatcher.h"
52 : #include "nsIJSEventListener.h"
53 : #ifdef MOZ_JSDEBUGGER
54 : #include "jsdIDebuggerService.h"
55 : #endif
56 :
57 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsEventListenerInfo, mListener)
58 :
59 : DOMCI_DATA(EventListenerInfo, nsEventListenerInfo)
60 :
61 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEventListenerInfo)
62 0 : NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo)
63 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
64 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(EventListenerInfo)
65 0 : NS_INTERFACE_MAP_END
66 :
67 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEventListenerInfo)
68 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEventListenerInfo)
69 :
70 : NS_IMETHODIMP
71 0 : nsEventListenerInfo::GetType(nsAString& aType)
72 : {
73 0 : aType = mType;
74 0 : return NS_OK;
75 : }
76 :
77 : NS_IMETHODIMP
78 0 : nsEventListenerInfo::GetCapturing(bool* aCapturing)
79 : {
80 0 : *aCapturing = mCapturing;
81 0 : return NS_OK;
82 : }
83 :
84 : NS_IMETHODIMP
85 0 : nsEventListenerInfo::GetAllowsUntrusted(bool* aAllowsUntrusted)
86 : {
87 0 : *aAllowsUntrusted = mAllowsUntrusted;
88 0 : return NS_OK;
89 : }
90 :
91 : NS_IMETHODIMP
92 0 : nsEventListenerInfo::GetInSystemEventGroup(bool* aInSystemEventGroup)
93 : {
94 0 : *aInSystemEventGroup = mInSystemEventGroup;
95 0 : return NS_OK;
96 : }
97 :
98 0 : NS_IMPL_ISUPPORTS1(nsEventListenerService, nsIEventListenerService)
99 :
100 : // Caller must root *aJSVal!
101 : bool
102 0 : nsEventListenerInfo::GetJSVal(JSContext* aCx, JSAutoEnterCompartment& aAc, jsval* aJSVal)
103 : {
104 0 : *aJSVal = JSVAL_NULL;
105 0 : nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
106 0 : if (wrappedJS) {
107 0 : JSObject* object = nsnull;
108 0 : if (NS_FAILED(wrappedJS->GetJSObject(&object)) || !aAc.enter(aCx, object)) {
109 0 : return false;
110 : }
111 0 : *aJSVal = OBJECT_TO_JSVAL(object);
112 0 : return true;
113 : }
114 :
115 0 : nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
116 0 : if (jsl) {
117 0 : JSObject *handler = jsl->GetHandler();
118 0 : if (handler) {
119 0 : if (!aAc.enter(aCx, handler)) {
120 0 : return false;
121 : }
122 0 : *aJSVal = OBJECT_TO_JSVAL(handler);
123 0 : return true;
124 : }
125 : }
126 0 : return false;
127 : }
128 :
129 : NS_IMETHODIMP
130 0 : nsEventListenerInfo::ToSource(nsAString& aResult)
131 : {
132 0 : aResult.SetIsVoid(true);
133 :
134 : nsCOMPtr<nsIThreadJSContextStack> stack =
135 0 : nsContentUtils::ThreadJSContextStack();
136 0 : if (stack) {
137 0 : JSContext* cx = nsnull;
138 0 : stack->GetSafeJSContext(&cx);
139 0 : if (cx && NS_SUCCEEDED(stack->Push(cx))) {
140 : {
141 : // Extra block to finish the auto request before calling pop
142 0 : JSAutoRequest ar(cx);
143 0 : JSAutoEnterCompartment ac;
144 0 : jsval v = JSVAL_NULL;
145 0 : if (GetJSVal(cx, ac, &v)) {
146 0 : JSString* str = JS_ValueToSource(cx, v);
147 0 : if (str) {
148 0 : nsDependentJSString depStr;
149 0 : if (depStr.init(cx, str)) {
150 0 : aResult.Assign(depStr);
151 : }
152 : }
153 : }
154 : }
155 0 : stack->Pop(&cx);
156 : }
157 : }
158 :
159 0 : return NS_OK;
160 : }
161 :
162 : NS_IMETHODIMP
163 0 : nsEventListenerInfo::GetDebugObject(nsISupports** aRetVal)
164 : {
165 0 : *aRetVal = nsnull;
166 :
167 : #ifdef MOZ_JSDEBUGGER
168 0 : nsresult rv = NS_OK;
169 : nsCOMPtr<jsdIDebuggerService> jsd =
170 0 : do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv);
171 0 : NS_ENSURE_SUCCESS(rv, NS_OK);
172 :
173 0 : bool isOn = false;
174 0 : jsd->GetIsOn(&isOn);
175 0 : NS_ENSURE_TRUE(isOn, NS_OK);
176 :
177 : nsCOMPtr<nsIThreadJSContextStack> stack =
178 0 : nsContentUtils::ThreadJSContextStack();
179 0 : if (stack) {
180 0 : JSContext* cx = nsnull;
181 0 : stack->GetSafeJSContext(&cx);
182 0 : if (cx && NS_SUCCEEDED(stack->Push(cx))) {
183 : {
184 : // Extra block to finish the auto request before calling pop
185 0 : JSAutoRequest ar(cx);
186 0 : JSAutoEnterCompartment ac;
187 0 : jsval v = JSVAL_NULL;
188 0 : if (GetJSVal(cx, ac, &v)) {
189 0 : nsCOMPtr<jsdIValue> jsdValue;
190 0 : rv = jsd->WrapValue(v, getter_AddRefs(jsdValue));
191 0 : NS_ENSURE_SUCCESS(rv, rv);
192 0 : jsdValue.forget(aRetVal);
193 : }
194 : }
195 0 : stack->Pop(&cx);
196 : }
197 : }
198 : #endif
199 :
200 0 : return NS_OK;
201 : }
202 :
203 : NS_IMETHODIMP
204 0 : nsEventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
205 : PRUint32* aCount,
206 : nsIEventListenerInfo*** aOutArray)
207 : {
208 0 : NS_ENSURE_ARG_POINTER(aEventTarget);
209 0 : *aCount = 0;
210 0 : *aOutArray = nsnull;
211 0 : nsCOMArray<nsIEventListenerInfo> listenerInfos;
212 : nsEventListenerManager* elm =
213 0 : aEventTarget->GetListenerManager(false);
214 0 : if (elm) {
215 0 : elm->GetListenerInfo(&listenerInfos);
216 : }
217 :
218 0 : PRInt32 count = listenerInfos.Count();
219 0 : if (count == 0) {
220 0 : return NS_OK;
221 : }
222 :
223 : *aOutArray =
224 : static_cast<nsIEventListenerInfo**>(
225 0 : nsMemory::Alloc(sizeof(nsIEventListenerInfo*) * count));
226 0 : NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY);
227 :
228 0 : for (PRInt32 i = 0; i < count; ++i) {
229 0 : NS_ADDREF((*aOutArray)[i] = listenerInfos[i]);
230 : }
231 0 : *aCount = count;
232 0 : return NS_OK;
233 : }
234 :
235 : NS_IMETHODIMP
236 0 : nsEventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget,
237 : PRUint32* aCount,
238 : nsIDOMEventTarget*** aOutArray)
239 : {
240 0 : *aCount = 0;
241 0 : *aOutArray = nsnull;
242 0 : NS_ENSURE_ARG(aEventTarget);
243 0 : nsEvent event(true, NS_EVENT_TYPE_NULL);
244 0 : nsCOMArray<nsIDOMEventTarget> targets;
245 : nsresult rv = nsEventDispatcher::Dispatch(aEventTarget, nsnull, &event,
246 0 : nsnull, nsnull, nsnull, &targets);
247 0 : NS_ENSURE_SUCCESS(rv, rv);
248 0 : PRInt32 count = targets.Count();
249 0 : if (count == 0) {
250 0 : return NS_OK;
251 : }
252 :
253 : *aOutArray =
254 : static_cast<nsIDOMEventTarget**>(
255 0 : nsMemory::Alloc(sizeof(nsIDOMEventTarget*) * count));
256 0 : NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY);
257 :
258 0 : for (PRInt32 i = 0; i < count; ++i) {
259 0 : NS_ADDREF((*aOutArray)[i] = targets[i]);
260 : }
261 0 : *aCount = count;
262 :
263 0 : return NS_OK;
264 : }
265 :
266 : NS_IMETHODIMP
267 0 : nsEventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget,
268 : const nsAString& aType,
269 : bool* aRetVal)
270 : {
271 0 : nsEventListenerManager* elm = aEventTarget->GetListenerManager(false);
272 0 : *aRetVal = elm && elm->HasListenersFor(aType);
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : nsEventListenerService::AddSystemEventListener(nsIDOMEventTarget *aTarget,
278 : const nsAString& aType,
279 : nsIDOMEventListener* aListener,
280 : bool aUseCapture)
281 : {
282 0 : NS_PRECONDITION(aTarget, "Missing target");
283 0 : NS_PRECONDITION(aListener, "Missing listener");
284 :
285 0 : nsEventListenerManager* manager = aTarget->GetListenerManager(true);
286 0 : NS_ENSURE_STATE(manager);
287 :
288 : PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE |
289 : NS_EVENT_FLAG_SYSTEM_EVENT :
290 : NS_EVENT_FLAG_BUBBLE |
291 0 : NS_EVENT_FLAG_SYSTEM_EVENT;
292 0 : manager->AddEventListenerByType(aListener, aType, flags);
293 0 : return NS_OK;
294 : }
295 :
296 : NS_IMETHODIMP
297 0 : nsEventListenerService::RemoveSystemEventListener(nsIDOMEventTarget *aTarget,
298 : const nsAString& aType,
299 : nsIDOMEventListener* aListener,
300 : bool aUseCapture)
301 : {
302 0 : NS_PRECONDITION(aTarget, "Missing target");
303 0 : NS_PRECONDITION(aListener, "Missing listener");
304 :
305 0 : nsEventListenerManager* manager = aTarget->GetListenerManager(false);
306 0 : if (manager) {
307 : PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE |
308 : NS_EVENT_FLAG_SYSTEM_EVENT :
309 : NS_EVENT_FLAG_BUBBLE |
310 0 : NS_EVENT_FLAG_SYSTEM_EVENT;
311 0 : manager->RemoveEventListenerByType(aListener, aType, flags);
312 : }
313 :
314 0 : return NS_OK;
315 : }
316 :
317 : nsresult
318 0 : NS_NewEventListenerService(nsIEventListenerService** aResult)
319 : {
320 0 : *aResult = new nsEventListenerService();
321 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
322 0 : NS_ADDREF(*aResult);
323 0 : return NS_OK;
324 4392 : }
|