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