shell32: Constify some variables.
[wine] / dlls / mshtml / nsembed.c
1 /*
2  * Copyright 2005-2007 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 "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "ole2.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "mshtml_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1"
39 #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1"
40 #define NS_PROFILE_CONTRACTID "@mozilla.org/profile/manager;1"
41 #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1"
42 #define NS_STRINGSTREAM_CONTRACTID "@mozilla.org/io/string-input-stream;1"
43 #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1"
44 #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html"
45 #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1"
46 #define NS_ARRAY_CONTRACTID "@mozilla.org/array;1"
47 #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1"
48
49 #define APPSTARTUP_TOPIC "app-startup"
50
51 #define PR_UINT32_MAX 0xffffffff
52
53 struct nsCStringContainer {
54     void *v;
55     void *d1;
56     PRUint32 d2;
57     void *d3;
58 };
59
60 static nsresult (*NS_InitXPCOM2)(nsIServiceManager**,void*,void*);
61 static nsresult (*NS_ShutdownXPCOM)(nsIServiceManager*);
62 static nsresult (*NS_GetComponentRegistrar)(nsIComponentRegistrar**);
63 static nsresult (*NS_StringContainerInit)(nsStringContainer*);
64 static nsresult (*NS_CStringContainerInit)(nsCStringContainer*);
65 static nsresult (*NS_StringContainerFinish)(nsStringContainer*);
66 static nsresult (*NS_CStringContainerFinish)(nsCStringContainer*);
67 static nsresult (*NS_StringSetData)(nsAString*,const PRUnichar*,PRUint32);
68 static nsresult (*NS_CStringSetData)(nsACString*,const char*,PRUint32);
69 static nsresult (*NS_NewLocalFile)(const nsAString*,PRBool,nsIFile**);
70 static PRUint32 (*NS_StringGetData)(const nsAString*,const PRUnichar **,PRBool*);
71 static PRUint32 (*NS_CStringGetData)(const nsACString*,const char**,PRBool*);
72
73 static HINSTANCE hXPCOM = NULL;
74
75 static nsIServiceManager *pServMgr = NULL;
76 static nsIComponentManager *pCompMgr = NULL;
77 static nsIMemory *nsmem = NULL;
78
79 static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0};
80
81 static ATOM nscontainer_class;
82
83 static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
84 {
85     NSContainer *This;
86     nsresult nsres;
87
88     static const WCHAR wszTHIS[] = {'T','H','I','S',0};
89
90     if(msg == WM_CREATE) {
91         This = *(NSContainer**)lParam;
92         SetPropW(hwnd, wszTHIS, This);
93     }else {
94         This = (NSContainer*)GetPropW(hwnd, wszTHIS);
95     }
96
97     switch(msg) {
98         case WM_SIZE:
99             TRACE("(%p)->(WM_SIZE)\n", This);
100
101             nsres = nsIBaseWindow_SetSize(This->window,
102                     LOWORD(lParam), HIWORD(lParam), TRUE);
103             if(NS_FAILED(nsres))
104                 WARN("SetSize failed: %08x\n", nsres);
105     }
106
107     return DefWindowProcW(hwnd, msg, wParam, lParam);
108 }
109
110
111 static void register_nscontainer_class(void)
112 {
113     static WNDCLASSEXW wndclass = {
114         sizeof(WNDCLASSEXW),
115         CS_DBLCLKS,
116         nsembed_proc,
117         0, 0, NULL, NULL, NULL, NULL, NULL,
118         wszNsContainer,
119         NULL,
120     };
121     wndclass.hInstance = hInst;
122     nscontainer_class = RegisterClassExW(&wndclass);
123 }
124
125 static BOOL load_xpcom(const PRUnichar *gre_path)
126 {
127     WCHAR path_env[MAX_PATH];
128     int len;
129
130     static const WCHAR wszPATH[] = {'P','A','T','H',0};
131     static const WCHAR strXPCOM[] = {'x','p','c','o','m','.','d','l','l',0};
132
133     TRACE("(%s)\n", debugstr_w(gre_path));
134
135     /* We have to modify PATH as XPCOM loads other DLLs from this directory. */
136     GetEnvironmentVariableW(wszPATH, path_env, sizeof(path_env)/sizeof(WCHAR));
137     len = strlenW(path_env);
138     path_env[len++] = ';';
139     strcpyW(path_env+len, gre_path);
140     SetEnvironmentVariableW(wszPATH, path_env);
141
142     hXPCOM = LoadLibraryW(strXPCOM);
143     if(!hXPCOM) {
144         WARN("Could not load XPCOM: %d\n", GetLastError());
145         return FALSE;
146     }
147
148 #define NS_DLSYM(func) \
149     func = (typeof(func))GetProcAddress(hXPCOM, #func); \
150     if(!func) \
151         ERR("Could not GetProcAddress(" #func ") failed\n")
152
153     NS_DLSYM(NS_InitXPCOM2);
154     NS_DLSYM(NS_ShutdownXPCOM);
155     NS_DLSYM(NS_GetComponentRegistrar);
156     NS_DLSYM(NS_StringContainerInit);
157     NS_DLSYM(NS_CStringContainerInit);
158     NS_DLSYM(NS_StringContainerFinish);
159     NS_DLSYM(NS_CStringContainerFinish);
160     NS_DLSYM(NS_StringSetData);
161     NS_DLSYM(NS_CStringSetData);
162     NS_DLSYM(NS_NewLocalFile);
163     NS_DLSYM(NS_StringGetData);
164     NS_DLSYM(NS_CStringGetData);
165
166 #undef NS_DLSYM
167
168     return TRUE;
169 }
170
171 static BOOL check_version(LPCWSTR gre_path, const char *version_string)
172 {
173     WCHAR file_name[MAX_PATH];
174     char version[128];
175     DWORD read=0;
176     HANDLE hfile;
177
178     static const WCHAR wszVersion[] = {'\\','V','E','R','S','I','O','N',0};
179
180     strcpyW(file_name, gre_path);
181     strcatW(file_name, wszVersion);
182
183     hfile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
184                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
185     if(hfile == INVALID_HANDLE_VALUE) {
186         ERR("Could not open VERSION file\n");
187         return FALSE;
188     }
189
190     ReadFile(hfile, version, sizeof(version), &read, NULL);
191     version[read] = 0;
192     CloseHandle(hfile);
193
194     TRACE("%s\n", debugstr_a(version));
195
196     if(strcmp(version, version_string)) {
197         ERR("Unexpected version %s, expected %s\n", debugstr_a(version),
198             debugstr_a(version_string));
199         return FALSE;
200     }
201
202     return TRUE;
203 }
204
205 static BOOL load_wine_gecko_v(PRUnichar *gre_path, HKEY mshtml_key,
206         const char *version, const char *version_string)
207 {
208     DWORD res, type, size = MAX_PATH;
209     HKEY hkey = mshtml_key;
210
211     static const WCHAR wszGeckoPath[] =
212         {'G','e','c','k','o','P','a','t','h',0};
213
214     if(version) {
215         /* @@ Wine registry key: HKCU\Software\Wine\MSHTML\<version> */
216         res = RegOpenKeyA(mshtml_key, version, &hkey);
217         if(res != ERROR_SUCCESS)
218             return FALSE;
219     }
220
221     res = RegQueryValueExW(hkey, wszGeckoPath, NULL, &type, (LPBYTE)gre_path, &size);
222     if(hkey != mshtml_key)
223         RegCloseKey(hkey);
224     if(res != ERROR_SUCCESS || type != REG_SZ)
225         return FALSE;
226
227     if(!check_version(gre_path, version_string))
228         return FALSE;
229
230     return load_xpcom(gre_path);
231 }
232
233 static BOOL load_wine_gecko(PRUnichar *gre_path)
234 {
235     HKEY hkey;
236     DWORD res;
237     BOOL ret;
238
239     static const WCHAR wszMshtmlKey[] = {
240         'S','o','f','t','w','a','r','e','\\','W','i','n','e',
241         '\\','M','S','H','T','M','L',0};
242
243     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
244     res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey);
245     if(res != ERROR_SUCCESS)
246         return FALSE;
247
248     ret = load_wine_gecko_v(gre_path, hkey, GECKO_VERSION, GECKO_VERSION_STRING)
249         || load_wine_gecko_v(gre_path, hkey, "0.0.1", "Wine Gecko 0.0.1\n")
250         || load_wine_gecko_v(gre_path, hkey, NULL, "Wine Gecko 0.0.1\n");
251
252     RegCloseKey(hkey);
253     return ret;
254 }
255
256 static void set_profile(void)
257 {
258     nsIProfile *profile;
259     PRBool exists = FALSE;
260     nsresult nsres;
261
262     static const WCHAR wszMSHTML[] = {'M','S','H','T','M','L',0};
263
264     nsres = nsIServiceManager_GetServiceByContractID(pServMgr, NS_PROFILE_CONTRACTID,
265             &IID_nsIProfile, (void**)&profile);
266     if(NS_FAILED(nsres)) {
267         ERR("Could not get profile service: %08x\n", nsres);
268         return;
269     }
270
271     nsres = nsIProfile_ProfileExists(profile, wszMSHTML, &exists);
272     if(!exists) {
273         nsres = nsIProfile_CreateNewProfile(profile, wszMSHTML, NULL, NULL, FALSE);
274         if(NS_FAILED(nsres))
275             ERR("CreateNewProfile failed: %08x\n", nsres);
276     }
277
278     nsres = nsIProfile_SetCurrentProfile(profile, wszMSHTML);
279     if(NS_FAILED(nsres))
280         ERR("SetCurrentProfile failed: %08x\n", nsres);
281
282     nsIProfile_Release(profile);
283 }
284
285 static BOOL init_xpcom(const PRUnichar *gre_path)
286 {
287     nsresult nsres;
288     nsIObserver *pStartNotif;
289     nsIComponentRegistrar *registrar = NULL;
290     nsAString path;
291     nsIFile *gre_dir;
292
293     nsAString_Init(&path, gre_path);
294     nsres = NS_NewLocalFile(&path, FALSE, &gre_dir);
295     nsAString_Finish(&path);
296     if(NS_FAILED(nsres)) {
297         ERR("NS_NewLocalFile failed: %08x\n", nsres);
298         FreeLibrary(hXPCOM);
299         return FALSE;
300     }
301
302     nsres = NS_InitXPCOM2(&pServMgr, gre_dir, NULL);
303     if(NS_FAILED(nsres)) {
304         ERR("NS_InitXPCOM2 failed: %08x\n", nsres);
305         FreeLibrary(hXPCOM);
306         return FALSE;
307     }
308
309     nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr);
310     if(NS_FAILED(nsres))
311         ERR("Could not get nsIComponentManager: %08x\n", nsres);
312
313     nsres = NS_GetComponentRegistrar(&registrar);
314     if(NS_SUCCEEDED(nsres)) {
315         nsres = nsIComponentRegistrar_AutoRegister(registrar, NULL);
316         if(NS_FAILED(nsres))
317             ERR("AutoRegister(NULL) failed: %08x\n", nsres);
318
319         nsres = nsIComponentRegistrar_AutoRegister(registrar, gre_dir);
320         if(NS_FAILED(nsres))
321             ERR("AutoRegister(gre_dir) failed: %08x\n", nsres);
322
323         init_nsio(pCompMgr, registrar);
324     }else {
325         ERR("NS_GetComponentRegistrar failed: %08x\n", nsres);
326     }
327
328     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_APPSTARTUPNOTIFIER_CONTRACTID,
329             NULL, &IID_nsIObserver, (void**)&pStartNotif);
330     if(NS_SUCCEEDED(nsres)) {
331         nsres = nsIObserver_Observe(pStartNotif, NULL, APPSTARTUP_TOPIC, NULL);
332         if(NS_FAILED(nsres))
333             ERR("Observe failed: %08x\n", nsres);
334
335         nsIObserver_Release(pStartNotif);
336     }else {
337         ERR("could not get appstartup-notifier: %08x\n", nsres);
338     }
339
340     set_profile();
341
342     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_MEMORY_CONTRACTID,
343             NULL, &IID_nsIMemory, (void**)&nsmem);
344     if(NS_FAILED(nsres))
345         ERR("Could not get nsIMemory: %08x\n", nsres);
346
347     if(registrar) {
348         register_nsservice(registrar, pServMgr);
349         nsIComponentRegistrar_Release(registrar);
350     }
351
352     return TRUE;
353 }
354
355 static CRITICAL_SECTION cs_load_gecko;
356 static CRITICAL_SECTION_DEBUG cs_load_gecko_dbg =
357 {
358     0, 0, &cs_load_gecko,
359     { &cs_load_gecko_dbg.ProcessLocksList, &cs_load_gecko_dbg.ProcessLocksList },
360       0, 0, { (DWORD_PTR)(__FILE__ ": load_gecko") }
361 };
362 static CRITICAL_SECTION cs_load_gecko = { &cs_load_gecko_dbg, -1, 0, 0, 0, 0 };
363
364 BOOL load_gecko(BOOL silent)
365 {
366     PRUnichar gre_path[MAX_PATH];
367     BOOL ret = FALSE;
368
369     static LONG loading_thread;
370
371     TRACE("()\n");
372
373     /* load_gecko may be called recursively */
374     if(loading_thread == GetCurrentThreadId())
375         return pCompMgr != NULL;
376
377     EnterCriticalSection(&cs_load_gecko);
378
379     if(!loading_thread) {
380         loading_thread = GetCurrentThreadId();
381
382         if(load_wine_gecko(gre_path)
383            || (install_wine_gecko(silent) && load_wine_gecko(gre_path)))
384             ret = init_xpcom(gre_path);
385         else
386            MESSAGE("Could not load Mozilla. HTML rendering will be disabled.\n");
387     }else {
388         ret = pCompMgr != NULL;
389     }
390
391     LeaveCriticalSection(&cs_load_gecko);
392
393     return ret;
394 }
395
396 void *nsalloc(size_t size)
397 {
398     return nsIMemory_Alloc(nsmem, size);
399 }
400
401 void nsfree(void *mem)
402 {
403     nsIMemory_Free(nsmem, mem);
404 }
405
406 void nsACString_Init(nsACString *str, const char *data)
407 {
408     NS_CStringContainerInit(str);
409     if(data)
410         nsACString_SetData(str, data);
411 }
412
413 void nsACString_SetData(nsACString *str, const char *data)
414 {
415     NS_CStringSetData(str, data, PR_UINT32_MAX);
416 }
417
418 PRUint32 nsACString_GetData(const nsACString *str, const char **data, PRBool *termited)
419 {
420     return NS_CStringGetData(str, data, termited);
421 }
422
423 void nsACString_Finish(nsACString *str)
424 {
425     NS_CStringContainerFinish(str);
426 }
427
428 void nsAString_Init(nsAString *str, const PRUnichar *data)
429 {
430     NS_StringContainerInit(str);
431     if(data)
432         NS_StringSetData(str, data, PR_UINT32_MAX);
433 }
434
435 PRUint32 nsAString_GetData(const nsAString *str, const PRUnichar **data, PRBool *termited)
436 {
437     return NS_StringGetData(str, data, termited);
438 }
439
440 void nsAString_Finish(nsAString *str)
441 {
442     NS_StringContainerFinish(str);
443 }
444
445 nsIInputStream *create_nsstream(const char *data, PRInt32 data_len)
446 {
447     nsIStringInputStream *ret;
448     nsresult nsres;
449
450     if(!pCompMgr)
451         return NULL;
452
453     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
454             NS_STRINGSTREAM_CONTRACTID, NULL, &IID_nsIStringInputStream,
455             (void**)&ret);
456     if(NS_FAILED(nsres)) {
457         ERR("Could not get nsIStringInputStream\n");
458         return NULL;
459     }
460
461     nsres = nsIStringInputStream_SetData(ret, data, data_len);
462     if(NS_FAILED(nsres)) {
463         ERR("AdoptData failed: %08x\n", nsres);
464         nsIStringInputStream_Release(ret);
465         return NULL;
466     }
467
468     return (nsIInputStream*)ret;
469 }
470
471 nsIMutableArray *create_nsarray(void)
472 {
473     nsIMutableArray *ret;
474     nsresult nsres;
475
476     if(!pCompMgr)
477         return NULL;
478
479     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
480             NS_ARRAY_CONTRACTID, NULL, &IID_nsIMutableArray,
481             (void**)&ret);
482     if(NS_FAILED(nsres)) {
483         ERR("Could not get nsIArray: %08x\n", nsres);
484         return NULL;
485     }
486
487     return ret;
488 }
489
490 nsIWritableVariant *create_nsvariant(void)
491 {
492     nsIWritableVariant *ret;
493     nsresult nsres;
494
495     if(!pCompMgr)
496         return NULL;
497
498     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
499             NS_VARIANT_CONTRACTID, NULL, &IID_nsIWritableVariant,
500             (void**)&ret);
501     if(NS_FAILED(nsres)) {
502         ERR("Could not get nsIWritableVariant: %08x\n", nsres);
503         return NULL;
504     }
505
506     return ret;
507 }
508
509 nsICommandParams *create_nscommand_params(void)
510 {
511     nsICommandParams *ret = NULL;
512     nsresult nsres;
513
514     if(!pCompMgr)
515         return NULL;
516
517     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
518             NS_COMMANDPARAMS_CONTRACTID, NULL, &IID_nsICommandParams,
519             (void**)&ret);
520     if(NS_FAILED(nsres))
521         ERR("Could not get nsICommandParams\n");
522
523     return ret;
524 }
525
526 nsresult get_nsinterface(nsISupports *iface, REFIID riid, void **ppv)
527 {
528     nsIInterfaceRequestor *iface_req;
529     nsresult nsres;
530
531     nsres = nsISupports_QueryInterface(iface, &IID_nsIInterfaceRequestor, (void**)&iface_req);
532     if(NS_FAILED(nsres))
533         return nsres;
534
535     nsres = nsIInterfaceRequestor_GetInterface(iface_req, riid, ppv);
536     nsIInterfaceRequestor_Release(iface_req);
537
538     return nsres;
539 }
540
541 static void nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str)
542 {
543     nsIDOMNodeList *node_list = NULL;
544     PRBool has_children = FALSE;
545     PRUint16 type;
546     nsresult nsres;
547
548     nsIDOMNode_HasChildNodes(nsnode, &has_children);
549
550     nsres = nsIDOMNode_GetNodeType(nsnode, &type);
551     if(NS_FAILED(nsres)) {
552         ERR("GetType failed: %08x\n", nsres);
553         return;
554     }
555
556     switch(type) {
557     case ELEMENT_NODE: {
558         nsIDOMElement *nselem;
559         nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMElement, (void**)&nselem);
560         nsIContentSerializer_AppendElementStart(serializer, nselem, has_children, str);
561         nsIDOMElement_Release(nselem);
562         break;
563     }
564     case TEXT_NODE: {
565         nsIDOMText *nstext;
566         nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMText, (void**)&nstext);
567         nsIContentSerializer_AppendText(serializer, nstext, 0, -1, str);
568         nsIDOMText_Release(nstext);
569         break;
570     }
571     case COMMENT_NODE: {
572         nsIDOMComment *nscomment;
573         nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMComment, (void**)&nscomment);
574         nsres = nsIContentSerializer_AppendComment(serializer, nscomment, 0, -1, str);
575         break;
576     }
577     case DOCUMENT_NODE: {
578         nsIDOMDocument *nsdoc;
579         nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMDocument, (void**)&nsdoc);
580         nsIContentSerializer_AppendDocumentStart(serializer, nsdoc, str);
581         nsIDOMDocument_Release(nsdoc);
582         break;
583     }
584     case DOCUMENT_FRAGMENT_NODE:
585         break;
586     default:
587         FIXME("Unhandled type %u\n", type);
588     }
589
590     if(has_children) {
591         PRUint32 child_cnt, i;
592         nsIDOMNode *child_node;
593
594         nsIDOMNode_GetChildNodes(nsnode, &node_list);
595         nsIDOMNodeList_GetLength(node_list, &child_cnt);
596
597         for(i=0; i<child_cnt; i++) {
598             nsres = nsIDOMNodeList_Item(node_list, i, &child_node);
599             if(NS_SUCCEEDED(nsres)) {
600                 nsnode_to_nsstring_rec(serializer, child_node, str);
601                 nsIDOMNode_Release(child_node);
602             }else {
603                 ERR("Item failed: %08x\n", nsres);
604             }
605         }
606
607         nsIDOMNodeList_Release(node_list);
608     }
609
610     if(type == ELEMENT_NODE) {
611         nsIDOMElement *nselem;
612         nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMElement, (void**)&nselem);
613         nsIContentSerializer_AppendElementEnd(serializer, nselem, str);
614         nsIDOMElement_Release(nselem);
615     }
616 }
617
618 void nsnode_to_nsstring(nsIDOMNode *nsdoc, nsAString *str)
619 {
620     nsIContentSerializer *serializer;
621     nsIDOMNode *nsnode;
622     nsresult nsres;
623
624     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
625             NS_HTMLSERIALIZER_CONTRACTID, NULL, &IID_nsIContentSerializer,
626             (void**)&serializer);
627     if(NS_FAILED(nsres)) {
628         ERR("Could not get nsIContentSerializer: %08x\n", nsres);
629         return;
630     }
631
632     nsres = nsIContentSerializer_Init(serializer, 0, 100, NULL, FALSE);
633     if(NS_FAILED(nsres))
634         ERR("Init failed: %08x\n", nsres);
635
636     nsIDOMDocument_QueryInterface(nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
637     nsnode_to_nsstring_rec(serializer, nsnode, str);
638     nsIDOMNode_Release(nsnode);
639
640     nsres = nsIContentSerializer_Flush(serializer, str);
641     if(NS_FAILED(nsres))
642         ERR("Flush failed: %08x\n", nsres);
643
644     nsIContentSerializer_Release(serializer);
645 }
646
647 void get_editor_controller(NSContainer *This)
648 {
649     nsIEditingSession *editing_session = NULL;
650     nsIControllerContext *ctrlctx;
651     nsresult nsres;
652
653     if(This->editor) {
654         nsIEditor_Release(This->editor);
655         This->editor = NULL;
656     }
657
658     if(This->editor_controller) {
659         nsIController_Release(This->editor_controller);
660         This->editor_controller = NULL;
661     }
662
663     nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession,
664             (void**)&editing_session);
665     if(NS_FAILED(nsres)) {
666         ERR("Could not get nsIEditingSession: %08x\n", nsres);
667         return;
668     }
669
670     nsres = nsIEditingSession_GetEditorForWindow(editing_session,
671             This->doc->window->nswindow, &This->editor);
672     nsIEditingSession_Release(editing_session);
673     if(NS_FAILED(nsres)) {
674         ERR("Could not get editor: %08x\n", nsres);
675         return;
676     }
677
678     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
679             NS_EDITORCONTROLLER_CONTRACTID, NULL, &IID_nsIControllerContext, (void**)&ctrlctx);
680     if(NS_SUCCEEDED(nsres)) {
681         nsres = nsIControllerContext_SetCommandContext(ctrlctx, (nsISupports *)This->editor);
682         if(NS_FAILED(nsres))
683             ERR("SetCommandContext failed: %08x\n", nsres);
684         nsres = nsIControllerContext_QueryInterface(ctrlctx, &IID_nsIController,
685                 (void**)&This->editor_controller);
686         nsIControllerContext_Release(ctrlctx);
687         if(NS_FAILED(nsres))
688             ERR("Could not get nsIController interface: %08x\n", nsres);
689     }else {
690         ERR("Could not create edit controller: %08x\n", nsres);
691     }
692 }
693
694 void set_ns_editmode(NSContainer *This)
695 {
696     nsIEditingSession *editing_session = NULL;
697     nsIURIContentListener *listener = NULL;
698     nsIDOMWindow *dom_window = NULL;
699     nsresult nsres;
700
701     nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession,
702             (void**)&editing_session);
703     if(NS_FAILED(nsres)) {
704         ERR("Could not get nsIEditingSession: %08x\n", nsres);
705         return;
706     }
707
708     nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window);
709     if(NS_FAILED(nsres)) {
710         ERR("Could not get content DOM window: %08x\n", nsres);
711         nsIEditingSession_Release(editing_session);
712         return;
713     }
714
715     nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE);
716     nsIEditingSession_Release(editing_session);
717     nsIDOMWindow_Release(dom_window);
718     if(NS_FAILED(nsres)) {
719         ERR("MakeWindowEditable failed: %08x\n", nsres);
720         return;
721     }
722
723     /* MakeWindowEditable changes WebBrowser's parent URI content listener.
724      * It seams to be a bug in Gecko. To workaround it we set our content
725      * listener again and Gecko's one as its parent.
726      */
727     nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener);
728     nsIURIContentListener_SetParentContentListener(NSURICL(This), listener);
729     nsIURIContentListener_Release(listener);
730     nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This));
731 }
732
733 void close_gecko(void)
734 {
735     TRACE("()\n");
736
737     if(pCompMgr)
738         nsIComponentManager_Release(pCompMgr);
739
740     if(pServMgr)
741         nsIServiceManager_Release(pServMgr);
742
743     if(nsmem)
744         nsIMemory_Release(nsmem);
745
746     if(hXPCOM)
747         FreeLibrary(hXPCOM);
748 }
749
750 /**********************************************************
751  *      nsIWebBrowserChrome interface
752  */
753
754 #define NSWBCHROME_THIS(iface) DEFINE_THIS(NSContainer, WebBrowserChrome, iface)
755
756 static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface,
757         nsIIDRef riid, nsQIResult result)
758 {
759     NSContainer *This = NSWBCHROME_THIS(iface);
760
761     *result = NULL;
762     if(IsEqualGUID(&IID_nsISupports, riid)) {
763         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
764         *result = NSWBCHROME(This);
765     }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) {
766         TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result);
767         *result = NSWBCHROME(This);
768     }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) {
769         TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result);
770         *result = NSCML(This);
771     }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) {
772         TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result);
773         *result = NSURICL(This);
774     }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) {
775         TRACE("(%p)->(IID_nsIEmbeddingSiteWindow %p)\n", This, result);
776         *result = NSEMBWNDS(This);
777     }else if(IsEqualGUID(&IID_nsITooltipListener, riid)) {
778         TRACE("(%p)->(IID_nsITooltipListener %p)\n", This, result);
779         *result = NSTOOLTIP(This);
780     }else if(IsEqualGUID(&IID_nsIInterfaceRequestor, riid)) {
781         TRACE("(%p)->(IID_nsIInterfaceRequestor %p)\n", This, result);
782         *result = NSIFACEREQ(This);
783     }else if(IsEqualGUID(&IID_nsIWeakReference, riid)) {
784         TRACE("(%p)->(IID_nsIWeakReference %p)\n", This, result);
785         *result = NSWEAKREF(This);
786     }else if(IsEqualGUID(&IID_nsISupportsWeakReference, riid)) {
787         TRACE("(%p)->(IID_nsISupportsWeakReference %p)\n", This, result);
788         *result = NSSUPWEAKREF(This);
789     }
790
791     if(*result) {
792         nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
793         return NS_OK;
794     }
795
796     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
797     return NS_NOINTERFACE;
798 }
799
800 static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface)
801 {
802     NSContainer *This = NSWBCHROME_THIS(iface);
803     LONG ref = InterlockedIncrement(&This->ref);
804
805     TRACE("(%p) ref=%d\n", This, ref);
806
807     return ref;
808 }
809
810 static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface)
811 {
812     NSContainer *This = NSWBCHROME_THIS(iface);
813     LONG ref = InterlockedDecrement(&This->ref);
814
815     TRACE("(%p) ref=%d\n", This, ref);
816
817     if(!ref) {
818         if(This->parent)
819             nsIWebBrowserChrome_Release(NSWBCHROME(This->parent));
820         mshtml_free(This);
821     }
822
823     return ref;
824 }
825
826 static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface,
827         PRUint32 statusType, const PRUnichar *status)
828 {
829     NSContainer *This = NSWBCHROME_THIS(iface);
830     TRACE("(%p)->(%d %s)\n", This, statusType, debugstr_w(status));
831     return NS_ERROR_NOT_IMPLEMENTED;
832 }
833
834 static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface,
835         nsIWebBrowser **aWebBrowser)
836 {
837     NSContainer *This = NSWBCHROME_THIS(iface);
838
839     TRACE("(%p)->(%p)\n", This, aWebBrowser);
840
841     if(!aWebBrowser)
842         return NS_ERROR_INVALID_ARG;
843
844     if(This->webbrowser)
845         nsIWebBrowser_AddRef(This->webbrowser);
846     *aWebBrowser = This->webbrowser;
847     return S_OK;
848 }
849
850 static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface,
851         nsIWebBrowser *aWebBrowser)
852 {
853     NSContainer *This = NSWBCHROME_THIS(iface);
854
855     TRACE("(%p)->(%p)\n", This, aWebBrowser);
856
857     if(aWebBrowser != This->webbrowser)
858         ERR("Wrong nsWebBrowser!\n");
859
860     return NS_OK;
861 }
862
863 static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface,
864         PRUint32 *aChromeFlags)
865 {
866     NSContainer *This = NSWBCHROME_THIS(iface);
867     WARN("(%p)->(%p)\n", This, aChromeFlags);
868     return NS_ERROR_NOT_IMPLEMENTED;
869 }
870
871 static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface,
872         PRUint32 aChromeFlags)
873 {
874     NSContainer *This = NSWBCHROME_THIS(iface);
875     WARN("(%p)->(%08x)\n", This, aChromeFlags);
876     return NS_ERROR_NOT_IMPLEMENTED;
877 }
878
879 static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface)
880 {
881     NSContainer *This = NSWBCHROME_THIS(iface);
882     TRACE("(%p)\n", This);
883     return NS_ERROR_NOT_IMPLEMENTED;
884 }
885
886 static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface,
887         PRInt32 aCX, PRInt32 aCY)
888 {
889     NSContainer *This = NSWBCHROME_THIS(iface);
890     WARN("(%p)->(%d %d)\n", This, aCX, aCY);
891     return NS_ERROR_NOT_IMPLEMENTED;
892 }
893
894 static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface)
895 {
896     NSContainer *This = NSWBCHROME_THIS(iface);
897     WARN("(%p)\n", This);
898     return NS_ERROR_NOT_IMPLEMENTED;
899 }
900
901 static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, PRBool *_retval)
902 {
903     NSContainer *This = NSWBCHROME_THIS(iface);
904     WARN("(%p)->(%p)\n", This, _retval);
905     return NS_ERROR_NOT_IMPLEMENTED;
906 }
907
908 static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface,
909         nsresult aStatus)
910 {
911     NSContainer *This = NSWBCHROME_THIS(iface);
912     WARN("(%p)->(%08x)\n", This, aStatus);
913     return NS_ERROR_NOT_IMPLEMENTED;
914 }
915
916 #undef NSWBCHROME_THIS
917
918 static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = {
919     nsWebBrowserChrome_QueryInterface,
920     nsWebBrowserChrome_AddRef,
921     nsWebBrowserChrome_Release,
922     nsWebBrowserChrome_SetStatus,
923     nsWebBrowserChrome_GetWebBrowser,
924     nsWebBrowserChrome_SetWebBrowser,
925     nsWebBrowserChrome_GetChromeFlags,
926     nsWebBrowserChrome_SetChromeFlags,
927     nsWebBrowserChrome_DestroyBrowserWindow,
928     nsWebBrowserChrome_SizeBrowserTo,
929     nsWebBrowserChrome_ShowAsModal,
930     nsWebBrowserChrome_IsWindowModal,
931     nsWebBrowserChrome_ExitModalEventLoop
932 };
933
934 /**********************************************************
935  *      nsIContextMenuListener interface
936  */
937
938 #define NSCML_THIS(iface) DEFINE_THIS(NSContainer, ContextMenuListener, iface)
939
940 static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface,
941         nsIIDRef riid, nsQIResult result)
942 {
943     NSContainer *This = NSCML_THIS(iface);
944     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
945 }
946
947 static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface)
948 {
949     NSContainer *This = NSCML_THIS(iface);
950     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
951 }
952
953 static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface)
954 {
955     NSContainer *This = NSCML_THIS(iface);
956     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
957 }
958
959 static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface,
960         PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
961 {
962     NSContainer *This = NSCML_THIS(iface);
963     nsIDOMMouseEvent *event;
964     POINT pt;
965     DWORD dwID = CONTEXT_MENU_DEFAULT;
966     nsresult nsres;
967
968     TRACE("(%p)->(%08x %p %p)\n", This, aContextFlags, aEvent, aNode);
969
970     nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event);
971     if(NS_FAILED(nsres)) {
972         ERR("Could not get nsIDOMMouseEvent interface: %08x\n", nsres);
973         return nsres;
974     }
975
976     nsIDOMMouseEvent_GetScreenX(event, &pt.x);
977     nsIDOMMouseEvent_GetScreenY(event, &pt.y);
978     nsIDOMMouseEvent_Release(event);
979
980     switch(aContextFlags) {
981     case CONTEXT_NONE:
982     case CONTEXT_DOCUMENT:
983     case CONTEXT_TEXT:
984         dwID = CONTEXT_MENU_DEFAULT;
985         break;
986     case CONTEXT_IMAGE:
987     case CONTEXT_IMAGE|CONTEXT_LINK:
988         dwID = CONTEXT_MENU_IMAGE;
989         break;
990     case CONTEXT_LINK:
991         dwID = CONTEXT_MENU_ANCHOR;
992         break;
993     case CONTEXT_INPUT:
994         dwID = CONTEXT_MENU_CONTROL;
995         break;
996     default:
997         FIXME("aContextFlags=%08x\n", aContextFlags);
998     };
999
1000     show_context_menu(This->doc, dwID, &pt, (IDispatch*)HTMLDOMNODE(get_node(This->doc, aNode)));
1001
1002     return NS_OK;
1003 }
1004
1005 #undef NSCML_THIS
1006
1007 static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = {
1008     nsContextMenuListener_QueryInterface,
1009     nsContextMenuListener_AddRef,
1010     nsContextMenuListener_Release,
1011     nsContextMenuListener_OnShowContextMenu
1012 };
1013
1014 /**********************************************************
1015  *      nsIURIContentListener interface
1016  */
1017
1018 #define NSURICL_THIS(iface) DEFINE_THIS(NSContainer, URIContentListener, iface)
1019
1020 static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface,
1021         nsIIDRef riid, nsQIResult result)
1022 {
1023     NSContainer *This = NSURICL_THIS(iface);
1024     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1025 }
1026
1027 static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface)
1028 {
1029     NSContainer *This = NSURICL_THIS(iface);
1030     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1031 }
1032
1033 static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
1034 {
1035     NSContainer *This = NSURICL_THIS(iface);
1036     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1037 }
1038
1039 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
1040                                                           nsIURI *aURI, PRBool *_retval)
1041 {
1042     NSContainer *This = NSURICL_THIS(iface);
1043     nsIWineURI *wine_uri;
1044     nsACString spec_str;
1045     const char *spec;
1046     nsresult nsres;
1047
1048     nsACString_Init(&spec_str, NULL);
1049     nsIURI_GetSpec(aURI, &spec_str);
1050     nsACString_GetData(&spec_str, &spec, NULL);
1051
1052     TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval);
1053
1054     nsACString_Finish(&spec_str);
1055
1056     nsres = nsIURI_QueryInterface(aURI, &IID_nsIWineURI, (void**)&wine_uri);
1057     if(NS_FAILED(nsres)) {
1058         WARN("Could not get nsIWineURI interface: %08x\n", nsres);
1059         return NS_ERROR_NOT_IMPLEMENTED;
1060     }
1061
1062     nsIWineURI_SetNSContainer(wine_uri, This);
1063     nsIWineURI_SetIsDocumentURI(wine_uri, TRUE);
1064
1065     if(This->bscallback && This->bscallback->mon) {
1066         LPWSTR wine_url;
1067         HRESULT hres;
1068
1069         hres = IMoniker_GetDisplayName(This->bscallback->mon, NULL, 0, &wine_url);
1070         if(SUCCEEDED(hres)) {
1071             nsIWineURI_SetWineURL(wine_uri, wine_url);
1072             CoTaskMemFree(wine_url);
1073         }else {
1074             WARN("GetDisplayName failed: %08x\n", hres);
1075         }
1076     }
1077
1078     nsIWineURI_Release(wine_uri);
1079
1080     *_retval = FALSE;
1081     return This->content_listener
1082         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
1083         : NS_OK;
1084 }
1085
1086 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
1087         const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest,
1088         nsIStreamListener **aContentHandler, PRBool *_retval)
1089 {
1090     NSContainer *This = NSURICL_THIS(iface);
1091
1092     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1093             aRequest, aContentHandler, _retval);
1094
1095     return This->content_listener
1096         ? nsIURIContentListener_DoContent(This->content_listener, aContentType,
1097                   aIsContentPreferred, aRequest, aContentHandler, _retval)
1098         : NS_ERROR_NOT_IMPLEMENTED;
1099 }
1100
1101 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
1102         const char *aContentType, char **aDesiredContentType, PRBool *_retval)
1103 {
1104     NSContainer *This = NSURICL_THIS(iface);
1105
1106     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
1107
1108     /* FIXME: Should we do something here? */
1109     *_retval = TRUE; 
1110
1111     return This->content_listener
1112         ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType,
1113                   aDesiredContentType, _retval)
1114         : NS_OK;
1115 }
1116
1117 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
1118         const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType,
1119         PRBool *_retval)
1120 {
1121     NSContainer *This = NSURICL_THIS(iface);
1122
1123     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1124             aDesiredContentType, _retval);
1125
1126     return This->content_listener
1127         ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType,
1128                 aIsContentPreferred, aDesiredContentType, _retval)
1129         : NS_ERROR_NOT_IMPLEMENTED;
1130 }
1131
1132 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
1133         nsISupports **aLoadCookie)
1134 {
1135     NSContainer *This = NSURICL_THIS(iface);
1136
1137     WARN("(%p)->(%p)\n", This, aLoadCookie);
1138
1139     return This->content_listener
1140         ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie)
1141         : NS_ERROR_NOT_IMPLEMENTED;
1142 }
1143
1144 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
1145         nsISupports *aLoadCookie)
1146 {
1147     NSContainer *This = NSURICL_THIS(iface);
1148
1149     WARN("(%p)->(%p)\n", This, aLoadCookie);
1150
1151     return This->content_listener
1152         ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie)
1153         : NS_ERROR_NOT_IMPLEMENTED;
1154 }
1155
1156 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
1157         nsIURIContentListener **aParentContentListener)
1158 {
1159     NSContainer *This = NSURICL_THIS(iface);
1160
1161     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1162
1163     if(This->content_listener)
1164         nsIURIContentListener_AddRef(This->content_listener);
1165
1166     *aParentContentListener = This->content_listener;
1167     return NS_OK;
1168 }
1169
1170 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
1171         nsIURIContentListener *aParentContentListener)
1172 {
1173     NSContainer *This = NSURICL_THIS(iface);
1174
1175     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1176
1177     if(aParentContentListener == NSURICL(This))
1178         return NS_OK;
1179
1180     if(This->content_listener)
1181         nsIURIContentListener_Release(This->content_listener);
1182
1183     This->content_listener = aParentContentListener;
1184     if(This->content_listener)
1185         nsIURIContentListener_AddRef(This->content_listener);
1186
1187     return NS_OK;
1188 }
1189
1190 #undef NSURICL_THIS
1191
1192 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
1193     nsURIContentListener_QueryInterface,
1194     nsURIContentListener_AddRef,
1195     nsURIContentListener_Release,
1196     nsURIContentListener_OnStartURIOpen,
1197     nsURIContentListener_DoContent,
1198     nsURIContentListener_IsPreferred,
1199     nsURIContentListener_CanHandleContent,
1200     nsURIContentListener_GetLoadCookie,
1201     nsURIContentListener_SetLoadCookie,
1202     nsURIContentListener_GetParentContentListener,
1203     nsURIContentListener_SetParentContentListener
1204 };
1205
1206 /**********************************************************
1207  *      nsIEmbeddinSiteWindow interface
1208  */
1209
1210 #define NSEMBWNDS_THIS(iface) DEFINE_THIS(NSContainer, EmbeddingSiteWindow, iface)
1211
1212 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
1213         nsIIDRef riid, nsQIResult result)
1214 {
1215     NSContainer *This = NSEMBWNDS_THIS(iface);
1216     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1217 }
1218
1219 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
1220 {
1221     NSContainer *This = NSEMBWNDS_THIS(iface);
1222     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1223 }
1224
1225 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
1226 {
1227     NSContainer *This = NSEMBWNDS_THIS(iface);
1228     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1229 }
1230
1231 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
1232         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
1233 {
1234     NSContainer *This = NSEMBWNDS_THIS(iface);
1235     WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy);
1236     return NS_ERROR_NOT_IMPLEMENTED;
1237 }
1238
1239 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
1240         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
1241 {
1242     NSContainer *This = NSEMBWNDS_THIS(iface);
1243     WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy);
1244     return NS_ERROR_NOT_IMPLEMENTED;
1245 }
1246
1247 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
1248 {
1249     NSContainer *This = NSEMBWNDS_THIS(iface);
1250
1251     TRACE("(%p)\n", This);
1252
1253     return nsIBaseWindow_SetFocus(This->window);
1254 }
1255
1256 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
1257         PRBool *aVisibility)
1258 {
1259     NSContainer *This = NSEMBWNDS_THIS(iface);
1260
1261     TRACE("(%p)->(%p)\n", This, aVisibility);
1262
1263     *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd);
1264     return NS_OK;
1265 }
1266
1267 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
1268         PRBool aVisibility)
1269 {
1270     NSContainer *This = NSEMBWNDS_THIS(iface);
1271
1272     TRACE("(%p)->(%x)\n", This, aVisibility);
1273
1274     return NS_OK;
1275 }
1276
1277 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
1278         PRUnichar **aTitle)
1279 {
1280     NSContainer *This = NSEMBWNDS_THIS(iface);
1281     WARN("(%p)->(%p)\n", This, aTitle);
1282     return NS_ERROR_NOT_IMPLEMENTED;
1283 }
1284
1285 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
1286         const PRUnichar *aTitle)
1287 {
1288     NSContainer *This = NSEMBWNDS_THIS(iface);
1289     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
1290     return NS_ERROR_NOT_IMPLEMENTED;
1291 }
1292
1293 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
1294         void **aSiteWindow)
1295 {
1296     NSContainer *This = NSEMBWNDS_THIS(iface);
1297
1298     TRACE("(%p)->(%p)\n", This, aSiteWindow);
1299
1300     *aSiteWindow = This->hwnd;
1301     return NS_OK;
1302 }
1303
1304 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
1305     nsEmbeddingSiteWindow_QueryInterface,
1306     nsEmbeddingSiteWindow_AddRef,
1307     nsEmbeddingSiteWindow_Release,
1308     nsEmbeddingSiteWindow_SetDimensions,
1309     nsEmbeddingSiteWindow_GetDimensions,
1310     nsEmbeddingSiteWindow_SetFocus,
1311     nsEmbeddingSiteWindow_GetVisibility,
1312     nsEmbeddingSiteWindow_SetVisibility,
1313     nsEmbeddingSiteWindow_GetTitle,
1314     nsEmbeddingSiteWindow_SetTitle,
1315     nsEmbeddingSiteWindow_GetSiteWindow
1316 };
1317
1318 #define NSTOOLTIP_THIS(iface) DEFINE_THIS(NSContainer, TooltipListener, iface)
1319
1320 static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid,
1321                                                        nsQIResult result)
1322 {
1323     NSContainer *This = NSTOOLTIP_THIS(iface);
1324     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1325 }
1326
1327 static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface)
1328 {
1329     NSContainer *This = NSTOOLTIP_THIS(iface);
1330     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1331 }
1332
1333 static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface)
1334 {
1335     NSContainer *This = NSTOOLTIP_THIS(iface);
1336     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1337 }
1338
1339 static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface,
1340         PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText)
1341 {
1342     NSContainer *This = NSTOOLTIP_THIS(iface);
1343
1344     show_tooltip(This->doc, aXCoord, aYCoord, aTipText);
1345
1346     return NS_OK;
1347 }
1348
1349 static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface)
1350 {
1351     NSContainer *This = NSTOOLTIP_THIS(iface);
1352
1353     hide_tooltip(This->doc);
1354
1355     return NS_OK;
1356 }
1357
1358 #undef NSTOOLTIM_THIS
1359
1360 static const nsITooltipListenerVtbl nsTooltipListenerVtbl = {
1361     nsTooltipListener_QueryInterface,
1362     nsTooltipListener_AddRef,
1363     nsTooltipListener_Release,
1364     nsTooltipListener_OnShowTooltip,
1365     nsTooltipListener_OnHideTooltip
1366 };
1367
1368 #define NSIFACEREQ_THIS(iface) DEFINE_THIS(NSContainer, InterfaceRequestor, iface)
1369
1370 static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface,
1371                                                           nsIIDRef riid, nsQIResult result)
1372 {
1373     NSContainer *This = NSIFACEREQ_THIS(iface);
1374     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1375 }
1376
1377 static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface)
1378 {
1379     NSContainer *This = NSIFACEREQ_THIS(iface);
1380     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1381 }
1382
1383 static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface)
1384 {
1385     NSContainer *This = NSIFACEREQ_THIS(iface);
1386     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1387 }
1388
1389 static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface,
1390                                                         nsIIDRef riid, nsQIResult result)
1391 {
1392     NSContainer *This = NSIFACEREQ_THIS(iface);
1393
1394     if(IsEqualGUID(&IID_nsIDOMWindow, riid)) {
1395         TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result);
1396         return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result);
1397     }
1398
1399     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1400 }
1401
1402 #undef NSIFACEREQ_THIS
1403
1404 static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = {
1405     nsInterfaceRequestor_QueryInterface,
1406     nsInterfaceRequestor_AddRef,
1407     nsInterfaceRequestor_Release,
1408     nsInterfaceRequestor_GetInterface
1409 };
1410
1411 #define NSWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, WeakReference, iface)
1412
1413 static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface,
1414         nsIIDRef riid, nsQIResult result)
1415 {
1416     NSContainer *This = NSWEAKREF_THIS(iface);
1417     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1418 }
1419
1420 static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface)
1421 {
1422     NSContainer *This = NSWEAKREF_THIS(iface);
1423     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1424 }
1425
1426 static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface)
1427 {
1428     NSContainer *This = NSWEAKREF_THIS(iface);
1429     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1430 }
1431
1432 static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface,
1433         const nsIID *riid, void **result)
1434 {
1435     NSContainer *This = NSWEAKREF_THIS(iface);
1436     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1437 }
1438
1439 #undef NSWEAKREF_THIS
1440
1441 static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = {
1442     nsWeakReference_QueryInterface,
1443     nsWeakReference_AddRef,
1444     nsWeakReference_Release,
1445     nsWeakReference_QueryReferent
1446 };
1447
1448 #define NSSUPWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, SupportsWeakReference, iface)
1449
1450 static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface,
1451         nsIIDRef riid, nsQIResult result)
1452 {
1453     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1454     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1455 }
1456
1457 static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface)
1458 {
1459     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1460     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1461 }
1462
1463 static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface)
1464 {
1465     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1466     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1467 }
1468
1469 static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface,
1470         nsIWeakReference **_retval)
1471 {
1472     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1473
1474     TRACE("(%p)->(%p)\n", This, _retval);
1475
1476     nsIWeakReference_AddRef(NSWEAKREF(This));
1477     *_retval = NSWEAKREF(This);
1478     return NS_OK;
1479 }
1480
1481 #undef NSWEAKREF_THIS
1482
1483 static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = {
1484     nsSupportsWeakReference_QueryInterface,
1485     nsSupportsWeakReference_AddRef,
1486     nsSupportsWeakReference_Release,
1487     nsSupportsWeakReference_GetWeakReference
1488 };
1489
1490
1491 NSContainer *NSContainer_Create(HTMLDocument *doc, NSContainer *parent)
1492 {
1493     nsIWebBrowserSetup *wbsetup;
1494     nsIScrollable *scrollable;
1495     NSContainer *ret;
1496     nsresult nsres;
1497
1498     if(!load_gecko(FALSE))
1499         return NULL;
1500
1501     ret = mshtml_alloc(sizeof(NSContainer));
1502
1503     ret->lpWebBrowserChromeVtbl      = &nsWebBrowserChromeVtbl;
1504     ret->lpContextMenuListenerVtbl   = &nsContextMenuListenerVtbl;
1505     ret->lpURIContentListenerVtbl    = &nsURIContentListenerVtbl;
1506     ret->lpEmbeddingSiteWindowVtbl   = &nsEmbeddingSiteWindowVtbl;
1507     ret->lpTooltipListenerVtbl       = &nsTooltipListenerVtbl;
1508     ret->lpInterfaceRequestorVtbl    = &nsInterfaceRequestorVtbl;
1509     ret->lpWeakReferenceVtbl         = &nsWeakReferenceVtbl;
1510     ret->lpSupportsWeakReferenceVtbl = &nsSupportsWeakReferenceVtbl;
1511
1512     ret->doc = doc;
1513     ret->ref = 1;
1514     ret->bscallback = NULL;
1515     ret->content_listener = NULL;
1516     ret->editor_controller = NULL;
1517     ret->editor = NULL;
1518
1519     if(parent)
1520         nsIWebBrowserChrome_AddRef(NSWBCHROME(parent));
1521     ret->parent = parent;
1522
1523     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
1524             NULL, &IID_nsIWebBrowser, (void**)&ret->webbrowser);
1525     if(NS_FAILED(nsres))
1526         ERR("Creating WebBrowser failed: %08x\n", nsres);
1527
1528     nsres = nsIWebBrowser_SetContainerWindow(ret->webbrowser, NSWBCHROME(ret));
1529     if(NS_FAILED(nsres))
1530         ERR("SetContainerWindow failed: %08x\n", nsres);
1531
1532     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIBaseWindow,
1533             (void**)&ret->window);
1534     if(NS_FAILED(nsres))
1535         ERR("Could not get nsIBaseWindow interface: %08x\n", nsres);
1536
1537     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserSetup,
1538                                          (void**)&wbsetup);
1539     if(NS_SUCCEEDED(nsres)) {
1540         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE);
1541         nsIWebBrowserSetup_Release(wbsetup);
1542         if(NS_FAILED(nsres))
1543             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres);
1544     }else {
1545         ERR("Could not get nsIWebBrowserSetup interface\n");
1546     }
1547
1548     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebNavigation,
1549             (void**)&ret->navigation);
1550     if(NS_FAILED(nsres))
1551         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
1552
1553     nsres = nsIWebBrowserFocus_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserFocus,
1554             (void**)&ret->focus);
1555     if(NS_FAILED(nsres))
1556         ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres);
1557
1558     if(!nscontainer_class)
1559         register_nscontainer_class();
1560
1561     ret->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
1562             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
1563             GetDesktopWindow(), NULL, hInst, ret);
1564
1565     nsres = nsIBaseWindow_InitWindow(ret->window, ret->hwnd, NULL, 0, 0, 100, 100);
1566     if(NS_SUCCEEDED(nsres)) {
1567         nsres = nsIBaseWindow_Create(ret->window);
1568         if(NS_FAILED(nsres))
1569             WARN("Creating window failed: %08x\n", nsres);
1570
1571         nsIBaseWindow_SetVisibility(ret->window, FALSE);
1572         nsIBaseWindow_SetEnabled(ret->window, FALSE);
1573     }else {
1574         ERR("InitWindow failed: %08x\n", nsres);
1575     }
1576
1577     nsres = nsIWebBrowser_SetParentURIContentListener(ret->webbrowser, NSURICL(ret));
1578     if(NS_FAILED(nsres))
1579         ERR("SetParentURIContentListener failed: %08x\n", nsres);
1580
1581     init_nsevents(ret);
1582
1583     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
1584     if(NS_SUCCEEDED(nsres)) {
1585         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1586                 ScrollOrientation_Y, Scrollbar_Always);
1587         if(NS_FAILED(nsres))
1588             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
1589
1590         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1591                 ScrollOrientation_X, Scrollbar_Auto);
1592         if(NS_FAILED(nsres))
1593             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
1594
1595         nsIScrollable_Release(scrollable);
1596     }else {
1597         ERR("Could not get nsIScrollable: %08x\n", nsres);
1598     }
1599
1600     return ret;
1601 }
1602
1603 void NSContainer_Release(NSContainer *This)
1604 {
1605     TRACE("(%p)\n", This);
1606
1607     ShowWindow(This->hwnd, SW_HIDE);
1608     SetParent(This->hwnd, NULL);
1609
1610     nsIBaseWindow_SetVisibility(This->window, FALSE);
1611     nsIBaseWindow_Destroy(This->window);
1612
1613     nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL);
1614
1615     nsIWebBrowser_Release(This->webbrowser);
1616     This->webbrowser = NULL;
1617
1618     nsIWebNavigation_Release(This->navigation);
1619     This->navigation = NULL;
1620
1621     nsIBaseWindow_Release(This->window);
1622     This->window = NULL;
1623
1624     nsIWebBrowserFocus_Release(This->focus);
1625     This->focus = NULL;
1626
1627     if(This->editor_controller) {
1628         nsIController_Release(This->editor_controller);
1629         This->editor_controller = NULL;
1630     }
1631
1632     if(This->editor) {
1633         nsIEditor_Release(This->editor);
1634         This->editor = NULL;
1635     }
1636
1637     if(This->content_listener) {
1638         nsIURIContentListener_Release(This->content_listener);
1639         This->content_listener = NULL;
1640     }
1641
1642     if(This->hwnd) {
1643         DestroyWindow(This->hwnd);
1644         This->hwnd = NULL;
1645     }
1646
1647     nsIWebBrowserChrome_Release(NSWBCHROME(This));
1648 }