mshtml: Added IDOMEvent:get_eventPhase implementation.
[wine.git] / dlls / mshtml / htmlevent.c
blobd64238fea7a8971a5662792e326dafc63f72406c
1 /*
2 * Copyright 2008-2009 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <assert.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "ole2.h"
28 #include "mshtmdid.h"
30 #include "mshtml_private.h"
31 #include "htmlevent.h"
32 #include "htmlscript.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
38 typedef struct {
39 struct wine_rb_entry entry;
40 eventid_t event_id;
41 IDispatch *handler_prop;
42 DWORD handler_cnt;
43 IDispatch **handlers;
44 } handler_vector_t;
46 static const WCHAR abortW[] = {'a','b','o','r','t',0};
47 static const WCHAR beforeactivateW[] = {'b','e','f','o','r','e','a','c','t','i','v','a','t','e',0};
48 static const WCHAR beforeunloadW[] = {'b','e','f','o','r','e','u','n','l','o','a','d',0};
49 static const WCHAR blurW[] = {'b','l','u','r',0};
50 static const WCHAR changeW[] = {'c','h','a','n','g','e',0};
51 static const WCHAR clickW[] = {'c','l','i','c','k',0};
52 static const WCHAR contextmenuW[] = {'c','o','n','t','e','x','t','m','e','n','u',0};
53 static const WCHAR dataavailableW[] = {'d','a','t','a','a','v','a','i','l','a','b','l','e',0};
54 static const WCHAR dblclickW[] = {'d','b','l','c','l','i','c','k',0};
55 static const WCHAR dragW[] = {'d','r','a','g',0};
56 static const WCHAR dragstartW[] = {'d','r','a','g','s','t','a','r','t',0};
57 static const WCHAR errorW[] = {'e','r','r','o','r',0};
58 static const WCHAR focusW[] = {'f','o','c','u','s',0};
59 static const WCHAR focusinW[] = {'f','o','c','u','s','i','n',0};
60 static const WCHAR focusoutW[] = {'f','o','c','u','s','o','u','t',0};
61 static const WCHAR helpW[] = {'h','e','l','p',0};
62 static const WCHAR keydownW[] = {'k','e','y','d','o','w','n',0};
63 static const WCHAR keypressW[] = {'k','e','y','p','r','e','s','s',0};
64 static const WCHAR keyupW[] = {'k','e','y','u','p',0};
65 static const WCHAR loadW[] = {'l','o','a','d',0};
66 static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0};
67 static const WCHAR mousedownW[] = {'m','o','u','s','e','d','o','w','n',0};
68 static const WCHAR mousemoveW[] = {'m','o','u','s','e','m','o','v','e',0};
69 static const WCHAR mouseoutW[] = {'m','o','u','s','e','o','u','t',0};
70 static const WCHAR mouseoverW[] = {'m','o','u','s','e','o','v','e','r',0};
71 static const WCHAR mouseupW[] = {'m','o','u','s','e','u','p',0};
72 static const WCHAR mousewheelW[] = {'m','o','u','s','e','w','h','e','e','l',0};
73 static const WCHAR pasteW[] = {'p','a','s','t','e',0};
74 static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
75 static const WCHAR resizeW[] = {'r','e','s','i','z','e',0};
76 static const WCHAR scrollW[] = {'s','c','r','o','l','l',0};
77 static const WCHAR selectstartW[] = {'s','e','l','e','c','t','s','t','a','r','t',0};
78 static const WCHAR selectionchangeW[] = {'s','e','l','e','c','t','i','o','n','c','h','a','n','g','e',0};
79 static const WCHAR submitW[] = {'s','u','b','m','i','t',0};
80 static const WCHAR unloadW[] = {'u','n','l','o','a','d',0};
82 static const WCHAR EventW[] = {'E','v','e','n','t',0};
83 static const WCHAR UIEventW[] = {'U','I','E','v','e','n','t',0};
84 static const WCHAR KeyboardEventW[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
85 static const WCHAR MouseEventW[] = {'M','o','u','s','e','E','v','e','n','t',0};
87 typedef enum {
88 EVENT_TYPE_EVENT,
89 EVENT_TYPE_UIEVENT,
90 EVENT_TYPE_KEYBOARD,
91 EVENT_TYPE_MOUSE,
92 EVENT_TYPE_FOCUS,
93 EVENT_TYPE_DRAG,
94 EVENT_TYPE_MESSAGE,
95 EVENT_TYPE_CLIPBOARD
96 } event_type_t;
98 static const WCHAR *event_types[] = {
99 EventW,
100 UIEventW,
101 KeyboardEventW,
102 MouseEventW,
103 EventW, /* FIXME */
104 EventW, /* FIXME */
105 EventW, /* FIXME */
106 EventW /* FIXME */
109 typedef struct {
110 const WCHAR *name;
111 event_type_t type;
112 DISPID dispid;
113 DWORD flags;
114 } event_info_t;
116 #define EVENT_DEFAULTLISTENER 0x0001
117 #define EVENT_BUBBLES 0x0002
118 #define EVENT_BIND_TO_BODY 0x0008
119 #define EVENT_CANCELABLE 0x0010
120 #define EVENT_HASDEFAULTHANDLERS 0x0020
121 #define EVENT_FIXME 0x0040
123 static const event_info_t event_info[] = {
124 {abortW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONABORT,
125 EVENT_BIND_TO_BODY},
126 {beforeactivateW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONBEFOREACTIVATE,
127 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
128 {beforeunloadW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONBEFOREUNLOAD,
129 EVENT_DEFAULTLISTENER | EVENT_CANCELABLE },
130 {blurW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONBLUR,
131 EVENT_DEFAULTLISTENER},
132 {changeW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONCHANGE,
133 EVENT_DEFAULTLISTENER | EVENT_BUBBLES},
134 {clickW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONCLICK,
135 EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE },
136 {contextmenuW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONCONTEXTMENU,
137 EVENT_BUBBLES | EVENT_CANCELABLE},
138 {dataavailableW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONDATAAVAILABLE,
139 EVENT_FIXME | EVENT_BUBBLES},
140 {dblclickW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONDBLCLICK,
141 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
142 {dragW, EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAG,
143 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
144 {dragstartW, EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAGSTART,
145 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
146 {errorW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONERROR,
147 EVENT_BIND_TO_BODY},
148 {focusW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUS,
149 EVENT_DEFAULTLISTENER},
150 {focusinW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUSIN,
151 EVENT_BUBBLES},
152 {focusoutW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUSOUT,
153 EVENT_BUBBLES},
154 {helpW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONHELP,
155 EVENT_BUBBLES | EVENT_CANCELABLE},
156 {keydownW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYDOWN,
157 EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE },
158 {keypressW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYPRESS,
159 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
160 {keyupW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYUP,
161 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
162 {loadW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONLOAD,
163 EVENT_BIND_TO_BODY},
164 {messageW, EVENT_TYPE_MESSAGE, DISPID_EVMETH_ONMESSAGE,
166 {mousedownW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
167 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
168 {mousemoveW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEMOVE,
169 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
170 {mouseoutW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEOUT,
171 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
172 {mouseoverW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEOVER,
173 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
174 {mouseupW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEUP,
175 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
176 {mousewheelW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEWHEEL,
177 EVENT_FIXME},
178 {pasteW, EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE,
179 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
180 {readystatechangeW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONREADYSTATECHANGE,
182 {resizeW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONRESIZE,
183 EVENT_DEFAULTLISTENER},
184 {scrollW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONSCROLL,
185 EVENT_DEFAULTLISTENER | EVENT_BUBBLES /* FIXME: not for elements */},
186 {selectionchangeW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONSELECTIONCHANGE,
187 EVENT_FIXME},
188 {selectstartW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONSELECTSTART,
189 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
190 {submitW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONSUBMIT,
191 EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE},
192 {unloadW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD,
193 EVENT_FIXME}
196 static BOOL use_event_quirks(EventTarget*);
198 static eventid_t str_to_eid(const WCHAR *str)
200 int i;
202 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
203 if(!strcmpW(event_info[i].name, str))
204 return i;
207 ERR("unknown type %s\n", debugstr_w(str));
208 return EVENTID_LAST;
211 static eventid_t attr_to_eid(const WCHAR *str)
213 int i;
215 if((str[0] != 'o' && str[0] != 'O') || (str[1] != 'n' && str[1] != 'N'))
216 return EVENTID_LAST;
218 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
219 if(!strcmpW(event_info[i].name, str+2))
220 return i;
223 return EVENTID_LAST;
226 typedef struct {
227 DispatchEx dispex;
228 IHTMLEventObj IHTMLEventObj_iface;
230 LONG ref;
232 const event_info_t *type;
233 DOMEvent *event;
234 VARIANT return_value;
235 } HTMLEventObj;
237 static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface)
239 return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj_iface);
242 static HRESULT WINAPI HTMLEventObj_QueryInterface(IHTMLEventObj *iface, REFIID riid, void **ppv)
244 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
246 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
248 if(IsEqualGUID(&IID_IUnknown, riid)) {
249 *ppv = &This->IHTMLEventObj_iface;
250 }else if(IsEqualGUID(&IID_IHTMLEventObj, riid)) {
251 *ppv = &This->IHTMLEventObj_iface;
252 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
253 return *ppv ? S_OK : E_NOINTERFACE;
254 }else {
255 *ppv = NULL;
256 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
257 return E_NOINTERFACE;
260 IUnknown_AddRef((IUnknown*)*ppv);
261 return S_OK;
264 static ULONG WINAPI HTMLEventObj_AddRef(IHTMLEventObj *iface)
266 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
267 LONG ref = InterlockedIncrement(&This->ref);
269 TRACE("(%p) ref=%d\n", This, ref);
271 return ref;
274 static ULONG WINAPI HTMLEventObj_Release(IHTMLEventObj *iface)
276 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
277 LONG ref = InterlockedDecrement(&This->ref);
279 TRACE("(%p) ref=%d\n", This, ref);
281 if(!ref) {
282 if(This->event)
283 IDOMEvent_Release(&This->event->IDOMEvent_iface);
284 release_dispex(&This->dispex);
285 heap_free(This);
288 return ref;
291 static HRESULT WINAPI HTMLEventObj_GetTypeInfoCount(IHTMLEventObj *iface, UINT *pctinfo)
293 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
294 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
297 static HRESULT WINAPI HTMLEventObj_GetTypeInfo(IHTMLEventObj *iface, UINT iTInfo,
298 LCID lcid, ITypeInfo **ppTInfo)
300 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
301 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
304 static HRESULT WINAPI HTMLEventObj_GetIDsOfNames(IHTMLEventObj *iface, REFIID riid,
305 LPOLESTR *rgszNames, UINT cNames,
306 LCID lcid, DISPID *rgDispId)
308 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
309 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
310 lcid, rgDispId);
313 static HRESULT WINAPI HTMLEventObj_Invoke(IHTMLEventObj *iface, DISPID dispIdMember,
314 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
315 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
317 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
318 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
319 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
322 static HRESULT WINAPI HTMLEventObj_get_srcElement(IHTMLEventObj *iface, IHTMLElement **p)
324 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
326 TRACE("(%p)->(%p)\n", This, p);
328 *p = NULL;
329 if(This->event && This->event->target)
330 IDispatchEx_QueryInterface(&This->event->target->dispex.IDispatchEx_iface, &IID_IHTMLElement, (void**)p);
331 return S_OK;
334 static HRESULT WINAPI HTMLEventObj_get_altKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
336 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
337 cpp_bool ret = FALSE;
339 TRACE("(%p)->(%p)\n", This, p);
341 if(This->event) {
342 nsIDOMKeyEvent *key_event;
343 nsresult nsres;
345 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
346 if(NS_SUCCEEDED(nsres)) {
347 nsIDOMKeyEvent_GetAltKey(key_event, &ret);
348 nsIDOMKeyEvent_Release(key_event);
349 }else {
350 nsIDOMMouseEvent *mouse_event;
352 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
353 if(NS_SUCCEEDED(nsres)) {
354 nsIDOMMouseEvent_GetAltKey(mouse_event, &ret);
355 nsIDOMMouseEvent_Release(mouse_event);
360 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
361 return S_OK;
364 static HRESULT WINAPI HTMLEventObj_get_ctrlKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
366 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
367 cpp_bool ret = FALSE;
369 TRACE("(%p)->(%p)\n", This, p);
371 if(This->event) {
372 nsIDOMKeyEvent *key_event;
373 nsresult nsres;
375 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
376 if(NS_SUCCEEDED(nsres)) {
377 nsIDOMKeyEvent_GetCtrlKey(key_event, &ret);
378 nsIDOMKeyEvent_Release(key_event);
379 }else {
380 nsIDOMMouseEvent *mouse_event;
382 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
383 if(NS_SUCCEEDED(nsres)) {
384 nsIDOMMouseEvent_GetCtrlKey(mouse_event, &ret);
385 nsIDOMMouseEvent_Release(mouse_event);
390 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
391 return S_OK;
394 static HRESULT WINAPI HTMLEventObj_get_shiftKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
396 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
397 cpp_bool ret = FALSE;
399 TRACE("(%p)->(%p)\n", This, p);
401 if(This->event) {
402 nsIDOMKeyEvent *key_event;
403 nsresult nsres;
405 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
406 if(NS_SUCCEEDED(nsres)) {
407 nsIDOMKeyEvent_GetShiftKey(key_event, &ret);
408 nsIDOMKeyEvent_Release(key_event);
409 }else {
410 nsIDOMMouseEvent *mouse_event;
412 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
413 if(NS_SUCCEEDED(nsres)) {
414 nsIDOMMouseEvent_GetShiftKey(mouse_event, &ret);
415 nsIDOMMouseEvent_Release(mouse_event);
420 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
421 return S_OK;
424 static HRESULT WINAPI HTMLEventObj_put_returnValue(IHTMLEventObj *iface, VARIANT v)
426 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
428 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
430 if(V_VT(&v) != VT_BOOL) {
431 FIXME("unsupported value %s\n", debugstr_variant(&v));
432 return DISP_E_BADVARTYPE;
435 This->return_value = v;
436 if(!V_BOOL(&v) && This->event)
437 IDOMEvent_preventDefault(&This->event->IDOMEvent_iface);
438 return S_OK;
441 static HRESULT WINAPI HTMLEventObj_get_returnValue(IHTMLEventObj *iface, VARIANT *p)
443 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
445 TRACE("(%p)->(%p)\n", This, p);
447 V_VT(p) = VT_EMPTY;
448 return VariantCopy(p, &This->return_value);
451 static HRESULT WINAPI HTMLEventObj_put_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL v)
453 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
455 TRACE("(%p)->(%x)\n", This, v);
457 if(This->event)
458 IDOMEvent_stopPropagation(&This->event->IDOMEvent_iface);
459 return S_OK;
462 static HRESULT WINAPI HTMLEventObj_get_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL *p)
464 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
466 TRACE("(%p)->(%p)\n", This, p);
468 *p = This->event && This->event->stop_propagation ? VARIANT_TRUE : VARIANT_FALSE;
469 return S_OK;
472 static HRESULT WINAPI HTMLEventObj_get_fromElement(IHTMLEventObj *iface, IHTMLElement **p)
474 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
476 FIXME("(%p)->(%p)\n", This, p);
478 *p = NULL;
479 return S_OK;
482 static HRESULT WINAPI HTMLEventObj_get_toElement(IHTMLEventObj *iface, IHTMLElement **p)
484 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
486 FIXME("(%p)->(%p)\n", This, p);
488 *p = NULL;
489 return S_OK;
492 static HRESULT WINAPI HTMLEventObj_put_keyCode(IHTMLEventObj *iface, LONG v)
494 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
495 FIXME("(%p)->(%d)\n", This, v);
496 return E_NOTIMPL;
499 static HRESULT WINAPI HTMLEventObj_get_keyCode(IHTMLEventObj *iface, LONG *p)
501 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
502 UINT32 key_code = 0;
504 TRACE("(%p)->(%p)\n", This, p);
506 if(This->event) {
507 nsIDOMKeyEvent *key_event;
508 nsresult nsres;
510 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
511 if(NS_SUCCEEDED(nsres)) {
512 nsIDOMKeyEvent_GetKeyCode(key_event, &key_code);
513 nsIDOMKeyEvent_Release(key_event);
517 *p = key_code;
518 return S_OK;
521 static HRESULT WINAPI HTMLEventObj_get_button(IHTMLEventObj *iface, LONG *p)
523 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
524 INT16 button = 0;
526 TRACE("(%p)->(%p)\n", This, p);
528 if(This->event) {
529 nsIDOMMouseEvent *mouse_event;
530 nsresult nsres;
532 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
533 if(NS_SUCCEEDED(nsres)) {
534 nsIDOMMouseEvent_GetButton(mouse_event, &button);
535 nsIDOMMouseEvent_Release(mouse_event);
539 *p = button;
540 return S_OK;
543 static HRESULT WINAPI HTMLEventObj_get_type(IHTMLEventObj *iface, BSTR *p)
545 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
547 TRACE("(%p)->(%p)\n", This, p);
549 if(!This->type) {
550 *p = NULL;
551 return S_OK;
554 *p = SysAllocString(This->type->name);
555 return *p ? S_OK : E_OUTOFMEMORY;
558 static HRESULT WINAPI HTMLEventObj_get_qualifier(IHTMLEventObj *iface, BSTR *p)
560 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
562 FIXME("(%p)->(%p)\n", This, p);
564 *p = NULL;
565 return S_OK;
568 static HRESULT WINAPI HTMLEventObj_get_reason(IHTMLEventObj *iface, LONG *p)
570 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
572 FIXME("(%p)->(%p)\n", This, p);
574 *p = 0;
575 return S_OK;
578 static HRESULT WINAPI HTMLEventObj_get_x(IHTMLEventObj *iface, LONG *p)
580 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
581 LONG x = 0;
583 TRACE("(%p)->(%p)\n", This, p);
585 if(This->event) {
586 nsIDOMUIEvent *ui_event;
587 nsresult nsres;
589 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMUIEvent, (void**)&ui_event);
590 if(NS_SUCCEEDED(nsres)) {
591 /* NOTE: pageX is not exactly right here. */
592 nsres = nsIDOMUIEvent_GetPageX(ui_event, &x);
593 assert(nsres == NS_OK);
594 nsIDOMUIEvent_Release(ui_event);
598 *p = x;
599 return S_OK;
602 static HRESULT WINAPI HTMLEventObj_get_y(IHTMLEventObj *iface, LONG *p)
604 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
605 LONG y = 0;
607 TRACE("(%p)->(%p)\n", This, p);
609 if(This->event) {
610 nsIDOMUIEvent *ui_event;
611 nsresult nsres;
613 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMUIEvent, (void**)&ui_event);
614 if(NS_SUCCEEDED(nsres)) {
615 /* NOTE: pageY is not exactly right here. */
616 nsres = nsIDOMUIEvent_GetPageY(ui_event, &y);
617 assert(nsres == NS_OK);
618 nsIDOMUIEvent_Release(ui_event);
622 *p = y;
623 return S_OK;
626 static HRESULT WINAPI HTMLEventObj_get_clientX(IHTMLEventObj *iface, LONG *p)
628 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
629 LONG x = 0;
631 TRACE("(%p)->(%p)\n", This, p);
633 if(This->event) {
634 nsIDOMMouseEvent *mouse_event;
635 nsresult nsres;
637 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
638 if(NS_SUCCEEDED(nsres)) {
639 nsIDOMMouseEvent_GetClientX(mouse_event, &x);
640 nsIDOMMouseEvent_Release(mouse_event);
644 *p = x;
645 return S_OK;
648 static HRESULT WINAPI HTMLEventObj_get_clientY(IHTMLEventObj *iface, LONG *p)
650 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
651 LONG y = 0;
653 TRACE("(%p)->(%p)\n", This, p);
655 if(This->event) {
656 nsIDOMMouseEvent *mouse_event;
657 nsresult nsres;
659 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
660 if(NS_SUCCEEDED(nsres)) {
661 nsIDOMMouseEvent_GetClientY(mouse_event, &y);
662 nsIDOMMouseEvent_Release(mouse_event);
666 *p = y;
667 return S_OK;
670 static HRESULT WINAPI HTMLEventObj_get_offsetX(IHTMLEventObj *iface, LONG *p)
672 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
674 FIXME("(%p)->(%p)\n", This, p);
676 *p = 0;
677 return S_OK;
680 static HRESULT WINAPI HTMLEventObj_get_offsetY(IHTMLEventObj *iface, LONG *p)
682 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
684 FIXME("(%p)->(%p)\n", This, p);
686 *p = 0;
687 return S_OK;
690 static HRESULT WINAPI HTMLEventObj_get_screenX(IHTMLEventObj *iface, LONG *p)
692 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
693 LONG x = 0;
695 TRACE("(%p)->(%p)\n", This, p);
697 if(This->event) {
698 nsIDOMMouseEvent *mouse_event;
699 nsresult nsres;
701 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
702 if(NS_SUCCEEDED(nsres)) {
703 nsIDOMMouseEvent_GetScreenX(mouse_event, &x);
704 nsIDOMMouseEvent_Release(mouse_event);
708 *p = x;
709 return S_OK;
712 static HRESULT WINAPI HTMLEventObj_get_screenY(IHTMLEventObj *iface, LONG *p)
714 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
715 LONG y = 0;
717 TRACE("(%p)->(%p)\n", This, p);
719 if(This->event) {
720 nsIDOMMouseEvent *mouse_event;
721 nsresult nsres;
723 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
724 if(NS_SUCCEEDED(nsres)) {
725 nsIDOMMouseEvent_GetScreenY(mouse_event, &y);
726 nsIDOMMouseEvent_Release(mouse_event);
730 *p = y;
731 return S_OK;
734 static HRESULT WINAPI HTMLEventObj_get_srcFilter(IHTMLEventObj *iface, IDispatch **p)
736 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
738 FIXME("(%p)->(%p)\n", This, p);
740 *p = NULL;
741 return S_OK;
744 static const IHTMLEventObjVtbl HTMLEventObjVtbl = {
745 HTMLEventObj_QueryInterface,
746 HTMLEventObj_AddRef,
747 HTMLEventObj_Release,
748 HTMLEventObj_GetTypeInfoCount,
749 HTMLEventObj_GetTypeInfo,
750 HTMLEventObj_GetIDsOfNames,
751 HTMLEventObj_Invoke,
752 HTMLEventObj_get_srcElement,
753 HTMLEventObj_get_altKey,
754 HTMLEventObj_get_ctrlKey,
755 HTMLEventObj_get_shiftKey,
756 HTMLEventObj_put_returnValue,
757 HTMLEventObj_get_returnValue,
758 HTMLEventObj_put_cancelBubble,
759 HTMLEventObj_get_cancelBubble,
760 HTMLEventObj_get_fromElement,
761 HTMLEventObj_get_toElement,
762 HTMLEventObj_put_keyCode,
763 HTMLEventObj_get_keyCode,
764 HTMLEventObj_get_button,
765 HTMLEventObj_get_type,
766 HTMLEventObj_get_qualifier,
767 HTMLEventObj_get_reason,
768 HTMLEventObj_get_x,
769 HTMLEventObj_get_y,
770 HTMLEventObj_get_clientX,
771 HTMLEventObj_get_clientY,
772 HTMLEventObj_get_offsetX,
773 HTMLEventObj_get_offsetY,
774 HTMLEventObj_get_screenX,
775 HTMLEventObj_get_screenY,
776 HTMLEventObj_get_srcFilter
779 static inline HTMLEventObj *unsafe_impl_from_IHTMLEventObj(IHTMLEventObj *iface)
781 return iface->lpVtbl == &HTMLEventObjVtbl ? impl_from_IHTMLEventObj(iface) : NULL;
784 static const tid_t HTMLEventObj_iface_tids[] = {
785 IHTMLEventObj_tid,
789 static dispex_static_data_t HTMLEventObj_dispex = {
790 NULL,
791 DispCEventObj_tid,
792 HTMLEventObj_iface_tids
795 static HTMLEventObj *alloc_event_obj(DOMEvent *event)
797 HTMLEventObj *event_obj;
799 event_obj = heap_alloc_zero(sizeof(*event_obj));
800 if(!event_obj)
801 return NULL;
803 event_obj->IHTMLEventObj_iface.lpVtbl = &HTMLEventObjVtbl;
804 event_obj->ref = 1;
805 event_obj->event = event;
806 if(event)
807 IDOMEvent_AddRef(&event->IDOMEvent_iface);
809 init_dispex(&event_obj->dispex, (IUnknown*)&event_obj->IHTMLEventObj_iface, &HTMLEventObj_dispex);
810 return event_obj;
813 HRESULT create_event_obj(IHTMLEventObj **ret)
815 HTMLEventObj *event_obj;
817 event_obj = alloc_event_obj(NULL);
818 if(!event_obj)
819 return E_OUTOFMEMORY;
821 *ret = &event_obj->IHTMLEventObj_iface;
822 return S_OK;
825 static inline DOMEvent *impl_from_IDOMEvent(IDOMEvent *iface)
827 return CONTAINING_RECORD(iface, DOMEvent, IDOMEvent_iface);
830 static HRESULT WINAPI DOMEvent_QueryInterface(IDOMEvent *iface, REFIID riid, void **ppv)
832 DOMEvent *This = impl_from_IDOMEvent(iface);
834 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
836 if(IsEqualGUID(&IID_IUnknown, riid))
837 *ppv = &This->IDOMEvent_iface;
838 else if(IsEqualGUID(&IID_IDOMEvent, riid))
839 *ppv = &This->IDOMEvent_iface;
840 else if(dispex_query_interface(&This->dispex, riid, ppv))
841 return *ppv ? S_OK : E_NOINTERFACE;
842 else {
843 *ppv = NULL;
844 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
845 return E_NOINTERFACE;
848 IUnknown_AddRef((IUnknown*)*ppv);
849 return S_OK;
852 static ULONG WINAPI DOMEvent_AddRef(IDOMEvent *iface)
854 DOMEvent *This = impl_from_IDOMEvent(iface);
855 LONG ref = InterlockedIncrement(&This->ref);
857 TRACE("(%p) ref=%u\n", This, ref);
859 return ref;
862 static ULONG WINAPI DOMEvent_Release(IDOMEvent *iface)
864 DOMEvent *This = impl_from_IDOMEvent(iface);
865 LONG ref = InterlockedDecrement(&This->ref);
867 TRACE("(%p) ref=%u\n", This, ref);
869 if(!ref) {
870 if(This->target)
871 IDispatchEx_Release(&This->target->dispex.IDispatchEx_iface);
872 nsIDOMEvent_Release(This->nsevent);
873 release_dispex(&This->dispex);
874 heap_free(This);
877 return ref;
880 static HRESULT WINAPI DOMEvent_GetTypeInfoCount(IDOMEvent *iface, UINT *pctinfo)
882 DOMEvent *This = impl_from_IDOMEvent(iface);
883 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
886 static HRESULT WINAPI DOMEvent_GetTypeInfo(IDOMEvent *iface, UINT iTInfo,
887 LCID lcid, ITypeInfo **ppTInfo)
889 DOMEvent *This = impl_from_IDOMEvent(iface);
890 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
893 static HRESULT WINAPI DOMEvent_GetIDsOfNames(IDOMEvent *iface, REFIID riid,
894 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
896 DOMEvent *This = impl_from_IDOMEvent(iface);
897 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
898 lcid, rgDispId);
901 static HRESULT WINAPI DOMEvent_Invoke(IDOMEvent *iface, DISPID dispIdMember,
902 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
903 EXCEPINFO *pExcepInfo, UINT *puArgErr)
905 DOMEvent *This = impl_from_IDOMEvent(iface);
906 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
907 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
910 static HRESULT WINAPI DOMEvent_get_bubbles(IDOMEvent *iface, VARIANT_BOOL *p)
912 DOMEvent *This = impl_from_IDOMEvent(iface);
913 FIXME("(%p)->(%p)\n", This, p);
914 return E_NOTIMPL;
917 static HRESULT WINAPI DOMEvent_get_cancelable(IDOMEvent *iface, VARIANT_BOOL *p)
919 DOMEvent *This = impl_from_IDOMEvent(iface);
920 FIXME("(%p)->(%p)\n", This, p);
921 return E_NOTIMPL;
924 static HRESULT WINAPI DOMEvent_get_currentTarget(IDOMEvent *iface, IEventTarget **p)
926 DOMEvent *This = impl_from_IDOMEvent(iface);
927 FIXME("(%p)->(%p)\n", This, p);
928 return E_NOTIMPL;
931 static HRESULT WINAPI DOMEvent_get_defaultPrevented(IDOMEvent *iface, VARIANT_BOOL *p)
933 DOMEvent *This = impl_from_IDOMEvent(iface);
934 FIXME("(%p)->(%p)\n", This, p);
935 return E_NOTIMPL;
938 static HRESULT WINAPI DOMEvent_get_eventPhase(IDOMEvent *iface, USHORT *p)
940 DOMEvent *This = impl_from_IDOMEvent(iface);
942 TRACE("(%p)->(%p)\n", This, p);
944 *p = This->phase;
945 return S_OK;
948 static HRESULT WINAPI DOMEvent_get_target(IDOMEvent *iface, IEventTarget **p)
950 DOMEvent *This = impl_from_IDOMEvent(iface);
951 FIXME("(%p)->(%p)\n", This, p);
952 return E_NOTIMPL;
955 static HRESULT WINAPI DOMEvent_get_timeStamp(IDOMEvent *iface, ULONGLONG *p)
957 DOMEvent *This = impl_from_IDOMEvent(iface);
958 FIXME("(%p)->(%p)\n", This, p);
959 return E_NOTIMPL;
962 static HRESULT WINAPI DOMEvent_get_type(IDOMEvent *iface, BSTR *p)
964 DOMEvent *This = impl_from_IDOMEvent(iface);
965 FIXME("(%p)->(%p)\n", This, p);
966 return E_NOTIMPL;
969 static HRESULT WINAPI DOMEvent_initEvent(IDOMEvent *iface, BSTR type, VARIANT_BOOL can_bubble, VARIANT_BOOL cancelable)
971 DOMEvent *This = impl_from_IDOMEvent(iface);
972 FIXME("(%p)->()\n", This);
973 return E_NOTIMPL;
976 static HRESULT WINAPI DOMEvent_preventDefault(IDOMEvent *iface)
978 DOMEvent *This = impl_from_IDOMEvent(iface);
980 TRACE("(%p)\n", This);
982 This->prevent_default = TRUE;
983 nsIDOMEvent_PreventDefault(This->nsevent);
984 return S_OK;
987 static HRESULT WINAPI DOMEvent_stopPropagation(IDOMEvent *iface)
989 DOMEvent *This = impl_from_IDOMEvent(iface);
991 TRACE("(%p)\n", This);
993 This->stop_propagation = TRUE;
994 nsIDOMEvent_StopPropagation(This->nsevent);
995 IDOMEvent_preventDefault(&This->IDOMEvent_iface);
996 return S_OK;
999 static HRESULT WINAPI DOMEvent_stopImmediatePropagation(IDOMEvent *iface)
1001 DOMEvent *This = impl_from_IDOMEvent(iface);
1002 FIXME("(%p)\n", This);
1003 return E_NOTIMPL;
1006 static HRESULT WINAPI DOMEvent_get_isTrusted(IDOMEvent *iface, VARIANT_BOOL *p)
1008 DOMEvent *This = impl_from_IDOMEvent(iface);
1009 FIXME("(%p)->(%p)\n", This, p);
1010 return E_NOTIMPL;
1013 static HRESULT WINAPI DOMEvent_put_cancelBubble(IDOMEvent *iface, VARIANT_BOOL v)
1015 DOMEvent *This = impl_from_IDOMEvent(iface);
1016 FIXME("(%p)->(%x)\n", This, v);
1017 return E_NOTIMPL;
1020 static HRESULT WINAPI DOMEvent_get_cancelBubble(IDOMEvent *iface, VARIANT_BOOL *p)
1022 DOMEvent *This = impl_from_IDOMEvent(iface);
1023 FIXME("(%p)->(%p)\n", This, p);
1024 return E_NOTIMPL;
1027 static HRESULT WINAPI DOMEvent_get_srcElement(IDOMEvent *iface, IHTMLElement **p)
1029 DOMEvent *This = impl_from_IDOMEvent(iface);
1030 FIXME("(%p)->(%p)\n", This, p);
1031 return E_NOTIMPL;
1034 static const IDOMEventVtbl DOMEventVtbl = {
1035 DOMEvent_QueryInterface,
1036 DOMEvent_AddRef,
1037 DOMEvent_Release,
1038 DOMEvent_GetTypeInfoCount,
1039 DOMEvent_GetTypeInfo,
1040 DOMEvent_GetIDsOfNames,
1041 DOMEvent_Invoke,
1042 DOMEvent_get_bubbles,
1043 DOMEvent_get_cancelable,
1044 DOMEvent_get_currentTarget,
1045 DOMEvent_get_defaultPrevented,
1046 DOMEvent_get_eventPhase,
1047 DOMEvent_get_target,
1048 DOMEvent_get_timeStamp,
1049 DOMEvent_get_type,
1050 DOMEvent_initEvent,
1051 DOMEvent_preventDefault,
1052 DOMEvent_stopPropagation,
1053 DOMEvent_stopImmediatePropagation,
1054 DOMEvent_get_isTrusted,
1055 DOMEvent_put_cancelBubble,
1056 DOMEvent_get_cancelBubble,
1057 DOMEvent_get_srcElement
1060 static const tid_t DOMEvent_iface_tids[] = {
1061 IDOMEvent_tid,
1065 static dispex_static_data_t DOMEvent_dispex = {
1066 NULL,
1067 IDOMEvent_tid,
1068 DOMEvent_iface_tids
1071 static DOMEvent *alloc_event(nsIDOMEvent *nsevent)
1073 DOMEvent *event;
1075 event = heap_alloc_zero(sizeof(*event));
1076 if(!event)
1077 return NULL;
1079 init_dispex(&event->dispex, (IUnknown*)&event->IDOMEvent_iface, &DOMEvent_dispex);
1080 event->IDOMEvent_iface.lpVtbl = &DOMEventVtbl;
1081 event->ref = 1;
1082 nsIDOMEvent_AddRef(event->nsevent = nsevent);
1083 event->event_id = EVENTID_LAST;
1084 return event;
1087 HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, DOMEvent **ret_event)
1089 DOMEvent *event;
1090 nsAString nsstr;
1091 nsresult nsres;
1093 event = alloc_event(nsevent);
1094 if(!event)
1095 return E_OUTOFMEMORY;
1097 nsAString_Init(&nsstr, NULL);
1098 nsres = nsIDOMEvent_GetType(event->nsevent, &nsstr);
1099 if(NS_SUCCEEDED(nsres)) {
1100 const WCHAR *type;
1101 nsAString_GetData(&nsstr, &type);
1102 event->event_id = str_to_eid(type);
1103 if(event->event_id == EVENTID_LAST)
1104 FIXME("unknown event type %s\n", debugstr_w(type));
1105 }else {
1106 ERR("GetType failed: %08x\n", nsres);
1108 nsAString_Finish(&nsstr);
1110 *ret_event = event;
1111 return S_OK;
1114 HRESULT create_document_event_str(HTMLDocumentNode *doc, const WCHAR *type, IDOMEvent **ret_event)
1116 nsIDOMEvent *nsevent;
1117 DOMEvent *event;
1118 nsAString nsstr;
1119 nsresult nsres;
1121 nsAString_InitDepend(&nsstr, type);
1122 nsres = nsIDOMHTMLDocument_CreateEvent(doc->nsdoc, &nsstr, &nsevent);
1123 nsAString_Finish(&nsstr);
1124 if(NS_FAILED(nsres)) {
1125 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(type), nsres);
1126 return E_FAIL;
1129 event = alloc_event(nsevent);
1130 nsIDOMEvent_Release(nsevent);
1131 if(!event)
1132 return E_OUTOFMEMORY;
1134 *ret_event = &event->IDOMEvent_iface;
1135 return S_OK;
1138 HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEvent **ret_event)
1140 nsIDOMEvent *nsevent;
1141 DOMEvent *event;
1142 nsAString nsstr;
1143 nsresult nsres;
1145 nsAString_InitDepend(&nsstr, event_types[event_info[event_id].type]);
1146 nsres = nsIDOMHTMLDocument_CreateEvent(doc->nsdoc, &nsstr, &nsevent);
1147 nsAString_Finish(&nsstr);
1148 if(NS_FAILED(nsres)) {
1149 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(event_types[event_info[event_id].type]), nsres);
1150 return E_FAIL;
1153 event = alloc_event(nsevent);
1154 if(!event)
1155 return E_OUTOFMEMORY;
1157 event->event_id = event_id;
1158 *ret_event = event;
1159 return S_OK;
1162 static handler_vector_t *get_handler_vector(EventTarget *event_target, eventid_t eid, BOOL alloc)
1164 const event_target_vtbl_t *vtbl;
1165 handler_vector_t *handler_vector;
1166 struct wine_rb_entry *entry;
1168 entry = wine_rb_get(&event_target->handler_map, (const void*)eid);
1169 if(entry)
1170 return WINE_RB_ENTRY_VALUE(entry, handler_vector_t, entry);
1171 if(!alloc)
1172 return NULL;
1174 handler_vector = heap_alloc_zero(sizeof(*handler_vector));
1175 if(!handler_vector)
1176 return NULL;
1178 handler_vector->event_id = eid;
1179 vtbl = dispex_get_vtbl(&event_target->dispex);
1180 if(vtbl->bind_event)
1181 vtbl->bind_event(&event_target->dispex, eid);
1182 else
1183 FIXME("Unsupported event binding on target %p\n", event_target);
1185 wine_rb_put(&event_target->handler_map, (const void*)eid, &handler_vector->entry);
1186 return handler_vector;
1189 static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
1191 IDispatchEx *dispex;
1192 EXCEPINFO ei;
1193 HRESULT hres;
1195 memset(&ei, 0, sizeof(ei));
1197 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1198 if(SUCCEEDED(hres)) {
1199 hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, dp, retv, &ei, NULL);
1200 IDispatchEx_Release(dispex);
1201 }else {
1202 TRACE("Could not get IDispatchEx interface: %08x\n", hres);
1203 hres = IDispatch_Invoke(disp, 0, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD,
1204 dp, retv, &ei, NULL);
1207 return hres;
1210 static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, IHTMLEventObj *event_obj, VARIANT *retv)
1212 DISPPARAMS dp = {NULL,NULL,0,0};
1213 VARIANT event_arg;
1214 ULONG argerr;
1215 EXCEPINFO ei;
1217 if(event_obj) {
1218 V_VT(&event_arg) = VT_DISPATCH;
1219 V_DISPATCH(&event_arg) = (IDispatch*)event_obj;
1220 dp.rgvarg = &event_arg;
1221 dp.cArgs = 1;
1224 memset(&ei, 0, sizeof(ei));
1225 return IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, retv, &ei, &argerr);
1228 static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
1230 int min, max, i;
1231 HRESULT hres;
1233 if(!data)
1234 return FALSE;
1236 if(!data->ids) {
1237 hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
1238 if(FAILED(hres))
1239 return FALSE;
1242 min = 0;
1243 max = data->id_cnt-1;
1244 while(min <= max) {
1245 i = (min+max)/2;
1246 if(data->ids[i] == dispid)
1247 return TRUE;
1249 if(data->ids[i] < dispid)
1250 min = i+1;
1251 else
1252 max = i-1;
1255 return FALSE;
1258 static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
1260 const eventid_t eid = event->event_id;
1261 handler_vector_t *handler_vector = get_handler_vector(event_target, eid, FALSE);
1262 const BOOL cancelable = event_info[eid].flags & EVENT_CANCELABLE;
1263 ConnectionPointContainer *cp_container = NULL;
1264 const event_target_vtbl_t *vtbl;
1265 VARIANT v;
1266 HRESULT hres;
1268 if(handler_vector && handler_vector->handler_prop) {
1269 DISPID named_arg = DISPID_THIS;
1270 VARIANTARG arg;
1271 DISPPARAMS dp = {&arg, &named_arg, 1, 1};
1273 if(!use_event_quirks(event_target))
1274 FIXME("Event argument not supported\n");
1276 V_VT(&arg) = VT_DISPATCH;
1277 V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
1278 V_VT(&v) = VT_EMPTY;
1280 TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
1281 hres = call_disp_func(handler_vector->handler_prop, &dp, &v);
1282 if(hres == S_OK) {
1283 TRACE("%s <<< %s\n", debugstr_w(event_info[eid].name), debugstr_variant(&v));
1285 if(cancelable) {
1286 if(V_VT(&v) == VT_BOOL) {
1287 if(!V_BOOL(&v))
1288 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1289 }else if(V_VT(&v) != VT_EMPTY) {
1290 FIXME("unhandled result %s\n", debugstr_variant(&v));
1293 VariantClear(&v);
1294 }else {
1295 WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
1299 if(handler_vector && handler_vector->handler_cnt) {
1300 VARIANTARG arg;
1301 DISPPARAMS dp = {&arg, NULL, 1, 0};
1302 int i;
1304 V_VT(&arg) = VT_DISPATCH;
1305 V_DISPATCH(&arg) = (IDispatch*)event->event_obj;
1307 i = handler_vector->handler_cnt;
1308 while(i--) {
1309 if(handler_vector->handlers[i]) {
1310 V_VT(&v) = VT_EMPTY;
1312 TRACE("%s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
1313 hres = call_disp_func(handler_vector->handlers[i], &dp, &v);
1314 if(hres == S_OK) {
1315 TRACE("%s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
1317 if(cancelable) {
1318 if(V_VT(&v) == VT_BOOL) {
1319 if(!V_BOOL(&v))
1320 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1321 }else if(V_VT(&v) != VT_EMPTY) {
1322 FIXME("unhandled result %s\n", debugstr_variant(&v));
1325 VariantClear(&v);
1326 }else {
1327 WARN("%s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
1333 if((vtbl = dispex_get_vtbl(&event_target->dispex)) && vtbl->get_cp_container)
1334 cp_container = vtbl->get_cp_container(&event_target->dispex);
1335 if(cp_container) {
1336 if(cp_container->cps) {
1337 ConnectionPoint *cp;
1338 unsigned i, j;
1340 for(j=0; cp_container->cp_entries[j].riid; j++) {
1341 cp = cp_container->cps + j;
1342 if(!cp->sinks_size || !is_cp_event(cp->data, event_info[eid].dispid))
1343 continue;
1345 for(i=0; i < cp->sinks_size; i++) {
1346 if(!cp->sinks[i].disp)
1347 continue;
1349 V_VT(&v) = VT_EMPTY;
1351 TRACE("cp %s [%u] >>>\n", debugstr_w(event_info[eid].name), i);
1352 hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid,
1353 cp->data->pass_event_arg ? event->event_obj : NULL, &v);
1354 if(hres == S_OK) {
1355 TRACE("cp %s [%u] <<<\n", debugstr_w(event_info[eid].name), i);
1357 if(cancelable) {
1358 if(V_VT(&v) == VT_BOOL) {
1359 if(!V_BOOL(&v))
1360 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1361 }else if(V_VT(&v) != VT_EMPTY) {
1362 FIXME("unhandled result %s\n", debugstr_variant(&v));
1365 VariantClear(&v);
1366 }else {
1367 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
1372 IConnectionPointContainer_Release(&cp_container->IConnectionPointContainer_iface);
1376 void dispatch_event(EventTarget *event_target, DOMEvent *event)
1378 EventTarget *target_chain_buf[8], **target_chain = target_chain_buf;
1379 unsigned chain_cnt, chain_buf_size, i;
1380 const event_target_vtbl_t *vtbl, *target_vtbl;
1381 HTMLEventObj *event_obj_ref = NULL;
1382 IHTMLEventObj *prev_event = NULL;
1383 EventTarget *iter;
1384 DWORD event_flags;
1385 HRESULT hres;
1387 if(event->event_id == EVENTID_LAST) {
1388 FIXME("Unsupported on unknown events\n");
1389 return;
1392 TRACE("(%p) %s\n", event_target, debugstr_w(event_info[event->event_id].name));
1394 event_flags = event_info[event->event_id].flags;
1395 iter = event_target;
1396 IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
1398 chain_cnt = 0;
1399 chain_buf_size = sizeof(target_chain_buf)/sizeof(*target_chain_buf);
1401 do {
1402 if(chain_cnt == chain_buf_size) {
1403 EventTarget **new_chain;
1404 if(target_chain == target_chain_buf) {
1405 new_chain = heap_alloc(chain_buf_size * 2 * sizeof(*new_chain));
1406 if(!new_chain)
1407 break;
1408 memcpy(new_chain, target_chain, chain_buf_size * sizeof(*new_chain));
1409 }else {
1410 new_chain = heap_realloc(target_chain, chain_buf_size * 2 * sizeof(*new_chain));
1411 if(!new_chain)
1412 break;
1414 chain_buf_size *= 2;
1415 target_chain = new_chain;
1418 target_chain[chain_cnt++] = iter;
1420 if(!(vtbl = dispex_get_vtbl(&iter->dispex)) || !vtbl->get_parent_event_target)
1421 break;
1422 iter = vtbl->get_parent_event_target(&iter->dispex);
1423 } while(iter);
1425 if(!event->event_obj && !event->no_event_obj) {
1426 event_obj_ref = alloc_event_obj(event);
1427 if(event_obj_ref) {
1428 event_obj_ref->type = event_info + event->event_id;
1429 event->event_obj = &event_obj_ref->IHTMLEventObj_iface;
1433 target_vtbl = dispex_get_vtbl(&event_target->dispex);
1434 if(target_vtbl && target_vtbl->set_current_event)
1435 prev_event = target_vtbl->set_current_event(&event_target->dispex, event->event_obj);
1437 event->target = event_target;
1438 IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
1440 event->phase = DEP_AT_TARGET;
1441 call_event_handlers(target_chain[0], event);
1443 if(event_flags & EVENT_BUBBLES) {
1444 event->phase = DEP_BUBBLING_PHASE;
1445 for(i = 1; !event->stop_propagation && i < chain_cnt; i++)
1446 call_event_handlers(target_chain[i], event);
1449 if(target_vtbl && target_vtbl->set_current_event) {
1450 prev_event = target_vtbl->set_current_event(&event_target->dispex, prev_event);
1451 if(prev_event)
1452 IHTMLEventObj_Release(prev_event);
1455 if(event_flags & EVENT_HASDEFAULTHANDLERS) {
1456 for(i = 0; !event->prevent_default && i < chain_cnt; i++) {
1457 BOOL prevent_default = FALSE;
1458 vtbl = dispex_get_vtbl(&target_chain[i]->dispex);
1459 if(!vtbl || !vtbl->handle_event_default)
1460 continue;
1461 hres = vtbl->handle_event_default(&event_target->dispex, event->event_id,
1462 event->nsevent, &prevent_default);
1463 if(FAILED(hres) || event->stop_propagation)
1464 break;
1465 if(prevent_default)
1466 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1470 if(event_obj_ref) {
1471 event->event_obj = NULL;
1472 IHTMLEventObj_Release(&event_obj_ref->IHTMLEventObj_iface);
1475 for(i = 0; i < chain_cnt; i++)
1476 IDispatchEx_Release(&target_chain[i]->dispex.IDispatchEx_iface);
1477 if(target_chain != target_chain_buf)
1478 heap_free(target_chain);
1481 HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_var, VARIANT_BOOL *cancelled)
1483 HTMLEventObj *event_obj = NULL;
1484 eventid_t eid;
1485 HRESULT hres = S_OK;
1487 eid = attr_to_eid(event_name);
1488 if(eid == EVENTID_LAST) {
1489 WARN("unknown event %s\n", debugstr_w(event_name));
1490 return E_INVALIDARG;
1493 if(event_var && V_VT(event_var) != VT_EMPTY && V_VT(event_var) != VT_ERROR) {
1494 if(V_VT(event_var) != VT_DISPATCH) {
1495 FIXME("event_var %s not supported\n", debugstr_variant(event_var));
1496 return E_NOTIMPL;
1499 if(V_DISPATCH(event_var)) {
1500 IHTMLEventObj *event_iface;
1502 hres = IDispatch_QueryInterface(V_DISPATCH(event_var), &IID_IHTMLEventObj, (void**)&event_iface);
1503 if(FAILED(hres)) {
1504 FIXME("No IHTMLEventObj iface\n");
1505 return hres;
1508 event_obj = unsafe_impl_from_IHTMLEventObj(event_iface);
1509 if(!event_obj) {
1510 ERR("Not our IHTMLEventObj?\n");
1511 IHTMLEventObj_Release(event_iface);
1512 return E_FAIL;
1517 if(!event_obj) {
1518 event_obj = alloc_event_obj(NULL);
1519 if(!event_obj)
1520 return E_OUTOFMEMORY;
1523 event_obj->type = event_info + eid;
1524 if(!event_obj->event)
1525 hres = create_document_event(node->doc, eid, &event_obj->event);
1527 if(SUCCEEDED(hres)) {
1528 event_obj->event->event_obj = &event_obj->IHTMLEventObj_iface;
1529 dispatch_event(&node->event_target, event_obj->event);
1530 event_obj->event->event_obj = NULL;
1533 IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
1534 if(FAILED(hres))
1535 return hres;
1537 *cancelled = VARIANT_TRUE; /* FIXME */
1538 return S_OK;
1541 HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, eventid_t eid)
1543 nsIDOMNode *nsnode = NULL;
1545 TRACE("%s\n", debugstr_w(event_info[eid].name));
1547 if(!doc->nsdoc)
1548 return S_OK;
1550 switch(eid) {
1551 case EVENTID_FOCUSIN:
1552 doc->event_vector[eid] = TRUE;
1553 eid = EVENTID_FOCUS;
1554 break;
1555 case EVENTID_FOCUSOUT:
1556 doc->event_vector[eid] = TRUE;
1557 eid = EVENTID_BLUR;
1558 break;
1559 default:
1560 break;
1563 if(doc->event_vector[eid] || !(event_info[eid].flags & (EVENT_DEFAULTLISTENER|EVENT_BIND_TO_BODY)))
1564 return S_OK;
1566 if(event_info[eid].flags & EVENT_BIND_TO_BODY) {
1567 nsnode = doc->node.nsnode;
1568 nsIDOMNode_AddRef(nsnode);
1571 doc->event_vector[eid] = TRUE;
1572 add_nsevent_listener(doc, nsnode, event_info[eid].name);
1574 if(nsnode)
1575 nsIDOMNode_Release(nsnode);
1576 return S_OK;
1579 void detach_events(HTMLDocumentNode *doc)
1581 if(doc->event_vector) {
1582 int i;
1584 for(i=0; i < EVENTID_LAST; i++) {
1585 if(doc->event_vector[i]) {
1586 detach_nsevent(doc, event_info[i].name);
1587 doc->event_vector[i] = FALSE;
1592 release_nsevents(doc);
1595 static HRESULT get_event_dispex_ref(EventTarget *event_target, eventid_t eid, BOOL alloc, VARIANT **ret)
1597 WCHAR buf[64];
1598 buf[0] = 'o';
1599 buf[1] = 'n';
1600 strcpyW(buf+2, event_info[eid].name);
1601 return dispex_get_dprop_ref(&event_target->dispex, buf, alloc, ret);
1604 static void remove_event_handler(EventTarget *event_target, eventid_t eid)
1606 handler_vector_t *handler_vector;
1607 VARIANT *store;
1608 HRESULT hres;
1610 hres = get_event_dispex_ref(event_target, eid, FALSE, &store);
1611 if(SUCCEEDED(hres))
1612 VariantClear(store);
1614 handler_vector = get_handler_vector(event_target, eid, FALSE);
1615 if(handler_vector && handler_vector->handler_prop) {
1616 IDispatch_Release(handler_vector->handler_prop);
1617 handler_vector->handler_prop = NULL;
1621 static HRESULT set_event_handler_disp(EventTarget *event_target, eventid_t eid, IDispatch *disp)
1623 handler_vector_t *handler_vector;
1625 if(event_info[eid].flags & EVENT_FIXME)
1626 FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
1628 remove_event_handler(event_target, eid);
1629 if(!disp)
1630 return S_OK;
1632 handler_vector = get_handler_vector(event_target, eid, TRUE);
1633 if(!handler_vector)
1634 return E_OUTOFMEMORY;
1636 if(handler_vector->handler_prop)
1637 IDispatch_Release(handler_vector->handler_prop);
1639 handler_vector->handler_prop = disp;
1640 IDispatch_AddRef(disp);
1641 return S_OK;
1644 HRESULT set_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
1646 switch(V_VT(var)) {
1647 case VT_EMPTY:
1648 if(use_event_quirks(event_target)) {
1649 WARN("attempt to set to VT_EMPTY in quirks mode\n");
1650 return E_NOTIMPL;
1652 /* fall through */
1653 case VT_NULL:
1654 remove_event_handler(event_target, eid);
1655 return S_OK;
1657 case VT_DISPATCH:
1658 return set_event_handler_disp(event_target, eid, V_DISPATCH(var));
1660 case VT_BSTR: {
1661 VARIANT *v;
1662 HRESULT hres;
1664 if(!use_event_quirks(event_target))
1665 FIXME("Setting to string %s not supported\n", debugstr_w(V_BSTR(var)));
1668 * Setting event handler to string is a rare case and we don't want to
1669 * complicate nor increase memory of handler_vector_t for that. Instead,
1670 * we store the value in DispatchEx, which can already handle custom
1671 * properties.
1673 remove_event_handler(event_target, eid);
1675 hres = get_event_dispex_ref(event_target, eid, TRUE, &v);
1676 if(FAILED(hres))
1677 return hres;
1679 V_BSTR(v) = SysAllocString(V_BSTR(var));
1680 if(!V_BSTR(v))
1681 return E_OUTOFMEMORY;
1682 V_VT(v) = VT_BSTR;
1683 return S_OK;
1686 default:
1687 FIXME("not handler %s\n", debugstr_variant(var));
1688 return E_NOTIMPL;
1691 return S_OK;
1694 HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
1696 handler_vector_t *handler_vector;
1697 VARIANT *v;
1698 HRESULT hres;
1700 hres = get_event_dispex_ref(event_target, eid, FALSE, &v);
1701 if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY) {
1702 V_VT(var) = VT_EMPTY;
1703 return VariantCopy(var, v);
1706 handler_vector = get_handler_vector(event_target, eid, FALSE);
1707 if(handler_vector && handler_vector->handler_prop) {
1708 V_VT(var) = VT_DISPATCH;
1709 V_DISPATCH(var) = handler_vector->handler_prop;
1710 IDispatch_AddRef(V_DISPATCH(var));
1711 }else {
1712 V_VT(var) = VT_NULL;
1715 return S_OK;
1718 HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARIANT_BOOL *res)
1720 handler_vector_t *handler_vector;
1721 eventid_t eid;
1722 DWORD i = 0;
1724 eid = attr_to_eid(name);
1725 if(eid == EVENTID_LAST) {
1726 WARN("Unknown event\n");
1727 *res = VARIANT_TRUE;
1728 return S_OK;
1731 if(event_info[eid].flags & EVENT_FIXME)
1732 FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
1734 handler_vector = get_handler_vector(event_target, eid, TRUE);
1735 if(!handler_vector)
1736 return E_OUTOFMEMORY;
1738 while(i < handler_vector->handler_cnt && handler_vector->handlers[i])
1739 i++;
1740 if(i == handler_vector->handler_cnt) {
1741 if(i)
1742 handler_vector->handlers = heap_realloc_zero(handler_vector->handlers,
1743 (i + 1) * sizeof(*handler_vector->handlers));
1744 else
1745 handler_vector->handlers = heap_alloc_zero(sizeof(*handler_vector->handlers));
1746 if(!handler_vector->handlers)
1747 return E_OUTOFMEMORY;
1748 handler_vector->handler_cnt++;
1751 IDispatch_AddRef(disp);
1752 handler_vector->handlers[i] = disp;
1754 *res = VARIANT_TRUE;
1755 return S_OK;
1758 HRESULT detach_event(EventTarget *event_target, BSTR name, IDispatch *disp)
1760 handler_vector_t *handler_vector;
1761 eventid_t eid;
1762 unsigned i;
1764 eid = attr_to_eid(name);
1765 if(eid == EVENTID_LAST) {
1766 WARN("Unknown event\n");
1767 return S_OK;
1770 handler_vector = get_handler_vector(event_target, eid, FALSE);
1771 if(!handler_vector)
1772 return S_OK;
1774 for(i = 0; i < handler_vector->handler_cnt; i++) {
1775 if(handler_vector->handlers[i] == disp) {
1776 IDispatch_Release(handler_vector->handlers[i]);
1777 handler_vector->handlers[i] = NULL;
1781 return S_OK;
1784 void bind_target_event(HTMLDocumentNode *doc, EventTarget *event_target, const WCHAR *event, IDispatch *disp)
1786 eventid_t eid;
1788 TRACE("(%p %p %s %p)\n", doc, event_target, debugstr_w(event), disp);
1790 eid = attr_to_eid(event);
1791 if(eid == EVENTID_LAST) {
1792 WARN("Unsupported event %s\n", debugstr_w(event));
1793 return;
1796 set_event_handler_disp(event_target, eid, disp);
1799 void update_doc_cp_events(HTMLDocumentNode *doc, cp_static_data_t *cp)
1801 int i;
1803 for(i=0; i < EVENTID_LAST; i++) {
1804 if((event_info[i].flags & EVENT_DEFAULTLISTENER) && is_cp_event(cp, event_info[i].dispid))
1805 ensure_doc_nsevent_handler(doc, i);
1809 void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
1811 nsIDOMMozNamedAttrMap *attr_map;
1812 const PRUnichar *name, *value;
1813 nsAString name_str, value_str;
1814 HTMLDOMNode *node = NULL;
1815 cpp_bool has_attrs;
1816 nsIDOMAttr *attr;
1817 IDispatch *disp;
1818 UINT32 length, i;
1819 eventid_t eid;
1820 nsresult nsres;
1821 HRESULT hres;
1823 nsres = nsIDOMHTMLElement_HasAttributes(nselem, &has_attrs);
1824 if(NS_FAILED(nsres) || !has_attrs)
1825 return;
1827 nsres = nsIDOMHTMLElement_GetAttributes(nselem, &attr_map);
1828 if(NS_FAILED(nsres))
1829 return;
1831 nsres = nsIDOMMozNamedAttrMap_GetLength(attr_map, &length);
1832 assert(nsres == NS_OK);
1834 nsAString_Init(&name_str, NULL);
1835 nsAString_Init(&value_str, NULL);
1837 for(i = 0; i < length; i++) {
1838 nsres = nsIDOMMozNamedAttrMap_Item(attr_map, i, &attr);
1839 if(NS_FAILED(nsres))
1840 continue;
1842 nsres = nsIDOMAttr_GetName(attr, &name_str);
1843 if(NS_FAILED(nsres)) {
1844 nsIDOMAttr_Release(attr);
1845 continue;
1848 nsAString_GetData(&name_str, &name);
1849 eid = attr_to_eid(name);
1850 if(eid == EVENTID_LAST) {
1851 nsIDOMAttr_Release(attr);
1852 continue;
1855 nsres = nsIDOMAttr_GetValue(attr, &value_str);
1856 nsIDOMAttr_Release(attr);
1857 if(NS_FAILED(nsres))
1858 continue;
1860 nsAString_GetData(&value_str, &value);
1861 if(!*value)
1862 continue;
1864 TRACE("%p.%s = %s\n", nselem, debugstr_w(name), debugstr_w(value));
1866 disp = script_parse_event(doc->window, value);
1867 if(!disp)
1868 continue;
1870 if(!node) {
1871 hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
1872 if(FAILED(hres)) {
1873 IDispatch_Release(disp);
1874 break;
1878 set_event_handler_disp(get_node_event_prop_target(node, eid), eid, disp);
1879 IDispatch_Release(disp);
1882 if(node)
1883 node_release(node);
1884 nsAString_Finish(&name_str);
1885 nsAString_Finish(&value_str);
1886 nsIDOMMozNamedAttrMap_Release(attr_map);
1889 HRESULT doc_init_events(HTMLDocumentNode *doc)
1891 unsigned i;
1892 HRESULT hres;
1894 doc->event_vector = heap_alloc_zero(EVENTID_LAST*sizeof(BOOL));
1895 if(!doc->event_vector)
1896 return E_OUTOFMEMORY;
1898 init_nsevents(doc);
1900 for(i=0; i < EVENTID_LAST; i++) {
1901 if(event_info[i].flags & EVENT_HASDEFAULTHANDLERS) {
1902 hres = ensure_doc_nsevent_handler(doc, i);
1903 if(FAILED(hres))
1904 return hres;
1908 return S_OK;
1911 static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
1913 return CONTAINING_RECORD(iface, EventTarget, IEventTarget_iface);
1916 static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
1918 EventTarget *This = impl_from_IEventTarget(iface);
1919 return IDispatchEx_QueryInterface(&This->dispex.IDispatchEx_iface, riid, ppv);
1922 static ULONG WINAPI EventTarget_AddRef(IEventTarget *iface)
1924 EventTarget *This = impl_from_IEventTarget(iface);
1925 return IDispatchEx_AddRef(&This->dispex.IDispatchEx_iface);
1928 static ULONG WINAPI EventTarget_Release(IEventTarget *iface)
1930 EventTarget *This = impl_from_IEventTarget(iface);
1931 return IDispatchEx_Release(&This->dispex.IDispatchEx_iface);
1934 static HRESULT WINAPI EventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo)
1936 EventTarget *This = impl_from_IEventTarget(iface);
1937 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1940 static HRESULT WINAPI EventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo,
1941 LCID lcid, ITypeInfo **ppTInfo)
1943 EventTarget *This = impl_from_IEventTarget(iface);
1944 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1947 static HRESULT WINAPI EventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames,
1948 UINT cNames, LCID lcid, DISPID *rgDispId)
1950 EventTarget *This = impl_from_IEventTarget(iface);
1951 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid,
1952 rgszNames, cNames, lcid, rgDispId);
1955 static HRESULT WINAPI EventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember,
1956 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1957 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1959 EventTarget *This = impl_from_IEventTarget(iface);
1960 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember,
1961 riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1964 static HRESULT WINAPI EventTarget_addEventListener(IEventTarget *iface, BSTR type,
1965 IDispatch *listener, VARIANT_BOOL capture)
1967 EventTarget *This = impl_from_IEventTarget(iface);
1968 FIXME("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
1969 return E_NOTIMPL;
1972 static HRESULT WINAPI EventTarget_removeEventListener(IEventTarget *iface, BSTR type,
1973 IDispatch *listener, VARIANT_BOOL capture)
1975 EventTarget *This = impl_from_IEventTarget(iface);
1976 FIXME("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
1977 return E_NOTIMPL;
1980 static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event, VARIANT_BOOL *result)
1982 EventTarget *This = impl_from_IEventTarget(iface);
1983 FIXME("(%p)->(%p %p)\n", This, event, result);
1984 return E_NOTIMPL;
1987 static const IEventTargetVtbl EventTargetVtbl = {
1988 EventTarget_QueryInterface,
1989 EventTarget_AddRef,
1990 EventTarget_Release,
1991 EventTarget_GetTypeInfoCount,
1992 EventTarget_GetTypeInfo,
1993 EventTarget_GetIDsOfNames,
1994 EventTarget_Invoke,
1995 EventTarget_addEventListener,
1996 EventTarget_removeEventListener,
1997 EventTarget_dispatchEvent
2000 #define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
2002 static BOOL use_event_quirks(EventTarget *event_target)
2004 if(event_target->IEventTarget_iface.lpVtbl == DELAY_INIT_VTBL) {
2005 event_target->IEventTarget_iface.lpVtbl =
2006 dispex_compat_mode(&event_target->dispex) >= COMPAT_MODE_IE9
2007 ? &EventTargetVtbl : NULL;
2009 return !event_target->IEventTarget_iface.lpVtbl;
2012 HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
2014 if(IsEqualGUID(riid, &IID_IEventTarget)) {
2015 if(use_event_quirks(event_target)) {
2016 WARN("IEventTarget queried, but not supported by in document mode\n");
2017 *ppv = NULL;
2018 return E_NOINTERFACE;
2020 IEventTarget_AddRef(&event_target->IEventTarget_iface);
2021 *ppv = &event_target->IEventTarget_iface;
2022 return S_OK;
2025 if(dispex_query_interface(&event_target->dispex, riid, ppv))
2026 return *ppv ? S_OK : E_NOINTERFACE;
2028 WARN("(%p)->(%s %p)\n", event_target, debugstr_mshtml_guid(riid), ppv);
2029 *ppv = NULL;
2030 return E_NOINTERFACE;
2033 static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)
2035 return (INT_PTR)key - WINE_RB_ENTRY_VALUE(entry, handler_vector_t, entry)->event_id;
2038 void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_data_t *dispex_data,
2039 compat_mode_t compat_mode)
2041 init_dispex_with_compat_mode(&event_target->dispex, outer, dispex_data, compat_mode);
2042 wine_rb_init(&event_target->handler_map, event_id_cmp);
2045 * IEventTarget is supported by the object or not depending on compatibility mode.
2046 * We use NULL vtbl for objects in compatibility mode not supporting the interface.
2047 * For targets that don't know compatibility mode at creation time, we set vtbl
2048 * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
2049 * when it's needed.
2051 if(compat_mode == COMPAT_MODE_QUIRKS && dispex_data->vtbl && dispex_data->vtbl->get_compat_mode)
2052 event_target->IEventTarget_iface.lpVtbl = DELAY_INIT_VTBL;
2053 else if(compat_mode < COMPAT_MODE_IE9)
2054 event_target->IEventTarget_iface.lpVtbl = NULL;
2055 else
2056 event_target->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
2059 void release_event_target(EventTarget *event_target)
2061 handler_vector_t *iter, *iter2;
2062 unsigned i;
2064 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &event_target->handler_map, handler_vector_t, entry) {
2065 if(iter->handler_prop)
2066 IDispatch_Release(iter->handler_prop);
2067 for(i = 0; i < iter->handler_cnt; i++)
2068 if(iter->handlers[i])
2069 IDispatch_Release(iter->handlers[i]);
2070 heap_free(iter->handlers);
2071 heap_free(iter);