mshtml: COM cleanup for the IHTMLDOMNode iface.
[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 #include "shlobj.h"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 #include "mshtml_private.h"
36 #include "htmlevent.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
39 WINE_DECLARE_DEBUG_CHANNEL(gecko);
40
41 #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1"
42 #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1"
43 #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1"
44 #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1"
45 #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html"
46 #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1"
47 #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1"
48
49 #define APPSTARTUP_TOPIC "app-startup"
50
51 #define PR_UINT32_MAX 0xffffffff
52
53 #define NS_STRING_CONTAINER_INIT_DEPEND  0x0002
54 #define NS_CSTRING_CONTAINER_INIT_DEPEND 0x0002
55
56 static nsresult (CDECL *NS_InitXPCOM2)(nsIServiceManager**,void*,void*);
57 static nsresult (CDECL *NS_ShutdownXPCOM)(nsIServiceManager*);
58 static nsresult (CDECL *NS_GetComponentRegistrar)(nsIComponentRegistrar**);
59 static nsresult (CDECL *NS_StringContainerInit2)(nsStringContainer*,const PRUnichar*,PRUint32,PRUint32);
60 static nsresult (CDECL *NS_CStringContainerInit2)(nsCStringContainer*,const char*,PRUint32,PRUint32);
61 static nsresult (CDECL *NS_StringContainerFinish)(nsStringContainer*);
62 static nsresult (CDECL *NS_CStringContainerFinish)(nsCStringContainer*);
63 static nsresult (CDECL *NS_StringSetData)(nsAString*,const PRUnichar*,PRUint32);
64 static nsresult (CDECL *NS_CStringSetData)(nsACString*,const char*,PRUint32);
65 static nsresult (CDECL *NS_NewLocalFile)(const nsAString*,PRBool,nsIFile**);
66 static PRUint32 (CDECL *NS_StringGetData)(const nsAString*,const PRUnichar **,PRBool*);
67 static PRUint32 (CDECL *NS_CStringGetData)(const nsACString*,const char**,PRBool*);
68
69 static HINSTANCE hXPCOM = NULL;
70
71 static nsIServiceManager *pServMgr = NULL;
72 static nsIComponentManager *pCompMgr = NULL;
73 static nsIMemory *nsmem = NULL;
74 static nsIFile *profile_directory;
75
76 static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0};
77
78 static ATOM nscontainer_class;
79 static WCHAR gecko_path[MAX_PATH];
80 static unsigned gecko_path_len;
81
82 static nsresult NSAPI nsDirectoryServiceProvider_QueryInterface(nsIDirectoryServiceProvider *iface,
83         nsIIDRef riid, void **result)
84 {
85     if(IsEqualGUID(&IID_nsISupports, riid)) {
86         TRACE("(IID_nsISupports %p)\n", result);
87         *result = iface;
88     }else if(IsEqualGUID(&IID_nsIDirectoryServiceProvider, riid)) {
89         TRACE("(IID_nsIDirectoryServiceProvider %p)\n", result);
90         *result = iface;
91     }else {
92         WARN("(%s %p)\n", debugstr_guid(riid), result);
93         *result = NULL;
94         return NS_NOINTERFACE;
95     }
96
97     nsISupports_AddRef((nsISupports*)*result);
98     return NS_OK;
99 }
100
101 static nsrefcnt NSAPI nsDirectoryServiceProvider_AddRef(nsIDirectoryServiceProvider *iface)
102 {
103     return 2;
104 }
105
106 static nsrefcnt NSAPI nsDirectoryServiceProvider_Release(nsIDirectoryServiceProvider *iface)
107 {
108     return 1;
109 }
110
111 static nsresult create_profile_directory(void)
112 {
113     static const WCHAR wine_geckoW[] = {'\\','w','i','n','e','_','g','e','c','k','o',0};
114
115     WCHAR path[MAX_PATH + sizeof(wine_geckoW)/sizeof(WCHAR)];
116     nsAString str;
117     PRBool exists;
118     nsresult nsres;
119     HRESULT hres;
120
121     hres = SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_DEFAULT, path);
122     if(FAILED(hres)) {
123         ERR("SHGetFolderPath failed: %08x\n", hres);
124         return NS_ERROR_FAILURE;
125     }
126
127     strcatW(path, wine_geckoW);
128     nsAString_InitDepend(&str, path);
129     nsres = NS_NewLocalFile(&str, FALSE, &profile_directory);
130     nsAString_Finish(&str);
131     if(NS_FAILED(nsres)) {
132         ERR("NS_NewLocalFile failed: %08x\n", nsres);
133         return nsres;
134     }
135
136     nsres = nsIFile_Exists(profile_directory, &exists);
137     if(NS_FAILED(nsres)) {
138         ERR("Exists failed: %08x\n", nsres);
139         return nsres;
140     }
141
142     if(!exists) {
143         nsres = nsIFile_Create(profile_directory, 1, 0700);
144         if(NS_FAILED(nsres))
145             ERR("Create failed: %08x\n", nsres);
146     }
147
148     return nsres;
149 }
150
151 static nsresult NSAPI nsDirectoryServiceProvider_GetFile(nsIDirectoryServiceProvider *iface,
152         const char *prop, PRBool *persistent, nsIFile **_retval)
153 {
154     TRACE("(%s %p %p)\n", debugstr_a(prop), persistent, _retval);
155
156     if(!strcmp(prop, "ProfD")) {
157         if(!profile_directory) {
158             nsresult nsres;
159
160             nsres = create_profile_directory();
161             if(NS_FAILED(nsres))
162                 return nsres;
163         }
164
165         return nsIFile_Clone(profile_directory, _retval);
166     }
167
168     return NS_ERROR_FAILURE;
169 }
170
171 static const nsIDirectoryServiceProviderVtbl nsDirectoryServiceProviderVtbl = {
172     nsDirectoryServiceProvider_QueryInterface,
173     nsDirectoryServiceProvider_AddRef,
174     nsDirectoryServiceProvider_Release,
175     nsDirectoryServiceProvider_GetFile
176 };
177
178 static nsIDirectoryServiceProvider nsDirectoryServiceProvider =
179     { &nsDirectoryServiceProviderVtbl };
180
181 static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
182 {
183     NSContainer *This;
184     nsresult nsres;
185
186     static const WCHAR wszTHIS[] = {'T','H','I','S',0};
187
188     if(msg == WM_CREATE) {
189         This = *(NSContainer**)lParam;
190         SetPropW(hwnd, wszTHIS, This);
191     }else {
192         This = GetPropW(hwnd, wszTHIS);
193     }
194
195     switch(msg) {
196     case WM_SIZE:
197         TRACE("(%p)->(WM_SIZE)\n", This);
198
199         nsres = nsIBaseWindow_SetSize(This->window,
200                 LOWORD(lParam), HIWORD(lParam), TRUE);
201         if(NS_FAILED(nsres))
202             WARN("SetSize failed: %08x\n", nsres);
203         break;
204
205     case WM_PARENTNOTIFY:
206         TRACE("WM_PARENTNOTIFY %x\n", (unsigned)wParam);
207
208         switch(wParam) {
209         case WM_LBUTTONDOWN:
210         case WM_RBUTTONDOWN:
211             nsIWebBrowserFocus_Activate(This->focus);
212         }
213     }
214
215     return DefWindowProcW(hwnd, msg, wParam, lParam);
216 }
217
218
219 static void register_nscontainer_class(void)
220 {
221     static WNDCLASSEXW wndclass = {
222         sizeof(WNDCLASSEXW),
223         CS_DBLCLKS,
224         nsembed_proc,
225         0, 0, NULL, NULL, NULL, NULL, NULL,
226         wszNsContainer,
227         NULL,
228     };
229     wndclass.hInstance = hInst;
230     nscontainer_class = RegisterClassExW(&wndclass);
231 }
232
233 static BOOL install_wine_gecko(BOOL silent)
234 {
235     PROCESS_INFORMATION pi;
236     STARTUPINFOW si;
237     WCHAR app[MAX_PATH];
238     WCHAR *args;
239     LONG len;
240     BOOL ret;
241
242     static const WCHAR controlW[] = {'\\','c','o','n','t','r','o','l','.','e','x','e',0};
243     static const WCHAR argsW[] =
244         {' ','a','p','p','w','i','z','.','c','p','l',' ','i','n','s','t','a','l','l','_','g','e','c','k','o',0};
245
246     len = GetSystemDirectoryW(app, MAX_PATH-sizeof(controlW)/sizeof(WCHAR));
247     memcpy(app+len, controlW, sizeof(controlW));
248
249     args = heap_alloc(len*sizeof(WCHAR) + sizeof(controlW) + sizeof(argsW));
250     if(!args)
251         return FALSE;
252
253     memcpy(args, app, len*sizeof(WCHAR) + sizeof(controlW));
254     memcpy(args + len + sizeof(controlW)/sizeof(WCHAR)-1, argsW, sizeof(argsW));
255
256     TRACE("starting %s\n", debugstr_w(args));
257
258     memset(&si, 0, sizeof(si));
259     si.cb = sizeof(si);
260     ret = CreateProcessW(app, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
261     heap_free(args);
262     if (ret) {
263         CloseHandle(pi.hThread);
264         WaitForSingleObject(pi.hProcess, INFINITE);
265         CloseHandle(pi.hProcess);
266     }
267
268     return ret;
269 }
270
271 static void set_environment(LPCWSTR gre_path)
272 {
273     WCHAR path_env[MAX_PATH], buf[20];
274     int len, debug_level = 0;
275
276     static const WCHAR pathW[] = {'P','A','T','H',0};
277     static const WCHAR warnW[] = {'w','a','r','n',0};
278     static const WCHAR xpcom_debug_breakW[] =
279         {'X','P','C','O','M','_','D','E','B','U','G','_','B','R','E','A','K',0};
280     static const WCHAR nspr_log_modulesW[] =
281         {'N','S','P','R','_','L','O','G','_','M','O','D','U','L','E','S',0};
282     static const WCHAR debug_formatW[] = {'a','l','l',':','%','d',0};
283     static const WCHAR moz_plugin_pathW[] = {'M','O','Z','_','P','L','U','G','I','N','_','P','A','T','H',0};
284     static const WCHAR gecko_pluginW[] = {'\\','g','e','c','k','o','\\','p','l','u','g','i','n',0};
285
286     /* We have to modify PATH as XPCOM loads other DLLs from this directory. */
287     GetEnvironmentVariableW(pathW, path_env, sizeof(path_env)/sizeof(WCHAR));
288     len = strlenW(path_env);
289     path_env[len++] = ';';
290     strcpyW(path_env+len, gre_path);
291     SetEnvironmentVariableW(pathW, path_env);
292
293     SetEnvironmentVariableW(xpcom_debug_breakW, warnW);
294
295     if(TRACE_ON(gecko))
296         debug_level = 5;
297     else if(WARN_ON(gecko))
298         debug_level = 3;
299     else if(ERR_ON(gecko))
300         debug_level = 2;
301
302     sprintfW(buf, debug_formatW, debug_level);
303     SetEnvironmentVariableW(nspr_log_modulesW, buf);
304
305     len = GetSystemDirectoryW(path_env, (sizeof(path_env)-sizeof(gecko_pluginW))/sizeof(WCHAR)+1);
306     if(len) {
307         strcpyW(path_env+len, gecko_pluginW);
308         SetEnvironmentVariableW(moz_plugin_pathW, path_env);
309     }
310 }
311
312 static BOOL load_xpcom(const PRUnichar *gre_path)
313 {
314     static const WCHAR strXPCOM[] = {'x','p','c','o','m','.','d','l','l',0};
315
316     TRACE("(%s)\n", debugstr_w(gre_path));
317
318     set_environment(gre_path);
319
320     hXPCOM = LoadLibraryW(strXPCOM);
321     if(!hXPCOM) {
322         WARN("Could not load XPCOM: %d\n", GetLastError());
323         return FALSE;
324     }
325
326 #define NS_DLSYM(func) \
327     func = (void *)GetProcAddress(hXPCOM, #func); \
328     if(!func) \
329         ERR("Could not GetProcAddress(" #func ") failed\n")
330
331     NS_DLSYM(NS_InitXPCOM2);
332     NS_DLSYM(NS_ShutdownXPCOM);
333     NS_DLSYM(NS_GetComponentRegistrar);
334     NS_DLSYM(NS_StringContainerInit2);
335     NS_DLSYM(NS_CStringContainerInit2);
336     NS_DLSYM(NS_StringContainerFinish);
337     NS_DLSYM(NS_CStringContainerFinish);
338     NS_DLSYM(NS_StringSetData);
339     NS_DLSYM(NS_CStringSetData);
340     NS_DLSYM(NS_NewLocalFile);
341     NS_DLSYM(NS_StringGetData);
342     NS_DLSYM(NS_CStringGetData);
343
344 #undef NS_DLSYM
345
346     return TRUE;
347 }
348
349 static BOOL check_version(LPCWSTR gre_path, const char *version_string)
350 {
351     WCHAR file_name[MAX_PATH];
352     char version[128];
353     DWORD read=0;
354     HANDLE hfile;
355
356     static const WCHAR wszVersion[] = {'\\','V','E','R','S','I','O','N',0};
357
358     strcpyW(file_name, gre_path);
359     strcatW(file_name, wszVersion);
360
361     hfile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
362                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
363     if(hfile == INVALID_HANDLE_VALUE) {
364         ERR("Could not open VERSION file\n");
365         return FALSE;
366     }
367
368     ReadFile(hfile, version, sizeof(version), &read, NULL);
369     version[read] = 0;
370     CloseHandle(hfile);
371
372     TRACE("%s\n", debugstr_a(version));
373
374     if(strcmp(version, version_string)) {
375         ERR("Unexpected version %s, expected %s\n", debugstr_a(version),
376             debugstr_a(version_string));
377         return FALSE;
378     }
379
380     return TRUE;
381 }
382
383 static BOOL load_wine_gecko_v(PRUnichar *gre_path, HKEY mshtml_key,
384         const char *version, const char *version_string)
385 {
386     DWORD res, type, size = MAX_PATH;
387     HKEY hkey = mshtml_key;
388
389     static const WCHAR wszGeckoPath[] =
390         {'G','e','c','k','o','P','a','t','h',0};
391
392     if(version) {
393         /* @@ Wine registry key: HKCU\Software\Wine\MSHTML\<version> */
394         res = RegOpenKeyA(mshtml_key, version, &hkey);
395         if(res != ERROR_SUCCESS)
396             return FALSE;
397     }
398
399     res = RegQueryValueExW(hkey, wszGeckoPath, NULL, &type, (LPBYTE)gre_path, &size);
400     if(hkey != mshtml_key)
401         RegCloseKey(hkey);
402     if(res != ERROR_SUCCESS || type != REG_SZ)
403         return FALSE;
404
405     if(!check_version(gre_path, version_string))
406         return FALSE;
407
408     return load_xpcom(gre_path);
409 }
410
411 static BOOL load_wine_gecko(PRUnichar *gre_path)
412 {
413     HKEY hkey;
414     DWORD res;
415     BOOL ret;
416
417     static const WCHAR wszMshtmlKey[] = {
418         'S','o','f','t','w','a','r','e','\\','W','i','n','e',
419         '\\','M','S','H','T','M','L',0};
420
421     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
422     res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey);
423     if(res != ERROR_SUCCESS)
424         return FALSE;
425
426     ret = load_wine_gecko_v(gre_path, hkey, GECKO_VERSION, GECKO_VERSION_STRING);
427
428     RegCloseKey(hkey);
429     return ret;
430 }
431
432 static void set_bool_pref(nsIPrefBranch *pref, const char *pref_name, BOOL val)
433 {
434     nsresult nsres;
435
436     nsres = nsIPrefBranch_SetBoolPref(pref, pref_name, val);
437     if(NS_FAILED(nsres))
438         ERR("Could not set pref %s\n", debugstr_a(pref_name));
439 }
440
441 static void set_int_pref(nsIPrefBranch *pref, const char *pref_name, int val)
442 {
443     nsresult nsres;
444
445     nsres = nsIPrefBranch_SetIntPref(pref, pref_name, val);
446     if(NS_FAILED(nsres))
447         ERR("Could not set pref %s\n", debugstr_a(pref_name));
448 }
449
450 static void set_string_pref(nsIPrefBranch *pref, const char *pref_name, const char *val)
451 {
452     nsresult nsres;
453
454     nsres = nsIPrefBranch_SetCharPref(pref, pref_name, val);
455     if(NS_FAILED(nsres))
456         ERR("Could not set pref %s\n", debugstr_a(pref_name));
457 }
458
459 static void set_lang(nsIPrefBranch *pref)
460 {
461     char langs[100];
462     DWORD res, size, type;
463     HKEY hkey;
464
465     static const WCHAR international_keyW[] =
466         {'S','o','f','t','w','a','r','e',
467          '\\','M','i','c','r','o','s','o','f','t',
468          '\\','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',
469          '\\','I','n','t','e','r','n','a','t','i','o','n','a','l',0};
470
471     res = RegOpenKeyW(HKEY_CURRENT_USER, international_keyW, &hkey);
472     if(res != ERROR_SUCCESS)
473         return;
474
475     size = sizeof(langs);
476     res = RegQueryValueExA(hkey, "AcceptLanguage", 0, &type, (LPBYTE)langs, &size);
477     RegCloseKey(hkey);
478     if(res != ERROR_SUCCESS || type != REG_SZ)
479         return;
480
481     TRACE("Setting lang %s\n", debugstr_a(langs));
482
483     set_string_pref(pref, "intl.accept_languages", langs);
484 }
485
486 static void set_proxy(nsIPrefBranch *pref)
487 {
488     char proxy[512];
489     char * proxy_port;
490     int proxy_port_num;
491     DWORD enabled = 0, res, size, type;
492     HKEY hkey;
493
494     static const WCHAR proxy_keyW[] =
495         {'S','o','f','t','w','a','r','e',
496          '\\','M','i','c','r','o','s','o','f','t',
497          '\\','W','i','n','d','o','w','s',
498          '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',
499          '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
500
501     res = RegOpenKeyW(HKEY_CURRENT_USER, proxy_keyW, &hkey);
502     if(res != ERROR_SUCCESS)
503         return;
504
505     size = sizeof(enabled);
506     res = RegQueryValueExA(hkey, "ProxyEnable", 0, &type, (LPBYTE)&enabled, &size);
507     if(res != ERROR_SUCCESS || type != REG_DWORD || enabled == 0)
508     {
509         RegCloseKey(hkey);
510         return;
511     }
512
513     size = sizeof(proxy);
514     res = RegQueryValueExA(hkey, "ProxyServer", 0, &type, (LPBYTE)proxy, &size);
515     RegCloseKey(hkey);
516     if(res != ERROR_SUCCESS || type != REG_SZ)
517         return;
518
519     proxy_port = strchr(proxy, ':');
520     if (!proxy_port)
521         return;
522
523     *proxy_port = 0;
524     proxy_port_num = atoi(proxy_port + 1);
525     TRACE("Setting proxy to %s, port %d\n", debugstr_a(proxy), proxy_port_num);
526
527     set_string_pref(pref, "network.proxy.http", proxy);
528     set_string_pref(pref, "network.proxy.ssl", proxy);
529
530     set_int_pref(pref, "network.proxy.type", 1);
531     set_int_pref(pref, "network.proxy.http_port", proxy_port_num);
532     set_int_pref(pref, "network.proxy.ssl_port", proxy_port_num);
533 }
534
535 static void set_preferences(void)
536 {
537     nsIPrefBranch *pref;
538     nsresult nsres;
539
540     nsres = nsIServiceManager_GetServiceByContractID(pServMgr, NS_PREFERENCES_CONTRACTID,
541             &IID_nsIPrefBranch, (void**)&pref);
542     if(NS_FAILED(nsres)) {
543         ERR("Could not get preference service: %08x\n", nsres);
544         return;
545     }
546
547     set_lang(pref);
548     set_proxy(pref);
549     set_bool_pref(pref, "security.warn_entering_secure", FALSE);
550     set_bool_pref(pref, "security.warn_submit_insecure", FALSE);
551     set_int_pref(pref, "layout.spellcheckDefault", 0);
552
553     nsIPrefBranch_Release(pref);
554 }
555
556 static BOOL init_xpcom(const PRUnichar *gre_path)
557 {
558     nsresult nsres;
559     nsIObserver *pStartNotif;
560     nsIComponentRegistrar *registrar = NULL;
561     nsAString path;
562     nsIFile *gre_dir;
563     WCHAR *ptr;
564
565     nsAString_InitDepend(&path, gre_path);
566     nsres = NS_NewLocalFile(&path, FALSE, &gre_dir);
567     nsAString_Finish(&path);
568     if(NS_FAILED(nsres)) {
569         ERR("NS_NewLocalFile failed: %08x\n", nsres);
570         FreeLibrary(hXPCOM);
571         return FALSE;
572     }
573
574     nsres = NS_InitXPCOM2(&pServMgr, gre_dir, &nsDirectoryServiceProvider);
575     if(NS_FAILED(nsres)) {
576         ERR("NS_InitXPCOM2 failed: %08x\n", nsres);
577         FreeLibrary(hXPCOM);
578         return FALSE;
579     }
580
581     strcpyW(gecko_path, gre_path);
582     for(ptr = gecko_path; *ptr; ptr++) {
583         if(*ptr == '\\')
584             *ptr = '/';
585     }
586     gecko_path_len = ptr-gecko_path;
587
588     nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr);
589     if(NS_FAILED(nsres))
590         ERR("Could not get nsIComponentManager: %08x\n", nsres);
591
592     nsres = NS_GetComponentRegistrar(&registrar);
593     if(NS_SUCCEEDED(nsres))
594         init_nsio(pCompMgr, registrar);
595     else
596         ERR("NS_GetComponentRegistrar failed: %08x\n", nsres);
597
598     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_APPSTARTUPNOTIFIER_CONTRACTID,
599             NULL, &IID_nsIObserver, (void**)&pStartNotif);
600     if(NS_SUCCEEDED(nsres)) {
601         nsres = nsIObserver_Observe(pStartNotif, NULL, APPSTARTUP_TOPIC, NULL);
602         if(NS_FAILED(nsres))
603             ERR("Observe failed: %08x\n", nsres);
604
605         nsIObserver_Release(pStartNotif);
606     }else {
607         ERR("could not get appstartup-notifier: %08x\n", nsres);
608     }
609
610     set_preferences();
611
612     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_MEMORY_CONTRACTID,
613             NULL, &IID_nsIMemory, (void**)&nsmem);
614     if(NS_FAILED(nsres))
615         ERR("Could not get nsIMemory: %08x\n", nsres);
616
617     if(registrar) {
618         register_nsservice(registrar, pServMgr);
619         nsIComponentRegistrar_Release(registrar);
620     }
621
622     return TRUE;
623 }
624
625 static CRITICAL_SECTION cs_load_gecko;
626 static CRITICAL_SECTION_DEBUG cs_load_gecko_dbg =
627 {
628     0, 0, &cs_load_gecko,
629     { &cs_load_gecko_dbg.ProcessLocksList, &cs_load_gecko_dbg.ProcessLocksList },
630       0, 0, { (DWORD_PTR)(__FILE__ ": load_gecko") }
631 };
632 static CRITICAL_SECTION cs_load_gecko = { &cs_load_gecko_dbg, -1, 0, 0, 0, 0 };
633
634 BOOL load_gecko(BOOL silent)
635 {
636     PRUnichar gre_path[MAX_PATH];
637     BOOL ret = FALSE;
638
639     static DWORD loading_thread;
640
641     TRACE("()\n");
642
643     /* load_gecko may be called recursively */
644     if(loading_thread == GetCurrentThreadId())
645         return pCompMgr != NULL;
646
647     EnterCriticalSection(&cs_load_gecko);
648
649     if(!loading_thread) {
650         loading_thread = GetCurrentThreadId();
651
652         if(load_wine_gecko(gre_path)
653            || (install_wine_gecko(silent) && load_wine_gecko(gre_path)))
654             ret = init_xpcom(gre_path);
655         else
656            MESSAGE("Could not load wine-gecko. HTML rendering will be disabled.\n");
657     }else {
658         ret = pCompMgr != NULL;
659     }
660
661     LeaveCriticalSection(&cs_load_gecko);
662
663     return ret;
664 }
665
666 void *nsalloc(size_t size)
667 {
668     return nsIMemory_Alloc(nsmem, size);
669 }
670
671 void nsfree(void *mem)
672 {
673     nsIMemory_Free(nsmem, mem);
674 }
675
676 static BOOL nsACString_Init(nsACString *str, const char *data)
677 {
678     return NS_SUCCEEDED(NS_CStringContainerInit2(str, data, PR_UINT32_MAX, 0));
679 }
680
681 /*
682  * Initializes nsACString with data owned by caller.
683  * Caller must ensure that data is valid during lifetime of string object.
684  */
685 void nsACString_InitDepend(nsACString *str, const char *data)
686 {
687     NS_CStringContainerInit2(str, data, PR_UINT32_MAX, NS_CSTRING_CONTAINER_INIT_DEPEND);
688 }
689
690 void nsACString_SetData(nsACString *str, const char *data)
691 {
692     NS_CStringSetData(str, data, PR_UINT32_MAX);
693 }
694
695 PRUint32 nsACString_GetData(const nsACString *str, const char **data)
696 {
697     return NS_CStringGetData(str, data, NULL);
698 }
699
700 void nsACString_Finish(nsACString *str)
701 {
702     NS_CStringContainerFinish(str);
703 }
704
705 BOOL nsAString_Init(nsAString *str, const PRUnichar *data)
706 {
707     return NS_SUCCEEDED(NS_StringContainerInit2(str, data, PR_UINT32_MAX, 0));
708 }
709
710 /*
711  * Initializes nsAString with data owned by caller.
712  * Caller must ensure that data is valid during lifetime of string object.
713  */
714 void nsAString_InitDepend(nsAString *str, const PRUnichar *data)
715 {
716     NS_StringContainerInit2(str, data, PR_UINT32_MAX, NS_STRING_CONTAINER_INIT_DEPEND);
717 }
718
719 void nsAString_SetData(nsAString *str, const PRUnichar *data)
720 {
721     NS_StringSetData(str, data, PR_UINT32_MAX);
722 }
723
724 PRUint32 nsAString_GetData(const nsAString *str, const PRUnichar **data)
725 {
726     return NS_StringGetData(str, data, NULL);
727 }
728
729 void nsAString_Finish(nsAString *str)
730 {
731     NS_StringContainerFinish(str);
732 }
733
734 HRESULT return_nsstr(nsresult nsres, nsAString *nsstr, BSTR *p)
735 {
736     const PRUnichar *str;
737
738     if(NS_FAILED(nsres)) {
739         ERR("failed: %08x\n", nsres);
740         nsAString_Finish(nsstr);
741         return E_FAIL;
742     }
743
744     nsAString_GetData(nsstr, &str);
745     TRACE("ret %s\n", debugstr_w(str));
746     if(*str) {
747         *p = SysAllocString(str);
748         if(!*p)
749             return E_OUTOFMEMORY;
750     }else {
751         *p = NULL;
752     }
753
754     nsAString_Finish(nsstr);
755     return S_OK;
756 }
757
758 nsICommandParams *create_nscommand_params(void)
759 {
760     nsICommandParams *ret = NULL;
761     nsresult nsres;
762
763     if(!pCompMgr)
764         return NULL;
765
766     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
767             NS_COMMANDPARAMS_CONTRACTID, NULL, &IID_nsICommandParams,
768             (void**)&ret);
769     if(NS_FAILED(nsres))
770         ERR("Could not get nsICommandParams\n");
771
772     return ret;
773 }
774
775 nsresult get_nsinterface(nsISupports *iface, REFIID riid, void **ppv)
776 {
777     nsIInterfaceRequestor *iface_req;
778     nsresult nsres;
779
780     nsres = nsISupports_QueryInterface(iface, &IID_nsIInterfaceRequestor, (void**)&iface_req);
781     if(NS_FAILED(nsres))
782         return nsres;
783
784     nsres = nsIInterfaceRequestor_GetInterface(iface_req, riid, ppv);
785     nsIInterfaceRequestor_Release(iface_req);
786
787     return nsres;
788 }
789
790 static HRESULT nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str)
791 {
792     nsIDOMNodeList *node_list = NULL;
793     PRBool has_children = FALSE;
794     nsIContent *nscontent;
795     PRUint16 type;
796     nsresult nsres;
797
798     nsIDOMNode_HasChildNodes(nsnode, &has_children);
799
800     nsres = nsIDOMNode_GetNodeType(nsnode, &type);
801     if(NS_FAILED(nsres)) {
802         ERR("GetType failed: %08x\n", nsres);
803         return E_FAIL;
804     }
805
806     nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIContent, (void**)&nscontent);
807     if(NS_FAILED(nsres)) {
808         ERR("Could not get nsIDontent interface: %08x\n", nsres);
809         return E_FAIL;
810     }
811
812     switch(type) {
813     case ELEMENT_NODE:
814         nsIContentSerializer_AppendElementStart(serializer, nscontent, nscontent, str);
815         break;
816     case TEXT_NODE:
817         nsIContentSerializer_AppendText(serializer, nscontent, 0, -1, str);
818         break;
819     case COMMENT_NODE:
820         nsres = nsIContentSerializer_AppendComment(serializer, nscontent, 0, -1, str);
821         break;
822     case DOCUMENT_NODE: {
823         nsIDocument *nsdoc;
824         nsIDOMNode_QueryInterface(nsnode, &IID_nsIDocument, (void**)&nsdoc);
825         nsIContentSerializer_AppendDocumentStart(serializer, nsdoc, str);
826         nsIDocument_Release(nsdoc);
827         break;
828     }
829     case DOCUMENT_TYPE_NODE:
830         WARN("Ignoring DOCUMENT_TYPE_NODE\n");
831         break;
832     case DOCUMENT_FRAGMENT_NODE:
833         break;
834     default:
835         FIXME("Unhandled type %u\n", type);
836     }
837
838     if(has_children) {
839         PRUint32 child_cnt, i;
840         nsIDOMNode *child_node;
841
842         nsIDOMNode_GetChildNodes(nsnode, &node_list);
843         nsIDOMNodeList_GetLength(node_list, &child_cnt);
844
845         for(i=0; i<child_cnt; i++) {
846             nsres = nsIDOMNodeList_Item(node_list, i, &child_node);
847             if(NS_SUCCEEDED(nsres)) {
848                 nsnode_to_nsstring_rec(serializer, child_node, str);
849                 nsIDOMNode_Release(child_node);
850             }else {
851                 ERR("Item failed: %08x\n", nsres);
852             }
853         }
854
855         nsIDOMNodeList_Release(node_list);
856     }
857
858     if(type == ELEMENT_NODE)
859         nsIContentSerializer_AppendElementEnd(serializer, nscontent, str);
860
861     nsIContent_Release(nscontent);
862     return S_OK;
863 }
864
865 HRESULT nsnode_to_nsstring(nsIDOMNode *nsnode, nsAString *str)
866 {
867     nsIContentSerializer *serializer;
868     nsresult nsres;
869     HRESULT hres;
870
871     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
872             NS_HTMLSERIALIZER_CONTRACTID, NULL, &IID_nsIContentSerializer,
873             (void**)&serializer);
874     if(NS_FAILED(nsres)) {
875         ERR("Could not get nsIContentSerializer: %08x\n", nsres);
876         return E_FAIL;
877     }
878
879     nsres = nsIContentSerializer_Init(serializer, 0, 100, NULL, FALSE, FALSE /* FIXME */);
880     if(NS_FAILED(nsres))
881         ERR("Init failed: %08x\n", nsres);
882
883     hres = nsnode_to_nsstring_rec(serializer, nsnode, str);
884     if(SUCCEEDED(hres)) {
885         nsres = nsIContentSerializer_Flush(serializer, str);
886         if(NS_FAILED(nsres))
887             ERR("Flush failed: %08x\n", nsres);
888     }
889
890     nsIContentSerializer_Release(serializer);
891     return hres;
892 }
893
894 void get_editor_controller(NSContainer *This)
895 {
896     nsIEditingSession *editing_session = NULL;
897     nsIControllerContext *ctrlctx;
898     nsresult nsres;
899
900     if(This->editor) {
901         nsIEditor_Release(This->editor);
902         This->editor = NULL;
903     }
904
905     if(This->editor_controller) {
906         nsIController_Release(This->editor_controller);
907         This->editor_controller = NULL;
908     }
909
910     nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession,
911             (void**)&editing_session);
912     if(NS_FAILED(nsres)) {
913         ERR("Could not get nsIEditingSession: %08x\n", nsres);
914         return;
915     }
916
917     nsres = nsIEditingSession_GetEditorForWindow(editing_session,
918             This->doc->basedoc.window->nswindow, &This->editor);
919     nsIEditingSession_Release(editing_session);
920     if(NS_FAILED(nsres)) {
921         ERR("Could not get editor: %08x\n", nsres);
922         return;
923     }
924
925     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
926             NS_EDITORCONTROLLER_CONTRACTID, NULL, &IID_nsIControllerContext, (void**)&ctrlctx);
927     if(NS_SUCCEEDED(nsres)) {
928         nsres = nsIControllerContext_SetCommandContext(ctrlctx, (nsISupports *)This->editor);
929         if(NS_FAILED(nsres))
930             ERR("SetCommandContext failed: %08x\n", nsres);
931         nsres = nsIControllerContext_QueryInterface(ctrlctx, &IID_nsIController,
932                 (void**)&This->editor_controller);
933         nsIControllerContext_Release(ctrlctx);
934         if(NS_FAILED(nsres))
935             ERR("Could not get nsIController interface: %08x\n", nsres);
936     }else {
937         ERR("Could not create edit controller: %08x\n", nsres);
938     }
939 }
940
941 void close_gecko(void)
942 {
943     TRACE("()\n");
944
945     release_nsio();
946
947     if(profile_directory) {
948         nsIFile_Release(profile_directory);
949         profile_directory = NULL;
950     }
951
952     if(pCompMgr)
953         nsIComponentManager_Release(pCompMgr);
954
955     if(pServMgr)
956         nsIServiceManager_Release(pServMgr);
957
958     if(nsmem)
959         nsIMemory_Release(nsmem);
960
961     /* Gecko doesn't really support being unloaded */
962     /* if (hXPCOM) FreeLibrary(hXPCOM); */
963 }
964
965 BOOL is_gecko_path(const char *path)
966 {
967     WCHAR *buf, *ptr;
968     BOOL ret;
969
970     buf = heap_strdupAtoW(path);
971     if(strlenW(buf) < gecko_path_len)
972         return FALSE;
973
974     buf[gecko_path_len] = 0;
975     for(ptr = buf; *ptr; ptr++) {
976         if(*ptr == '\\')
977             *ptr = '/';
978     }
979
980     ret = !strcmpiW(buf, gecko_path);
981     heap_free(buf);
982     return ret;
983 }
984
985 /**********************************************************
986  *      nsIWebBrowserChrome interface
987  */
988
989 static inline NSContainer *impl_from_nsIWebBrowserChrome(nsIWebBrowserChrome *iface)
990 {
991     return CONTAINING_RECORD(iface, NSContainer, nsIWebBrowserChrome_iface);
992 }
993
994 static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface,
995         nsIIDRef riid, void **result)
996 {
997     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
998
999     *result = NULL;
1000     if(IsEqualGUID(&IID_nsISupports, riid)) {
1001         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
1002         *result = &This->nsIWebBrowserChrome_iface;
1003     }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) {
1004         TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result);
1005         *result = &This->nsIWebBrowserChrome_iface;
1006     }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) {
1007         TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result);
1008         *result = &This->nsIContextMenuListener_iface;
1009     }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) {
1010         TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result);
1011         *result = &This->nsIURIContentListener_iface;
1012     }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) {
1013         TRACE("(%p)->(IID_nsIEmbeddingSiteWindow %p)\n", This, result);
1014         *result = &This->nsIEmbeddingSiteWindow_iface;
1015     }else if(IsEqualGUID(&IID_nsITooltipListener, riid)) {
1016         TRACE("(%p)->(IID_nsITooltipListener %p)\n", This, result);
1017         *result = &This->nsITooltipListener_iface;
1018     }else if(IsEqualGUID(&IID_nsIInterfaceRequestor, riid)) {
1019         TRACE("(%p)->(IID_nsIInterfaceRequestor %p)\n", This, result);
1020         *result = &This->nsIInterfaceRequestor_iface;
1021     }else if(IsEqualGUID(&IID_nsIWeakReference, riid)) {
1022         TRACE("(%p)->(IID_nsIWeakReference %p)\n", This, result);
1023         *result = &This->nsIWeakReference_iface;
1024     }else if(IsEqualGUID(&IID_nsISupportsWeakReference, riid)) {
1025         TRACE("(%p)->(IID_nsISupportsWeakReference %p)\n", This, result);
1026         *result = &This->nsISupportsWeakReference_iface;
1027     }
1028
1029     if(*result) {
1030         nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1031         return NS_OK;
1032     }
1033
1034     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
1035     return NS_NOINTERFACE;
1036 }
1037
1038 static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface)
1039 {
1040     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1041     LONG ref = InterlockedIncrement(&This->ref);
1042
1043     TRACE("(%p) ref=%d\n", This, ref);
1044
1045     return ref;
1046 }
1047
1048 static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface)
1049 {
1050     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1051     LONG ref = InterlockedDecrement(&This->ref);
1052
1053     TRACE("(%p) ref=%d\n", This, ref);
1054
1055     if(!ref) {
1056         if(This->parent)
1057             nsIWebBrowserChrome_Release(&This->parent->nsIWebBrowserChrome_iface);
1058         heap_free(This);
1059     }
1060
1061     return ref;
1062 }
1063
1064 static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface,
1065         PRUint32 statusType, const PRUnichar *status)
1066 {
1067     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1068     TRACE("(%p)->(%d %s)\n", This, statusType, debugstr_w(status));
1069     return NS_OK;
1070 }
1071
1072 static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface,
1073         nsIWebBrowser **aWebBrowser)
1074 {
1075     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1076
1077     TRACE("(%p)->(%p)\n", This, aWebBrowser);
1078
1079     if(!aWebBrowser)
1080         return NS_ERROR_INVALID_ARG;
1081
1082     if(This->webbrowser)
1083         nsIWebBrowser_AddRef(This->webbrowser);
1084     *aWebBrowser = This->webbrowser;
1085     return S_OK;
1086 }
1087
1088 static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface,
1089         nsIWebBrowser *aWebBrowser)
1090 {
1091     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1092
1093     TRACE("(%p)->(%p)\n", This, aWebBrowser);
1094
1095     if(aWebBrowser != This->webbrowser)
1096         ERR("Wrong nsWebBrowser!\n");
1097
1098     return NS_OK;
1099 }
1100
1101 static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface,
1102         PRUint32 *aChromeFlags)
1103 {
1104     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1105     WARN("(%p)->(%p)\n", This, aChromeFlags);
1106     return NS_ERROR_NOT_IMPLEMENTED;
1107 }
1108
1109 static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface,
1110         PRUint32 aChromeFlags)
1111 {
1112     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1113     WARN("(%p)->(%08x)\n", This, aChromeFlags);
1114     return NS_ERROR_NOT_IMPLEMENTED;
1115 }
1116
1117 static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface)
1118 {
1119     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1120     TRACE("(%p)\n", This);
1121     return NS_ERROR_NOT_IMPLEMENTED;
1122 }
1123
1124 static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface,
1125         PRInt32 aCX, PRInt32 aCY)
1126 {
1127     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1128     WARN("(%p)->(%d %d)\n", This, aCX, aCY);
1129     return NS_ERROR_NOT_IMPLEMENTED;
1130 }
1131
1132 static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface)
1133 {
1134     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1135     WARN("(%p)\n", This);
1136     return NS_ERROR_NOT_IMPLEMENTED;
1137 }
1138
1139 static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, PRBool *_retval)
1140 {
1141     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1142     WARN("(%p)->(%p)\n", This, _retval);
1143     return NS_ERROR_NOT_IMPLEMENTED;
1144 }
1145
1146 static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface,
1147         nsresult aStatus)
1148 {
1149     NSContainer *This = impl_from_nsIWebBrowserChrome(iface);
1150     WARN("(%p)->(%08x)\n", This, aStatus);
1151     return NS_ERROR_NOT_IMPLEMENTED;
1152 }
1153
1154 static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = {
1155     nsWebBrowserChrome_QueryInterface,
1156     nsWebBrowserChrome_AddRef,
1157     nsWebBrowserChrome_Release,
1158     nsWebBrowserChrome_SetStatus,
1159     nsWebBrowserChrome_GetWebBrowser,
1160     nsWebBrowserChrome_SetWebBrowser,
1161     nsWebBrowserChrome_GetChromeFlags,
1162     nsWebBrowserChrome_SetChromeFlags,
1163     nsWebBrowserChrome_DestroyBrowserWindow,
1164     nsWebBrowserChrome_SizeBrowserTo,
1165     nsWebBrowserChrome_ShowAsModal,
1166     nsWebBrowserChrome_IsWindowModal,
1167     nsWebBrowserChrome_ExitModalEventLoop
1168 };
1169
1170 /**********************************************************
1171  *      nsIContextMenuListener interface
1172  */
1173
1174 static inline NSContainer *impl_from_nsIContextMenuListener(nsIContextMenuListener *iface)
1175 {
1176     return CONTAINING_RECORD(iface, NSContainer, nsIContextMenuListener_iface);
1177 }
1178
1179 static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface,
1180         nsIIDRef riid, void **result)
1181 {
1182     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1183     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1184 }
1185
1186 static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface)
1187 {
1188     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1189     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1190 }
1191
1192 static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface)
1193 {
1194     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1195     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1196 }
1197
1198 static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface,
1199         PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
1200 {
1201     NSContainer *This = impl_from_nsIContextMenuListener(iface);
1202     nsIDOMMouseEvent *event;
1203     HTMLDOMNode *node;
1204     POINT pt;
1205     DWORD dwID = CONTEXT_MENU_DEFAULT;
1206     nsresult nsres;
1207     HRESULT hres;
1208
1209     TRACE("(%p)->(%08x %p %p)\n", This, aContextFlags, aEvent, aNode);
1210
1211     fire_event(This->doc->basedoc.doc_node /* FIXME */, EVENTID_CONTEXTMENU, TRUE, aNode, aEvent);
1212
1213     nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event);
1214     if(NS_FAILED(nsres)) {
1215         ERR("Could not get nsIDOMMouseEvent interface: %08x\n", nsres);
1216         return nsres;
1217     }
1218
1219     nsIDOMMouseEvent_GetScreenX(event, &pt.x);
1220     nsIDOMMouseEvent_GetScreenY(event, &pt.y);
1221     nsIDOMMouseEvent_Release(event);
1222
1223     switch(aContextFlags) {
1224     case CONTEXT_NONE:
1225     case CONTEXT_DOCUMENT:
1226     case CONTEXT_TEXT:
1227         dwID = CONTEXT_MENU_DEFAULT;
1228         break;
1229     case CONTEXT_IMAGE:
1230     case CONTEXT_IMAGE|CONTEXT_LINK:
1231         dwID = CONTEXT_MENU_IMAGE;
1232         break;
1233     case CONTEXT_LINK:
1234         dwID = CONTEXT_MENU_ANCHOR;
1235         break;
1236     case CONTEXT_INPUT:
1237         dwID = CONTEXT_MENU_CONTROL;
1238         break;
1239     default:
1240         FIXME("aContextFlags=%08x\n", aContextFlags);
1241     };
1242
1243     hres = get_node(This->doc->basedoc.doc_node, aNode, TRUE, &node);
1244     if(FAILED(hres))
1245         return NS_ERROR_FAILURE;
1246
1247     show_context_menu(This->doc, dwID, &pt, (IDispatch*)&node->IHTMLDOMNode_iface);
1248     return NS_OK;
1249 }
1250
1251 static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = {
1252     nsContextMenuListener_QueryInterface,
1253     nsContextMenuListener_AddRef,
1254     nsContextMenuListener_Release,
1255     nsContextMenuListener_OnShowContextMenu
1256 };
1257
1258 /**********************************************************
1259  *      nsIURIContentListener interface
1260  */
1261
1262 static inline NSContainer *impl_from_nsIURIContentListener(nsIURIContentListener *iface)
1263 {
1264     return CONTAINING_RECORD(iface, NSContainer, nsIURIContentListener_iface);
1265 }
1266
1267 static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface,
1268         nsIIDRef riid, void **result)
1269 {
1270     NSContainer *This = impl_from_nsIURIContentListener(iface);
1271     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1272 }
1273
1274 static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface)
1275 {
1276     NSContainer *This = impl_from_nsIURIContentListener(iface);
1277     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1278 }
1279
1280 static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
1281 {
1282     NSContainer *This = impl_from_nsIURIContentListener(iface);
1283     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1284 }
1285
1286 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
1287                                                           nsIURI *aURI, PRBool *_retval)
1288 {
1289     NSContainer *This = impl_from_nsIURIContentListener(iface);
1290     nsACString spec_str;
1291     const char *spec;
1292     nsresult nsres;
1293
1294     nsACString_Init(&spec_str, NULL);
1295     nsIURI_GetSpec(aURI, &spec_str);
1296     nsACString_GetData(&spec_str, &spec);
1297
1298     TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval);
1299
1300     nsACString_Finish(&spec_str);
1301
1302     nsres = on_start_uri_open(This, aURI, _retval);
1303     if(NS_FAILED(nsres))
1304         return nsres;
1305
1306     return !*_retval && This->content_listener
1307         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
1308         : NS_OK;
1309 }
1310
1311 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
1312         const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest,
1313         nsIStreamListener **aContentHandler, PRBool *_retval)
1314 {
1315     NSContainer *This = impl_from_nsIURIContentListener(iface);
1316
1317     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1318             aRequest, aContentHandler, _retval);
1319
1320     return This->content_listener
1321         ? nsIURIContentListener_DoContent(This->content_listener, aContentType,
1322                   aIsContentPreferred, aRequest, aContentHandler, _retval)
1323         : NS_ERROR_NOT_IMPLEMENTED;
1324 }
1325
1326 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
1327         const char *aContentType, char **aDesiredContentType, PRBool *_retval)
1328 {
1329     NSContainer *This = impl_from_nsIURIContentListener(iface);
1330
1331     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
1332
1333     /* FIXME: Should we do something here? */
1334     *_retval = TRUE; 
1335
1336     return This->content_listener
1337         ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType,
1338                   aDesiredContentType, _retval)
1339         : NS_OK;
1340 }
1341
1342 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
1343         const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType,
1344         PRBool *_retval)
1345 {
1346     NSContainer *This = impl_from_nsIURIContentListener(iface);
1347
1348     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1349             aDesiredContentType, _retval);
1350
1351     return This->content_listener
1352         ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType,
1353                 aIsContentPreferred, aDesiredContentType, _retval)
1354         : NS_ERROR_NOT_IMPLEMENTED;
1355 }
1356
1357 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
1358         nsISupports **aLoadCookie)
1359 {
1360     NSContainer *This = impl_from_nsIURIContentListener(iface);
1361
1362     WARN("(%p)->(%p)\n", This, aLoadCookie);
1363
1364     return This->content_listener
1365         ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie)
1366         : NS_ERROR_NOT_IMPLEMENTED;
1367 }
1368
1369 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
1370         nsISupports *aLoadCookie)
1371 {
1372     NSContainer *This = impl_from_nsIURIContentListener(iface);
1373
1374     WARN("(%p)->(%p)\n", This, aLoadCookie);
1375
1376     return This->content_listener
1377         ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie)
1378         : NS_ERROR_NOT_IMPLEMENTED;
1379 }
1380
1381 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
1382         nsIURIContentListener **aParentContentListener)
1383 {
1384     NSContainer *This = impl_from_nsIURIContentListener(iface);
1385
1386     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1387
1388     if(This->content_listener)
1389         nsIURIContentListener_AddRef(This->content_listener);
1390
1391     *aParentContentListener = This->content_listener;
1392     return NS_OK;
1393 }
1394
1395 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
1396         nsIURIContentListener *aParentContentListener)
1397 {
1398     NSContainer *This = impl_from_nsIURIContentListener(iface);
1399
1400     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1401
1402     if(aParentContentListener == &This->nsIURIContentListener_iface)
1403         return NS_OK;
1404
1405     if(This->content_listener)
1406         nsIURIContentListener_Release(This->content_listener);
1407
1408     This->content_listener = aParentContentListener;
1409     if(This->content_listener)
1410         nsIURIContentListener_AddRef(This->content_listener);
1411
1412     return NS_OK;
1413 }
1414
1415 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
1416     nsURIContentListener_QueryInterface,
1417     nsURIContentListener_AddRef,
1418     nsURIContentListener_Release,
1419     nsURIContentListener_OnStartURIOpen,
1420     nsURIContentListener_DoContent,
1421     nsURIContentListener_IsPreferred,
1422     nsURIContentListener_CanHandleContent,
1423     nsURIContentListener_GetLoadCookie,
1424     nsURIContentListener_SetLoadCookie,
1425     nsURIContentListener_GetParentContentListener,
1426     nsURIContentListener_SetParentContentListener
1427 };
1428
1429 /**********************************************************
1430  *      nsIEmbeddinSiteWindow interface
1431  */
1432
1433 static inline NSContainer *impl_from_nsIEmbeddingSiteWindow(nsIEmbeddingSiteWindow *iface)
1434 {
1435     return CONTAINING_RECORD(iface, NSContainer, nsIEmbeddingSiteWindow_iface);
1436 }
1437
1438 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
1439         nsIIDRef riid, void **result)
1440 {
1441     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1442     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1443 }
1444
1445 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
1446 {
1447     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1448     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1449 }
1450
1451 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
1452 {
1453     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1454     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1455 }
1456
1457 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
1458         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
1459 {
1460     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1461     WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy);
1462     return NS_ERROR_NOT_IMPLEMENTED;
1463 }
1464
1465 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
1466         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
1467 {
1468     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1469     WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy);
1470     return NS_ERROR_NOT_IMPLEMENTED;
1471 }
1472
1473 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
1474 {
1475     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1476
1477     TRACE("(%p)\n", This);
1478
1479     return nsIBaseWindow_SetFocus(This->window);
1480 }
1481
1482 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
1483         PRBool *aVisibility)
1484 {
1485     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1486
1487     TRACE("(%p)->(%p)\n", This, aVisibility);
1488
1489     *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd);
1490     return NS_OK;
1491 }
1492
1493 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
1494         PRBool aVisibility)
1495 {
1496     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1497
1498     TRACE("(%p)->(%x)\n", This, aVisibility);
1499
1500     return NS_OK;
1501 }
1502
1503 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
1504         PRUnichar **aTitle)
1505 {
1506     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1507     WARN("(%p)->(%p)\n", This, aTitle);
1508     return NS_ERROR_NOT_IMPLEMENTED;
1509 }
1510
1511 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
1512         const PRUnichar *aTitle)
1513 {
1514     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1515     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
1516     return NS_ERROR_NOT_IMPLEMENTED;
1517 }
1518
1519 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
1520         void **aSiteWindow)
1521 {
1522     NSContainer *This = impl_from_nsIEmbeddingSiteWindow(iface);
1523
1524     TRACE("(%p)->(%p)\n", This, aSiteWindow);
1525
1526     *aSiteWindow = This->hwnd;
1527     return NS_OK;
1528 }
1529
1530 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
1531     nsEmbeddingSiteWindow_QueryInterface,
1532     nsEmbeddingSiteWindow_AddRef,
1533     nsEmbeddingSiteWindow_Release,
1534     nsEmbeddingSiteWindow_SetDimensions,
1535     nsEmbeddingSiteWindow_GetDimensions,
1536     nsEmbeddingSiteWindow_SetFocus,
1537     nsEmbeddingSiteWindow_GetVisibility,
1538     nsEmbeddingSiteWindow_SetVisibility,
1539     nsEmbeddingSiteWindow_GetTitle,
1540     nsEmbeddingSiteWindow_SetTitle,
1541     nsEmbeddingSiteWindow_GetSiteWindow
1542 };
1543
1544 static inline NSContainer *impl_from_nsITooltipListener(nsITooltipListener *iface)
1545 {
1546     return CONTAINING_RECORD(iface, NSContainer, nsITooltipListener_iface);
1547 }
1548
1549 static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid,
1550         void **result)
1551 {
1552     NSContainer *This = impl_from_nsITooltipListener(iface);
1553     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1554 }
1555
1556 static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface)
1557 {
1558     NSContainer *This = impl_from_nsITooltipListener(iface);
1559     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1560 }
1561
1562 static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface)
1563 {
1564     NSContainer *This = impl_from_nsITooltipListener(iface);
1565     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1566 }
1567
1568 static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface,
1569         PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText)
1570 {
1571     NSContainer *This = impl_from_nsITooltipListener(iface);
1572
1573     if (This->doc)
1574         show_tooltip(This->doc, aXCoord, aYCoord, aTipText);
1575
1576     return NS_OK;
1577 }
1578
1579 static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface)
1580 {
1581     NSContainer *This = impl_from_nsITooltipListener(iface);
1582
1583     if (This->doc)
1584         hide_tooltip(This->doc);
1585
1586     return NS_OK;
1587 }
1588
1589 static const nsITooltipListenerVtbl nsTooltipListenerVtbl = {
1590     nsTooltipListener_QueryInterface,
1591     nsTooltipListener_AddRef,
1592     nsTooltipListener_Release,
1593     nsTooltipListener_OnShowTooltip,
1594     nsTooltipListener_OnHideTooltip
1595 };
1596
1597 static inline NSContainer *impl_from_nsIInterfaceRequestor(nsIInterfaceRequestor *iface)
1598 {
1599     return CONTAINING_RECORD(iface, NSContainer, nsIInterfaceRequestor_iface);
1600 }
1601
1602 static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface,
1603         nsIIDRef riid, void **result)
1604 {
1605     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1606     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1607 }
1608
1609 static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface)
1610 {
1611     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1612     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1613 }
1614
1615 static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface)
1616 {
1617     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1618     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1619 }
1620
1621 static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface,
1622         nsIIDRef riid, void **result)
1623 {
1624     NSContainer *This = impl_from_nsIInterfaceRequestor(iface);
1625
1626     if(IsEqualGUID(&IID_nsIDOMWindow, riid)) {
1627         TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result);
1628         return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result);
1629     }
1630
1631     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1632 }
1633
1634 static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = {
1635     nsInterfaceRequestor_QueryInterface,
1636     nsInterfaceRequestor_AddRef,
1637     nsInterfaceRequestor_Release,
1638     nsInterfaceRequestor_GetInterface
1639 };
1640
1641 static inline NSContainer *impl_from_nsIWeakReference(nsIWeakReference *iface)
1642 {
1643     return CONTAINING_RECORD(iface, NSContainer, nsIWeakReference_iface);
1644 }
1645
1646 static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface,
1647         nsIIDRef riid, void **result)
1648 {
1649     NSContainer *This = impl_from_nsIWeakReference(iface);
1650     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1651 }
1652
1653 static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface)
1654 {
1655     NSContainer *This = impl_from_nsIWeakReference(iface);
1656     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1657 }
1658
1659 static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface)
1660 {
1661     NSContainer *This = impl_from_nsIWeakReference(iface);
1662     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1663 }
1664
1665 static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface,
1666         const nsIID *riid, void **result)
1667 {
1668     NSContainer *This = impl_from_nsIWeakReference(iface);
1669     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1670 }
1671
1672 static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = {
1673     nsWeakReference_QueryInterface,
1674     nsWeakReference_AddRef,
1675     nsWeakReference_Release,
1676     nsWeakReference_QueryReferent
1677 };
1678
1679 static inline NSContainer *impl_from_nsISupportsWeakReference(nsISupportsWeakReference *iface)
1680 {
1681     return CONTAINING_RECORD(iface, NSContainer, nsISupportsWeakReference_iface);
1682 }
1683
1684 static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface,
1685         nsIIDRef riid, void **result)
1686 {
1687     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1688     return nsIWebBrowserChrome_QueryInterface(&This->nsIWebBrowserChrome_iface, riid, result);
1689 }
1690
1691 static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface)
1692 {
1693     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1694     return nsIWebBrowserChrome_AddRef(&This->nsIWebBrowserChrome_iface);
1695 }
1696
1697 static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface)
1698 {
1699     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1700     return nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1701 }
1702
1703 static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface,
1704         nsIWeakReference **_retval)
1705 {
1706     NSContainer *This = impl_from_nsISupportsWeakReference(iface);
1707
1708     TRACE("(%p)->(%p)\n", This, _retval);
1709
1710     nsIWeakReference_AddRef(&This->nsIWeakReference_iface);
1711     *_retval = &This->nsIWeakReference_iface;
1712     return NS_OK;
1713 }
1714
1715 static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = {
1716     nsSupportsWeakReference_QueryInterface,
1717     nsSupportsWeakReference_AddRef,
1718     nsSupportsWeakReference_Release,
1719     nsSupportsWeakReference_GetWeakReference
1720 };
1721
1722 nsresult create_chrome_window(nsIWebBrowserChrome *parent, nsIWebBrowserChrome **ret)
1723 {
1724     NSContainer *new_container;
1725
1726     if(parent->lpVtbl != &nsWebBrowserChromeVtbl)
1727         return NS_ERROR_UNEXPECTED;
1728
1729     new_container = NSContainer_Create(NULL, impl_from_nsIWebBrowserChrome(parent));
1730     *ret = &new_container->nsIWebBrowserChrome_iface;
1731     return NS_OK;
1732 }
1733
1734 NSContainer *NSContainer_Create(HTMLDocumentObj *doc, NSContainer *parent)
1735 {
1736     nsIWebBrowserSetup *wbsetup;
1737     nsIScrollable *scrollable;
1738     NSContainer *ret;
1739     nsresult nsres;
1740
1741     if(!load_gecko(TRUE))
1742         return NULL;
1743
1744     ret = heap_alloc_zero(sizeof(NSContainer));
1745
1746     ret->nsIWebBrowserChrome_iface.lpVtbl = &nsWebBrowserChromeVtbl;
1747     ret->nsIContextMenuListener_iface.lpVtbl = &nsContextMenuListenerVtbl;
1748     ret->nsIURIContentListener_iface.lpVtbl = &nsURIContentListenerVtbl;
1749     ret->nsIEmbeddingSiteWindow_iface.lpVtbl = &nsEmbeddingSiteWindowVtbl;
1750     ret->nsITooltipListener_iface.lpVtbl = &nsTooltipListenerVtbl;
1751     ret->nsIInterfaceRequestor_iface.lpVtbl = &nsInterfaceRequestorVtbl;
1752     ret->nsIWeakReference_iface.lpVtbl = &nsWeakReferenceVtbl;
1753     ret->nsISupportsWeakReference_iface.lpVtbl = &nsSupportsWeakReferenceVtbl;
1754
1755     ret->doc = doc;
1756     ret->ref = 1;
1757
1758     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
1759             NULL, &IID_nsIWebBrowser, (void**)&ret->webbrowser);
1760     if(NS_FAILED(nsres)) {
1761         ERR("Creating WebBrowser failed: %08x\n", nsres);
1762         heap_free(ret);
1763         return NULL;
1764     }
1765
1766     if(parent)
1767         nsIWebBrowserChrome_AddRef(&parent->nsIWebBrowserChrome_iface);
1768     ret->parent = parent;
1769
1770     nsres = nsIWebBrowser_SetContainerWindow(ret->webbrowser, &ret->nsIWebBrowserChrome_iface);
1771     if(NS_FAILED(nsres))
1772         ERR("SetContainerWindow failed: %08x\n", nsres);
1773
1774     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIBaseWindow,
1775             (void**)&ret->window);
1776     if(NS_FAILED(nsres))
1777         ERR("Could not get nsIBaseWindow interface: %08x\n", nsres);
1778
1779     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserSetup,
1780                                          (void**)&wbsetup);
1781     if(NS_SUCCEEDED(nsres)) {
1782         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE);
1783         nsIWebBrowserSetup_Release(wbsetup);
1784         if(NS_FAILED(nsres))
1785             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres);
1786     }else {
1787         ERR("Could not get nsIWebBrowserSetup interface\n");
1788     }
1789
1790     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebNavigation,
1791             (void**)&ret->navigation);
1792     if(NS_FAILED(nsres))
1793         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
1794
1795     nsres = nsIWebBrowserFocus_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserFocus,
1796             (void**)&ret->focus);
1797     if(NS_FAILED(nsres))
1798         ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres);
1799
1800     if(!nscontainer_class)
1801         register_nscontainer_class();
1802
1803     ret->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
1804             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
1805             GetDesktopWindow(), NULL, hInst, ret);
1806
1807     nsres = nsIBaseWindow_InitWindow(ret->window, ret->hwnd, NULL, 0, 0, 100, 100);
1808     if(NS_SUCCEEDED(nsres)) {
1809         nsres = nsIBaseWindow_Create(ret->window);
1810         if(NS_FAILED(nsres))
1811             WARN("Creating window failed: %08x\n", nsres);
1812
1813         nsIBaseWindow_SetVisibility(ret->window, FALSE);
1814         nsIBaseWindow_SetEnabled(ret->window, FALSE);
1815     }else {
1816         ERR("InitWindow failed: %08x\n", nsres);
1817     }
1818
1819     nsres = nsIWebBrowser_SetParentURIContentListener(ret->webbrowser,
1820             &ret->nsIURIContentListener_iface);
1821     if(NS_FAILED(nsres))
1822         ERR("SetParentURIContentListener failed: %08x\n", nsres);
1823
1824     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
1825     if(NS_SUCCEEDED(nsres)) {
1826         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1827                 ScrollOrientation_Y, Scrollbar_Always);
1828         if(NS_FAILED(nsres))
1829             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
1830
1831         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1832                 ScrollOrientation_X, Scrollbar_Auto);
1833         if(NS_FAILED(nsres))
1834             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
1835
1836         nsIScrollable_Release(scrollable);
1837     }else {
1838         ERR("Could not get nsIScrollable: %08x\n", nsres);
1839     }
1840
1841     return ret;
1842 }
1843
1844 void NSContainer_Release(NSContainer *This)
1845 {
1846     TRACE("(%p)\n", This);
1847
1848     This->doc = NULL;
1849
1850     ShowWindow(This->hwnd, SW_HIDE);
1851     SetParent(This->hwnd, NULL);
1852
1853     nsIBaseWindow_SetVisibility(This->window, FALSE);
1854     nsIBaseWindow_Destroy(This->window);
1855
1856     nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL);
1857
1858     nsIWebBrowser_Release(This->webbrowser);
1859     This->webbrowser = NULL;
1860
1861     nsIWebNavigation_Release(This->navigation);
1862     This->navigation = NULL;
1863
1864     nsIBaseWindow_Release(This->window);
1865     This->window = NULL;
1866
1867     nsIWebBrowserFocus_Release(This->focus);
1868     This->focus = NULL;
1869
1870     if(This->editor_controller) {
1871         nsIController_Release(This->editor_controller);
1872         This->editor_controller = NULL;
1873     }
1874
1875     if(This->editor) {
1876         nsIEditor_Release(This->editor);
1877         This->editor = NULL;
1878     }
1879
1880     if(This->content_listener) {
1881         nsIURIContentListener_Release(This->content_listener);
1882         This->content_listener = NULL;
1883     }
1884
1885     if(This->hwnd) {
1886         DestroyWindow(This->hwnd);
1887         This->hwnd = NULL;
1888     }
1889
1890     nsIWebBrowserChrome_Release(&This->nsIWebBrowserChrome_iface);
1891 }