diff --git a/mozilla/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp b/mozilla/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp index 37a3d85afb8..0a69ed47ffc 100644 --- a/mozilla/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp +++ b/mozilla/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp @@ -298,7 +298,7 @@ void nsDocShellTreeOwner::AddToWatcher() { if (domWindow) { nsCOMPtr wwatch(do_GetService(sWindowWatcherContractID)); if (wwatch) - wwatch->AddWindow(domWindow); + wwatch->AddWindow(domWindow, mWebBrowserChrome); } } } diff --git a/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl b/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl index 69172f50d4e..0bd20b131b7 100644 --- a/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl +++ b/mozilla/embedding/components/windowwatcher/public/nsIWindowWatcher.idl @@ -48,6 +48,7 @@ interface nsIObserver; interface nsIPrompt; interface nsIAuthPrompt; interface nsISimpleEnumerator; +interface nsIWebBrowserChrome; interface nsIWindowCreator; [scriptable, uuid(002286a8-494b-43b3-8ddd-49e3fc50622b)] @@ -125,6 +126,16 @@ interface nsIWindowWatcher : nsISupports { void setWindowCreator(in nsIWindowCreator creator); + /** Retrieve the chrome window mapped to the given DOM window. Window + Watcher keeps a list of all top-level DOM windows currently open, + along with their corresponding chrome interfaces. Since DOM Windows + lack a (public) means of retrieving their corresponding chrome, + this method will do that. + @param aWindow the DOM window whose chrome window the caller needs + @return the corresponding chrome window + */ + nsIWebBrowserChrome getChromeForWindow(in nsIDOMWindow aWindow); + /** 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 ab2bda4ef71..03015a1599d 100644 --- a/mozilla/embedding/components/windowwatcher/public/nsPIWindowWatcher.idl +++ b/mozilla/embedding/components/windowwatcher/public/nsPIWindowWatcher.idl @@ -19,10 +19,15 @@ * Contributor(s): */ +/* Private "control" methods on the Window Watcher. These are annoying + bookkeeping methods, not part of the public (embedding) interface. +*/ + #include "nsISupports.idl" interface nsIDOMWindow; interface nsISimpleEnumerator; +interface nsIWebBrowserChrome; [ptr] native jsvalptr(jsval); @@ -32,8 +37,13 @@ interface nsPIWindowWatcher : nsISupports { /** A window has been created. Add it to our list. @param aWindow the window to add + @param aChrome the corresponding chrome window. The DOM window + and chrome will be mapped together, and the corresponding + chrome can be retrieved using the (not private) + method getChromeForWindow. If null, any extant mapping + will be cleared. */ - void addWindow(in nsIDOMWindow aWindow); + void addWindow(in nsIDOMWindow aWindow, in nsIWebBrowserChrome aChrome); /** A window has been closed. Remove it from our list. @param aWindow the window to remove diff --git a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp index 968ec40cae8..f751ed83ef5 100644 --- a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp +++ b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.cpp @@ -75,12 +75,13 @@ class nsWindowWatcher; struct WindowInfo { - WindowInfo(nsIDOMWindow* inWindow) { + WindowInfo(nsIDOMWindow *inWindow, nsIWebBrowserChrome *inChrome) { #ifdef USEWEAKREFS mWindow = getter_AddRefs(NS_GetWeakReference(inWindow)); #else mWindow = inWindow; #endif + mChrome = inChrome; ReferenceSelf(); } ~WindowInfo() {} @@ -94,6 +95,7 @@ struct WindowInfo { #else // still not an owning ref nsIDOMWindow *mWindow; #endif + nsIWebBrowserChrome *mChrome; // each struct is in a circular, doubly-linked list WindowInfo *mYounger, // next younger in sequence *mOlder; @@ -742,19 +744,29 @@ nsWindowWatcher::SetActiveWindow(nsIDOMWindow *aActiveWindow) } NS_IMETHODIMP -nsWindowWatcher::AddWindow(nsIDOMWindow *aWindow) +nsWindowWatcher::AddWindow(nsIDOMWindow *aWindow, nsIWebBrowserChrome *aChrome) { nsresult rv; if (!aWindow) return NS_ERROR_INVALID_ARG; + + WindowInfo *info; + nsAutoLock lock(mListLock); + + // if we already have an entry for this window, adjust + // its chrome mapping and return + info = FindWindowInfo(aWindow); + if (info) { + info->mChrome = aChrome; + return NS_OK; + } - // create window info struct and add to list of windows - WindowInfo* info = new WindowInfo(aWindow); + // create a window info struct and add it to the list of windows + info = new WindowInfo(aWindow, aChrome); if (!info) return NS_ERROR_OUT_OF_MEMORY; - nsAutoLock lock(mListLock); if (mOldestWindow) info->InsertAfter(mOldestWindow->mOlder); else @@ -775,6 +787,23 @@ NS_IMETHODIMP nsWindowWatcher::RemoveWindow(nsIDOMWindow *aWindow) { // find the corresponding WindowInfo, remove it + + if (!aWindow) + return NS_ERROR_INVALID_ARG; + + WindowInfo *info = FindWindowInfo(aWindow); + if (info) { + RemoveWindow(info); + return NS_OK; + } + NS_WARNING("requested removal of nonexistent window\n"); + return NS_ERROR_INVALID_ARG; +} + +WindowInfo * +nsWindowWatcher::FindWindowInfo(nsIDOMWindow *aWindow) +{ + // find the corresponding WindowInfo WindowInfo *info, *listEnd; #ifdef USEWEAKREFS @@ -782,9 +811,6 @@ nsWindowWatcher::RemoveWindow(nsIDOMWindow *aWindow) PRBool found; #endif - if (!aWindow) - return NS_ERROR_INVALID_ARG; - info = mOldestWindow; listEnd = 0; #ifdef USEWEAKREFS @@ -792,25 +818,23 @@ nsWindowWatcher::RemoveWindow(nsIDOMWindow *aWindow) found = PR_FALSE; while (info != listEnd && NS_SUCCEEDED(rv)) { nsCOMPtr infoWindow(do_QueryReferent(info->mWindow)); - if (!infoWindow) + if (!infoWindow) // clean up dangling reference, while we're here rv = RemoveWindow(info); - else if (infoWindow.get() == aWindow) { - found = PR_TRUE; - rv = RemoveWindow(info); - } + else if (infoWindow.get() == aWindow) + return info; + info = info->mYounger; listEnd = mOldestWindow; } - return found ? rv : NS_ERROR_INVALID_ARG; + return 0; #else while (info != listEnd) { if (info->mWindow == aWindow) - return RemoveWindow(info); + return info; info = info->mYounger; listEnd = mOldestWindow; } - NS_WARNING("requested removal of nonexistent window\n"); - return NS_ERROR_INVALID_ARG; + return 0; #endif } @@ -830,6 +854,10 @@ nsresult nsWindowWatcher::RemoveWindow(WindowInfo *inInfo) if (inInfo == mOldestWindow) mOldestWindow = inInfo->mYounger == mOldestWindow ? 0 : inInfo->mYounger; inInfo->Unlink(); + + // clear the active window, if they're the same + if (mActiveWindow == inInfo->mWindow) + mActiveWindow = 0; } // a window being removed from us signifies a newly closed window. @@ -851,6 +879,22 @@ nsresult nsWindowWatcher::RemoveWindow(WindowInfo *inInfo) return NS_OK; } +NS_IMETHODIMP +nsWindowWatcher::GetChromeForWindow(nsIDOMWindow *aWindow, nsIWebBrowserChrome **_retval) +{ + if (!aWindow || !_retval) + return NS_ERROR_INVALID_ARG; + *_retval = 0; + + nsAutoLock lock(mListLock); + WindowInfo *info = FindWindowInfo(aWindow); + if (info) { + *_retval = info->mChrome; + NS_IF_ADDREF(*_retval); + } + return NS_OK; +} + PRBool nsWindowWatcher::AddEnumerator(nsWindowEnumerator* inEnumerator) { diff --git a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h index bea547a34bc..430f58e39b1 100644 --- a/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h +++ b/mozilla/embedding/components/windowwatcher/src/nsWindowWatcher.h @@ -67,6 +67,7 @@ private: PRBool AddEnumerator(nsWindowEnumerator* inEnumerator); PRBool RemoveEnumerator(nsWindowEnumerator* inEnumerator); + WindowInfo *FindWindowInfo(nsIDOMWindow *aWindow); nsresult RemoveWindow(WindowInfo *inInfo); nsresult FindItemWithName(const PRUnichar *aName, diff --git a/mozilla/xpfe/appshell/src/nsWindowMediator.cpp b/mozilla/xpfe/appshell/src/nsWindowMediator.cpp index 909c6328942..70bf1f49cea 100644 --- a/mozilla/xpfe/appshell/src/nsWindowMediator.cpp +++ b/mozilla/xpfe/appshell/src/nsWindowMediator.cpp @@ -27,6 +27,7 @@ #include "nsVoidArray.h" #include "rdf.h" #include "nsIBaseWindow.h" +#include "nsIDOMWindow.h" #include "nsIDOMWindowInternal.h" #include "nsIDOMElement.h" #include "nsIDocumentViewer.h" @@ -41,7 +42,6 @@ #include "nsIServiceManager.h" #include "nsISimpleEnumerator.h" #include "nsIWebShell.h" -#include "nsIWindowMediator.h" #include "nsRDFCID.h" #include "nsWindowMediator.h" #include "nsXPIDLString.h" @@ -492,6 +492,18 @@ NS_IMETHODIMP nsWindowMediator::UnregisterWindow( nsWindowInfo *inInfo ) mTopmostWindow = 0; delete inInfo; + // inform WindowWatcher + nsWindowInfo *info = MostRecentWindowInfo(0); + nsCOMPtr domWindow; + if (info && info->mWindow) { + nsCOMPtr idomWindow; + GetDOMWindow(info->mWindow, idomWindow); + domWindow = do_QueryInterface(idomWindow); + } + + // failure or no more windows sets it to 0, which is acceptable + mWatcher->SetActiveWindow(domWindow); + return NS_OK; } @@ -539,34 +551,18 @@ PRInt32 nsWindowMediator::RemoveEnumerator( nsWindowEnumerator* inEnumerator) */ NS_IMETHODIMP nsWindowMediator::GetMostRecentWindow( const PRUnichar* inType, nsIDOMWindowInternal** outWindow ) { + NS_ENSURE_ARG_POINTER(outWindow); *outWindow = NULL; - PRInt32 lastTimeStamp = -1; - nsIXULWindow* mostRecentWindow = NULL; - nsAutoString typeString( inType ); - PRBool allWindows = !inType || typeString.Length() == 0; // Find the most window with the highest time stamp that matches // the requested type - nsWindowInfo *info, - *listEnd; nsAutoLock lock(mListLock); - info = mOldestWindow; - listEnd = 0; - while (info != listEnd) { - if ((allWindows || info->GetType() == typeString) && - info->mTimeStamp >= lastTimeStamp) { + nsWindowInfo *info = MostRecentWindowInfo(inType); - mostRecentWindow = info->mWindow; - lastTimeStamp = info->mTimeStamp; - } - info = info->mYounger; - listEnd = mOldestWindow; - } - - if (mostRecentWindow) { + if (info && info->mWindow) { nsCOMPtr DOMWindow; - if( NS_SUCCEEDED ( GetDOMWindow( mostRecentWindow, DOMWindow ) ) ) { + if(NS_SUCCEEDED(GetDOMWindow(info->mWindow, DOMWindow))) { *outWindow = DOMWindow; (*outWindow)->AddRef(); return NS_OK; @@ -578,6 +574,35 @@ NS_IMETHODIMP nsWindowMediator::GetMostRecentWindow( const PRUnichar* inType, ns } +nsWindowInfo * +nsWindowMediator::MostRecentWindowInfo(const PRUnichar* inType) +{ + PRInt32 lastTimeStamp = -1; + nsAutoString typeString(inType); + PRBool allWindows = !inType || typeString.Length() == 0; + + // Find the most window with the highest time stamp that matches + // the requested type + nsWindowInfo *searchInfo, + *listEnd, + *foundInfo = 0; + + searchInfo = mOldestWindow; + listEnd = 0; + while (searchInfo != listEnd) { + if ((allWindows || searchInfo->GetType() == typeString) && + searchInfo->mTimeStamp >= lastTimeStamp) { + + foundInfo = searchInfo; + lastTimeStamp = searchInfo->mTimeStamp; + } + searchInfo = searchInfo->mYounger; + listEnd = mOldestWindow; + } + return foundInfo; +} + + NS_IMETHODIMP nsWindowMediator::UpdateWindowTimeStamp( nsIXULWindow* inWindow ) { nsWindowInfo *info, @@ -588,7 +613,17 @@ NS_IMETHODIMP nsWindowMediator::UpdateWindowTimeStamp( nsIXULWindow* inWindow ) listEnd = 0; while (info != listEnd) { if (info->mWindow.get() == inWindow) { + // increment the window's time stamp info->mTimeStamp = ++mTimeStamp; + + // inform WindowWatcher + nsCOMPtr idomwindow; + GetDOMWindow(info->mWindow, idomwindow); + nsCOMPtr domwindow(do_QueryInterface(idomwindow)); + // if for some reason anything failed, it'll be set to 0, which is + // better than an invalid pointer. + mWatcher->SetActiveWindow(domwindow); + return NS_OK; } info = info->mYounger; @@ -958,6 +993,10 @@ nsWindowMediator::Init() if ( gRDFService == NULL ) return NS_ERROR_NULL_POINTER; + mWatcher = do_GetService("@mozilla.org/embedcomp/window-watcher;1", &rv); + if (NS_FAILED(rv)) + return rv; + // register this as a named data source with the RDF service return gRDFService->RegisterDataSource(this, PR_FALSE); } diff --git a/mozilla/xpfe/appshell/src/nsWindowMediator.h b/mozilla/xpfe/appshell/src/nsWindowMediator.h index ef3f758df35..d653c7fcae4 100644 --- a/mozilla/xpfe/appshell/src/nsWindowMediator.h +++ b/mozilla/xpfe/appshell/src/nsWindowMediator.h @@ -23,7 +23,9 @@ #ifndef __nsWindowMediator_h #define __nsWindowMediator_h +#include "nsCOMPtr.h" #include "nsIWindowMediator.h" +#include "nsIWindowWatcher.h" #include "nsXPIDLString.h" class nsWindowEnumerator; @@ -171,6 +173,7 @@ private: nsresult AddWindowToRDF( nsWindowInfo* ioWindowInfo ); PRInt32 AddEnumerator( nsWindowEnumerator* inEnumerator ); PRInt32 RemoveEnumerator( nsWindowEnumerator* inEnumerator); + nsWindowInfo *MostRecentWindowInfo(const PRUnichar* inType); NS_IMETHOD UnregisterWindow( nsWindowInfo *inInfo ); @@ -179,6 +182,7 @@ private: *mTopmostWindow; PRInt32 mTimeStamp; PRLock *mListLock; + nsCOMPtr mWatcher; // pseudo-constants for RDF static nsIRDFResource* kNC_WindowMediatorRoot;