winex11: Get the current pixel format from the drawable structure in wglCreateContext...
[wine] / dlls / mshtml / htmlevent.c
1 /*
2  * Copyright 2008-2009 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27 #include "mshtmdid.h"
28
29 #include "mshtml_private.h"
30 #include "htmlevent.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
35
36 typedef struct {
37     IDispatch *handler_prop;
38     DWORD handler_cnt;
39     IDispatch *handlers[0];
40 } handler_vector_t;
41
42 struct event_target_t {
43     DWORD node_handlers_mask;
44     handler_vector_t *event_table[EVENTID_LAST];
45 };
46
47 static const WCHAR beforeunloadW[] = {'b','e','f','o','r','e','u','n','l','o','a','d',0};
48 static const WCHAR onbeforeunloadW[] = {'o','n','b','e','f','o','r','e','u','n','l','o','a','d',0};
49
50 static const WCHAR blurW[] = {'b','l','u','r',0};
51 static const WCHAR onblurW[] = {'o','n','b','l','u','r',0};
52
53 static const WCHAR changeW[] = {'c','h','a','n','g','e',0};
54 static const WCHAR onchangeW[] = {'o','n','c','h','a','n','g','e',0};
55
56 static const WCHAR clickW[] = {'c','l','i','c','k',0};
57 static const WCHAR onclickW[] = {'o','n','c','l','i','c','k',0};
58
59 static const WCHAR contextmenuW[] = {'c','o','n','t','e','x','t','m','e','n','u',0};
60 static const WCHAR oncontextmenuW[] = {'o','n','c','o','n','t','e','x','t','m','e','n','u',0};
61
62 static const WCHAR dblclickW[] = {'d','b','l','c','l','i','c','k',0};
63 static const WCHAR ondblclickW[] = {'o','n','d','b','l','c','l','i','c','k',0};
64
65 static const WCHAR dragW[] = {'d','r','a','g',0};
66 static const WCHAR ondragW[] = {'o','n','d','r','a','g',0};
67
68 static const WCHAR dragstartW[] = {'d','r','a','g','s','t','a','r','t',0};
69 static const WCHAR ondragstartW[] = {'o','n','d','r','a','g','s','t','a','r','t',0};
70
71 static const WCHAR errorW[] = {'e','r','r','o','r',0};
72 static const WCHAR onerrorW[] = {'o','n','e','r','r','o','r',0};
73
74 static const WCHAR focusW[] = {'f','o','c','u','s',0};
75 static const WCHAR onfocusW[] = {'o','n','f','o','c','u','s',0};
76
77 static const WCHAR helpW[] = {'h','e','l','p',0};
78 static const WCHAR onhelpW[] = {'o','n','h','e','l','p',0};
79
80 static const WCHAR keydownW[] = {'k','e','y','d','o','w','n',0};
81 static const WCHAR onkeydownW[] = {'o','n','k','e','y','d','o','w','n',0};
82
83 static const WCHAR keypressW[] = {'k','e','y','p','r','e','s','s',0};
84 static const WCHAR onkeypressW[] = {'o','n','k','e','y','p','r','e','s','s',0};
85
86 static const WCHAR keyupW[] = {'k','e','y','u','p',0};
87 static const WCHAR onkeyupW[] = {'o','n','k','e','y','u','p',0};
88
89 static const WCHAR loadW[] = {'l','o','a','d',0};
90 static const WCHAR onloadW[] = {'o','n','l','o','a','d',0};
91
92 static const WCHAR mousedownW[] = {'m','o','u','s','e','d','o','w','n',0};
93 static const WCHAR onmousedownW[] = {'o','n','m','o','u','s','e','d','o','w','n',0};
94
95 static const WCHAR mousemoveW[] = {'m','o','u','s','e','m','o','v','e',0};
96 static const WCHAR onmousemoveW[] = {'o','n','m','o','u','s','e','m','o','v','e',0};
97
98 static const WCHAR mouseoutW[] = {'m','o','u','s','e','o','u','t',0};
99 static const WCHAR onmouseoutW[] = {'o','n','m','o','u','s','e','o','u','t',0};
100
101 static const WCHAR mouseoverW[] = {'m','o','u','s','e','o','v','e','r',0};
102 static const WCHAR onmouseoverW[] = {'o','n','m','o','u','s','e','o','v','e','r',0};
103
104 static const WCHAR mouseupW[] = {'m','o','u','s','e','u','p',0};
105 static const WCHAR onmouseupW[] = {'o','n','m','o','u','s','e','u','p',0};
106
107 static const WCHAR pasteW[] = {'p','a','s','t','e',0};
108 static const WCHAR onpasteW[] = {'o','n','p','a','s','t','e',0};
109
110 static const WCHAR readystatechangeW[] = {'r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
111 static const WCHAR onreadystatechangeW[] = {'o','n','r','e','a','d','y','s','t','a','t','e','c','h','a','n','g','e',0};
112
113 static const WCHAR resizeW[] = {'r','e','s','i','z','e',0};
114 static const WCHAR onresizeW[] = {'o','n','r','e','s','i','z','e',0};
115
116 static const WCHAR selectstartW[] = {'s','e','l','e','c','t','s','t','a','r','t',0};
117 static const WCHAR onselectstartW[] = {'o','n','s','e','l','e','c','t','s','t','a','r','t',0};
118
119 static const WCHAR submitW[] = {'s','u','b','m','i','t',0};
120 static const WCHAR onsubmitW[] = {'o','n','s','u','b','m','i','t',0};
121
122 static const WCHAR HTMLEventsW[] = {'H','T','M','L','E','v','e','n','t','s',0};
123 static const WCHAR KeyboardEventW[] = {'K','e','y','b','o','a','r','d','E','v','e','n','t',0};
124 static const WCHAR MouseEventW[] = {'M','o','u','s','e','E','v','e','n','t',0};
125
126 enum {
127     EVENTT_NONE,
128     EVENTT_HTML,
129     EVENTT_KEY,
130     EVENTT_MOUSE
131 };
132
133 static const WCHAR *event_types[] = {
134     NULL,
135     HTMLEventsW,
136     KeyboardEventW,
137     MouseEventW
138 };
139
140 typedef struct {
141     LPCWSTR name;
142     LPCWSTR attr_name;
143     DWORD type;
144     DISPID dispid;
145     DWORD flags;
146 } event_info_t;
147
148 #define EVENT_DEFAULTLISTENER    0x0001
149 #define EVENT_BUBBLE             0x0002
150 #define EVENT_FORWARDBODY        0x0004
151 #define EVENT_NODEHANDLER        0x0008
152 #define EVENT_CANCELABLE         0x0010
153 #define EVENT_HASDEFAULTHANDLERS 0x0020
154
155 static const event_info_t event_info[] = {
156     {beforeunloadW,      onbeforeunloadW,      EVENTT_NONE,   DISPID_EVMETH_ONBEFOREUNLOAD,
157         EVENT_DEFAULTLISTENER|EVENT_FORWARDBODY},
158     {blurW,              onblurW,              EVENTT_HTML,   DISPID_EVMETH_ONBLUR,
159         EVENT_DEFAULTLISTENER},
160     {changeW,            onchangeW,            EVENTT_HTML,   DISPID_EVMETH_ONCHANGE,
161         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
162     {clickW,             onclickW,             EVENTT_MOUSE,  DISPID_EVMETH_ONCLICK,
163         EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE|EVENT_HASDEFAULTHANDLERS},
164     {contextmenuW,       oncontextmenuW,       EVENTT_MOUSE,  DISPID_EVMETH_ONCONTEXTMENU,
165         EVENT_BUBBLE|EVENT_CANCELABLE},
166     {dblclickW,          ondblclickW,          EVENTT_MOUSE,  DISPID_EVMETH_ONDBLCLICK,
167         EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE},
168     {dragW,              ondragW,              EVENTT_MOUSE,  DISPID_EVMETH_ONDRAG,
169         EVENT_CANCELABLE},
170     {dragstartW,         ondragstartW,         EVENTT_MOUSE,  DISPID_EVMETH_ONDRAGSTART,
171         EVENT_CANCELABLE},
172     {errorW,             onerrorW,             EVENTT_NONE,   DISPID_EVMETH_ONERROR,
173         EVENT_NODEHANDLER},
174     {focusW,             onfocusW,             EVENTT_HTML,   DISPID_EVMETH_ONFOCUS,
175         EVENT_DEFAULTLISTENER},
176     {helpW,              onhelpW,              EVENTT_KEY,    DISPID_EVMETH_ONHELP,
177         EVENT_BUBBLE|EVENT_CANCELABLE},
178     {keydownW,           onkeydownW,           EVENTT_KEY,    DISPID_EVMETH_ONKEYDOWN,
179         EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_HASDEFAULTHANDLERS},
180     {keypressW,          onkeypressW,          EVENTT_KEY,    DISPID_EVMETH_ONKEYPRESS,
181         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
182     {keyupW,             onkeyupW,             EVENTT_KEY,    DISPID_EVMETH_ONKEYUP,
183         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
184     {loadW,              onloadW,              EVENTT_HTML,   DISPID_EVMETH_ONLOAD,
185         EVENT_NODEHANDLER},
186     {mousedownW,         onmousedownW,         EVENTT_MOUSE,  DISPID_EVMETH_ONMOUSEDOWN,
187         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
188     {mousemoveW,         onmousemoveW,         EVENTT_MOUSE,  DISPID_EVMETH_ONMOUSEMOVE,
189         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
190     {mouseoutW,          onmouseoutW,          EVENTT_MOUSE,  DISPID_EVMETH_ONMOUSEOUT,
191         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
192     {mouseoverW,         onmouseoverW,         EVENTT_MOUSE,  DISPID_EVMETH_ONMOUSEOVER,
193         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
194     {mouseupW,           onmouseupW,           EVENTT_MOUSE,  DISPID_EVMETH_ONMOUSEUP,
195         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
196     {pasteW,             onpasteW,             EVENTT_NONE,   DISPID_EVMETH_ONPASTE,
197         EVENT_CANCELABLE},
198     {readystatechangeW,  onreadystatechangeW,  EVENTT_NONE,   DISPID_EVMETH_ONREADYSTATECHANGE,
199         0},
200     {resizeW,            onresizeW,            EVENTT_NONE,   DISPID_EVMETH_ONRESIZE,
201         EVENT_DEFAULTLISTENER|EVENT_BUBBLE},
202     {selectstartW,       onselectstartW,       EVENTT_MOUSE,  DISPID_EVMETH_ONSELECTSTART,
203         EVENT_CANCELABLE},
204     {submitW,            onsubmitW,            EVENTT_HTML,   DISPID_EVMETH_ONSUBMIT,
205         EVENT_DEFAULTLISTENER|EVENT_BUBBLE|EVENT_CANCELABLE}
206 };
207
208 static const eventid_t node_handled_list[] = { EVENTID_ERROR, EVENTID_LOAD };
209
210 eventid_t str_to_eid(LPCWSTR str)
211 {
212     int i;
213
214     for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
215         if(!strcmpW(event_info[i].name, str))
216             return i;
217     }
218
219     ERR("unknown type %s\n", debugstr_w(str));
220     return EVENTID_LAST;
221 }
222
223 static eventid_t attr_to_eid(LPCWSTR str)
224 {
225     int i;
226
227     for(i=0; i < sizeof(event_info)/sizeof(event_info[0]); i++) {
228         if(!strcmpW(event_info[i].attr_name, str))
229             return i;
230     }
231
232     return EVENTID_LAST;
233 }
234
235 static DWORD get_node_handler_mask(eventid_t eid)
236 {
237     DWORD i;
238
239     for(i=0; i<sizeof(node_handled_list)/sizeof(*node_handled_list); i++) {
240         if(node_handled_list[i] == eid)
241             return 1 << i;
242     }
243
244     ERR("Invalid eid %d\n", eid);
245     return ~0;
246 }
247
248 typedef struct {
249     DispatchEx dispex;
250     IHTMLEventObj IHTMLEventObj_iface;
251
252     LONG ref;
253
254     HTMLDOMNode *target;
255     const event_info_t *type;
256     nsIDOMEvent *nsevent;
257     BOOL prevent_default;
258     BOOL cancel_bubble;
259 } HTMLEventObj;
260
261 static inline HTMLEventObj *impl_from_IHTMLEventObj(IHTMLEventObj *iface)
262 {
263     return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj_iface);
264 }
265
266 static HRESULT WINAPI HTMLEventObj_QueryInterface(IHTMLEventObj *iface, REFIID riid, void **ppv)
267 {
268     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
269
270     *ppv = NULL;
271
272     if(IsEqualGUID(&IID_IUnknown, riid)) {
273         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
274         *ppv = &This->IHTMLEventObj_iface;
275     }else if(IsEqualGUID(&IID_IHTMLEventObj, riid)) {
276         TRACE("(%p)->(IID_IHTMLEventObj %p)\n", This, ppv);
277         *ppv = &This->IHTMLEventObj_iface;
278     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
279         return *ppv ? S_OK : E_NOINTERFACE;
280     }
281
282     if(*ppv) {
283         IUnknown_AddRef((IUnknown*)*ppv);
284         return S_OK;
285     }
286
287     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
288     return E_NOINTERFACE;
289 }
290
291 static ULONG WINAPI HTMLEventObj_AddRef(IHTMLEventObj *iface)
292 {
293     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
294     LONG ref = InterlockedIncrement(&This->ref);
295
296     TRACE("(%p) ref=%d\n", This, ref);
297
298     return ref;
299 }
300
301 static ULONG WINAPI HTMLEventObj_Release(IHTMLEventObj *iface)
302 {
303     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
304     LONG ref = InterlockedDecrement(&This->ref);
305
306     TRACE("(%p) ref=%d\n", This, ref);
307
308     if(!ref) {
309         if(This->target)
310             IHTMLDOMNode_Release(&This->target->IHTMLDOMNode_iface);
311         if(This->nsevent)
312             nsIDOMEvent_Release(This->nsevent);
313         release_dispex(&This->dispex);
314         heap_free(This);
315     }
316
317     return ref;
318 }
319
320 static HRESULT WINAPI HTMLEventObj_GetTypeInfoCount(IHTMLEventObj *iface, UINT *pctinfo)
321 {
322     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
323     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
324 }
325
326 static HRESULT WINAPI HTMLEventObj_GetTypeInfo(IHTMLEventObj *iface, UINT iTInfo,
327                                               LCID lcid, ITypeInfo **ppTInfo)
328 {
329     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
330     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
331 }
332
333 static HRESULT WINAPI HTMLEventObj_GetIDsOfNames(IHTMLEventObj *iface, REFIID riid,
334                                                 LPOLESTR *rgszNames, UINT cNames,
335                                                 LCID lcid, DISPID *rgDispId)
336 {
337     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
338     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
339             lcid, rgDispId);
340 }
341
342 static HRESULT WINAPI HTMLEventObj_Invoke(IHTMLEventObj *iface, DISPID dispIdMember,
343                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
344                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
345 {
346     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
347     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
348             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
349 }
350
351 static HRESULT WINAPI HTMLEventObj_get_srcElement(IHTMLEventObj *iface, IHTMLElement **p)
352 {
353     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
354
355     TRACE("(%p)->(%p)\n", This, p);
356
357     return IHTMLDOMNode_QueryInterface(&This->target->IHTMLDOMNode_iface, &IID_IHTMLElement,
358             (void**)p);
359 }
360
361 static HRESULT WINAPI HTMLEventObj_get_altKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
362 {
363     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
364     cpp_bool ret = FALSE;
365
366     TRACE("(%p)->(%p)\n", This, p);
367
368     if(This->nsevent) {
369         nsIDOMKeyEvent *key_event;
370         nsresult nsres;
371
372         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
373         if(NS_SUCCEEDED(nsres)) {
374             nsIDOMKeyEvent_GetAltKey(key_event, &ret);
375             nsIDOMKeyEvent_Release(key_event);
376         }else {
377             nsIDOMMouseEvent *mouse_event;
378
379             nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
380             if(NS_SUCCEEDED(nsres)) {
381                 nsIDOMMouseEvent_GetAltKey(mouse_event, &ret);
382                 nsIDOMMouseEvent_Release(mouse_event);
383             }
384         }
385     }
386
387     *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
388     return S_OK;
389 }
390
391 static HRESULT WINAPI HTMLEventObj_get_ctrlKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
392 {
393     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
394     cpp_bool ret = FALSE;
395
396     TRACE("(%p)->(%p)\n", This, p);
397
398     if(This->nsevent) {
399         nsIDOMKeyEvent *key_event;
400         nsresult nsres;
401
402         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
403         if(NS_SUCCEEDED(nsres)) {
404             nsIDOMKeyEvent_GetCtrlKey(key_event, &ret);
405             nsIDOMKeyEvent_Release(key_event);
406         }else {
407             nsIDOMMouseEvent *mouse_event;
408
409             nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
410             if(NS_SUCCEEDED(nsres)) {
411                 nsIDOMMouseEvent_GetCtrlKey(mouse_event, &ret);
412                 nsIDOMMouseEvent_Release(mouse_event);
413             }
414         }
415     }
416
417     *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
418     return S_OK;
419 }
420
421 static HRESULT WINAPI HTMLEventObj_get_shiftKey(IHTMLEventObj *iface, VARIANT_BOOL *p)
422 {
423     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
424     cpp_bool ret = FALSE;
425
426     TRACE("(%p)->(%p)\n", This, p);
427
428     if(This->nsevent) {
429         nsIDOMKeyEvent *key_event;
430         nsresult nsres;
431
432         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
433         if(NS_SUCCEEDED(nsres)) {
434             nsIDOMKeyEvent_GetShiftKey(key_event, &ret);
435             nsIDOMKeyEvent_Release(key_event);
436         }else {
437             nsIDOMMouseEvent *mouse_event;
438
439             nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
440             if(NS_SUCCEEDED(nsres)) {
441                 nsIDOMMouseEvent_GetShiftKey(mouse_event, &ret);
442                 nsIDOMMouseEvent_Release(mouse_event);
443             }
444         }
445     }
446
447     *p = ret ? VARIANT_TRUE : VARIANT_FALSE;
448     return S_OK;
449 }
450
451 static HRESULT WINAPI HTMLEventObj_put_returnValue(IHTMLEventObj *iface, VARIANT v)
452 {
453     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
454
455     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
456
457     if(V_VT(&v) != VT_BOOL) {
458         FIXME("unsupported value %s\n", debugstr_variant(&v));
459         return DISP_E_BADVARTYPE;
460     }
461
462     if(!V_BOOL(&v))
463         This->prevent_default = TRUE;
464     return S_OK;
465 }
466
467 static HRESULT WINAPI HTMLEventObj_get_returnValue(IHTMLEventObj *iface, VARIANT *p)
468 {
469     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
470
471     FIXME("(%p)->(%p)\n", This, p);
472
473     V_VT(p) = VT_EMPTY;
474     return S_OK;
475 }
476
477 static HRESULT WINAPI HTMLEventObj_put_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL v)
478 {
479     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
480
481     TRACE("(%p)->(%x)\n", This, v);
482
483     This->cancel_bubble = !!v;
484     return S_OK;
485 }
486
487 static HRESULT WINAPI HTMLEventObj_get_cancelBubble(IHTMLEventObj *iface, VARIANT_BOOL *p)
488 {
489     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
490
491     TRACE("(%p)->(%p)\n", This, p);
492
493     *p = This->cancel_bubble ? VARIANT_TRUE : VARIANT_FALSE;
494     return S_OK;
495 }
496
497 static HRESULT WINAPI HTMLEventObj_get_fromElement(IHTMLEventObj *iface, IHTMLElement **p)
498 {
499     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
500
501     FIXME("(%p)->(%p)\n", This, p);
502
503     *p = NULL;
504     return S_OK;
505 }
506
507 static HRESULT WINAPI HTMLEventObj_get_toElement(IHTMLEventObj *iface, IHTMLElement **p)
508 {
509     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
510
511     FIXME("(%p)->(%p)\n", This, p);
512
513     *p = NULL;
514     return S_OK;
515 }
516
517 static HRESULT WINAPI HTMLEventObj_put_keyCode(IHTMLEventObj *iface, LONG v)
518 {
519     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
520     FIXME("(%p)->(%d)\n", This, v);
521     return E_NOTIMPL;
522 }
523
524 static HRESULT WINAPI HTMLEventObj_get_keyCode(IHTMLEventObj *iface, LONG *p)
525 {
526     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
527     PRUint32 key_code = 0;
528
529     TRACE("(%p)->(%p)\n", This, p);
530
531     if(This->nsevent) {
532         nsIDOMKeyEvent *key_event;
533         nsresult nsres;
534
535         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMKeyEvent, (void**)&key_event);
536         if(NS_SUCCEEDED(nsres)) {
537             nsIDOMKeyEvent_GetKeyCode(key_event, &key_code);
538             nsIDOMKeyEvent_Release(key_event);
539         }
540     }
541
542     *p = key_code;
543     return S_OK;
544 }
545
546 static HRESULT WINAPI HTMLEventObj_get_button(IHTMLEventObj *iface, LONG *p)
547 {
548     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
549     PRUint16 button = 0;
550
551     TRACE("(%p)->(%p)\n", This, p);
552
553     if(This->nsevent) {
554         nsIDOMMouseEvent *mouse_event;
555         nsresult nsres;
556
557         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
558         if(NS_SUCCEEDED(nsres)) {
559             nsIDOMMouseEvent_GetButton(mouse_event, &button);
560             nsIDOMMouseEvent_Release(mouse_event);
561         }
562     }
563
564     *p = button;
565     return S_OK;
566 }
567
568 static HRESULT WINAPI HTMLEventObj_get_type(IHTMLEventObj *iface, BSTR *p)
569 {
570     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
571
572     TRACE("(%p)->(%p)\n", This, p);
573
574     *p = SysAllocString(This->type->name);
575     return *p ? S_OK : E_OUTOFMEMORY;
576 }
577
578 static HRESULT WINAPI HTMLEventObj_get_qualifier(IHTMLEventObj *iface, BSTR *p)
579 {
580     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
581
582     FIXME("(%p)->(%p)\n", This, p);
583
584     *p = NULL;
585     return S_OK;
586 }
587
588 static HRESULT WINAPI HTMLEventObj_get_reason(IHTMLEventObj *iface, LONG *p)
589 {
590     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
591
592     FIXME("(%p)->(%p)\n", This, p);
593
594     *p = 0;
595     return S_OK;
596 }
597
598 static HRESULT WINAPI HTMLEventObj_get_x(IHTMLEventObj *iface, LONG *p)
599 {
600     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
601
602     FIXME("(%p)->(%p)\n", This, p);
603
604     *p = -1;
605     return S_OK;
606 }
607
608 static HRESULT WINAPI HTMLEventObj_get_y(IHTMLEventObj *iface, LONG *p)
609 {
610     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
611
612     FIXME("(%p)->(%p)\n", This, p);
613
614     *p = -1;
615     return S_OK;
616 }
617
618 static HRESULT WINAPI HTMLEventObj_get_clientX(IHTMLEventObj *iface, LONG *p)
619 {
620     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
621     PRInt32 x = 0;
622
623     TRACE("(%p)->(%p)\n", This, p);
624
625     if(This->nsevent) {
626         nsIDOMMouseEvent *mouse_event;
627         nsresult nsres;
628
629         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
630         if(NS_SUCCEEDED(nsres)) {
631             nsIDOMMouseEvent_GetClientX(mouse_event, &x);
632             nsIDOMMouseEvent_Release(mouse_event);
633         }
634     }
635
636     *p = x;
637     return S_OK;
638 }
639
640 static HRESULT WINAPI HTMLEventObj_get_clientY(IHTMLEventObj *iface, LONG *p)
641 {
642     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
643     PRInt32 y = 0;
644
645     TRACE("(%p)->(%p)\n", This, p);
646
647     if(This->nsevent) {
648         nsIDOMMouseEvent *mouse_event;
649         nsresult nsres;
650
651         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
652         if(NS_SUCCEEDED(nsres)) {
653             nsIDOMMouseEvent_GetClientY(mouse_event, &y);
654             nsIDOMMouseEvent_Release(mouse_event);
655         }
656     }
657
658     *p = y;
659     return S_OK;
660 }
661
662 static HRESULT WINAPI HTMLEventObj_get_offsetX(IHTMLEventObj *iface, LONG *p)
663 {
664     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
665
666     FIXME("(%p)->(%p)\n", This, p);
667
668     *p = 0;
669     return S_OK;
670 }
671
672 static HRESULT WINAPI HTMLEventObj_get_offsetY(IHTMLEventObj *iface, LONG *p)
673 {
674     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
675
676     FIXME("(%p)->(%p)\n", This, p);
677
678     *p = 0;
679     return S_OK;
680 }
681
682 static HRESULT WINAPI HTMLEventObj_get_screenX(IHTMLEventObj *iface, LONG *p)
683 {
684     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
685     PRInt32 x = 0;
686
687     TRACE("(%p)->(%p)\n", This, p);
688
689     if(This->nsevent) {
690         nsIDOMMouseEvent *mouse_event;
691         nsresult nsres;
692
693         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
694         if(NS_SUCCEEDED(nsres)) {
695             nsIDOMMouseEvent_GetScreenX(mouse_event, &x);
696             nsIDOMMouseEvent_Release(mouse_event);
697         }
698     }
699
700     *p = x;
701     return S_OK;
702 }
703
704 static HRESULT WINAPI HTMLEventObj_get_screenY(IHTMLEventObj *iface, LONG *p)
705 {
706     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
707     PRInt32 y = 0;
708
709     TRACE("(%p)->(%p)\n", This, p);
710
711     if(This->nsevent) {
712         nsIDOMMouseEvent *mouse_event;
713         nsresult nsres;
714
715         nsres = nsIDOMEvent_QueryInterface(This->nsevent, &IID_nsIDOMMouseEvent, (void**)&mouse_event);
716         if(NS_SUCCEEDED(nsres)) {
717             nsIDOMMouseEvent_GetScreenY(mouse_event, &y);
718             nsIDOMMouseEvent_Release(mouse_event);
719         }
720     }
721
722     *p = y;
723     return S_OK;
724 }
725
726 static HRESULT WINAPI HTMLEventObj_get_srcFilter(IHTMLEventObj *iface, IDispatch **p)
727 {
728     HTMLEventObj *This = impl_from_IHTMLEventObj(iface);
729
730     FIXME("(%p)->(%p)\n", This, p);
731
732     *p = NULL;
733     return S_OK;
734 }
735
736 static const IHTMLEventObjVtbl HTMLEventObjVtbl = {
737     HTMLEventObj_QueryInterface,
738     HTMLEventObj_AddRef,
739     HTMLEventObj_Release,
740     HTMLEventObj_GetTypeInfoCount,
741     HTMLEventObj_GetTypeInfo,
742     HTMLEventObj_GetIDsOfNames,
743     HTMLEventObj_Invoke,
744     HTMLEventObj_get_srcElement,
745     HTMLEventObj_get_altKey,
746     HTMLEventObj_get_ctrlKey,
747     HTMLEventObj_get_shiftKey,
748     HTMLEventObj_put_returnValue,
749     HTMLEventObj_get_returnValue,
750     HTMLEventObj_put_cancelBubble,
751     HTMLEventObj_get_cancelBubble,
752     HTMLEventObj_get_fromElement,
753     HTMLEventObj_get_toElement,
754     HTMLEventObj_put_keyCode,
755     HTMLEventObj_get_keyCode,
756     HTMLEventObj_get_button,
757     HTMLEventObj_get_type,
758     HTMLEventObj_get_qualifier,
759     HTMLEventObj_get_reason,
760     HTMLEventObj_get_x,
761     HTMLEventObj_get_y,
762     HTMLEventObj_get_clientX,
763     HTMLEventObj_get_clientY,
764     HTMLEventObj_get_offsetX,
765     HTMLEventObj_get_offsetY,
766     HTMLEventObj_get_screenX,
767     HTMLEventObj_get_screenY,
768     HTMLEventObj_get_srcFilter
769 };
770
771 static const tid_t HTMLEventObj_iface_tids[] = {
772     IHTMLEventObj_tid,
773     0
774 };
775
776 static dispex_static_data_t HTMLEventObj_dispex = {
777     NULL,
778     DispCEventObj_tid,
779     NULL,
780     HTMLEventObj_iface_tids
781 };
782
783 static HTMLEventObj *create_event(HTMLDOMNode *target, eventid_t eid, nsIDOMEvent *nsevent)
784 {
785     HTMLEventObj *ret;
786
787     ret = heap_alloc_zero(sizeof(*ret));
788     if(!ret)
789         return NULL;
790
791     ret->IHTMLEventObj_iface.lpVtbl = &HTMLEventObjVtbl;
792     ret->ref = 1;
793     ret->type = event_info+eid;
794
795     ret->nsevent = nsevent;
796     if(nsevent) {
797         nsIDOMEvent_AddRef(nsevent);
798     }else if(event_types[event_info[eid].type]) {
799         nsAString type_str;
800         nsresult nsres;
801
802         nsAString_InitDepend(&type_str, event_types[event_info[eid].type]);
803         nsres = nsIDOMHTMLDocument_CreateEvent(target->doc->nsdoc, &type_str, &ret->nsevent);
804         nsAString_Finish(&type_str);
805         if(NS_FAILED(nsres)) {
806             ERR("Could not create event: %08x\n", nsres);
807             IHTMLEventObj_Release(&ret->IHTMLEventObj_iface);
808             return NULL;
809         }
810     }
811
812     ret->target = target;
813     IHTMLDOMNode_AddRef(&target->IHTMLDOMNode_iface);
814
815     init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLEventObj_iface, &HTMLEventObj_dispex);
816
817     return ret;
818 }
819
820 static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv)
821 {
822     IDispatchEx *dispex;
823     EXCEPINFO ei;
824     HRESULT hres;
825
826     memset(&ei, 0, sizeof(ei));
827
828     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
829     if(SUCCEEDED(hres)) {
830         hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, dp, retv, &ei, NULL);
831         IDispatchEx_Release(dispex);
832     }else {
833         TRACE("Could not get IDispatchEx interface: %08x\n", hres);
834         hres = IDispatch_Invoke(disp, 0, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD,
835                 dp, retv, &ei, NULL);
836     }
837
838     return hres;
839 }
840
841 static HRESULT call_cp_func(IDispatch *disp, DISPID dispid, VARIANT *retv)
842 {
843     DISPPARAMS dp = {NULL,NULL,0,0};
844     ULONG argerr;
845     EXCEPINFO ei;
846
847     memset(&ei, 0, sizeof(ei));
848     return IDispatch_Invoke(disp, dispid, &IID_NULL, 0, DISPATCH_METHOD, &dp, retv, &ei, &argerr);
849 }
850
851 static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid)
852 {
853     int min, max, i;
854     HRESULT hres;
855
856     if(!data)
857         return FALSE;
858
859     if(!data->ids) {
860         hres = get_dispids(data->tid, &data->id_cnt, &data->ids);
861         if(FAILED(hres))
862             return FALSE;
863     }
864
865     min = 0;
866     max = data->id_cnt-1;
867     while(min <= max) {
868         i = (min+max)/2;
869         if(data->ids[i] == dispid)
870             return TRUE;
871
872         if(data->ids[i] < dispid)
873             min = i+1;
874         else
875             max = i-1;
876     }
877
878     return FALSE;
879 }
880
881 static void call_event_handlers(HTMLDocumentNode *doc, HTMLEventObj *event_obj, event_target_t *event_target,
882         ConnectionPointContainer *cp_container, eventid_t eid, IDispatch *this_obj)
883 {
884     const BOOL cancelable = event_info[eid].flags & EVENT_CANCELABLE;
885     handler_vector_t *handler_vector = NULL;
886     VARIANT v;
887     int i;
888     HRESULT hres;
889
890     if(event_target)
891         handler_vector = event_target->event_table[eid];
892
893     if(handler_vector && handler_vector->handler_prop) {
894         DISPID named_arg = DISPID_THIS;
895         VARIANTARG arg;
896         DISPPARAMS dp = {&arg, &named_arg, 1, 1};
897
898         V_VT(&arg) = VT_DISPATCH;
899         V_DISPATCH(&arg) = this_obj;
900         V_VT(&v) = VT_EMPTY;
901
902         TRACE("%s >>>\n", debugstr_w(event_info[eid].name));
903         hres = call_disp_func(handler_vector->handler_prop, &dp, &v);
904         if(hres == S_OK) {
905             TRACE("%s <<< %s\n", debugstr_w(event_info[eid].name), debugstr_variant(&v));
906
907             if(cancelable) {
908                 if(V_VT(&v) == VT_BOOL) {
909                     if(!V_BOOL(&v))
910                         event_obj->prevent_default = TRUE;
911                 }else if(V_VT(&v) != VT_EMPTY) {
912                     FIXME("unhandled result %s\n", debugstr_variant(&v));
913                 }
914             }
915             VariantClear(&v);
916         }else {
917             WARN("%s <<< %08x\n", debugstr_w(event_info[eid].name), hres);
918         }
919     }
920
921     if(handler_vector && handler_vector->handler_cnt) {
922         VARIANTARG arg;
923         DISPPARAMS dp = {&arg, NULL, 1, 0};
924
925         V_VT(&arg) = VT_DISPATCH;
926         V_DISPATCH(&arg) = (IDispatch*)event_obj;
927
928         i = handler_vector->handler_cnt;
929         while(i--) {
930             if(handler_vector->handlers[i]) {
931                 V_VT(&v) = VT_EMPTY;
932
933                 TRACE("%s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
934                 hres = call_disp_func(handler_vector->handlers[i], &dp, &v);
935                 if(hres == S_OK) {
936                     TRACE("%s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
937
938                     if(cancelable) {
939                         if(V_VT(&v) == VT_BOOL) {
940                             if(!V_BOOL(&v))
941                                 event_obj->prevent_default = TRUE;
942                         }else if(V_VT(&v) != VT_EMPTY) {
943                             FIXME("unhandled result %s\n", debugstr_variant(&v));
944                         }
945                     }
946                     VariantClear(&v);
947                 }else {
948                     WARN("%s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
949                 }
950             }
951         }
952     }
953
954     if(cp_container) {
955         ConnectionPoint *cp;
956
957         if(cp_container->forward_container)
958             cp_container = cp_container->forward_container;
959
960         for(cp = cp_container->cp_list; cp; cp = cp->next) {
961             if(cp->sinks_size && is_cp_event(cp->data, event_info[eid].dispid)) {
962                 for(i=0; i < cp->sinks_size; i++) {
963                     if(!cp->sinks[i].disp)
964                         continue;
965
966                     V_VT(&v) = VT_EMPTY;
967
968                     TRACE("cp %s [%d] >>>\n", debugstr_w(event_info[eid].name), i);
969                     hres = call_cp_func(cp->sinks[i].disp, event_info[eid].dispid, &v);
970                     if(hres == S_OK) {
971                         TRACE("cp %s [%d] <<<\n", debugstr_w(event_info[eid].name), i);
972
973                         if(cancelable) {
974                             if(V_VT(&v) == VT_BOOL) {
975                                 if(!V_BOOL(&v))
976                                     event_obj->prevent_default = TRUE;
977                             }else if(V_VT(&v) != VT_EMPTY) {
978                                 FIXME("unhandled result %s\n", debugstr_variant(&v));
979                             }
980                         }
981                         VariantClear(&v);
982                     }else {
983                         WARN("cp %s [%d] <<< %08x\n", debugstr_w(event_info[eid].name), i, hres);
984                     }
985                 }
986             }
987         }
988     }
989 }
990
991 void fire_event(HTMLDocumentNode *doc, eventid_t eid, BOOL set_event, nsIDOMNode *target, nsIDOMEvent *nsevent)
992 {
993     HTMLEventObj *event_obj = NULL;
994     IHTMLEventObj *prev_event;
995     nsIDOMNode *parent, *nsnode;
996     BOOL prevent_default = FALSE;
997     HTMLInnerWindow *window;
998     HTMLDOMNode *node;
999     PRUint16 node_type;
1000     nsresult nsres;
1001     HRESULT hres;
1002
1003     TRACE("(%p) %s\n", doc, debugstr_w(event_info[eid].name));
1004
1005     window = doc->window;
1006     prev_event = window->event;
1007     if(set_event) {
1008         hres = get_node(doc, target, TRUE, &node);
1009         if(FAILED(hres))
1010             return;
1011
1012         event_obj = create_event(node, eid, nsevent);
1013         node_release(node);
1014         window->event = &event_obj->IHTMLEventObj_iface;
1015     }else {
1016         window->event = NULL;
1017     }
1018
1019     nsIDOMNode_GetNodeType(target, &node_type);
1020     nsnode = target;
1021     nsIDOMNode_AddRef(nsnode);
1022
1023     switch(node_type) {
1024     case ELEMENT_NODE:
1025         do {
1026             hres = get_node(doc, nsnode, FALSE, &node);
1027             if(SUCCEEDED(hres) && node) {
1028                 call_event_handlers(doc, event_obj, *get_node_event_target(node),
1029                         node->cp_container, eid, (IDispatch*)&node->IHTMLDOMNode_iface);
1030                 node_release(node);
1031             }
1032
1033             if(!(event_info[eid].flags & EVENT_BUBBLE) || (event_obj && event_obj->cancel_bubble))
1034                 break;
1035
1036             nsIDOMNode_GetParentNode(nsnode, &parent);
1037             nsIDOMNode_Release(nsnode);
1038             nsnode = parent;
1039             if(!nsnode)
1040                 break;
1041
1042             nsIDOMNode_GetNodeType(nsnode, &node_type);
1043         }while(node_type == ELEMENT_NODE);
1044
1045         if(!(event_info[eid].flags & EVENT_BUBBLE) || (event_obj && event_obj->cancel_bubble))
1046             break;
1047
1048     case DOCUMENT_NODE:
1049         if(event_info[eid].flags & EVENT_FORWARDBODY) {
1050             nsIDOMHTMLElement *nsbody;
1051             nsresult nsres;
1052
1053             nsres = nsIDOMHTMLDocument_GetBody(doc->nsdoc, &nsbody);
1054             if(NS_SUCCEEDED(nsres) && nsbody) {
1055                 hres = get_node(doc, (nsIDOMNode*)nsbody, FALSE, &node);
1056                 if(SUCCEEDED(hres) && node) {
1057                     call_event_handlers(doc, event_obj, *get_node_event_target(node),
1058                             node->cp_container, eid, (IDispatch*)&node->IHTMLDOMNode_iface);
1059                     node_release(node);
1060                 }
1061                 nsIDOMHTMLElement_Release(nsbody);
1062             }else {
1063                 ERR("Could not get body: %08x\n", nsres);
1064             }
1065         }
1066
1067         call_event_handlers(doc, event_obj, doc->node.event_target, &doc->basedoc.cp_container, eid,
1068                 (IDispatch*)&doc->basedoc.IHTMLDocument2_iface);
1069         break;
1070
1071     default:
1072         FIXME("unimplemented node type %d\n", node_type);
1073     }
1074
1075     if(nsnode)
1076         nsIDOMNode_Release(nsnode);
1077
1078     if(event_obj && event_obj->prevent_default)
1079         prevent_default = TRUE;
1080     window->event = prev_event;
1081     if(event_obj)
1082         IHTMLEventObj_Release(&event_obj->IHTMLEventObj_iface);
1083
1084     if(!prevent_default && (event_info[eid].flags & EVENT_HASDEFAULTHANDLERS)) {
1085         nsIDOMNode_AddRef(target);
1086         nsnode = target;
1087
1088         do {
1089             hres = get_node(doc, nsnode, TRUE, &node);
1090             if(FAILED(hres))
1091                 break;
1092
1093             if(node) {
1094                 if(node->vtbl->handle_event)
1095                     hres = node->vtbl->handle_event(node, eid, nsevent, &prevent_default);
1096                 node_release(node);
1097                 if(FAILED(hres) || prevent_default || (event_obj && event_obj->cancel_bubble))
1098                     break;
1099             }
1100
1101             nsres = nsIDOMNode_GetParentNode(nsnode, &parent);
1102             if(NS_FAILED(nsres))
1103                 break;
1104
1105             nsIDOMNode_Release(nsnode);
1106             nsnode = parent;
1107         } while(nsnode);
1108
1109         if(nsnode)
1110             nsIDOMNode_Release(nsnode);
1111     }
1112
1113     if(prevent_default && nsevent) {
1114         TRACE("calling PreventDefault\n");
1115         nsIDOMEvent_PreventDefault(nsevent);
1116     }
1117 }
1118
1119 HRESULT dispatch_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_obj, VARIANT_BOOL *cancelled)
1120 {
1121     eventid_t eid;
1122
1123     eid = attr_to_eid(event_name);
1124     if(eid == EVENTID_LAST) {
1125         WARN("unknown event %s\n", debugstr_w(event_name));
1126         return E_INVALIDARG;
1127     }
1128
1129     if(event_obj && V_VT(event_obj) != VT_EMPTY && V_VT(event_obj) != VT_ERROR)
1130         FIXME("event_obj not implemented\n");
1131
1132     if(!(event_info[eid].flags & EVENT_DEFAULTLISTENER)) {
1133         FIXME("not EVENT_DEFAULTEVENTHANDLER\n");
1134         return E_NOTIMPL;
1135     }
1136
1137     fire_event(node->doc, eid, TRUE, node->nsnode, NULL);
1138
1139     *cancelled = VARIANT_TRUE; /* FIXME */
1140     return S_OK;
1141 }
1142
1143 HRESULT call_fire_event(HTMLDOMNode *node, eventid_t eid)
1144 {
1145     HRESULT hres;
1146
1147     if(node->vtbl->fire_event) {
1148         BOOL handled = FALSE;
1149
1150         hres = node->vtbl->fire_event(node, eid, &handled);
1151         if(handled)
1152             return hres;
1153     }
1154
1155     fire_event(node->doc, eid, TRUE, node->nsnode, NULL);
1156     return S_OK;
1157 }
1158
1159 static inline event_target_t *get_event_target(event_target_t **event_target_ptr)
1160 {
1161     if(!*event_target_ptr)
1162         *event_target_ptr = heap_alloc_zero(sizeof(event_target_t));
1163     return *event_target_ptr;
1164 }
1165
1166 static BOOL alloc_handler_vector(event_target_t *event_target, eventid_t eid, int cnt)
1167 {
1168     handler_vector_t *new_vector, *handler_vector = event_target->event_table[eid];
1169
1170     if(handler_vector) {
1171         if(cnt <= handler_vector->handler_cnt)
1172             return TRUE;
1173
1174         new_vector = heap_realloc_zero(handler_vector, sizeof(handler_vector_t) + sizeof(IDispatch*)*cnt);
1175     }else {
1176         new_vector = heap_alloc_zero(sizeof(handler_vector_t) + sizeof(IDispatch*)*cnt);
1177     }
1178
1179     if(!new_vector)
1180         return FALSE;
1181
1182     new_vector->handler_cnt = cnt;
1183     event_target->event_table[eid] = new_vector;
1184     return TRUE;
1185 }
1186
1187 static HRESULT ensure_nsevent_handler(HTMLDocumentNode *doc, event_target_t *event_target, nsIDOMNode *nsnode, eventid_t eid)
1188 {
1189     if(!doc->nsdoc)
1190         return S_OK;
1191
1192     if(event_info[eid].flags & EVENT_NODEHANDLER) {
1193         DWORD mask;
1194
1195         mask = get_node_handler_mask(eid);
1196         if(event_target->node_handlers_mask & mask)
1197             return S_OK;
1198
1199         add_nsevent_listener(doc, nsnode, event_info[eid].name);
1200         event_target->node_handlers_mask |= mask;
1201         return S_OK;
1202     }
1203
1204     if(!(event_info[eid].flags & EVENT_DEFAULTLISTENER))
1205         return S_OK;
1206
1207     if(!doc->event_vector[eid]) {
1208         doc->event_vector[eid] = TRUE;
1209         add_nsevent_listener(doc, NULL, event_info[eid].name);
1210     }
1211
1212     return S_OK;
1213 }
1214
1215 void detach_events(HTMLDocumentNode *doc)
1216 {
1217     if(doc->event_vector) {
1218         int i;
1219
1220         for(i=0; i < EVENTID_LAST; i++) {
1221             if(doc->event_vector[i])
1222                 detach_nsevent(doc, event_info[i].name);
1223         }
1224     }
1225
1226     release_nsevents(doc);
1227 }
1228
1229
1230 static HRESULT remove_event_handler(event_target_t **event_target, eventid_t eid)
1231 {
1232     if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) {
1233         IDispatch_Release((*event_target)->event_table[eid]->handler_prop);
1234         (*event_target)->event_table[eid]->handler_prop = NULL;
1235     }
1236
1237     return S_OK;
1238 }
1239
1240 static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, nsIDOMNode *nsnode, HTMLDocumentNode *doc,
1241         eventid_t eid, IDispatch *disp)
1242 {
1243     event_target_t *event_target;
1244
1245     if(!disp)
1246         return remove_event_handler(event_target_ptr, eid);
1247
1248     event_target = get_event_target(event_target_ptr);
1249     if(!event_target)
1250         return E_OUTOFMEMORY;
1251
1252     if(!alloc_handler_vector(event_target, eid, 0))
1253         return E_OUTOFMEMORY;
1254
1255     if(event_target->event_table[eid]->handler_prop)
1256         IDispatch_Release(event_target->event_table[eid]->handler_prop);
1257
1258     event_target->event_table[eid]->handler_prop = disp;
1259     IDispatch_AddRef(disp);
1260
1261     return ensure_nsevent_handler(doc, event_target, nsnode, eid);
1262 }
1263
1264 HRESULT set_event_handler(event_target_t **event_target, nsIDOMNode *nsnode, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var)
1265 {
1266     switch(V_VT(var)) {
1267     case VT_NULL:
1268         return remove_event_handler(event_target, eid);
1269
1270     case VT_DISPATCH:
1271         return set_event_handler_disp(event_target, nsnode, doc, eid, V_DISPATCH(var));
1272
1273     default:
1274         FIXME("not handler %s\n", debugstr_variant(var));
1275         /* fall through */
1276     case VT_EMPTY:
1277         return E_NOTIMPL;
1278     }
1279
1280     return S_OK;
1281 }
1282
1283 HRESULT get_event_handler(event_target_t **event_target, eventid_t eid, VARIANT *var)
1284 {
1285     if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) {
1286         V_VT(var) = VT_DISPATCH;
1287         V_DISPATCH(var) = (*event_target)->event_table[eid]->handler_prop;
1288         IDispatch_AddRef(V_DISPATCH(var));
1289     }else {
1290         V_VT(var) = VT_NULL;
1291     }
1292
1293     return S_OK;
1294 }
1295
1296 HRESULT attach_event(event_target_t **event_target_ptr, nsIDOMNode *nsnode, HTMLDocument *doc, BSTR name,
1297         IDispatch *disp, VARIANT_BOOL *res)
1298 {
1299     event_target_t *event_target;
1300     eventid_t eid;
1301     DWORD i = 0;
1302
1303     eid = attr_to_eid(name);
1304     if(eid == EVENTID_LAST) {
1305         WARN("Unknown event\n");
1306         *res = VARIANT_TRUE;
1307         return S_OK;
1308     }
1309
1310     event_target = get_event_target(event_target_ptr);
1311     if(!event_target)
1312         return E_OUTOFMEMORY;
1313
1314     if(event_target->event_table[eid]) {
1315         while(i < event_target->event_table[eid]->handler_cnt && event_target->event_table[eid]->handlers[i])
1316             i++;
1317         if(i == event_target->event_table[eid]->handler_cnt && !alloc_handler_vector(event_target, eid, i+1))
1318             return E_OUTOFMEMORY;
1319     }else if(!alloc_handler_vector(event_target, eid, i+1)) {
1320         return E_OUTOFMEMORY;
1321     }
1322
1323     IDispatch_AddRef(disp);
1324     event_target->event_table[eid]->handlers[i] = disp;
1325
1326     *res = VARIANT_TRUE;
1327     return ensure_nsevent_handler(doc->doc_node, event_target, nsnode, eid);
1328 }
1329
1330 HRESULT detach_event(event_target_t *event_target, HTMLDocument *doc, BSTR name, IDispatch *disp)
1331 {
1332     eventid_t eid;
1333     DWORD i = 0;
1334
1335     if(!event_target)
1336         return S_OK;
1337
1338     eid = attr_to_eid(name);
1339     if(eid == EVENTID_LAST) {
1340         WARN("Unknown event\n");
1341         return S_OK;
1342     }
1343
1344     if(!event_target->event_table[eid])
1345         return S_OK;
1346
1347     while(i < event_target->event_table[eid]->handler_cnt) {
1348         if(event_target->event_table[eid]->handlers[i] == disp) {
1349             IDispatch_Release(event_target->event_table[eid]->handlers[i]);
1350             event_target->event_table[eid]->handlers[i] = NULL;
1351         }
1352         i++;
1353     }
1354
1355     return S_OK;
1356 }
1357
1358 void update_cp_events(HTMLInnerWindow *window, event_target_t **event_target_ptr, cp_static_data_t *cp, nsIDOMNode *nsnode)
1359 {
1360     event_target_t *event_target;
1361     int i;
1362
1363     event_target = get_event_target(event_target_ptr);
1364     if(!event_target)
1365         return; /* FIXME */
1366
1367     for(i=0; i < EVENTID_LAST; i++) {
1368         if((event_info[i].flags & EVENT_DEFAULTLISTENER) && is_cp_event(cp, event_info[i].dispid))
1369             ensure_nsevent_handler(window->doc, event_target, nsnode, i);
1370     }
1371 }
1372
1373 void check_event_attr(HTMLDocumentNode *doc, nsIDOMElement *nselem)
1374 {
1375     const PRUnichar *attr_value;
1376     nsAString attr_name_str, attr_value_str;
1377     IDispatch *disp;
1378     HTMLDOMNode *node;
1379     int i;
1380     nsresult nsres;
1381     HRESULT hres;
1382
1383     nsAString_Init(&attr_value_str, NULL);
1384     nsAString_Init(&attr_name_str, NULL);
1385
1386     for(i=0; i < EVENTID_LAST; i++) {
1387         nsAString_SetData(&attr_name_str, event_info[i].attr_name);
1388         nsres = nsIDOMElement_GetAttribute(nselem, &attr_name_str, &attr_value_str);
1389         if(NS_SUCCEEDED(nsres)) {
1390             nsAString_GetData(&attr_value_str, &attr_value);
1391             if(!*attr_value)
1392                 continue;
1393
1394             TRACE("%p.%s = %s\n", nselem, debugstr_w(event_info[i].attr_name), debugstr_w(attr_value));
1395
1396             disp = script_parse_event(doc->window, attr_value);
1397             if(disp) {
1398                 hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node);
1399                 if(SUCCEEDED(hres)) {
1400                     set_event_handler_disp(get_node_event_target(node), node->nsnode, node->doc, i, disp);
1401                     node_release(node);
1402                 }
1403                 IDispatch_Release(disp);
1404             }
1405         }
1406     }
1407
1408     nsAString_Finish(&attr_value_str);
1409     nsAString_Finish(&attr_name_str);
1410 }
1411
1412 HRESULT doc_init_events(HTMLDocumentNode *doc)
1413 {
1414     unsigned i;
1415     HRESULT hres;
1416
1417     doc->event_vector = heap_alloc_zero(EVENTID_LAST*sizeof(BOOL));
1418     if(!doc->event_vector)
1419         return E_OUTOFMEMORY;
1420
1421     init_nsevents(doc);
1422
1423     for(i=0; i < EVENTID_LAST; i++) {
1424         if(event_info[i].flags & EVENT_HASDEFAULTHANDLERS) {
1425             hres = ensure_nsevent_handler(doc, NULL, NULL, i);
1426             if(FAILED(hres))
1427                 return hres;
1428         }
1429     }
1430
1431     return S_OK;
1432 }
1433
1434 void release_event_target(event_target_t *event_target)
1435 {
1436     int i, j;
1437
1438     for(i=0; i < EVENTID_LAST; i++) {
1439         if(event_target->event_table[i]) {
1440             if(event_target->event_table[i]->handler_prop)
1441                 IDispatch_Release(event_target->event_table[i]->handler_prop);
1442             for(j=0; j < event_target->event_table[i]->handler_cnt; j++)
1443                 if(event_target->event_table[i]->handlers[j])
1444                     IDispatch_Release(event_target->event_table[i]->handlers[j]);
1445         }
1446     }
1447
1448     heap_free(event_target);
1449 }