kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[wine] / dlls / mshtml / nsembed.c
1 /*
2  * Copyright 2005 Jacek Caban
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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_IOSERVICE_CONTRACTID "@mozilla.org/network/io-service;1"
41 #define NS_PROFILE_CONTRACTID "@mozilla.org/profile/manager;1"
42
43 #define APPSTARTUP_TOPIC "app-startup"
44
45 #define PR_UINT32_MAX 0xffffffff
46
47 struct nsStringContainer {
48     void *v;
49     void *d1;
50     PRUint32 d2;
51     void *d3;
52 };
53
54 static nsresult (*NS_InitXPCOM2)(nsIServiceManager**,void*,void*);
55 static nsresult (*NS_ShutdownXPCOM)(nsIServiceManager*);
56 static nsresult (*NS_GetComponentRegistrar)(nsIComponentRegistrar**);
57 static nsresult (*NS_StringContainerInit)(nsStringContainer*);
58 static nsresult (*NS_CStringContainerInit)(nsCStringContainer*);
59 static nsresult (*NS_StringContainerFinish)(nsStringContainer*);
60 static nsresult (*NS_CStringContainerFinish)(nsCStringContainer*);
61 static nsresult (*NS_StringSetData)(nsAString*,const PRUnichar*,PRUint32);
62 static nsresult (*NS_CStringSetData)(nsACString*,const char*,PRUint32);
63 static nsresult (*NS_NewLocalFile)(const nsAString*,PRBool,nsIFile**);
64 static PRUint32 (*NS_CStringGetData)(nsACString*,const char**,PRBool*);
65
66 static HINSTANCE hXPCOM = NULL;
67
68 static nsIServiceManager *pServMgr = NULL;
69 static nsIComponentManager *pCompMgr = NULL;
70 static nsIIOService *pIOService = NULL;
71
72 static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0};
73
74 static ATOM nscontainer_class;
75
76 static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
77 {
78     HTMLDocument *This;
79     nsresult nsres;
80
81     static const WCHAR wszTHIS[] = {'T','H','I','S',0};
82
83     if(msg == WM_CREATE) {
84         This = *(HTMLDocument**)lParam;
85         SetPropW(hwnd, wszTHIS, This);
86     }else {
87         This = (HTMLDocument*)GetPropW(hwnd, wszTHIS);
88     }
89
90     switch(msg) {
91         case WM_SIZE:
92             TRACE("(%p)->(WM_SIZE)\n", This);
93
94             nsres = nsIBaseWindow_SetSize(This->nscontainer->window,
95                     LOWORD(lParam), HIWORD(lParam), TRUE);
96             if(NS_FAILED(nsres))
97                 WARN("SetSize failed: %08lx\n", nsres);
98     }
99
100     return DefWindowProcW(hwnd, msg, wParam, lParam);
101 }
102
103
104 static void register_nscontainer_class(void)
105 {
106     static WNDCLASSEXW wndclass = {
107         sizeof(WNDCLASSEXW),
108         CS_DBLCLKS,
109         nsembed_proc,
110         0, 0, NULL, NULL, NULL, NULL, NULL,
111         wszNsContainer,
112         NULL,
113     };
114     wndclass.hInstance = hInst;
115     nscontainer_class = RegisterClassExW(&wndclass);
116 }
117
118 static BOOL get_mozilla_path(PRUnichar *gre_path)
119 {
120     DWORD res, type, i, size = MAX_PATH;
121     HKEY mozilla_key, hkey;
122     WCHAR key_name[100];
123     BOOL ret = FALSE;
124
125     static const WCHAR wszGreKey[] =
126         {'S','o','f','t','w','a','r','e','\\',
127             'm','o','z','i','l','l','a','.','o','r','g','\\',
128                 'G','R','E',0};
129
130     static const WCHAR wszGreHome[] = {'G','r','e','H','o','m','e',0};
131
132     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszGreKey, &mozilla_key);
133     if(res != ERROR_SUCCESS) {
134         TRACE("Could not open key %s\n", debugstr_w(wszGreKey));
135         return FALSE;
136     }
137
138     for(i=0; !ret && RegEnumKeyW(mozilla_key, i, key_name, sizeof(key_name)/sizeof(WCHAR)) == ERROR_SUCCESS; i++) {
139         RegOpenKeyW(mozilla_key, key_name, &hkey);
140         res = RegQueryValueExW(hkey, wszGreHome, NULL, &type, (LPBYTE)gre_path, &size);
141         if(res == ERROR_SUCCESS)
142             ret = TRUE;
143         RegCloseKey(hkey);
144     }
145
146     RegCloseKey(mozilla_key);
147     return ret;
148 }
149
150 static BOOL get_mozctl_path(PRUnichar *gre_path)
151 {
152     HKEY hkey;
153     DWORD res, type, size = MAX_PATH;
154
155     static const WCHAR wszMozCtlKey[] =
156         {'S','o','f','t','w','a','r','e','\\','M','o','z','i','l','l','a',0};
157     static const WCHAR wszBinDirectoryPath[] =
158         {'B','i','n','D','i','r','e','c','t','o','r','y','P','a','t','h',0};
159     static const WCHAR wszMozCtlClsidKey[] =
160         {'C','L','S','I','D','\\',
161          '{','1','3','3','9','B','5','4','C','-','3','4','5','3','-','1','1','D','2',
162          '-','9','3','B','9','-','0','0','0','0','0','0','0','0','0','0','0','0','}','\\',
163          'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
164
165     res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszMozCtlKey, &hkey);
166     if(res == ERROR_SUCCESS) {
167         res = RegQueryValueExW(hkey, wszBinDirectoryPath, NULL, &type, (LPBYTE)gre_path, &size);
168         if(res == ERROR_SUCCESS)
169             return TRUE;
170         else
171             ERR("Could not get value %s\n", debugstr_w(wszBinDirectoryPath));
172     }
173
174     res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszMozCtlClsidKey, &hkey);
175     if(res == ERROR_SUCCESS) {
176         res = RegQueryValueExW(hkey, NULL, NULL, &type, (LPBYTE)gre_path, &size);
177         if(res == ERROR_SUCCESS) {
178             WCHAR *ptr;
179             if((ptr = strrchrW(gre_path, '\\')))
180                 ptr[1] = 0;
181             return TRUE;
182         }else {
183             ERR("Could not get value of %s\n", debugstr_w(wszMozCtlClsidKey));
184         }
185     }
186
187     TRACE("Could not find Mozilla ActiveX Control\n");
188
189     return FALSE;
190 }
191
192 static BOOL get_wine_gecko_path(PRUnichar *gre_path)
193 {
194     HKEY hkey;
195     DWORD res, type, size = MAX_PATH;
196
197     static const WCHAR wszMshtmlKey[] = {
198         'S','o','f','t','w','a','r','e','\\','W','i','n','e',
199         '\\','M','S','H','T','M','L',0};
200     static const WCHAR wszGeckoPath[] =
201         {'G','e','c','k','o','P','a','t','h',0};
202
203     /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */
204     res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey);
205     if(res != ERROR_SUCCESS)
206         return FALSE;
207
208     res = RegQueryValueExW(hkey, wszGeckoPath, NULL, &type, (LPBYTE)gre_path, &size);
209     if(res != ERROR_SUCCESS || type != REG_SZ)
210         return FALSE;
211
212     return TRUE;
213 }
214
215 static void set_profile(void)
216 {
217     nsIProfile *profile;
218     PRBool exists = FALSE;
219     nsresult nsres;
220
221     static const WCHAR wszMSHTML[] = {'M','S','H','T','M','L',0};
222
223     nsres = nsIServiceManager_GetServiceByContactID(pServMgr, NS_PROFILE_CONTRACTID,
224                                          &IID_nsIProfile, (void**)&profile);
225     if(NS_FAILED(nsres)) {
226         ERR("Could not get profile service: %08lx\n", nsres);
227         return;
228     }
229
230     nsres = nsIProfile_ProfileExists(profile, wszMSHTML, &exists);
231     if(!exists) {
232         nsres = nsIProfile_CreateNewProfile(profile, wszMSHTML, NULL, NULL, FALSE);
233         if(NS_FAILED(nsres))
234             ERR("CreateNewProfile failed: %08lx\n", nsres);
235     }
236
237     nsres = nsIProfile_SetCurrentProfile(profile, wszMSHTML);
238     if(NS_FAILED(nsres))
239         ERR("SetCurrentProfile failed: %08lx\n", nsres);
240
241     nsIProfile_Release(profile);
242 }
243
244 static BOOL load_gecko()
245 {
246     nsresult nsres;
247     nsIObserver *pStartNotif;
248     nsIComponentRegistrar *registrar = NULL;
249     nsAString path;
250     nsIFile *gre_dir;
251     PRUnichar gre_path[MAX_PATH];
252     WCHAR path_env[MAX_PATH];
253     int len;
254
255     static BOOL tried_load = FALSE;
256     static const WCHAR wszPATH[] = {'P','A','T','H',0};
257     static const WCHAR strXPCOM[] = {'x','p','c','o','m','.','d','l','l',0};
258
259     TRACE("()\n");
260
261     if(tried_load)
262         return pCompMgr != NULL;
263     tried_load = TRUE;
264
265     if(!get_wine_gecko_path(gre_path) && !get_mozctl_path(gre_path)
266        && !get_mozilla_path(gre_path)) {
267         MESSAGE("Could not load Mozilla. HTML rendering will be disabled.\n");
268         return FALSE;
269     }
270
271     TRACE("found path %s\n", debugstr_w(gre_path));
272
273     /* We have to modify PATH as XPCOM loads other DLLs from this directory. */
274     GetEnvironmentVariableW(wszPATH, path_env, sizeof(path_env)/sizeof(WCHAR));
275     len = strlenW(path_env);
276     path_env[len++] = ';';
277     strcpyW(path_env+len, gre_path);
278     SetEnvironmentVariableW(wszPATH, path_env);
279
280     hXPCOM = LoadLibraryW(strXPCOM);
281     if(!hXPCOM) {
282         ERR("Could not load XPCOM: %ld\n", GetLastError());
283         return FALSE;
284     }
285
286 #define NS_DLSYM(func) \
287     func = (typeof(func))GetProcAddress(hXPCOM, #func); \
288     if(!func) \
289         ERR("Could not GetProcAddress(" #func ") failed\n")
290
291     NS_DLSYM(NS_InitXPCOM2);
292     NS_DLSYM(NS_ShutdownXPCOM);
293     NS_DLSYM(NS_GetComponentRegistrar);
294     NS_DLSYM(NS_StringContainerInit);
295     NS_DLSYM(NS_CStringContainerInit);
296     NS_DLSYM(NS_StringContainerFinish);
297     NS_DLSYM(NS_CStringContainerFinish);
298     NS_DLSYM(NS_StringSetData);
299     NS_DLSYM(NS_CStringSetData);
300     NS_DLSYM(NS_NewLocalFile);
301     NS_DLSYM(NS_CStringGetData);
302
303 #undef NS_DLSYM
304
305     NS_StringContainerInit(&path);
306     NS_StringSetData(&path, gre_path, PR_UINT32_MAX);
307     nsres = NS_NewLocalFile(&path, FALSE, &gre_dir);
308     NS_StringContainerFinish(&path);
309     if(NS_FAILED(nsres)) {
310         ERR("NS_NewLocalFile failed: %08lx\n", nsres);
311         FreeLibrary(hXPCOM);
312         return FALSE;
313     }
314
315     nsres = NS_InitXPCOM2(&pServMgr, gre_dir, NULL);
316     if(NS_FAILED(nsres)) {
317         ERR("NS_InitXPCOM2 failed: %08lx\n", nsres);
318         FreeLibrary(hXPCOM);
319         return FALSE;
320     }
321
322     nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr);
323     if(NS_FAILED(nsres))
324         ERR("Could not get nsIComponentManager: %08lx\n", nsres);
325
326     nsres = NS_GetComponentRegistrar(&registrar);
327     if(NS_SUCCEEDED(nsres)) {
328         nsres = nsIComponentRegistrar_AutoRegister(registrar, NULL);
329         if(NS_FAILED(nsres))
330             ERR("AutoRegister(NULL) failed: %08lx\n", nsres);
331
332         nsres = nsIComponentRegistrar_AutoRegister(registrar, gre_dir);
333         if(NS_FAILED(nsres))
334             ERR("AutoRegister(gre_dir) failed: %08lx\n", nsres);
335     }else {
336         ERR("NS_GetComponentRegistrar failed: %08lx\n", nsres);
337     }
338
339     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_APPSTARTUPNOTIFIER_CONTRACTID,
340             NULL, &IID_nsIObserver, (void**)&pStartNotif);
341     if(NS_SUCCEEDED(nsres)) {
342         nsres = nsIObserver_Observe(pStartNotif, NULL, APPSTARTUP_TOPIC, NULL);
343         if(NS_FAILED(nsres))
344             ERR("Observe failed: %08lx\n", nsres);
345
346         nsIObserver_Release(pStartNotif);
347     }else {
348         ERR("could not get appstartup-notifier: %08lx\n", nsres);
349     }
350
351     if(registrar) {
352         register_nsservice(registrar);
353         nsIComponentRegistrar_Release(registrar);
354     }
355
356     set_profile();
357
358     return TRUE;
359 }
360
361 nsACString *nsACString_Create(void)
362 {
363     nsACString *ret;
364     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(nsACString));
365     NS_CStringContainerInit(ret);
366     return ret;
367 }
368
369 void nsACString_SetData(nsACString *str, const char *data)
370 {
371     NS_CStringSetData(str, data, PR_UINT32_MAX);
372 }
373
374 static PRUint32 nsACString_GetData(nsACString *str, const char **data, PRBool *termited)
375 {
376     return NS_CStringGetData(str, data, termited);
377 }
378
379 void nsACString_Destroy(nsACString *str)
380 {
381     NS_CStringContainerFinish(str);
382     HeapFree(GetProcessHeap(), 0, str);
383 }
384
385 void close_gecko()
386 {
387     TRACE("()\n");
388
389     if(pCompMgr)
390         nsIComponentManager_Release(pCompMgr);
391
392     if(pServMgr)
393         nsIServiceManager_Release(pServMgr);
394
395     if(hXPCOM)
396         FreeLibrary(hXPCOM);
397 }
398
399 nsIURI *get_nsIURI(LPCWSTR url)
400 {
401     nsIURI *ret;
402     nsACString *acstr;
403     nsresult nsres;
404     char *urla;
405     int len;
406
407     if(!pIOService) {
408         nsres = nsIServiceManager_GetServiceByContactID(pServMgr, NS_IOSERVICE_CONTRACTID,
409                 &IID_nsIIOService, (void**)&pIOService);
410         if(NS_FAILED(nsres))
411             ERR("Failed to create nsIOService: %08lx\n", nsres);
412     }
413
414     len = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, -1, NULL, NULL);
415     urla = HeapAlloc(GetProcessHeap(), 0, len);
416     WideCharToMultiByte(CP_ACP, 0, url, -1, urla, -1, NULL, NULL);
417
418     acstr = nsACString_Create();
419     nsACString_SetData(acstr, urla);
420
421     nsres = nsIIOService_NewURI(pIOService, acstr, NULL, NULL, &ret);
422     if(NS_FAILED(nsres))
423         FIXME("NewURI failed: %08lx\n", nsres);
424
425     nsACString_Destroy(acstr);
426     HeapFree(GetProcessHeap(), 0, urla);
427
428     return ret;
429 }
430
431 /**********************************************************
432  *      nsIWebBrowserChrome interface
433  */
434
435 #define NSWBCHROME_THIS(iface) DEFINE_THIS(NSContainer, WebBrowserChrome, iface)
436
437 static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface,
438         nsIIDRef riid, nsQIResult result)
439 {
440     NSContainer *This = NSWBCHROME_THIS(iface);
441
442     *result = NULL;
443     if(IsEqualGUID(&IID_nsISupports, riid)) {
444         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
445         *result = NSWBCHROME(This);
446     }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) {
447         TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result);
448         *result = NSWBCHROME(This);
449     }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) {
450         TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result);
451         *result = NSCML(This);
452     }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) {
453         TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result);
454         *result = NSURICL(This);
455     }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) {
456         TRACE("(%p)->(IIS_nsIEmbeddingSiteWindow %p)\n", This, result);
457         *result = NSEMBWNDS(This);
458     }
459
460     if(*result)
461         return NS_OK;
462
463     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
464     return NS_NOINTERFACE;
465 }
466
467 static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface)
468 {
469     NSContainer *This = NSWBCHROME_THIS(iface);
470     TRACE("(%p)\n", This);
471     return 2;  /* Should we implement ref conunting here? */
472 }
473
474 static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface)
475 {
476     NSContainer *This = NSWBCHROME_THIS(iface);
477     TRACE("(%p)\n", This);
478     return 1;
479 }
480
481 static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface,
482         PRUint32 statusType, const PRUnichar *status)
483 {
484     NSContainer *This = NSWBCHROME_THIS(iface);
485     TRACE("(%p)->(%ld %s)\n", This, statusType, debugstr_w(status));
486     return NS_ERROR_NOT_IMPLEMENTED;
487 }
488
489 static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface,
490         nsIWebBrowser **aWebBrowser)
491 {
492     NSContainer *This = NSWBCHROME_THIS(iface);
493
494     TRACE("(%p)->(%p)\n", This, aWebBrowser);
495
496     if(!aWebBrowser)
497         return NS_ERROR_INVALID_ARG;
498
499     *aWebBrowser = This->webbrowser;
500     return S_OK;
501 }
502
503 static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface,
504         nsIWebBrowser *aWebBrowser)
505 {
506     NSContainer *This = NSWBCHROME_THIS(iface);
507
508     TRACE("(%p)->(%p)\n", This, aWebBrowser);
509
510     if(aWebBrowser != This->webbrowser)
511         ERR("Wrong nsWebBrowser!\n");
512
513     return NS_OK;
514 }
515
516 static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface,
517         PRUint32 *aChromeFlags)
518 {
519     NSContainer *This = NSWBCHROME_THIS(iface);
520     WARN("(%p)->(%p)\n", This, aChromeFlags);
521     return NS_ERROR_NOT_IMPLEMENTED;
522 }
523
524 static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface,
525         PRUint32 aChromeFlags)
526 {
527     NSContainer *This = NSWBCHROME_THIS(iface);
528     WARN("(%p)->(%08lx)\n", This, aChromeFlags);
529     return NS_ERROR_NOT_IMPLEMENTED;
530 }
531
532 static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface)
533 {
534     NSContainer *This = NSWBCHROME_THIS(iface);
535     TRACE("(%p)\n", This);
536     return NS_ERROR_NOT_IMPLEMENTED;
537 }
538
539 static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface,
540         PRInt32 aCX, PRInt32 aCY)
541 {
542     NSContainer *This = NSWBCHROME_THIS(iface);
543     WARN("(%p)->(%ld %ld)\n", This, aCX, aCY);
544     return NS_ERROR_NOT_IMPLEMENTED;
545 }
546
547 static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface)
548 {
549     NSContainer *This = NSWBCHROME_THIS(iface);
550     WARN("(%p)\n", This);
551     return NS_ERROR_NOT_IMPLEMENTED;
552 }
553
554 static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, PRBool *_retval)
555 {
556     NSContainer *This = NSWBCHROME_THIS(iface);
557     WARN("(%p)->(%p)\n", This, _retval);
558     return NS_ERROR_NOT_IMPLEMENTED;
559 }
560
561 static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface,
562         nsresult aStatus)
563 {
564     NSContainer *This = NSWBCHROME_THIS(iface);
565     WARN("(%p)->(%08lx)\n", This, aStatus);
566     return NS_ERROR_NOT_IMPLEMENTED;
567 }
568
569 #undef NSWBCHROME_THIS
570
571 static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = {
572     nsWebBrowserChrome_QueryInterface,
573     nsWebBrowserChrome_AddRef,
574     nsWebBrowserChrome_Release,
575     nsWebBrowserChrome_SetStatus,
576     nsWebBrowserChrome_GetWebBrowser,
577     nsWebBrowserChrome_SetWebBrowser,
578     nsWebBrowserChrome_GetChromeFlags,
579     nsWebBrowserChrome_SetChromeFlags,
580     nsWebBrowserChrome_DestroyBrowserWindow,
581     nsWebBrowserChrome_SizeBrowserTo,
582     nsWebBrowserChrome_ShowAsModal,
583     nsWebBrowserChrome_IsWindowModal,
584     nsWebBrowserChrome_ExitModalEventLoop
585 };
586
587 /**********************************************************
588  *      nsIContextMenuListener interface
589  */
590
591 #define NSCML_THIS(iface) DEFINE_THIS(NSContainer, ContextMenuListener, iface)
592
593 static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface,
594         nsIIDRef riid, nsQIResult result)
595 {
596     NSContainer *This = NSCML_THIS(iface);
597     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
598 }
599
600 static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface)
601 {
602     NSContainer *This = NSCML_THIS(iface);
603     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
604 }
605
606 static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface)
607 {
608     NSContainer *This = NSCML_THIS(iface);
609     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
610 }
611
612 static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface,
613         PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
614 {
615     NSContainer *This = NSCML_THIS(iface);
616     nsIDOMMouseEvent *event;
617     POINT pt;
618     DWORD dwID = CONTEXT_MENU_DEFAULT;
619     nsresult nsres;
620
621     TRACE("(%p)->(%08lx %p %p)\n", This, aContextFlags, aEvent, aNode);
622
623     nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event);
624     if(NS_FAILED(nsres)) {
625         ERR("Could not get nsIDOMMouseEvent interface: %08lx\n", nsres);
626         return nsres;
627     }
628
629     nsIDOMMouseEvent_GetScreenX(event, &pt.x);
630     nsIDOMMouseEvent_GetScreenY(event, &pt.y);
631     nsIDOMMouseEvent_Release(event);
632
633     switch(aContextFlags) {
634     case CONTEXT_NONE:
635     case CONTEXT_DOCUMENT:
636     case CONTEXT_TEXT:
637         dwID = CONTEXT_MENU_DEFAULT;
638         break;
639     case CONTEXT_IMAGE:
640     case CONTEXT_IMAGE|CONTEXT_LINK:
641         dwID = CONTEXT_MENU_IMAGE;
642         break;
643     case CONTEXT_LINK:
644         dwID = CONTEXT_MENU_ANCHOR;
645         break;
646     case CONTEXT_INPUT:
647         dwID = CONTEXT_MENU_CONTROL;
648         break;
649     default:
650         FIXME("aContextFlags=%08lx\n", aContextFlags);
651     };
652
653     HTMLDocument_ShowContextMenu(This->doc, dwID, &pt);
654
655     return NS_OK;
656 }
657
658 #undef NSCML_THIS
659
660 static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = {
661     nsContextMenuListener_QueryInterface,
662     nsContextMenuListener_AddRef,
663     nsContextMenuListener_Release,
664     nsContextMenuListener_OnShowContextMenu
665 };
666
667 /**********************************************************
668  *      nsIURIContentListener interface
669  */
670
671 #define NSURICL_THIS(iface) DEFINE_THIS(NSContainer, URIContentListener, iface)
672
673 static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface,
674         nsIIDRef riid, nsQIResult result)
675 {
676     NSContainer *This = NSURICL_THIS(iface);
677     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
678 }
679
680 static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface)
681 {
682     NSContainer *This = NSURICL_THIS(iface);
683     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
684 }
685
686 static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
687 {
688     NSContainer *This = NSURICL_THIS(iface);
689     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
690 }
691
692 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface, nsIURI *aURI,
693         PRBool *_retval)
694 {
695     NSContainer *This = NSURICL_THIS(iface);
696     BOOL do_load = TRUE;
697     nsresult nsres;
698     nsACString *spec_str = nsACString_Create();
699
700     TRACE("(%p)->(%p %p)\n", This, aURI, _retval);
701
702     nsres = nsIURI_GetSpec(aURI, spec_str);
703     if(NS_SUCCEEDED(nsres)) {
704         const char *spec = NULL;
705         LPWSTR specw;
706         int len;
707
708         nsACString_GetData(spec_str, &spec, NULL);
709
710         len = MultiByteToWideChar(CP_ACP, 0, spec, -1, NULL, 0);
711         specw = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
712         MultiByteToWideChar(CP_ACP, 0, spec, -1, specw, -1);
713
714         if(strcmpW(This->url, specw)) /* hack */
715             do_load = HTMLDocument_OnLoad(This->doc, specw);
716
717         HeapFree(GetProcessHeap(), 0, specw);
718     }else {
719         ERR("GetSpec failed: %08lx\n", nsres);
720     }
721
722     nsACString_Destroy(spec_str);
723
724     if(!do_load) {
725         *_retval = TRUE;
726         return NS_OK;
727     }
728
729     return NS_ERROR_NOT_IMPLEMENTED;
730 }
731
732 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
733         const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest,
734         nsIStreamListener **aContentHandler, PRBool *_retval)
735 {
736     NSContainer *This = NSURICL_THIS(iface);
737     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
738             aRequest, aContentHandler, _retval);
739     return NS_ERROR_NOT_IMPLEMENTED;
740 }
741
742 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
743         const char *aContentType, char **aDesiredContentType, PRBool *_retval)
744 {
745     NSContainer *This = NSURICL_THIS(iface);
746
747     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
748
749     /* FIXME: Should we do something here? */
750     *_retval = TRUE; 
751     return NS_OK;
752 }
753
754 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
755         const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType,
756         PRBool *_retval)
757 {
758     NSContainer *This = NSURICL_THIS(iface);
759     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
760             aDesiredContentType, _retval);
761     return NS_ERROR_NOT_IMPLEMENTED;
762 }
763
764 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
765         nsISupports **aLoadCookie)
766 {
767     NSContainer *This = NSURICL_THIS(iface);
768     WARN("(%p)->(%p)\n", This, aLoadCookie);
769     return NS_ERROR_NOT_IMPLEMENTED;
770 }
771
772 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
773         nsISupports *aLoadCookie)
774 {
775     NSContainer *This = NSURICL_THIS(iface);
776     WARN("(%p)->(%p)\n", This, aLoadCookie);
777     return NS_ERROR_NOT_IMPLEMENTED;
778 }
779
780 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
781         nsIURIContentListener **aParentContentListener)
782 {
783     NSContainer *This = NSURICL_THIS(iface);
784     WARN("(%p)->(%p)\n", This, aParentContentListener);
785     return NS_ERROR_NOT_IMPLEMENTED;
786 }
787
788 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
789         nsIURIContentListener *aParentContentListener)
790 {
791     NSContainer *This = NSURICL_THIS(iface);
792     WARN("(%p)->(%p)\n", This, aParentContentListener);
793     return NS_ERROR_NOT_IMPLEMENTED;
794 }
795
796 #undef NSURICL_THIS
797
798 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
799     nsURIContentListener_QueryInterface,
800     nsURIContentListener_AddRef,
801     nsURIContentListener_Release,
802     nsURIContentListener_OnStartURIOpen,
803     nsURIContentListener_DoContent,
804     nsURIContentListener_IsPreferred,
805     nsURIContentListener_CanHandleContent,
806     nsURIContentListener_GetLoadCookie,
807     nsURIContentListener_SetLoadCookie,
808     nsURIContentListener_GetParentContentListener,
809     nsURIContentListener_SetParentContentListener
810 };
811
812 /**********************************************************
813  *      nsIEmbeddinSiteWindow interface
814  */
815
816 #define NSEMBWNDS_THIS(iface) DEFINE_THIS(NSContainer, EmbeddingSiteWindow, iface)
817
818 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
819         nsIIDRef riid, nsQIResult result)
820 {
821     NSContainer *This = NSEMBWNDS_THIS(iface);
822     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
823 }
824
825 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
826 {
827     NSContainer *This = NSEMBWNDS_THIS(iface);
828     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
829 }
830
831 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
832 {
833     NSContainer *This = NSEMBWNDS_THIS(iface);
834     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
835 }
836
837 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
838         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
839 {
840     NSContainer *This = NSEMBWNDS_THIS(iface);
841     WARN("(%p)->(%08lx %ld %ld %ld %ld)\n", This, flags, x, y, cx, cy);
842     return NS_ERROR_NOT_IMPLEMENTED;
843 }
844
845 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
846         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
847 {
848     NSContainer *This = NSEMBWNDS_THIS(iface);
849     WARN("(%p)->(%08lx %p %p %p %p)\n", This, flags, x, y, cx, cy);
850     return NS_ERROR_NOT_IMPLEMENTED;
851 }
852
853 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
854 {
855     NSContainer *This = NSEMBWNDS_THIS(iface);
856     WARN("(%p)\n", This);
857     return NS_ERROR_NOT_IMPLEMENTED;
858 }
859
860 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
861         PRBool *aVisibility)
862 {
863     NSContainer *This = NSEMBWNDS_THIS(iface);
864     WARN("(%p)->(%p)\n", This, aVisibility);
865     return NS_ERROR_NOT_IMPLEMENTED;
866 }
867
868 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
869         PRBool aVisibility)
870 {
871     NSContainer *This = NSEMBWNDS_THIS(iface);
872     WARN("(%p)->(%x)\n", This, aVisibility);
873     return NS_ERROR_NOT_IMPLEMENTED;
874 }
875
876 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
877         PRUnichar **aTitle)
878 {
879     NSContainer *This = NSEMBWNDS_THIS(iface);
880     WARN("(%p)->(%p)\n", This, aTitle);
881     return NS_ERROR_NOT_IMPLEMENTED;
882 }
883
884 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
885         const PRUnichar *aTitle)
886 {
887     NSContainer *This = NSEMBWNDS_THIS(iface);
888     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
889     return NS_ERROR_NOT_IMPLEMENTED;
890 }
891
892 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
893         void **aSiteWindow)
894 {
895     NSContainer *This = NSEMBWNDS_THIS(iface);
896
897     TRACE("(%p)->(%p)\n", This, aSiteWindow);
898
899     *aSiteWindow = This->hwnd;
900     return NS_OK;
901 }
902
903 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
904     nsEmbeddingSiteWindow_QueryInterface,
905     nsEmbeddingSiteWindow_AddRef,
906     nsEmbeddingSiteWindow_Release,
907     nsEmbeddingSiteWindow_SetDimensions,
908     nsEmbeddingSiteWindow_GetDimensions,
909     nsEmbeddingSiteWindow_SetFocus,
910     nsEmbeddingSiteWindow_GetVisibility,
911     nsEmbeddingSiteWindow_SetVisibility,
912     nsEmbeddingSiteWindow_GetTitle,
913     nsEmbeddingSiteWindow_SetTitle,
914     nsEmbeddingSiteWindow_GetSiteWindow
915 };
916
917 void HTMLDocument_NSContainer_Init(HTMLDocument *This)
918 {
919     nsIWebBrowserSetup *wbsetup;
920     nsresult nsres;
921
922     This->nscontainer = NULL;
923
924     if(!load_gecko())
925         return;
926
927     This->nscontainer = HeapAlloc(GetProcessHeap(), 0, sizeof(NSContainer));
928
929     This->nscontainer->lpWebBrowserChromeVtbl    = &nsWebBrowserChromeVtbl;
930     This->nscontainer->lpContextMenuListenerVtbl = &nsContextMenuListenerVtbl;
931     This->nscontainer->lpURIContentListenerVtbl  = &nsURIContentListenerVtbl;
932     This->nscontainer->lpEmbeddingSiteWindowVtbl = &nsEmbeddingSiteWindowVtbl;
933
934     This->nscontainer->doc = This;
935
936     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
937             NULL, &IID_nsIWebBrowser, (void**)&This->nscontainer->webbrowser);
938     if(NS_FAILED(nsres))
939         ERR("Creating WebBrowser failed: %08lx\n", nsres);
940
941     nsres = nsIWebBrowser_SetContainerWindow(This->nscontainer->webbrowser,
942             NSWBCHROME(This->nscontainer));
943     if(NS_FAILED(nsres))
944         ERR("SetContainerWindow failed: %08lx\n", nsres);
945
946     nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, &IID_nsIBaseWindow,
947             (void**)&This->nscontainer->window);
948     if(NS_FAILED(nsres))
949         ERR("Could not get nsIBaseWindow interface: %08lx\n", nsres);
950
951     nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser,
952             &IID_nsIWebBrowserSetup, (void**)&wbsetup);
953     if(NS_SUCCEEDED(nsres)) {
954         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, TRUE);
955         nsIWebBrowserSetup_Release(wbsetup);
956         if(NS_FAILED(nsres))
957             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08lx\n", nsres);
958     }else {
959         ERR("Could not get nsIWebBrowserSetup interface\n");
960     }
961
962     nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, &IID_nsIWebNavigation,
963             (void**)&This->nscontainer->navigation);
964     if(NS_FAILED(nsres))
965         ERR("Could not get nsIWebNavigation interface: %08lx\n", nsres);
966
967     nsres = nsIWebBrowserFocus_QueryInterface(This->nscontainer->webbrowser, &IID_nsIWebBrowserFocus,
968             (void**)&This->nscontainer->focus);
969     if(NS_FAILED(nsres))
970         ERR("Could not get nsIWebBrowserFocus interface: %08lx\n", nsres);
971
972 #if 0
973     nsres = nsIWebBrowserStream_QueryInterface(This->nscontainer->webbrowser, &IID_nsIWebBrowserStream,
974             (void**)&This->nscontainer->stream);
975     if(NS_FAILED(nsres))
976         ERR("Could not get nsIWebBrowserStream interface: %08lx\n", nsres);
977 #else
978     This->nscontainer->stream = NULL;
979 #endif
980
981     if(!nscontainer_class)
982         register_nscontainer_class();
983
984     This->nscontainer->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
985             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
986             GetDesktopWindow(), NULL, hInst, This);
987
988     nsres = nsIBaseWindow_InitWindow(This->nscontainer->window, This->nscontainer->hwnd, NULL,
989             0, 0, 100, 100);
990     if(NS_SUCCEEDED(nsres)) {
991         nsres = nsIBaseWindow_Create(This->nscontainer->window);
992         if(NS_FAILED(nsres))
993             WARN("Creating window failed: %08lx\n", nsres);
994
995         nsIBaseWindow_SetVisibility(This->nscontainer->window, FALSE);
996         nsIBaseWindow_SetEnabled(This->nscontainer->window, FALSE);
997     }else {
998         ERR("InitWindow failed: %08lx\n", nsres);
999     }
1000
1001     nsres = nsIWebBrowser_SetParentURIContentListener(This->nscontainer->webbrowser,
1002             NSURICL(This->nscontainer));
1003     if(NS_FAILED(nsres))
1004         ERR("SetParentURIContentListener failed: %08lx\n", nsres);
1005
1006     This->nscontainer->url = NULL;
1007 }
1008
1009 void HTMLDocument_NSContainer_Destroy(HTMLDocument *This)
1010 {
1011     TRACE("(%p)\n", This);
1012
1013     nsIWebBrowser_Release(This->nscontainer->webbrowser);
1014     nsIWebNavigation_Release(This->nscontainer->navigation);
1015     nsIBaseWindow_Release(This->nscontainer->window);
1016
1017     if(This->nscontainer->stream)
1018         nsIWebBrowserStream_Release(This->nscontainer->stream);
1019
1020     HeapFree(GetProcessHeap(), 0, This->nscontainer);
1021
1022     if(This->nscontainer->url)
1023         CoTaskMemFree(This->nscontainer->url);
1024 }