mshtml: Added IDOMUIEvent::initUIEvent implementation.
[wine.git] / dlls / mshtml / htmlevent.c
blobb788b2ed6f9e471c59cc0e9af6183e1e2e34b87f
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 enum {
39 LISTENER_TYPE_CAPTURE,
40 LISTENER_TYPE_BUBBLE,
41 LISTENER_TYPE_ONEVENT,
42 LISTENER_TYPE_ATTACHED
43 } listener_type_t;
45 typedef struct {
46 struct list entry;
47 listener_type_t type;
48 IDispatch *function;
49 } event_listener_t;
51 typedef struct {
52 struct wine_rb_entry entry;
53 struct list listeners;
54 WCHAR type[1];
55 } listener_container_t;
57 typedef enum {
58 DISPATCH_BOTH,
59 DISPATCH_STANDARD,
60 DISPATCH_LEGACY
61 } dispatch_mode_t;
63 static const WCHAR abortW[] = {'a','b','o','r','t',0};
64 static const WCHAR beforeactivateW[] = {'b','e','f','o','r','e','a','c','t','i','v','a','t','e',0};
65 static const WCHAR beforeunloadW[] = {'b','e','f','o','r','e','u','n','l','o','a','d',0};
66 static const WCHAR blurW[] = {'b','l','u','r',0};
67 static const WCHAR changeW[] = {'c','h','a','n','g','e',0};
68 static const WCHAR clickW[] = {'c','l','i','c','k',0};
69 static const WCHAR contextmenuW[] = {'c','o','n','t','e','x','t','m','e','n','u',0};
70 static const WCHAR dataavailableW[] = {'d','a','t','a','a','v','a','i','l','a','b','l','e',0};
71 static const WCHAR dblclickW[] = {'d','b','l','c','l','i','c','k',0};
72 static const WCHAR dragW[] = {'d','r','a','g',0};
73 static const WCHAR dragstartW[] = {'d','r','a','g','s','t','a','r','t',0};
74 static const WCHAR errorW[] = {'e','r','r','o','r',0};
75 static const WCHAR focusW[] = {'f','o','c','u','s',0};
76 static const WCHAR focusinW[] = {'f','o','c','u','s','i','n',0};
77 static const WCHAR focusoutW[] = {'f','o','c','u','s','o','u','t',0};
78 static const WCHAR helpW[] = {'h','e','l','p',0};
79 static const WCHAR keydownW[] = {'k','e','y','d','o','w','n',0};
80 static const WCHAR keypressW[] = {'k','e','y','p','r','e','s','s',0};
81 static const WCHAR keyupW[] = {'k','e','y','u','p',0};
82 static const WCHAR loadW[] = {'l','o','a','d',0};
83 static const WCHAR messageW[] = {'m','e','s','s','a','g','e',0};
84 static const WCHAR mousedownW[] = {'m','o','u','s','e','d','o','w','n',0};
85 static const WCHAR mousemoveW[] = {'m','o','u','s','e','m','o','v','e',0};
86 static const WCHAR mouseoutW[] = {'m','o','u','s','e','o','u','t',0};
87 static const WCHAR mouseoverW[] = {'m','o','u','s','e','o','v','e','r',0};
88 static const WCHAR mouseupW[] = {'m','o','u','s','e','u','p',0};
89 static const WCHAR mousewheelW[] = {'m','o','u','s','e','w','h','e','e','l',0};
90 static const WCHAR pasteW[] = {'p','a','s','t','e',0};
91 static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
92 static const WCHAR resizeW[] = {'r','e','s','i','z','e',0};
93 static const WCHAR scrollW[] = {'s','c','r','o','l','l',0};
94 static const WCHAR selectstartW[] = {'s','e','l','e','c','t','s','t','a','r','t',0};
95 static const WCHAR selectionchangeW[] = {'s','e','l','e','c','t','i','o','n','c','h','a','n','g','e',0};
96 static const WCHAR submitW[] = {'s','u','b','m','i','t',0};
97 static const WCHAR unloadW[] = {'u','n','l','o','a','d',0};
98 static const WCHAR DOMContentLoadedW[] = {'D','O','M','C','o','n','t','e','n','t','L','o','a','d','e','d',0};
100 static const WCHAR EventW[] = {'E','v','e','n','t',0};
101 static const WCHAR UIEventW[] = {'U','I','E','v','e','n','t',0};
102 static const WCHAR KeyboardEventW[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
103 static const WCHAR MouseEventW[] = {'M','o','u','s','e','E','v','e','n','t',0};
105 typedef enum {
106 EVENT_TYPE_EVENT,
107 EVENT_TYPE_UIEVENT,
108 EVENT_TYPE_KEYBOARD,
109 EVENT_TYPE_MOUSE,
110 EVENT_TYPE_FOCUS,
111 EVENT_TYPE_DRAG,
112 EVENT_TYPE_MESSAGE,
113 EVENT_TYPE_CLIPBOARD
114 } event_type_t;
116 static const WCHAR *event_types[] = {
117 EventW,
118 UIEventW,
119 KeyboardEventW,
120 MouseEventW,
121 EventW, /* FIXME */
122 EventW, /* FIXME */
123 EventW, /* FIXME */
124 EventW /* FIXME */
127 typedef struct {
128 const WCHAR *name;
129 event_type_t type;
130 DISPID dispid;
131 DWORD flags;
132 } event_info_t;
134 #define EVENT_DEFAULTLISTENER 0x0001
135 #define EVENT_BUBBLES 0x0002
136 #define EVENT_BIND_TO_BODY 0x0008
137 #define EVENT_CANCELABLE 0x0010
138 #define EVENT_HASDEFAULTHANDLERS 0x0020
139 #define EVENT_FIXME 0x0040
141 static const event_info_t event_info[] = {
142 {abortW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONABORT,
143 EVENT_BIND_TO_BODY},
144 {beforeactivateW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONBEFOREACTIVATE,
145 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
146 {beforeunloadW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONBEFOREUNLOAD,
147 EVENT_DEFAULTLISTENER | EVENT_CANCELABLE },
148 {blurW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONBLUR,
149 EVENT_DEFAULTLISTENER},
150 {changeW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONCHANGE,
151 EVENT_DEFAULTLISTENER | EVENT_BUBBLES},
152 {clickW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONCLICK,
153 EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE },
154 {contextmenuW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONCONTEXTMENU,
155 EVENT_BUBBLES | EVENT_CANCELABLE},
156 {dataavailableW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONDATAAVAILABLE,
157 EVENT_FIXME | EVENT_BUBBLES},
158 {dblclickW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONDBLCLICK,
159 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
160 {DOMContentLoadedW, EVENT_TYPE_EVENT, 0,
161 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
162 {dragW, EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAG,
163 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
164 {dragstartW, EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAGSTART,
165 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
166 {errorW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONERROR,
167 EVENT_BIND_TO_BODY},
168 {focusW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUS,
169 EVENT_DEFAULTLISTENER},
170 {focusinW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUSIN,
171 EVENT_BUBBLES},
172 {focusoutW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUSOUT,
173 EVENT_BUBBLES},
174 {helpW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONHELP,
175 EVENT_BUBBLES | EVENT_CANCELABLE},
176 {keydownW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYDOWN,
177 EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE },
178 {keypressW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYPRESS,
179 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
180 {keyupW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYUP,
181 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
182 {loadW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONLOAD,
183 EVENT_BIND_TO_BODY},
184 {messageW, EVENT_TYPE_MESSAGE, DISPID_EVMETH_ONMESSAGE,
186 {mousedownW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
187 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
188 {mousemoveW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEMOVE,
189 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
190 {mouseoutW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEOUT,
191 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
192 {mouseoverW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEOVER,
193 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
194 {mouseupW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEUP,
195 EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
196 {mousewheelW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEWHEEL,
197 EVENT_FIXME},
198 {pasteW, EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE,
199 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
200 {readystatechangeW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONREADYSTATECHANGE,
202 {resizeW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONRESIZE,
203 EVENT_DEFAULTLISTENER},
204 {scrollW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONSCROLL,
205 EVENT_DEFAULTLISTENER | EVENT_BUBBLES /* FIXME: not for elements */},
206 {selectionchangeW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONSELECTIONCHANGE,
207 EVENT_FIXME},
208 {selectstartW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONSELECTSTART,
209 EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
210 {submitW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONSUBMIT,
211 EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE},
212 {unloadW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD,
213 EVENT_FIXME}
216 static BOOL use_event_quirks(EventTarget*);
218 static eventid_t str_to_eid(const WCHAR *str)
220 int i;
222 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
223 if(!strcmpW(event_info[i].name, str))
224 return i;
227 return EVENTID_LAST;
230 static eventid_t attr_to_eid(const WCHAR *str)
232 int i;
234 if((str[0] != 'o' && str[0] != 'O') || (str[1] != 'n' && str[1] != 'N'))
235 return EVENTID_LAST;
237 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
238 if(!strcmpW(event_info[i].name, str+2) && event_info[i].dispid)
239 return i;
242 return EVENTID_LAST;
245 static listener_container_t *get_listener_container(EventTarget *event_target, const WCHAR *type, BOOL alloc)
247 const event_target_vtbl_t *vtbl;
248 listener_container_t *container;
249 struct wine_rb_entry *entry;
250 size_t type_len;
251 eventid_t eid;
253 entry = wine_rb_get(&event_target->handler_map, type);
254 if(entry)
255 return WINE_RB_ENTRY_VALUE(entry, listener_container_t, entry);
256 if(!alloc)
257 return NULL;
259 eid = str_to_eid(type);
260 if(eid != EVENTID_LAST && (event_info[eid].flags & EVENT_FIXME))
261 FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
263 type_len = strlenW(type);
264 container = heap_alloc(FIELD_OFFSET(listener_container_t, type[type_len+1]));
265 if(!container)
266 return NULL;
267 memcpy(container->type, type, (type_len + 1) * sizeof(WCHAR));
268 list_init(&container->listeners);
269 vtbl = dispex_get_vtbl(&event_target->dispex);
270 if(vtbl->bind_event)
271 vtbl->bind_event(&event_target->dispex, eid);
272 else
273 FIXME("Unsupported event binding on target %p\n", event_target);
275 wine_rb_put(&event_target->handler_map, container->type, &container->entry);
276 return container;
279 static void remove_event_listener(EventTarget *event_target, const WCHAR *type_name, listener_type_t type, IDispatch *function)
281 listener_container_t *container;
282 event_listener_t *listener;
284 container = get_listener_container(event_target, type_name, FALSE);
285 if(!container)
286 return;
288 LIST_FOR_EACH_ENTRY(listener, &container->listeners, event_listener_t, entry) {
289 if(listener->function == function && listener->type == type) {
290 IDispatch_Release(listener->function);
291 list_remove(&listener->entry);
292 heap_free(listener);
293 break;
298 typedef struct {
299 DispatchEx dispex;
300 IHTMLEventObj IHTMLEventObj_iface;
302 LONG ref;
304 DOMEvent *event;
305 VARIANT return_value;
306 } HTMLEventObj;
308 static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface)
310 return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj_iface);
313 static HRESULT WINAPI HTMLEventObj_QueryInterface(IHTMLEventObj *iface, REFIID riid, void **ppv)
315 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
317 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
319 if(IsEqualGUID(&IID_IUnknown, riid)) {
320 *ppv = &This->IHTMLEventObj_iface;
321 }else if(IsEqualGUID(&IID_IHTMLEventObj, riid)) {
322 *ppv = &This->IHTMLEventObj_iface;
323 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
324 return *ppv ? S_OK : E_NOINTERFACE;
325 }else {
326 *ppv = NULL;
327 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
328 return E_NOINTERFACE;
331 IUnknown_AddRef((IUnknown*)*ppv);
332 return S_OK;
335 static ULONG WINAPI HTMLEventObj_AddRef(IHTMLEventObj *iface)
337 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
338 LONG ref = InterlockedIncrement(&This->ref);
340 TRACE("(%p) ref=%d\n", This, ref);
342 return ref;
345 static ULONG WINAPI HTMLEventObj_Release(IHTMLEventObj *iface)
347 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
348 LONG ref = InterlockedDecrement(&This->ref);
350 TRACE("(%p) ref=%d\n", This, ref);
352 if(!ref) {
353 if(This->event)
354 IDOMEvent_Release(&This->event->IDOMEvent_iface);
355 release_dispex(&This->dispex);
356 heap_free(This);
359 return ref;
362 static HRESULT WINAPI HTMLEventObj_GetTypeInfoCount(IHTMLEventObj *iface, UINT *pctinfo)
364 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
365 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
368 static HRESULT WINAPI HTMLEventObj_GetTypeInfo(IHTMLEventObj *iface, UINT iTInfo,
369 LCID lcid, ITypeInfo **ppTInfo)
371 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
372 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
375 static HRESULT WINAPI HTMLEventObj_GetIDsOfNames(IHTMLEventObj *iface, REFIID riid,
376 LPOLESTR *rgszNames, UINT cNames,
377 LCID lcid, DISPID *rgDispId)
379 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
380 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
381 lcid, rgDispId);
384 static HRESULT WINAPI HTMLEventObj_Invoke(IHTMLEventObj *iface, DISPID dispIdMember,
385 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
386 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
388 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
389 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
390 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
393 static HRESULT WINAPI HTMLEventObj_get_srcElement(IHTMLEventObj *iface, IHTMLElement **p)
395 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
397 TRACE("(%p)->(%p)\n", This, p);
399 if(!This->event) {
400 *p = NULL;
401 return S_OK;
404 return IDOMEvent_get_srcElement(&This->event->IDOMEvent_iface, p);
407 static HRESULT WINAPI HTMLEventObj_get_altKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
409 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
410 cpp_bool ret = FALSE;
412 TRACE("(%p)->(%p)\n", This, p);
414 if(This->event && This->event->mouse_event)
415 return IDOMMouseEvent_get_altKey(&This->event->IDOMMouseEvent_iface, p);
417 if(This->event) {
418 nsIDOMKeyEvent *key_event;
419 nsresult nsres;
421 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
422 if(NS_SUCCEEDED(nsres)) {
423 nsIDOMKeyEvent_GetAltKey(key_event, &ret);
424 nsIDOMKeyEvent_Release(key_event);
428 *p = variant_bool(ret);
429 return S_OK;
432 static HRESULT WINAPI HTMLEventObj_get_ctrlKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
434 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
435 cpp_bool ret = FALSE;
437 TRACE("(%p)->(%p)\n", This, p);
439 if(This->event && This->event->mouse_event)
440 return IDOMMouseEvent_get_ctrlKey(&This->event->IDOMMouseEvent_iface, p);
442 if(This->event) {
443 nsIDOMKeyEvent *key_event;
444 nsresult nsres;
446 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
447 if(NS_SUCCEEDED(nsres)) {
448 nsIDOMKeyEvent_GetCtrlKey(key_event, &ret);
449 nsIDOMKeyEvent_Release(key_event);
453 *p = variant_bool(ret);
454 return S_OK;
457 static HRESULT WINAPI HTMLEventObj_get_shiftKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
459 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
460 cpp_bool ret = FALSE;
462 TRACE("(%p)->(%p)\n", This, p);
464 if(This->event && This->event->mouse_event)
465 return IDOMMouseEvent_get_shiftKey(&This->event->IDOMMouseEvent_iface, p);
467 if(This->event) {
468 nsIDOMKeyEvent *key_event;
469 nsresult nsres;
471 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
472 if(NS_SUCCEEDED(nsres)) {
473 nsIDOMKeyEvent_GetShiftKey(key_event, &ret);
474 nsIDOMKeyEvent_Release(key_event);
478 *p = variant_bool(ret);
479 return S_OK;
482 static HRESULT WINAPI HTMLEventObj_put_returnValue(IHTMLEventObj *iface, VARIANT v)
484 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
486 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
488 if(V_VT(&v) != VT_BOOL) {
489 FIXME("unsupported value %s\n", debugstr_variant(&v));
490 return DISP_E_BADVARTYPE;
493 This->return_value = v;
494 if(!V_BOOL(&v) && This->event)
495 IDOMEvent_preventDefault(&This->event->IDOMEvent_iface);
496 return S_OK;
499 static HRESULT WINAPI HTMLEventObj_get_returnValue(IHTMLEventObj *iface, VARIANT *p)
501 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
503 TRACE("(%p)->(%p)\n", This, p);
505 V_VT(p) = VT_EMPTY;
506 return VariantCopy(p, &This->return_value);
509 static HRESULT WINAPI HTMLEventObj_put_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL v)
511 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
513 TRACE("(%p)->(%x)\n", This, v);
515 if(This->event)
516 IDOMEvent_stopPropagation(&This->event->IDOMEvent_iface);
517 return S_OK;
520 static HRESULT WINAPI HTMLEventObj_get_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL *p)
522 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
524 TRACE("(%p)->(%p)\n", This, p);
526 *p = variant_bool(This->event && This->event->stop_propagation);
527 return S_OK;
530 static HRESULT WINAPI HTMLEventObj_get_fromElement(IHTMLEventObj *iface, IHTMLElement **p)
532 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
534 FIXME("(%p)->(%p)\n", This, p);
536 *p = NULL;
537 return S_OK;
540 static HRESULT WINAPI HTMLEventObj_get_toElement(IHTMLEventObj *iface, IHTMLElement **p)
542 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
544 FIXME("(%p)->(%p)\n", This, p);
546 *p = NULL;
547 return S_OK;
550 static HRESULT WINAPI HTMLEventObj_put_keyCode(IHTMLEventObj *iface, LONG v)
552 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
553 FIXME("(%p)->(%d)\n", This, v);
554 return E_NOTIMPL;
557 static HRESULT WINAPI HTMLEventObj_get_keyCode(IHTMLEventObj *iface, LONG *p)
559 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
560 UINT32 key_code = 0;
562 TRACE("(%p)->(%p)\n", This, p);
564 if(This->event) {
565 nsIDOMKeyEvent *key_event;
566 nsresult nsres;
568 nsres = nsIDOMEvent_QueryInterface(This->event->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
569 if(NS_SUCCEEDED(nsres)) {
570 nsIDOMKeyEvent_GetKeyCode(key_event, &key_code);
571 nsIDOMKeyEvent_Release(key_event);
575 *p = key_code;
576 return S_OK;
579 static HRESULT WINAPI HTMLEventObj_get_button(IHTMLEventObj *iface, LONG *p)
581 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
582 USHORT button = 0;
584 TRACE("(%p)->(%p)\n", This, p);
586 if(This->event && This->event->mouse_event) {
587 HRESULT hres;
588 hres = IDOMMouseEvent_get_button(&This->event->IDOMMouseEvent_iface, &button);
589 if(FAILED(hres))
590 return hres;
593 *p = button;
594 return S_OK;
597 static HRESULT WINAPI HTMLEventObj_get_type(IHTMLEventObj *iface, BSTR *p)
599 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
601 TRACE("(%p)->(%p)\n", This, p);
603 if(!This->event) {
604 *p = NULL;
605 return S_OK;
608 return IDOMEvent_get_type(&This->event->IDOMEvent_iface, p);
611 static HRESULT WINAPI HTMLEventObj_get_qualifier(IHTMLEventObj *iface, BSTR *p)
613 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
615 FIXME("(%p)->(%p)\n", This, p);
617 *p = NULL;
618 return S_OK;
621 static HRESULT WINAPI HTMLEventObj_get_reason(IHTMLEventObj *iface, LONG *p)
623 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
625 FIXME("(%p)->(%p)\n", This, p);
627 *p = 0;
628 return S_OK;
631 static HRESULT WINAPI HTMLEventObj_get_x(IHTMLEventObj *iface, LONG *p)
633 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
634 LONG x = 0;
636 TRACE("(%p)->(%p)\n", This, p);
638 if(This->event && This->event->ui_event) {
639 nsresult nsres;
641 /* NOTE: pageX is not exactly right here. */
642 nsres = nsIDOMUIEvent_GetPageX(This->event->ui_event, &x);
643 assert(nsres == NS_OK);
646 *p = x;
647 return S_OK;
650 static HRESULT WINAPI HTMLEventObj_get_y(IHTMLEventObj *iface, LONG *p)
652 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
653 LONG y = 0;
655 TRACE("(%p)->(%p)\n", This, p);
657 if(This->event && This->event->ui_event) {
658 nsresult nsres;
660 /* NOTE: pageY is not exactly right here. */
661 nsres = nsIDOMUIEvent_GetPageY(This->event->ui_event, &y);
662 assert(nsres == NS_OK);
665 *p = y;
666 return S_OK;
669 static HRESULT WINAPI HTMLEventObj_get_clientX(IHTMLEventObj *iface, LONG *p)
671 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
673 TRACE("(%p)->(%p)\n", This, p);
675 if(This->event && This->event->mouse_event)
676 return IDOMMouseEvent_get_clientX(&This->event->IDOMMouseEvent_iface, p);
678 *p = 0;
679 return S_OK;
682 static HRESULT WINAPI HTMLEventObj_get_clientY(IHTMLEventObj *iface, LONG *p)
684 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
686 TRACE("(%p)->(%p)\n", This, p);
688 if(This->event && This->event->mouse_event)
689 return IDOMMouseEvent_get_clientY(&This->event->IDOMMouseEvent_iface, p);
691 *p = 0;
692 return S_OK;
695 static HRESULT WINAPI HTMLEventObj_get_offsetX(IHTMLEventObj *iface, LONG *p)
697 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
699 FIXME("(%p)->(%p)\n", This, p);
701 *p = 0;
702 return S_OK;
705 static HRESULT WINAPI HTMLEventObj_get_offsetY(IHTMLEventObj *iface, LONG *p)
707 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
709 FIXME("(%p)->(%p)\n", This, p);
711 *p = 0;
712 return S_OK;
715 static HRESULT WINAPI HTMLEventObj_get_screenX(IHTMLEventObj *iface, LONG *p)
717 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
719 TRACE("(%p)->(%p)\n", This, p);
721 if(This->event && This->event->mouse_event)
722 return IDOMMouseEvent_get_screenX(&This->event->IDOMMouseEvent_iface, p);
724 *p = 0;
725 return S_OK;
728 static HRESULT WINAPI HTMLEventObj_get_screenY(IHTMLEventObj *iface, LONG *p)
730 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
732 TRACE("(%p)->(%p)\n", This, p);
734 if(This->event && This->event->mouse_event)
735 return IDOMMouseEvent_get_screenY(&This->event->IDOMMouseEvent_iface, p);
737 *p = 0;
738 return S_OK;
741 static HRESULT WINAPI HTMLEventObj_get_srcFilter(IHTMLEventObj *iface, IDispatch **p)
743 HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
745 FIXME("(%p)->(%p)\n", This, p);
747 *p = NULL;
748 return S_OK;
751 static const IHTMLEventObjVtbl HTMLEventObjVtbl = {
752 HTMLEventObj_QueryInterface,
753 HTMLEventObj_AddRef,
754 HTMLEventObj_Release,
755 HTMLEventObj_GetTypeInfoCount,
756 HTMLEventObj_GetTypeInfo,
757 HTMLEventObj_GetIDsOfNames,
758 HTMLEventObj_Invoke,
759 HTMLEventObj_get_srcElement,
760 HTMLEventObj_get_altKey,
761 HTMLEventObj_get_ctrlKey,
762 HTMLEventObj_get_shiftKey,
763 HTMLEventObj_put_returnValue,
764 HTMLEventObj_get_returnValue,
765 HTMLEventObj_put_cancelBubble,
766 HTMLEventObj_get_cancelBubble,
767 HTMLEventObj_get_fromElement,
768 HTMLEventObj_get_toElement,
769 HTMLEventObj_put_keyCode,
770 HTMLEventObj_get_keyCode,
771 HTMLEventObj_get_button,
772 HTMLEventObj_get_type,
773 HTMLEventObj_get_qualifier,
774 HTMLEventObj_get_reason,
775 HTMLEventObj_get_x,
776 HTMLEventObj_get_y,
777 HTMLEventObj_get_clientX,
778 HTMLEventObj_get_clientY,
779 HTMLEventObj_get_offsetX,
780 HTMLEventObj_get_offsetY,
781 HTMLEventObj_get_screenX,
782 HTMLEventObj_get_screenY,
783 HTMLEventObj_get_srcFilter
786 static inline HTMLEventObj *unsafe_impl_from_IHTMLEventObj(IHTMLEventObj *iface)
788 return iface->lpVtbl == &HTMLEventObjVtbl ? impl_from_IHTMLEventObj(iface) : NULL;
791 static const tid_t HTMLEventObj_iface_tids[] = {
792 IHTMLEventObj_tid,
796 static dispex_static_data_t HTMLEventObj_dispex = {
797 NULL,
798 DispCEventObj_tid,
799 HTMLEventObj_iface_tids
802 static HTMLEventObj *alloc_event_obj(DOMEvent *event)
804 HTMLEventObj *event_obj;
806 event_obj = heap_alloc_zero(sizeof(*event_obj));
807 if(!event_obj)
808 return NULL;
810 event_obj->IHTMLEventObj_iface.lpVtbl = &HTMLEventObjVtbl;
811 event_obj->ref = 1;
812 event_obj->event = event;
813 if(event)
814 IDOMEvent_AddRef(&event->IDOMEvent_iface);
816 init_dispex(&event_obj->dispex, (IUnknown*)&event_obj->IHTMLEventObj_iface, &HTMLEventObj_dispex);
817 return event_obj;
820 HRESULT create_event_obj(IHTMLEventObj **ret)
822 HTMLEventObj *event_obj;
824 event_obj = alloc_event_obj(NULL);
825 if(!event_obj)
826 return E_OUTOFMEMORY;
828 *ret = &event_obj->IHTMLEventObj_iface;
829 return S_OK;
832 static inline DOMEvent *impl_from_IDOMEvent(IDOMEvent *iface)
834 return CONTAINING_RECORD(iface, DOMEvent, IDOMEvent_iface);
837 static const IDOMEventVtbl DOMEventVtbl;
839 static inline DOMEvent *unsafe_impl_from_IDOMEvent(IDOMEvent *iface)
841 return iface && iface->lpVtbl == &DOMEventVtbl ? impl_from_IDOMEvent(iface) : NULL;
844 static HRESULT WINAPI DOMEvent_QueryInterface(IDOMEvent *iface, REFIID riid, void **ppv)
846 DOMEvent *This = impl_from_IDOMEvent(iface);
848 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
850 if(IsEqualGUID(&IID_IUnknown, riid))
851 *ppv = &This->IDOMEvent_iface;
852 else if(IsEqualGUID(&IID_IDOMEvent, riid))
853 *ppv = &This->IDOMEvent_iface;
854 else if(This->ui_event && IsEqualGUID(&IID_IDOMUIEvent, riid))
855 *ppv = &This->IDOMUIEvent_iface;
856 else if(This->mouse_event && IsEqualGUID(&IID_IDOMMouseEvent, riid))
857 *ppv = &This->IDOMMouseEvent_iface;
858 else if(dispex_query_interface(&This->dispex, riid, ppv))
859 return *ppv ? S_OK : E_NOINTERFACE;
860 else {
861 *ppv = NULL;
862 WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
863 return E_NOINTERFACE;
866 IUnknown_AddRef((IUnknown*)*ppv);
867 return S_OK;
870 static ULONG WINAPI DOMEvent_AddRef(IDOMEvent *iface)
872 DOMEvent *This = impl_from_IDOMEvent(iface);
873 LONG ref = InterlockedIncrement(&This->ref);
875 TRACE("(%p) ref=%u\n", This, ref);
877 return ref;
880 static ULONG WINAPI DOMEvent_Release(IDOMEvent *iface)
882 DOMEvent *This = impl_from_IDOMEvent(iface);
883 LONG ref = InterlockedDecrement(&This->ref);
885 TRACE("(%p) ref=%u\n", This, ref);
887 if(!ref) {
888 if(This->ui_event)
889 nsIDOMUIEvent_Release(This->ui_event);
890 if(This->mouse_event)
891 nsIDOMMouseEvent_Release(This->mouse_event);
892 if(This->target)
893 IDispatchEx_Release(&This->target->dispex.IDispatchEx_iface);
894 nsIDOMEvent_Release(This->nsevent);
895 release_dispex(&This->dispex);
896 heap_free(This->type);
897 heap_free(This);
900 return ref;
903 static HRESULT WINAPI DOMEvent_GetTypeInfoCount(IDOMEvent *iface, UINT *pctinfo)
905 DOMEvent *This = impl_from_IDOMEvent(iface);
906 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
909 static HRESULT WINAPI DOMEvent_GetTypeInfo(IDOMEvent *iface, UINT iTInfo,
910 LCID lcid, ITypeInfo **ppTInfo)
912 DOMEvent *This = impl_from_IDOMEvent(iface);
913 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
916 static HRESULT WINAPI DOMEvent_GetIDsOfNames(IDOMEvent *iface, REFIID riid,
917 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
919 DOMEvent *This = impl_from_IDOMEvent(iface);
920 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
921 lcid, rgDispId);
924 static HRESULT WINAPI DOMEvent_Invoke(IDOMEvent *iface, DISPID dispIdMember,
925 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
926 EXCEPINFO *pExcepInfo, UINT *puArgErr)
928 DOMEvent *This = impl_from_IDOMEvent(iface);
929 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
930 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
933 static HRESULT WINAPI DOMEvent_get_bubbles(IDOMEvent *iface, VARIANT_BOOL *p)
935 DOMEvent *This = impl_from_IDOMEvent(iface);
937 TRACE("(%p)->(%p)\n", This, p);
939 *p = variant_bool(This->bubbles);
940 return S_OK;
943 static HRESULT WINAPI DOMEvent_get_cancelable(IDOMEvent *iface, VARIANT_BOOL *p)
945 DOMEvent *This = impl_from_IDOMEvent(iface);
947 TRACE("(%p)->(%p)\n", This, p);
949 *p = variant_bool(This->cancelable);
950 return S_OK;
953 static HRESULT WINAPI DOMEvent_get_currentTarget(IDOMEvent *iface, IEventTarget **p)
955 DOMEvent *This = impl_from_IDOMEvent(iface);
957 TRACE("(%p)->(%p)\n", This, p);
959 if(This->current_target)
960 IEventTarget_AddRef(*p = &This->current_target->IEventTarget_iface);
961 else
962 *p = NULL;
963 return S_OK;
966 static HRESULT WINAPI DOMEvent_get_defaultPrevented(IDOMEvent *iface, VARIANT_BOOL *p)
968 DOMEvent *This = impl_from_IDOMEvent(iface);
970 TRACE("(%p)->(%p)\n", This, p);
972 *p = variant_bool(This->prevent_default);
973 return S_OK;
976 static HRESULT WINAPI DOMEvent_get_eventPhase(IDOMEvent *iface, USHORT *p)
978 DOMEvent *This = impl_from_IDOMEvent(iface);
980 TRACE("(%p)->(%p)\n", This, p);
982 *p = This->phase;
983 return S_OK;
986 static HRESULT WINAPI DOMEvent_get_target(IDOMEvent *iface, IEventTarget **p)
988 DOMEvent *This = impl_from_IDOMEvent(iface);
990 TRACE("(%p)->(%p)\n", This, p);
992 if(This->target)
993 IEventTarget_AddRef(*p = &This->target->IEventTarget_iface);
994 else
995 *p = NULL;
996 return S_OK;
999 static HRESULT WINAPI DOMEvent_get_timeStamp(IDOMEvent *iface, ULONGLONG *p)
1001 DOMEvent *This = impl_from_IDOMEvent(iface);
1003 TRACE("(%p)->(%p)\n", This, p);
1005 *p = This->time_stamp;
1006 return S_OK;
1009 static HRESULT WINAPI DOMEvent_get_type(IDOMEvent *iface, BSTR *p)
1011 DOMEvent *This = impl_from_IDOMEvent(iface);
1013 TRACE("(%p)->(%p)\n", This, p);
1015 if(This->type) {
1016 *p = SysAllocString(This->type);
1017 if(!*p)
1018 return E_OUTOFMEMORY;
1019 }else {
1020 *p = NULL;
1022 return S_OK;
1025 #ifdef __i386__
1026 #define nsIDOMEvent_InitEvent(_this,type,bubbles,cancelable) \
1027 ((void (WINAPI*)(void*,nsIDOMEvent*,const nsAString*,cpp_bool,cpp_bool)) \
1028 &call_thiscall_func)((_this)->lpVtbl->InitEvent,_this,type,bubbles,cancelable)
1030 #endif
1032 static HRESULT WINAPI DOMEvent_initEvent(IDOMEvent *iface, BSTR type, VARIANT_BOOL can_bubble, VARIANT_BOOL cancelable)
1034 DOMEvent *This = impl_from_IDOMEvent(iface);
1035 nsAString nsstr;
1037 TRACE("(%p)->(%s %x %x)\n", This, debugstr_w(type), can_bubble, cancelable);
1039 if(This->target) {
1040 TRACE("called on already dispatched event\n");
1041 return S_OK;
1044 heap_free(This->type);
1045 This->type = heap_strdupW(type);
1046 if(!This->type)
1047 return E_OUTOFMEMORY;
1048 This->event_id = str_to_eid(type);
1050 This->bubbles = !!can_bubble;
1051 This->cancelable = !!cancelable;
1053 nsAString_InitDepend(&nsstr, type);
1054 nsIDOMEvent_InitEvent(This->nsevent, &nsstr, This->bubbles, This->cancelable);
1055 nsAString_Finish(&nsstr);
1057 return S_OK;
1060 static HRESULT WINAPI DOMEvent_preventDefault(IDOMEvent *iface)
1062 DOMEvent *This = impl_from_IDOMEvent(iface);
1064 TRACE("(%p)\n", This);
1066 if(This->current_target && This->cancelable) {
1067 This->prevent_default = TRUE;
1068 nsIDOMEvent_PreventDefault(This->nsevent);
1070 return S_OK;
1073 static HRESULT WINAPI DOMEvent_stopPropagation(IDOMEvent *iface)
1075 DOMEvent *This = impl_from_IDOMEvent(iface);
1077 TRACE("(%p)\n", This);
1079 This->stop_propagation = TRUE;
1080 nsIDOMEvent_StopPropagation(This->nsevent);
1081 return S_OK;
1084 static HRESULT WINAPI DOMEvent_stopImmediatePropagation(IDOMEvent *iface)
1086 DOMEvent *This = impl_from_IDOMEvent(iface);
1087 FIXME("(%p)\n", This);
1088 return E_NOTIMPL;
1091 static HRESULT WINAPI DOMEvent_get_isTrusted(IDOMEvent *iface, VARIANT_BOOL *p)
1093 DOMEvent *This = impl_from_IDOMEvent(iface);
1094 FIXME("(%p)->(%p)\n", This, p);
1095 return E_NOTIMPL;
1098 static HRESULT WINAPI DOMEvent_put_cancelBubble(IDOMEvent *iface, VARIANT_BOOL v)
1100 DOMEvent *This = impl_from_IDOMEvent(iface);
1101 FIXME("(%p)->(%x)\n", This, v);
1102 return E_NOTIMPL;
1105 static HRESULT WINAPI DOMEvent_get_cancelBubble(IDOMEvent *iface, VARIANT_BOOL *p)
1107 DOMEvent *This = impl_from_IDOMEvent(iface);
1108 FIXME("(%p)->(%p)\n", This, p);
1109 return E_NOTIMPL;
1112 static HRESULT WINAPI DOMEvent_get_srcElement(IDOMEvent *iface, IHTMLElement **p)
1114 DOMEvent *This = impl_from_IDOMEvent(iface);
1116 TRACE("(%p)->(%p)\n", This, p);
1118 if(This->target)
1119 IDispatchEx_QueryInterface(&This->target->dispex.IDispatchEx_iface, &IID_IHTMLElement, (void**)p);
1120 else
1121 *p = NULL;
1122 return S_OK;
1125 static const IDOMEventVtbl DOMEventVtbl = {
1126 DOMEvent_QueryInterface,
1127 DOMEvent_AddRef,
1128 DOMEvent_Release,
1129 DOMEvent_GetTypeInfoCount,
1130 DOMEvent_GetTypeInfo,
1131 DOMEvent_GetIDsOfNames,
1132 DOMEvent_Invoke,
1133 DOMEvent_get_bubbles,
1134 DOMEvent_get_cancelable,
1135 DOMEvent_get_currentTarget,
1136 DOMEvent_get_defaultPrevented,
1137 DOMEvent_get_eventPhase,
1138 DOMEvent_get_target,
1139 DOMEvent_get_timeStamp,
1140 DOMEvent_get_type,
1141 DOMEvent_initEvent,
1142 DOMEvent_preventDefault,
1143 DOMEvent_stopPropagation,
1144 DOMEvent_stopImmediatePropagation,
1145 DOMEvent_get_isTrusted,
1146 DOMEvent_put_cancelBubble,
1147 DOMEvent_get_cancelBubble,
1148 DOMEvent_get_srcElement
1151 static inline DOMEvent *impl_from_IDOMUIEvent(IDOMUIEvent *iface)
1153 return CONTAINING_RECORD(iface, DOMEvent, IDOMUIEvent_iface);
1156 static HRESULT WINAPI DOMUIEvent_QueryInterface(IDOMUIEvent *iface, REFIID riid, void **ppv)
1158 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1159 return IDOMEvent_QueryInterface(&This->IDOMEvent_iface, riid, ppv);
1162 static ULONG WINAPI DOMUIEvent_AddRef(IDOMUIEvent *iface)
1164 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1165 return IDOMEvent_AddRef(&This->IDOMEvent_iface);
1168 static ULONG WINAPI DOMUIEvent_Release(IDOMUIEvent *iface)
1170 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1171 return IDOMEvent_Release(&This->IDOMEvent_iface);
1174 static HRESULT WINAPI DOMUIEvent_GetTypeInfoCount(IDOMUIEvent *iface, UINT *pctinfo)
1176 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1177 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1180 static HRESULT WINAPI DOMUIEvent_GetTypeInfo(IDOMUIEvent *iface, UINT iTInfo,
1181 LCID lcid, ITypeInfo **ppTInfo)
1183 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1184 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1187 static HRESULT WINAPI DOMUIEvent_GetIDsOfNames(IDOMUIEvent *iface, REFIID riid,
1188 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1190 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1191 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
1192 lcid, rgDispId);
1195 static HRESULT WINAPI DOMUIEvent_Invoke(IDOMUIEvent *iface, DISPID dispIdMember,
1196 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
1197 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1199 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1200 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
1201 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1204 static HRESULT WINAPI DOMUIEvent_get_view(IDOMUIEvent *iface, IHTMLWindow2 **p)
1206 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1207 FIXME("(%p)->(%p)\n", This, p);
1208 return E_NOTIMPL;
1211 static HRESULT WINAPI DOMUIEvent_get_detail(IDOMUIEvent *iface, LONG *p)
1213 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1214 FIXME("(%p)->(%p)\n", This, p);
1215 return E_NOTIMPL;
1218 static HRESULT WINAPI DOMUIEvent_initUIEvent(IDOMUIEvent *iface, BSTR type, VARIANT_BOOL can_bubble,
1219 VARIANT_BOOL cancelable, IHTMLWindow2 *view, LONG detail)
1221 DOMEvent *This = impl_from_IDOMUIEvent(iface);
1222 nsAString type_str;
1223 nsresult nsres;
1224 HRESULT hres;
1226 TRACE("(%p)->(%s %x %x %p %x)\n", This, debugstr_w(type), can_bubble, cancelable, view, detail);
1228 if(This->target) {
1229 TRACE("called on already dispatched event\n");
1230 return S_OK;
1233 hres = IDOMEvent_initEvent(&This->IDOMEvent_iface, type, can_bubble, cancelable);
1234 if(FAILED(hres))
1235 return hres;
1237 nsAString_InitDepend(&type_str, type);
1238 nsres = nsIDOMUIEvent_InitUIEvent(This->ui_event, &type_str, can_bubble, cancelable,
1239 NULL /* FIXME */, detail);
1240 nsAString_Finish(&type_str);
1241 if(NS_FAILED(nsres)) {
1242 FIXME("InitUIEvent failed: %08x\n", nsres);
1243 return E_FAIL;
1246 return S_OK;
1249 static const IDOMUIEventVtbl DOMUIEventVtbl = {
1250 DOMUIEvent_QueryInterface,
1251 DOMUIEvent_AddRef,
1252 DOMUIEvent_Release,
1253 DOMUIEvent_GetTypeInfoCount,
1254 DOMUIEvent_GetTypeInfo,
1255 DOMUIEvent_GetIDsOfNames,
1256 DOMUIEvent_Invoke,
1257 DOMUIEvent_get_view,
1258 DOMUIEvent_get_detail,
1259 DOMUIEvent_initUIEvent
1262 static inline DOMEvent *impl_from_IDOMMouseEvent(IDOMMouseEvent *iface)
1264 return CONTAINING_RECORD(iface, DOMEvent, IDOMMouseEvent_iface);
1267 static HRESULT WINAPI DOMMouseEvent_QueryInterface(IDOMMouseEvent *iface, REFIID riid, void **ppv)
1269 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1270 return IDOMEvent_QueryInterface(&This->IDOMEvent_iface, riid, ppv);
1273 static ULONG WINAPI DOMMouseEvent_AddRef(IDOMMouseEvent *iface)
1275 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1276 return IDOMEvent_AddRef(&This->IDOMEvent_iface);
1279 static ULONG WINAPI DOMMouseEvent_Release(IDOMMouseEvent *iface)
1281 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1282 return IDOMEvent_Release(&This->IDOMEvent_iface);
1285 static HRESULT WINAPI DOMMouseEvent_GetTypeInfoCount(IDOMMouseEvent *iface, UINT *pctinfo)
1287 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1288 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
1291 static HRESULT WINAPI DOMMouseEvent_GetTypeInfo(IDOMMouseEvent *iface, UINT iTInfo,
1292 LCID lcid, ITypeInfo **ppTInfo)
1294 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1295 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1298 static HRESULT WINAPI DOMMouseEvent_GetIDsOfNames(IDOMMouseEvent *iface, REFIID riid,
1299 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1301 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1302 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
1303 lcid, rgDispId);
1306 static HRESULT WINAPI DOMMouseEvent_Invoke(IDOMMouseEvent *iface, DISPID dispIdMember,
1307 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
1308 EXCEPINFO *pExcepInfo, UINT *puArgErr)
1310 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1311 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
1312 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1315 static HRESULT WINAPI DOMMouseEvent_get_screenX(IDOMMouseEvent *iface, LONG *p)
1317 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1318 INT32 screen_x;
1319 nsresult nsres;
1321 TRACE("(%p)->(%p)\n", This, p);
1323 nsres = nsIDOMMouseEvent_GetScreenX(This->mouse_event, &screen_x);
1324 if(NS_FAILED(nsres))
1325 return E_FAIL;
1327 *p = screen_x;
1328 return S_OK;
1331 static HRESULT WINAPI DOMMouseEvent_get_screenY(IDOMMouseEvent *iface, LONG *p)
1333 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1334 INT32 screen_y;
1335 nsresult nsres;
1337 TRACE("(%p)->(%p)\n", This, p);
1339 nsres = nsIDOMMouseEvent_GetScreenY(This->mouse_event, &screen_y);
1340 if(NS_FAILED(nsres))
1341 return E_FAIL;
1343 *p = screen_y;
1344 return S_OK;
1347 static HRESULT WINAPI DOMMouseEvent_get_clientX(IDOMMouseEvent *iface, LONG *p)
1349 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1350 INT32 client_x;
1351 nsresult nsres;
1353 TRACE("(%p)->(%p)\n", This, p);
1355 nsres = nsIDOMMouseEvent_GetClientX(This->mouse_event, &client_x);
1356 if(NS_FAILED(nsres))
1357 return E_FAIL;
1359 *p = client_x;
1360 return S_OK;
1363 static HRESULT WINAPI DOMMouseEvent_get_clientY(IDOMMouseEvent *iface, LONG *p)
1365 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1366 INT32 client_y;
1367 nsresult nsres;
1369 TRACE("(%p)->(%p)\n", This, p);
1371 nsres = nsIDOMMouseEvent_GetClientY(This->mouse_event, &client_y);
1372 if(NS_FAILED(nsres))
1373 return E_FAIL;
1375 *p = client_y;
1376 return S_OK;
1379 static HRESULT WINAPI DOMMouseEvent_get_ctrlKey(IDOMMouseEvent *iface, VARIANT_BOOL *p)
1381 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1382 cpp_bool r;
1383 nsresult nsres;
1385 TRACE("(%p)->(%p)\n", This, p);
1387 nsres = nsIDOMMouseEvent_GetCtrlKey(This->mouse_event, &r);
1388 if(NS_FAILED(nsres))
1389 return E_FAIL;
1391 *p = variant_bool(r);
1392 return S_OK;
1395 static HRESULT WINAPI DOMMouseEvent_get_shiftKey(IDOMMouseEvent *iface, VARIANT_BOOL *p)
1397 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1398 cpp_bool r;
1399 nsresult nsres;
1401 TRACE("(%p)->(%p)\n", This, p);
1403 nsres = nsIDOMMouseEvent_GetShiftKey(This->mouse_event, &r);
1404 if(NS_FAILED(nsres))
1405 return E_FAIL;
1407 *p = variant_bool(r);
1408 return S_OK;
1411 static HRESULT WINAPI DOMMouseEvent_get_altKey(IDOMMouseEvent *iface, VARIANT_BOOL *p)
1413 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1414 cpp_bool r;
1415 nsresult nsres;
1417 TRACE("(%p)->(%p)\n", This, p);
1419 nsres = nsIDOMMouseEvent_GetAltKey(This->mouse_event, &r);
1420 if(NS_FAILED(nsres))
1421 return E_FAIL;
1423 *p = variant_bool(r);
1424 return S_OK;
1427 static HRESULT WINAPI DOMMouseEvent_get_metaKey(IDOMMouseEvent *iface, VARIANT_BOOL *p)
1429 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1430 cpp_bool r;
1431 nsresult nsres;
1433 TRACE("(%p)->(%p)\n", This, p);
1435 nsres = nsIDOMMouseEvent_GetMetaKey(This->mouse_event, &r);
1436 if(NS_FAILED(nsres))
1437 return E_FAIL;
1439 *p = variant_bool(r);
1440 return S_OK;
1443 static HRESULT WINAPI DOMMouseEvent_get_button(IDOMMouseEvent *iface, USHORT *p)
1445 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1446 INT16 r;
1447 nsresult nsres;
1449 TRACE("(%p)->(%p)\n", This, p);
1451 nsres = nsIDOMMouseEvent_GetButton(This->mouse_event, &r);
1452 if(NS_FAILED(nsres))
1453 return E_FAIL;
1455 *p = r;
1456 return S_OK;
1459 static HRESULT WINAPI DOMMouseEvent_get_relatedTarget(IDOMMouseEvent *iface, IEventTarget **p)
1461 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1462 FIXME("(%p)->(%p)\n", This, p);
1463 return E_NOTIMPL;
1466 static HRESULT WINAPI DOMMouseEvent_initMouseEvent(IDOMMouseEvent *iface, BSTR type,
1467 VARIANT_BOOL can_bubble, VARIANT_BOOL cancelable, IHTMLWindow2 *view, LONG detail,
1468 LONG screen_x, LONG screen_y, LONG client_x, LONG client_y, VARIANT_BOOL ctrl_key,
1469 VARIANT_BOOL alt_key, VARIANT_BOOL shift_key, VARIANT_BOOL meta_key, USHORT button,
1470 IEventTarget *related_target)
1472 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1473 nsAString type_str;
1474 nsresult nsres;
1475 HRESULT hres;
1477 TRACE("(%p)->(%s %x %x %p %d %d %d %d %d %x %x %x %x %u %p)\n", This, debugstr_w(type),
1478 can_bubble, cancelable, view, detail, screen_x, screen_y, client_x, client_y,
1479 ctrl_key, alt_key, shift_key, meta_key, button, related_target);
1481 if(This->target) {
1482 TRACE("called on already dispatched event\n");
1483 return S_OK;
1486 hres = IDOMEvent_initEvent(&This->IDOMEvent_iface, type, can_bubble, cancelable);
1487 if(FAILED(hres))
1488 return hres;
1490 nsAString_InitDepend(&type_str, type);
1491 nsres = nsIDOMMouseEvent_InitMouseEvent(This->mouse_event, &type_str, can_bubble, cancelable,
1492 NULL /* FIXME */, detail, screen_x, screen_y,
1493 client_x, client_y, ctrl_key, alt_key, shift_key,
1494 meta_key, button, NULL /* FIXME */);
1495 nsAString_Finish(&type_str);
1496 if(NS_FAILED(nsres)) {
1497 FIXME("InitMouseEvent failed: %08x\n", nsres);
1498 return E_FAIL;
1501 return S_OK;
1504 static HRESULT WINAPI DOMMouseEvent_getModifierState(IDOMMouseEvent *iface, BSTR key,
1505 VARIANT_BOOL *activated)
1507 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1508 FIXME("(%p)->(%s %p)\n", This, debugstr_w(key), activated);
1509 return E_NOTIMPL;
1512 static HRESULT WINAPI DOMMouseEvent_get_buttons(IDOMMouseEvent *iface, USHORT *p)
1514 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1515 FIXME("(%p)->(%p)\n", This, p);
1516 return E_NOTIMPL;
1519 static HRESULT WINAPI DOMMouseEvent_get_fromElement(IDOMMouseEvent *iface, IHTMLElement **p)
1521 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1522 FIXME("(%p)->(%p)\n", This, p);
1523 return E_NOTIMPL;
1526 static HRESULT WINAPI DOMMouseEvent_get_toElement(IDOMMouseEvent *iface, IHTMLElement **p)
1528 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1529 FIXME("(%p)->(%p)\n", This, p);
1530 return E_NOTIMPL;
1533 static HRESULT WINAPI DOMMouseEvent_get_x(IDOMMouseEvent *iface, LONG *p)
1535 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1536 FIXME("(%p)->(%p)\n", This, p);
1537 return E_NOTIMPL;
1540 static HRESULT WINAPI DOMMouseEvent_get_y(IDOMMouseEvent *iface, LONG *p)
1542 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1543 FIXME("(%p)->(%p)\n", This, p);
1544 return E_NOTIMPL;
1547 static HRESULT WINAPI DOMMouseEvent_get_offsetX(IDOMMouseEvent *iface, LONG *p)
1549 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1550 FIXME("(%p)->(%p)\n", This, p);
1551 return E_NOTIMPL;
1554 static HRESULT WINAPI DOMMouseEvent_get_offsetY(IDOMMouseEvent *iface, LONG *p)
1556 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1557 FIXME("(%p)->(%p)\n", This, p);
1558 return E_NOTIMPL;
1561 static HRESULT WINAPI DOMMouseEvent_get_pageX(IDOMMouseEvent *iface, LONG *p)
1563 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1564 FIXME("(%p)->(%p)\n", This, p);
1565 return E_NOTIMPL;
1568 static HRESULT WINAPI DOMMouseEvent_get_pageY(IDOMMouseEvent *iface, LONG *p)
1570 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1571 FIXME("(%p)->(%p)\n", This, p);
1572 return E_NOTIMPL;
1575 static HRESULT WINAPI DOMMouseEvent_get_layerX(IDOMMouseEvent *iface, LONG *p)
1577 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1578 FIXME("(%p)->(%p)\n", This, p);
1579 return E_NOTIMPL;
1582 static HRESULT WINAPI DOMMouseEvent_get_layerY(IDOMMouseEvent *iface, LONG *p)
1584 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1585 FIXME("(%p)->(%p)\n", This, p);
1586 return E_NOTIMPL;
1589 static HRESULT WINAPI DOMMouseEvent_get_which(IDOMMouseEvent *iface, USHORT *p)
1591 DOMEvent *This = impl_from_IDOMMouseEvent(iface);
1592 FIXME("(%p)->(%p)\n", This, p);
1593 return E_NOTIMPL;
1596 static const IDOMMouseEventVtbl DOMMouseEventVtbl = {
1597 DOMMouseEvent_QueryInterface,
1598 DOMMouseEvent_AddRef,
1599 DOMMouseEvent_Release,
1600 DOMMouseEvent_GetTypeInfoCount,
1601 DOMMouseEvent_GetTypeInfo,
1602 DOMMouseEvent_GetIDsOfNames,
1603 DOMMouseEvent_Invoke,
1604 DOMMouseEvent_get_screenX,
1605 DOMMouseEvent_get_screenY,
1606 DOMMouseEvent_get_clientX,
1607 DOMMouseEvent_get_clientY,
1608 DOMMouseEvent_get_ctrlKey,
1609 DOMMouseEvent_get_shiftKey,
1610 DOMMouseEvent_get_altKey,
1611 DOMMouseEvent_get_metaKey,
1612 DOMMouseEvent_get_button,
1613 DOMMouseEvent_get_relatedTarget,
1614 DOMMouseEvent_initMouseEvent,
1615 DOMMouseEvent_getModifierState,
1616 DOMMouseEvent_get_buttons,
1617 DOMMouseEvent_get_fromElement,
1618 DOMMouseEvent_get_toElement,
1619 DOMMouseEvent_get_x,
1620 DOMMouseEvent_get_y,
1621 DOMMouseEvent_get_offsetX,
1622 DOMMouseEvent_get_offsetY,
1623 DOMMouseEvent_get_pageX,
1624 DOMMouseEvent_get_pageY,
1625 DOMMouseEvent_get_layerX,
1626 DOMMouseEvent_get_layerY,
1627 DOMMouseEvent_get_which
1630 static const tid_t DOMEvent_iface_tids[] = {
1631 IDOMEvent_tid,
1635 static dispex_static_data_t DOMEvent_dispex = {
1636 NULL,
1637 DispDOMEvent_tid,
1638 DOMEvent_iface_tids
1641 static const tid_t DOMMouseEvent_iface_tids[] = {
1642 IDOMEvent_tid,
1643 IDOMMouseEvent_tid,
1647 static dispex_static_data_t DOMMouseEvent_dispex = {
1648 NULL,
1649 DispDOMMouseEvent_tid,
1650 DOMMouseEvent_iface_tids
1653 static DOMEvent *alloc_event(nsIDOMEvent *nsevent, eventid_t event_id)
1655 dispex_static_data_t *dispex_data = &DOMEvent_dispex;
1656 DOMEvent *event;
1657 FILETIME time;
1658 nsresult nsres;
1660 /* 1601 to 1970 is 369 years plus 89 leap days */
1661 const ULONGLONG time_epoch = (ULONGLONG)(369 * 365 + 89) * 86400 * 1000;
1663 event = heap_alloc_zero(sizeof(*event));
1664 if(!event)
1665 return NULL;
1667 event->IDOMEvent_iface.lpVtbl = &DOMEventVtbl;
1668 event->IDOMUIEvent_iface.lpVtbl = &DOMUIEventVtbl;
1669 event->IDOMMouseEvent_iface.lpVtbl = &DOMMouseEventVtbl;
1670 event->ref = 1;
1671 event->event_id = event_id;
1672 if(event_id != EVENTID_LAST) {
1673 event->type = heap_strdupW(event_info[event_id].name);
1674 if(!event->type) {
1675 heap_free(event);
1676 return NULL;
1678 event->bubbles = (event_info[event_id].flags & EVENT_BUBBLES) != 0;
1679 event->cancelable = (event_info[event_id].flags & EVENT_CANCELABLE) != 0;
1681 nsIDOMEvent_AddRef(event->nsevent = nsevent);
1683 GetSystemTimeAsFileTime(&time);
1684 event->time_stamp = (((ULONGLONG)time.dwHighDateTime<<32) + time.dwLowDateTime) / 10000
1685 - time_epoch;
1687 nsres = nsIDOMEvent_QueryInterface(nsevent, &IID_nsIDOMUIEvent, (void**)&event->ui_event);
1688 if(NS_FAILED(nsres))
1689 event->ui_event = NULL;
1691 nsres = nsIDOMEvent_QueryInterface(nsevent, &IID_nsIDOMMouseEvent, (void**)&event->mouse_event);
1692 if(NS_SUCCEEDED(nsres))
1693 dispex_data = &DOMMouseEvent_dispex;
1694 else
1695 event->mouse_event = NULL;
1697 init_dispex(&event->dispex, (IUnknown*)&event->IDOMEvent_iface, dispex_data);
1698 return event;
1701 HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, DOMEvent **ret_event)
1703 eventid_t event_id = EVENTID_LAST;
1704 DOMEvent *event;
1705 nsAString nsstr;
1706 nsresult nsres;
1708 nsAString_Init(&nsstr, NULL);
1709 nsres = nsIDOMEvent_GetType(nsevent, &nsstr);
1710 if(NS_SUCCEEDED(nsres)) {
1711 const WCHAR *type;
1712 nsAString_GetData(&nsstr, &type);
1713 event_id = str_to_eid(type);
1714 if(event_id == EVENTID_LAST)
1715 FIXME("unknown event type %s\n", debugstr_w(type));
1716 }else {
1717 ERR("GetType failed: %08x\n", nsres);
1719 nsAString_Finish(&nsstr);
1721 event = alloc_event(nsevent, event_id);
1722 if(!event)
1723 return E_OUTOFMEMORY;
1725 *ret_event = event;
1726 return S_OK;
1729 HRESULT create_document_event_str(HTMLDocumentNode *doc, const WCHAR *type, IDOMEvent **ret_event)
1731 nsIDOMEvent *nsevent;
1732 DOMEvent *event;
1733 nsAString nsstr;
1734 nsresult nsres;
1736 nsAString_InitDepend(&nsstr, type);
1737 nsres = nsIDOMHTMLDocument_CreateEvent(doc->nsdoc, &nsstr, &nsevent);
1738 nsAString_Finish(&nsstr);
1739 if(NS_FAILED(nsres)) {
1740 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(type), nsres);
1741 return E_FAIL;
1744 event = alloc_event(nsevent, EVENTID_LAST);
1745 nsIDOMEvent_Release(nsevent);
1746 if(!event)
1747 return E_OUTOFMEMORY;
1749 *ret_event = &event->IDOMEvent_iface;
1750 return S_OK;
1753 HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEvent **ret_event)
1755 nsIDOMEvent *nsevent;
1756 DOMEvent *event;
1757 nsAString nsstr;
1758 nsresult nsres;
1760 nsAString_InitDepend(&nsstr, event_types[event_info[event_id].type]);
1761 nsres = nsIDOMHTMLDocument_CreateEvent(doc->nsdoc, &nsstr, &nsevent);
1762 nsAString_Finish(&nsstr);
1763 if(NS_FAILED(nsres)) {
1764 FIXME("CreateEvent(%s) failed: %08x\n", debugstr_w(event_types[event_info[event_id].type]), nsres);
1765 return E_FAIL;
1768 event = alloc_event(nsevent, event_id);
1769 if(!event)
1770 return E_OUTOFMEMORY;
1772 event->event_id = event_id;
1773 *ret_event = event;
1774 return S_OK;
1777 static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
1779 IDispatchEx *dispex;
1780 EXCEPINFO ei;
1781 HRESULT hres;
1783 memset(&ei, 0, sizeof(ei));
1785 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1786 if(SUCCEEDED(hres)) {
1787 hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, dp, retv, &ei, NULL);
1788 IDispatchEx_Release(dispex);
1789 }else {
1790 TRACE("Could not get IDispatchEx interface: %08x\n", hres);
1791 hres = IDispatch_Invoke(disp, 0, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD,
1792 dp, retv, &ei, NULL);
1795 return hres;
1798 static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, IHTMLEventObj *event_obj, VARIANT *retv)
1800 DISPPARAMS dp = {NULL,NULL,0,0};
1801 VARIANT event_arg;
1802 ULONG argerr;
1803 EXCEPINFO ei;
1805 if(event_obj) {
1806 V_VT(&event_arg) = VT_DISPATCH;
1807 V_DISPATCH(&event_arg) = (IDispatch*)event_obj;
1808 dp.rgvarg = &event_arg;
1809 dp.cArgs = 1;
1812 memset(&ei, 0, sizeof(ei));
1813 return IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, retv, &ei, &argerr);
1816 static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
1818 int min, max, i;
1819 HRESULT hres;
1821 if(!data)
1822 return FALSE;
1824 if(!data->ids) {
1825 hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
1826 if(FAILED(hres))
1827 return FALSE;
1830 min = 0;
1831 max = data->id_cnt-1;
1832 while(min <= max) {
1833 i = (min+max)/2;
1834 if(data->ids[i] == dispid)
1835 return TRUE;
1837 if(data->ids[i] < dispid)
1838 min = i+1;
1839 else
1840 max = i-1;
1843 return FALSE;
1846 static void call_event_handlers(EventTarget *event_target, DOMEvent *event, dispatch_mode_t dispatch_mode)
1848 const listener_container_t *container = get_listener_container(event_target, event->type, FALSE);
1849 const BOOL use_quirks = use_event_quirks(event_target);
1850 event_listener_t *listener, listeners_buf[8], *listeners = listeners_buf;
1851 unsigned listeners_cnt, listeners_size;
1852 ConnectionPointContainer *cp_container = NULL;
1853 const event_target_vtbl_t *vtbl = NULL;
1854 VARIANT v;
1855 HRESULT hres;
1857 assert(!event->current_target);
1858 event->current_target = event_target;
1860 if(use_quirks && container && !list_empty(&container->listeners)
1861 && event->phase != DEP_CAPTURING_PHASE) {
1862 listener = LIST_ENTRY(list_tail(&container->listeners), event_listener_t, entry);
1863 if(listener && listener->function && listener->type == LISTENER_TYPE_ONEVENT) {
1864 DISPID named_arg = DISPID_THIS;
1865 VARIANTARG arg;
1866 DISPPARAMS dp = {&arg, &named_arg, 1, 1};
1868 V_VT(&arg) = VT_DISPATCH;
1869 V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
1870 V_VT(&v) = VT_EMPTY;
1872 TRACE("%s >>>\n", debugstr_w(event->type));
1873 hres = call_disp_func(listener->function, &dp, &v);
1874 if(hres == S_OK) {
1875 TRACE("%s <<< %s\n", debugstr_w(event->type), debugstr_variant(&v));
1877 if(event->cancelable) {
1878 if(V_VT(&v) == VT_BOOL) {
1879 if(!V_BOOL(&v))
1880 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1881 }else if(V_VT(&v) != VT_EMPTY) {
1882 FIXME("unhandled result %s\n", debugstr_variant(&v));
1885 VariantClear(&v);
1886 }else {
1887 WARN("%s <<< %08x\n", debugstr_w(event->type), hres);
1892 listeners_cnt = 0;
1893 listeners_size = sizeof(listeners_buf)/sizeof(*listeners_buf);
1895 if(container) {
1896 LIST_FOR_EACH_ENTRY(listener, &container->listeners, event_listener_t, entry) {
1897 if(!listener->function)
1898 continue;
1899 switch(listener->type) {
1900 case LISTENER_TYPE_ONEVENT:
1901 if(use_quirks || event->phase == DEP_CAPTURING_PHASE)
1902 continue;
1903 break;
1904 case LISTENER_TYPE_CAPTURE:
1905 if(event->phase == DEP_BUBBLING_PHASE || dispatch_mode == DISPATCH_LEGACY)
1906 continue;
1907 break;
1908 case LISTENER_TYPE_BUBBLE:
1909 if(event->phase == DEP_CAPTURING_PHASE || dispatch_mode == DISPATCH_LEGACY)
1910 continue;
1911 break;
1912 case LISTENER_TYPE_ATTACHED:
1913 if(event->phase == DEP_CAPTURING_PHASE || dispatch_mode == DISPATCH_STANDARD)
1914 continue;
1915 break;
1918 if(listeners_cnt == listeners_size) {
1919 event_listener_t *new_listeners;
1920 if(listeners == listeners_buf) {
1921 new_listeners = heap_alloc(listeners_size * 2 * sizeof(*new_listeners));
1922 if(!new_listeners)
1923 break;
1924 memcpy(new_listeners, listeners, listeners_cnt * sizeof(*listeners));
1925 }else {
1926 new_listeners = heap_realloc(listeners, listeners_size * 2 * sizeof(*new_listeners));
1928 listeners = new_listeners;
1929 listeners_size *= 2;
1932 listeners[listeners_cnt].type = listener->type;
1933 IDispatch_AddRef(listeners[listeners_cnt].function = listener->function);
1934 listeners_cnt++;
1938 for(listener = listeners; listener < listeners + listeners_cnt; listener++) {
1939 if(listener->type != LISTENER_TYPE_ATTACHED) {
1940 DISPID named_arg = DISPID_THIS;
1941 VARIANTARG args[2];
1942 DISPPARAMS dp = {args, &named_arg, 2, 1};
1944 V_VT(args) = VT_DISPATCH;
1945 V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IDispatchEx_iface;
1946 V_VT(args+1) = VT_DISPATCH;
1947 V_DISPATCH(args+1) = dispatch_mode == DISPATCH_LEGACY
1948 ? (IDispatch*)event->event_obj : (IDispatch*)&event->IDOMEvent_iface;
1949 V_VT(&v) = VT_EMPTY;
1951 TRACE("%s >>>\n", debugstr_w(event->type));
1952 hres = call_disp_func(listener->function, &dp, &v);
1953 if(hres == S_OK) {
1954 TRACE("%s <<< %s\n", debugstr_w(event->type),
1955 debugstr_variant(&v));
1957 if(event->cancelable) {
1958 if(V_VT(&v) == VT_BOOL) {
1959 if(!V_BOOL(&v))
1960 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1961 }else if(V_VT(&v) != VT_EMPTY) {
1962 FIXME("unhandled result %s\n", debugstr_variant(&v));
1965 VariantClear(&v);
1966 }else {
1967 WARN("%s <<< %08x\n", debugstr_w(event->type), hres);
1969 }else {
1970 VARIANTARG arg;
1971 DISPPARAMS dp = {&arg, NULL, 1, 0};
1973 V_VT(&arg) = VT_DISPATCH;
1974 V_DISPATCH(&arg) = (IDispatch*)event->event_obj;
1975 V_VT(&v) = VT_EMPTY;
1977 TRACE("%s attached >>>\n", debugstr_w(event->type));
1978 hres = call_disp_func(listener->function, &dp, &v);
1979 if(hres == S_OK) {
1980 TRACE("%s attached <<<\n", debugstr_w(event->type));
1982 if(event->cancelable) {
1983 if(V_VT(&v) == VT_BOOL) {
1984 if(!V_BOOL(&v))
1985 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
1986 }else if(V_VT(&v) != VT_EMPTY) {
1987 FIXME("unhandled result %s\n", debugstr_variant(&v));
1990 VariantClear(&v);
1991 }else {
1992 WARN("%s attached <<< %08x\n", debugstr_w(event->type), hres);
1997 for(listener = listeners; listener < listeners + listeners_cnt; listener++)
1998 IDispatch_Release(listener->function);
1999 if(listeners != listeners_buf)
2000 heap_free(listeners);
2002 if(event->phase != DEP_CAPTURING_PHASE && event->event_id != EVENTID_LAST
2003 && event_info[event->event_id].dispid && (vtbl = dispex_get_vtbl(&event_target->dispex))
2004 && vtbl->get_cp_container)
2005 cp_container = vtbl->get_cp_container(&event_target->dispex);
2006 if(cp_container) {
2007 if(cp_container->cps) {
2008 ConnectionPoint *cp;
2009 unsigned i, j;
2011 for(j=0; cp_container->cp_entries[j].riid; j++) {
2012 cp = cp_container->cps + j;
2013 if(!cp->sinks_size || !is_cp_event(cp->data, event_info[event->event_id].dispid))
2014 continue;
2016 for(i=0; i < cp->sinks_size; i++) {
2017 if(!cp->sinks[i].disp)
2018 continue;
2020 V_VT(&v) = VT_EMPTY;
2022 TRACE("cp %s [%u] >>>\n", debugstr_w(event->type), i);
2023 hres = call_cp_func(cp->sinks[i].disp, event_info[event->event_id].dispid,
2024 cp->data->pass_event_arg ? event->event_obj : NULL, &v);
2025 if(hres == S_OK) {
2026 TRACE("cp %s [%u] <<<\n", debugstr_w(event->type), i);
2028 if(event->cancelable) {
2029 if(V_VT(&v) == VT_BOOL) {
2030 if(!V_BOOL(&v))
2031 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
2032 }else if(V_VT(&v) != VT_EMPTY) {
2033 FIXME("unhandled result %s\n", debugstr_variant(&v));
2036 VariantClear(&v);
2037 }else {
2038 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event->type), i, hres);
2043 IConnectionPointContainer_Release(&cp_container->IConnectionPointContainer_iface);
2046 event->current_target = NULL;
2049 static HRESULT dispatch_event_object(EventTarget *event_target, DOMEvent *event,
2050 dispatch_mode_t dispatch_mode, VARIANT_BOOL *r)
2052 EventTarget *target_chain_buf[8], **target_chain = target_chain_buf;
2053 unsigned chain_cnt, chain_buf_size, i;
2054 const event_target_vtbl_t *vtbl, *target_vtbl;
2055 HTMLEventObj *event_obj_ref = NULL;
2056 IHTMLEventObj *prev_event = NULL;
2057 EventTarget *iter;
2058 HRESULT hres;
2060 TRACE("(%p) %s\n", event_target, debugstr_w(event->type));
2062 if(!event->type) {
2063 FIXME("Uninitialized event.\n");
2064 return E_FAIL;
2067 if(event->current_target) {
2068 FIXME("event is being dispatched.\n");
2069 return E_FAIL;
2072 iter = event_target;
2073 IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
2075 chain_cnt = 0;
2076 chain_buf_size = sizeof(target_chain_buf)/sizeof(*target_chain_buf);
2078 do {
2079 if(chain_cnt == chain_buf_size) {
2080 EventTarget **new_chain;
2081 if(target_chain == target_chain_buf) {
2082 new_chain = heap_alloc(chain_buf_size * 2 * sizeof(*new_chain));
2083 if(!new_chain)
2084 break;
2085 memcpy(new_chain, target_chain, chain_buf_size * sizeof(*new_chain));
2086 }else {
2087 new_chain = heap_realloc(target_chain, chain_buf_size * 2 * sizeof(*new_chain));
2088 if(!new_chain)
2089 break;
2091 chain_buf_size *= 2;
2092 target_chain = new_chain;
2095 target_chain[chain_cnt++] = iter;
2097 if(!(vtbl = dispex_get_vtbl(&iter->dispex)) || !vtbl->get_parent_event_target)
2098 break;
2099 iter = vtbl->get_parent_event_target(&iter->dispex);
2100 } while(iter);
2102 if(!event->event_obj && !event->no_event_obj) {
2103 event_obj_ref = alloc_event_obj(event);
2104 if(event_obj_ref)
2105 event->event_obj = &event_obj_ref->IHTMLEventObj_iface;
2108 target_vtbl = dispex_get_vtbl(&event_target->dispex);
2109 if(target_vtbl && target_vtbl->set_current_event)
2110 prev_event = target_vtbl->set_current_event(&event_target->dispex, event->event_obj);
2112 if(event->target)
2113 IDispatchEx_Release(&event->target->dispex.IDispatchEx_iface);
2114 event->target = event_target;
2115 IDispatchEx_AddRef(&event_target->dispex.IDispatchEx_iface);
2117 event->phase = DEP_CAPTURING_PHASE;
2118 i = chain_cnt-1;
2119 while(!event->stop_propagation && i)
2120 call_event_handlers(target_chain[i--], event, dispatch_mode);
2122 if(!event->stop_propagation) {
2123 event->phase = DEP_AT_TARGET;
2124 call_event_handlers(target_chain[0], event, dispatch_mode);
2127 if(event->bubbles) {
2128 event->phase = DEP_BUBBLING_PHASE;
2129 for(i = 1; !event->stop_propagation && i < chain_cnt; i++)
2130 call_event_handlers(target_chain[i], event, dispatch_mode);
2133 if(r)
2134 *r = variant_bool(!event->prevent_default);
2136 if(target_vtbl && target_vtbl->set_current_event) {
2137 prev_event = target_vtbl->set_current_event(&event_target->dispex, prev_event);
2138 if(prev_event)
2139 IHTMLEventObj_Release(prev_event);
2142 if(event->event_id != EVENTID_LAST && (event_info[event->event_id].flags & EVENT_HASDEFAULTHANDLERS)) {
2143 for(i = 0; !event->prevent_default && i < chain_cnt; i++) {
2144 BOOL prevent_default = FALSE;
2145 vtbl = dispex_get_vtbl(&target_chain[i]->dispex);
2146 if(!vtbl || !vtbl->handle_event_default)
2147 continue;
2148 hres = vtbl->handle_event_default(&event_target->dispex, event->event_id,
2149 event->nsevent, &prevent_default);
2150 if(FAILED(hres) || event->stop_propagation)
2151 break;
2152 if(prevent_default)
2153 IDOMEvent_preventDefault(&event->IDOMEvent_iface);
2157 event->prevent_default = FALSE;
2158 if(event_obj_ref) {
2159 event->event_obj = NULL;
2160 IHTMLEventObj_Release(&event_obj_ref->IHTMLEventObj_iface);
2163 for(i = 0; i < chain_cnt; i++)
2164 IDispatchEx_Release(&target_chain[i]->dispex.IDispatchEx_iface);
2165 if(target_chain != target_chain_buf)
2166 heap_free(target_chain);
2168 return S_OK;
2171 void dispatch_event(EventTarget *event_target, DOMEvent *event)
2173 dispatch_event_object(event_target, event, DISPATCH_BOTH, NULL);
2176 HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_var, VARIANT_BOOL *cancelled)
2178 HTMLEventObj *event_obj = NULL;
2179 eventid_t eid;
2180 HRESULT hres = S_OK;
2182 eid = attr_to_eid(event_name);
2183 if(eid == EVENTID_LAST) {
2184 WARN("unknown event %s\n", debugstr_w(event_name));
2185 return E_INVALIDARG;
2188 if(event_var && V_VT(event_var) != VT_EMPTY && V_VT(event_var) != VT_ERROR) {
2189 if(V_VT(event_var) != VT_DISPATCH) {
2190 FIXME("event_var %s not supported\n", debugstr_variant(event_var));
2191 return E_NOTIMPL;
2194 if(V_DISPATCH(event_var)) {
2195 IHTMLEventObj *event_iface;
2197 hres = IDispatch_QueryInterface(V_DISPATCH(event_var), &IID_IHTMLEventObj, (void**)&event_iface);
2198 if(FAILED(hres)) {
2199 FIXME("No IHTMLEventObj iface\n");
2200 return hres;
2203 event_obj = unsafe_impl_from_IHTMLEventObj(event_iface);
2204 if(!event_obj) {
2205 ERR("Not our IHTMLEventObj?\n");
2206 IHTMLEventObj_Release(event_iface);
2207 return E_FAIL;
2212 if(!event_obj) {
2213 event_obj = alloc_event_obj(NULL);
2214 if(!event_obj)
2215 return E_OUTOFMEMORY;
2218 if(!event_obj->event)
2219 hres = create_document_event(node->doc, eid, &event_obj->event);
2221 if(SUCCEEDED(hres)) {
2222 event_obj->event->event_obj = &event_obj->IHTMLEventObj_iface;
2223 dispatch_event_object(&node->event_target, event_obj->event, DISPATCH_LEGACY, NULL);
2224 event_obj->event->event_obj = NULL;
2227 IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
2228 if(FAILED(hres))
2229 return hres;
2231 *cancelled = VARIANT_TRUE; /* FIXME */
2232 return S_OK;
2235 HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, eventid_t eid)
2237 nsIDOMNode *nsnode = NULL;
2239 TRACE("%s\n", debugstr_w(event_info[eid].name));
2241 if(!doc->nsdoc)
2242 return S_OK;
2244 switch(eid) {
2245 case EVENTID_FOCUSIN:
2246 doc->event_vector[eid] = TRUE;
2247 eid = EVENTID_FOCUS;
2248 break;
2249 case EVENTID_FOCUSOUT:
2250 doc->event_vector[eid] = TRUE;
2251 eid = EVENTID_BLUR;
2252 break;
2253 default:
2254 break;
2257 if(doc->event_vector[eid] || !(event_info[eid].flags & (EVENT_DEFAULTLISTENER|EVENT_BIND_TO_BODY)))
2258 return S_OK;
2260 if(event_info[eid].flags & EVENT_BIND_TO_BODY) {
2261 nsnode = doc->node.nsnode;
2262 nsIDOMNode_AddRef(nsnode);
2265 doc->event_vector[eid] = TRUE;
2266 add_nsevent_listener(doc, nsnode, event_info[eid].name);
2268 if(nsnode)
2269 nsIDOMNode_Release(nsnode);
2270 return S_OK;
2273 void detach_events(HTMLDocumentNode *doc)
2275 if(doc->event_vector) {
2276 int i;
2278 for(i=0; i < EVENTID_LAST; i++) {
2279 if(doc->event_vector[i]) {
2280 detach_nsevent(doc, event_info[i].name);
2281 doc->event_vector[i] = FALSE;
2286 release_nsevents(doc);
2289 static HRESULT get_event_dispex_ref(EventTarget *event_target, eventid_t eid, BOOL alloc, VARIANT **ret)
2291 WCHAR buf[64];
2292 buf[0] = 'o';
2293 buf[1] = 'n';
2294 strcpyW(buf+2, event_info[eid].name);
2295 return dispex_get_dprop_ref(&event_target->dispex, buf, alloc, ret);
2298 static event_listener_t *get_onevent_listener(EventTarget *event_target, eventid_t eid, BOOL alloc)
2300 listener_container_t *container;
2301 event_listener_t *listener;
2303 container = get_listener_container(event_target, event_info[eid].name, alloc);
2304 if(!container)
2305 return NULL;
2307 LIST_FOR_EACH_ENTRY_REV(listener, &container->listeners, event_listener_t, entry) {
2308 if(listener->type == LISTENER_TYPE_ONEVENT)
2309 return listener;
2312 if(!alloc)
2313 return NULL;
2315 listener = heap_alloc(sizeof(*listener));
2316 if(!listener)
2317 return NULL;
2319 listener->type = LISTENER_TYPE_ONEVENT;
2320 listener->function = NULL;
2321 list_add_tail(&container->listeners, &listener->entry);
2322 return listener;
2325 static void remove_event_handler(EventTarget *event_target, eventid_t eid)
2327 event_listener_t *listener;
2328 VARIANT *store;
2329 HRESULT hres;
2331 hres = get_event_dispex_ref(event_target, eid, FALSE, &store);
2332 if(SUCCEEDED(hres))
2333 VariantClear(store);
2335 listener = get_onevent_listener(event_target, eid, FALSE);
2336 if(listener && listener->function) {
2337 IDispatch_Release(listener->function);
2338 listener->function = NULL;
2342 static HRESULT set_event_handler_disp(EventTarget *event_target, eventid_t eid, IDispatch *disp)
2344 event_listener_t *listener;
2346 if(event_info[eid].flags & EVENT_FIXME)
2347 FIXME("unimplemented event %s\n", debugstr_w(event_info[eid].name));
2349 remove_event_handler(event_target, eid);
2350 if(!disp)
2351 return S_OK;
2353 listener = get_onevent_listener(event_target, eid, TRUE);
2354 if(!listener)
2355 return E_OUTOFMEMORY;
2357 if(listener->function)
2358 IDispatch_Release(listener->function);
2360 IDispatch_AddRef(listener->function = disp);
2361 return S_OK;
2364 HRESULT set_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
2366 switch(V_VT(var)) {
2367 case VT_EMPTY:
2368 if(use_event_quirks(event_target)) {
2369 WARN("attempt to set to VT_EMPTY in quirks mode\n");
2370 return E_NOTIMPL;
2372 /* fall through */
2373 case VT_NULL:
2374 remove_event_handler(event_target, eid);
2375 return S_OK;
2377 case VT_DISPATCH:
2378 return set_event_handler_disp(event_target, eid, V_DISPATCH(var));
2380 case VT_BSTR: {
2381 VARIANT *v;
2382 HRESULT hres;
2384 if(!use_event_quirks(event_target))
2385 FIXME("Setting to string %s not supported\n", debugstr_w(V_BSTR(var)));
2388 * Setting event handler to string is a rare case and we don't want to
2389 * complicate nor increase memory of listener_container_t for that. Instead,
2390 * we store the value in DispatchEx, which can already handle custom
2391 * properties.
2393 remove_event_handler(event_target, eid);
2395 hres = get_event_dispex_ref(event_target, eid, TRUE, &v);
2396 if(FAILED(hres))
2397 return hres;
2399 V_BSTR(v) = SysAllocString(V_BSTR(var));
2400 if(!V_BSTR(v))
2401 return E_OUTOFMEMORY;
2402 V_VT(v) = VT_BSTR;
2403 return S_OK;
2406 default:
2407 FIXME("not handler %s\n", debugstr_variant(var));
2408 return E_NOTIMPL;
2411 return S_OK;
2414 HRESULT get_event_handler(EventTarget *event_target, eventid_t eid, VARIANT *var)
2416 event_listener_t *listener;
2417 VARIANT *v;
2418 HRESULT hres;
2420 hres = get_event_dispex_ref(event_target, eid, FALSE, &v);
2421 if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY) {
2422 V_VT(var) = VT_EMPTY;
2423 return VariantCopy(var, v);
2426 listener = get_onevent_listener(event_target, eid, FALSE);
2427 if(listener && listener->function) {
2428 V_VT(var) = VT_DISPATCH;
2429 V_DISPATCH(var) = listener->function;
2430 IDispatch_AddRef(V_DISPATCH(var));
2431 }else {
2432 V_VT(var) = VT_NULL;
2435 return S_OK;
2438 HRESULT attach_event(EventTarget *event_target, BSTR name, IDispatch *disp, VARIANT_BOOL *res)
2440 listener_container_t *container;
2441 event_listener_t *listener;
2442 eventid_t eid;
2444 eid = attr_to_eid(name);
2445 if(eid == EVENTID_LAST) {
2446 WARN("Unknown event\n");
2447 *res = VARIANT_TRUE;
2448 return S_OK;
2451 container = get_listener_container(event_target, event_info[eid].name, TRUE);
2452 if(!container)
2453 return E_OUTOFMEMORY;
2455 listener = heap_alloc(sizeof(*listener));
2456 if(!listener)
2457 return E_OUTOFMEMORY;
2459 listener->type = LISTENER_TYPE_ATTACHED;
2460 IDispatch_AddRef(listener->function = disp);
2461 if(use_event_quirks(event_target))
2462 list_add_head(&container->listeners, &listener->entry);
2463 else
2464 list_add_tail(&container->listeners, &listener->entry);
2466 *res = VARIANT_TRUE;
2467 return S_OK;
2470 HRESULT detach_event(EventTarget *event_target, BSTR name, IDispatch *disp)
2472 eventid_t eid;
2474 eid = attr_to_eid(name);
2475 if(eid == EVENTID_LAST) {
2476 WARN("Unknown event\n");
2477 return S_OK;
2480 remove_event_listener(event_target, event_info[eid].name, LISTENER_TYPE_ATTACHED, disp);
2481 return S_OK;
2484 void bind_target_event(HTMLDocumentNode *doc, EventTarget *event_target, const WCHAR *event, IDispatch *disp)
2486 eventid_t eid;
2488 TRACE("(%p %p %s %p)\n", doc, event_target, debugstr_w(event), disp);
2490 eid = attr_to_eid(event);
2491 if(eid == EVENTID_LAST) {
2492 WARN("Unsupported event %s\n", debugstr_w(event));
2493 return;
2496 set_event_handler_disp(event_target, eid, disp);
2499 void update_doc_cp_events(HTMLDocumentNode *doc, cp_static_data_t *cp)
2501 int i;
2503 for(i=0; i < EVENTID_LAST; i++) {
2504 if((event_info[i].flags & EVENT_DEFAULTLISTENER) && is_cp_event(cp, event_info[i].dispid))
2505 ensure_doc_nsevent_handler(doc, i);
2509 void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
2511 nsIDOMMozNamedAttrMap *attr_map;
2512 const PRUnichar *name, *value;
2513 nsAString name_str, value_str;
2514 HTMLDOMNode *node = NULL;
2515 cpp_bool has_attrs;
2516 nsIDOMAttr *attr;
2517 IDispatch *disp;
2518 UINT32 length, i;
2519 eventid_t eid;
2520 nsresult nsres;
2521 HRESULT hres;
2523 nsres = nsIDOMHTMLElement_HasAttributes(nselem, &has_attrs);
2524 if(NS_FAILED(nsres) || !has_attrs)
2525 return;
2527 nsres = nsIDOMHTMLElement_GetAttributes(nselem, &attr_map);
2528 if(NS_FAILED(nsres))
2529 return;
2531 nsres = nsIDOMMozNamedAttrMap_GetLength(attr_map, &length);
2532 assert(nsres == NS_OK);
2534 nsAString_Init(&name_str, NULL);
2535 nsAString_Init(&value_str, NULL);
2537 for(i = 0; i < length; i++) {
2538 nsres = nsIDOMMozNamedAttrMap_Item(attr_map, i, &attr);
2539 if(NS_FAILED(nsres))
2540 continue;
2542 nsres = nsIDOMAttr_GetName(attr, &name_str);
2543 if(NS_FAILED(nsres)) {
2544 nsIDOMAttr_Release(attr);
2545 continue;
2548 nsAString_GetData(&name_str, &name);
2549 eid = attr_to_eid(name);
2550 if(eid == EVENTID_LAST) {
2551 nsIDOMAttr_Release(attr);
2552 continue;
2555 nsres = nsIDOMAttr_GetValue(attr, &value_str);
2556 nsIDOMAttr_Release(attr);
2557 if(NS_FAILED(nsres))
2558 continue;
2560 nsAString_GetData(&value_str, &value);
2561 if(!*value)
2562 continue;
2564 TRACE("%p.%s = %s\n", nselem, debugstr_w(name), debugstr_w(value));
2566 disp = script_parse_event(doc->window, value);
2567 if(!disp)
2568 continue;
2570 if(!node) {
2571 hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
2572 if(FAILED(hres)) {
2573 IDispatch_Release(disp);
2574 break;
2578 set_event_handler_disp(get_node_event_prop_target(node, eid), eid, disp);
2579 IDispatch_Release(disp);
2582 if(node)
2583 node_release(node);
2584 nsAString_Finish(&name_str);
2585 nsAString_Finish(&value_str);
2586 nsIDOMMozNamedAttrMap_Release(attr_map);
2589 HRESULT doc_init_events(HTMLDocumentNode *doc)
2591 unsigned i;
2592 HRESULT hres;
2594 doc->event_vector = heap_alloc_zero(EVENTID_LAST*sizeof(BOOL));
2595 if(!doc->event_vector)
2596 return E_OUTOFMEMORY;
2598 init_nsevents(doc);
2600 for(i=0; i < EVENTID_LAST; i++) {
2601 if(event_info[i].flags & EVENT_HASDEFAULTHANDLERS) {
2602 hres = ensure_doc_nsevent_handler(doc, i);
2603 if(FAILED(hres))
2604 return hres;
2608 return S_OK;
2611 static inline EventTarget *impl_from_IEventTarget(IEventTarget *iface)
2613 return CONTAINING_RECORD(iface, EventTarget, IEventTarget_iface);
2616 static HRESULT WINAPI EventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv)
2618 EventTarget *This = impl_from_IEventTarget(iface);
2619 return IDispatchEx_QueryInterface(&This->dispex.IDispatchEx_iface, riid, ppv);
2622 static ULONG WINAPI EventTarget_AddRef(IEventTarget *iface)
2624 EventTarget *This = impl_from_IEventTarget(iface);
2625 return IDispatchEx_AddRef(&This->dispex.IDispatchEx_iface);
2628 static ULONG WINAPI EventTarget_Release(IEventTarget *iface)
2630 EventTarget *This = impl_from_IEventTarget(iface);
2631 return IDispatchEx_Release(&This->dispex.IDispatchEx_iface);
2634 static HRESULT WINAPI EventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo)
2636 EventTarget *This = impl_from_IEventTarget(iface);
2637 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2640 static HRESULT WINAPI EventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo,
2641 LCID lcid, ITypeInfo **ppTInfo)
2643 EventTarget *This = impl_from_IEventTarget(iface);
2644 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
2647 static HRESULT WINAPI EventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames,
2648 UINT cNames, LCID lcid, DISPID *rgDispId)
2650 EventTarget *This = impl_from_IEventTarget(iface);
2651 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid,
2652 rgszNames, cNames, lcid, rgDispId);
2655 static HRESULT WINAPI EventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember,
2656 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
2657 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
2659 EventTarget *This = impl_from_IEventTarget(iface);
2660 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember,
2661 riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
2664 static HRESULT WINAPI EventTarget_addEventListener(IEventTarget *iface, BSTR type,
2665 IDispatch *function, VARIANT_BOOL capture)
2667 EventTarget *This = impl_from_IEventTarget(iface);
2668 listener_type_t listener_type = capture ? LISTENER_TYPE_CAPTURE : LISTENER_TYPE_BUBBLE;
2669 listener_container_t *container;
2670 event_listener_t *listener;
2672 TRACE("(%p)->(%s %p %x)\n", This, debugstr_w(type), function, capture);
2674 container = get_listener_container(This, type, TRUE);
2675 if(!container)
2676 return E_OUTOFMEMORY;
2678 /* check for duplicates */
2679 LIST_FOR_EACH_ENTRY(listener, &container->listeners, event_listener_t, entry) {
2680 if(listener->type == listener_type && listener->function == function)
2681 return S_OK;
2684 listener = heap_alloc(sizeof(*listener));
2685 if(!listener)
2686 return E_OUTOFMEMORY;
2688 listener->type = listener_type;
2689 IDispatch_AddRef(listener->function = function);
2690 list_add_tail(&container->listeners, &listener->entry);
2691 return S_OK;
2694 static HRESULT WINAPI EventTarget_removeEventListener(IEventTarget *iface, BSTR type,
2695 IDispatch *listener, VARIANT_BOOL capture)
2697 EventTarget *This = impl_from_IEventTarget(iface);
2699 TRACE("(%p)->(%s %p %x)\n", This, debugstr_w(type), listener, capture);
2701 remove_event_listener(This, type, capture ? LISTENER_TYPE_CAPTURE : LISTENER_TYPE_BUBBLE, listener);
2702 return S_OK;
2705 static HRESULT WINAPI EventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event_iface, VARIANT_BOOL *result)
2707 EventTarget *This = impl_from_IEventTarget(iface);
2708 DOMEvent *event = unsafe_impl_from_IDOMEvent(event_iface);
2710 TRACE("(%p)->(%p %p)\n", This, event, result);
2712 if(!event) {
2713 WARN("Invalid event\n");
2714 return E_INVALIDARG;
2717 return dispatch_event_object(This, event, DISPATCH_STANDARD, result);
2720 static HRESULT IEventTarget_addEventListener_hook(DispatchEx *dispex, LCID lcid, WORD flags,
2721 DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
2723 /* If only two arguments were given, implicitly set capture to false */
2724 if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) {
2725 VARIANT args[3];
2726 DISPPARAMS new_dp = {args, NULL, 3, 0};
2727 V_VT(args) = VT_BOOL;
2728 V_BOOL(args) = VARIANT_FALSE;
2729 args[1] = dp->rgvarg[0];
2730 args[2] = dp->rgvarg[1];
2732 TRACE("implicit capture\n");
2734 return IDispatchEx_InvokeEx(&dispex->IDispatchEx_iface, DISPID_IEVENTTARGET_ADDEVENTLISTENER,
2735 lcid, flags, &new_dp, res, ei, caller);
2738 return S_FALSE; /* fallback to default */
2741 static HRESULT IEventTarget_removeEventListener_hook(DispatchEx *dispex, LCID lcid, WORD flags,
2742 DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
2744 /* If only two arguments were given, implicitly set capture to false */
2745 if((flags & DISPATCH_METHOD) && dp->cArgs == 2 && !dp->cNamedArgs) {
2746 VARIANT args[3];
2747 DISPPARAMS new_dp = {args, NULL, 3, 0};
2748 V_VT(args) = VT_BOOL;
2749 V_BOOL(args) = VARIANT_FALSE;
2750 args[1] = dp->rgvarg[0];
2751 args[2] = dp->rgvarg[1];
2753 TRACE("implicit capture\n");
2755 return IDispatchEx_InvokeEx(&dispex->IDispatchEx_iface, DISPID_IEVENTTARGET_REMOVEEVENTLISTENER,
2756 lcid, flags, &new_dp, res, ei, caller);
2759 return S_FALSE; /* fallback to default */
2762 static const IEventTargetVtbl EventTargetVtbl = {
2763 EventTarget_QueryInterface,
2764 EventTarget_AddRef,
2765 EventTarget_Release,
2766 EventTarget_GetTypeInfoCount,
2767 EventTarget_GetTypeInfo,
2768 EventTarget_GetIDsOfNames,
2769 EventTarget_Invoke,
2770 EventTarget_addEventListener,
2771 EventTarget_removeEventListener,
2772 EventTarget_dispatchEvent
2775 #define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
2777 static BOOL use_event_quirks(EventTarget *event_target)
2779 if(event_target->IEventTarget_iface.lpVtbl == DELAY_INIT_VTBL) {
2780 event_target->IEventTarget_iface.lpVtbl =
2781 dispex_compat_mode(&event_target->dispex) >= COMPAT_MODE_IE9
2782 ? &EventTargetVtbl : NULL;
2784 return !event_target->IEventTarget_iface.lpVtbl;
2787 HRESULT EventTarget_QI(EventTarget *event_target, REFIID riid, void **ppv)
2789 if(IsEqualGUID(riid, &IID_IEventTarget)) {
2790 if(use_event_quirks(event_target)) {
2791 WARN("IEventTarget queried, but not supported by in document mode\n");
2792 *ppv = NULL;
2793 return E_NOINTERFACE;
2795 IEventTarget_AddRef(&event_target->IEventTarget_iface);
2796 *ppv = &event_target->IEventTarget_iface;
2797 return S_OK;
2800 if(dispex_query_interface(&event_target->dispex, riid, ppv))
2801 return *ppv ? S_OK : E_NOINTERFACE;
2803 WARN("(%p)->(%s %p)\n", event_target, debugstr_mshtml_guid(riid), ppv);
2804 *ppv = NULL;
2805 return E_NOINTERFACE;
2808 void EventTarget_init_dispex_info(dispex_data_t *dispex_info, compat_mode_t compat_mode)
2810 static const dispex_hook_t IEventTarget_hooks[] = {
2811 {DISPID_IEVENTTARGET_ADDEVENTLISTENER, IEventTarget_addEventListener_hook},
2812 {DISPID_IEVENTTARGET_REMOVEEVENTLISTENER, IEventTarget_removeEventListener_hook},
2813 {DISPID_UNKNOWN}
2816 if(compat_mode >= COMPAT_MODE_IE9)
2817 dispex_info_add_interface(dispex_info, IEventTarget_tid, IEventTarget_hooks);
2820 static int event_id_cmp(const void *key, const struct wine_rb_entry *entry)
2822 return strcmpW(key, WINE_RB_ENTRY_VALUE(entry, listener_container_t, entry)->type);
2825 void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_data_t *dispex_data,
2826 compat_mode_t compat_mode)
2828 init_dispex_with_compat_mode(&event_target->dispex, outer, dispex_data, compat_mode);
2829 wine_rb_init(&event_target->handler_map, event_id_cmp);
2832 * IEventTarget is supported by the object or not depending on compatibility mode.
2833 * We use NULL vtbl for objects in compatibility mode not supporting the interface.
2834 * For targets that don't know compatibility mode at creation time, we set vtbl
2835 * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
2836 * when it's needed.
2838 if(compat_mode == COMPAT_MODE_QUIRKS && dispex_data->vtbl && dispex_data->vtbl->get_compat_mode)
2839 event_target->IEventTarget_iface.lpVtbl = DELAY_INIT_VTBL;
2840 else if(compat_mode < COMPAT_MODE_IE9)
2841 event_target->IEventTarget_iface.lpVtbl = NULL;
2842 else
2843 event_target->IEventTarget_iface.lpVtbl = &EventTargetVtbl;
2846 void release_event_target(EventTarget *event_target)
2848 listener_container_t *iter, *iter2;
2850 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter, iter2, &event_target->handler_map, listener_container_t, entry) {
2851 while(!list_empty(&iter->listeners)) {
2852 event_listener_t *listener = LIST_ENTRY(list_head(&iter->listeners), event_listener_t, entry);
2853 if(listener->function)
2854 IDispatch_Release(listener->function);
2855 list_remove(&listener->entry);
2856 heap_free(listener);
2858 heap_free(iter);