push 149f0a5527ac85057a8ef03858d34d91c36f97e8
[wine/hacks.git] / dlls / mshtml / htmlevent.c
blobc09db52e2382fc7a5e96f2b099b4b2ba47135462
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>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27 #include "mshtmdid.h"
29 #include "mshtml_private.h"
30 #include "htmlevent.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
36 typedef struct {
37 IDispatch *handler_prop;
38 DWORD handler_cnt;
39 IDispatch *handlers[0];
40 } handler_vector_t;
42 struct event_target_t {
43 handler_vector_t *event_table[EVENTID_LAST];
46 static const WCHAR beforeunloadW[] = {'b','e','f','o','r','e','u','n','l','o','a','d',0};
47 static const WCHAR onbeforeunloadW[] = {'o','n','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 onblurW[] = {'o','n','b','l','u','r',0};
52 static const WCHAR changeW[] = {'c','h','a','n','g','e',0};
53 static const WCHAR onchangeW[] = {'o','n','c','h','a','n','g','e',0};
55 static const WCHAR clickW[] = {'c','l','i','c','k',0};
56 static const WCHAR onclickW[] = {'o','n','c','l','i','c','k',0};
58 static const WCHAR dblclickW[] = {'d','b','l','c','l','i','c','k',0};
59 static const WCHAR ondblclickW[] = {'o','n','d','b','l','c','l','i','c','k',0};
61 static const WCHAR dragW[] = {'d','r','a','g',0};
62 static const WCHAR ondragW[] = {'o','n','d','r','a','g',0};
64 static const WCHAR dragstartW[] = {'d','r','a','g','s','t','a','r','t',0};
65 static const WCHAR ondragstartW[] = {'o','n','d','r','a','g','s','t','a','r','t',0};
67 static const WCHAR focusW[] = {'f','o','c','u','s',0};
68 static const WCHAR onfocusW[] = {'o','n','f','o','c','u','s',0};
70 static const WCHAR keydownW[] = {'k','e','y','d','o','w','n',0};
71 static const WCHAR onkeydownW[] = {'o','n','k','e','y','d','o','w','n',0};
73 static const WCHAR keyupW[] = {'k','e','y','u','p',0};
74 static const WCHAR onkeyupW[] = {'o','n','k','e','y','u','p',0};
76 static const WCHAR loadW[] = {'l','o','a','d',0};
77 static const WCHAR onloadW[] = {'o','n','l','o','a','d',0};
79 static const WCHAR mousedownW[] = {'m','o','u','s','e','d','o','w','n',0};
80 static const WCHAR onmousedownW[] = {'o','n','m','o','u','s','e','d','o','w','n',0};
82 static const WCHAR mouseoutW[] = {'m','o','u','s','e','o','u','t',0};
83 static const WCHAR onmouseoutW[] = {'o','n','m','o','u','s','e','o','u','t',0};
85 static const WCHAR mouseoverW[] = {'m','o','u','s','e','o','v','e','r',0};
86 static const WCHAR onmouseoverW[] = {'o','n','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 onmouseupW[] = {'o','n','m','o','u','s','e','u','p',0};
91 static const WCHAR pasteW[] = {'p','a','s','t','e',0};
92 static const WCHAR onpasteW[] = {'o','n','p','a','s','t','e',0};
94 static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
95 static const WCHAR onreadystatechangeW[] = {'o','n','r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
97 static const WCHAR selectstartW[] = {'s','e','l','e','c','t','s','t','a','r','t',0};
98 static const WCHAR onselectstartW[] = {'o','n','s','e','l','e','c','t','s','t','a','r','t',0};
100 static const WCHAR HTMLEventsW[] = {'H','T','M','L','E','v','e','n','t','s',0};
101 static const WCHAR KeyboardEventW[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
102 static const WCHAR MouseEventW[] = {'M','o','u','s','e','E','v','e','n','t',0};
104 enum {
105 EVENTT_NONE,
106 EVENTT_HTML,
107 EVENTT_KEY,
108 EVENTT_MOUSE
111 static const WCHAR *event_types[] = {
112 NULL,
113 HTMLEventsW,
114 KeyboardEventW,
115 MouseEventW
118 typedef struct {
119 LPCWSTR name;
120 LPCWSTR attr_name;
121 DWORD type;
122 DISPID dispid;
123 DWORD flags;
124 } event_info_t;
126 #define EVENT_DEFAULTLISTENER 0x0001
127 #define EVENT_BUBBLE 0x0002
128 #define EVENT_FORWARDBODY 0x0004
130 static const event_info_t event_info[] = {
131 {beforeunloadW, onbeforeunloadW, EVENTT_NONE, DISPID_EVMETH_ONBEFOREUNLOAD,
132 EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
133 {blurW, onblurW, EVENTT_HTML, DISPID_EVMETH_ONBLUR,
134 EVENT_DEFAULTLISTENER},
135 {changeW, onchangeW, EVENTT_HTML, DISPID_EVMETH_ONCHANGE,
136 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
137 {clickW, onclickW, EVENTT_MOUSE, DISPID_EVMETH_ONCLICK,
138 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
139 {dblclickW, ondblclickW, EVENTT_MOUSE, DISPID_EVMETH_ONDBLCLICK,
140 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
141 {dragW, ondragW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAG,
143 {dragstartW, ondragstartW, EVENTT_MOUSE, DISPID_EVMETH_ONDRAGSTART,
145 {focusW, onfocusW, EVENTT_HTML, DISPID_EVMETH_ONFOCUS,
146 EVENT_DEFAULTLISTENER},
147 {keydownW, onkeydownW, EVENTT_KEY, DISPID_EVMETH_ONKEYDOWN,
148 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
149 {keyupW, onkeyupW, EVENTT_KEY, DISPID_EVMETH_ONKEYUP,
150 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
151 {loadW, onloadW, EVENTT_HTML, DISPID_EVMETH_ONLOAD,
153 {mousedownW, onmousedownW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
154 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
155 {mouseoutW, onmouseoutW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOUT,
156 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
157 {mouseoverW, onmouseoverW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEOVER,
158 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
159 {mouseupW, onmouseupW, EVENTT_MOUSE, DISPID_EVMETH_ONMOUSEUP,
160 EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
161 {pasteW, onpasteW, EVENTT_NONE, DISPID_EVMETH_ONPASTE,
163 {readystatechangeW, onreadystatechangeW, EVENTT_NONE, DISPID_EVMETH_ONREADYSTATECHANGE,
165 {selectstartW, onselectstartW, EVENTT_MOUSE, DISPID_EVMETH_ONSELECTSTART,
169 eventid_t str_to_eid(LPCWSTR str)
171 int i;
173 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
174 if(!strcmpW(event_info[i].name, str))
175 return i;
178 ERR("unknown type %s\n", debugstr_w(str));
179 return EVENTID_LAST;
182 static eventid_t attr_to_eid(LPCWSTR str)
184 int i;
186 for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
187 if(!strcmpW(event_info[i].attr_name, str))
188 return i;
191 return EVENTID_LAST;
194 typedef struct {
195 DispatchEx dispex;
196 const IHTMLEventObjVtbl *lpIHTMLEventObjVtbl;
198 LONG ref;
200 HTMLDOMNode *target;
201 const event_info_t *type;
202 nsIDOMEvent *nsevent;
203 } HTMLEventObj;
205 #define HTMLEVENTOBJ(x) ((IHTMLEventObj*) &(x)->lpIHTMLEventObjVtbl)
207 #define HTMLEVENTOBJ_THIS(iface) DEFINE_THIS(HTMLEventObj, IHTMLEventObj, iface)
209 static HRESULT WINAPI HTMLEventObj_QueryInterface(IHTMLEventObj *iface, REFIID riid, void **ppv)
211 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
213 *ppv = NULL;
215 if(IsEqualGUID(&IID_IUnknown, riid)) {
216 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
217 *ppv = HTMLEVENTOBJ(This);
218 }else if(IsEqualGUID(&IID_IHTMLEventObj, riid)) {
219 TRACE("(%p)->(IID_IHTMLEventObj %p)\n", This, ppv);
220 *ppv = HTMLEVENTOBJ(This);
221 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
222 return *ppv ? S_OK : E_NOINTERFACE;
225 if(*ppv) {
226 IUnknown_AddRef((IUnknown*)*ppv);
227 return S_OK;
230 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
231 return E_NOINTERFACE;
234 static ULONG WINAPI HTMLEventObj_AddRef(IHTMLEventObj *iface)
236 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
237 LONG ref = InterlockedIncrement(&This->ref);
239 TRACE("(%p) ref=%d\n", This, ref);
241 return ref;
244 static ULONG WINAPI HTMLEventObj_Release(IHTMLEventObj *iface)
246 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
247 LONG ref = InterlockedDecrement(&This->ref);
249 TRACE("(%p) ref=%d\n", This, ref);
251 if(!ref) {
252 if(This->nsevent)
253 nsIDOMEvent_Release(This->nsevent);
254 release_dispex(&This->dispex);
255 heap_free(This);
258 return ref;
261 static HRESULT WINAPI HTMLEventObj_GetTypeInfoCount(IHTMLEventObj *iface, UINT *pctinfo)
263 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
264 FIXME("(%p)->(%p)\n", This, pctinfo);
265 return E_NOTIMPL;
268 static HRESULT WINAPI HTMLEventObj_GetTypeInfo(IHTMLEventObj *iface, UINT iTInfo,
269 LCID lcid, ITypeInfo **ppTInfo)
271 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
272 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
273 return E_NOTIMPL;
276 static HRESULT WINAPI HTMLEventObj_GetIDsOfNames(IHTMLEventObj *iface, REFIID riid,
277 LPOLESTR *rgszNames, UINT cNames,
278 LCID lcid, DISPID *rgDispId)
280 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
281 FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
282 lcid, rgDispId);
283 return E_NOTIMPL;
286 static HRESULT WINAPI HTMLEventObj_Invoke(IHTMLEventObj *iface, DISPID dispIdMember,
287 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
288 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
290 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
291 FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
292 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
293 return E_NOTIMPL;
296 static HRESULT WINAPI HTMLEventObj_get_srcElement(IHTMLEventObj *iface, IHTMLElement **p)
298 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
300 TRACE("(%p)->(%p)\n", This, p);
302 return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(This->target), &IID_IHTMLElement, (void**)p);
305 static HRESULT WINAPI HTMLEventObj_get_altKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
307 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
308 PRBool ret = FALSE;
310 TRACE("(%p)->(%p)\n", This, p);
312 if(This->nsevent) {
313 nsIDOMKeyEvent *key_event;
314 nsresult nsres;
316 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
317 if(NS_SUCCEEDED(nsres)) {
318 nsIDOMKeyEvent_GetAltKey(key_event, &ret);
319 nsIDOMKeyEvent_Release(key_event);
320 }else {
321 nsIDOMMouseEvent *mouse_event;
323 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
324 if(NS_SUCCEEDED(nsres)) {
325 nsIDOMMouseEvent_GetAltKey(mouse_event, &ret);
326 nsIDOMMouseEvent_Release(mouse_event);
331 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
332 return S_OK;
335 static HRESULT WINAPI HTMLEventObj_get_ctrlKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
337 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
338 PRBool ret = FALSE;
340 TRACE("(%p)->(%p)\n", This, p);
342 if(This->nsevent) {
343 nsIDOMKeyEvent *key_event;
344 nsresult nsres;
346 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
347 if(NS_SUCCEEDED(nsres)) {
348 nsIDOMKeyEvent_GetCtrlKey(key_event, &ret);
349 nsIDOMKeyEvent_Release(key_event);
350 }else {
351 nsIDOMMouseEvent *mouse_event;
353 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
354 if(NS_SUCCEEDED(nsres)) {
355 nsIDOMMouseEvent_GetCtrlKey(mouse_event, &ret);
356 nsIDOMMouseEvent_Release(mouse_event);
361 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
362 return S_OK;
365 static HRESULT WINAPI HTMLEventObj_get_shiftKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
367 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
368 PRBool ret = FALSE;
370 TRACE("(%p)->(%p)\n", This, p);
372 if(This->nsevent) {
373 nsIDOMKeyEvent *key_event;
374 nsresult nsres;
376 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
377 if(NS_SUCCEEDED(nsres)) {
378 nsIDOMKeyEvent_GetShiftKey(key_event, &ret);
379 nsIDOMKeyEvent_Release(key_event);
380 }else {
381 nsIDOMMouseEvent *mouse_event;
383 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
384 if(NS_SUCCEEDED(nsres)) {
385 nsIDOMMouseEvent_GetShiftKey(mouse_event, &ret);
386 nsIDOMMouseEvent_Release(mouse_event);
391 *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
392 return S_OK;
395 static HRESULT WINAPI HTMLEventObj_put_returnValue(IHTMLEventObj *iface, VARIANT v)
397 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
398 FIXME("(%p)->()\n", This);
399 return E_NOTIMPL;
402 static HRESULT WINAPI HTMLEventObj_get_returnValue(IHTMLEventObj *iface, VARIANT *p)
404 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
406 FIXME("(%p)->(%p)\n", This, p);
408 V_VT(p) = VT_EMPTY;
409 return S_OK;
412 static HRESULT WINAPI HTMLEventObj_put_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL v)
414 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
415 FIXME("(%p)->(%x)\n", This, v);
416 return E_NOTIMPL;
419 static HRESULT WINAPI HTMLEventObj_get_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL *p)
421 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
423 FIXME("(%p)->(%p)\n", This, p);
425 *p = VARIANT_FALSE;
426 return S_OK;
429 static HRESULT WINAPI HTMLEventObj_get_fromElement(IHTMLEventObj *iface, IHTMLElement **p)
431 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
433 FIXME("(%p)->(%p)\n", This, p);
435 *p = NULL;
436 return S_OK;
439 static HRESULT WINAPI HTMLEventObj_get_toElement(IHTMLEventObj *iface, IHTMLElement **p)
441 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
443 FIXME("(%p)->(%p)\n", This, p);
445 *p = NULL;
446 return S_OK;
449 static HRESULT WINAPI HTMLEventObj_put_keyCode(IHTMLEventObj *iface, LONG v)
451 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
452 FIXME("(%p)->(%d)\n", This, v);
453 return E_NOTIMPL;
456 static HRESULT WINAPI HTMLEventObj_get_keyCode(IHTMLEventObj *iface, LONG *p)
458 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
459 PRUint32 key_code = 0;
461 TRACE("(%p)->(%p)\n", This, p);
463 if(This->nsevent) {
464 nsIDOMKeyEvent *key_event;
465 nsresult nsres;
467 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
468 if(NS_SUCCEEDED(nsres)) {
469 nsIDOMKeyEvent_GetKeyCode(key_event, &key_code);
470 nsIDOMKeyEvent_Release(key_event);
474 *p = key_code;
475 return S_OK;
478 static HRESULT WINAPI HTMLEventObj_get_button(IHTMLEventObj *iface, LONG *p)
480 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
481 PRUint16 button = 0;
483 TRACE("(%p)->(%p)\n", This, p);
485 if(This->nsevent) {
486 nsIDOMMouseEvent *mouse_event;
487 nsresult nsres;
489 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
490 if(NS_SUCCEEDED(nsres)) {
491 nsIDOMMouseEvent_GetButton(mouse_event, &button);
492 nsIDOMMouseEvent_Release(mouse_event);
496 *p = button;
497 return S_OK;
500 static HRESULT WINAPI HTMLEventObj_get_type(IHTMLEventObj *iface, BSTR *p)
502 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
504 TRACE("(%p)->(%p)\n", This, p);
506 *p = SysAllocString(This->type->name);
507 return *p ? S_OK : E_OUTOFMEMORY;
510 static HRESULT WINAPI HTMLEventObj_get_qualifier(IHTMLEventObj *iface, BSTR *p)
512 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
514 FIXME("(%p)->(%p)\n", This, p);
516 *p = NULL;
517 return S_OK;
520 static HRESULT WINAPI HTMLEventObj_get_reason(IHTMLEventObj *iface, LONG *p)
522 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
524 FIXME("(%p)->(%p)\n", This, p);
526 *p = 0;
527 return S_OK;
530 static HRESULT WINAPI HTMLEventObj_get_x(IHTMLEventObj *iface, LONG *p)
532 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
534 FIXME("(%p)->(%p)\n", This, p);
536 *p = -1;
537 return S_OK;
540 static HRESULT WINAPI HTMLEventObj_get_y(IHTMLEventObj *iface, LONG *p)
542 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
544 FIXME("(%p)->(%p)\n", This, p);
546 *p = -1;
547 return S_OK;
550 static HRESULT WINAPI HTMLEventObj_get_clientX(IHTMLEventObj *iface, LONG *p)
552 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
553 PRInt32 x = 0;
555 TRACE("(%p)->(%p)\n", This, p);
557 if(This->nsevent) {
558 nsIDOMMouseEvent *mouse_event;
559 nsresult nsres;
561 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
562 if(NS_SUCCEEDED(nsres)) {
563 nsIDOMMouseEvent_GetClientX(mouse_event, &x);
564 nsIDOMMouseEvent_Release(mouse_event);
568 *p = x;
569 return S_OK;
572 static HRESULT WINAPI HTMLEventObj_get_clientY(IHTMLEventObj *iface, LONG *p)
574 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
575 PRInt32 y = 0;
577 TRACE("(%p)->(%p)\n", This, p);
579 if(This->nsevent) {
580 nsIDOMMouseEvent *mouse_event;
581 nsresult nsres;
583 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
584 if(NS_SUCCEEDED(nsres)) {
585 nsIDOMMouseEvent_GetClientY(mouse_event, &y);
586 nsIDOMMouseEvent_Release(mouse_event);
590 *p = y;
591 return S_OK;
594 static HRESULT WINAPI HTMLEventObj_get_offsetX(IHTMLEventObj *iface, LONG *p)
596 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
598 FIXME("(%p)->(%p)\n", This, p);
600 *p = 0;
601 return S_OK;
604 static HRESULT WINAPI HTMLEventObj_get_offsetY(IHTMLEventObj *iface, LONG *p)
606 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
608 FIXME("(%p)->(%p)\n", This, p);
610 *p = 0;
611 return S_OK;
614 static HRESULT WINAPI HTMLEventObj_get_screenX(IHTMLEventObj *iface, LONG *p)
616 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
617 PRInt32 x = 0;
619 TRACE("(%p)->(%p)\n", This, p);
621 if(This->nsevent) {
622 nsIDOMMouseEvent *mouse_event;
623 nsresult nsres;
625 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
626 if(NS_SUCCEEDED(nsres)) {
627 nsIDOMMouseEvent_GetScreenX(mouse_event, &x);
628 nsIDOMMouseEvent_Release(mouse_event);
632 *p = x;
633 return S_OK;
636 static HRESULT WINAPI HTMLEventObj_get_screenY(IHTMLEventObj *iface, LONG *p)
638 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
639 PRInt32 y = 0;
641 TRACE("(%p)->(%p)\n", This, p);
643 if(This->nsevent) {
644 nsIDOMMouseEvent *mouse_event;
645 nsresult nsres;
647 nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
648 if(NS_SUCCEEDED(nsres)) {
649 nsIDOMMouseEvent_GetScreenY(mouse_event, &y);
650 nsIDOMMouseEvent_Release(mouse_event);
654 *p = y;
655 return S_OK;
658 static HRESULT WINAPI HTMLEventObj_get_srcFilter(IHTMLEventObj *iface, IDispatch **p)
660 HTMLEventObj *This = HTMLEVENTOBJ_THIS(iface);
662 FIXME("(%p)->(%p)\n", This, p);
664 *p = NULL;
665 return S_OK;
668 #undef HTMLEVENTOBJ_THIS
670 static const IHTMLEventObjVtbl HTMLEventObjVtbl = {
671 HTMLEventObj_QueryInterface,
672 HTMLEventObj_AddRef,
673 HTMLEventObj_Release,
674 HTMLEventObj_GetTypeInfoCount,
675 HTMLEventObj_GetTypeInfo,
676 HTMLEventObj_GetIDsOfNames,
677 HTMLEventObj_Invoke,
678 HTMLEventObj_get_srcElement,
679 HTMLEventObj_get_altKey,
680 HTMLEventObj_get_ctrlKey,
681 HTMLEventObj_get_shiftKey,
682 HTMLEventObj_put_returnValue,
683 HTMLEventObj_get_returnValue,
684 HTMLEventObj_put_cancelBubble,
685 HTMLEventObj_get_cancelBubble,
686 HTMLEventObj_get_fromElement,
687 HTMLEventObj_get_toElement,
688 HTMLEventObj_put_keyCode,
689 HTMLEventObj_get_keyCode,
690 HTMLEventObj_get_button,
691 HTMLEventObj_get_type,
692 HTMLEventObj_get_qualifier,
693 HTMLEventObj_get_reason,
694 HTMLEventObj_get_x,
695 HTMLEventObj_get_y,
696 HTMLEventObj_get_clientX,
697 HTMLEventObj_get_clientY,
698 HTMLEventObj_get_offsetX,
699 HTMLEventObj_get_offsetY,
700 HTMLEventObj_get_screenX,
701 HTMLEventObj_get_screenY,
702 HTMLEventObj_get_srcFilter
705 static const tid_t HTMLEventObj_iface_tids[] = {
706 IHTMLEventObj_tid,
710 static dispex_static_data_t HTMLEventObj_dispex = {
711 NULL,
712 DispCEventObj_tid,
713 NULL,
714 HTMLEventObj_iface_tids
717 static IHTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEvent *nsevent)
719 HTMLEventObj *ret;
721 ret = heap_alloc(sizeof(*ret));
722 if(!ret)
723 return NULL;
725 ret->lpIHTMLEventObjVtbl = &HTMLEventObjVtbl;
726 ret->ref = 1;
727 ret->type = event_info+eid;
729 ret->nsevent = nsevent;
730 if(nsevent) {
731 nsIDOMEvent_AddRef(nsevent);
732 }else if(event_types[event_info[eid].type]) {
733 nsIDOMDocumentEvent *doc_event;
734 nsresult nsres;
736 nsres = nsIDOMHTMLDocument_QueryInterface(target->doc->nsdoc, &IID_nsIDOMDocumentEvent,
737 (void**)&doc_event);
738 if(NS_SUCCEEDED(nsres)) {
739 nsAString type_str;
741 nsAString_Init(&type_str, event_types[event_info[eid].type]);
742 nsres = nsIDOMDocumentEvent_CreateEvent(doc_event, &type_str, &ret->nsevent);
743 nsAString_Finish(&type_str);
744 nsIDOMDocumentEvent_Release(doc_event);
746 if(NS_FAILED(nsres)) {
747 ERR("Could not create event: %08x\n", nsres);
748 IHTMLEventObj_Release(HTMLEVENTOBJ(ret));
749 return NULL;
753 ret->target = target;
754 IHTMLDOMNode_AddRef(HTMLDOMNODE(target));
756 init_dispex(&ret->dispex, (IUnknown*)HTMLEVENTOBJ(ret), &HTMLEventObj_dispex);
758 return HTMLEVENTOBJ(ret);
761 static HRESULT call_cp_func(IDispatch *disp, DISPID dispid)
763 DISPPARAMS dp = {NULL,NULL,0,0};
764 ULONG argerr;
765 EXCEPINFO ei;
766 VARIANT vres;
767 HRESULT hres;
769 V_VT(&vres) = VT_EMPTY;
770 memset(&ei, 0, sizeof(ei));
771 hres = IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, &vres, &ei, &argerr);
772 if(SUCCEEDED(hres) && V_VT(&vres) != VT_EMPTY) {
773 FIXME("handle result %s\n", debugstr_variant(&vres));
774 VariantClear(&vres);
777 return hres;
780 static BOOL is_cp_event(ConnectionPoint *cp, DISPID dispid)
782 cp_static_data_t *data;
783 int min, max, i;
784 HRESULT hres;
786 data = cp->data;
787 if(!data)
788 return FALSE;
790 if(!data->ids) {
791 hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
792 if(FAILED(hres))
793 return FALSE;
796 min = 0;
797 max = data->id_cnt-1;
798 while(min <= max) {
799 i = (min+max)/2;
800 if(data->ids[i] == dispid)
801 return TRUE;
803 if(data->ids[i] < dispid)
804 min = i+1;
805 else
806 max = i-1;
809 return FALSE;
812 static void call_event_handlers(HTMLDocumentNode *doc, IHTMLEventObj *event_obj, event_target_t *event_target,
813 ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj)
815 handler_vector_t *handler_vector = NULL;
816 DWORD i;
817 HRESULT hres;
819 if(event_target)
820 handler_vector = event_target->event_table[eid];
822 if(handler_vector && handler_vector->handler_prop) {
823 DISPID named_arg = DISPID_THIS;
824 VARIANTARG arg;
825 DISPPARAMS dp = {&arg, &named_arg, 1, 1};
827 V_VT(&arg) = VT_DISPATCH;
828 V_DISPATCH(&arg) = this_obj;
830 TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
831 hres = call_disp_func(handler_vector->handler_prop, &dp);
832 if(hres == S_OK)
833 TRACE("%s <<<\n", debugstr_w(event_info[eid].name));
834 else
835 WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
838 if(handler_vector && handler_vector->handler_cnt) {
839 VARIANTARG arg;
840 DISPPARAMS dp = {&arg, NULL, 1, 0};
842 V_VT(&arg) = VT_DISPATCH;
843 V_DISPATCH(&arg) = (IDispatch*)event_obj;
845 for(i=0; i < handler_vector->handler_cnt; i++) {
846 if(handler_vector->handlers[i]) {
847 TRACE("%s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
848 hres = call_disp_func(handler_vector->handlers[i], &dp);
849 if(hres == S_OK)
850 TRACE("%s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
851 else
852 WARN("%s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
857 if(cp_container) {
858 ConnectionPoint *cp;
860 if(cp_container->forward_container)
861 cp_container = cp_container->forward_container;
863 for(cp = cp_container->cp_list; cp; cp = cp->next) {
864 if(cp->sinks_size && is_cp_event(cp, event_info[eid].dispid)) {
865 for(i=0; i < cp->sinks_size; i++) {
866 TRACE("cp %s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
867 hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid);
868 if(hres == S_OK)
869 TRACE("cp %s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
870 else
871 WARN("cp %s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
878 void fire_event(HTMLDocumentNode *doc, eventid_t eid, nsIDOMNode *target, nsIDOMEvent *nsevent)
880 IHTMLEventObj *prev_event, *event_obj = NULL;
881 nsIDOMNode *parent, *nsnode;
882 HTMLDOMNode *node;
883 PRUint16 node_type;
885 TRACE("(%p) %s\n", doc, debugstr_w(event_info[eid].name));
887 prev_event = doc->basedoc.window->event;
888 event_obj = doc->basedoc.window->event = create_event(get_node(doc, target, TRUE), eid, nsevent);
890 nsIDOMNode_GetNodeType(target, &node_type);
891 nsnode = target;
892 nsIDOMNode_AddRef(nsnode);
894 switch(node_type) {
895 case ELEMENT_NODE:
896 do {
897 node = get_node(doc, nsnode, FALSE);
898 if(node)
899 call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container, eid,
900 (IDispatch*)HTMLDOMNODE(node));
902 if(!(event_info[eid].flags & EVENT_BUBBLE))
903 break;
905 nsIDOMNode_GetParentNode(nsnode, &parent);
906 nsIDOMNode_Release(nsnode);
907 nsnode = parent;
908 if(!nsnode)
909 break;
911 nsIDOMNode_GetNodeType(nsnode, &node_type);
912 }while(node_type == ELEMENT_NODE);
914 if(!(event_info[eid].flags & EVENT_BUBBLE))
915 break;
917 case DOCUMENT_NODE:
918 if(event_info[eid].flags & EVENT_FORWARDBODY) {
919 nsIDOMHTMLElement *nsbody;
920 nsresult nsres;
922 nsres = nsIDOMHTMLDocument_GetBody(doc->nsdoc, &nsbody);
923 if(NS_SUCCEEDED(nsres) && nsbody) {
924 node = get_node(doc, (nsIDOMNode*)nsbody, FALSE);
925 if(node)
926 call_event_handlers(doc, event_obj, *get_node_event_target(node), node->cp_container,
927 eid, (IDispatch*)HTMLDOMNODE(node));
928 nsIDOMHTMLElement_Release(nsbody);
929 }else {
930 ERR("Could not get body: %08x\n", nsres);
934 call_event_handlers(doc, event_obj, doc->basedoc.doc_node->node.event_target, &doc->basedoc.cp_container, eid,
935 (IDispatch*)HTMLDOC(&doc->basedoc));
936 break;
938 default:
939 FIXME("unimplemented node type %d\n", node_type);
942 if(nsnode)
943 nsIDOMNode_Release(nsnode);
945 IHTMLEventObj_Release(event_obj);
946 doc->basedoc.window->event = prev_event;
949 HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_obj, VARIANT_BOOL *cancelled)
951 eventid_t eid;
953 eid = attr_to_eid(event_name);
954 if(eid == EVENTID_LAST) {
955 WARN("unknown event %s\n", debugstr_w(event_name));
956 return E_INVALIDARG;
959 if(event_obj && V_VT(event_obj) != VT_EMPTY && V_VT(event_obj) != VT_ERROR)
960 FIXME("event_obj not implemented\n");
962 if(!(event_info[eid].flags & EVENT_DEFAULTLISTENER)) {
963 FIXME("not EVENT_DEFAULTEVENTHANDLER\n");
964 return E_NOTIMPL;
967 fire_event(node->doc, eid, node->nsnode, NULL);
969 *cancelled = VARIANT_TRUE; /* FIXME */
970 return S_OK;
973 HRESULT call_event(HTMLDOMNode *node, eventid_t eid)
975 HRESULT hres;
977 if(node->vtbl->call_event) {
978 BOOL handled = FALSE;
980 hres = node->vtbl->call_event(node, eid, &handled);
981 if(handled)
982 return hres;
985 fire_event(node->doc, eid, node->nsnode, NULL);
986 return S_OK;
989 static inline event_target_t *get_event_target(event_target_t **event_target_ptr)
991 if(!*event_target_ptr)
992 *event_target_ptr = heap_alloc_zero(sizeof(event_target_t));
993 return *event_target_ptr;
996 static BOOL alloc_handler_vector(event_target_t *event_target, eventid_t eid, int cnt)
998 handler_vector_t *new_vector, *handler_vector = event_target->event_table[eid];
1000 if(handler_vector) {
1001 if(cnt <= handler_vector->handler_cnt)
1002 return TRUE;
1004 new_vector = heap_realloc_zero(handler_vector, sizeof(handler_vector_t) + sizeof(IDispatch*)*cnt);
1005 }else {
1006 new_vector = heap_alloc_zero(sizeof(handler_vector_t) + sizeof(IDispatch*)*cnt);
1009 if(!new_vector)
1010 return FALSE;
1012 new_vector->handler_cnt = cnt;
1013 event_target->event_table[eid] = new_vector;
1014 return TRUE;
1017 static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDocumentNode *doc,
1018 eventid_t eid, IDispatch *disp)
1020 event_target_t *event_target;
1022 event_target = get_event_target(event_target_ptr);
1023 if(!event_target)
1024 return E_OUTOFMEMORY;
1026 if(!alloc_handler_vector(event_target, eid, 0))
1027 return E_OUTOFMEMORY;
1029 if(event_target->event_table[eid]->handler_prop)
1030 IDispatch_Release(event_target->event_table[eid]->handler_prop);
1032 event_target->event_table[eid]->handler_prop = disp;
1033 if(!disp)
1034 return S_OK;
1035 IDispatch_AddRef(disp);
1037 if(doc->nsdoc && (event_info[eid].flags & EVENT_DEFAULTLISTENER)) {
1038 if(!doc->event_vector) {
1039 doc->event_vector = heap_alloc_zero(EVENTID_LAST*sizeof(BOOL));
1040 if(!doc->event_vector)
1041 return E_OUTOFMEMORY;
1044 if(!doc->event_vector[eid]) {
1045 doc->event_vector[eid] = TRUE;
1046 add_nsevent_listener(doc, event_info[eid].name);
1050 return S_OK;
1053 HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var)
1055 switch(V_VT(var)) {
1056 case VT_NULL:
1057 if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) {
1058 IDispatch_Release((*event_target)->event_table[eid]->handler_prop);
1059 (*event_target)->event_table[eid]->handler_prop = NULL;
1061 break;
1063 case VT_DISPATCH:
1064 return set_event_handler_disp(event_target, doc, eid, V_DISPATCH(var));
1066 default:
1067 FIXME("not supported vt=%d\n", V_VT(var));
1068 return E_NOTIMPL;
1071 return S_OK;
1074 HRESULT get_event_handler(event_target_t **event_target, eventid_t eid, VARIANT *var)
1076 if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) {
1077 V_VT(var) = VT_DISPATCH;
1078 V_DISPATCH(var) = (*event_target)->event_table[eid]->handler_prop;
1079 IDispatch_AddRef(V_DISPATCH(var));
1080 }else {
1081 V_VT(var) = VT_NULL;
1084 return S_OK;
1087 HRESULT attach_event(event_target_t **event_target_ptr, HTMLDocument *doc, BSTR name, IDispatch *disp, VARIANT_BOOL *res)
1089 event_target_t *event_target;
1090 eventid_t eid;
1091 DWORD i = 0;
1093 eid = attr_to_eid(name);
1094 if(eid == EVENTID_LAST) {
1095 WARN("Unknown event\n");
1096 *res = VARIANT_TRUE;
1097 return S_OK;
1100 event_target = get_event_target(event_target_ptr);
1101 if(!event_target)
1102 return E_OUTOFMEMORY;
1104 if(event_target->event_table[eid]) {
1105 while(i < event_target->event_table[eid]->handler_cnt && event_target->event_table[eid]->handlers[i])
1106 i++;
1107 if(i == event_target->event_table[eid]->handler_cnt && !alloc_handler_vector(event_target, eid, i+1))
1108 return E_OUTOFMEMORY;
1109 }else if(!alloc_handler_vector(event_target, eid, i+1)) {
1110 return E_OUTOFMEMORY;
1113 IDispatch_AddRef(disp);
1114 event_target->event_table[eid]->handlers[i] = disp;
1116 *res = VARIANT_TRUE;
1117 return S_OK;
1120 void check_event_attr(HTMLDocumentNode *doc, nsIDOMElement *nselem)
1122 const PRUnichar *attr_value;
1123 nsAString attr_name_str, attr_value_str;
1124 IDispatch *disp;
1125 HTMLDOMNode *node;
1126 int i;
1127 nsresult nsres;
1129 nsAString_Init(&attr_value_str, NULL);
1130 nsAString_Init(&attr_name_str, NULL);
1132 for(i=0; i < EVENTID_LAST; i++) {
1133 nsAString_SetData(&attr_name_str, event_info[i].attr_name);
1134 nsres = nsIDOMElement_GetAttribute(nselem, &attr_name_str, &attr_value_str);
1135 if(NS_SUCCEEDED(nsres)) {
1136 nsAString_GetData(&attr_value_str, &attr_value);
1137 if(!*attr_value)
1138 continue;
1140 TRACE("%p.%s = %s\n", nselem, debugstr_w(event_info[i].attr_name), debugstr_w(attr_value));
1142 disp = script_parse_event(doc->basedoc.window, attr_value);
1143 if(disp) {
1144 node = get_node(doc, (nsIDOMNode*)nselem, TRUE);
1145 set_event_handler_disp(get_node_event_target(node), node->doc, i, disp);
1146 IDispatch_Release(disp);
1151 nsAString_Finish(&attr_value_str);
1152 nsAString_Finish(&attr_name_str);
1155 void release_event_target(event_target_t *event_target)
1157 int i, j;
1159 for(i=0; i < EVENTID_LAST; i++) {
1160 if(event_target->event_table[i]) {
1161 if(event_target->event_table[i]->handler_prop)
1162 IDispatch_Release(event_target->event_table[i]->handler_prop);
1163 for(j=0; j < event_target->event_table[i]->handler_cnt; j++)
1164 IDispatch_Release(event_target->event_table[i]->handlers[j]);
1168 heap_free(event_target);