/* * Copyright 2005-2007 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include #define COBJMACROS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "winreg.h" #include "ole2.h" #include "wine/debug.h" #include "wine/unicode.h" #include "mshtml_private.h" WINE_DEFAULT_DEBUG_CHANNEL(mshtml); WINE_DECLARE_DEBUG_CHANNEL(gecko); #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1" #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1" #define NS_PROFILE_CONTRACTID "@mozilla.org/profile/manager;1" #define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1" #define NS_STRINGSTREAM_CONTRACTID "@mozilla.org/io/string-input-stream;1" #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1" #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html" #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1" #define NS_ARRAY_CONTRACTID "@mozilla.org/array;1" #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1" #define APPSTARTUP_TOPIC "app-startup" #define PR_UINT32_MAX 0xffffffff struct nsCStringContainer { void *v; void *d1; PRUint32 d2; void *d3; }; static nsresult (*NS_InitXPCOM2)(nsIServiceManager**,void*,void*); static nsresult (*NS_ShutdownXPCOM)(nsIServiceManager*); static nsresult (*NS_GetComponentRegistrar)(nsIComponentRegistrar**); static nsresult (*NS_StringContainerInit)(nsStringContainer*); static nsresult (*NS_CStringContainerInit)(nsCStringContainer*); static nsresult (*NS_StringContainerFinish)(nsStringContainer*); static nsresult (*NS_CStringContainerFinish)(nsCStringContainer*); static nsresult (*NS_StringSetData)(nsAString*,const PRUnichar*,PRUint32); static nsresult (*NS_CStringSetData)(nsACString*,const char*,PRUint32); static nsresult (*NS_NewLocalFile)(const nsAString*,PRBool,nsIFile**); static PRUint32 (*NS_StringGetData)(const nsAString*,const PRUnichar **,PRBool*); static PRUint32 (*NS_CStringGetData)(const nsACString*,const char**,PRBool*); static HINSTANCE hXPCOM = NULL; static nsIServiceManager *pServMgr = NULL; static nsIComponentManager *pCompMgr = NULL; static nsIMemory *nsmem = NULL; static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0}; static ATOM nscontainer_class; #define WM_RESETFOCUS_HACK WM_USER+600 static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { NSContainer *This; nsresult nsres; static const WCHAR wszTHIS[] = {'T','H','I','S',0}; if(msg == WM_CREATE) { This = *(NSContainer**)lParam; SetPropW(hwnd, wszTHIS, This); }else { This = GetPropW(hwnd, wszTHIS); } switch(msg) { case WM_SIZE: TRACE("(%p)->(WM_SIZE)\n", This); nsres = nsIBaseWindow_SetSize(This->window, LOWORD(lParam), HIWORD(lParam), TRUE); if(NS_FAILED(nsres)) WARN("SetSize failed: %08x\n", nsres); break; case WM_RESETFOCUS_HACK: /* * FIXME * Gecko grabs focus in edit mode and some apps don't like it. * We should somehow prevent grabbing focus. */ TRACE("WM_RESETFOCUS_HACK\n"); if(This->reset_focus) { SetFocus(This->reset_focus); This->reset_focus = NULL; if(This->doc) This->doc->focus = FALSE; } } return DefWindowProcW(hwnd, msg, wParam, lParam); } static void register_nscontainer_class(void) { static WNDCLASSEXW wndclass = { sizeof(WNDCLASSEXW), CS_DBLCLKS, nsembed_proc, 0, 0, NULL, NULL, NULL, NULL, NULL, wszNsContainer, NULL, }; wndclass.hInstance = hInst; nscontainer_class = RegisterClassExW(&wndclass); } static void set_environment(LPCWSTR gre_path) { WCHAR path_env[MAX_PATH], buf[20]; int len, debug_level = 0; static const WCHAR pathW[] = {'P','A','T','H',0}; static const WCHAR warnW[] = {'w','a','r','n',0}; static const WCHAR xpcom_debug_breakW[] = {'X','P','C','O','M','_','D','E','B','U','G','_','B','R','E','A','K',0}; static const WCHAR nspr_log_modulesW[] = {'N','S','P','R','_','L','O','G','_','M','O','D','U','L','E','S',0}; static const WCHAR debug_formatW[] = {'a','l','l',':','%','d',0}; /* We have to modify PATH as XPCOM loads other DLLs from this directory. */ GetEnvironmentVariableW(pathW, path_env, sizeof(path_env)/sizeof(WCHAR)); len = strlenW(path_env); path_env[len++] = ';'; strcpyW(path_env+len, gre_path); SetEnvironmentVariableW(pathW, path_env); SetEnvironmentVariableW(xpcom_debug_breakW, warnW); if(TRACE_ON(gecko)) debug_level = 5; else if(WARN_ON(gecko)) debug_level = 3; else if(ERR_ON(gecko)) debug_level = 2; sprintfW(buf, debug_formatW, debug_level); SetEnvironmentVariableW(nspr_log_modulesW, buf); } static BOOL load_xpcom(const PRUnichar *gre_path) { static const WCHAR strXPCOM[] = {'x','p','c','o','m','.','d','l','l',0}; TRACE("(%s)\n", debugstr_w(gre_path)); set_environment(gre_path); hXPCOM = LoadLibraryW(strXPCOM); if(!hXPCOM) { WARN("Could not load XPCOM: %d\n", GetLastError()); return FALSE; } #define NS_DLSYM(func) \ func = (void *)GetProcAddress(hXPCOM, #func); \ if(!func) \ ERR("Could not GetProcAddress(" #func ") failed\n") NS_DLSYM(NS_InitXPCOM2); NS_DLSYM(NS_ShutdownXPCOM); NS_DLSYM(NS_GetComponentRegistrar); NS_DLSYM(NS_StringContainerInit); NS_DLSYM(NS_CStringContainerInit); NS_DLSYM(NS_StringContainerFinish); NS_DLSYM(NS_CStringContainerFinish); NS_DLSYM(NS_StringSetData); NS_DLSYM(NS_CStringSetData); NS_DLSYM(NS_NewLocalFile); NS_DLSYM(NS_StringGetData); NS_DLSYM(NS_CStringGetData); #undef NS_DLSYM return TRUE; } static BOOL check_version(LPCWSTR gre_path, const char *version_string) { WCHAR file_name[MAX_PATH]; char version[128]; DWORD read=0; HANDLE hfile; static const WCHAR wszVersion[] = {'\\','V','E','R','S','I','O','N',0}; strcpyW(file_name, gre_path); strcatW(file_name, wszVersion); hfile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hfile == INVALID_HANDLE_VALUE) { ERR("Could not open VERSION file\n"); return FALSE; } ReadFile(hfile, version, sizeof(version), &read, NULL); version[read] = 0; CloseHandle(hfile); TRACE("%s\n", debugstr_a(version)); if(strcmp(version, version_string)) { ERR("Unexpected version %s, expected %s\n", debugstr_a(version), debugstr_a(version_string)); return FALSE; } return TRUE; } static BOOL load_wine_gecko_v(PRUnichar *gre_path, HKEY mshtml_key, const char *version, const char *version_string) { DWORD res, type, size = MAX_PATH; HKEY hkey = mshtml_key; static const WCHAR wszGeckoPath[] = {'G','e','c','k','o','P','a','t','h',0}; if(version) { /* @@ Wine registry key: HKCU\Software\Wine\MSHTML\ */ res = RegOpenKeyA(mshtml_key, version, &hkey); if(res != ERROR_SUCCESS) return FALSE; } res = RegQueryValueExW(hkey, wszGeckoPath, NULL, &type, (LPBYTE)gre_path, &size); if(hkey != mshtml_key) RegCloseKey(hkey); if(res != ERROR_SUCCESS || type != REG_SZ) return FALSE; if(!check_version(gre_path, version_string)) return FALSE; return load_xpcom(gre_path); } static BOOL load_wine_gecko(PRUnichar *gre_path) { HKEY hkey; DWORD res; BOOL ret; static const WCHAR wszMshtmlKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e', '\\','M','S','H','T','M','L',0}; /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */ res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey); if(res != ERROR_SUCCESS) return FALSE; ret = load_wine_gecko_v(gre_path, hkey, GECKO_VERSION, GECKO_VERSION_STRING); RegCloseKey(hkey); return ret; } static void set_lang(nsIPrefBranch *pref) { char langs[100]; DWORD res, size, type; HKEY hkey; nsresult nsres; static const WCHAR international_keyW[] = {'S','o','f','t','w','a','r','e', '\\','M','i','c','r','o','s','o','f','t', '\\','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r', '\\','I','n','t','e','r','n','a','t','i','o','n','a','l',0}; res = RegOpenKeyW(HKEY_CURRENT_USER, international_keyW, &hkey); if(res != ERROR_SUCCESS) return; size = sizeof(langs); res = RegQueryValueExA(hkey, "AcceptLanguage", 0, &type, (LPBYTE)langs, &size); RegCloseKey(hkey); if(res != ERROR_SUCCESS || type != REG_SZ) return; TRACE("Setting lang %s\n", debugstr_a(langs)); nsres = nsIPrefBranch_SetCharPref(pref, "intl.accept_languages", langs); if(NS_FAILED(nsres)) ERR("SetCharPref failed: %08x\n", nsres); } static void set_proxy(nsIPrefBranch *pref) { char proxy[512]; char * proxy_port; int proxy_port_num; DWORD enabled = 0, res, size, type; HKEY hkey; nsresult nsres; static const WCHAR proxy_keyW[] = {'S','o','f','t','w','a','r','e', '\\','M','i','c','r','o','s','o','f','t', '\\','W','i','n','d','o','w','s', '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0}; res = RegOpenKeyW(HKEY_CURRENT_USER, proxy_keyW, &hkey); if(res != ERROR_SUCCESS) return; size = sizeof(enabled); res = RegQueryValueExA(hkey, "ProxyEnable", 0, &type, (LPBYTE)&enabled, &size); if(res != ERROR_SUCCESS || type != REG_DWORD || enabled == 0) { RegCloseKey(hkey); return; } size = sizeof(proxy); res = RegQueryValueExA(hkey, "ProxyServer", 0, &type, (LPBYTE)proxy, &size); RegCloseKey(hkey); if(res != ERROR_SUCCESS || type != REG_SZ) return; proxy_port = strchr(proxy, ':'); if (!proxy_port) return; *proxy_port = 0; proxy_port_num = atoi(proxy_port + 1); TRACE("Setting proxy to %s, port %d\n", debugstr_a(proxy), proxy_port_num); nsres = nsIPrefBranch_SetIntPref(pref, "network.proxy.type", 1); if(NS_FAILED(nsres)) ERR("SetIntPref network.proxy.type failed: %08x\n", nsres); nsres = nsIPrefBranch_SetCharPref(pref, "network.proxy.http", proxy); if(NS_FAILED(nsres)) ERR("SetCharPref network.proxy.http failed: %08x\n", nsres); nsres = nsIPrefBranch_SetIntPref(pref, "network.proxy.http_port", proxy_port_num); if(NS_FAILED(nsres)) ERR("SetIntPref network.proxy.http_port failed: %08x\n", nsres); nsres = nsIPrefBranch_SetCharPref(pref, "network.proxy.ssl", proxy); if(NS_FAILED(nsres)) ERR("SetCharPref network.proxy.ssl failed: %08x\n", nsres); nsres = nsIPrefBranch_SetIntPref(pref, "network.proxy.ssl_port", proxy_port_num); if(NS_FAILED(nsres)) ERR("SetIntPref network.proxy.ssl_port failed: %08x\n", nsres); } static void set_bool_pref(nsIPrefBranch *pref, const char *pref_name, BOOL val) { nsresult nsres; nsres = nsIPrefBranch_SetBoolPref(pref, pref_name, val); if(NS_FAILED(nsres)) ERR("Could not set pref %s\n", debugstr_a(pref_name)); } static void set_preferences(void) { nsIPrefBranch *pref; nsresult nsres; nsres = nsIServiceManager_GetServiceByContractID(pServMgr, NS_PREFERENCES_CONTRACTID, &IID_nsIPrefBranch, (void**)&pref); if(NS_FAILED(nsres)) { ERR("Could not get preference service: %08x\n", nsres); return; } set_lang(pref); set_proxy(pref); set_bool_pref(pref, "security.warn_entering_secure", FALSE); set_bool_pref(pref, "security.warn_submit_insecure", FALSE); nsIPrefBranch_Release(pref); } static BOOL init_xpcom(const PRUnichar *gre_path) { nsresult nsres; nsIObserver *pStartNotif; nsIComponentRegistrar *registrar = NULL; nsAString path; nsIFile *gre_dir; nsAString_Init(&path, gre_path); nsres = NS_NewLocalFile(&path, FALSE, &gre_dir); nsAString_Finish(&path); if(NS_FAILED(nsres)) { ERR("NS_NewLocalFile failed: %08x\n", nsres); FreeLibrary(hXPCOM); return FALSE; } nsres = NS_InitXPCOM2(&pServMgr, gre_dir, NULL); if(NS_FAILED(nsres)) { ERR("NS_InitXPCOM2 failed: %08x\n", nsres); FreeLibrary(hXPCOM); return FALSE; } nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr); if(NS_FAILED(nsres)) ERR("Could not get nsIComponentManager: %08x\n", nsres); nsres = NS_GetComponentRegistrar(®istrar); if(NS_SUCCEEDED(nsres)) { nsres = nsIComponentRegistrar_AutoRegister(registrar, NULL); if(NS_FAILED(nsres)) ERR("AutoRegister(NULL) failed: %08x\n", nsres); init_nsio(pCompMgr, registrar); }else { ERR("NS_GetComponentRegistrar failed: %08x\n", nsres); } nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_APPSTARTUPNOTIFIER_CONTRACTID, NULL, &IID_nsIObserver, (void**)&pStartNotif); if(NS_SUCCEEDED(nsres)) { nsres = nsIObserver_Observe(pStartNotif, NULL, APPSTARTUP_TOPIC, NULL); if(NS_FAILED(nsres)) ERR("Observe failed: %08x\n", nsres); nsIObserver_Release(pStartNotif); }else { ERR("could not get appstartup-notifier: %08x\n", nsres); } set_preferences(); nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_MEMORY_CONTRACTID, NULL, &IID_nsIMemory, (void**)&nsmem); if(NS_FAILED(nsres)) ERR("Could not get nsIMemory: %08x\n", nsres); if(registrar) { register_nsservice(registrar, pServMgr); nsIComponentRegistrar_Release(registrar); } return TRUE; } static CRITICAL_SECTION cs_load_gecko; static CRITICAL_SECTION_DEBUG cs_load_gecko_dbg = { 0, 0, &cs_load_gecko, { &cs_load_gecko_dbg.ProcessLocksList, &cs_load_gecko_dbg.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": load_gecko") } }; static CRITICAL_SECTION cs_load_gecko = { &cs_load_gecko_dbg, -1, 0, 0, 0, 0 }; BOOL load_gecko(BOOL silent) { PRUnichar gre_path[MAX_PATH]; BOOL ret = FALSE; static DWORD loading_thread; TRACE("()\n"); /* load_gecko may be called recursively */ if(loading_thread == GetCurrentThreadId()) return pCompMgr != NULL; EnterCriticalSection(&cs_load_gecko); if(!loading_thread) { loading_thread = GetCurrentThreadId(); if(load_wine_gecko(gre_path) || (install_wine_gecko(silent) && load_wine_gecko(gre_path))) ret = init_xpcom(gre_path); else MESSAGE("Could not load wine-gecko. HTML rendering will be disabled.\n"); }else { ret = pCompMgr != NULL; } LeaveCriticalSection(&cs_load_gecko); return ret; } void *nsalloc(size_t size) { return nsIMemory_Alloc(nsmem, size); } void nsfree(void *mem) { nsIMemory_Free(nsmem, mem); } void nsACString_Init(nsACString *str, const char *data) { NS_CStringContainerInit(str); if(data) nsACString_SetData(str, data); } void nsACString_SetData(nsACString *str, const char *data) { NS_CStringSetData(str, data, PR_UINT32_MAX); } PRUint32 nsACString_GetData(const nsACString *str, const char **data) { return NS_CStringGetData(str, data, NULL); } void nsACString_Finish(nsACString *str) { NS_CStringContainerFinish(str); } void nsAString_Init(nsAString *str, const PRUnichar *data) { NS_StringContainerInit(str); if(data) nsAString_SetData(str, data); } void nsAString_SetData(nsAString *str, const PRUnichar *data) { NS_StringSetData(str, data, PR_UINT32_MAX); } PRUint32 nsAString_GetData(const nsAString *str, const PRUnichar **data) { return NS_StringGetData(str, data, NULL); } void nsAString_Finish(nsAString *str) { NS_StringContainerFinish(str); } nsIInputStream *create_nsstream(const char *data, PRInt32 data_len) { nsIStringInputStream *ret; nsresult nsres; if(!pCompMgr) return NULL; nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_STRINGSTREAM_CONTRACTID, NULL, &IID_nsIStringInputStream, (void**)&ret); if(NS_FAILED(nsres)) { ERR("Could not get nsIStringInputStream\n"); return NULL; } nsres = nsIStringInputStream_SetData(ret, data, data_len); if(NS_FAILED(nsres)) { ERR("AdoptData failed: %08x\n", nsres); nsIStringInputStream_Release(ret); return NULL; } return (nsIInputStream*)ret; } nsICommandParams *create_nscommand_params(void) { nsICommandParams *ret = NULL; nsresult nsres; if(!pCompMgr) return NULL; nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_COMMANDPARAMS_CONTRACTID, NULL, &IID_nsICommandParams, (void**)&ret); if(NS_FAILED(nsres)) ERR("Could not get nsICommandParams\n"); return ret; } nsresult get_nsinterface(nsISupports *iface, REFIID riid, void **ppv) { nsIInterfaceRequestor *iface_req; nsresult nsres; nsres = nsISupports_QueryInterface(iface, &IID_nsIInterfaceRequestor, (void**)&iface_req); if(NS_FAILED(nsres)) return nsres; nsres = nsIInterfaceRequestor_GetInterface(iface_req, riid, ppv); nsIInterfaceRequestor_Release(iface_req); return nsres; } static HRESULT nsnode_to_nsstring_rec(nsIContentSerializer *serializer, nsIDOMNode *nsnode, nsAString *str) { nsIDOMNodeList *node_list = NULL; PRBool has_children = FALSE; PRUint16 type; nsresult nsres; nsIDOMNode_HasChildNodes(nsnode, &has_children); nsres = nsIDOMNode_GetNodeType(nsnode, &type); if(NS_FAILED(nsres)) { ERR("GetType failed: %08x\n", nsres); return E_FAIL; } switch(type) { case ELEMENT_NODE: { nsIDOMElement *nselem; nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMElement, (void**)&nselem); nsIContentSerializer_AppendElementStart(serializer, nselem, nselem, str); nsIDOMElement_Release(nselem); break; } case TEXT_NODE: { nsIDOMText *nstext; nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMText, (void**)&nstext); nsIContentSerializer_AppendText(serializer, nstext, 0, -1, str); nsIDOMText_Release(nstext); break; } case COMMENT_NODE: { nsIDOMComment *nscomment; nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMComment, (void**)&nscomment); nsres = nsIContentSerializer_AppendComment(serializer, nscomment, 0, -1, str); break; } case DOCUMENT_NODE: { nsIDOMDocument *nsdoc; nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMDocument, (void**)&nsdoc); nsIContentSerializer_AppendDocumentStart(serializer, nsdoc, str); nsIDOMDocument_Release(nsdoc); break; } case DOCUMENT_TYPE_NODE: WARN("Ignoring DOCUMENT_TYPE_NODE\n"); break; case DOCUMENT_FRAGMENT_NODE: break; default: FIXME("Unhandled type %u\n", type); } if(has_children) { PRUint32 child_cnt, i; nsIDOMNode *child_node; nsIDOMNode_GetChildNodes(nsnode, &node_list); nsIDOMNodeList_GetLength(node_list, &child_cnt); for(i=0; ieditor) { nsIEditor_Release(This->editor); This->editor = NULL; } if(This->editor_controller) { nsIController_Release(This->editor_controller); This->editor_controller = NULL; } nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession, (void**)&editing_session); if(NS_FAILED(nsres)) { ERR("Could not get nsIEditingSession: %08x\n", nsres); return; } nsres = nsIEditingSession_GetEditorForWindow(editing_session, This->doc->window->nswindow, &This->editor); nsIEditingSession_Release(editing_session); if(NS_FAILED(nsres)) { ERR("Could not get editor: %08x\n", nsres); return; } nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_EDITORCONTROLLER_CONTRACTID, NULL, &IID_nsIControllerContext, (void**)&ctrlctx); if(NS_SUCCEEDED(nsres)) { nsres = nsIControllerContext_SetCommandContext(ctrlctx, (nsISupports *)This->editor); if(NS_FAILED(nsres)) ERR("SetCommandContext failed: %08x\n", nsres); nsres = nsIControllerContext_QueryInterface(ctrlctx, &IID_nsIController, (void**)&This->editor_controller); nsIControllerContext_Release(ctrlctx); if(NS_FAILED(nsres)) ERR("Could not get nsIController interface: %08x\n", nsres); }else { ERR("Could not create edit controller: %08x\n", nsres); } } void set_ns_editmode(NSContainer *This) { nsIEditingSession *editing_session = NULL; nsIURIContentListener *listener = NULL; nsIDOMWindow *dom_window = NULL; nsresult nsres; nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsIEditingSession, (void**)&editing_session); if(NS_FAILED(nsres)) { ERR("Could not get nsIEditingSession: %08x\n", nsres); return; } nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window); if(NS_FAILED(nsres)) { ERR("Could not get content DOM window: %08x\n", nsres); nsIEditingSession_Release(editing_session); return; } nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE, TRUE, TRUE); nsIEditingSession_Release(editing_session); nsIDOMWindow_Release(dom_window); if(NS_FAILED(nsres)) { ERR("MakeWindowEditable failed: %08x\n", nsres); return; } /* MakeWindowEditable changes WebBrowser's parent URI content listener. * It seams to be a bug in Gecko. To workaround it we set our content * listener again and Gecko's one as its parent. */ nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener); nsIURIContentListener_SetParentContentListener(NSURICL(This), listener); nsIURIContentListener_Release(listener); nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This)); } void update_nsdocument(HTMLDocument *doc) { nsIDOMHTMLDocument *nsdoc; nsIDOMDocument *nsdomdoc; nsresult nsres; if(!doc->nscontainer || !doc->nscontainer->navigation) return; nsres = nsIWebNavigation_GetDocument(doc->nscontainer->navigation, &nsdomdoc); if(NS_FAILED(nsres) || !nsdomdoc) { ERR("GetDocument failed: %08x\n", nsres); return; } nsres = nsIDOMDocument_QueryInterface(nsdomdoc, &IID_nsIDOMHTMLDocument, (void**)&nsdoc); nsIDOMDocument_Release(nsdomdoc); if(NS_FAILED(nsres)) { ERR("Could not get nsIDOMHTMLDocument iface: %08x\n", nsres); return; } if(nsdoc == doc->nsdoc) { nsIDOMHTMLDocument_Release(nsdoc); return; } if(doc->nsdoc) { remove_mutation_observer(doc->nscontainer, doc->nsdoc); nsIDOMHTMLDocument_Release(doc->nsdoc); } doc->nsdoc = nsdoc; if(nsdoc) set_mutation_observer(doc->nscontainer, nsdoc); } void close_gecko(void) { TRACE("()\n"); release_nsio(); if(pCompMgr) nsIComponentManager_Release(pCompMgr); if(pServMgr) nsIServiceManager_Release(pServMgr); if(nsmem) nsIMemory_Release(nsmem); /* Gecko doesn't really support being unloaded */ /* if (hXPCOM) FreeLibrary(hXPCOM); */ } /********************************************************** * nsIWebBrowserChrome interface */ #define NSWBCHROME_THIS(iface) DEFINE_THIS(NSContainer, WebBrowserChrome, iface) static nsresult NSAPI nsWebBrowserChrome_QueryInterface(nsIWebBrowserChrome *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSWBCHROME_THIS(iface); *result = NULL; if(IsEqualGUID(&IID_nsISupports, riid)) { TRACE("(%p)->(IID_nsISupports, %p)\n", This, result); *result = NSWBCHROME(This); }else if(IsEqualGUID(&IID_nsIWebBrowserChrome, riid)) { TRACE("(%p)->(IID_nsIWebBrowserChrome, %p)\n", This, result); *result = NSWBCHROME(This); }else if(IsEqualGUID(&IID_nsIContextMenuListener, riid)) { TRACE("(%p)->(IID_nsIContextMenuListener, %p)\n", This, result); *result = NSCML(This); }else if(IsEqualGUID(&IID_nsIURIContentListener, riid)) { TRACE("(%p)->(IID_nsIURIContentListener %p)\n", This, result); *result = NSURICL(This); }else if(IsEqualGUID(&IID_nsIEmbeddingSiteWindow, riid)) { TRACE("(%p)->(IID_nsIEmbeddingSiteWindow %p)\n", This, result); *result = NSEMBWNDS(This); }else if(IsEqualGUID(&IID_nsITooltipListener, riid)) { TRACE("(%p)->(IID_nsITooltipListener %p)\n", This, result); *result = NSTOOLTIP(This); }else if(IsEqualGUID(&IID_nsIInterfaceRequestor, riid)) { TRACE("(%p)->(IID_nsIInterfaceRequestor %p)\n", This, result); *result = NSIFACEREQ(This); }else if(IsEqualGUID(&IID_nsIWeakReference, riid)) { TRACE("(%p)->(IID_nsIWeakReference %p)\n", This, result); *result = NSWEAKREF(This); }else if(IsEqualGUID(&IID_nsISupportsWeakReference, riid)) { TRACE("(%p)->(IID_nsISupportsWeakReference %p)\n", This, result); *result = NSSUPWEAKREF(This); } if(*result) { nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); return NS_OK; } TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result); return NS_NOINTERFACE; } static nsrefcnt NSAPI nsWebBrowserChrome_AddRef(nsIWebBrowserChrome *iface) { NSContainer *This = NSWBCHROME_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static nsrefcnt NSAPI nsWebBrowserChrome_Release(nsIWebBrowserChrome *iface) { NSContainer *This = NSWBCHROME_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if(!ref) { heap_free(This->event_vector); if(This->parent) nsIWebBrowserChrome_Release(NSWBCHROME(This->parent)); heap_free(This); } return ref; } static nsresult NSAPI nsWebBrowserChrome_SetStatus(nsIWebBrowserChrome *iface, PRUint32 statusType, const PRUnichar *status) { NSContainer *This = NSWBCHROME_THIS(iface); TRACE("(%p)->(%d %s)\n", This, statusType, debugstr_w(status)); /* FIXME: This hack should be removed when we'll load all pages by URLMoniker */ if(This->doc) update_nsdocument(This->doc); return NS_OK; } static nsresult NSAPI nsWebBrowserChrome_GetWebBrowser(nsIWebBrowserChrome *iface, nsIWebBrowser **aWebBrowser) { NSContainer *This = NSWBCHROME_THIS(iface); TRACE("(%p)->(%p)\n", This, aWebBrowser); if(!aWebBrowser) return NS_ERROR_INVALID_ARG; if(This->webbrowser) nsIWebBrowser_AddRef(This->webbrowser); *aWebBrowser = This->webbrowser; return S_OK; } static nsresult NSAPI nsWebBrowserChrome_SetWebBrowser(nsIWebBrowserChrome *iface, nsIWebBrowser *aWebBrowser) { NSContainer *This = NSWBCHROME_THIS(iface); TRACE("(%p)->(%p)\n", This, aWebBrowser); if(aWebBrowser != This->webbrowser) ERR("Wrong nsWebBrowser!\n"); return NS_OK; } static nsresult NSAPI nsWebBrowserChrome_GetChromeFlags(nsIWebBrowserChrome *iface, PRUint32 *aChromeFlags) { NSContainer *This = NSWBCHROME_THIS(iface); WARN("(%p)->(%p)\n", This, aChromeFlags); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_SetChromeFlags(nsIWebBrowserChrome *iface, PRUint32 aChromeFlags) { NSContainer *This = NSWBCHROME_THIS(iface); WARN("(%p)->(%08x)\n", This, aChromeFlags); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_DestroyBrowserWindow(nsIWebBrowserChrome *iface) { NSContainer *This = NSWBCHROME_THIS(iface); TRACE("(%p)\n", This); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_SizeBrowserTo(nsIWebBrowserChrome *iface, PRInt32 aCX, PRInt32 aCY) { NSContainer *This = NSWBCHROME_THIS(iface); WARN("(%p)->(%d %d)\n", This, aCX, aCY); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_ShowAsModal(nsIWebBrowserChrome *iface) { NSContainer *This = NSWBCHROME_THIS(iface); WARN("(%p)\n", This); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_IsWindowModal(nsIWebBrowserChrome *iface, PRBool *_retval) { NSContainer *This = NSWBCHROME_THIS(iface); WARN("(%p)->(%p)\n", This, _retval); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsWebBrowserChrome_ExitModalEventLoop(nsIWebBrowserChrome *iface, nsresult aStatus) { NSContainer *This = NSWBCHROME_THIS(iface); WARN("(%p)->(%08x)\n", This, aStatus); return NS_ERROR_NOT_IMPLEMENTED; } #undef NSWBCHROME_THIS static const nsIWebBrowserChromeVtbl nsWebBrowserChromeVtbl = { nsWebBrowserChrome_QueryInterface, nsWebBrowserChrome_AddRef, nsWebBrowserChrome_Release, nsWebBrowserChrome_SetStatus, nsWebBrowserChrome_GetWebBrowser, nsWebBrowserChrome_SetWebBrowser, nsWebBrowserChrome_GetChromeFlags, nsWebBrowserChrome_SetChromeFlags, nsWebBrowserChrome_DestroyBrowserWindow, nsWebBrowserChrome_SizeBrowserTo, nsWebBrowserChrome_ShowAsModal, nsWebBrowserChrome_IsWindowModal, nsWebBrowserChrome_ExitModalEventLoop }; /********************************************************** * nsIContextMenuListener interface */ #define NSCML_THIS(iface) DEFINE_THIS(NSContainer, ContextMenuListener, iface) static nsresult NSAPI nsContextMenuListener_QueryInterface(nsIContextMenuListener *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSCML_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsContextMenuListener_AddRef(nsIContextMenuListener *iface) { NSContainer *This = NSCML_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsContextMenuListener_Release(nsIContextMenuListener *iface) { NSContainer *This = NSCML_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuListener *iface, PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode) { NSContainer *This = NSCML_THIS(iface); nsIDOMMouseEvent *event; POINT pt; DWORD dwID = CONTEXT_MENU_DEFAULT; nsresult nsres; TRACE("(%p)->(%08x %p %p)\n", This, aContextFlags, aEvent, aNode); nsres = nsIDOMEvent_QueryInterface(aEvent, &IID_nsIDOMMouseEvent, (void**)&event); if(NS_FAILED(nsres)) { ERR("Could not get nsIDOMMouseEvent interface: %08x\n", nsres); return nsres; } nsIDOMMouseEvent_GetScreenX(event, &pt.x); nsIDOMMouseEvent_GetScreenY(event, &pt.y); nsIDOMMouseEvent_Release(event); switch(aContextFlags) { case CONTEXT_NONE: case CONTEXT_DOCUMENT: case CONTEXT_TEXT: dwID = CONTEXT_MENU_DEFAULT; break; case CONTEXT_IMAGE: case CONTEXT_IMAGE|CONTEXT_LINK: dwID = CONTEXT_MENU_IMAGE; break; case CONTEXT_LINK: dwID = CONTEXT_MENU_ANCHOR; break; case CONTEXT_INPUT: dwID = CONTEXT_MENU_CONTROL; break; default: FIXME("aContextFlags=%08x\n", aContextFlags); }; show_context_menu(This->doc, dwID, &pt, (IDispatch*)HTMLDOMNODE(get_node(This->doc, aNode, TRUE))); return NS_OK; } #undef NSCML_THIS static const nsIContextMenuListenerVtbl nsContextMenuListenerVtbl = { nsContextMenuListener_QueryInterface, nsContextMenuListener_AddRef, nsContextMenuListener_Release, nsContextMenuListener_OnShowContextMenu }; /********************************************************** * nsIURIContentListener interface */ #define NSURICL_THIS(iface) DEFINE_THIS(NSContainer, URIContentListener, iface) static nsresult NSAPI nsURIContentListener_QueryInterface(nsIURIContentListener *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSURICL_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsURIContentListener_AddRef(nsIURIContentListener *iface) { NSContainer *This = NSURICL_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsURIContentListener_Release(nsIURIContentListener *iface) { NSContainer *This = NSURICL_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static BOOL translate_url(HTMLDocument *doc, nsIWineURI *nsuri) { OLECHAR *new_url = NULL, *url; BOOL ret = FALSE; LPCWSTR wine_url; HRESULT hres; if(!doc->hostui) return FALSE; nsIWineURI_GetWineURL(nsuri, &wine_url); url = heap_strdupW(wine_url); hres = IDocHostUIHandler_TranslateUrl(doc->hostui, 0, url, &new_url); heap_free(url); if(hres != S_OK || !new_url) return FALSE; if(strcmpW(url, new_url)) { FIXME("TranslateUrl returned new URL %s -> %s\n", debugstr_w(url), debugstr_w(new_url)); ret = TRUE; } CoTaskMemFree(new_url); return ret; } static nsresult NSAPI nsURIContentListener_OnStartURIOpen(nsIURIContentListener *iface, nsIURI *aURI, PRBool *_retval) { NSContainer *This = NSURICL_THIS(iface); nsIWineURI *wine_uri; nsACString spec_str; const char *spec; nsresult nsres; nsACString_Init(&spec_str, NULL); nsIURI_GetSpec(aURI, &spec_str); nsACString_GetData(&spec_str, &spec); TRACE("(%p)->(%p(%s) %p)\n", This, aURI, debugstr_a(spec), _retval); nsACString_Finish(&spec_str); nsres = nsIURI_QueryInterface(aURI, &IID_nsIWineURI, (void**)&wine_uri); if(NS_FAILED(nsres)) { WARN("Could not get nsIWineURI interface: %08x\n", nsres); return NS_ERROR_NOT_IMPLEMENTED; } nsIWineURI_SetNSContainer(wine_uri, This); nsIWineURI_SetIsDocumentURI(wine_uri, TRUE); if(This->bscallback) { IMoniker *mon = get_channelbsc_mon(This->bscallback); if(mon) { LPWSTR wine_url; HRESULT hres; hres = IMoniker_GetDisplayName(mon, NULL, 0, &wine_url); if(SUCCEEDED(hres)) { nsIWineURI_SetWineURL(wine_uri, wine_url); CoTaskMemFree(wine_url); }else { WARN("GetDisplayName failed: %08x\n", hres); } IMoniker_Release(mon); } *_retval = FALSE; }else if(This->doc) { *_retval = translate_url(This->doc, wine_uri); } nsIWineURI_Release(wine_uri); return !*_retval && This->content_listener ? nsIURIContentListener_OnStartURIOpen(This->content_listener, aURI, _retval) : NS_OK; } static nsresult NSAPI nsURIContentListener_DoContent(nsIURIContentListener *iface, const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest, nsIStreamListener **aContentHandler, PRBool *_retval) { NSContainer *This = NSURICL_THIS(iface); TRACE("(%p)->(%s %x %p %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred, aRequest, aContentHandler, _retval); return This->content_listener ? nsIURIContentListener_DoContent(This->content_listener, aContentType, aIsContentPreferred, aRequest, aContentHandler, _retval) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_IsPreferred(nsIURIContentListener *iface, const char *aContentType, char **aDesiredContentType, PRBool *_retval) { NSContainer *This = NSURICL_THIS(iface); TRACE("(%p)->(%s %p %p)\n", This, debugstr_a(aContentType), aDesiredContentType, _retval); /* FIXME: Should we do something here? */ *_retval = TRUE; return This->content_listener ? nsIURIContentListener_IsPreferred(This->content_listener, aContentType, aDesiredContentType, _retval) : NS_OK; } static nsresult NSAPI nsURIContentListener_CanHandleContent(nsIURIContentListener *iface, const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType, PRBool *_retval) { NSContainer *This = NSURICL_THIS(iface); TRACE("(%p)->(%s %x %p %p)\n", This, debugstr_a(aContentType), aIsContentPreferred, aDesiredContentType, _retval); return This->content_listener ? nsIURIContentListener_CanHandleContent(This->content_listener, aContentType, aIsContentPreferred, aDesiredContentType, _retval) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_GetLoadCookie(nsIURIContentListener *iface, nsISupports **aLoadCookie) { NSContainer *This = NSURICL_THIS(iface); WARN("(%p)->(%p)\n", This, aLoadCookie); return This->content_listener ? nsIURIContentListener_GetLoadCookie(This->content_listener, aLoadCookie) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_SetLoadCookie(nsIURIContentListener *iface, nsISupports *aLoadCookie) { NSContainer *This = NSURICL_THIS(iface); WARN("(%p)->(%p)\n", This, aLoadCookie); return This->content_listener ? nsIURIContentListener_SetLoadCookie(This->content_listener, aLoadCookie) : NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsURIContentListener_GetParentContentListener(nsIURIContentListener *iface, nsIURIContentListener **aParentContentListener) { NSContainer *This = NSURICL_THIS(iface); TRACE("(%p)->(%p)\n", This, aParentContentListener); if(This->content_listener) nsIURIContentListener_AddRef(This->content_listener); *aParentContentListener = This->content_listener; return NS_OK; } static nsresult NSAPI nsURIContentListener_SetParentContentListener(nsIURIContentListener *iface, nsIURIContentListener *aParentContentListener) { NSContainer *This = NSURICL_THIS(iface); TRACE("(%p)->(%p)\n", This, aParentContentListener); if(aParentContentListener == NSURICL(This)) return NS_OK; if(This->content_listener) nsIURIContentListener_Release(This->content_listener); This->content_listener = aParentContentListener; if(This->content_listener) nsIURIContentListener_AddRef(This->content_listener); return NS_OK; } #undef NSURICL_THIS static const nsIURIContentListenerVtbl nsURIContentListenerVtbl = { nsURIContentListener_QueryInterface, nsURIContentListener_AddRef, nsURIContentListener_Release, nsURIContentListener_OnStartURIOpen, nsURIContentListener_DoContent, nsURIContentListener_IsPreferred, nsURIContentListener_CanHandleContent, nsURIContentListener_GetLoadCookie, nsURIContentListener_SetLoadCookie, nsURIContentListener_GetParentContentListener, nsURIContentListener_SetParentContentListener }; /********************************************************** * nsIEmbeddinSiteWindow interface */ #define NSEMBWNDS_THIS(iface) DEFINE_THIS(NSContainer, EmbeddingSiteWindow, iface) static nsresult NSAPI nsEmbeddingSiteWindow_QueryInterface(nsIEmbeddingSiteWindow *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSEMBWNDS_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsEmbeddingSiteWindow_AddRef(nsIEmbeddingSiteWindow *iface) { NSContainer *This = NSEMBWNDS_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsEmbeddingSiteWindow_Release(nsIEmbeddingSiteWindow *iface) { NSContainer *This = NSEMBWNDS_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static nsresult NSAPI nsEmbeddingSiteWindow_SetDimensions(nsIEmbeddingSiteWindow *iface, PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy) { NSContainer *This = NSEMBWNDS_THIS(iface); WARN("(%p)->(%08x %d %d %d %d)\n", This, flags, x, y, cx, cy); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_GetDimensions(nsIEmbeddingSiteWindow *iface, PRUint32 flags, PRInt32 *x, PRInt32 *y, PRInt32 *cx, PRInt32 *cy) { NSContainer *This = NSEMBWNDS_THIS(iface); WARN("(%p)->(%08x %p %p %p %p)\n", This, flags, x, y, cx, cy); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_SetFocus(nsIEmbeddingSiteWindow *iface) { NSContainer *This = NSEMBWNDS_THIS(iface); TRACE("(%p)\n", This); if(This->reset_focus) PostMessageW(This->hwnd, WM_RESETFOCUS_HACK, 0, 0); return nsIBaseWindow_SetFocus(This->window); } static nsresult NSAPI nsEmbeddingSiteWindow_GetVisibility(nsIEmbeddingSiteWindow *iface, PRBool *aVisibility) { NSContainer *This = NSEMBWNDS_THIS(iface); TRACE("(%p)->(%p)\n", This, aVisibility); *aVisibility = This->doc && This->doc->hwnd && IsWindowVisible(This->doc->hwnd); return NS_OK; } static nsresult NSAPI nsEmbeddingSiteWindow_SetVisibility(nsIEmbeddingSiteWindow *iface, PRBool aVisibility) { NSContainer *This = NSEMBWNDS_THIS(iface); TRACE("(%p)->(%x)\n", This, aVisibility); return NS_OK; } static nsresult NSAPI nsEmbeddingSiteWindow_GetTitle(nsIEmbeddingSiteWindow *iface, PRUnichar **aTitle) { NSContainer *This = NSEMBWNDS_THIS(iface); WARN("(%p)->(%p)\n", This, aTitle); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_SetTitle(nsIEmbeddingSiteWindow *iface, const PRUnichar *aTitle) { NSContainer *This = NSEMBWNDS_THIS(iface); WARN("(%p)->(%s)\n", This, debugstr_w(aTitle)); return NS_ERROR_NOT_IMPLEMENTED; } static nsresult NSAPI nsEmbeddingSiteWindow_GetSiteWindow(nsIEmbeddingSiteWindow *iface, void **aSiteWindow) { NSContainer *This = NSEMBWNDS_THIS(iface); TRACE("(%p)->(%p)\n", This, aSiteWindow); *aSiteWindow = This->hwnd; return NS_OK; } static const nsIEmbeddingSiteWindowVtbl nsEmbeddingSiteWindowVtbl = { nsEmbeddingSiteWindow_QueryInterface, nsEmbeddingSiteWindow_AddRef, nsEmbeddingSiteWindow_Release, nsEmbeddingSiteWindow_SetDimensions, nsEmbeddingSiteWindow_GetDimensions, nsEmbeddingSiteWindow_SetFocus, nsEmbeddingSiteWindow_GetVisibility, nsEmbeddingSiteWindow_SetVisibility, nsEmbeddingSiteWindow_GetTitle, nsEmbeddingSiteWindow_SetTitle, nsEmbeddingSiteWindow_GetSiteWindow }; #define NSTOOLTIP_THIS(iface) DEFINE_THIS(NSContainer, TooltipListener, iface) static nsresult NSAPI nsTooltipListener_QueryInterface(nsITooltipListener *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSTOOLTIP_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsTooltipListener_AddRef(nsITooltipListener *iface) { NSContainer *This = NSTOOLTIP_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsTooltipListener_Release(nsITooltipListener *iface) { NSContainer *This = NSTOOLTIP_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static nsresult NSAPI nsTooltipListener_OnShowTooltip(nsITooltipListener *iface, PRInt32 aXCoord, PRInt32 aYCoord, const PRUnichar *aTipText) { NSContainer *This = NSTOOLTIP_THIS(iface); if (This->doc) show_tooltip(This->doc, aXCoord, aYCoord, aTipText); return NS_OK; } static nsresult NSAPI nsTooltipListener_OnHideTooltip(nsITooltipListener *iface) { NSContainer *This = NSTOOLTIP_THIS(iface); if (This->doc) hide_tooltip(This->doc); return NS_OK; } #undef NSTOOLTIM_THIS static const nsITooltipListenerVtbl nsTooltipListenerVtbl = { nsTooltipListener_QueryInterface, nsTooltipListener_AddRef, nsTooltipListener_Release, nsTooltipListener_OnShowTooltip, nsTooltipListener_OnHideTooltip }; #define NSIFACEREQ_THIS(iface) DEFINE_THIS(NSContainer, InterfaceRequestor, iface) static nsresult NSAPI nsInterfaceRequestor_QueryInterface(nsIInterfaceRequestor *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSIFACEREQ_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsInterfaceRequestor_AddRef(nsIInterfaceRequestor *iface) { NSContainer *This = NSIFACEREQ_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsInterfaceRequestor_Release(nsIInterfaceRequestor *iface) { NSContainer *This = NSIFACEREQ_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static nsresult NSAPI nsInterfaceRequestor_GetInterface(nsIInterfaceRequestor *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSIFACEREQ_THIS(iface); if(IsEqualGUID(&IID_nsIDOMWindow, riid)) { TRACE("(%p)->(IID_nsIDOMWindow %p)\n", This, result); return nsIWebBrowser_GetContentDOMWindow(This->webbrowser, (nsIDOMWindow**)result); } return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } #undef NSIFACEREQ_THIS static const nsIInterfaceRequestorVtbl nsInterfaceRequestorVtbl = { nsInterfaceRequestor_QueryInterface, nsInterfaceRequestor_AddRef, nsInterfaceRequestor_Release, nsInterfaceRequestor_GetInterface }; #define NSWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, WeakReference, iface) static nsresult NSAPI nsWeakReference_QueryInterface(nsIWeakReference *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSWEAKREF_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsWeakReference_AddRef(nsIWeakReference *iface) { NSContainer *This = NSWEAKREF_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsWeakReference_Release(nsIWeakReference *iface) { NSContainer *This = NSWEAKREF_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static nsresult NSAPI nsWeakReference_QueryReferent(nsIWeakReference *iface, const nsIID *riid, void **result) { NSContainer *This = NSWEAKREF_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } #undef NSWEAKREF_THIS static const nsIWeakReferenceVtbl nsWeakReferenceVtbl = { nsWeakReference_QueryInterface, nsWeakReference_AddRef, nsWeakReference_Release, nsWeakReference_QueryReferent }; #define NSSUPWEAKREF_THIS(iface) DEFINE_THIS(NSContainer, SupportsWeakReference, iface) static nsresult NSAPI nsSupportsWeakReference_QueryInterface(nsISupportsWeakReference *iface, nsIIDRef riid, nsQIResult result) { NSContainer *This = NSSUPWEAKREF_THIS(iface); return nsIWebBrowserChrome_QueryInterface(NSWBCHROME(This), riid, result); } static nsrefcnt NSAPI nsSupportsWeakReference_AddRef(nsISupportsWeakReference *iface) { NSContainer *This = NSSUPWEAKREF_THIS(iface); return nsIWebBrowserChrome_AddRef(NSWBCHROME(This)); } static nsrefcnt NSAPI nsSupportsWeakReference_Release(nsISupportsWeakReference *iface) { NSContainer *This = NSSUPWEAKREF_THIS(iface); return nsIWebBrowserChrome_Release(NSWBCHROME(This)); } static nsresult NSAPI nsSupportsWeakReference_GetWeakReference(nsISupportsWeakReference *iface, nsIWeakReference **_retval) { NSContainer *This = NSSUPWEAKREF_THIS(iface); TRACE("(%p)->(%p)\n", This, _retval); nsIWeakReference_AddRef(NSWEAKREF(This)); *_retval = NSWEAKREF(This); return NS_OK; } #undef NSWEAKREF_THIS static const nsISupportsWeakReferenceVtbl nsSupportsWeakReferenceVtbl = { nsSupportsWeakReference_QueryInterface, nsSupportsWeakReference_AddRef, nsSupportsWeakReference_Release, nsSupportsWeakReference_GetWeakReference }; NSContainer *NSContainer_Create(HTMLDocument *doc, NSContainer *parent) { nsIWebBrowserSetup *wbsetup; nsIScrollable *scrollable; NSContainer *ret; nsresult nsres; if(!load_gecko(FALSE)) return NULL; ret = heap_alloc_zero(sizeof(NSContainer)); ret->lpWebBrowserChromeVtbl = &nsWebBrowserChromeVtbl; ret->lpContextMenuListenerVtbl = &nsContextMenuListenerVtbl; ret->lpURIContentListenerVtbl = &nsURIContentListenerVtbl; ret->lpEmbeddingSiteWindowVtbl = &nsEmbeddingSiteWindowVtbl; ret->lpTooltipListenerVtbl = &nsTooltipListenerVtbl; ret->lpInterfaceRequestorVtbl = &nsInterfaceRequestorVtbl; ret->lpWeakReferenceVtbl = &nsWeakReferenceVtbl; ret->lpSupportsWeakReferenceVtbl = &nsSupportsWeakReferenceVtbl; ret->doc = doc; ret->ref = 1; init_mutation(ret); nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID, NULL, &IID_nsIWebBrowser, (void**)&ret->webbrowser); if(NS_FAILED(nsres)) { ERR("Creating WebBrowser failed: %08x\n", nsres); heap_free(ret); return NULL; } if(parent) nsIWebBrowserChrome_AddRef(NSWBCHROME(parent)); ret->parent = parent; nsres = nsIWebBrowser_SetContainerWindow(ret->webbrowser, NSWBCHROME(ret)); if(NS_FAILED(nsres)) ERR("SetContainerWindow failed: %08x\n", nsres); nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIBaseWindow, (void**)&ret->window); if(NS_FAILED(nsres)) ERR("Could not get nsIBaseWindow interface: %08x\n", nsres); nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserSetup, (void**)&wbsetup); if(NS_SUCCEEDED(nsres)) { nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, FALSE); nsIWebBrowserSetup_Release(wbsetup); if(NS_FAILED(nsres)) ERR("SetProperty(SETUP_IS_CHROME_WRAPPER) failed: %08x\n", nsres); }else { ERR("Could not get nsIWebBrowserSetup interface\n"); } nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIWebNavigation, (void**)&ret->navigation); if(NS_FAILED(nsres)) ERR("Could not get nsIWebNavigation interface: %08x\n", nsres); nsres = nsIWebBrowserFocus_QueryInterface(ret->webbrowser, &IID_nsIWebBrowserFocus, (void**)&ret->focus); if(NS_FAILED(nsres)) ERR("Could not get nsIWebBrowserFocus interface: %08x\n", nsres); if(!nscontainer_class) register_nscontainer_class(); ret->hwnd = CreateWindowExW(0, wszNsContainer, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100, GetDesktopWindow(), NULL, hInst, ret); nsres = nsIBaseWindow_InitWindow(ret->window, ret->hwnd, NULL, 0, 0, 100, 100); if(NS_SUCCEEDED(nsres)) { nsres = nsIBaseWindow_Create(ret->window); if(NS_FAILED(nsres)) WARN("Creating window failed: %08x\n", nsres); nsIBaseWindow_SetVisibility(ret->window, FALSE); nsIBaseWindow_SetEnabled(ret->window, FALSE); }else { ERR("InitWindow failed: %08x\n", nsres); } nsres = nsIWebBrowser_SetParentURIContentListener(ret->webbrowser, NSURICL(ret)); if(NS_FAILED(nsres)) ERR("SetParentURIContentListener failed: %08x\n", nsres); init_nsevents(ret); nsres = nsIWebBrowser_QueryInterface(ret->webbrowser, &IID_nsIScrollable, (void**)&scrollable); if(NS_SUCCEEDED(nsres)) { nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_Y, Scrollbar_Always); if(NS_FAILED(nsres)) ERR("Could not set default Y scrollbar prefs: %08x\n", nsres); nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_X, Scrollbar_Auto); if(NS_FAILED(nsres)) ERR("Could not set default X scrollbar prefs: %08x\n", nsres); nsIScrollable_Release(scrollable); }else { ERR("Could not get nsIScrollable: %08x\n", nsres); } return ret; } void NSContainer_Release(NSContainer *This) { TRACE("(%p)\n", This); This->doc = NULL; ShowWindow(This->hwnd, SW_HIDE); SetParent(This->hwnd, NULL); nsIBaseWindow_SetVisibility(This->window, FALSE); nsIBaseWindow_Destroy(This->window); nsIWebBrowser_SetContainerWindow(This->webbrowser, NULL); nsIWebBrowser_Release(This->webbrowser); This->webbrowser = NULL; nsIWebNavigation_Release(This->navigation); This->navigation = NULL; nsIBaseWindow_Release(This->window); This->window = NULL; nsIWebBrowserFocus_Release(This->focus); This->focus = NULL; if(This->editor_controller) { nsIController_Release(This->editor_controller); This->editor_controller = NULL; } if(This->editor) { nsIEditor_Release(This->editor); This->editor = NULL; } if(This->content_listener) { nsIURIContentListener_Release(This->content_listener); This->content_listener = NULL; } if(This->hwnd) { DestroyWindow(This->hwnd); This->hwnd = NULL; } nsIWebBrowserChrome_Release(NSWBCHROME(This)); }