diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index f607fcd5c2d8..ca69a77e16f0 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1152,6 +1152,12 @@ public: nsNativeKeyEvent* aNativeEvent, PRBool aGetCharCode); + /** + * Hide any XUL popups associated with aDocument, including any documents + * displayed in child frames. + */ + static void HidePopupsInDocument(nsIDocument* aDocument); + /** * Get the application manifest URI for this context. The manifest URI * is specified in the manifest= attribute of the root element of the diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 42d0857265aa..b55550d32028 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -145,6 +145,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsIDOMNSUIEvent.h" #include "nsIDOMNSEvent.h" #include "nsIPrivateDOMEvent.h" +#include "nsXULPopupManager.h" #include "nsIPermissionManager.h" #ifdef IBMBIDI @@ -3924,6 +3925,21 @@ nsContentUtils::DOMEventToNativeKeyEvent(nsIDOMEvent* aDOMEvent, return PR_TRUE; } +/* static */ +void +nsContentUtils::HidePopupsInDocument(nsIDocument* aDocument) +{ + NS_PRECONDITION(aDocument, "Null document"); + + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); + if (pm) { + nsCOMPtr container = aDocument->GetContainer(); + nsCOMPtr docShellToHide = do_QueryInterface(container); + if (docShellToHide) + pm->HidePopupsInDocShell(docShellToHide); + } +} + /* static */ void nsAutoGCRoot::Shutdown() diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 3cd3708f1dc6..18d771c47b2c 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -3297,10 +3297,8 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight) #ifdef MOZ_XUL if (!nsContentUtils::IsCallerTrustedForWrite()) { // if attempting to resize the window, hide any open popups - nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); nsCOMPtr doc(do_QueryInterface(mDocument)); - if (pm && doc) - pm->HidePopupsInDocument(doc); + nsContentUtils::HidePopupsInDocument(doc); } #endif @@ -3332,10 +3330,8 @@ nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop) if (!nsContentUtils::IsCallerTrustedForWrite()) { #ifdef MOZ_XUL // if attempting to move the window, hide any open popups - nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); nsCOMPtr doc(do_QueryInterface(mDocument)); - if (pm && doc) - pm->HidePopupsInDocument(doc); + nsContentUtils::HidePopupsInDocument(doc); #endif PRInt32 screenLeft, screenTop, screenWidth, screenHeight; diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index ba9bd02ee06c..bab3ac1fd033 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1179,9 +1179,8 @@ DocumentViewerImpl::PageHide(PRBool aIsUnload) #ifdef MOZ_XUL // look for open menupopups and close them after the unload event, in case // the unload event listeners open any new popups - nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); - if (pm && mDocument) - pm->HidePopupsInDocument(mDocument); + if (mDocument) + nsContentUtils::HidePopupsInDocument(mDocument); #endif return NS_OK; diff --git a/layout/generic/nsFrameFrame.cpp b/layout/generic/nsFrameFrame.cpp index 3c010c19c7e6..3b66578af62f 100644 --- a/layout/generic/nsFrameFrame.cpp +++ b/layout/generic/nsFrameFrame.cpp @@ -21,7 +21,7 @@ * * Contributor(s): * Travis Bogard - * Håkan Waara + * HÂkan Waara * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -94,6 +94,10 @@ #include "nsIObjectLoadingContent.h" #include "nsLayoutUtils.h" +#ifdef MOZ_XUL +#include "nsXULPopupManager.h" +#endif + // For Accessibility #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" @@ -673,6 +677,15 @@ nsSubDocumentFrame::AttributeChanged(PRInt32 aNameSpaceID, PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary"); +#ifdef MOZ_XUL + // when a content panel is no longer primary, hide any open popups it may have + if (!is_primary) { + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); + if (pm) + pm->HidePopupsInDocShell(docShellAsItem); + } +#endif + parentTreeOwner->ContentShellRemoved(docShellAsItem); if (value.LowerCaseEqualsLiteral("content") || diff --git a/layout/xul/base/public/nsXULPopupManager.h b/layout/xul/base/public/nsXULPopupManager.h index 7b077f051b7b..1172e6bc3a61 100644 --- a/layout/xul/base/public/nsXULPopupManager.h +++ b/layout/xul/base/public/nsXULPopupManager.h @@ -75,6 +75,7 @@ class nsMenuPopupFrame; class nsMenuBarFrame; class nsIMenuParent; class nsIDOMKeyEvent; +class nsIDocShellTreeItem; enum nsPopupType { ePopupTypePanel, @@ -473,10 +474,10 @@ public: void HidePopupAfterDelay(nsMenuPopupFrame* aPopup); /** - * Hide all of the popups from a given document. This should be called when the + * Hide all of the popups from a given docshell. This should be called when the * document is hidden. */ - void HidePopupsInDocument(nsIDocument* aDocument); + void HidePopupsInDocShell(nsIDocShellTreeItem* aDocShellToHide); /** * Execute a menu command from the triggering event aEvent. @@ -712,6 +713,11 @@ protected: */ void UpdateKeyboardListeners(); + /* + * Returns true if the docshell for aDoc is aExpected or a child of aExpected. + */ + PRBool IsChildOfDocShell(nsIDocument* aDoc, nsIDocShellTreeItem* aExpected); + // the document the key event listener is attached to nsCOMPtr mKeyListener; diff --git a/layout/xul/base/src/nsXULPopupManager.cpp b/layout/xul/base/src/nsXULPopupManager.cpp index 78eddd2339d4..6cc44cf6f2fd 100644 --- a/layout/xul/base/src/nsXULPopupManager.cpp +++ b/layout/xul/base/src/nsXULPopupManager.cpp @@ -60,6 +60,7 @@ #include "nsPIDOMWindow.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIBaseWindow.h" +#include "nsIDocShellTreeItem.h" // See matching definitions in nsXULPopupManager.h nsNavigationDirection DirectionFromKeyCode_lr_tb [6] = { @@ -765,8 +766,25 @@ nsXULPopupManager::HidePopupsInList(const nsTArray &aFrames, SetCaptureState(nsnull); } +PRBool +nsXULPopupManager::IsChildOfDocShell(nsIDocument* aDoc, nsIDocShellTreeItem* aExpected) +{ + nsCOMPtr doc = aDoc->GetContainer(); + nsCOMPtr docShellItem(do_QueryInterface(doc)); + while(docShellItem) { + if (docShellItem == aExpected) + return PR_TRUE; + + nsCOMPtr parent; + docShellItem->GetParent(getter_AddRefs(parent)); + docShellItem = parent; + } + + return PR_FALSE; +} + void -nsXULPopupManager::HidePopupsInDocument(nsIDocument* aDocument) +nsXULPopupManager::HidePopupsInDocShell(nsIDocShellTreeItem* aDocShellToHide) { nsTArray popupsToHide; @@ -775,7 +793,7 @@ nsXULPopupManager::HidePopupsInDocument(nsIDocument* aDocument) while (item) { nsMenuChainItem* parent = item->GetParent(); if (item->Frame()->PopupState() != ePopupInvisible && - aDocument && item->Content()->GetOwnerDoc() == aDocument) { + IsChildOfDocShell(item->Content()->GetOwnerDoc(), aDocShellToHide)) { nsMenuPopupFrame* frame = item->Frame(); item->Detach(&mCurrentMenu); delete item; @@ -789,7 +807,7 @@ nsXULPopupManager::HidePopupsInDocument(nsIDocument* aDocument) while (item) { nsMenuChainItem* parent = item->GetParent(); if (item->Frame()->PopupState() != ePopupInvisible && - aDocument && item->Content()->GetOwnerDoc() == aDocument) { + IsChildOfDocShell(item->Content()->GetOwnerDoc(), aDocShellToHide)) { nsMenuPopupFrame* frame = item->Frame(); item->Detach(&mPanels); delete item;