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_BIND_TO_BODY 0x0008
110 #define EVENT_CANCELABLE 0x0010
111 #define EVENT_HASDEFAULTHANDLERS 0x0020
112 #define EVENT_FIXME 0x0040
114 static const event_info_t event_info
[] = {
115 {abortW
, EVENTT_NONE
, DISPID_EVMETH_ONABORT
,
117 {beforeactivateW
, EVENTT_NONE
, DISPID_EVMETH_ONBEFOREACTIVATE
,
119 {beforeunloadW
, EVENTT_NONE
, DISPID_EVMETH_ONBEFOREUNLOAD
,
120 EVENT_DEFAULTLISTENER
},
121 {blurW
, EVENTT_HTML
, DISPID_EVMETH_ONBLUR
,
122 EVENT_DEFAULTLISTENER
},
123 {changeW
, EVENTT_HTML
, DISPID_EVMETH_ONCHANGE
,
124 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
125 {clickW
, EVENTT_MOUSE
, DISPID_EVMETH_ONCLICK
,
126 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
|EVENT_HASDEFAULTHANDLERS
},
127 {contextmenuW
, EVENTT_MOUSE
, DISPID_EVMETH_ONCONTEXTMENU
,
128 EVENT_BUBBLE
|EVENT_CANCELABLE
},
129 {dataavailableW
, EVENTT_NONE
, DISPID_EVMETH_ONDATAAVAILABLE
,
131 {dblclickW
, EVENTT_MOUSE
, DISPID_EVMETH_ONDBLCLICK
,
132 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
},
133 {dragW
, EVENTT_MOUSE
, DISPID_EVMETH_ONDRAG
,
134 EVENT_FIXME
|EVENT_CANCELABLE
},
135 {dragstartW
, EVENTT_MOUSE
, DISPID_EVMETH_ONDRAGSTART
,
136 EVENT_FIXME
|EVENT_CANCELABLE
},
137 {errorW
, EVENTT_NONE
, DISPID_EVMETH_ONERROR
,
139 {focusW
, EVENTT_HTML
, DISPID_EVMETH_ONFOCUS
,
140 EVENT_DEFAULTLISTENER
},
141 {focusinW
, EVENTT_HTML
, DISPID_EVMETH_ONFOCUSIN
,
143 {focusoutW
, EVENTT_HTML
, DISPID_EVMETH_ONFOCUSOUT
,
145 {helpW
, EVENTT_KEY
, DISPID_EVMETH_ONHELP
,
146 EVENT_BUBBLE
|EVENT_CANCELABLE
},
147 {keydownW
, EVENTT_KEY
, DISPID_EVMETH_ONKEYDOWN
,
148 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_HASDEFAULTHANDLERS
},
149 {keypressW
, EVENTT_KEY
, DISPID_EVMETH_ONKEYPRESS
,
150 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
151 {keyupW
, EVENTT_KEY
, DISPID_EVMETH_ONKEYUP
,
152 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
153 {loadW
, EVENTT_HTML
, DISPID_EVMETH_ONLOAD
,
155 {messageW
, EVENTT_NONE
, DISPID_EVMETH_ONMESSAGE
,
157 {mousedownW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEDOWN
,
158 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
},
159 {mousemoveW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEMOVE
,
160 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
161 {mouseoutW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEOUT
,
162 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
163 {mouseoverW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEOVER
,
164 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
165 {mouseupW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEUP
,
166 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
167 {mousewheelW
, EVENTT_MOUSE
, DISPID_EVMETH_ONMOUSEWHEEL
,
169 {pasteW
, EVENTT_NONE
, DISPID_EVMETH_ONPASTE
,
171 {readystatechangeW
, EVENTT_NONE
, DISPID_EVMETH_ONREADYSTATECHANGE
,
173 {resizeW
, EVENTT_NONE
, DISPID_EVMETH_ONRESIZE
,
174 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
175 {scrollW
, EVENTT_HTML
, DISPID_EVMETH_ONSCROLL
,
176 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
},
177 {selectionchangeW
, EVENTT_NONE
, DISPID_EVMETH_ONSELECTIONCHANGE
,
179 {selectstartW
, EVENTT_MOUSE
, DISPID_EVMETH_ONSELECTSTART
,
181 {submitW
, EVENTT_HTML
, DISPID_EVMETH_ONSUBMIT
,
182 EVENT_DEFAULTLISTENER
|EVENT_BUBBLE
|EVENT_CANCELABLE
|EVENT_HASDEFAULTHANDLERS
},
183 {unloadW
, EVENTT_HTML
, DISPID_EVMETH_ONUNLOAD
,
187 static BOOL
use_event_quirks(EventTarget
*);
189 eventid_t
str_to_eid(LPCWSTR str
)
193 for(i
=0; i
< sizeof(event_info
)/sizeof(event_info
[0]); i
++) {
194 if(!strcmpW(event_info
[i
].name
, str
))
198 ERR("unknown type %s\n", debugstr_w(str
));
202 static eventid_t
attr_to_eid(const WCHAR
*str
)
206 if((str
[0] != 'o' && str
[0] != 'O') || (str
[1] != 'n' && str
[1] != 'N'))
209 for(i
=0; i
< sizeof(event_info
)/sizeof(event_info
[0]); i
++) {
210 if(!strcmpW(event_info
[i
].name
, str
+2))
217 struct HTMLEventObj
{
219 IHTMLEventObj IHTMLEventObj_iface
;
224 const event_info_t
*type
;
225 nsIDOMEvent
*nsevent
;
226 VARIANT return_value
;
227 BOOL prevent_default
;
231 static inline HTMLEventObj
*impl_from_IHTMLEventObj(IHTMLEventObj
*iface
)
233 return CONTAINING_RECORD(iface
, HTMLEventObj
, IHTMLEventObj_iface
);
236 static HRESULT WINAPI
HTMLEventObj_QueryInterface(IHTMLEventObj
*iface
, REFIID riid
, void **ppv
)
238 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
240 TRACE("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
242 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
243 *ppv
= &This
->IHTMLEventObj_iface
;
244 }else if(IsEqualGUID(&IID_IHTMLEventObj
, riid
)) {
245 *ppv
= &This
->IHTMLEventObj_iface
;
246 }else if(dispex_query_interface(&This
->dispex
, riid
, ppv
)) {
247 return *ppv
? S_OK
: E_NOINTERFACE
;
250 WARN("(%p)->(%s %p)\n", This
, debugstr_mshtml_guid(riid
), ppv
);
251 return E_NOINTERFACE
;
254 IUnknown_AddRef((IUnknown
*)*ppv
);
258 static ULONG WINAPI
HTMLEventObj_AddRef(IHTMLEventObj
*iface
)
260 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
261 LONG ref
= InterlockedIncrement(&This
->ref
);
263 TRACE("(%p) ref=%d\n", This
, ref
);
268 static ULONG WINAPI
HTMLEventObj_Release(IHTMLEventObj
*iface
)
270 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
271 LONG ref
= InterlockedDecrement(&This
->ref
);
273 TRACE("(%p) ref=%d\n", This
, ref
);
277 IHTMLDOMNode_Release(&This
->target
->IHTMLDOMNode_iface
);
279 nsIDOMEvent_Release(This
->nsevent
);
280 release_dispex(&This
->dispex
);
287 static HRESULT WINAPI
HTMLEventObj_GetTypeInfoCount(IHTMLEventObj
*iface
, UINT
*pctinfo
)
289 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
290 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
293 static HRESULT WINAPI
HTMLEventObj_GetTypeInfo(IHTMLEventObj
*iface
, UINT iTInfo
,
294 LCID lcid
, ITypeInfo
**ppTInfo
)
296 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
297 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
300 static HRESULT WINAPI
HTMLEventObj_GetIDsOfNames(IHTMLEventObj
*iface
, REFIID riid
,
301 LPOLESTR
*rgszNames
, UINT cNames
,
302 LCID lcid
, DISPID
*rgDispId
)
304 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
305 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
, rgszNames
, cNames
,
309 static HRESULT WINAPI
HTMLEventObj_Invoke(IHTMLEventObj
*iface
, DISPID dispIdMember
,
310 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
311 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
313 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
314 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
, riid
, lcid
,
315 wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
318 static HRESULT WINAPI
HTMLEventObj_get_srcElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
320 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
322 TRACE("(%p)->(%p)\n", This
, p
);
326 IHTMLDOMNode_QueryInterface(&This
->target
->IHTMLDOMNode_iface
, &IID_IHTMLElement
, (void**)p
);
330 static HRESULT WINAPI
HTMLEventObj_get_altKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
332 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
333 cpp_bool ret
= FALSE
;
335 TRACE("(%p)->(%p)\n", This
, p
);
338 nsIDOMKeyEvent
*key_event
;
341 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
342 if(NS_SUCCEEDED(nsres
)) {
343 nsIDOMKeyEvent_GetAltKey(key_event
, &ret
);
344 nsIDOMKeyEvent_Release(key_event
);
346 nsIDOMMouseEvent
*mouse_event
;
348 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
349 if(NS_SUCCEEDED(nsres
)) {
350 nsIDOMMouseEvent_GetAltKey(mouse_event
, &ret
);
351 nsIDOMMouseEvent_Release(mouse_event
);
356 *p
= ret
? VARIANT_TRUE
: VARIANT_FALSE
;
360 static HRESULT WINAPI
HTMLEventObj_get_ctrlKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
362 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
363 cpp_bool ret
= FALSE
;
365 TRACE("(%p)->(%p)\n", This
, p
);
368 nsIDOMKeyEvent
*key_event
;
371 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
372 if(NS_SUCCEEDED(nsres
)) {
373 nsIDOMKeyEvent_GetCtrlKey(key_event
, &ret
);
374 nsIDOMKeyEvent_Release(key_event
);
376 nsIDOMMouseEvent
*mouse_event
;
378 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
379 if(NS_SUCCEEDED(nsres
)) {
380 nsIDOMMouseEvent_GetCtrlKey(mouse_event
, &ret
);
381 nsIDOMMouseEvent_Release(mouse_event
);
386 *p
= ret
? VARIANT_TRUE
: VARIANT_FALSE
;
390 static HRESULT WINAPI
HTMLEventObj_get_shiftKey(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
392 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
393 cpp_bool ret
= FALSE
;
395 TRACE("(%p)->(%p)\n", This
, p
);
398 nsIDOMKeyEvent
*key_event
;
401 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
402 if(NS_SUCCEEDED(nsres
)) {
403 nsIDOMKeyEvent_GetShiftKey(key_event
, &ret
);
404 nsIDOMKeyEvent_Release(key_event
);
406 nsIDOMMouseEvent
*mouse_event
;
408 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
409 if(NS_SUCCEEDED(nsres
)) {
410 nsIDOMMouseEvent_GetShiftKey(mouse_event
, &ret
);
411 nsIDOMMouseEvent_Release(mouse_event
);
416 *p
= ret
? VARIANT_TRUE
: VARIANT_FALSE
;
420 static HRESULT WINAPI
HTMLEventObj_put_returnValue(IHTMLEventObj
*iface
, VARIANT v
)
422 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
424 TRACE("(%p)->(%s)\n", This
, debugstr_variant(&v
));
426 if(V_VT(&v
) != VT_BOOL
) {
427 FIXME("unsupported value %s\n", debugstr_variant(&v
));
428 return DISP_E_BADVARTYPE
;
431 This
->return_value
= v
;
433 This
->prevent_default
= TRUE
;
437 static HRESULT WINAPI
HTMLEventObj_get_returnValue(IHTMLEventObj
*iface
, VARIANT
*p
)
439 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
441 TRACE("(%p)->(%p)\n", This
, p
);
444 return VariantCopy(p
, &This
->return_value
);
447 static HRESULT WINAPI
HTMLEventObj_put_cancelBubble(IHTMLEventObj
*iface
, VARIANT_BOOL v
)
449 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
451 TRACE("(%p)->(%x)\n", This
, v
);
453 This
->cancel_bubble
= !!v
;
457 static HRESULT WINAPI
HTMLEventObj_get_cancelBubble(IHTMLEventObj
*iface
, VARIANT_BOOL
*p
)
459 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
461 TRACE("(%p)->(%p)\n", This
, p
);
463 *p
= This
->cancel_bubble
? VARIANT_TRUE
: VARIANT_FALSE
;
467 static HRESULT WINAPI
HTMLEventObj_get_fromElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
469 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
471 FIXME("(%p)->(%p)\n", This
, p
);
477 static HRESULT WINAPI
HTMLEventObj_get_toElement(IHTMLEventObj
*iface
, IHTMLElement
**p
)
479 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
481 FIXME("(%p)->(%p)\n", This
, p
);
487 static HRESULT WINAPI
HTMLEventObj_put_keyCode(IHTMLEventObj
*iface
, LONG v
)
489 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
490 FIXME("(%p)->(%d)\n", This
, v
);
494 static HRESULT WINAPI
HTMLEventObj_get_keyCode(IHTMLEventObj
*iface
, LONG
*p
)
496 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
499 TRACE("(%p)->(%p)\n", This
, p
);
502 nsIDOMKeyEvent
*key_event
;
505 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMKeyEvent
, (void**)&key_event
);
506 if(NS_SUCCEEDED(nsres
)) {
507 nsIDOMKeyEvent_GetKeyCode(key_event
, &key_code
);
508 nsIDOMKeyEvent_Release(key_event
);
516 static HRESULT WINAPI
HTMLEventObj_get_button(IHTMLEventObj
*iface
, LONG
*p
)
518 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
521 TRACE("(%p)->(%p)\n", This
, p
);
524 nsIDOMMouseEvent
*mouse_event
;
527 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
528 if(NS_SUCCEEDED(nsres
)) {
529 nsIDOMMouseEvent_GetButton(mouse_event
, &button
);
530 nsIDOMMouseEvent_Release(mouse_event
);
538 static HRESULT WINAPI
HTMLEventObj_get_type(IHTMLEventObj
*iface
, BSTR
*p
)
540 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
542 TRACE("(%p)->(%p)\n", This
, p
);
549 *p
= SysAllocString(This
->type
->name
);
550 return *p
? S_OK
: E_OUTOFMEMORY
;
553 static HRESULT WINAPI
HTMLEventObj_get_qualifier(IHTMLEventObj
*iface
, BSTR
*p
)
555 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
557 FIXME("(%p)->(%p)\n", This
, p
);
563 static HRESULT WINAPI
HTMLEventObj_get_reason(IHTMLEventObj
*iface
, LONG
*p
)
565 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
567 FIXME("(%p)->(%p)\n", This
, p
);
573 static HRESULT WINAPI
HTMLEventObj_get_x(IHTMLEventObj
*iface
, LONG
*p
)
575 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
578 TRACE("(%p)->(%p)\n", This
, p
);
581 nsIDOMUIEvent
*ui_event
;
584 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMUIEvent
, (void**)&ui_event
);
585 if(NS_SUCCEEDED(nsres
)) {
586 /* NOTE: pageX is not exactly right here. */
587 nsres
= nsIDOMUIEvent_GetPageX(ui_event
, &x
);
588 assert(nsres
== NS_OK
);
589 nsIDOMUIEvent_Release(ui_event
);
597 static HRESULT WINAPI
HTMLEventObj_get_y(IHTMLEventObj
*iface
, LONG
*p
)
599 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
602 TRACE("(%p)->(%p)\n", This
, p
);
605 nsIDOMUIEvent
*ui_event
;
608 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMUIEvent
, (void**)&ui_event
);
609 if(NS_SUCCEEDED(nsres
)) {
610 /* NOTE: pageY is not exactly right here. */
611 nsres
= nsIDOMUIEvent_GetPageY(ui_event
, &y
);
612 assert(nsres
== NS_OK
);
613 nsIDOMUIEvent_Release(ui_event
);
621 static HRESULT WINAPI
HTMLEventObj_get_clientX(IHTMLEventObj
*iface
, LONG
*p
)
623 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
626 TRACE("(%p)->(%p)\n", This
, p
);
629 nsIDOMMouseEvent
*mouse_event
;
632 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
633 if(NS_SUCCEEDED(nsres
)) {
634 nsIDOMMouseEvent_GetClientX(mouse_event
, &x
);
635 nsIDOMMouseEvent_Release(mouse_event
);
643 static HRESULT WINAPI
HTMLEventObj_get_clientY(IHTMLEventObj
*iface
, LONG
*p
)
645 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
648 TRACE("(%p)->(%p)\n", This
, p
);
651 nsIDOMMouseEvent
*mouse_event
;
654 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
655 if(NS_SUCCEEDED(nsres
)) {
656 nsIDOMMouseEvent_GetClientY(mouse_event
, &y
);
657 nsIDOMMouseEvent_Release(mouse_event
);
665 static HRESULT WINAPI
HTMLEventObj_get_offsetX(IHTMLEventObj
*iface
, LONG
*p
)
667 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
669 FIXME("(%p)->(%p)\n", This
, p
);
675 static HRESULT WINAPI
HTMLEventObj_get_offsetY(IHTMLEventObj
*iface
, LONG
*p
)
677 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
679 FIXME("(%p)->(%p)\n", This
, p
);
685 static HRESULT WINAPI
HTMLEventObj_get_screenX(IHTMLEventObj
*iface
, LONG
*p
)
687 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
690 TRACE("(%p)->(%p)\n", This
, p
);
693 nsIDOMMouseEvent
*mouse_event
;
696 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
697 if(NS_SUCCEEDED(nsres
)) {
698 nsIDOMMouseEvent_GetScreenX(mouse_event
, &x
);
699 nsIDOMMouseEvent_Release(mouse_event
);
707 static HRESULT WINAPI
HTMLEventObj_get_screenY(IHTMLEventObj
*iface
, LONG
*p
)
709 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
712 TRACE("(%p)->(%p)\n", This
, p
);
715 nsIDOMMouseEvent
*mouse_event
;
718 nsres
= nsIDOMEvent_QueryInterface(This
->nsevent
, &IID_nsIDOMMouseEvent
, (void**)&mouse_event
);
719 if(NS_SUCCEEDED(nsres
)) {
720 nsIDOMMouseEvent_GetScreenY(mouse_event
, &y
);
721 nsIDOMMouseEvent_Release(mouse_event
);
729 static HRESULT WINAPI
HTMLEventObj_get_srcFilter(IHTMLEventObj
*iface
, IDispatch
**p
)
731 HTMLEventObj
*This
= impl_from_IHTMLEventObj(iface
);
733 FIXME("(%p)->(%p)\n", This
, p
);
739 static const IHTMLEventObjVtbl HTMLEventObjVtbl
= {
740 HTMLEventObj_QueryInterface
,
742 HTMLEventObj_Release
,
743 HTMLEventObj_GetTypeInfoCount
,
744 HTMLEventObj_GetTypeInfo
,
745 HTMLEventObj_GetIDsOfNames
,
747 HTMLEventObj_get_srcElement
,
748 HTMLEventObj_get_altKey
,
749 HTMLEventObj_get_ctrlKey
,
750 HTMLEventObj_get_shiftKey
,
751 HTMLEventObj_put_returnValue
,
752 HTMLEventObj_get_returnValue
,
753 HTMLEventObj_put_cancelBubble
,
754 HTMLEventObj_get_cancelBubble
,
755 HTMLEventObj_get_fromElement
,
756 HTMLEventObj_get_toElement
,
757 HTMLEventObj_put_keyCode
,
758 HTMLEventObj_get_keyCode
,
759 HTMLEventObj_get_button
,
760 HTMLEventObj_get_type
,
761 HTMLEventObj_get_qualifier
,
762 HTMLEventObj_get_reason
,
765 HTMLEventObj_get_clientX
,
766 HTMLEventObj_get_clientY
,
767 HTMLEventObj_get_offsetX
,
768 HTMLEventObj_get_offsetY
,
769 HTMLEventObj_get_screenX
,
770 HTMLEventObj_get_screenY
,
771 HTMLEventObj_get_srcFilter
774 static inline HTMLEventObj
*unsafe_impl_from_IHTMLEventObj(IHTMLEventObj
*iface
)
776 return iface
->lpVtbl
== &HTMLEventObjVtbl
? impl_from_IHTMLEventObj(iface
) : NULL
;
779 static const tid_t HTMLEventObj_iface_tids
[] = {
784 static dispex_static_data_t HTMLEventObj_dispex
= {
787 HTMLEventObj_iface_tids
790 static HTMLEventObj
*create_event(void)
794 ret
= heap_alloc_zero(sizeof(*ret
));
798 ret
->IHTMLEventObj_iface
.lpVtbl
= &HTMLEventObjVtbl
;
801 init_dispex(&ret
->dispex
, (IUnknown
*)&ret
->IHTMLEventObj_iface
, &HTMLEventObj_dispex
);
806 static HRESULT
set_event_info(HTMLEventObj
*event
, HTMLDOMNode
*target
, eventid_t eid
, nsIDOMEvent
*nsevent
)
808 event
->type
= event_info
+eid
;
809 event
->nsevent
= nsevent
;
812 nsIDOMEvent_AddRef(nsevent
);
813 }else if(event_types
[event_info
[eid
].type
]) {
817 nsAString_InitDepend(&type_str
, event_types
[event_info
[eid
].type
]);
818 nsres
= nsIDOMHTMLDocument_CreateEvent(target
->doc
->nsdoc
, &type_str
, &event
->nsevent
);
819 nsAString_Finish(&type_str
);
820 if(NS_FAILED(nsres
)) {
821 ERR("Could not create event: %08x\n", nsres
);
826 event
->target
= target
;
828 IHTMLDOMNode_AddRef(&target
->IHTMLDOMNode_iface
);
832 HRESULT
create_event_obj(IHTMLEventObj
**ret
)
836 event
= create_event();
838 return E_OUTOFMEMORY
;
840 *ret
= &event
->IHTMLEventObj_iface
;
844 static handler_vector_t
*get_handler_vector(EventTarget
*event_target
, eventid_t eid
, BOOL alloc
)
846 const event_target_vtbl_t
*vtbl
;
847 handler_vector_t
*handler_vector
;
848 struct wine_rb_entry
*entry
;
850 entry
= wine_rb_get(&event_target
->handler_map
, (const void*)eid
);
852 return WINE_RB_ENTRY_VALUE(entry
, handler_vector_t
, entry
);
856 handler_vector
= heap_alloc_zero(sizeof(*handler_vector
));
860 handler_vector
->event_id
= eid
;
861 vtbl
= dispex_get_vtbl(&event_target
->dispex
);
863 vtbl
->bind_event(&event_target
->dispex
, eid
);
865 FIXME("Unsupported event binding on target %p\n", event_target
);
867 wine_rb_put(&event_target
->handler_map
, (const void*)eid
, &handler_vector
->entry
);
868 return handler_vector
;
871 static HRESULT
call_disp_func(IDispatch
*disp
, DISPPARAMS
*dp
, VARIANT
*retv
)
877 memset(&ei
, 0, sizeof(ei
));
879 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
880 if(SUCCEEDED(hres
)) {
881 hres
= IDispatchEx_InvokeEx(dispex
, 0, GetUserDefaultLCID(), DISPATCH_METHOD
, dp
, retv
, &ei
, NULL
);
882 IDispatchEx_Release(dispex
);
884 TRACE("Could not get IDispatchEx interface: %08x\n", hres
);
885 hres
= IDispatch_Invoke(disp
, 0, &IID_NULL
, GetUserDefaultLCID(), DISPATCH_METHOD
,
886 dp
, retv
, &ei
, NULL
);
892 static HRESULT
call_cp_func(IDispatch
*disp
, DISPID dispid
, HTMLEventObj
*event_obj
, VARIANT
*retv
)
894 DISPPARAMS dp
= {NULL
,NULL
,0,0};
900 V_VT(&event_arg
) = VT_DISPATCH
;
901 V_DISPATCH(&event_arg
) = (IDispatch
*)&event_obj
->IHTMLEventObj_iface
;
902 dp
.rgvarg
= &event_arg
;
906 memset(&ei
, 0, sizeof(ei
));
907 return IDispatch_Invoke(disp
, dispid
, &IID_NULL
, 0, DISPATCH_METHOD
, &dp
, retv
, &ei
, &argerr
);
910 static BOOL
is_cp_event(cp_static_data_t
*data
, DISPID dispid
)
919 hres
= get_dispids(data
->tid
, &data
->id_cnt
, &data
->ids
);
925 max
= data
->id_cnt
-1;
928 if(data
->ids
[i
] == dispid
)
931 if(data
->ids
[i
] < dispid
)
940 void call_event_handlers(HTMLEventObj
*event_obj
, EventTarget
*event_target
, eventid_t eid
)
942 handler_vector_t
*handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
943 const BOOL cancelable
= event_info
[eid
].flags
& EVENT_CANCELABLE
;
944 ConnectionPointContainer
*cp_container
= NULL
;
945 const event_target_vtbl_t
*vtbl
;
949 if(handler_vector
&& handler_vector
->handler_prop
) {
950 DISPID named_arg
= DISPID_THIS
;
952 DISPPARAMS dp
= {&arg
, &named_arg
, 1, 1};
954 if(!use_event_quirks(event_target
))
955 FIXME("Event argument not supported\n");
957 V_VT(&arg
) = VT_DISPATCH
;
958 V_DISPATCH(&arg
) = (IDispatch
*)&event_target
->dispex
.IDispatchEx_iface
;
961 TRACE("%s >>>\n", debugstr_w(event_info
[eid
].name
));
962 hres
= call_disp_func(handler_vector
->handler_prop
, &dp
, &v
);
964 TRACE("%s <<< %s\n", debugstr_w(event_info
[eid
].name
), debugstr_variant(&v
));
967 if(V_VT(&v
) == VT_BOOL
) {
969 event_obj
->prevent_default
= TRUE
;
970 }else if(V_VT(&v
) != VT_EMPTY
) {
971 FIXME("unhandled result %s\n", debugstr_variant(&v
));
976 WARN("%s <<< %08x\n", debugstr_w(event_info
[eid
].name
), hres
);
980 if(handler_vector
&& handler_vector
->handler_cnt
) {
982 DISPPARAMS dp
= {&arg
, NULL
, 1, 0};
985 V_VT(&arg
) = VT_DISPATCH
;
986 V_DISPATCH(&arg
) = (IDispatch
*)&event_obj
->dispex
.IDispatchEx_iface
;
988 i
= handler_vector
->handler_cnt
;
990 if(handler_vector
->handlers
[i
]) {
993 TRACE("%s [%d] >>>\n", debugstr_w(event_info
[eid
].name
), i
);
994 hres
= call_disp_func(handler_vector
->handlers
[i
], &dp
, &v
);
996 TRACE("%s [%d] <<<\n", debugstr_w(event_info
[eid
].name
), i
);
999 if(V_VT(&v
) == VT_BOOL
) {
1001 event_obj
->prevent_default
= TRUE
;
1002 }else if(V_VT(&v
) != VT_EMPTY
) {
1003 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1008 WARN("%s [%d] <<< %08x\n", debugstr_w(event_info
[eid
].name
), i
, hres
);
1014 if((vtbl
= dispex_get_vtbl(&event_target
->dispex
)) && vtbl
->get_cp_container
)
1015 cp_container
= vtbl
->get_cp_container(&event_target
->dispex
);
1017 if(cp_container
->cps
) {
1018 ConnectionPoint
*cp
;
1021 for(j
=0; cp_container
->cp_entries
[j
].riid
; j
++) {
1022 cp
= cp_container
->cps
+ j
;
1023 if(!cp
->sinks_size
|| !is_cp_event(cp
->data
, event_info
[eid
].dispid
))
1026 for(i
=0; i
< cp
->sinks_size
; i
++) {
1027 if(!cp
->sinks
[i
].disp
)
1030 V_VT(&v
) = VT_EMPTY
;
1032 TRACE("cp %s [%u] >>>\n", debugstr_w(event_info
[eid
].name
), i
);
1033 hres
= call_cp_func(cp
->sinks
[i
].disp
, event_info
[eid
].dispid
,
1034 cp
->data
->pass_event_arg
? event_obj
: NULL
, &v
);
1036 TRACE("cp %s [%u] <<<\n", debugstr_w(event_info
[eid
].name
), i
);
1039 if(V_VT(&v
) == VT_BOOL
) {
1041 event_obj
->prevent_default
= TRUE
;
1042 }else if(V_VT(&v
) != VT_EMPTY
) {
1043 FIXME("unhandled result %s\n", debugstr_variant(&v
));
1048 WARN("cp %s [%u] <<< %08x\n", debugstr_w(event_info
[eid
].name
), i
, hres
);
1053 IConnectionPointContainer_Release(&cp_container
->IConnectionPointContainer_iface
);
1057 static void fire_event_obj(HTMLDocumentNode
*doc
, eventid_t eid
, HTMLEventObj
*event_obj
,
1058 HTMLDOMNode
*target
)
1060 IHTMLEventObj
*prev_event
;
1061 nsIDOMNode
*parent
, *nsnode
= NULL
;
1062 BOOL prevent_default
= FALSE
;
1063 HTMLInnerWindow
*window
;
1065 UINT16 node_type
= 0;
1069 TRACE("(%p) %s\n", doc
, debugstr_w(event_info
[eid
].name
));
1071 window
= doc
->window
;
1073 WARN("NULL window\n");
1077 htmldoc_addref(&doc
->basedoc
);
1079 prev_event
= window
->event
;
1080 window
->event
= event_obj
? &event_obj
->IHTMLEventObj_iface
: NULL
;
1083 nsIDOMNode_GetNodeType(target
->nsnode
, &node_type
);
1084 nsnode
= target
->nsnode
;
1085 nsIDOMNode_AddRef(nsnode
);
1091 hres
= get_node(doc
, nsnode
, FALSE
, &node
);
1092 if(SUCCEEDED(hres
) && node
) {
1093 call_event_handlers(event_obj
, &node
->event_target
, eid
);
1097 if(!(event_info
[eid
].flags
& EVENT_BUBBLE
) || (event_obj
&& event_obj
->cancel_bubble
))
1100 nsIDOMNode_GetParentNode(nsnode
, &parent
);
1101 nsIDOMNode_Release(nsnode
);
1106 nsIDOMNode_GetNodeType(nsnode
, &node_type
);
1107 }while(node_type
== ELEMENT_NODE
);
1109 if(!(event_info
[eid
].flags
& EVENT_BUBBLE
) || (event_obj
&& event_obj
->cancel_bubble
))
1114 call_event_handlers(event_obj
, &doc
->node
.event_target
, eid
);
1115 if(!(event_info
[eid
].flags
& EVENT_BUBBLE
) || (event_obj
&& event_obj
->cancel_bubble
))
1119 default: /* window object */
1120 call_event_handlers(event_obj
, &doc
->window
->event_target
, eid
);
1124 nsIDOMNode_Release(nsnode
);
1126 if(event_obj
&& event_obj
->prevent_default
)
1127 prevent_default
= TRUE
;
1128 window
->event
= prev_event
;
1130 if(target
&& !prevent_default
&& (event_info
[eid
].flags
& EVENT_HASDEFAULTHANDLERS
)) {
1131 nsnode
= target
->nsnode
;
1132 nsIDOMNode_AddRef(nsnode
);
1135 hres
= get_node(doc
, nsnode
, TRUE
, &node
);
1140 const event_target_vtbl_t
*vtbl
= dispex_get_vtbl(&node
->event_target
.dispex
);
1141 if(vtbl
&& vtbl
->handle_event_default
)
1142 hres
= vtbl
->handle_event_default(&node
->event_target
.dispex
, eid
, event_obj
? event_obj
->nsevent
: NULL
, &prevent_default
);
1144 if(FAILED(hres
) || prevent_default
|| (event_obj
&& event_obj
->cancel_bubble
))
1148 nsres
= nsIDOMNode_GetParentNode(nsnode
, &parent
);
1149 if(NS_FAILED(nsres
))
1152 nsIDOMNode_Release(nsnode
);
1157 nsIDOMNode_Release(nsnode
);
1160 if(prevent_default
&& event_obj
&& event_obj
->nsevent
) {
1161 TRACE("calling PreventDefault\n");
1162 nsIDOMEvent_PreventDefault(event_obj
->nsevent
);
1165 htmldoc_release(&doc
->basedoc
);
1168 void fire_event(HTMLDocumentNode
*doc
, eventid_t eid
, BOOL set_event
, HTMLDOMNode
*target
, nsIDOMEvent
*nsevent
)
1170 HTMLEventObj
*event_obj
= NULL
;
1174 event_obj
= create_event();
1178 hres
= set_event_info(event_obj
, target
, eid
, nsevent
);
1180 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1185 fire_event_obj(doc
, eid
, event_obj
, target
);
1188 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1191 HRESULT
dispatch_event(HTMLDOMNode
*node
, const WCHAR
*event_name
, VARIANT
*event_var
, VARIANT_BOOL
*cancelled
)
1193 HTMLEventObj
*event_obj
= NULL
;
1197 eid
= attr_to_eid(event_name
);
1198 if(eid
== EVENTID_LAST
) {
1199 WARN("unknown event %s\n", debugstr_w(event_name
));
1200 return E_INVALIDARG
;
1203 if(event_var
&& V_VT(event_var
) != VT_EMPTY
&& V_VT(event_var
) != VT_ERROR
) {
1204 if(V_VT(event_var
) != VT_DISPATCH
) {
1205 FIXME("event_var %s not supported\n", debugstr_variant(event_var
));
1209 if(V_DISPATCH(event_var
)) {
1210 IHTMLEventObj
*event_iface
;
1212 hres
= IDispatch_QueryInterface(V_DISPATCH(event_var
), &IID_IHTMLEventObj
, (void**)&event_iface
);
1214 FIXME("No IHTMLEventObj iface\n");
1218 event_obj
= unsafe_impl_from_IHTMLEventObj(event_iface
);
1220 ERR("Not our IHTMLEventObj?\n");
1221 IHTMLEventObj_Release(event_iface
);
1228 hres
= set_event_info(event_obj
, node
, eid
, NULL
);
1230 fire_event_obj(node
->doc
, eid
, event_obj
, node
);
1232 IHTMLEventObj_Release(&event_obj
->IHTMLEventObj_iface
);
1236 fire_event(node
->doc
, eid
, TRUE
, node
, NULL
);
1239 *cancelled
= VARIANT_TRUE
; /* FIXME */
1243 HRESULT
ensure_doc_nsevent_handler(HTMLDocumentNode
*doc
, eventid_t eid
)
1245 nsIDOMNode
*nsnode
= NULL
;
1247 TRACE("%s\n", debugstr_w(event_info
[eid
].name
));
1253 case EVENTID_FOCUSIN
:
1254 doc
->event_vector
[eid
] = TRUE
;
1255 eid
= EVENTID_FOCUS
;
1257 case EVENTID_FOCUSOUT
:
1258 doc
->event_vector
[eid
] = TRUE
;
1265 if(doc
->event_vector
[eid
] || !(event_info
[eid
].flags
& (EVENT_DEFAULTLISTENER
|EVENT_BIND_TO_BODY
)))
1268 if(event_info
[eid
].flags
& EVENT_BIND_TO_BODY
) {
1269 nsnode
= doc
->node
.nsnode
;
1270 nsIDOMNode_AddRef(nsnode
);
1273 doc
->event_vector
[eid
] = TRUE
;
1274 add_nsevent_listener(doc
, nsnode
, event_info
[eid
].name
);
1277 nsIDOMNode_Release(nsnode
);
1281 void detach_events(HTMLDocumentNode
*doc
)
1283 if(doc
->event_vector
) {
1286 for(i
=0; i
< EVENTID_LAST
; i
++) {
1287 if(doc
->event_vector
[i
]) {
1288 detach_nsevent(doc
, event_info
[i
].name
);
1289 doc
->event_vector
[i
] = FALSE
;
1294 release_nsevents(doc
);
1297 static HRESULT
get_event_dispex_ref(EventTarget
*event_target
, eventid_t eid
, BOOL alloc
, VARIANT
**ret
)
1302 strcpyW(buf
+2, event_info
[eid
].name
);
1303 return dispex_get_dprop_ref(&event_target
->dispex
, buf
, alloc
, ret
);
1306 static void remove_event_handler(EventTarget
*event_target
, eventid_t eid
)
1308 handler_vector_t
*handler_vector
;
1312 hres
= get_event_dispex_ref(event_target
, eid
, FALSE
, &store
);
1314 VariantClear(store
);
1316 handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
1317 if(handler_vector
&& handler_vector
->handler_prop
) {
1318 IDispatch_Release(handler_vector
->handler_prop
);
1319 handler_vector
->handler_prop
= NULL
;
1323 static HRESULT
set_event_handler_disp(EventTarget
*event_target
, eventid_t eid
, IDispatch
*disp
)
1325 handler_vector_t
*handler_vector
;
1327 if(event_info
[eid
].flags
& EVENT_FIXME
)
1328 FIXME("unimplemented event %s\n", debugstr_w(event_info
[eid
].name
));
1330 remove_event_handler(event_target
, eid
);
1334 handler_vector
= get_handler_vector(event_target
, eid
, TRUE
);
1336 return E_OUTOFMEMORY
;
1338 if(handler_vector
->handler_prop
)
1339 IDispatch_Release(handler_vector
->handler_prop
);
1341 handler_vector
->handler_prop
= disp
;
1342 IDispatch_AddRef(disp
);
1346 HRESULT
set_event_handler(EventTarget
*event_target
, eventid_t eid
, VARIANT
*var
)
1350 if(use_event_quirks(event_target
)) {
1351 WARN("attempt to set to VT_EMPTY in quirks mode\n");
1356 remove_event_handler(event_target
, eid
);
1360 return set_event_handler_disp(event_target
, eid
, V_DISPATCH(var
));
1366 if(!use_event_quirks(event_target
))
1367 FIXME("Setting to string %s not supported\n", debugstr_w(V_BSTR(var
)));
1370 * Setting event handler to string is a rare case and we don't want to
1371 * complicate nor increase memory of handler_vector_t for that. Instead,
1372 * we store the value in DispatchEx, which can already handle custom
1375 remove_event_handler(event_target
, eid
);
1377 hres
= get_event_dispex_ref(event_target
, eid
, TRUE
, &v
);
1381 V_BSTR(v
) = SysAllocString(V_BSTR(var
));
1383 return E_OUTOFMEMORY
;
1389 FIXME("not handler %s\n", debugstr_variant(var
));
1396 HRESULT
get_event_handler(EventTarget
*event_target
, eventid_t eid
, VARIANT
*var
)
1398 handler_vector_t
*handler_vector
;
1402 hres
= get_event_dispex_ref(event_target
, eid
, FALSE
, &v
);
1403 if(SUCCEEDED(hres
) && V_VT(v
) != VT_EMPTY
) {
1404 V_VT(var
) = VT_EMPTY
;
1405 return VariantCopy(var
, v
);
1408 handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
1409 if(handler_vector
&& handler_vector
->handler_prop
) {
1410 V_VT(var
) = VT_DISPATCH
;
1411 V_DISPATCH(var
) = handler_vector
->handler_prop
;
1412 IDispatch_AddRef(V_DISPATCH(var
));
1414 V_VT(var
) = VT_NULL
;
1420 HRESULT
attach_event(EventTarget
*event_target
, BSTR name
, IDispatch
*disp
, VARIANT_BOOL
*res
)
1422 handler_vector_t
*handler_vector
;
1426 eid
= attr_to_eid(name
);
1427 if(eid
== EVENTID_LAST
) {
1428 WARN("Unknown event\n");
1429 *res
= VARIANT_TRUE
;
1433 if(event_info
[eid
].flags
& EVENT_FIXME
)
1434 FIXME("unimplemented event %s\n", debugstr_w(event_info
[eid
].name
));
1436 handler_vector
= get_handler_vector(event_target
, eid
, TRUE
);
1438 return E_OUTOFMEMORY
;
1440 while(i
< handler_vector
->handler_cnt
&& handler_vector
->handlers
[i
])
1442 if(i
== handler_vector
->handler_cnt
) {
1444 handler_vector
->handlers
= heap_realloc_zero(handler_vector
->handlers
,
1445 (i
+ 1) * sizeof(*handler_vector
->handlers
));
1447 handler_vector
->handlers
= heap_alloc_zero(sizeof(*handler_vector
->handlers
));
1448 if(!handler_vector
->handlers
)
1449 return E_OUTOFMEMORY
;
1450 handler_vector
->handler_cnt
++;
1453 IDispatch_AddRef(disp
);
1454 handler_vector
->handlers
[i
] = disp
;
1456 *res
= VARIANT_TRUE
;
1460 HRESULT
detach_event(EventTarget
*event_target
, BSTR name
, IDispatch
*disp
)
1462 handler_vector_t
*handler_vector
;
1466 eid
= attr_to_eid(name
);
1467 if(eid
== EVENTID_LAST
) {
1468 WARN("Unknown event\n");
1472 handler_vector
= get_handler_vector(event_target
, eid
, FALSE
);
1476 for(i
= 0; i
< handler_vector
->handler_cnt
; i
++) {
1477 if(handler_vector
->handlers
[i
] == disp
) {
1478 IDispatch_Release(handler_vector
->handlers
[i
]);
1479 handler_vector
->handlers
[i
] = NULL
;
1486 void bind_target_event(HTMLDocumentNode
*doc
, EventTarget
*event_target
, const WCHAR
*event
, IDispatch
*disp
)
1490 TRACE("(%p %p %s %p)\n", doc
, event_target
, debugstr_w(event
), disp
);
1492 eid
= attr_to_eid(event
);
1493 if(eid
== EVENTID_LAST
) {
1494 WARN("Unsupported event %s\n", debugstr_w(event
));
1498 set_event_handler_disp(event_target
, eid
, disp
);
1501 void update_doc_cp_events(HTMLDocumentNode
*doc
, cp_static_data_t
*cp
)
1505 for(i
=0; i
< EVENTID_LAST
; i
++) {
1506 if((event_info
[i
].flags
& EVENT_DEFAULTLISTENER
) && is_cp_event(cp
, event_info
[i
].dispid
))
1507 ensure_doc_nsevent_handler(doc
, i
);
1511 void check_event_attr(HTMLDocumentNode
*doc
, nsIDOMHTMLElement
*nselem
)
1513 nsIDOMMozNamedAttrMap
*attr_map
;
1514 const PRUnichar
*name
, *value
;
1515 nsAString name_str
, value_str
;
1516 HTMLDOMNode
*node
= NULL
;
1525 nsres
= nsIDOMHTMLElement_HasAttributes(nselem
, &has_attrs
);
1526 if(NS_FAILED(nsres
) || !has_attrs
)
1529 nsres
= nsIDOMHTMLElement_GetAttributes(nselem
, &attr_map
);
1530 if(NS_FAILED(nsres
))
1533 nsres
= nsIDOMMozNamedAttrMap_GetLength(attr_map
, &length
);
1534 assert(nsres
== NS_OK
);
1536 nsAString_Init(&name_str
, NULL
);
1537 nsAString_Init(&value_str
, NULL
);
1539 for(i
= 0; i
< length
; i
++) {
1540 nsres
= nsIDOMMozNamedAttrMap_Item(attr_map
, i
, &attr
);
1541 if(NS_FAILED(nsres
))
1544 nsres
= nsIDOMAttr_GetName(attr
, &name_str
);
1545 if(NS_FAILED(nsres
)) {
1546 nsIDOMAttr_Release(attr
);
1550 nsAString_GetData(&name_str
, &name
);
1551 eid
= attr_to_eid(name
);
1552 if(eid
== EVENTID_LAST
) {
1553 nsIDOMAttr_Release(attr
);
1557 nsres
= nsIDOMAttr_GetValue(attr
, &value_str
);
1558 nsIDOMAttr_Release(attr
);
1559 if(NS_FAILED(nsres
))
1562 nsAString_GetData(&value_str
, &value
);
1566 TRACE("%p.%s = %s\n", nselem
, debugstr_w(name
), debugstr_w(value
));
1568 disp
= script_parse_event(doc
->window
, value
);
1573 hres
= get_node(doc
, (nsIDOMNode
*)nselem
, TRUE
, &node
);
1575 IDispatch_Release(disp
);
1580 set_event_handler_disp(get_node_event_prop_target(node
, eid
), eid
, disp
);
1581 IDispatch_Release(disp
);
1586 nsAString_Finish(&name_str
);
1587 nsAString_Finish(&value_str
);
1588 nsIDOMMozNamedAttrMap_Release(attr_map
);
1591 HRESULT
doc_init_events(HTMLDocumentNode
*doc
)
1596 doc
->event_vector
= heap_alloc_zero(EVENTID_LAST
*sizeof(BOOL
));
1597 if(!doc
->event_vector
)
1598 return E_OUTOFMEMORY
;
1602 for(i
=0; i
< EVENTID_LAST
; i
++) {
1603 if(event_info
[i
].flags
& EVENT_HASDEFAULTHANDLERS
) {
1604 hres
= ensure_doc_nsevent_handler(doc
, i
);
1613 static inline EventTarget
*impl_from_IEventTarget(IEventTarget
*iface
)
1615 return CONTAINING_RECORD(iface
, EventTarget
, IEventTarget_iface
);
1618 static HRESULT WINAPI
EventTarget_QueryInterface(IEventTarget
*iface
, REFIID riid
, void **ppv
)
1620 EventTarget
*This
= impl_from_IEventTarget(iface
);
1621 return IDispatchEx_QueryInterface(&This
->dispex
.IDispatchEx_iface
, riid
, ppv
);
1624 static ULONG WINAPI
EventTarget_AddRef(IEventTarget
*iface
)
1626 EventTarget
*This
= impl_from_IEventTarget(iface
);
1627 return IDispatchEx_AddRef(&This
->dispex
.IDispatchEx_iface
);
1630 static ULONG WINAPI
EventTarget_Release(IEventTarget
*iface
)
1632 EventTarget
*This
= impl_from_IEventTarget(iface
);
1633 return IDispatchEx_Release(&This
->dispex
.IDispatchEx_iface
);
1636 static HRESULT WINAPI
EventTarget_GetTypeInfoCount(IEventTarget
*iface
, UINT
*pctinfo
)
1638 EventTarget
*This
= impl_from_IEventTarget(iface
);
1639 return IDispatchEx_GetTypeInfoCount(&This
->dispex
.IDispatchEx_iface
, pctinfo
);
1642 static HRESULT WINAPI
EventTarget_GetTypeInfo(IEventTarget
*iface
, UINT iTInfo
,
1643 LCID lcid
, ITypeInfo
**ppTInfo
)
1645 EventTarget
*This
= impl_from_IEventTarget(iface
);
1646 return IDispatchEx_GetTypeInfo(&This
->dispex
.IDispatchEx_iface
, iTInfo
, lcid
, ppTInfo
);
1649 static HRESULT WINAPI
EventTarget_GetIDsOfNames(IEventTarget
*iface
, REFIID riid
, LPOLESTR
*rgszNames
,
1650 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
1652 EventTarget
*This
= impl_from_IEventTarget(iface
);
1653 return IDispatchEx_GetIDsOfNames(&This
->dispex
.IDispatchEx_iface
, riid
,
1654 rgszNames
, cNames
, lcid
, rgDispId
);
1657 static HRESULT WINAPI
EventTarget_Invoke(IEventTarget
*iface
, DISPID dispIdMember
,
1658 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1659 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1661 EventTarget
*This
= impl_from_IEventTarget(iface
);
1662 return IDispatchEx_Invoke(&This
->dispex
.IDispatchEx_iface
, dispIdMember
,
1663 riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1666 static HRESULT WINAPI
EventTarget_addEventListener(IEventTarget
*iface
, BSTR type
,
1667 IDispatch
*listener
, VARIANT_BOOL capture
)
1669 EventTarget
*This
= impl_from_IEventTarget(iface
);
1670 FIXME("(%p)->(%s %p %x)\n", This
, debugstr_w(type
), listener
, capture
);
1674 static HRESULT WINAPI
EventTarget_removeEventListener(IEventTarget
*iface
, BSTR type
,
1675 IDispatch
*listener
, VARIANT_BOOL capture
)
1677 EventTarget
*This
= impl_from_IEventTarget(iface
);
1678 FIXME("(%p)->(%s %p %x)\n", This
, debugstr_w(type
), listener
, capture
);
1682 static HRESULT WINAPI
EventTarget_dispatchEvent(IEventTarget
*iface
, IDOMEvent
*event
, VARIANT_BOOL
*result
)
1684 EventTarget
*This
= impl_from_IEventTarget(iface
);
1685 FIXME("(%p)->(%p %p)\n", This
, event
, result
);
1689 static const IEventTargetVtbl EventTargetVtbl
= {
1690 EventTarget_QueryInterface
,
1692 EventTarget_Release
,
1693 EventTarget_GetTypeInfoCount
,
1694 EventTarget_GetTypeInfo
,
1695 EventTarget_GetIDsOfNames
,
1697 EventTarget_addEventListener
,
1698 EventTarget_removeEventListener
,
1699 EventTarget_dispatchEvent
1702 #define DELAY_INIT_VTBL ((const IEventTargetVtbl*)1)
1704 static BOOL
use_event_quirks(EventTarget
*event_target
)
1706 if(event_target
->IEventTarget_iface
.lpVtbl
== DELAY_INIT_VTBL
) {
1707 event_target
->IEventTarget_iface
.lpVtbl
=
1708 dispex_compat_mode(&event_target
->dispex
) >= COMPAT_MODE_IE9
1709 ? &EventTargetVtbl
: NULL
;
1711 return !event_target
->IEventTarget_iface
.lpVtbl
;
1714 HRESULT
EventTarget_QI(EventTarget
*event_target
, REFIID riid
, void **ppv
)
1716 if(IsEqualGUID(riid
, &IID_IEventTarget
)) {
1717 if(use_event_quirks(event_target
)) {
1718 WARN("IEventTarget queried, but not supported by in document mode\n");
1720 return E_NOINTERFACE
;
1722 IEventTarget_AddRef(&event_target
->IEventTarget_iface
);
1723 *ppv
= &event_target
->IEventTarget_iface
;
1727 if(dispex_query_interface(&event_target
->dispex
, riid
, ppv
))
1728 return *ppv
? S_OK
: E_NOINTERFACE
;
1730 WARN("(%p)->(%s %p)\n", event_target
, debugstr_mshtml_guid(riid
), ppv
);
1732 return E_NOINTERFACE
;
1735 static int event_id_cmp(const void *key
, const struct wine_rb_entry
*entry
)
1737 return (INT_PTR
)key
- WINE_RB_ENTRY_VALUE(entry
, handler_vector_t
, entry
)->event_id
;
1740 void EventTarget_Init(EventTarget
*event_target
, IUnknown
*outer
, dispex_static_data_t
*dispex_data
,
1741 compat_mode_t compat_mode
)
1743 init_dispex_with_compat_mode(&event_target
->dispex
, outer
, dispex_data
, compat_mode
);
1744 wine_rb_init(&event_target
->handler_map
, event_id_cmp
);
1747 * IEventTarget is supported by the object or not depending on compatibility mode.
1748 * We use NULL vtbl for objects in compatibility mode not supporting the interface.
1749 * For targets that don't know compatibility mode at creation time, we set vtbl
1750 * to special DELAY_INIT_VTBL value so that vtbl will be set to proper value
1753 if(compat_mode
== COMPAT_MODE_QUIRKS
&& dispex_data
->vtbl
&& dispex_data
->vtbl
->get_compat_mode
)
1754 event_target
->IEventTarget_iface
.lpVtbl
= DELAY_INIT_VTBL
;
1755 else if(compat_mode
< COMPAT_MODE_IE9
)
1756 event_target
->IEventTarget_iface
.lpVtbl
= NULL
;
1758 event_target
->IEventTarget_iface
.lpVtbl
= &EventTargetVtbl
;
1761 void release_event_target(EventTarget
*event_target
)
1763 handler_vector_t
*iter
, *iter2
;
1766 WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR(iter
, iter2
, &event_target
->handler_map
, handler_vector_t
, entry
) {
1767 if(iter
->handler_prop
)
1768 IDispatch_Release(iter
->handler_prop
);
1769 for(i
= 0; i
< iter
->handler_cnt
; i
++)
1770 if(iter
->handlers
[i
])
1771 IDispatch_Release(iter
->handlers
[i
]);
1772 heap_free(iter
->handlers
);