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
30 #include "mshtml_private.h"
31 #include "htmlevent.h"
32 #include "htmlscript.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml
);
39 struct wine_rb_entry entry
;
41 IDispatch
*handler_prop
;
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 HTMLEventsW
[] = {'H','T','M','L','E','v','e','n','t','s',0};
83 static const WCHAR KeyboardEventW
[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
84 static const WCHAR MouseEventW
[] = {'M','o','u','s','e','E','v','e','n','t',0};
93 static const WCHAR
*event_types
[] = {
107 #define EVENT_DEFAULTLISTENER 0x0001
108 #define EVENT_BUBBLE 0x0002
109 #define EVENT_FORWARDBODY 0x0004
110 #define EVENT_BIND_TO_BODY 0x0008
111 #define EVENT_CANCELABLE 0x0010
112 #define EVENT_HASDEFAULTHANDLERS 0x0020
113 #define EVENT_FIXME 0x0040
115 static const event_info_t event_info
[] = {
116 {abortW
, EVENTT_NONE
, DISPID_EVMETH_ONABORT
,
118 {beforeactivateW
, EVENTT_NONE
, DISPID_EVMETH_ONBEFOREACTIVATE
,
120 {beforeunloadW
, EVENTT_NONE
, DISPID_EVMETH_ONBEFOREUNLOAD
,
121 EVENT_DEFAULTLISTENER
|EVENT_FORWARDBODY
},
122 {blurW
, EVENTT_HTML
, DISPID_EVMETH_ONBLUR
,
123 EVENT_DEFAULTLISTENER
},
124 {changeW
, EVENTT_HTML
, DISPID_EVMETH_ONCHANGE
,
125 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
126 {clickW
, EVENTT_MOUSE
, DISPID_EVMETH_ONCLICK
,
127 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
|EVENT_HASDEFAULTHANDLERS
},
128 {contextmenuW
, EVENTT_MOUSE
, DISPID_EVMETH_ONCONTEXTMENU
,
129 EVENT_BUBBLE
|EVENT_CANCELABLE
},
130 {dataavailableW
, EVENTT_NONE
, DISPID_EVMETH_ONDATAAVAILABLE
,
132 {dblclickW
, EVENTT_MOUSE
, DISPID_EVMETH_ONDBLCLICK
,
133 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
},
134 {dragW
, EVENTT_MOUSE
, DISPID_EVMETH_ONDRAG
,
135 EVENT_FIXME
|EVENT_CANCELABLE
},
136 {dragstartW
, EVENTT_MOUSE
, DISPID_EVMETH_ONDRAGSTART
,
137 EVENT_FIXME
|EVENT_CANCELABLE
},
138 {errorW
, EVENTT_NONE
, DISPID_EVMETH_ONERROR
,
140 {focusW
, EVENTT_HTML
, DISPID_EVMETH_ONFOCUS
,
141 EVENT_DEFAULTLISTENER
},
142 {focusinW
, EVENTT_HTML
, DISPID_EVMETH_ONFOCUSIN
,
144 {focusoutW
, EVENTT_HTML
, DISPID_EVMETH_ONFOCUSOUT
,
146 {helpW
, EVENTT_KEY
, DISPID_EVMETH_ONHELP
,
147 EVENT_BUBBLE
|EVENT_CANCELABLE
},
148 {keydownW
, EVENTT_KEY
, DISPID_EVMETH_ONKEYDOWN
,
149 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_HASDEFAULTHANDLERS
},
150 {keypressW
, EVENTT_KEY
, DISPID_EVMETH_ONKEYPRESS
,
151 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
152 {keyupW
, EVENTT_KEY
, DISPID_EVMETH_ONKEYUP
,
153 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
154 {loadW
, EVENTT_HTML
, DISPID_EVMETH_ONLOAD
,
156 {messageW
, EVENTT_NONE
, DISPID_EVMETH_ONMESSAGE
,
157 EVENT_FORWARDBODY
/* FIXME: remove when we get the target right */ },
158 {mousedownW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEDOWN
,
159 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
},
160 {mousemoveW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEMOVE
,
161 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
162 {mouseoutW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEOUT
,
163 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
164 {mouseoverW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEOVER
,
165 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
166 {mouseupW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEUP
,
167 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
168 {mousewheelW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEWHEEL
,
170 {pasteW
, EVENTT_NONE
, DISPID_EVMETH_ONPASTE
,
172 {readystatechangeW
, EVENTT_NONE
, DISPID_EVMETH_ONREADYSTATECHANGE
,
174 {resizeW
, EVENTT_NONE
, DISPID_EVMETH_ONRESIZE
,
175 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
176 {scrollW
, EVENTT_HTML
, DISPID_EVMETH_ONSCROLL
,
177 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
178 {selectionchangeW
, EVENTT_NONE
, DISPID_EVMETH_ONSELECTIONCHANGE
,
180 {selectstartW
, EVENTT_MOUSE
, DISPID_EVMETH_ONSELECTSTART
,
182 {submitW
, EVENTT_HTML
, DISPID_EVMETH_ONSUBMIT
,
183 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
|EVENT_HASDEFAULTHANDLERS
},
184 {unloadW
, EVENTT_HTML
, DISPID_EVMETH_ONUNLOAD
,
188 static BOOL
use_event_quirks(EventTarget
*);
190 eventid_t
str_to_eid(LPCWSTR str
)
194 for(i
=0; i
< sizeof(event_info
)/sizeof(event_info
[0]); i
++) {
195 if(!strcmpW(event_info
[i
].name
, str
))
199 ERR("unknown type %s\n", debugstr_w(str
));
203 static eventid_t
attr_to_eid(const WCHAR
*str
)
207 if((str
[0] != 'o' && str
[0] != 'O') || (str
[1] != 'n' && str
[1] != 'N'))
210 for(i
=0; i
< sizeof(event_info
)/sizeof(event_info
[0]); i
++) {
211 if(!strcmpW(event_info
[i
].name
, str
+2))
218 struct HTMLEventObj
{
220 IHTMLEventObj IHTMLEventObj_iface
;
225 const event_info_t
*type
;
226 nsIDOMEvent
*nsevent
;
227 VARIANT return_value
;
228 BOOL prevent_default
;
232 static inline HTMLEventObj
*impl_from_IHTMLEventObj(IHTMLEventObj
*iface
)
234 return CONTAINING_RECORD(iface
, HTMLEventObj
, IHTMLEventObj_iface
);
237 static HRESULT WINAPI
HTMLEventObj_QueryInterface(IHTMLEventObj
*iface
, REFIID riid
, void **ppv
)
239 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
241 TRACE("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
243 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
244 *ppv
= &This
->IHTMLEventObj_iface
;
245 }else if(IsEqualGUID(&IID_IHTMLEventObj
, riid
)) {
246 *ppv
= &This
->IHTMLEventObj_iface
;
247 }else if(dispex_query_interface(&This
->dispex
, riid
, ppv
)) {
248 return *ppv
? S_OK
: E_NOINTERFACE
;
251 WARN("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
252 return E_NOINTERFACE
;
255 IUnknown_AddRef((IUnknown
*)*ppv
);
259 static ULONG WINAPI
HTMLEventObj_AddRef(IHTMLEventObj
*iface
)
261 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
262 LONG ref
= InterlockedIncrement(&This
->ref
);
264 TRACE("(%p) ref=%d\n", This
, ref
);
269 static ULONG WINAPI
HTMLEventObj_Release(IHTMLEventObj
*iface
)
271 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
272 LONG ref
= InterlockedDecrement(&This
->ref
);
274 TRACE("(%p) ref=%d\n", This
, ref
);
278 IHTMLDOMNode_Release(&This
->target
->IHTMLDOMNode_iface
);
280 nsIDOMEvent_Release(This
->nsevent
);
281 release_dispex(&This
->dispex
);
288 static HRESULT WINAPI
HTMLEventObj_GetTypeInfoCount(IHTMLEventObj
*iface
, UINT
*pctinfo
)
290 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
291 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
294 static HRESULT WINAPI
HTMLEventObj_GetTypeInfo(IHTMLEventObj
*iface
, UINT iTInfo
,
295 LCID lcid
, ITypeInfo
**ppTInfo
)
297 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
298 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
301 static HRESULT WINAPI
HTMLEventObj_GetIDsOfNames(IHTMLEventObj
*iface
, REFIID riid
,
302 LPOLESTR
*rgszNames
, UINT cNames
,
303 LCID lcid
, DISPID
*rgDispId
)
305 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
306 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
, rgszNames
, cNames
,
310 static HRESULT WINAPI
HTMLEventObj_Invoke(IHTMLEventObj
*iface
, DISPID dispIdMember
,
311 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
312 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
314 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
315 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
, riid
, lcid
,
316 wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
319 static HRESULT WINAPI
HTMLEventObj_get_srcElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
321 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
323 TRACE("(%p)->(%p)\n", This
, p
);
327 IHTMLDOMNode_QueryInterface(&This
->target
->IHTMLDOMNode_iface
, &IID_IHTMLElement
, (void**)p
);
331 static HRESULT WINAPI
HTMLEventObj_get_altKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
333 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
334 cpp_bool ret
= FALSE
;
336 TRACE("(%p)->(%p)\n", This
, p
);
339 nsIDOMKeyEvent
*key_event
;
342 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
343 if(NS_SUCCEEDED(nsres
)) {
344 nsIDOMKeyEvent_GetAltKey(key_event
, &ret
);
345 nsIDOMKeyEvent_Release(key_event
);
347 nsIDOMMouseEvent
*mouse_event
;
349 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
350 if(NS_SUCCEEDED(nsres
)) {
351 nsIDOMMouseEvent_GetAltKey(mouse_event
, &ret
);
352 nsIDOMMouseEvent_Release(mouse_event
);
357 *p
= ret
? VARIANT_TRUE
: VARIANT_FALSE
;
361 static HRESULT WINAPI
HTMLEventObj_get_ctrlKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
363 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
364 cpp_bool ret
= FALSE
;
366 TRACE("(%p)->(%p)\n", This
, p
);
369 nsIDOMKeyEvent
*key_event
;
372 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
373 if(NS_SUCCEEDED(nsres
)) {
374 nsIDOMKeyEvent_GetCtrlKey(key_event
, &ret
);
375 nsIDOMKeyEvent_Release(key_event
);
377 nsIDOMMouseEvent
*mouse_event
;
379 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
380 if(NS_SUCCEEDED(nsres
)) {
381 nsIDOMMouseEvent_GetCtrlKey(mouse_event
, &ret
);
382 nsIDOMMouseEvent_Release(mouse_event
);
387 *p
= ret
? VARIANT_TRUE
: VARIANT_FALSE
;
391 static HRESULT WINAPI
HTMLEventObj_get_shiftKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
393 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
394 cpp_bool ret
= FALSE
;
396 TRACE("(%p)->(%p)\n", This
, p
);
399 nsIDOMKeyEvent
*key_event
;
402 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
403 if(NS_SUCCEEDED(nsres
)) {
404 nsIDOMKeyEvent_GetShiftKey(key_event
, &ret
);
405 nsIDOMKeyEvent_Release(key_event
);
407 nsIDOMMouseEvent
*mouse_event
;
409 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
410 if(NS_SUCCEEDED(nsres
)) {
411 nsIDOMMouseEvent_GetShiftKey(mouse_event
, &ret
);
412 nsIDOMMouseEvent_Release(mouse_event
);
417 *p
= ret
? VARIANT_TRUE
: VARIANT_FALSE
;
421 static HRESULT WINAPI
HTMLEventObj_put_returnValue(IHTMLEventObj
*iface
, VARIANT v
)
423 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
425 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&v
));
427 if(V_VT(&v
) != VT_BOOL
) {
428 FIXME("unsupported value %s\n", debugstr_variant(&v
));
429 return DISP_E_BADVARTYPE
;
432 This
->return_value
= v
;
434 This
->prevent_default
= TRUE
;
438 static HRESULT WINAPI
HTMLEventObj_get_returnValue(IHTMLEventObj
*iface
, VARIANT
*p
)
440 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
442 TRACE("(%p)->(%p)\n", This
, p
);
445 return VariantCopy(p
, &This
->return_value
);
448 static HRESULT WINAPI
HTMLEventObj_put_cancelBubble(IHTMLEventObj
*iface
, VARIANT_BOOL v
)
450 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
452 TRACE("(%p)->(%x)\n", This
, v
);
454 This
->cancel_bubble
= !!v
;
458 static HRESULT WINAPI
HTMLEventObj_get_cancelBubble(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
460 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
462 TRACE("(%p)->(%p)\n", This
, p
);
464 *p
= This
->cancel_bubble
? VARIANT_TRUE
: VARIANT_FALSE
;
468 static HRESULT WINAPI
HTMLEventObj_get_fromElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
470 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
472 FIXME("(%p)->(%p)\n", This
, p
);
478 static HRESULT WINAPI
HTMLEventObj_get_toElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
480 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
482 FIXME("(%p)->(%p)\n", This
, p
);
488 static HRESULT WINAPI
HTMLEventObj_put_keyCode(IHTMLEventObj
*iface
, LONG v
)
490 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
491 FIXME("(%p)->(%d)\n", This
, v
);
495 static HRESULT WINAPI
HTMLEventObj_get_keyCode(IHTMLEventObj
*iface
, LONG
*p
)
497 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
500 TRACE("(%p)->(%p)\n", This
, p
);
503 nsIDOMKeyEvent
*key_event
;
506 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
507 if(NS_SUCCEEDED(nsres
)) {
508 nsIDOMKeyEvent_GetKeyCode(key_event
, &key_code
);
509 nsIDOMKeyEvent_Release(key_event
);
517 static HRESULT WINAPI
HTMLEventObj_get_button(IHTMLEventObj
*iface
, LONG
*p
)
519 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
522 TRACE("(%p)->(%p)\n", This
, p
);
525 nsIDOMMouseEvent
*mouse_event
;
528 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
529 if(NS_SUCCEEDED(nsres
)) {
530 nsIDOMMouseEvent_GetButton(mouse_event
, &button
);
531 nsIDOMMouseEvent_Release(mouse_event
);
539 static HRESULT WINAPI
HTMLEventObj_get_type(IHTMLEventObj
*iface
, BSTR
*p
)
541 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
543 TRACE("(%p)->(%p)\n", This
, p
);
550 *p
= SysAllocString(This
->type
->name
);
551 return *p
? S_OK
: E_OUTOFMEMORY
;
554 static HRESULT WINAPI
HTMLEventObj_get_qualifier(IHTMLEventObj
*iface
, BSTR
*p
)
556 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
558 FIXME("(%p)->(%p)\n", This
, p
);
564 static HRESULT WINAPI
HTMLEventObj_get_reason(IHTMLEventObj
*iface
, LONG
*p
)
566 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
568 FIXME("(%p)->(%p)\n", This
, p
);
574 static HRESULT WINAPI
HTMLEventObj_get_x(IHTMLEventObj
*iface
, LONG
*p
)
576 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
579 TRACE("(%p)->(%p)\n", This
, p
);
582 nsIDOMUIEvent
*ui_event
;
585 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMUIEvent
, (void**)&ui_event
);
586 if(NS_SUCCEEDED(nsres
)) {
587 /* NOTE: pageX is not exactly right here. */
588 nsres
= nsIDOMUIEvent_GetPageX(ui_event
, &x
);
589 assert(nsres
== NS_OK
);
590 nsIDOMUIEvent_Release(ui_event
);
598 static HRESULT WINAPI
HTMLEventObj_get_y(IHTMLEventObj
*iface
, LONG
*p
)
600 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
603 TRACE("(%p)->(%p)\n", This
, p
);
606 nsIDOMUIEvent
*ui_event
;
609 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMUIEvent
, (void**)&ui_event
);
610 if(NS_SUCCEEDED(nsres
)) {
611 /* NOTE: pageY is not exactly right here. */
612 nsres
= nsIDOMUIEvent_GetPageY(ui_event
, &y
);
613 assert(nsres
== NS_OK
);
614 nsIDOMUIEvent_Release(ui_event
);
622 static HRESULT WINAPI
HTMLEventObj_get_clientX(IHTMLEventObj
*iface
, LONG
*p
)
624 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
627 TRACE("(%p)->(%p)\n", This
, p
);
630 nsIDOMMouseEvent
*mouse_event
;
633 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
634 if(NS_SUCCEEDED(nsres
)) {
635 nsIDOMMouseEvent_GetClientX(mouse_event
, &x
);
636 nsIDOMMouseEvent_Release(mouse_event
);
644 static HRESULT WINAPI
HTMLEventObj_get_clientY(IHTMLEventObj
*iface
, LONG
*p
)
646 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
649 TRACE("(%p)->(%p)\n", This
, p
);
652 nsIDOMMouseEvent
*mouse_event
;
655 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
656 if(NS_SUCCEEDED(nsres
)) {
657 nsIDOMMouseEvent_GetClientY(mouse_event
, &y
);
658 nsIDOMMouseEvent_Release(mouse_event
);
666 static HRESULT WINAPI
HTMLEventObj_get_offsetX(IHTMLEventObj
*iface
, LONG
*p
)
668 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
670 FIXME("(%p)->(%p)\n", This
, p
);
676 static HRESULT WINAPI
HTMLEventObj_get_offsetY(IHTMLEventObj
*iface
, LONG
*p
)
678 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
680 FIXME("(%p)->(%p)\n", This
, p
);
686 static HRESULT WINAPI
HTMLEventObj_get_screenX(IHTMLEventObj
*iface
, LONG
*p
)
688 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
691 TRACE("(%p)->(%p)\n", This
, p
);
694 nsIDOMMouseEvent
*mouse_event
;
697 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
698 if(NS_SUCCEEDED(nsres
)) {
699 nsIDOMMouseEvent_GetScreenX(mouse_event
, &x
);
700 nsIDOMMouseEvent_Release(mouse_event
);
708 static HRESULT WINAPI
HTMLEventObj_get_screenY(IHTMLEventObj
*iface
, LONG
*p
)
710 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
713 TRACE("(%p)->(%p)\n", This
, p
);
716 nsIDOMMouseEvent
*mouse_event
;
719 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
720 if(NS_SUCCEEDED(nsres
)) {
721 nsIDOMMouseEvent_GetScreenY(mouse_event
, &y
);
722 nsIDOMMouseEvent_Release(mouse_event
);
730 static HRESULT WINAPI
HTMLEventObj_get_srcFilter(IHTMLEventObj
*iface
, IDispatch
**p
)
732 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
734 FIXME("(%p)->(%p)\n", This
, p
);
740 static const IHTMLEventObjVtbl HTMLEventObjVtbl
= {
741 HTMLEventObj_QueryInterface
,
743 HTMLEventObj_Release
,
744 HTMLEventObj_GetTypeInfoCount
,
745 HTMLEventObj_GetTypeInfo
,
746 HTMLEventObj_GetIDsOfNames
,
748 HTMLEventObj_get_srcElement
,
749 HTMLEventObj_get_altKey
,
750 HTMLEventObj_get_ctrlKey
,
751 HTMLEventObj_get_shiftKey
,
752 HTMLEventObj_put_returnValue
,
753 HTMLEventObj_get_returnValue
,
754 HTMLEventObj_put_cancelBubble
,
755 HTMLEventObj_get_cancelBubble
,
756 HTMLEventObj_get_fromElement
,
757 HTMLEventObj_get_toElement
,
758 HTMLEventObj_put_keyCode
,
759 HTMLEventObj_get_keyCode
,
760 HTMLEventObj_get_button
,
761 HTMLEventObj_get_type
,
762 HTMLEventObj_get_qualifier
,
763 HTMLEventObj_get_reason
,
766 HTMLEventObj_get_clientX
,
767 HTMLEventObj_get_clientY
,
768 HTMLEventObj_get_offsetX
,
769 HTMLEventObj_get_offsetY
,
770 HTMLEventObj_get_screenX
,
771 HTMLEventObj_get_screenY
,
772 HTMLEventObj_get_srcFilter
775 static inline HTMLEventObj
*unsafe_impl_from_IHTMLEventObj(IHTMLEventObj
*iface
)
777 return iface
->lpVtbl
== &HTMLEventObjVtbl
? impl_from_IHTMLEventObj(iface
) : NULL
;
780 static const tid_t HTMLEventObj_iface_tids
[] = {
785 static dispex_static_data_t HTMLEventObj_dispex
= {
788 HTMLEventObj_iface_tids
791 static HTMLEventObj
*create_event(void)
795 ret
= heap_alloc_zero(sizeof(*ret
));
799 ret
->IHTMLEventObj_iface
.lpVtbl
= &HTMLEventObjVtbl
;
802 init_dispex(&ret
->dispex
, (IUnknown
*)&ret
->IHTMLEventObj_iface
, &HTMLEventObj_dispex
);
807 static HRESULT
set_event_info(HTMLEventObj
*event
, HTMLDOMNode
*target
, eventid_t eid
, nsIDOMEvent
*nsevent
)
809 event
->type
= event_info
+eid
;
810 event
->nsevent
= nsevent
;
813 nsIDOMEvent_AddRef(nsevent
);
814 }else if(event_types
[event_info
[eid
].type
]) {
818 nsAString_InitDepend(&type_str
, event_types
[event_info
[eid
].type
]);
819 nsres
= nsIDOMHTMLDocument_CreateEvent(target
->doc
->nsdoc
, &type_str
, &event
->nsevent
);
820 nsAString_Finish(&type_str
);
821 if(NS_FAILED(nsres
)) {
822 ERR("Could not create event: %08x\n", nsres
);
827 event
->target
= target
;
829 IHTMLDOMNode_AddRef(&target
->IHTMLDOMNode_iface
);
833 HRESULT
create_event_obj(IHTMLEventObj
**ret
)
837 event
= create_event();
839 return E_OUTOFMEMORY
;
841 *ret
= &event
->IHTMLEventObj_iface
;
845 static handler_vector_t
*get_handler_vector(EventTarget
*event_target
, eventid_t eid
, BOOL alloc
)
847 const dispex_static_data_vtbl_t
*vtbl
;
848 handler_vector_t
*handler_vector
;
849 struct wine_rb_entry
*entry
;
851 vtbl
= dispex_get_vtbl(&event_target
->dispex
);
852 if(vtbl
->get_event_target
)
853 event_target
= vtbl
->get_event_target(&event_target
->dispex
);
855 entry
= wine_rb_get(&event_target
->handler_map
, (const void*)eid
);
857 return WINE_RB_ENTRY_VALUE(entry
, handler_vector_t
, entry
);
861 handler_vector
= heap_alloc_zero(sizeof(*handler_vector
));
865 handler_vector
->event_id
= eid
;
866 vtbl
= dispex_get_vtbl(&event_target
->dispex
);
868 vtbl
->bind_event(&event_target
->dispex
, eid
);
870 FIXME("Unsupported event binding on target %p\n", event_target
);
872 wine_rb_put(&event_target
->handler_map
, (const void*)eid
, &handler_vector
->entry
);
873 return handler_vector
;
876 static HRESULT
call_disp_func(IDispatch
*disp
, DISPPARAMS
*dp
, VARIANT
*retv
)
882 memset(&ei
, 0, sizeof(ei
));
884 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
885 if(SUCCEEDED(hres
)) {
886 hres
= IDispatchEx_InvokeEx(dispex
, 0, GetUserDefaultLCID(), DISPATCH_METHOD
, dp
, retv
, &ei
, NULL
);
887 IDispatchEx_Release(dispex
);
889 TRACE("Could not get IDispatchEx interface: %08x\n", hres
);
890 hres
= IDispatch_Invoke(disp
, 0, &IID_NULL
, GetUserDefaultLCID(), DISPATCH_METHOD
,
891 dp
, retv
, &ei
, NULL
);
897 static HRESULT
call_cp_func(IDispatch
*disp
, DISPID dispid
, HTMLEventObj
*event_obj
, VARIANT
*retv
)
899 DISPPARAMS dp
= {NULL
,NULL
,0,0};
905 V_VT(&event_arg
) = VT_DISPATCH
;
906 V_DISPATCH(&event_arg
) = (IDispatch
*)&event_obj
->IHTMLEventObj_iface
;
907 dp
.rgvarg
= &event_arg
;
911 memset(&ei
, 0, sizeof(ei
));
912 return IDispatch_Invoke(disp
, dispid
, &IID_NULL
, 0, DISPATCH_METHOD
, &dp
, retv
, &ei
, &argerr
);
915 static BOOL
is_cp_event(cp_static_data_t
*data
, DISPID dispid
)
924 hres
= get_dispids(data
->tid
, &data
->id_cnt
, &data
->ids
);
930 max
= data
->id_cnt
-1;
933 if(data
->ids
[i
] == dispid
)
936 if(data
->ids
[i
] < dispid
)
945 void call_event_handlers(HTMLDocumentNode
*doc
, HTMLEventObj
*event_obj
, EventTarget
*event_target
,
946 ConnectionPointContainer
*cp_container
, eventid_t eid
, IDispatch
*this_obj
)
948 handler_vector_t
*handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
949 const BOOL cancelable
= event_info
[eid
].flags
& EVENT_CANCELABLE
;
953 if(handler_vector
&& handler_vector
->handler_prop
) {
954 DISPID named_arg
= DISPID_THIS
;
956 DISPPARAMS dp
= {&arg
, &named_arg
, 1, 1};
958 if(!use_event_quirks(event_target
))
959 FIXME("Event argument not supported\n");
961 V_VT(&arg
) = VT_DISPATCH
;
962 V_DISPATCH(&arg
) = this_obj
;
965 TRACE("%s >>>\n", debugstr_w(event_info
[eid
].name
));
966 hres
= call_disp_func(handler_vector
->handler_prop
, &dp
, &v
);
968 TRACE("%s <<< %s\n", debugstr_w(event_info
[eid
].name
), debugstr_variant(&v
));
971 if(V_VT(&v
) == VT_BOOL
) {
973 event_obj
->prevent_default
= TRUE
;
974 }else if(V_VT(&v
) != VT_EMPTY
) {
975 FIXME("unhandled result %s\n", debugstr_variant(&v
));
980 WARN("%s <<< %08x\n", debugstr_w(event_info
[eid
].name
), hres
);
984 if(handler_vector
&& handler_vector
->handler_cnt
) {
986 DISPPARAMS dp
= {&arg
, NULL
, 1, 0};
989 V_VT(&arg
) = VT_DISPATCH
;
990 V_DISPATCH(&arg
) = (IDispatch
*)&event_obj
->dispex
.IDispatchEx_iface
;
992 i
= handler_vector
->handler_cnt
;
994 if(handler_vector
->handlers
[i
]) {
997 TRACE("%s [%d] >>>\n", debugstr_w(event_info
[eid
].name
), i
);
998 hres
= call_disp_func(handler_vector
->handlers
[i
], &dp
, &v
);
1000 TRACE("%s [%d] <<<\n", debugstr_w(event_info
[eid
].name
), i
);
1003 if(V_VT(&v
) == VT_BOOL
) {
1005 event_obj
->prevent_default
= TRUE
;
1006 }else if(V_VT(&v
) != VT_EMPTY
) {
1007 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1012 WARN("%s [%d] <<< %08x\n", debugstr_w(event_info
[eid
].name
), i
, hres
);
1019 * NOTE: CP events may require doc_obj reference, which we don't own. We make sure that
1020 * it's safe to call event handler by checking nsevent_listener, which is NULL for
1021 * detached documents.
1023 if(cp_container
&& cp_container
->forward_container
)
1024 cp_container
= cp_container
->forward_container
;
1025 if(cp_container
&& cp_container
->cps
&& doc
->nsevent_listener
) {
1026 ConnectionPoint
*cp
;
1029 for(j
=0; cp_container
->cp_entries
[j
].riid
; j
++) {
1030 cp
= cp_container
->cps
+ j
;
1031 if(!cp
->sinks_size
|| !is_cp_event(cp
->data
, event_info
[eid
].dispid
))
1034 for(i
=0; doc
->nsevent_listener
&& i
< cp
->sinks_size
; i
++) {
1035 if(!cp
->sinks
[i
].disp
)
1038 V_VT(&v
) = VT_EMPTY
;
1040 TRACE("cp %s [%u] >>>\n", debugstr_w(event_info
[eid
].name
), i
);
1041 hres
= call_cp_func(cp
->sinks
[i
].disp
, event_info
[eid
].dispid
,
1042 cp
->data
->pass_event_arg
? event_obj
: NULL
, &v
);
1044 TRACE("cp %s [%u] <<<\n", debugstr_w(event_info
[eid
].name
), i
);
1047 if(V_VT(&v
) == VT_BOOL
) {
1049 event_obj
->prevent_default
= TRUE
;
1050 }else if(V_VT(&v
) != VT_EMPTY
) {
1051 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1056 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event_info
[eid
].name
), i
, hres
);
1060 if(!doc
->nsevent_listener
)
1066 static void fire_event_obj(HTMLDocumentNode
*doc
, eventid_t eid
, HTMLEventObj
*event_obj
,
1067 HTMLDOMNode
*target
, IDispatch
*script_this
)
1069 IHTMLEventObj
*prev_event
;
1070 nsIDOMNode
*parent
, *nsnode
;
1071 BOOL prevent_default
= FALSE
;
1072 HTMLInnerWindow
*window
;
1078 TRACE("(%p) %s\n", doc
, debugstr_w(event_info
[eid
].name
));
1080 window
= doc
->window
;
1082 WARN("NULL window\n");
1086 htmldoc_addref(&doc
->basedoc
);
1088 prev_event
= window
->event
;
1089 window
->event
= event_obj
? &event_obj
->IHTMLEventObj_iface
: NULL
;
1091 nsIDOMNode_GetNodeType(target
->nsnode
, &node_type
);
1092 nsnode
= target
->nsnode
;
1093 nsIDOMNode_AddRef(nsnode
);
1098 hres
= get_node(doc
, nsnode
, FALSE
, &node
);
1099 if(SUCCEEDED(hres
) && node
) {
1100 call_event_handlers(doc
, event_obj
, &node
->event_target
, node
->cp_container
, eid
,
1101 script_this
? script_this
: (IDispatch
*)&node
->IHTMLDOMNode_iface
);
1105 if(!(event_info
[eid
].flags
& EVENT_BUBBLE
) || (event_obj
&& event_obj
->cancel_bubble
))
1108 nsIDOMNode_GetParentNode(nsnode
, &parent
);
1109 nsIDOMNode_Release(nsnode
);
1114 nsIDOMNode_GetNodeType(nsnode
, &node_type
);
1115 }while(node_type
== ELEMENT_NODE
);
1117 if(!(event_info
[eid
].flags
& EVENT_BUBBLE
) || (event_obj
&& event_obj
->cancel_bubble
))
1121 if(event_info
[eid
].flags
& EVENT_FORWARDBODY
) {
1122 nsIDOMHTMLElement
*nsbody
;
1125 nsres
= nsIDOMHTMLDocument_GetBody(doc
->nsdoc
, &nsbody
);
1126 if(NS_SUCCEEDED(nsres
) && nsbody
) {
1127 hres
= get_node(doc
, (nsIDOMNode
*)nsbody
, FALSE
, &node
);
1128 if(SUCCEEDED(hres
) && node
) {
1129 call_event_handlers(doc
, event_obj
, &node
->event_target
, node
->cp_container
, eid
,
1130 script_this
? script_this
: (IDispatch
*)&node
->IHTMLDOMNode_iface
);
1133 nsIDOMHTMLElement_Release(nsbody
);
1135 ERR("Could not get body: %08x\n", nsres
);
1139 call_event_handlers(doc
, event_obj
, &doc
->node
.event_target
, &doc
->basedoc
.cp_container
, eid
,
1140 script_this
? script_this
: (IDispatch
*)&doc
->basedoc
.IHTMLDocument2_iface
);
1144 FIXME("unimplemented node type %d\n", node_type
);
1148 nsIDOMNode_Release(nsnode
);
1150 if(event_obj
&& event_obj
->prevent_default
)
1151 prevent_default
= TRUE
;
1152 window
->event
= prev_event
;
1154 if(!prevent_default
&& (event_info
[eid
].flags
& EVENT_HASDEFAULTHANDLERS
)) {
1155 nsnode
= target
->nsnode
;
1156 nsIDOMNode_AddRef(nsnode
);
1159 hres
= get_node(doc
, nsnode
, TRUE
, &node
);
1164 if(node
->vtbl
->handle_event
)
1165 hres
= node
->vtbl
->handle_event(node
, eid
, event_obj
? event_obj
->nsevent
: NULL
, &prevent_default
);
1167 if(FAILED(hres
) || prevent_default
|| (event_obj
&& event_obj
->cancel_bubble
))
1171 nsres
= nsIDOMNode_GetParentNode(nsnode
, &parent
);
1172 if(NS_FAILED(nsres
))
1175 nsIDOMNode_Release(nsnode
);
1180 nsIDOMNode_Release(nsnode
);
1183 if(prevent_default
&& event_obj
&& event_obj
->nsevent
) {
1184 TRACE("calling PreventDefault\n");
1185 nsIDOMEvent_PreventDefault(event_obj
->nsevent
);
1188 htmldoc_release(&doc
->basedoc
);
1191 void fire_event(HTMLDocumentNode
*doc
, eventid_t eid
, BOOL set_event
, HTMLDOMNode
*target
, nsIDOMEvent
*nsevent
,
1192 IDispatch
*script_this
)
1194 HTMLEventObj
*event_obj
= NULL
;
1198 event_obj
= create_event();
1202 hres
= set_event_info(event_obj
, target
, eid
, nsevent
);
1204 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1209 fire_event_obj(doc
, eid
, event_obj
, target
, script_this
);
1212 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1215 HRESULT
dispatch_event(HTMLDOMNode
*node
, const WCHAR
*event_name
, VARIANT
*event_var
, VARIANT_BOOL
*cancelled
)
1217 HTMLEventObj
*event_obj
= NULL
;
1221 eid
= attr_to_eid(event_name
);
1222 if(eid
== EVENTID_LAST
) {
1223 WARN("unknown event %s\n", debugstr_w(event_name
));
1224 return E_INVALIDARG
;
1227 if(event_var
&& V_VT(event_var
) != VT_EMPTY
&& V_VT(event_var
) != VT_ERROR
) {
1228 if(V_VT(event_var
) != VT_DISPATCH
) {
1229 FIXME("event_var %s not supported\n", debugstr_variant(event_var
));
1233 if(V_DISPATCH(event_var
)) {
1234 IHTMLEventObj
*event_iface
;
1236 hres
= IDispatch_QueryInterface(V_DISPATCH(event_var
), &IID_IHTMLEventObj
, (void**)&event_iface
);
1238 FIXME("No IHTMLEventObj iface\n");
1242 event_obj
= unsafe_impl_from_IHTMLEventObj(event_iface
);
1244 ERR("Not our IHTMLEventObj?\n");
1245 IHTMLEventObj_Release(event_iface
);
1252 hres
= set_event_info(event_obj
, node
, eid
, NULL
);
1254 fire_event_obj(node
->doc
, eid
, event_obj
, node
, NULL
);
1256 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1260 fire_event(node
->doc
, eid
, TRUE
, node
, NULL
, NULL
);
1263 *cancelled
= VARIANT_TRUE
; /* FIXME */
1267 HRESULT
call_fire_event(HTMLDOMNode
*node
, eventid_t eid
)
1271 if(node
->vtbl
->fire_event
) {
1272 BOOL handled
= FALSE
;
1274 hres
= node
->vtbl
->fire_event(node
, eid
, &handled
);
1279 fire_event(node
->doc
, eid
, TRUE
, node
, NULL
, NULL
);
1283 HRESULT
ensure_doc_nsevent_handler(HTMLDocumentNode
*doc
, eventid_t eid
)
1285 nsIDOMNode
*nsnode
= NULL
;
1287 TRACE("%s\n", debugstr_w(event_info
[eid
].name
));
1293 case EVENTID_FOCUSIN
:
1294 doc
->event_vector
[eid
] = TRUE
;
1295 eid
= EVENTID_FOCUS
;
1297 case EVENTID_FOCUSOUT
:
1298 doc
->event_vector
[eid
] = TRUE
;
1305 if(doc
->event_vector
[eid
] || !(event_info
[eid
].flags
& (EVENT_DEFAULTLISTENER
|EVENT_BIND_TO_BODY
)))
1308 if(event_info
[eid
].flags
& EVENT_BIND_TO_BODY
) {
1309 nsnode
= doc
->node
.nsnode
;
1310 nsIDOMNode_AddRef(nsnode
);
1313 doc
->event_vector
[eid
] = TRUE
;
1314 add_nsevent_listener(doc
, nsnode
, event_info
[eid
].name
);
1317 nsIDOMNode_Release(nsnode
);
1321 void detach_events(HTMLDocumentNode
*doc
)
1323 if(doc
->event_vector
) {
1326 for(i
=0; i
< EVENTID_LAST
; i
++) {
1327 if(doc
->event_vector
[i
]) {
1328 detach_nsevent(doc
, event_info
[i
].name
);
1329 doc
->event_vector
[i
] = FALSE
;
1334 release_nsevents(doc
);
1337 static HRESULT
get_event_dispex_ref(EventTarget
*event_target
, eventid_t eid
, BOOL alloc
, VARIANT
**ret
)
1342 strcpyW(buf
+2, event_info
[eid
].name
);
1343 return dispex_get_dprop_ref(&event_target
->dispex
, buf
, alloc
, ret
);
1346 static void remove_event_handler(EventTarget
*event_target
, eventid_t eid
)
1348 handler_vector_t
*handler_vector
;
1352 hres
= get_event_dispex_ref(event_target
, eid
, FALSE
, &store
);
1354 VariantClear(store
);
1356 handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
1357 if(handler_vector
&& handler_vector
->handler_prop
) {
1358 IDispatch_Release(handler_vector
->handler_prop
);
1359 handler_vector
->handler_prop
= NULL
;
1363 static HRESULT
set_event_handler_disp(EventTarget
*event_target
, eventid_t eid
, IDispatch
*disp
)
1365 handler_vector_t
*handler_vector
;
1367 if(event_info
[eid
].flags
& EVENT_FIXME
)
1368 FIXME("unimplemented event %s\n", debugstr_w(event_info
[eid
].name
));
1370 remove_event_handler(event_target
, eid
);
1374 handler_vector
= get_handler_vector(event_target
, eid
, TRUE
);
1376 return E_OUTOFMEMORY
;
1378 if(handler_vector
->handler_prop
)
1379 IDispatch_Release(handler_vector
->handler_prop
);
1381 handler_vector
->handler_prop
= disp
;
1382 IDispatch_AddRef(disp
);
1386 HRESULT
set_event_handler(EventTarget
*event_target
, eventid_t eid
, VARIANT
*var
)
1390 if(use_event_quirks(event_target
)) {
1391 WARN("attempt to set to VT_EMPTY in quirks mode\n");
1396 remove_event_handler(event_target
, eid
);
1400 return set_event_handler_disp(event_target
, eid
, V_DISPATCH(var
));
1406 if(!use_event_quirks(event_target
))
1407 FIXME("Setting to string %s not supported\n", debugstr_w(V_BSTR(var
)));
1410 * Setting event handler to string is a rare case and we don't want to
1411 * complicate nor increase memory of handler_vector_t for that. Instead,
1412 * we store the value in DispatchEx, which can already handle custom
1415 remove_event_handler(event_target
, eid
);
1417 hres
= get_event_dispex_ref(event_target
, eid
, TRUE
, &v
);
1421 V_BSTR(v
) = SysAllocString(V_BSTR(var
));
1423 return E_OUTOFMEMORY
;
1429 FIXME("not handler %s\n", debugstr_variant(var
));
1436 HRESULT
get_event_handler(EventTarget
*event_target
, eventid_t eid
, VARIANT
*var
)
1438 handler_vector_t
*handler_vector
;
1442 hres
= get_event_dispex_ref(event_target
, eid
, FALSE
, &v
);
1443 if(SUCCEEDED(hres
) && V_VT(v
) != VT_EMPTY
) {
1444 V_VT(var
) = VT_EMPTY
;
1445 return VariantCopy(var
, v
);
1448 handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
1449 if(handler_vector
&& handler_vector
->handler_prop
) {
1450 V_VT(var
) = VT_DISPATCH
;
1451 V_DISPATCH(var
) = handler_vector
->handler_prop
;
1452 IDispatch_AddRef(V_DISPATCH(var
));
1454 V_VT(var
) = VT_NULL
;
1460 HRESULT
attach_event(EventTarget
*event_target
, BSTR name
, IDispatch
*disp
, VARIANT_BOOL
*res
)
1462 handler_vector_t
*handler_vector
;
1466 eid
= attr_to_eid(name
);
1467 if(eid
== EVENTID_LAST
) {
1468 WARN("Unknown event\n");
1469 *res
= VARIANT_TRUE
;
1473 if(event_info
[eid
].flags
& EVENT_FIXME
)
1474 FIXME("unimplemented event %s\n", debugstr_w(event_info
[eid
].name
));
1476 handler_vector
= get_handler_vector(event_target
, eid
, TRUE
);
1478 return E_OUTOFMEMORY
;
1480 while(i
< handler_vector
->handler_cnt
&& handler_vector
->handlers
[i
])
1482 if(i
== handler_vector
->handler_cnt
) {
1484 handler_vector
->handlers
= heap_realloc_zero(handler_vector
->handlers
,
1485 (i
+ 1) * sizeof(*handler_vector
->handlers
));
1487 handler_vector
->handlers
= heap_alloc_zero(sizeof(*handler_vector
->handlers
));
1488 if(!handler_vector
->handlers
)
1489 return E_OUTOFMEMORY
;
1490 handler_vector
->handler_cnt
++;
1493 IDispatch_AddRef(disp
);
1494 handler_vector
->handlers
[i
] = disp
;
1496 *res
= VARIANT_TRUE
;
1500 HRESULT
detach_event(EventTarget
*event_target
, BSTR name
, IDispatch
*disp
)
1502 handler_vector_t
*handler_vector
;
1506 eid
= attr_to_eid(name
);
1507 if(eid
== EVENTID_LAST
) {
1508 WARN("Unknown event\n");
1512 handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
1516 for(i
= 0; i
< handler_vector
->handler_cnt
; i
++) {
1517 if(handler_vector
->handlers
[i
] == disp
) {
1518 IDispatch_Release(handler_vector
->handlers
[i
]);
1519 handler_vector
->handlers
[i
] = NULL
;
1526 void bind_target_event(HTMLDocumentNode
*doc
, EventTarget
*event_target
, const WCHAR
*event
, IDispatch
*disp
)
1530 TRACE("(%p %p %s %p)\n", doc
, event_target
, debugstr_w(event
), disp
);
1532 eid
= attr_to_eid(event
);
1533 if(eid
== EVENTID_LAST
) {
1534 WARN("Unsupported event %s\n", debugstr_w(event
));
1538 set_event_handler_disp(event_target
, eid
, disp
);
1541 void update_doc_cp_events(HTMLDocumentNode
*doc
, cp_static_data_t
*cp
)
1545 for(i
=0; i
< EVENTID_LAST
; i
++) {
1546 if((event_info
[i
].flags
& EVENT_DEFAULTLISTENER
) && is_cp_event(cp
, event_info
[i
].dispid
))
1547 ensure_doc_nsevent_handler(doc
, i
);
1551 void check_event_attr(HTMLDocumentNode
*doc
, nsIDOMHTMLElement
*nselem
)
1553 nsIDOMMozNamedAttrMap
*attr_map
;
1554 const PRUnichar
*name
, *value
;
1555 nsAString name_str
, value_str
;
1556 HTMLDOMNode
*node
= NULL
;
1565 nsres
= nsIDOMHTMLElement_HasAttributes(nselem
, &has_attrs
);
1566 if(NS_FAILED(nsres
) || !has_attrs
)
1569 nsres
= nsIDOMHTMLElement_GetAttributes(nselem
, &attr_map
);
1570 if(NS_FAILED(nsres
))
1573 nsres
= nsIDOMMozNamedAttrMap_GetLength(attr_map
, &length
);
1574 assert(nsres
== NS_OK
);
1576 nsAString_Init(&name_str
, NULL
);
1577 nsAString_Init(&value_str
, NULL
);
1579 for(i
= 0; i
< length
; i
++) {
1580 nsres
= nsIDOMMozNamedAttrMap_Item(attr_map
, i
, &attr
);
1581 if(NS_FAILED(nsres
))
1584 nsres
= nsIDOMAttr_GetName(attr
, &name_str
);
1585 if(NS_FAILED(nsres
)) {
1586 nsIDOMAttr_Release(attr
);
1590 nsAString_GetData(&name_str
, &name
);
1591 eid
= attr_to_eid(name
);
1592 if(eid
== EVENTID_LAST
) {
1593 nsIDOMAttr_Release(attr
);
1597 nsres
= nsIDOMAttr_GetValue(attr
, &value_str
);
1598 nsIDOMAttr_Release(attr
);
1599 if(NS_FAILED(nsres
))
1602 nsAString_GetData(&value_str
, &value
);
1606 TRACE("%p.%s = %s\n", nselem
, debugstr_w(name
), debugstr_w(value
));
1608 disp
= script_parse_event(doc
->window
, value
);
1613 hres
= get_node(doc
, (nsIDOMNode
*)nselem
, TRUE
, &node
);
1615 IDispatch_Release(disp
);
1620 set_event_handler_disp(&node
->event_target
, eid
, disp
);
1621 IDispatch_Release(disp
);
1626 nsAString_Finish(&name_str
);
1627 nsAString_Finish(&value_str
);
1628 nsIDOMMozNamedAttrMap_Release(attr_map
);
1631 HRESULT
doc_init_events(HTMLDocumentNode
*doc
)
1636 doc
->event_vector
= heap_alloc_zero(EVENTID_LAST
*sizeof(BOOL
));
1637 if(!doc
->event_vector
)
1638 return E_OUTOFMEMORY
;
1642 for(i
=0; i
< EVENTID_LAST
; i
++) {
1643 if(event_info
[i
].flags
& EVENT_HASDEFAULTHANDLERS
) {
1644 hres
= ensure_doc_nsevent_handler(doc
, i
);
1653 static inline EventTarget
*impl_from_IEventTarget(IEventTarget
*iface
)
1655 return CONTAINING_RECORD(iface
, EventTarget
, IEventTarget_iface
);
1658 static HRESULT WINAPI
EventTarget_QueryInterface(IEventTarget
*iface
, REFIID riid
, void **ppv
)
1660 EventTarget
*This
= impl_from_IEventTarget(iface
);
1661 return IDispatchEx_QueryInterface(&This
->dispex
.IDispatchEx_iface
, riid
, ppv
);
1664 static ULONG WINAPI
EventTarget_AddRef(IEventTarget
*iface
)
1666 EventTarget
*This
= impl_from_IEventTarget(iface
);
1667 return IDispatchEx_AddRef(&This
->dispex
.IDispatchEx_iface
);
1670 static ULONG WINAPI
EventTarget_Release(IEventTarget
*iface
)
1672 EventTarget
*This
= impl_from_IEventTarget(iface
);
1673 return IDispatchEx_Release(&This
->dispex
.IDispatchEx_iface
);
1676 static HRESULT WINAPI
EventTarget_GetTypeInfoCount(IEventTarget
*iface
, UINT
*pctinfo
)
1678 EventTarget
*This
= impl_from_IEventTarget(iface
);
1679 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
1682 static HRESULT WINAPI
EventTarget_GetTypeInfo(IEventTarget
*iface
, UINT iTInfo
,
1683 LCID lcid
, ITypeInfo
**ppTInfo
)
1685 EventTarget
*This
= impl_from_IEventTarget(iface
);
1686 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
1689 static HRESULT WINAPI
EventTarget_GetIDsOfNames(IEventTarget
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
1690 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
1692 EventTarget
*This
= impl_from_IEventTarget(iface
);
1693 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
,
1694 rgszNames
, cNames
, lcid
, rgDispId
);
1697 static HRESULT WINAPI
EventTarget_Invoke(IEventTarget
*iface
, DISPID dispIdMember
,
1698 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1699 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1701 EventTarget
*This
= impl_from_IEventTarget(iface
);
1702 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
,
1703 riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1706 static HRESULT WINAPI
EventTarget_addEventListener(IEventTarget
*iface
, BSTR type
,
1707 IDispatch
*listener
, VARIANT_BOOL capture
)
1709 EventTarget
*This
= impl_from_IEventTarget(iface
);
1710 FIXME("(%p)->(%s %p %x)\n", This
, debugstr_w(type
), listener
, capture
);
1714 static HRESULT WINAPI
EventTarget_removeEventListener(IEventTarget
*iface
, BSTR type
,
1715 IDispatch
*listener
, VARIANT_BOOL capture
)
1717 EventTarget
*This
= impl_from_IEventTarget(iface
);
1718 FIXME("(%p)->(%s %p %x)\n", This
, debugstr_w(type
), listener
, capture
);
1722 static HRESULT WINAPI
EventTarget_dispatchEvent(IEventTarget
*iface
, IDOMEvent
*event
, VARIANT_BOOL
*result
)
1724 EventTarget
*This
= impl_from_IEventTarget(iface
);
1725 FIXME("(%p)->(%p %p)\n", This
, event
, result
);
1729 static const IEventTargetVtbl EventTargetVtbl
= {
1730 EventTarget_QueryInterface
,
1732 EventTarget_Release
,
1733 EventTarget_GetTypeInfoCount
,
1734 EventTarget_GetTypeInfo
,
1735 EventTarget_GetIDsOfNames
,
1737 EventTarget_addEventListener
,
1738 EventTarget_removeEventListener
,
1739 EventTarget_dispatchEvent
1742 #define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
1744 static BOOL
use_event_quirks(EventTarget
*event_target
)
1746 if(event_target
->IEventTarget_iface
.lpVtbl
== DELAY_INIT_VTBL
) {
1747 event_target
->IEventTarget_iface
.lpVtbl
=
1748 dispex_compat_mode(&event_target
->dispex
) >= COMPAT_MODE_IE9
1749 ? &EventTargetVtbl
: NULL
;
1751 return !event_target
->IEventTarget_iface
.lpVtbl
;
1754 HRESULT
EventTarget_QI(EventTarget
*event_target
, REFIID riid
, void **ppv
)
1756 if(IsEqualGUID(riid
, &IID_IEventTarget
)) {
1757 if(use_event_quirks(event_target
)) {
1758 WARN("IEventTarget queried, but not supported by in document mode\n");
1760 return E_NOINTERFACE
;
1762 IEventTarget_AddRef(&event_target
->IEventTarget_iface
);
1763 *ppv
= &event_target
->IEventTarget_iface
;
1767 if(dispex_query_interface(&event_target
->dispex
, riid
, ppv
))
1768 return *ppv
? S_OK
: E_NOINTERFACE
;
1770 WARN("(%p)->(%s %p)\n", event_target
, debugstr_mshtml_guid(riid
), ppv
);
1772 return E_NOINTERFACE
;
1775 static int event_id_cmp(const void *key
, const struct wine_rb_entry
*entry
)
1777 return (INT_PTR
)key
- WINE_RB_ENTRY_VALUE(entry
, handler_vector_t
, entry
)->event_id
;
1780 void EventTarget_Init(EventTarget
*event_target
, IUnknown
*outer
, dispex_static_data_t
*dispex_data
,
1781 compat_mode_t compat_mode
)
1783 init_dispex_with_compat_mode(&event_target
->dispex
, outer
, dispex_data
, compat_mode
);
1784 wine_rb_init(&event_target
->handler_map
, event_id_cmp
);
1787 * IEventTarget is supported by the object or not depending on compatibility mode.
1788 * We use NULL vtbl for objects in compatibility mode not supporting the interface.
1789 * For targets that don't know compatibility mode at creation time, we set vtbl
1790 * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
1793 if(compat_mode
== COMPAT_MODE_QUIRKS
&& dispex_data
->vtbl
&& dispex_data
->vtbl
->get_compat_mode
)
1794 event_target
->IEventTarget_iface
.lpVtbl
= DELAY_INIT_VTBL
;
1795 else if(compat_mode
< COMPAT_MODE_IE9
)
1796 event_target
->IEventTarget_iface
.lpVtbl
= NULL
;
1798 event_target
->IEventTarget_iface
.lpVtbl
= &EventTargetVtbl
;
1801 void release_event_target(EventTarget
*event_target
)
1803 handler_vector_t
*iter
, *iter2
;
1806 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter
, iter2
, &event_target
->handler_map
, handler_vector_t
, entry
) {
1807 if(iter
->handler_prop
)
1808 IDispatch_Release(iter
->handler_prop
);
1809 for(i
= 0; i
< iter
->handler_cnt
; i
++)
1810 if(iter
->handlers
[i
])
1811 IDispatch_Release(iter
->handlers
[i
]);
1812 heap_free(iter
->handlers
);