From fac88bc14a1cb3d0d50e367880d45e613dd6a896 Mon Sep 17 00:00:00 2001 From: "danm%netscape.com" Date: Sat, 17 Feb 2001 02:45:42 +0000 Subject: [PATCH] adding ability to WindowWatcher to open windows without parents. bug 67368 r=hyatt,pinkerton git-svn-id: svn://10.0.0.236/trunk@87263 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/embedding/base/Makefile.in | 4 + mozilla/embedding/base/makefile.win | 4 + .../embedding/components/build/Makefile.in | 2 +- .../embedding/components/build/makefile.win | 1 + .../windowwatcher/public/nsIWindowWatcher.idl | 53 +- .../public/nsPIWindowWatcher.idl | 19 + .../components/windowwatcher/src/Makefile.in | 3 +- .../components/windowwatcher/src/makefile.win | 1 + .../windowwatcher/src/nsWindowWatcher.cpp | 1025 ++++++++++++++++- .../windowwatcher/src/nsWindowWatcher.h | 46 +- mozilla/embedding/tests/winEmbed/makefile.win | 1 + 11 files changed, 1104 insertions(+), 55 deletions(-) diff --git a/mozilla/embedding/base/Makefile.in b/mozilla/embedding/base/Makefile.in index f3638063977..2afc8ce9410 100644 --- a/mozilla/embedding/base/Makefile.in +++ b/mozilla/embedding/base/Makefile.in @@ -25,6 +25,7 @@ VPATH = @srcdir@ MODULE = embed_base LIBRARY_NAME = embed_base_s +XPIDL_MODULE = embed_base include $(DEPTH)/config/autoconf.mk @@ -34,6 +35,9 @@ EXPORTS = \ nsEmbedAPI.h \ $(NULL) +XPIDLSRCS = nsIWindowCreator.idl \ + $(NULL) + CPPSRCS = \ nsSetupRegistry.cpp \ nsEmbedAPI.cpp \ diff --git a/mozilla/embedding/base/makefile.win b/mozilla/embedding/base/makefile.win index eef070db9bb..dfe0cb6130b 100644 --- a/mozilla/embedding/base/makefile.win +++ b/mozilla/embedding/base/makefile.win @@ -31,6 +31,10 @@ XPIDLSRCS= \ LIBRARY_NAME=baseembed_s +XPIDLSRCS = \ + .\nsIWindowCreator.idl \ + $(NULL) + CPP_OBJS= \ .\$(OBJDIR)\nsEmbedAPI.obj \ .\$(OBJDIR)\nsEmbedWin32.obj \ diff --git a/mozilla/embedding/components/build/Makefile.in b/mozilla/embedding/components/build/Makefile.in index ca9c443d947..558f4f9ab7e 100644 --- a/mozilla/embedding/components/build/Makefile.in +++ b/mozilla/embedding/components/build/Makefile.in @@ -26,7 +26,7 @@ include $(DEPTH)/config/autoconf.mk MODULE = embedcomponents LIBRARY_NAME = embedcomponents IS_COMPONENT = 1 -REQUIRES = xpcom windowwatcher +REQUIRES = js xpcom windowwatcher CPPSRCS = nsModule.cpp diff --git a/mozilla/embedding/components/build/makefile.win b/mozilla/embedding/components/build/makefile.win index b962891ce16..7919c349f4f 100644 --- a/mozilla/embedding/components/build/makefile.win +++ b/mozilla/embedding/components/build/makefile.win @@ -33,6 +33,7 @@ CPP_OBJS = \ LLIBS = \ $(LIBNSPR) \ + $(DIST)\lib\js3250.lib \ $(DIST)\lib\xpcom.lib \ $(DIST)\lib\windowwatcher_s.lib \ $(NULL) diff --git a/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl b/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl index 51bde6c9620..b42d9dbfdd0 100644 --- a/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl +++ b/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl @@ -21,8 +21,8 @@ /* nsIWindowWatcher is the keeper of Gecko/DOM Windows. It maintains -opens and closes windows, and maintains a traversable list of open -windows. +maintains a traversable list of open top-level windows, and allows +some operations on them. Usage notes: @@ -37,9 +37,8 @@ interface for doing so). claim no ownership. Since it's the nature of this service to always hold a ("weak") reference to an open window, this requirement removes a potential reference loop. It should be safe because it's a -design requirement that clients explicitly maintain |activeWindow| and -|currentWindow|, and that windows remove themselves from the service -when they are closed. +design requirement that clients explicitly maintain |activeWindow|, +and that windows remove themselves from the service when they are closed. */ #include "nsISupports.idl" @@ -47,36 +46,10 @@ when they are closed. interface nsIDOMWindow; interface nsIObserver; interface nsISimpleEnumerator; +interface nsIWindowCreator; [scriptable, uuid(002286a8-494b-43b3-8ddd-49e3fc50622b)] -/* - Subject to change without revision of CID until further notice. - -Assumptions: - - For now I'm assuming we'll use this component to track the current -"networking context." That is, the window currently being serviced by -the network libraries, and therefore the proper parent of any alerts -those libraries may need to pose. I'm not yet convinced that this will -actually work or be necessary. - The "networking context" must provide two things: an nsIDOMWindow -to provide a script context and a native window to act as a parent -for a networking dialog. This implies the nsIDOMWindow will be able -to walk up some chain to find its container native embedding window. - In fact, I believe I can always pull a JS context off that stack -of the things that people keep around when they're switching back and forth -between C++ and JS, so all I really need to create a window is a (native) -parent. - All windows must inform the Watcher when they're being closed (perhaps -automatically through the DOMWindow's destructor), so the Watcher can -trust all its windows to be real, so there's no need for the Watcher to -addref any of its windows. This means, for instance, that setCurrentContext -won't cause a leak if you don't unset it. It would be an error to fail -to set the current context before getting into a situation where one -might be necessary. -*/ - interface nsIWindowWatcher : nsISupports { /** Create a new window. It will automatically be added to our list @@ -87,8 +60,8 @@ interface nsIWindowWatcher : nsISupports { @param aFeatures window features from JS window.open @return the new window */ - nsIDOMWindow openWindow(in nsIDOMWindow aParent, in string aUrl, - in string aName, in string aFeatures); + nsIDOMWindow openWindow(in nsIDOMWindow aParent, in wstring aUrl, + in wstring aName, in wstring aFeatures); /** Clients of this service can register themselves to be notified when a window is opened or closed (added to or removed from this @@ -114,14 +87,22 @@ interface nsIWindowWatcher : nsISupports { */ void unregisterNotification(in nsIObserver aObserver); - /** iterates over currently open windows in the order they were opened, + /** Get an iterator for currently open windows in the order they were opened, guaranteeing that each will be visited exactly once. - @return an enumerator which will itself return an nsISupports which + @return an enumerator which will itself return nsISupports objects which can be QIed to an nsIDOMWindow */ nsISimpleEnumerator getWindowEnumerator(); + /** Set the window creator callback. It must be filled in by the app. + openWindow will use it to create new windows. + @param creator the callback. if null, the callback will be cleared + and window creation capabilities lost. + */ + void setWindowCreator(in nsIWindowCreator creator); + + /** The Watcher serves as a global storage facility for the current active (frontmost non-floating-palette-type) window, storing and returning it on demand. Users must keep this attribute current, including after diff --git a/mozilla/embedding/components/windowwatcher/public/nsPIWindowWatcher.idl b/mozilla/embedding/components/windowwatcher/public/nsPIWindowWatcher.idl index 02aabb15c4a..61b0a90827b 100644 --- a/mozilla/embedding/components/windowwatcher/public/nsPIWindowWatcher.idl +++ b/mozilla/embedding/components/windowwatcher/public/nsPIWindowWatcher.idl @@ -24,6 +24,8 @@ interface nsIDOMWindow; interface nsISimpleEnumerator; +[ptr] native jsvalptr(jsval); + [uuid(d535806e-afaf-47d1-8d89-783ad088c62a)] interface nsPIWindowWatcher : nsISupports @@ -38,6 +40,23 @@ interface nsPIWindowWatcher : nsISupports */ void removeWindow(in nsIDOMWindow aWindow); + /** Like the public interface's open(), but can deal with openDialog + style arguments. The exact definition of this method is temporary + pending the XPIDL rewrite of the DOM. + @param aParent parent window, if any. null if not. + @param aURL window URL from JS window.open + @param aName window name from JS window.open + @param aFeatures window features from JS window.open + @param aDialog use dialog defaults (see nsIDOMWindowInternal::openDialog) + @param argc count of argv arguments + @param argv extra JS arguments, if any + (see nsIDOMWindowInternal::openDialog) + @return the new window + */ + nsIDOMWindow openWindowJS(in nsIDOMWindow aParent, in wstring aUrl, + in wstring aName, in wstring aFeatures, in boolean aDialog, + in PRUint32 argc, in jsvalptr argv); + }; %{C++ diff --git a/mozilla/embedding/components/windowwatcher/src/Makefile.in b/mozilla/embedding/components/windowwatcher/src/Makefile.in index 2d6e790e08f..9ce8706f712 100644 --- a/mozilla/embedding/components/windowwatcher/src/Makefile.in +++ b/mozilla/embedding/components/windowwatcher/src/Makefile.in @@ -28,7 +28,8 @@ MODULE = embedcomponents LIBRARY_NAME = windowwatcher_s REQUIRES = xpcom dom windowwatcher -CPPSRCS = nsWindowWatcher.cpp \ +CPPSRCS = nsWWJSUtils.cpp \ + nsWindowWatcher.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a diff --git a/mozilla/embedding/components/windowwatcher/src/makefile.win b/mozilla/embedding/components/windowwatcher/src/makefile.win index 4f686194713..b3b45622ed4 100644 --- a/mozilla/embedding/components/windowwatcher/src/makefile.win +++ b/mozilla/embedding/components/windowwatcher/src/makefile.win @@ -24,6 +24,7 @@ MODULE=embedcomponents LIBRARY_NAME=windowwatcher_s CPP_OBJS= \ + .\$(OBJDIR)\nsWWJSUtils.obj \ .\$(OBJDIR)\nsWindowWatcher.obj \ $(NULL) diff --git a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp index f36d3683555..b49b67ca586 100644 --- a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp +++ b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp @@ -22,11 +22,40 @@ //#define USEWEAKREFS // (haven't quite figured that out yet) -#include "nsAutoLock.h" #include "nsWindowWatcher.h" + +#include "jscntxt.h" +#include "nsAutoLock.h" +#include "nsCRT.h" +#include "nsEscape.h" +#include "nsWWJSUtils.h" +#include "nsNetUtil.h" +#include "plstr.h" + +#include "nsIBaseWindow.h" +#include "nsICharsetConverterManager.h" +#include "nsIDocShell.h" +#include "nsIDocShellLoadInfo.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIDocument.h" +#include "nsIDOMDocument.h" +#include "nsIDOMScreen.h" #include "nsIDOMWindow.h" +#include "nsIDOMWindowInternal.h" +#include "nsIEventQueue.h" +#include "nsIEventQueueService.h" #include "nsIGenericFactory.h" +#include "nsIJSContextStack.h" #include "nsIObserverService.h" +#include "nsIScriptGlobalObject.h" +#include "nsIScriptObjectOwner.h" +#include "nsIScriptSecurityManager.h" +#include "nsIURI.h" +#include "nsIWebBrowser.h" +#include "nsIWebBrowserChrome.h" +#include "nsIWebNavigation.h" +#include "nsIWindowCreator.h" #ifdef USEWEAKREFS #include "nsIWeakReference.h" #endif @@ -34,20 +63,21 @@ #define NOTIFICATION_OPENED NS_LITERAL_STRING("domwindowopened") #define NOTIFICATION_CLOSED NS_LITERAL_STRING("domwindowclosed") +static const char *sJSStackContractID="@mozilla.org/js/xpc/ContextStack;1"; + /**************************************************************** - ************************* winfowInfo *************************** + ************************* WindowInfo *************************** ****************************************************************/ class nsWindowWatcher; struct WindowInfo { -#ifdef USEWEAKREFS WindowInfo(nsIDOMWindow* inWindow) { +#ifdef USEWEAKREFS mWindow = getter_AddRefs(NS_GetWeakReference(inWindow)); #else - WindowInfo(nsIDOMWindow* inWindow) : - mWindow(inWindow) { + mWindow = inWindow; #endif ReferenceSelf(); } @@ -59,8 +89,8 @@ struct WindowInfo { #ifdef USEWEAKREFS nsCOMPtr mWindow; -#else - nsCOMPtr mWindow; +#else // still not an owning ref + nsIDOMWindow *mWindow; #endif // each struct is in a circular, doubly-linked list WindowInfo *mYounger, // next younger in sequence @@ -208,7 +238,7 @@ nsWindowWatcher::nsWindowWatcher() : mActiveWindow(0), mListLock(0) { - NS_INIT_REFCNT(); + NS_INIT_REFCNT(); } nsWindowWatcher::~nsWindowWatcher() @@ -232,12 +262,256 @@ nsWindowWatcher::Init() NS_IMETHODIMP nsWindowWatcher::OpenWindow(nsIDOMWindow *aParent, - const char *aUrl, - const char *aName, - const char *aFeatures, + const PRUnichar *aUrl, + const PRUnichar *aName, + const PRUnichar *aFeatures, nsIDOMWindow **_retval) { - return NS_ERROR_NOT_IMPLEMENTED; + return OpenWindowJS(aParent, aUrl, aName, aFeatures, PR_FALSE, 0, 0, _retval); +} + +NS_IMETHODIMP +nsWindowWatcher::OpenWindowJS(nsIDOMWindow *aParent, + const PRUnichar *aUrl, + const PRUnichar *aName, + const PRUnichar *aFeatures, + PRBool aDialog, + PRUint32 argc, + jsval *argv, + nsIDOMWindow **_retval) +{ + nsresult rv = NS_OK; + JSContext *cx; + PRBool nameSpecified, + featuresSpecified; + PRUint32 chromeFlags; + nsAutoString name; // string version of aName + nsCString features; // string version of aFeatures + nsCOMPtr uriToLoad; // from aUrl, if any + nsCOMPtr parentTreeOwner; // from the parent window, if any + nsCOMPtr newDocShellItem; // from the new window + + NS_ENSURE_ARG_POINTER(_retval); + *_retval = 0; + + if (aParent) + GetWindowTreeOwner(aParent, getter_AddRefs(parentTreeOwner)); + + cx = GetJSContext(aParent); + if (!cx) + return NS_ERROR_FAILURE; + + if (aUrl) + rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad)); + if (NS_FAILED(rv)) + return rv; + + nameSpecified = PR_FALSE; + if (aName) { + name.Assign(aName); + CheckWindowName(name); + nameSpecified = PR_TRUE; + } + + featuresSpecified = PR_FALSE; + if (aFeatures) { + features.AssignWithConversion(aFeatures); + featuresSpecified = PR_TRUE; + } + + chromeFlags = CalculateChromeFlags(features, featuresSpecified, aDialog); + + // try to find an extant window with the given name + if (nameSpecified) { + /* Oh good. special target names are now handled in multiple places: + Here and within FindItemWithName, just below. I put _top here because + here it's able to do what it should: get the topmost shell of the same + (content/chrome) type as the docshell. treeOwner is always chrome, so + this scheme doesn't work there, where a lot of other special case + targets are handled. (treeOwner is, however, a good place to look + for browser windows by name, as it does.) + */ + if (aParent) { + if (name.EqualsIgnoreCase("_top")) { + nsCOMPtr shelltree; + GetWindowTreeItem(aParent, getter_AddRefs(shelltree)); + if (shelltree) + shelltree->GetSameTypeRootTreeItem(getter_AddRefs(newDocShellItem)); + } else + parentTreeOwner->FindItemWithName(name.GetUnicode(), nsnull, + getter_AddRefs(newDocShellItem)); + } else + FindItemWithName(name.GetUnicode(), getter_AddRefs(newDocShellItem)); + } + + nsCOMPtr modalEventQueue; // This has an odd ownership model + nsCOMPtr eventQService; + + PRBool windowIsNew = PR_FALSE; + PRBool windowIsModal = PR_FALSE; + + // no extant window? make a new one. + if (!newDocShellItem) { + windowIsNew = PR_TRUE; + PRBool weAreModal = PR_FALSE; + if (parentTreeOwner) + parentTreeOwner->IsModal(&weAreModal); + if (weAreModal || (chromeFlags & nsIWebBrowserChrome::CHROME_MODAL)) { + eventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID); + if (eventQService && + NS_SUCCEEDED(eventQService-> + PushThreadEventQueue(getter_AddRefs(modalEventQueue)))) + windowIsModal = PR_TRUE; + // in case we added this because weAreModal + chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT; + } + if (parentTreeOwner) + parentTreeOwner->GetNewWindow(chromeFlags, getter_AddRefs(newDocShellItem)); + else if (mWindowCreator) { + nsCOMPtr newChrome; + mWindowCreator->CreateWindow(0, chromeFlags, getter_AddRefs(newChrome)); + if (newChrome) { + nsCOMPtr newBrowser; + newChrome->GetWebBrowser(getter_AddRefs(newBrowser)); + if (newBrowser) { + nsCOMPtr newWindow; + newBrowser->GetContentDOMWindow(getter_AddRefs(newWindow)); + GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem)); + } + } + } + } + + // better have a window to use by this point + if (!newDocShellItem) + return NS_ERROR_FAILURE; + + rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, _retval); + if (NS_FAILED(rv)) + return rv; + + /* disable persistence of size/position in popups (determined by + looking for the outerWidth/outerHeight features. seems backward + though -- it's a popup if both features are lacking? */ + if (windowIsNew) { + PRBool present = PR_FALSE; + + if (!(WinHasOption(features, "outerWidth", 0, &present) || present) && + !(WinHasOption(features, "outerHeight", 0, &present) || present)) { + + nsCOMPtr newTreeOwner; + newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner)); + if (newTreeOwner) { + nsCOMPtr newChrome = do_GetInterface(newTreeOwner); + if (newChrome) + newChrome->SetPersistence(PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, + PR_FALSE); + } + } + } + + if (aDialog && argc > 3) + AttachArguments(*_retval, argc-3, argv+3); + + nsCOMPtr secMan; + + if (uriToLoad) { + /* Get security manager, check to see if URI is allowed. + Don't call CheckLoadURI for dialogs - see bug 56851 + The security of this function depends on window.openDialog being + inaccessible from web scripts */ + nsCOMPtr scriptCX; +#if 0 + nsJSUtils::nsGetDynamicScriptContext(cx, getter_AddRefs(scriptCX)); +#else + JSContext *tempCX; + JSObject *scriptObject; + if (aParent) + GetWindowScriptContextAndObject(aParent, &tempCX, &scriptObject); + else + GetWindowScriptContextAndObject(*_retval, &tempCX, &scriptObject); + nsWWJSUtils::nsGetStaticScriptContext(tempCX, scriptObject, + getter_AddRefs(scriptCX)); +#endif + if (!scriptCX || + NS_FAILED(scriptCX->GetSecurityManager(getter_AddRefs(secMan))) || + ((!aDialog && NS_FAILED(secMan->CheckLoadURIFromScript(cx, uriToLoad))))) + return NS_ERROR_FAILURE; + } + + newDocShellItem->SetName(nameSpecified ? name.GetUnicode() : nsnull); + + nsCOMPtr newDocShell(do_QueryInterface(newDocShellItem)); + if (uriToLoad) { // Get script principal and pass to docshell + nsCOMPtr principal; + if (NS_FAILED(secMan->GetSubjectPrincipal(getter_AddRefs(principal)))) + return NS_ERROR_FAILURE; + + nsCOMPtr loadInfo; + newDocShell->CreateLoadInfo(getter_AddRefs(loadInfo)); + NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE); + + if (principal) { + nsCOMPtr owner(do_QueryInterface(principal)); + loadInfo->SetOwner(owner); + } + + // Get the calling context off the JS context stack + nsCOMPtr stack = do_GetService(sJSStackContractID); + + JSContext* ccx = nsnull; + + if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) { + JSObject *global = ::JS_GetGlobalObject(ccx); + + if (global) { + JSClass* jsclass = ::JS_GetClass(ccx, global); + + // Check if the global object on the calling context has + // nsISupports * private data + if (jsclass && + !((~jsclass->flags) & (JSCLASS_HAS_PRIVATE | + JSCLASS_PRIVATE_IS_NSISUPPORTS))) { + nsISupports* sup = (nsISupports *)::JS_GetPrivate(ccx, global); + + nsCOMPtr w(do_QueryInterface(sup)); + + if (w) { + nsCOMPtr document; + + // Get the document from the window. + w->GetDocument(getter_AddRefs(document)); + + nsCOMPtr doc(do_QueryInterface(document)); + + if (doc) { + nsCOMPtr uri(dont_AddRef(doc->GetDocumentURL())); + + // Set the referrer + loadInfo->SetReferrer(uri); + } + } + } + } + } + + newDocShell->LoadURI(uriToLoad, loadInfo, + nsIWebNavigation::LOAD_FLAGS_NONE); + } + + if (windowIsNew) + SizeOpenedDocShellItem(newDocShellItem, aParent, features, chromeFlags); + if (windowIsModal) { + nsCOMPtr newTreeOwner; + newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner)); + + if (newTreeOwner) + newTreeOwner->ShowModal(); + + eventQService->PopThreadEventQueue(modalEventQueue); + } + + return NS_OK; } NS_IMETHODIMP @@ -290,7 +564,14 @@ nsWindowWatcher::GetWindowEnumerator(nsISimpleEnumerator** _retval) } NS_IMETHODIMP -nsWindowWatcher::GetActiveWindow(nsIDOMWindow * *aActiveWindow) +nsWindowWatcher::SetWindowCreator(nsIWindowCreator *creator) +{ + mWindowCreator = creator; // it's an nsCOMPtr, so this is an ownership ref + return NS_OK; +} + +NS_IMETHODIMP +nsWindowWatcher::GetActiveWindow(nsIDOMWindow **aActiveWindow) { if (!aActiveWindow) return NS_ERROR_INVALID_ARG; @@ -301,7 +582,7 @@ nsWindowWatcher::GetActiveWindow(nsIDOMWindow * *aActiveWindow) } NS_IMETHODIMP -nsWindowWatcher::SetActiveWindow(nsIDOMWindow * aActiveWindow) +nsWindowWatcher::SetActiveWindow(nsIDOMWindow *aActiveWindow) { mActiveWindow = aActiveWindow; return NS_OK; @@ -370,16 +651,17 @@ nsWindowWatcher::RemoveWindow(nsIDOMWindow *aWindow) return found ? rv : NS_ERROR_INVALID_ARG; #else while (info != listEnd) { - if (info->mWindow.get() == aWindow) + if (info->mWindow == aWindow) return RemoveWindow(info); info = info->mYounger; listEnd = mOldestWindow; } + NS_WARNING("requested removal of nonexistent window\n"); return NS_ERROR_INVALID_ARG; #endif } -NS_IMETHODIMP nsWindowWatcher::RemoveWindow(WindowInfo *inInfo) +nsresult nsWindowWatcher::RemoveWindow(WindowInfo *inInfo) { PRInt32 ctr, count = mEnumeratorList.Count(); @@ -430,3 +712,714 @@ nsWindowWatcher::RemoveEnumerator(nsWindowEnumerator* inEnumerator) return mEnumeratorList.RemoveElement(inEnumerator); } +JSContext * +nsWindowWatcher::GetJSContext(nsIDOMWindow *aWindow) +{ + JSContext *cx; + + // given a window, we'll use its + cx = 0; + if (aWindow) { + nsCOMPtr sgo(do_QueryInterface(aWindow)); + if (sgo) { + nsCOMPtr scx; + sgo->GetContext(getter_AddRefs(scx)); + if (scx) + cx = (JSContext *) scx->GetNativeContext(); // from iffy to skank. is this guaranteed? + } + /* apparently, if it comes to it, the nsIScriptContext can be retrieved by + nsCOMPtr scx; + nsJSUtils::nsGetDynamicScriptContext(cx, getter_AddRefs(scx)); + */ + } + + // still no JSContext? try pulling one from the stack. + if (!cx) { + nsCOMPtr cxStack(do_GetService(sJSStackContractID)); + if (cxStack) + cxStack->Peek(&cx); + } + + // better have one by now + NS_ASSERTION(cx, "no available JSContext"); + return cx; +} + +// stolen from GlobalWindowImpl +nsresult +nsWindowWatcher::Escape(const nsAReadableString& aStr, nsAWritableString& aReturn, + nsIDOMWindow *aWindow) +{ + nsresult rv = NS_OK; + nsCOMPtr encoder; + nsAutoString charset; + + // Get the document character set + charset.AssignWithConversion("UTF-8"); // default to utf-8 + if (aWindow) { // or use aWindow's, if possible + nsCOMPtr domDoc; + aWindow->GetDocument(getter_AddRefs(domDoc)); + if (domDoc) { + nsCOMPtr doc(do_QueryInterface(domDoc)); + if (doc) + rv = doc->GetDocumentCharacterSet(charset); + } + } + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr + ccm(do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID)); + if (!ccm) + return NS_ERROR_FAILURE; + + // Get an encoder for the character set + rv = ccm->GetUnicodeEncoder(&charset, getter_AddRefs(encoder)); + if (NS_FAILED(rv)) + return rv; + + rv = encoder->Reset(); + if (NS_FAILED(rv)) + return rv; + + PRInt32 maxByteLen, srcLen; + srcLen = aStr.Length(); + + nsPromiseFlatString flatSrc(aStr); + const PRUnichar* src = flatSrc.get(); + + // Get the expected length of result string + rv = encoder->GetMaxLength(src, srcLen, &maxByteLen); + if (NS_FAILED(rv)) + return rv; + + // Allocate a buffer of the maximum length + char* dest = (char *) nsMemory::Alloc(maxByteLen + 1); + PRInt32 destLen2, destLen = maxByteLen; + if (!dest) + return NS_ERROR_OUT_OF_MEMORY; + + // Convert from unicode to the character set + rv = encoder->Convert(src, &srcLen, dest, &destLen); + if (NS_SUCCEEDED(rv)) { + // Allow the encoder to finish the conversion + destLen2 = maxByteLen - destLen; + encoder->Finish(dest + destLen, &destLen2); + dest[destLen + destLen2] = '\0'; + + // Escape the string + char *outBuf = + nsEscape(dest, nsEscapeMask(url_XAlphas | url_XPAlphas | url_Path)); + CopyASCIItoUCS2(nsLiteralCString(outBuf), aReturn); + nsMemory::Free(outBuf); + } + + nsMemory::Free(dest); + + return rv; +} + +nsresult +nsWindowWatcher::URIfromURL(const PRUnichar *aURL, + nsIDOMWindow *aParent, + nsIURI **aURI) +{ + *aURI = 0; + + nsresult rv = NS_OK; + nsAutoString unescapedURL(aURL); + nsAutoString escapedURL; + + // fix bug 35076 + // if the URL contains non ASCII, then escape from the first non ASCII char + if (unescapedURL.IsASCII()) + escapedURL = unescapedURL; + else { + const PRUnichar *pt = unescapedURL.GetUnicode(); + PRUint32 len = unescapedURL.Length(); + PRUint32 i; + for (i = 0; i < len; i++) + if (0xFF80 & *pt++) + break; + + nsAutoString right, escapedRight; + unescapedURL.Left(escapedURL, i); + unescapedURL.Right(right, len - i); + if (NS_SUCCEEDED(Escape(right, escapedRight, aParent))) + escapedURL.Append(escapedRight); + else + escapedURL = unescapedURL; + } + + if (!escapedURL.IsEmpty()) { + nsAutoString absoluteURL; + nsCOMPtr doc; + nsCOMPtr baseURI; + + if (aParent) { + nsCOMPtr domDoc; + aParent->GetDocument(getter_AddRefs(domDoc)); + if (domDoc) + doc = do_QueryInterface(domDoc); + } + if (doc) { + // build absolute URI relative to this document. + baseURI = dont_AddRef(doc->GetDocumentURL()); + rv = NS_MakeAbsoluteURI(absoluteURL, escapedURL, baseURI); + } + if (NS_FAILED(rv) || !baseURI) { + /* probably no document, probably because the context window's + URL hasn't finished loading. (don't call this function with + no context window and a relative URL!). All we can do is hope + the URL we've been given is absolute. */ + absoluteURL = escapedURL; + } + // make URI; if absoluteURL is relative (or otherwise bogus) this will fail. + rv = NS_NewURI(aURI, absoluteURL); + } + + return rv; +} + +/* Check for an illegal name e.g. frame3.1 + This just prints a warning message an continues; we open the window anyway, + (see bug 32898). */ +void nsWindowWatcher::CheckWindowName(nsString& aName) +{ + nsReadingIterator scan; + nsReadingIterator endScan; + + aName.EndReading(endScan); + for (aName.BeginReading(scan); scan != endScan; ++scan) + if (!nsCRT::IsAsciiAlpha(*scan) && !nsCRT::IsAsciiDigit(*scan) && + *scan != '_') { + + // Don't use js_ReportError as this will cause the application + // to shut down (JS_ASSERT calls abort()) See bug 32898 + nsAutoString warn; + warn.AssignWithConversion("Illegal character in window name "); + warn.Append(aName); + char *cp = warn.ToNewCString(); + NS_WARNING(cp); + nsCRT::free(cp); + break; + } +} + +/** + * Calculate the chrome bitmask from a string list of features. + * @param aFeatures a string containing a list of named chrome features + * @param aNullFeatures true if aFeatures was a null pointer (which fact + * is lost by its conversion to a string in the caller) + * @param aDialog affects the assumptions made about unnamed features + * @return the chrome bitmask + */ +PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures, + PRBool aFeaturesSpecified, + PRBool aDialog) +{ + if(!aFeaturesSpecified || !aFeatures) { + if(aDialog) + return nsIWebBrowserChrome::CHROME_ALL | + nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | + nsIWebBrowserChrome::CHROME_OPENAS_CHROME; + else + return nsIWebBrowserChrome::CHROME_ALL; + } + + /* This function has become complicated since browser windows and + dialogs diverged. The difference is, browser windows assume all + chrome not explicitly mentioned is off, if the features string + is not null. Exceptions are some OS border chrome new with Mozilla. + Dialogs interpret a (mostly) empty features string to mean + "OS's choice," and also support an "all" flag explicitly disallowed + in the standards-compliant window.(normal)open. */ + + PRUint32 chromeFlags = 0; + PRBool presenceFlag = PR_FALSE; + + chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS; + if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) + chromeFlags = nsIWebBrowserChrome::CHROME_ALL; + + /* Next, allow explicitly named options to override the initial settings */ + + chromeFlags |= WinHasOption(aFeatures, "titlebar", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_TITLEBAR : 0; + chromeFlags |= WinHasOption(aFeatures, "close", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_WINDOW_CLOSE : 0; + chromeFlags |= WinHasOption(aFeatures, "toolbar", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_TOOLBAR : 0; + chromeFlags |= WinHasOption(aFeatures, "location", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_LOCATIONBAR : 0; + chromeFlags |= (WinHasOption(aFeatures, "directories", 0, &presenceFlag) || + WinHasOption(aFeatures, "personalbar", 0, &presenceFlag)) + ? nsIWebBrowserChrome::CHROME_PERSONAL_TOOLBAR : 0; + chromeFlags |= WinHasOption(aFeatures, "status", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_STATUSBAR : 0; + chromeFlags |= WinHasOption(aFeatures, "menubar", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_MENUBAR : 0; + chromeFlags |= WinHasOption(aFeatures, "scrollbars", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_SCROLLBARS : 0; + chromeFlags |= WinHasOption(aFeatures, "resizable", 0, &presenceFlag) + ? nsIWebBrowserChrome::CHROME_WINDOW_RESIZE : 0; + + /* OK. + Normal browser windows, in spite of a stated pattern of turning off + all chrome not mentioned explicitly, will want the new OS chrome (window + borders, titlebars, closebox) on, unless explicitly turned off. + Dialogs, on the other hand, take the absence of any explicit settings + to mean "OS' choice." */ + + // default titlebar and closebox to "on," if not mentioned at all + if (!PL_strcasestr(aFeatures, "titlebar")) + chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR; + if (!PL_strcasestr(aFeatures, "close")) + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE; + + if (aDialog && !presenceFlag) + chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT; + + /* Finally, once all the above normal chrome has been divined, deal + with the features that are more operating hints than appearance + instructions. (Note modality implies dependence.) */ + + if (WinHasOption(aFeatures, "alwaysLowered", 0, nsnull) || + WinHasOption(aFeatures, "z-lock", 0, nsnull)) + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_LOWERED; + else if (WinHasOption(aFeatures, "alwaysRaised", 0, nsnull)) + chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_RAISED; + + chromeFlags |= WinHasOption(aFeatures, "chrome", 0, nsnull) ? + nsIWebBrowserChrome::CHROME_OPENAS_CHROME : 0; + chromeFlags |= WinHasOption(aFeatures, "centerscreen", 0, nsnull) ? + nsIWebBrowserChrome::CHROME_CENTER_SCREEN : 0; + chromeFlags |= WinHasOption(aFeatures, "dependent", 0, nsnull) ? + nsIWebBrowserChrome::CHROME_DEPENDENT : 0; + chromeFlags |= WinHasOption(aFeatures, "modal", 0, nsnull) ? + (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0; + chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nsnull) ? + nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0; + + /* and dialogs need to have the last word. assume dialogs are dialogs, + and opened as chrome, unless explicitly told otherwise. */ + if (aDialog) { + if (!PL_strcasestr(aFeatures, "dialog")) + chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG; + if (!PL_strcasestr(aFeatures, "chrome")) + chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME; + } + + /* missing + chromeFlags->copy_history + */ + + /* Allow disabling of commands only if there is no menubar */ + /*if(!chromeFlags & NS_CHROME_MENU_BAR_ON) { + chromeFlags->disable_commands = !WinHasOption(aFeatures, "hotkeys"); + if(XP_STRCASESTR(aFeatures,"hotkeys")==NULL) + chromeFlags->disable_commands = FALSE; + } + */ + + //Check security state for use in determing window dimensions + nsCOMPtr + securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); + NS_ENSURE_TRUE(securityManager, NS_ERROR_FAILURE); + + PRBool enabled; + nsresult res = + securityManager->IsCapabilityEnabled("UniversalBrowserWrite", &enabled); + + res = securityManager->IsCapabilityEnabled("UniversalBrowserWrite", &enabled); + + if (NS_FAILED(res) || !enabled) { + //If priv check fails, set all elements to minimum reqs., else leave them alone. + chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR; + chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED; + chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED; + //XXX Temporarily removing this check to allow modal dialogs to be + //raised from script. A more complete security based fix is needed. + //chromeFlags &= ~nsIWebBrowserChrome::CHROME_MODAL; + } + + return chromeFlags; +} + +PRInt32 +nsWindowWatcher::WinHasOption(const char *aOptions, const char *aName, + PRInt32 aDefault, PRBool *aPresenceFlag) +{ + if (!aOptions) + return 0; + + char *comma, *equal; + PRInt32 found = 0; + + while (PR_TRUE) { + while (nsCRT::IsAsciiSpace(*aOptions)) + aOptions++; + + comma = strchr(aOptions, ','); + if (comma) + *comma = '\0'; + equal = strchr(aOptions, '='); + if (equal) + *equal = '\0'; + if (nsCRT::strcasecmp(aOptions, aName) == 0) { + if (aPresenceFlag) + *aPresenceFlag = PR_TRUE; + if (equal) + if (*(equal + 1) == '*') + found = aDefault; + else if (nsCRT::strcasecmp(equal + 1, "yes") == 0) + found = 1; + else + found = atoi(equal + 1); + else + found = 1; + } + if (equal) + *equal = '='; + if (comma) + *comma = ','; + if (found || !comma) + break; + aOptions = comma + 1; + } + return found; +} + +/* try to find an nsIDocShellTreeItem with the given name in any + known open window. a failure to find the item will not + necessarily return a failure method value. check aFoundItem. +*/ +nsresult +nsWindowWatcher::FindItemWithName( + const PRUnichar* aName, + nsIDocShellTreeItem** aFoundItem) +{ + PRBool more; + nsresult rv; + + *aFoundItem = 0; + + nsCOMPtr windows; + GetWindowEnumerator(getter_AddRefs(windows)); + if (!windows) + return NS_ERROR_FAILURE; + + rv = NS_OK; + do { + windows->HasMoreElements(&more); + if (!more) + break; + nsCOMPtr nextSupWindow; + windows->GetNext(getter_AddRefs(nextSupWindow)); + if (nextSupWindow) { + nsCOMPtr nextWindow(do_QueryInterface(nextSupWindow)); + if (nextWindow) { + nsCOMPtr treeItem; + GetWindowTreeItem(nextWindow, getter_AddRefs(treeItem)); + if (treeItem) { + rv = treeItem->FindItemWithName(aName, treeItem, aFoundItem); + if (NS_FAILED(rv) || *aFoundItem) + break; + } + } + } + } while(1); + + return rv; +} + +/* Fetch the nsIDOMWindow corresponding to the given nsIDocShellTreeItem. + This forces the creation of a script context, if one has not already + been created. Note it also sets the window's opener to the parent, + if applicable -- because it's just convenient, that's all. null aParent + is acceptable. */ +nsresult +nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem, + nsIDOMWindow *aParent, + nsIDOMWindow **aOpenedWindow) +{ + nsresult rv = NS_ERROR_FAILURE; + + *aOpenedWindow = 0; + nsCOMPtr globalObject(do_GetInterface(aOpenedItem)); + if (globalObject) { + if (aParent) { + nsCOMPtr internalParent(do_QueryInterface(aParent)); + globalObject->SetOpenerWindow(internalParent); // damnit + } + rv = CallQueryInterface(globalObject, aOpenedWindow); + } + return rv; +} + +void +nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem, + nsIDOMWindow *aParent, + const char *aFeatures, + PRUint32 aChromeFlags) +{ + PRInt32 chromeX = 0, chromeY = 0, chromeCX = 100, chromeCY = 100; + PRInt32 contentCX = 100, contentCY = 100; + + // Use sizes from the parent window, if any, as our default + if (aParent) { + nsCOMPtr item; + + GetWindowTreeItem(aParent, getter_AddRefs(item)); + if (item) { + // if we are content, we may need the content sizes + nsCOMPtr win(do_QueryInterface(item)); + win->GetSize(&contentCX, &contentCY); + + // now the main window + nsCOMPtr owner; + item->GetTreeOwner(getter_AddRefs(owner)); + if (owner) { + nsCOMPtr basewin(do_QueryInterface(owner)); + if (basewin) + basewin->GetPositionAndSize(&chromeX, &chromeY, + &chromeCX, &chromeCY); + } + } + } + + PRBool present = PR_FALSE; + PRBool positionSpecified = PR_FALSE; + PRInt32 temp; + + if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present) + chromeX = temp; + else if ((temp = WinHasOption(aFeatures, "screenX", 0, &present)) || present) + chromeX = temp; + + if (present) + positionSpecified = PR_TRUE; + + present = PR_FALSE; + + if ((temp = WinHasOption(aFeatures, "top", 0, &present)) || present) + chromeY = temp; + else if ((temp = WinHasOption(aFeatures, "screenY", 0, &present)) || present) + chromeY = temp; + + if (present) + positionSpecified = PR_TRUE; + + present = PR_FALSE; + + PRBool sizeChrome = PR_FALSE; + PRBool sizeSpecified = PR_FALSE; + + if ((temp = WinHasOption(aFeatures, "outerWidth", chromeCX, &present)) || + present) { + chromeCX = temp; + sizeChrome = PR_TRUE; + sizeSpecified = PR_TRUE; + } + + present = PR_FALSE; + + if ((temp = WinHasOption(aFeatures, "outerHeight", chromeCY, &present)) || + present) { + chromeCY = temp; + sizeChrome = PR_TRUE; + sizeSpecified = PR_TRUE; + } + + // We haven't switched to chrome sizing so we need to get the content area + if (!sizeChrome) { + if ((temp = WinHasOption(aFeatures, "width", chromeCX, &present)) || + present) { + contentCX = temp; + sizeSpecified = PR_TRUE; + } + else if ((temp = WinHasOption(aFeatures, "innerWidth", chromeCX, &present)) + || present) { + contentCX = temp; + sizeSpecified = PR_TRUE; + } + + if ((temp = WinHasOption(aFeatures, "height", chromeCY, &present)) || + present) { + contentCY = temp; + sizeSpecified = PR_TRUE; + } + else if ((temp = WinHasOption(aFeatures, "innerHeight", chromeCY, &present)) + || present) { + contentCY = temp; + sizeSpecified = PR_TRUE; + } + } + + nsresult res; + PRBool enabled = PR_FALSE; + PRInt32 screenWidth = 0, screenHeight = 0; + PRInt32 winWidth, winHeight; + + // Check security state for use in determing window dimensions + nsCOMPtr + securityManager(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID)); + if (securityManager) { + res = securityManager->IsCapabilityEnabled("UniversalBrowserWrite", &enabled); + if (NS_FAILED(res)) + enabled = PR_FALSE; + } + + if (!enabled) { + // Security check failed. Ensure all args meet minimum reqs. + if (sizeSpecified) { + if (sizeChrome) { + chromeCX = chromeCX < 100 ? 100 : chromeCX; + chromeCY = chromeCY < 100 ? 100 : chromeCY; + } + else { + contentCX = contentCX < 100 ? 100 : contentCX; + contentCY = contentCY < 100 ? 100 : contentCY; + } + } + + if (positionSpecified) { + // We'll also need the screen dimensions + // XXX This should use nsIScreenManager once it's fully fleshed out. + nsCOMPtr screen; + if (aParent) { + nsCOMPtr intparent(do_QueryInterface(aParent)); + if (intparent) + intparent->GetScreen(getter_AddRefs(screen)); + } else { + // XXX hmmph. try the new window. + } + if (screen) { + screen->GetAvailWidth(&screenWidth); + screen->GetAvailHeight(&screenHeight); + } + + // This isn't strictly true but close enough + winWidth = sizeSpecified ? (sizeChrome ? chromeCX : contentCX) : 100; + winHeight = sizeSpecified ? (sizeChrome ? chromeCY : contentCY) : 100; + + chromeX = + screenWidth < chromeX + winWidth ? screenWidth - winWidth : chromeX; + chromeX = chromeX < 0 ? 0 : chromeX; + chromeY = screenHeight < chromeY + winHeight + ? screenHeight - winHeight + : chromeY; + chromeY = chromeY < 0 ? 0 : chromeY; + } + } + + nsCOMPtr treeOwner; + aDocShellItem->GetTreeOwner(getter_AddRefs(treeOwner)); + nsCOMPtr treeOwnerAsWin(do_QueryInterface(treeOwner)); + if (treeOwnerAsWin) { + if (sizeChrome) { + if (positionSpecified && sizeSpecified) + treeOwnerAsWin->SetPositionAndSize(chromeX, chromeY, chromeCX, + chromeCY, PR_FALSE); + else { + if (sizeSpecified) + treeOwnerAsWin->SetSize(chromeCX, chromeCY, PR_FALSE); + if (positionSpecified) + treeOwnerAsWin->SetPosition(chromeX, chromeY); + } + } + else { + if (positionSpecified) + treeOwnerAsWin->SetPosition(chromeX, chromeY); + if (sizeSpecified) + treeOwner->SizeShellTo(aDocShellItem, contentCX, contentCY); + } + treeOwnerAsWin->SetVisibility(PR_TRUE); + } +} + +// attach the given array of JS values to the given window, as a property array +// named "arguments" +void +nsWindowWatcher::AttachArguments(nsIDOMWindow *aWindow, + PRUint32 argc, jsval *argv) +{ + if (argc == 0) + return; + + JSContext *cx; + JSObject *object; + + GetWindowScriptContextAndObject(aWindow, &cx, &object); + + // copy the extra parameters into a JS Array and attach it + nsCOMPtr scriptGlobal(do_QueryInterface(aWindow)); + if (scriptGlobal) { + nsCOMPtr scriptContext; + scriptGlobal->GetContext(getter_AddRefs(scriptContext)); + if (scriptContext) { + JSContext *cx; + cx = (JSContext *) scriptContext->GetNativeContext(); + nsCOMPtr owner(do_QueryInterface(aWindow)); + if (owner) { + JSObject *scriptObject; + owner->GetScriptObject(scriptContext, (void **) &scriptObject); + JSObject *args; + args = ::JS_NewArrayObject(cx, argc, argv); + if (args) { + jsval argsVal = OBJECT_TO_JSVAL(args); + // ::JS_DefineProperty(cx, scriptObject, "arguments", + // argsVal, NULL, NULL, JSPROP_PERMANENT); + ::JS_SetProperty(cx, scriptObject, "arguments", &argsVal); + } + } + } + } +} + +void +nsWindowWatcher::GetWindowTreeItem(nsIDOMWindow *inWindow, + nsIDocShellTreeItem **outTreeItem) +{ + *outTreeItem = 0; + + nsCOMPtr sgo(do_QueryInterface(inWindow)); + if (sgo) { + nsCOMPtr docshell; + sgo->GetDocShell(getter_AddRefs(docshell)); + if (docshell) + CallQueryInterface(docshell, outTreeItem); + } +} + +void +nsWindowWatcher::GetWindowTreeOwner(nsIDOMWindow *inWindow, + nsIDocShellTreeOwner **outTreeOwner) +{ + *outTreeOwner = 0; + + nsCOMPtr treeItem; + GetWindowTreeItem(inWindow, getter_AddRefs(treeItem)); + if (treeItem) + treeItem->GetTreeOwner(outTreeOwner); +} + +void nsWindowWatcher::GetWindowScriptContextAndObject(nsIDOMWindow *inWindow, + JSContext **cx, + JSObject **outObject) +{ + *cx = 0; + *outObject = 0; + nsCOMPtr scriptGlobal(do_QueryInterface(inWindow)); + if (scriptGlobal) { + nsCOMPtr scriptContext; + scriptGlobal->GetContext(getter_AddRefs(scriptContext)); + if (scriptContext) { + *cx = (JSContext *) scriptContext->GetNativeContext(); + + nsCOMPtr owner(do_QueryInterface(inWindow)); + if (owner) + owner->GetScriptObject(scriptContext, (void **) outObject); + } + } +} diff --git a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h index 66aed27d6b4..c53efe442df 100644 --- a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h +++ b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h @@ -29,11 +29,20 @@ #define NS_WINDOWWATCHER_CONTRACTID \ "@mozilla.org/embedcomp/window-watcher;1" +#include "nsCOMPtr.h" +#include "jspubtd.h" +#include "nsIWindowCreator.h" // for stupid compilers #include "nsIWindowWatcher.h" #include "nsPIWindowWatcher.h" #include "nsVoidArray.h" +class nsIURI; +class nsIDocShellTreeItem; +class nsIDocShellTreeOwner; +class nsString; class nsWindowEnumerator; +struct JSContext; +struct JSObject; struct WindowInfo; struct PRLock; @@ -58,12 +67,47 @@ private: PRBool AddEnumerator(nsWindowEnumerator* inEnumerator); PRBool RemoveEnumerator(nsWindowEnumerator* inEnumerator); - NS_IMETHOD RemoveWindow(WindowInfo *inInfo); + nsresult RemoveWindow(WindowInfo *inInfo); + + nsresult FindItemWithName(const PRUnichar *aName, + nsIDocShellTreeItem **aFoundItem); + + static JSContext *GetJSContext(nsIDOMWindow *aWindow); + static nsresult URIfromURL(const PRUnichar *aURL, + nsIDOMWindow *aParent, + nsIURI **aURI); + static nsresult Escape(const nsAReadableString& aStr, + nsAWritableString& aReturn, + nsIDOMWindow *aWindow); + static void CheckWindowName(nsString& aName); + static PRUint32 CalculateChromeFlags(const char *aFeatures, + PRBool aFeaturesSpecified, + PRBool aDialog); + static PRInt32 WinHasOption(const char *aOptions, const char *aName, + PRInt32 aDefault, PRBool *aPresenceFlag); + static nsresult ReadyOpenedDocShellItem(nsIDocShellTreeItem *aOpenedItem, + nsIDOMWindow *aParent, + nsIDOMWindow **aOpenedWindow); + static void SizeOpenedDocShellItem(nsIDocShellTreeItem *aDocShellItem, + nsIDOMWindow *aParent, + const char *aFeatures, + PRUint32 aChromeFlags); + static void AttachArguments(nsIDOMWindow *aWindow, + PRUint32 argc, jsval *argv); + static void GetWindowTreeItem(nsIDOMWindow *inWindow, + nsIDocShellTreeItem **outTreeItem); + static void GetWindowTreeOwner(nsIDOMWindow *inWindow, + nsIDocShellTreeOwner **outTreeOwner); + static void GetWindowScriptContextAndObject(nsIDOMWindow *inWindow, + JSContext **cx, + JSObject **outObject); nsVoidArray mEnumeratorList; WindowInfo *mOldestWindow; nsIDOMWindow *mActiveWindow; PRLock *mListLock; + + nsCOMPtr mWindowCreator; }; #endif diff --git a/mozilla/embedding/tests/winEmbed/makefile.win b/mozilla/embedding/tests/winEmbed/makefile.win index 7bc1b75972f..006bfeccd16 100644 --- a/mozilla/embedding/tests/winEmbed/makefile.win +++ b/mozilla/embedding/tests/winEmbed/makefile.win @@ -30,6 +30,7 @@ RESFILE = $(MODULE).res OBJS = \ .\$(OBJDIR)\winEmbed.obj \ .\$(OBJDIR)\WebBrowserChrome.obj \ + .\$(OBJDIR)\WindowCreator.obj \ .\$(OBJDIR)\StdAfx.obj \ $(NULL)