mshtml: Rename fire_event_obj and dispatch_event.
[wine.git] / dlls / mshtml / htmlevent.c
bloba42887926fcd1be0a08f53d560e2e747b22dc3ef
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);
941 FIXME("(%p)->(%p)\n", This, p);
942 return E_NOTIMPL;
945 static HRESULT WINAPI DOMEvent_get_target(IDOMEvent *iface, IEventTarget **p)
947 DOMEvent *This = impl_from_IDOMEvent(iface);
948 FIXME("(%p)->(%p)\n", This, p);
949 return E_NOTIMPL;
952 static HRESULT WINAPI DOMEvent_get_timeStamp(IDOMEvent *iface, ULONGLONG *p)
954 DOMEvent *This = impl_from_IDOMEvent(iface);
955 FIXME("(%p)->(%p)\n", This, p);
956 return E_NOTIMPL;
959 static HRESULT WINAPI DOMEvent_get_type(IDOMEvent *iface, BSTR *p)
961 DOMEvent *This = impl_from_IDOMEvent(iface);
962 FIXME("(%p)->(%p)\n", This, p);
963 return E_NOTIMPL;
966 static HRESULT WINAPI DOMEvent_initEvent(IDOMEvent *iface, BSTR type, VARIANT_BOOL can_bubble, VARIANT_BOOL cancelable)
968 DOMEvent *This = impl_from_IDOMEvent(iface);
969 FIXME("(%p)->()\n", This);
970 return E_NOTIMPL;
973 static HRESULT WINAPI DOMEvent_preventDefault(IDOMEvent *iface)
975 DOMEvent *This = impl_from_IDOMEvent(iface);
977 TRACE("(%p)\n", This);
979 This->prevent_default = TRUE;
980 nsIDOMEvent_PreventDefault(This->nsevent);
981 return S_OK;
984 static HRESULT WINAPI DOMEvent_stopPropagation(IDOMEvent *iface)
986 DOMEvent *This = impl_from_IDOMEvent(iface);
988 TRACE("(%p)\n", This);
990 This->stop_propagation = TRUE;
991 nsIDOMEvent_StopPropagation(This->nsevent);
992 IDOMEvent_preventDefault(&This->IDOMEvent_iface);
993 return S_OK;
996 static HRESULT WINAPI DOMEvent_stopImmediatePropagation(IDOMEvent *iface)
998 DOMEvent *This = impl_from_IDOMEvent(iface);
999 FIXME("(%p)\n", This);
1000 return E_NOTIMPL;
1003 static HRESULT WINAPI DOMEvent_get_isTrusted(IDOMEvent *iface, VARIANT_BOOL *p)
1005 DOMEvent *This = impl_from_IDOMEvent(iface);
1006 FIXME("(%p)->(%p)\n", This, p);
1007 return E_NOTIMPL;
1010 static HRESULT WINAPI DOMEvent_put_cancelBubble(IDOMEvent *iface, VARIANT_BOOL v)
1012 DOMEvent *This = impl_from_IDOMEvent(iface);
1013 FIXME("(%p)->(%x)\n", This, v);
1014 return E_NOTIMPL;
1017 static HRESULT WINAPI DOMEvent_get_cancelBubble(IDOMEvent *iface, VARIANT_BOOL *p)
1019 DOMEvent *This = impl_from_IDOMEvent(iface);
1020 FIXME("(%p)->(%p)\n", This, p);
1021 return E_NOTIMPL;
1024 static HRESULT WINAPI DOMEvent_get_srcElement(IDOMEvent *iface, IHTMLElement **p)
1026 DOMEvent *This = impl_from_IDOMEvent(iface);
1027 FIXME("(%p)->(%p)\n", This, p);
1028 return E_NOTIMPL;
1031 static const IDOMEventVtbl DOMEventVtbl = {
1032 DOMEvent_QueryInterface,
1033 DOMEvent_AddRef,
1034 DOMEvent_Release,
1035 DOMEvent_GetTypeInfoCount,
1036 DOMEvent_GetTypeInfo,
1037 DOMEvent_GetIDsOfNames,
1038 DOMEvent_Invoke,
1039 DOMEvent_get_bubbles,
1040 DOMEvent_get_cancelable,
1041 DOMEvent_get_currentTarget,
1042 DOMEvent_get_defaultPrevented,
1043 DOMEvent_get_eventPhase,
1044 DOMEvent_get_target,
1045 DOMEvent_get_timeStamp,
1046 DOMEvent_get_type,
1047 DOMEvent_initEvent,
1048 DOMEvent_preventDefault,
1049 DOMEvent_stopPropagation,
1050 DOMEvent_stopImmediatePropagation,
1051 DOMEvent_get_isTrusted,
1052 DOMEvent_put_cancelBubble,
1053 DOMEvent_get_cancelBubble,
1054 DOMEvent_get_srcElement
1057 static const tid_t DOMEvent_iface_tids[] = {
1058 IDOMEvent_tid,
1062 static dispex_static_data_t DOMEvent_dispex = {
1063 NULL,
1064 IDOMEvent_tid,
1065 DOMEvent_iface_tids
1068 static DOMEvent *alloc_event(nsIDOMEvent *nsevent)
1070 DOMEvent *event;
1072 event = heap_alloc_zero(sizeof(*event));
1073 if(!event)
1074 return NULL;
1076 init_dispex(&event->dispex, (IUnknown*)&event->IDOMEvent_iface, &DOMEvent_dispex);
1077 event->IDOMEvent_iface.lpVtbl = &DOMEventVtbl;
1078 event->ref = 1;
1079 nsIDOMEvent_AddRef(event->nsevent = nsevent);
1080 event->event_id = EVENTID_LAST;
1081 return event;
1084 HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, DOMEvent **ret_event)
1086 DOMEvent *event;
1087 nsAString nsstr;
1088 nsresult nsres;
1090 event = alloc_event(nsevent);
1091 if(!event)
1092 return E_OUTOFMEMORY;
1094 nsAString_Init(&nsstr, NULL);
1095 nsres = nsIDOMEvent_GetType(event->nsevent, &nsstr);
1096 if(NS_SUCCEEDED(nsres)) {
1097 const WCHAR *type;
1098 nsAString_GetData(&nsstr, &type);
1099 event->event_id = str_to_eid(type);
1100 if(event->event_id == EVENTID_LAST)
1101 FIXME("unknown event type %s\n", debugstr_w(type));
1102 }else {
1103 ERR("GetType failed: %08x\n", nsres);
1105 nsAString_Finish(&nsstr);
1107 *ret_event = event;
1108 return S_OK;
1111 HRESULT create_document_event_str(HTMLDocumentNode *doc, const WCHAR *type, IDOMEvent **ret_event)
1113 nsIDOMEvent *nsevent;
1114 DOMEvent *event;
1115 nsAString nsstr;
1116 nsresult nsres;
1118 nsAString_InitDepend(&nsstr, type);
1119 nsres = nsIDOMHTMLDocument_CreateEvent(doc->nsdoc, &nsstr, &nsevent);
1120 nsAString_Finish(&nsstr);
1121 if(NS_FAILED(nsres)) {
1122 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(type), nsres);
1123 return E_FAIL;
1126 event = alloc_event(nsevent);
1127 nsIDOMEvent_Release(nsevent);
1128 if(!event)
1129 return E_OUTOFMEMORY;
1131 *ret_event = &event->IDOMEvent_iface;
1132 return S_OK;
1135 HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEvent **ret_event)
1137 nsIDOMEvent *nsevent;
1138 DOMEvent *event;
1139 nsAString nsstr;
1140 nsresult nsres;
1142 nsAString_InitDepend(&nsstr, event_types[event_info[event_id].type]);
1143 nsres = nsIDOMHTMLDocument_CreateEvent(doc->nsdoc, &nsstr, &nsevent);
1144 nsAString_Finish(&nsstr);
1145 if(NS_FAILED(nsres)) {
1146 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(event_types[event_info[event_id].type]), nsres);
1147 return E_FAIL;
1150 event = alloc_event(nsevent);
1151 if(!event)
1152 return E_OUTOFMEMORY;
1154 event->event_id = event_id;
1155 *ret_event = event;
1156 return S_OK;
1159 static handler_vector_t *get_handler_vector(EventTarget *event_target, eventid_t eid, BOOL alloc)
1161 const event_target_vtbl_t *vtbl;
1162 handler_vector_t *handler_vector;
1163 struct wine_rb_entry *entry;
1165 entry = wine_rb_get(&event_target->handler_map, (const void*)eid);
1166 if(entry)
1167 return WINE_RB_ENTRY_VALUE(entry, handler_vector_t, entry);
1168 if(!alloc)
1169 return NULL;
1171 handler_vector = heap_alloc_zero(sizeof(*handler_vector));
1172 if(!handler_vector)
1173 return NULL;
1175 handler_vector->event_id = eid;
1176 vtbl = dispex_get_vtbl(&event_target->dispex);
1177 if(vtbl->bind_event)
1178 vtbl->bind_event(&event_target->dispex, eid);
1179 else
1180 FIXME("Unsupported event binding on target %p\n", event_target);
1182 wine_rb_put(&event_target->handler_map, (const void*)eid, &handler_vector->entry);
1183 return handler_vector;
1186 static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
1188 IDispatchEx *dispex;
1189 EXCEPINFO ei;
1190 HRESULT hres;
1192 memset(&ei, 0, sizeof(ei));
1194 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1195 if(SUCCEEDED(hres)) {
1196 hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, dp, retv, &ei, NULL);
1197 IDispatchEx_Release(dispex);
1198 }else {
1199 TRACE("Could not get IDispatchEx interface: %08x\n", hres);
1200 hres = IDispatch_Invoke(disp, 0, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD,
1201 dp, retv, &ei, NULL);
1204 return hres;
1207 static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, IHTMLEventObj *event_obj, VARIANT *retv)
1209 DISPPARAMS dp = {NULL,NULL,0,0};
1210 VARIANT event_arg;
1211 ULONG argerr;
1212 EXCEPINFO ei;
1214 if(event_obj) {
1215 V_VT(&event_arg) = VT_DISPATCH;
1216 V_DISPATCH(&event_arg) = (IDispatch*)event_obj;
1217 dp.rgvarg = &event_arg;
1218 dp.cArgs = 1;
1221 memset(&ei, 0, sizeof(ei));
1222 return IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, retv, &ei, &argerr);
1225 static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
1227 int min, max, i;
1228 HRESULT hres;
1230 if(!data)
1231 return FALSE;
1233 if(!data->ids) {
1234 hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
1235 if(FAILED(hres))
1236 return FALSE;
1239 min = 0;
1240 max = data->id_cnt-1;
1241 while(min <= max) {
1242 i = (min+max)/2;
1243 if(data->ids[i] == dispid)
1244 return TRUE;
1246 if(data->ids[i] < dispid)
1247 min = i+1;
1248 else
1249 max = i-1;
1252 return FALSE;
1255 static void call_event_handlers(EventTarget *event_target, DOMEvent *event)
1257 const eventid_t eid = event->event_id;
1258 handler_vector_t *handler_vector = get_handler_vector(event_target, eid, FALSE);
1259 const BOOL cancelable = event_info[eid].flags & EVENT_CANCELABLE;
1260 ConnectionPointContainer *cp_container = NULL;
1261 const event_target_vtbl_t *vtbl;
1262 VARIANT v;
1263 HRESULT hres;
1265 if(handler_vector && handler_vector->handler_prop) {
1266 DISPID named_arg = DISPID_THIS;
1267 VARIANTARG arg;
1268 DISPPARAMS dp = {&arg, &named_arg, 1, 1};
1270 if(!use_event_quirks(event_target))
1271 FIXME("Event argument not supported\n");
1273 V_VT(&arg) = VT_DISPATCH;
1274 V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
1275 V_VT(&v) = VT_EMPTY;
1277 TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
1278 hres = call_disp_func(handler_vector->handler_prop, &dp, &v);
1279 if(hres == S_OK) {
1280 TRACE("%s <<< %s\n", debugstr_w(event_info[eid].name), debugstr_variant(&v));
1282 if(cancelable) {
1283 if(V_VT(&v) == VT_BOOL) {
1284 if(!V_BOOL(&v))
1285 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1286 }else if(V_VT(&v) != VT_EMPTY) {
1287 FIXME("unhandled result %s\n", debugstr_variant(&v));
1290 VariantClear(&v);
1291 }else {
1292 WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
1296 if(handler_vector && handler_vector->handler_cnt) {
1297 VARIANTARG arg;
1298 DISPPARAMS dp = {&arg, NULL, 1, 0};
1299 int i;
1301 V_VT(&arg) = VT_DISPATCH;
1302 V_DISPATCH(&arg) = (IDispatch*)event->event_obj;
1304 i = handler_vector->handler_cnt;
1305 while(i--) {
1306 if(handler_vector->handlers[i]) {
1307 V_VT(&v) = VT_EMPTY;
1309 TRACE("%s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
1310 hres = call_disp_func(handler_vector->handlers[i], &dp, &v);
1311 if(hres == S_OK) {
1312 TRACE("%s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
1314 if(cancelable) {
1315 if(V_VT(&v) == VT_BOOL) {
1316 if(!V_BOOL(&v))
1317 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1318 }else if(V_VT(&v) != VT_EMPTY) {
1319 FIXME("unhandled result %s\n", debugstr_variant(&v));
1322 VariantClear(&v);
1323 }else {
1324 WARN("%s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
1330 if((vtbl = dispex_get_vtbl(&event_target->dispex)) && vtbl->get_cp_container)
1331 cp_container = vtbl->get_cp_container(&event_target->dispex);
1332 if(cp_container) {
1333 if(cp_container->cps) {
1334 ConnectionPoint *cp;
1335 unsigned i, j;
1337 for(j=0; cp_container->cp_entries[j].riid; j++) {
1338 cp = cp_container->cps + j;
1339 if(!cp->sinks_size || !is_cp_event(cp->data, event_info[eid].dispid))
1340 continue;
1342 for(i=0; i < cp->sinks_size; i++) {
1343 if(!cp->sinks[i].disp)
1344 continue;
1346 V_VT(&v) = VT_EMPTY;
1348 TRACE("cp %s [%u] >>>\n", debugstr_w(event_info[eid].name), i);
1349 hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid,
1350 cp->data->pass_event_arg ? event->event_obj : NULL, &v);
1351 if(hres == S_OK) {
1352 TRACE("cp %s [%u] <<<\n", debugstr_w(event_info[eid].name), i);
1354 if(cancelable) {
1355 if(V_VT(&v) == VT_BOOL) {
1356 if(!V_BOOL(&v))
1357 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1358 }else if(V_VT(&v) != VT_EMPTY) {
1359 FIXME("unhandled result %s\n", debugstr_variant(&v));
1362 VariantClear(&v);
1363 }else {
1364 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
1369 IConnectionPointContainer_Release(&cp_container->IConnectionPointContainer_iface);
1373 void dispatch_event(EventTarget *event_target, DOMEvent *event)
1375 EventTarget *target_chain_buf[8], **target_chain = target_chain_buf;
1376 unsigned chain_cnt, chain_buf_size, i;
1377 const event_target_vtbl_t *vtbl, *target_vtbl;
1378 HTMLEventObj *event_obj_ref = NULL;
1379 IHTMLEventObj *prev_event = NULL;
1380 EventTarget *iter;
1381 DWORD event_flags;
1382 HRESULT hres;
1384 if(event->event_id == EVENTID_LAST) {
1385 FIXME("Unsupported on unknown events\n");
1386 return;
1389 TRACE("(%p) %s\n", event_target, debugstr_w(event_info[event->event_id].name));
1391 event_flags = event_info[event->event_id].flags;
1392 iter = event_target;
1393 IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
1395 chain_cnt = 0;
1396 chain_buf_size = sizeof(target_chain_buf)/sizeof(*target_chain_buf);
1398 do {
1399 if(chain_cnt == chain_buf_size) {
1400 EventTarget **new_chain;
1401 if(target_chain == target_chain_buf) {
1402 new_chain = heap_alloc(chain_buf_size * 2 * sizeof(*new_chain));
1403 if(!new_chain)
1404 break;
1405 memcpy(new_chain, target_chain, chain_buf_size * sizeof(*new_chain));
1406 }else {
1407 new_chain = heap_realloc(target_chain, chain_buf_size * 2 * sizeof(*new_chain));
1408 if(!new_chain)
1409 break;
1411 chain_buf_size *= 2;
1412 target_chain = new_chain;
1415 target_chain[chain_cnt++] = iter;
1417 if(!(vtbl = dispex_get_vtbl(&iter->dispex)) || !vtbl->get_parent_event_target)
1418 break;
1419 iter = vtbl->get_parent_event_target(&iter->dispex);
1420 } while(iter);
1422 if(!event->event_obj && !event->no_event_obj) {
1423 event_obj_ref = alloc_event_obj(event);
1424 if(event_obj_ref) {
1425 event_obj_ref->type = event_info + event->event_id;
1426 event->event_obj = &event_obj_ref->IHTMLEventObj_iface;
1430 target_vtbl = dispex_get_vtbl(&event_target->dispex);
1431 if(target_vtbl && target_vtbl->set_current_event)
1432 prev_event = target_vtbl->set_current_event(&event_target->dispex, event->event_obj);
1434 event->target = event_target;
1435 IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
1437 for(i = 0; i < chain_cnt; i++) {
1438 call_event_handlers(target_chain[i], event);
1439 if(!(event_flags & EVENT_BUBBLES) || event->stop_propagation)
1440 break;
1443 if(target_vtbl && target_vtbl->set_current_event) {
1444 prev_event = target_vtbl->set_current_event(&event_target->dispex, prev_event);
1445 if(prev_event)
1446 IHTMLEventObj_Release(prev_event);
1449 if(event_flags & EVENT_HASDEFAULTHANDLERS) {
1450 for(i = 0; !event->prevent_default && i < chain_cnt; i++) {
1451 BOOL prevent_default = FALSE;
1452 vtbl = dispex_get_vtbl(&target_chain[i]->dispex);
1453 if(!vtbl || !vtbl->handle_event_default)
1454 continue;
1455 hres = vtbl->handle_event_default(&event_target->dispex, event->event_id,
1456 event->nsevent, &prevent_default);
1457 if(FAILED(hres) || event->stop_propagation)
1458 break;
1459 if(prevent_default)
1460 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1464 if(event_obj_ref) {
1465 event->event_obj = NULL;
1466 IHTMLEventObj_Release(&event_obj_ref->IHTMLEventObj_iface);
1469 for(i = 0; i < chain_cnt; i++)
1470 IDispatchEx_Release(&target_chain[i]->dispex.IDispatchEx_iface);
1471 if(target_chain != target_chain_buf)
1472 heap_free(target_chain);
1475 HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_var, VARIANT_BOOL *cancelled)
1477 HTMLEventObj *event_obj = NULL;
1478 eventid_t eid;
1479 HRESULT hres = S_OK;
1481 eid = attr_to_eid(event_name);
1482 if(eid == EVENTID_LAST) {
1483 WARN("unknown event %s\n", debugstr_w(event_name));
1484 return E_INVALIDARG;
1487 if(event_var && V_VT(event_var) != VT_EMPTY && V_VT(event_var) != VT_ERROR) {
1488 if(V_VT(event_var) != VT_DISPATCH) {
1489 FIXME("event_var %s not supported\n", debugstr_variant(event_var));
1490 return E_NOTIMPL;
1493 if(V_DISPATCH(event_var)) {
1494 IHTMLEventObj *event_iface;
1496 hres = IDispatch_QueryInterface(V_DISPATCH(event_var), &IID_IHTMLEventObj, (void**)&event_iface);
1497 if(FAILED(hres)) {
1498 FIXME("No IHTMLEventObj iface\n");
1499 return hres;
1502 event_obj = unsafe_impl_from_IHTMLEventObj(event_iface);
1503 if(!event_obj) {
1504 ERR("Not our IHTMLEventObj?\n");
1505 IHTMLEventObj_Release(event_iface);
1506 return E_FAIL;
1511 if(!event_obj) {
1512 event_obj = alloc_event_obj(NULL);
1513 if(!event_obj)
1514 return E_OUTOFMEMORY;
1517 event_obj->type = event_info + eid;
1518 if(!event_obj->event)
1519 hres = create_document_event(node->doc, eid, &event_obj->event);
1521 if(SUCCEEDED(hres)) {
1522 event_obj->event->event_obj = &event_obj->IHTMLEventObj_iface;
1523 dispatch_event(&node->event_target, event_obj->event);
1524 event_obj->event->event_obj = NULL;
1527 IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
1528 if(FAILED(hres))
1529 return hres;
1531 *cancelled = VARIANT_TRUE; /* FIXME */
1532 return S_OK;
1535 HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, eventid_t eid)
1537 nsIDOMNode *nsnode = NULL;
1539 TRACE("%s\n", debugstr_w(event_info[eid].name));
1541 if(!doc->nsdoc)
1542 return S_OK;
1544 switch(eid) {
1545 case EVENTID_FOCUSIN:
1546 doc->event_vector[eid] = TRUE;
1547 eid = EVENTID_FOCUS;
1548 break;
1549 case EVENTID_FOCUSOUT:
1550 doc->event_vector[eid] = TRUE;
1551 eid = EVENTID_BLUR;
1552 break;
1553 default:
1554 break;
1557 if(doc->event_vector[eid] || !(event_info[eid].flags & (EVENT_DEFAULTLISTENER|EVENT_BIND_TO_BODY)))
1558 return S_OK;
1560 if(event_info[eid].flags & EVENT_BIND_TO_BODY) {
1561 nsnode = doc->node.nsnode;
1562 nsIDOMNode_AddRef(nsnode);
1565 doc->event_vector[eid] = TRUE;
1566 add_nsevent_listener(doc, nsnode, event_info[eid].name);
1568 if(nsnode)
1569 nsIDOMNode_Release(nsnode);
1570 return S_OK;
1573 void detach_events(HTMLDocumentNode *doc)
1575 if(doc->event_vector) {
1576 int i;
1578 for(i=0; i < EVENTID_LAST; i++) {
1579 if(doc->event_vector[i]) {
1580 detach_nsevent(doc, event_info[i].name);
1581 doc->event_vector[i] = FALSE;
1586 release_nsevents(doc);
1589 static HRESULT get_event_dispex_ref(EventTarget *event_target, eventid_t eid, BOOL alloc, VARIANT **ret)
1591 WCHAR buf[64];
1592 buf[0] = 'o';
1593 buf[1] = 'n';
1594 strcpyW(buf+2, event_info[eid].name);
1595 return dispex_get_dprop_ref(&event_target->dispex, buf, alloc, ret);
1598 static void remove_event_handler(EventTarget *event_target, eventid_t eid)
1600 handler_vector_t *handler_vector;
1601 VARIANT *store;
1602 HRESULT hres;
1604 hres = get_event_dispex_ref(event_target, eid, FALSE, &store);
1605 if(SUCCEEDED(hres))
1606 VariantClear(store);
1608 handler_vector = get_handler_vector(event_target, eid, FALSE);
1609 if(handler_vector && handler_vector->handler_prop) {
1610 IDispatch_Release(handler_vector->handler_prop);
1611 handler_vector->handler_prop = NULL;
1615 static HRESULT set_event_handler_disp(EventTarget *event_target, eventid_t eid, IDispatch *disp)
1617 handler_vector_t *handler_vector;
1619 if(event_info[eid].flags & EVENT_FIXME)
1620 FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
1622 remove_event_handler(event_target, eid);
1623 if(!disp)
1624 return S_OK;
1626 handler_vector = get_handler_vector(event_target, eid, TRUE);
1627 if(!handler_vector)
1628 return E_OUTOFMEMORY;
1630 if(handler_vector->handler_prop)
1631 IDispatch_Release(handler_vector->handler_prop);
1633 handler_vector->handler_prop = disp;
1634 IDispatch_AddRef(disp);
1635 return S_OK;
1638 HRESULT set_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
1640 switch(V_VT(var)) {
1641 case VT_EMPTY:
1642 if(use_event_quirks(event_target)) {
1643 WARN("attempt to set to VT_EMPTY in quirks mode\n");
1644 return E_NOTIMPL;
1646 /* fall through */
1647 case VT_NULL:
1648 remove_event_handler(event_target, eid);
1649 return S_OK;
1651 case VT_DISPATCH:
1652 return set_event_handler_disp(event_target, eid, V_DISPATCH(var));
1654 case VT_BSTR: {
1655 VARIANT *v;
1656 HRESULT hres;
1658 if(!use_event_quirks(event_target))
1659 FIXME("Setting to string %s not supported\n", debugstr_w(V_BSTR(var)));
1662 * Setting event handler to string is a rare case and we don't want to
1663 * complicate nor increase memory of handler_vector_t for that. Instead,
1664 * we store the value in DispatchEx, which can already handle custom
1665 * properties.
1667 remove_event_handler(event_target, eid);
1669 hres = get_event_dispex_ref(event_target, eid, TRUE, &v);
1670 if(FAILED(hres))
1671 return hres;
1673 V_BSTR(v) = SysAllocString(V_BSTR(var));
1674 if(!V_BSTR(v))
1675 return E_OUTOFMEMORY;
1676 V_VT(v) = VT_BSTR;
1677 return S_OK;
1680 default:
1681 FIXME("not handler %s\n", debugstr_variant(var));
1682 return E_NOTIMPL;
1685 return S_OK;
1688 HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
1690 handler_vector_t *handler_vector;
1691 VARIANT *v;
1692 HRESULT hres;
1694 hres = get_event_dispex_ref(event_target, eid, FALSE, &v);
1695 if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY) {
1696 V_VT(var) = VT_EMPTY;
1697 return VariantCopy(var, v);
1700 handler_vector = get_handler_vector(event_target, eid, FALSE);
1701 if(handler_vector && handler_vector->handler_prop) {
1702 V_VT(var) = VT_DISPATCH;
1703 V_DISPATCH(var) = handler_vector->handler_prop;
1704 IDispatch_AddRef(V_DISPATCH(var));
1705 }else {
1706 V_VT(var) = VT_NULL;
1709 return S_OK;
1712 HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARIANT_BOOL *res)
1714 handler_vector_t *handler_vector;
1715 eventid_t eid;
1716 DWORD i = 0;
1718 eid = attr_to_eid(name);
1719 if(eid == EVENTID_LAST) {
1720 WARN("Unknown event\n");
1721 *res = VARIANT_TRUE;
1722 return S_OK;
1725 if(event_info[eid].flags & EVENT_FIXME)
1726 FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
1728 handler_vector = get_handler_vector(event_target, eid, TRUE);
1729 if(!handler_vector)
1730 return E_OUTOFMEMORY;
1732 while(i < handler_vector->handler_cnt && handler_vector->handlers[i])
1733 i++;
1734 if(i == handler_vector->handler_cnt) {
1735 if(i)
1736 handler_vector->handlers = heap_realloc_zero(handler_vector->handlers,
1737 (i + 1) * sizeof(*handler_vector->handlers));
1738 else
1739 handler_vector->handlers = heap_alloc_zero(sizeof(*handler_vector->handlers));
1740 if(!handler_vector->handlers)
1741 return E_OUTOFMEMORY;
1742 handler_vector->handler_cnt++;
1745 IDispatch_AddRef(disp);
1746 handler_vector->handlers[i] = disp;
1748 *res = VARIANT_TRUE;
1749 return S_OK;
1752 HRESULT detach_event(EventTarget *event_target, BSTR name, IDispatch *disp)
1754 handler_vector_t *handler_vector;
1755 eventid_t eid;
1756 unsigned i;
1758 eid = attr_to_eid(name);
1759 if(eid == EVENTID_LAST) {
1760 WARN("Unknown event\n");
1761 return S_OK;
1764 handler_vector = get_handler_vector(event_target, eid, FALSE);
1765 if(!handler_vector)
1766 return S_OK;
1768 for(i = 0; i < handler_vector->handler_cnt; i++) {
1769 if(handler_vector->handlers[i] == disp) {
1770 IDispatch_Release(handler_vector->handlers[i]);
1771 handler_vector->handlers[i] = NULL;
1775 return S_OK;
1778 void bind_target_event(HTMLDocumentNode *doc, EventTarget *event_target, const WCHAR *event, IDispatch *disp)
1780 eventid_t eid;
1782 TRACE("(%p %p %s %p)\n", doc, event_target, debugstr_w(event), disp);
1784 eid = attr_to_eid(event);
1785 if(eid == EVENTID_LAST) {
1786 WARN("Unsupported event %s\n", debugstr_w(event));
1787 return;
1790 set_event_handler_disp(event_target, eid, disp);
1793 void update_doc_cp_events(HTMLDocumentNode *doc, cp_static_data_t *cp)
1795 int i;
1797 for(i=0; i < EVENTID_LAST; i++) {
1798 if((event_info[i].flags & EVENT_DEFAULTLISTENER) && is_cp_event(cp, event_info[i].dispid))
1799 ensure_doc_nsevent_handler(doc, i);
1803 void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
1805 nsIDOMMozNamedAttrMap *attr_map;
1806 const PRUnichar *name, *value;
1807 nsAString name_str, value_str;
1808 HTMLDOMNode *node = NULL;
1809 cpp_bool has_attrs;
1810 nsIDOMAttr *attr;
1811 IDispatch *disp;
1812 UINT32 length, i;
1813 eventid_t eid;
1814 nsresult nsres;
1815 HRESULT hres;
1817 nsres = nsIDOMHTMLElement_HasAttributes(nselem, &has_attrs);
1818 if(NS_FAILED(nsres) || !has_attrs)
1819 return;
1821 nsres = nsIDOMHTMLElement_GetAttributes(nselem, &attr_map);
1822 if(NS_FAILED(nsres))
1823 return;
1825 nsres = nsIDOMMozNamedAttrMap_GetLength(attr_map, &length);
1826 assert(nsres == NS_OK);
1828 nsAString_Init(&name_str, NULL);
1829 nsAString_Init(&value_str, NULL);
1831 for(i = 0; i < length; i++) {
1832 nsres = nsIDOMMozNamedAttrMap_Item(attr_map, i, &attr);
1833 if(NS_FAILED(nsres))
1834 continue;
1836 nsres = nsIDOMAttr_GetName(attr, &name_str);
1837 if(NS_FAILED(nsres)) {
1838 nsIDOMAttr_Release(attr);
1839 continue;
1842 nsAString_GetData(&name_str, &name);
1843 eid = attr_to_eid(name);
1844 if(eid == EVENTID_LAST) {
1845 nsIDOMAttr_Release(attr);
1846 continue;
1849 nsres = nsIDOMAttr_GetValue(attr, &value_str);
1850 nsIDOMAttr_Release(attr);
1851 if(NS_FAILED(nsres))
1852 continue;
1854 nsAString_GetData(&value_str, &value);
1855 if(!*value)
1856 continue;
1858 TRACE("%p.%s = %s\n", nselem, debugstr_w(name), debugstr_w(value));
1860 disp = script_parse_event(doc->window, value);
1861 if(!disp)
1862 continue;
1864 if(!node) {
1865 hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
1866 if(FAILED(hres)) {
1867 IDispatch_Release(disp);
1868 break;
1872 set_event_handler_disp(get_node_event_prop_target(node, eid), eid, disp);
1873 IDispatch_Release(disp);
1876 if(node)
1877 node_release(node);
1878 nsAString_Finish(&name_str);
1879 nsAString_Finish(&value_str);
1880 nsIDOMMozNamedAttrMap_Release(attr_map);
1883 HRESULT doc_init_events(HTMLDocumentNode *doc)
1885 unsigned i;
1886 HRESULT hres;
1888 doc->event_vector = heap_alloc_zero(EVENTID_LAST*sizeof(BOOL));
1889 if(!doc->event_vector)
1890 return E_OUTOFMEMORY;
1892 init_nsevents(doc);
1894 for(i=0; i < EVENTID_LAST; i++) {
1895 if(event_info[i].flags & EVENT_HASDEFAULTHANDLERS) {
1896 hres = ensure_doc_nsevent_handler(doc, i);
1897 if(FAILED(hres))
1898 return hres;
1902 return S_OK;
1905 static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
1907 return CONTAINING_RECORD(iface, EventTarget, IEventTarget_iface);
1910 static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
1912 EventTarget *This = impl_from_IEventTarget(iface);
1913 return IDispatchEx_QueryInterface(&This->dispex.IDispatchEx_iface, riid, ppv);
1916 static ULONG WINAPI EventTarget_AddRef(IEventTarget *iface)
1918 EventTarget *This = impl_from_IEventTarget(iface);
1919 return IDispatchEx_AddRef(&This->dispex.IDispatchEx_iface);
1922 static ULONG WINAPI EventTarget_Release(IEventTarget *iface)
1924 EventTarget *This = impl_from_IEventTarget(iface);
1925 return IDispatchEx_Release(&This->dispex.IDispatchEx_iface);
1928 static HRESULT WINAPI EventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo)
1930 EventTarget *This = impl_from_IEventTarget(iface);
1931 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1934 static HRESULT WINAPI EventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo,
1935 LCID lcid, ITypeInfo **ppTInfo)
1937 EventTarget *This = impl_from_IEventTarget(iface);
1938 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1941 static HRESULT WINAPI EventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames,
1942 UINT cNames, LCID lcid, DISPID *rgDispId)
1944 EventTarget *This = impl_from_IEventTarget(iface);
1945 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid,
1946 rgszNames, cNames, lcid, rgDispId);
1949 static HRESULT WINAPI EventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember,
1950 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1951 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1953 EventTarget *This = impl_from_IEventTarget(iface);
1954 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember,
1955 riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1958 static HRESULT WINAPI EventTarget_addEventListener(IEventTarget *iface, BSTR type,
1959 IDispatch *listener, VARIANT_BOOL capture)
1961 EventTarget *This = impl_from_IEventTarget(iface);
1962 FIXME("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
1963 return E_NOTIMPL;
1966 static HRESULT WINAPI EventTarget_removeEventListener(IEventTarget *iface, BSTR type,
1967 IDispatch *listener, VARIANT_BOOL capture)
1969 EventTarget *This = impl_from_IEventTarget(iface);
1970 FIXME("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
1971 return E_NOTIMPL;
1974 static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event, VARIANT_BOOL *result)
1976 EventTarget *This = impl_from_IEventTarget(iface);
1977 FIXME("(%p)->(%p %p)\n", This, event, result);
1978 return E_NOTIMPL;
1981 static const IEventTargetVtbl EventTargetVtbl = {
1982 EventTarget_QueryInterface,
1983 EventTarget_AddRef,
1984 EventTarget_Release,
1985 EventTarget_GetTypeInfoCount,
1986 EventTarget_GetTypeInfo,
1987 EventTarget_GetIDsOfNames,
1988 EventTarget_Invoke,
1989 EventTarget_addEventListener,
1990 EventTarget_removeEventListener,
1991 EventTarget_dispatchEvent
1994 #define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
1996 static BOOL use_event_quirks(EventTarget *event_target)
1998 if(event_target->IEventTarget_iface.lpVtbl == DELAY_INIT_VTBL) {
1999 event_target->IEventTarget_iface.lpVtbl =
2000 dispex_compat_mode(&event_target->dispex) >= COMPAT_MODE_IE9
2001 ? &EventTargetVtbl : NULL;
2003 return !event_target->IEventTarget_iface.lpVtbl;
2006 HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
2008 if(IsEqualGUID(riid, &IID_IEventTarget)) {
2009 if(use_event_quirks(event_target)) {
2010 WARN("IEventTarget queried, but not supported by in document mode\n");
2011 *ppv = NULL;
2012 return E_NOINTERFACE;
2014 IEventTarget_AddRef(&event_target->IEventTarget_iface);
2015 *ppv = &event_target->IEventTarget_iface;
2016 return S_OK;
2019 if(dispex_query_interface(&event_target->dispex, riid, ppv))
2020 return *ppv ? S_OK : E_NOINTERFACE;
2022 WARN("(%p)->(%s %p)\n", event_target, debugstr_mshtml_guid(riid), ppv);
2023 *ppv = NULL;
2024 return E_NOINTERFACE;
2027 static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)
2029 return (INT_PTR)key - WINE_RB_ENTRY_VALUE(entry, handler_vector_t, entry)->event_id;
2032 void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_data_t *dispex_data,
2033 compat_mode_t compat_mode)
2035 init_dispex_with_compat_mode(&event_target->dispex, outer, dispex_data, compat_mode);
2036 wine_rb_init(&event_target->handler_map, event_id_cmp);
2039 * IEventTarget is supported by the object or not depending on compatibility mode.
2040 * We use NULL vtbl for objects in compatibility mode not supporting the interface.
2041 * For targets that don't know compatibility mode at creation time, we set vtbl
2042 * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
2043 * when it's needed.
2045 if(compat_mode == COMPAT_MODE_QUIRKS && dispex_data->vtbl && dispex_data->vtbl->get_compat_mode)
2046 event_target->IEventTarget_iface.lpVtbl = DELAY_INIT_VTBL;
2047 else if(compat_mode < COMPAT_MODE_IE9)
2048 event_target->IEventTarget_iface.lpVtbl = NULL;
2049 else
2050 event_target->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
2053 void release_event_target(EventTarget *event_target)
2055 handler_vector_t *iter, *iter2;
2056 unsigned i;
2058 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &event_target->handler_map, handler_vector_t, entry) {
2059 if(iter->handler_prop)
2060 IDispatch_Release(iter->handler_prop);
2061 for(i = 0; i < iter->handler_cnt; i++)
2062 if(iter->handlers[i])
2063 IDispatch_Release(iter->handlers[i]);
2064 heap_free(iter->handlers);
2065 heap_free(iter);