mshtml: Store the nsIEditor interface in the NSContainer object for use in implementi...
[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 void get_editor_controller(NSContainer *This)
633 {
634     nsIEditingSession *editing_session = NULL;
635     nsIInterfaceRequestor *iface_req;
636     nsIControllerContext *ctrlctx;
637     nsresult nsres;
638
639     if(This->editor) {
640         nsIEditor_Release(This->editor);
641         This->editor = NULL;
642     }
643
644     if(This->editor_controller) {
645         nsIController_Release(This->editor_controller);
646         This->editor_controller = NULL;
647     }
648
649     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
650             &IID_nsIInterfaceRequestor, (void**)&iface_req);
651     if(NS_FAILED(nsres)) {
652         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
653         return;
654     }
655
656     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIEditingSession,
657                                                (void**)&editing_session);
658     nsIInterfaceRequestor_Release(iface_req);
659     if(NS_FAILED(nsres)) {
660         ERR("Could not get nsIEditingSession: %08x\n", nsres);
661         return;
662     }
663
664     nsres = nsIEditingSession_GetEditorForWindow(editing_session,
665             This->doc->window->nswindow, &This->editor);
666     nsIEditingSession_Release(editing_session);
667     if(NS_FAILED(nsres)) {
668         ERR("Could not get editor: %08x\n", nsres);
669         return;
670     }
671
672     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr,
673             NS_EDITORCONTROLLER_CONTRACTID, NULL, &IID_nsIControllerContext, (void**)&ctrlctx);
674     if(NS_SUCCEEDED(nsres)) {
675         nsres = nsIControllerContext_SetCommandContext(ctrlctx, (nsISupports *)This->editor);
676         if(NS_FAILED(nsres))
677             ERR("SetCommandContext failed: %08x\n", nsres);
678         nsres = nsIControllerContext_QueryInterface(ctrlctx, &IID_nsIController,
679                 (void**)&This->editor_controller);
680         nsIControllerContext_Release(ctrlctx);
681         if(NS_FAILED(nsres))
682             ERR("Could not get nsIController interface: %08x\n", nsres);
683     }else {
684         ERR("Could not create edit controller: %08x\n", nsres);
685     }
686 }
687
688 void set_ns_editmode(NSContainer *This)
689 {
690     nsIInterfaceRequestor *iface_req;
691     nsIEditingSession *editing_session = NULL;
692     nsIURIContentListener *listener = NULL;
693     nsIDOMWindow *dom_window = NULL;
694     nsresult nsres;
695
696     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
697             &IID_nsIInterfaceRequestor, (void**)&iface_req);
698     if(NS_FAILED(nsres)) {
699         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
700         return;
701     }
702
703     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIEditingSession,
704                                                (void**)&editing_session);
705     nsIInterfaceRequestor_Release(iface_req);
706     if(NS_FAILED(nsres)) {
707         ERR("Could not get nsIEditingSession: %08x\n", nsres);
708         return;
709     }
710
711     nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window);
712     if(NS_FAILED(nsres)) {
713         ERR("Could not get content DOM window: %08x\n", nsres);
714         nsIEditingSession_Release(editing_session);
715         return;
716     }
717
718     nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE);
719     nsIEditingSession_Release(editing_session);
720     nsIDOMWindow_Release(dom_window);
721     if(NS_FAILED(nsres)) {
722         ERR("MakeWindowEditable failed: %08x\n", nsres);
723         return;
724     }
725
726     /* MakeWindowEditable changes WebBrowser's parent URI content listener.
727      * It seams to be a bug in Gecko. To workaround it we set our content
728      * listener again and Gecko's one as its parent.
729      */
730     nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener);
731     nsIURIContentListener_SetParentContentListener(NSURICL(This), listener);
732     nsIURIContentListener_Release(listener);
733     nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This));
734 }
735
736 void close_gecko(void)
737 {
738     TRACE("()\n");
739
740     if(pCompMgr)
741         nsIComponentManager_Release(pCompMgr);
742
743     if(pServMgr)
744         nsIServiceManager_Release(pServMgr);
745
746     if(nsmem)
747         nsIMemory_Release(nsmem);
748
749     if(hXPCOM)
750         FreeLibrary(hXPCOM);
751 }
752
753 /**********************************************************
754  *      nsIWebBrowserChrome interface
755  */
756
757 #define NSWBCHROME_THIS(iface) DEFINE_THIS(NSContainer, WebBrowserChrome, iface)
758
759 static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface,
760         nsIIDRef riid, nsQIResult result)
761 {
762     NSContainer *This = NSWBCHROME_THIS(iface);
763
764     *result = NULL;
765     if(IsEqualGUID(&IID_nsISupports, riid)) {
766         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
767         *result = NSWBCHROME(This);
768     }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) {
769         TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result);
770         *result = NSWBCHROME(This);
771     }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) {
772         TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result);
773         *result = NSCML(This);
774     }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) {
775         TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result);
776         *result = NSURICL(This);
777     }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) {
778         TRACE("(%p)->(IID_nsIEmbeddingSiteWindow %p)\n", This, result);
779         *result = NSEMBWNDS(This);
780     }else if(IsEqualGUID(&IID_nsITooltipListener, riid)) {
781         TRACE("(%p)->(IID_nsITooltipListener %p)\n", This, result);
782         *result = NSTOOLTIP(This);
783     }else if(IsEqualGUID(&IID_nsIInterfaceRequestor, riid)) {
784         TRACE("(%p)->(IID_nsIInterfaceRequestor %p)\n", This, result);
785         *result = NSIFACEREQ(This);
786     }else if(IsEqualGUID(&IID_nsIWeakReference, riid)) {
787         TRACE("(%p)->(IID_nsIWeakReference %p)\n", This, result);
788         *result = NSWEAKREF(This);
789     }else if(IsEqualGUID(&IID_nsISupportsWeakReference, riid)) {
790         TRACE("(%p)->(IID_nsISupportsWeakReference %p)\n", This, result);
791         *result = NSSUPWEAKREF(This);
792     }
793
794     if(*result) {
795         nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
796         return NS_OK;
797     }
798
799     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
800     return NS_NOINTERFACE;
801 }
802
803 static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface)
804 {
805     NSContainer *This = NSWBCHROME_THIS(iface);
806     LONG ref = InterlockedIncrement(&This->ref);
807
808     TRACE("(%p) ref=%d\n", This, ref);
809
810     return ref;
811 }
812
813 static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface)
814 {
815     NSContainer *This = NSWBCHROME_THIS(iface);
816     LONG ref = InterlockedDecrement(&This->ref);
817
818     TRACE("(%p) ref=%d\n", This, ref);
819
820     if(!ref) {
821         if(This->parent)
822             nsIWebBrowserChrome_Release(NSWBCHROME(This->parent));
823         mshtml_free(This);
824     }
825
826     return ref;
827 }
828
829 static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface,
830         PRUint32 statusType, const PRUnichar *status)
831 {
832     NSContainer *This = NSWBCHROME_THIS(iface);
833     TRACE("(%p)->(%d %s)\n", This, statusType, debugstr_w(status));
834     return NS_ERROR_NOT_IMPLEMENTED;
835 }
836
837 static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface,
838         nsIWebBrowser **aWebBrowser)
839 {
840     NSContainer *This = NSWBCHROME_THIS(iface);
841
842     TRACE("(%p)->(%p)\n", This, aWebBrowser);
843
844     if(!aWebBrowser)
845         return NS_ERROR_INVALID_ARG;
846
847     if(This->webbrowser)
848         nsIWebBrowser_AddRef(This->webbrowser);
849     *aWebBrowser = This->webbrowser;
850     return S_OK;
851 }
852
853 static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface,
854         nsIWebBrowser *aWebBrowser)
855 {
856     NSContainer *This = NSWBCHROME_THIS(iface);
857
858     TRACE("(%p)->(%p)\n", This, aWebBrowser);
859
860     if(aWebBrowser != This->webbrowser)
861         ERR("Wrong nsWebBrowser!\n");
862
863     return NS_OK;
864 }
865
866 static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface,
867         PRUint32 *aChromeFlags)
868 {
869     NSContainer *This = NSWBCHROME_THIS(iface);
870     WARN("(%p)->(%p)\n", This, aChromeFlags);
871     return NS_ERROR_NOT_IMPLEMENTED;
872 }
873
874 static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface,
875         PRUint32 aChromeFlags)
876 {
877     NSContainer *This = NSWBCHROME_THIS(iface);
878     WARN("(%p)->(%08x)\n", This, aChromeFlags);
879     return NS_ERROR_NOT_IMPLEMENTED;
880 }
881
882 static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface)
883 {
884     NSContainer *This = NSWBCHROME_THIS(iface);
885     TRACE("(%p)\n", This);
886     return NS_ERROR_NOT_IMPLEMENTED;
887 }
888
889 static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface,
890         PRInt32 aCX, PRInt32 aCY)
891 {
892     NSContainer *This = NSWBCHROME_THIS(iface);
893     WARN("(%p)->(%d %d)\n", This, aCX, aCY);
894     return NS_ERROR_NOT_IMPLEMENTED;
895 }
896
897 static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface)
898 {
899     NSContainer *This = NSWBCHROME_THIS(iface);
900     WARN("(%p)\n", This);
901     return NS_ERROR_NOT_IMPLEMENTED;
902 }
903
904 static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, PRBool *_retval)
905 {
906     NSContainer *This = NSWBCHROME_THIS(iface);
907     WARN("(%p)->(%p)\n", This, _retval);
908     return NS_ERROR_NOT_IMPLEMENTED;
909 }
910
911 static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface,
912         nsresult aStatus)
913 {
914     NSContainer *This = NSWBCHROME_THIS(iface);
915     WARN("(%p)->(%08x)\n", This, aStatus);
916     return NS_ERROR_NOT_IMPLEMENTED;
917 }
918
919 #undef NSWBCHROME_THIS
920
921 static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = {
922     nsWebBrowserChrome_QueryInterface,
923     nsWebBrowserChrome_AddRef,
924     nsWebBrowserChrome_Release,
925     nsWebBrowserChrome_SetStatus,
926     nsWebBrowserChrome_GetWebBrowser,
927     nsWebBrowserChrome_SetWebBrowser,
928     nsWebBrowserChrome_GetChromeFlags,
929     nsWebBrowserChrome_SetChromeFlags,
930     nsWebBrowserChrome_DestroyBrowserWindow,
931     nsWebBrowserChrome_SizeBrowserTo,
932     nsWebBrowserChrome_ShowAsModal,
933     nsWebBrowserChrome_IsWindowModal,
934     nsWebBrowserChrome_ExitModalEventLoop
935 };
936
937 /**********************************************************
938  *      nsIContextMenuListener interface
939  */
940
941 #define NSCML_THIS(iface) DEFINE_THIS(NSContainer, ContextMenuListener, iface)
942
943 static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface,
944         nsIIDRef riid, nsQIResult result)
945 {
946     NSContainer *This = NSCML_THIS(iface);
947     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
948 }
949
950 static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface)
951 {
952     NSContainer *This = NSCML_THIS(iface);
953     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
954 }
955
956 static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface)
957 {
958     NSContainer *This = NSCML_THIS(iface);
959     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
960 }
961
962 static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface,
963         PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
964 {
965     NSContainer *This = NSCML_THIS(iface);
966     nsIDOMMouseEvent *event;
967     POINT pt;
968     DWORD dwID = CONTEXT_MENU_DEFAULT;
969     nsresult nsres;
970
971     TRACE("(%p)->(%08x %p %p)\n", This, aContextFlags, aEvent, aNode);
972
973     nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event);
974     if(NS_FAILED(nsres)) {
975         ERR("Could not get nsIDOMMouseEvent interface: %08x\n", nsres);
976         return nsres;
977     }
978
979     nsIDOMMouseEvent_GetScreenX(event, &pt.x);
980     nsIDOMMouseEvent_GetScreenY(event, &pt.y);
981     nsIDOMMouseEvent_Release(event);
982
983     switch(aContextFlags) {
984     case CONTEXT_NONE:
985     case CONTEXT_DOCUMENT:
986     case CONTEXT_TEXT:
987         dwID = CONTEXT_MENU_DEFAULT;
988         break;
989     case CONTEXT_IMAGE:
990     case CONTEXT_IMAGE|CONTEXT_LINK:
991         dwID = CONTEXT_MENU_IMAGE;
992         break;
993     case CONTEXT_LINK:
994         dwID = CONTEXT_MENU_ANCHOR;
995         break;
996     case CONTEXT_INPUT:
997         dwID = CONTEXT_MENU_CONTROL;
998         break;
999     default:
1000         FIXME("aContextFlags=%08x\n", aContextFlags);
1001     };
1002
1003     show_context_menu(This->doc, dwID, &pt);
1004
1005     return NS_OK;
1006 }
1007
1008 #undef NSCML_THIS
1009
1010 static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = {
1011     nsContextMenuListener_QueryInterface,
1012     nsContextMenuListener_AddRef,
1013     nsContextMenuListener_Release,
1014     nsContextMenuListener_OnShowContextMenu
1015 };
1016
1017 /**********************************************************
1018  *      nsIURIContentListener interface
1019  */
1020
1021 #define NSURICL_THIS(iface) DEFINE_THIS(NSContainer, URIContentListener, iface)
1022
1023 static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface,
1024         nsIIDRef riid, nsQIResult result)
1025 {
1026     NSContainer *This = NSURICL_THIS(iface);
1027     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1028 }
1029
1030 static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface)
1031 {
1032     NSContainer *This = NSURICL_THIS(iface);
1033     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1034 }
1035
1036 static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface)
1037 {
1038     NSContainer *This = NSURICL_THIS(iface);
1039     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1040 }
1041
1042 static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface,
1043                                                           nsIURI *aURI, PRBool *_retval)
1044 {
1045     NSContainer *This = NSURICL_THIS(iface);
1046     nsIWineURI *wine_uri;
1047     nsACString spec_str;
1048     const char *spec;
1049     nsresult nsres;
1050
1051     nsACString_Init(&spec_str, NULL);
1052     nsIURI_GetSpec(aURI, &spec_str);
1053     nsACString_GetData(&spec_str, &spec, NULL);
1054
1055     TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval);
1056
1057     nsACString_Finish(&spec_str);
1058
1059     nsres = nsIURI_QueryInterface(aURI, &IID_nsIWineURI, (void**)&wine_uri);
1060     if(NS_FAILED(nsres)) {
1061         WARN("Could not get nsIWineURI interface: %08x\n", nsres);
1062         return NS_ERROR_NOT_IMPLEMENTED;
1063     }
1064
1065     nsIWineURI_SetNSContainer(wine_uri, This);
1066     nsIWineURI_SetIsDocumentURI(wine_uri, TRUE);
1067
1068     if(This->bscallback && This->bscallback->mon) {
1069         LPWSTR wine_url;
1070         HRESULT hres;
1071
1072         hres = IMoniker_GetDisplayName(This->bscallback->mon, NULL, 0, &wine_url);
1073         if(SUCCEEDED(hres)) {
1074             nsIWineURI_SetWineURL(wine_uri, wine_url);
1075             CoTaskMemFree(wine_url);
1076         }else {
1077             WARN("GetDisplayName failed: %08x\n", hres);
1078         }
1079     }
1080
1081     nsIWineURI_Release(wine_uri);
1082
1083     *_retval = FALSE;
1084     return This->content_listener
1085         ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval)
1086         : NS_OK;
1087 }
1088
1089 static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface,
1090         const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest,
1091         nsIStreamListener **aContentHandler, PRBool *_retval)
1092 {
1093     NSContainer *This = NSURICL_THIS(iface);
1094
1095     TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1096             aRequest, aContentHandler, _retval);
1097
1098     return This->content_listener
1099         ? nsIURIContentListener_DoContent(This->content_listener, aContentType,
1100                   aIsContentPreferred, aRequest, aContentHandler, _retval)
1101         : NS_ERROR_NOT_IMPLEMENTED;
1102 }
1103
1104 static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface,
1105         const char *aContentType, char **aDesiredContentType, PRBool *_retval)
1106 {
1107     NSContainer *This = NSURICL_THIS(iface);
1108
1109     TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval);
1110
1111     /* FIXME: Should we do something here? */
1112     *_retval = TRUE; 
1113
1114     return This->content_listener
1115         ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType,
1116                   aDesiredContentType, _retval)
1117         : NS_OK;
1118 }
1119
1120 static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface,
1121         const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType,
1122         PRBool *_retval)
1123 {
1124     NSContainer *This = NSURICL_THIS(iface);
1125
1126     TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred,
1127             aDesiredContentType, _retval);
1128
1129     return This->content_listener
1130         ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType,
1131                 aIsContentPreferred, aDesiredContentType, _retval)
1132         : NS_ERROR_NOT_IMPLEMENTED;
1133 }
1134
1135 static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface,
1136         nsISupports **aLoadCookie)
1137 {
1138     NSContainer *This = NSURICL_THIS(iface);
1139
1140     WARN("(%p)->(%p)\n", This, aLoadCookie);
1141
1142     return This->content_listener
1143         ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie)
1144         : NS_ERROR_NOT_IMPLEMENTED;
1145 }
1146
1147 static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface,
1148         nsISupports *aLoadCookie)
1149 {
1150     NSContainer *This = NSURICL_THIS(iface);
1151
1152     WARN("(%p)->(%p)\n", This, aLoadCookie);
1153
1154     return This->content_listener
1155         ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie)
1156         : NS_ERROR_NOT_IMPLEMENTED;
1157 }
1158
1159 static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface,
1160         nsIURIContentListener **aParentContentListener)
1161 {
1162     NSContainer *This = NSURICL_THIS(iface);
1163
1164     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1165
1166     if(This->content_listener)
1167         nsIURIContentListener_AddRef(This->content_listener);
1168
1169     *aParentContentListener = This->content_listener;
1170     return NS_OK;
1171 }
1172
1173 static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface,
1174         nsIURIContentListener *aParentContentListener)
1175 {
1176     NSContainer *This = NSURICL_THIS(iface);
1177
1178     TRACE("(%p)->(%p)\n", This, aParentContentListener);
1179
1180     if(aParentContentListener == NSURICL(This))
1181         return NS_OK;
1182
1183     if(This->content_listener)
1184         nsIURIContentListener_Release(This->content_listener);
1185
1186     This->content_listener = aParentContentListener;
1187     if(This->content_listener)
1188         nsIURIContentListener_AddRef(This->content_listener);
1189
1190     return NS_OK;
1191 }
1192
1193 #undef NSURICL_THIS
1194
1195 static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = {
1196     nsURIContentListener_QueryInterface,
1197     nsURIContentListener_AddRef,
1198     nsURIContentListener_Release,
1199     nsURIContentListener_OnStartURIOpen,
1200     nsURIContentListener_DoContent,
1201     nsURIContentListener_IsPreferred,
1202     nsURIContentListener_CanHandleContent,
1203     nsURIContentListener_GetLoadCookie,
1204     nsURIContentListener_SetLoadCookie,
1205     nsURIContentListener_GetParentContentListener,
1206     nsURIContentListener_SetParentContentListener
1207 };
1208
1209 /**********************************************************
1210  *      nsIEmbeddinSiteWindow interface
1211  */
1212
1213 #define NSEMBWNDS_THIS(iface) DEFINE_THIS(NSContainer, EmbeddingSiteWindow, iface)
1214
1215 static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface,
1216         nsIIDRef riid, nsQIResult result)
1217 {
1218     NSContainer *This = NSEMBWNDS_THIS(iface);
1219     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1220 }
1221
1222 static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface)
1223 {
1224     NSContainer *This = NSEMBWNDS_THIS(iface);
1225     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1226 }
1227
1228 static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface)
1229 {
1230     NSContainer *This = NSEMBWNDS_THIS(iface);
1231     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1232 }
1233
1234 static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface,
1235         PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy)
1236 {
1237     NSContainer *This = NSEMBWNDS_THIS(iface);
1238     WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy);
1239     return NS_ERROR_NOT_IMPLEMENTED;
1240 }
1241
1242 static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface,
1243         PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy)
1244 {
1245     NSContainer *This = NSEMBWNDS_THIS(iface);
1246     WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy);
1247     return NS_ERROR_NOT_IMPLEMENTED;
1248 }
1249
1250 static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface)
1251 {
1252     NSContainer *This = NSEMBWNDS_THIS(iface);
1253
1254     TRACE("(%p)\n", This);
1255
1256     return nsIBaseWindow_SetFocus(This->window);
1257 }
1258
1259 static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface,
1260         PRBool *aVisibility)
1261 {
1262     NSContainer *This = NSEMBWNDS_THIS(iface);
1263
1264     TRACE("(%p)->(%p)\n", This, aVisibility);
1265
1266     *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd);
1267     return NS_OK;
1268 }
1269
1270 static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface,
1271         PRBool aVisibility)
1272 {
1273     NSContainer *This = NSEMBWNDS_THIS(iface);
1274
1275     TRACE("(%p)->(%x)\n", This, aVisibility);
1276
1277     return NS_OK;
1278 }
1279
1280 static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface,
1281         PRUnichar **aTitle)
1282 {
1283     NSContainer *This = NSEMBWNDS_THIS(iface);
1284     WARN("(%p)->(%p)\n", This, aTitle);
1285     return NS_ERROR_NOT_IMPLEMENTED;
1286 }
1287
1288 static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface,
1289         const PRUnichar *aTitle)
1290 {
1291     NSContainer *This = NSEMBWNDS_THIS(iface);
1292     WARN("(%p)->(%s)\n", This, debugstr_w(aTitle));
1293     return NS_ERROR_NOT_IMPLEMENTED;
1294 }
1295
1296 static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface,
1297         void **aSiteWindow)
1298 {
1299     NSContainer *This = NSEMBWNDS_THIS(iface);
1300
1301     TRACE("(%p)->(%p)\n", This, aSiteWindow);
1302
1303     *aSiteWindow = This->hwnd;
1304     return NS_OK;
1305 }
1306
1307 static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = {
1308     nsEmbeddingSiteWindow_QueryInterface,
1309     nsEmbeddingSiteWindow_AddRef,
1310     nsEmbeddingSiteWindow_Release,
1311     nsEmbeddingSiteWindow_SetDimensions,
1312     nsEmbeddingSiteWindow_GetDimensions,
1313     nsEmbeddingSiteWindow_SetFocus,
1314     nsEmbeddingSiteWindow_GetVisibility,
1315     nsEmbeddingSiteWindow_SetVisibility,
1316     nsEmbeddingSiteWindow_GetTitle,
1317     nsEmbeddingSiteWindow_SetTitle,
1318     nsEmbeddingSiteWindow_GetSiteWindow
1319 };
1320
1321 #define NSTOOLTIP_THIS(iface) DEFINE_THIS(NSContainer, TooltipListener, iface)
1322
1323 static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid,
1324                                                        nsQIResult result)
1325 {
1326     NSContainer *This = NSTOOLTIP_THIS(iface);
1327     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1328 }
1329
1330 static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface)
1331 {
1332     NSContainer *This = NSTOOLTIP_THIS(iface);
1333     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1334 }
1335
1336 static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface)
1337 {
1338     NSContainer *This = NSTOOLTIP_THIS(iface);
1339     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1340 }
1341
1342 static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface,
1343         PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText)
1344 {
1345     NSContainer *This = NSTOOLTIP_THIS(iface);
1346
1347     show_tooltip(This->doc, aXCoord, aYCoord, aTipText);
1348
1349     return NS_OK;
1350 }
1351
1352 static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface)
1353 {
1354     NSContainer *This = NSTOOLTIP_THIS(iface);
1355
1356     hide_tooltip(This->doc);
1357
1358     return NS_OK;
1359 }
1360
1361 #undef NSTOOLTIM_THIS
1362
1363 static const nsITooltipListenerVtbl nsTooltipListenerVtbl = {
1364     nsTooltipListener_QueryInterface,
1365     nsTooltipListener_AddRef,
1366     nsTooltipListener_Release,
1367     nsTooltipListener_OnShowTooltip,
1368     nsTooltipListener_OnHideTooltip
1369 };
1370
1371 #define NSIFACEREQ_THIS(iface) DEFINE_THIS(NSContainer, InterfaceRequestor, iface)
1372
1373 static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface,
1374                                                           nsIIDRef riid, nsQIResult result)
1375 {
1376     NSContainer *This = NSIFACEREQ_THIS(iface);
1377     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1378 }
1379
1380 static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface)
1381 {
1382     NSContainer *This = NSIFACEREQ_THIS(iface);
1383     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1384 }
1385
1386 static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface)
1387 {
1388     NSContainer *This = NSIFACEREQ_THIS(iface);
1389     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1390 }
1391
1392 static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface,
1393                                                         nsIIDRef riid, nsQIResult result)
1394 {
1395     NSContainer *This = NSIFACEREQ_THIS(iface);
1396
1397     if(IsEqualGUID(&IID_nsIDOMWindow, riid)) {
1398         TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result);
1399         return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result);
1400     }
1401
1402     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1403 }
1404
1405 #undef NSIFACEREQ_THIS
1406
1407 static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = {
1408     nsInterfaceRequestor_QueryInterface,
1409     nsInterfaceRequestor_AddRef,
1410     nsInterfaceRequestor_Release,
1411     nsInterfaceRequestor_GetInterface
1412 };
1413
1414 #define NSWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, WeakReference, iface)
1415
1416 static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface,
1417         nsIIDRef riid, nsQIResult result)
1418 {
1419     NSContainer *This = NSWEAKREF_THIS(iface);
1420     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1421 }
1422
1423 static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface)
1424 {
1425     NSContainer *This = NSWEAKREF_THIS(iface);
1426     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1427 }
1428
1429 static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface)
1430 {
1431     NSContainer *This = NSWEAKREF_THIS(iface);
1432     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1433 }
1434
1435 static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface,
1436         const nsIID *riid, void **result)
1437 {
1438     NSContainer *This = NSWEAKREF_THIS(iface);
1439     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1440 }
1441
1442 #undef NSWEAKREF_THIS
1443
1444 static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = {
1445     nsWeakReference_QueryInterface,
1446     nsWeakReference_AddRef,
1447     nsWeakReference_Release,
1448     nsWeakReference_QueryReferent
1449 };
1450
1451 #define NSSUPWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, SupportsWeakReference, iface)
1452
1453 static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface,
1454         nsIIDRef riid, nsQIResult result)
1455 {
1456     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1457     return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result);
1458 }
1459
1460 static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface)
1461 {
1462     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1463     return nsIWebBrowserChrome_AddRef(NSWBCHROME(This));
1464 }
1465
1466 static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface)
1467 {
1468     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1469     return nsIWebBrowserChrome_Release(NSWBCHROME(This));
1470 }
1471
1472 static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface,
1473         nsIWeakReference **_retval)
1474 {
1475     NSContainer *This = NSSUPWEAKREF_THIS(iface);
1476
1477     TRACE("(%p)->(%p)\n", This, _retval);
1478
1479     nsIWeakReference_AddRef(NSWEAKREF(This));
1480     *_retval = NSWEAKREF(This);
1481     return NS_OK;
1482 }
1483
1484 #undef NSWEAKREF_THIS
1485
1486 static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = {
1487     nsSupportsWeakReference_QueryInterface,
1488     nsSupportsWeakReference_AddRef,
1489     nsSupportsWeakReference_Release,
1490     nsSupportsWeakReference_GetWeakReference
1491 };
1492
1493
1494 NSContainer *NSContainer_Create(HTMLDocument *doc, NSContainer *parent)
1495 {
1496     nsIWebBrowserSetup *wbsetup;
1497     nsIScrollable *scrollable;
1498     NSContainer *ret;
1499     nsresult nsres;
1500
1501     if(!load_gecko())
1502         return NULL;
1503
1504     ret = mshtml_alloc(sizeof(NSContainer));
1505
1506     ret->lpWebBrowserChromeVtbl      = &nsWebBrowserChromeVtbl;
1507     ret->lpContextMenuListenerVtbl   = &nsContextMenuListenerVtbl;
1508     ret->lpURIContentListenerVtbl    = &nsURIContentListenerVtbl;
1509     ret->lpEmbeddingSiteWindowVtbl   = &nsEmbeddingSiteWindowVtbl;
1510     ret->lpTooltipListenerVtbl       = &nsTooltipListenerVtbl;
1511     ret->lpInterfaceRequestorVtbl    = &nsInterfaceRequestorVtbl;
1512     ret->lpWeakReferenceVtbl         = &nsWeakReferenceVtbl;
1513     ret->lpSupportsWeakReferenceVtbl = &nsSupportsWeakReferenceVtbl;
1514
1515     ret->doc = doc;
1516     ret->ref = 1;
1517     ret->bscallback = NULL;
1518     ret->content_listener = NULL;
1519     ret->editor_controller = NULL;
1520     ret->editor = NULL;
1521
1522     if(parent)
1523         nsIWebBrowserChrome_AddRef(NSWBCHROME(parent));
1524     ret->parent = parent;
1525
1526     nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID,
1527             NULL, &IID_nsIWebBrowser, (void**)&ret->webbrowser);
1528     if(NS_FAILED(nsres))
1529         ERR("Creating WebBrowser failed: %08x\n", nsres);
1530
1531     nsres = nsIWebBrowser_SetContainerWindow(ret->webbrowser, NSWBCHROME(ret));
1532     if(NS_FAILED(nsres))
1533         ERR("SetContainerWindow failed: %08x\n", nsres);
1534
1535     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIBaseWindow,
1536             (void**)&ret->window);
1537     if(NS_FAILED(nsres))
1538         ERR("Could not get nsIBaseWindow interface: %08x\n", nsres);
1539
1540     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserSetup,
1541                                          (void**)&wbsetup);
1542     if(NS_SUCCEEDED(nsres)) {
1543         nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, TRUE);
1544         nsIWebBrowserSetup_Release(wbsetup);
1545         if(NS_FAILED(nsres))
1546             ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres);
1547     }else {
1548         ERR("Could not get nsIWebBrowserSetup interface\n");
1549     }
1550
1551     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebNavigation,
1552             (void**)&ret->navigation);
1553     if(NS_FAILED(nsres))
1554         ERR("Could not get nsIWebNavigation interface: %08x\n", nsres);
1555
1556     nsres = nsIWebBrowserFocus_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserFocus,
1557             (void**)&ret->focus);
1558     if(NS_FAILED(nsres))
1559         ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres);
1560
1561     if(!nscontainer_class)
1562         register_nscontainer_class();
1563
1564     ret->hwnd = CreateWindowExW(0, wszNsContainer, NULL,
1565             WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100,
1566             GetDesktopWindow(), NULL, hInst, ret);
1567
1568     nsres = nsIBaseWindow_InitWindow(ret->window, ret->hwnd, NULL, 0, 0, 100, 100);
1569     if(NS_SUCCEEDED(nsres)) {
1570         nsres = nsIBaseWindow_Create(ret->window);
1571         if(NS_FAILED(nsres))
1572             WARN("Creating window failed: %08x\n", nsres);
1573
1574         nsIBaseWindow_SetVisibility(ret->window, FALSE);
1575         nsIBaseWindow_SetEnabled(ret->window, FALSE);
1576     }else {
1577         ERR("InitWindow failed: %08x\n", nsres);
1578     }
1579
1580     nsres = nsIWebBrowser_SetParentURIContentListener(ret->webbrowser, NSURICL(ret));
1581     if(NS_FAILED(nsres))
1582         ERR("SetParentURIContentListener failed: %08x\n", nsres);
1583
1584     init_nsevents(ret);
1585
1586     nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIScrollable, (void**)&scrollable);
1587     if(NS_SUCCEEDED(nsres)) {
1588         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1589                 ScrollOrientation_Y, Scrollbar_Always);
1590         if(NS_FAILED(nsres))
1591             ERR("Could not set default Y scrollbar prefs: %08x\n", nsres);
1592
1593         nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable,
1594                 ScrollOrientation_X, Scrollbar_Auto);
1595         if(NS_FAILED(nsres))
1596             ERR("Could not set default X scrollbar prefs: %08x\n", nsres);
1597
1598         nsIScrollable_Release(scrollable);
1599     }else {
1600         ERR("Could not get nsIScrollable: %08x\n", nsres);
1601     }
1602
1603     return ret;
1604 }
1605
1606 void NSContainer_Release(NSContainer *This)
1607 {
1608     TRACE("(%p)\n", This);
1609
1610     ShowWindow(This->hwnd, SW_HIDE);
1611     SetParent(This->hwnd, NULL);
1612
1613     nsIBaseWindow_SetVisibility(This->window, FALSE);
1614     nsIBaseWindow_Destroy(This->window);
1615
1616     nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL);
1617
1618     nsIWebBrowser_Release(This->webbrowser);
1619     This->webbrowser = NULL;
1620
1621     nsIWebNavigation_Release(This->navigation);
1622     This->navigation = NULL;
1623
1624     nsIBaseWindow_Release(This->window);
1625     This->window = NULL;
1626
1627     nsIWebBrowserFocus_Release(This->focus);
1628     This->focus = NULL;
1629
1630     if(This->editor_controller) {
1631         nsIController_Release(This->editor_controller);
1632         This->editor_controller = NULL;
1633     }
1634
1635     if(This->editor) {
1636         nsIEditor_Release(This->editor);
1637         This->editor = NULL;
1638     }
1639
1640     if(This->content_listener) {
1641         nsIURIContentListener_Release(This->content_listener);
1642         This->content_listener = NULL;
1643     }
1644
1645     if(This->hwnd) {
1646         DestroyWindow(This->hwnd);
1647         This->hwnd = NULL;
1648     }
1649
1650     nsIWebBrowserChrome_Release(NSWBCHROME(This));
1651 }