Bug 326877, close popups when navigating pages, r+sr=bz

This commit is contained in:
enndeakin%sympatico.ca 2007-01-25 17:59:20 +00:00
parent 8a39ba9ca2
commit 42cfbd51a9
4 changed files with 116 additions and 21 deletions

View File

@ -120,6 +120,7 @@
#include "nsPIDOMWindow.h"
#include "nsJSEnvironment.h"
#include "nsIFocusController.h"
#include "nsIMenuParent.h"
#include "nsIScrollableView.h"
#include "nsIHTMLDocument.h"
@ -370,6 +371,8 @@ private:
nsresult GetPopupLinkNode(nsIDOMNode** aNode);
nsresult GetPopupImageNode(nsIImageLoadingContent** aNode);
void HideViewIfPopup(nsIView* aView);
void DumpContentToPPM(const char* aFileName);
void PrepareToStartLoad(void);
@ -1247,36 +1250,69 @@ DocumentViewerImpl::PageHide(PRBool aIsUnload)
}
mDocument->OnPageHide(!aIsUnload);
if (!aIsUnload)
return NS_OK;
if (aIsUnload) {
// if Destroy() was called during OnPageHide(), mDocument is nsnull.
NS_ENSURE_STATE(mDocument);
// if Destroy() was called during OnPageHide(), mDocument is nsnull.
NS_ENSURE_STATE(mDocument);
// First, get the window from the document...
nsPIDOMWindow *window = mDocument->GetWindow();
// First, get the window from the document...
nsPIDOMWindow *window = mDocument->GetWindow();
if (!window) {
// Fail if no window is available...
NS_ERROR("window not set for document!");
return NS_ERROR_NULL_POINTER;
}
if (!window) {
// Fail if no window is available...
NS_ERROR("window not set for document!");
return NS_ERROR_NULL_POINTER;
// Now, fire an Unload event to the document...
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event(PR_TRUE, NS_PAGE_UNLOAD);
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
// XXX Dispatching to |window|, but using |document| as the target.
event.target = mDocument;
// Never permit popups from the unload handler, no matter how we get
// here.
nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
}
// Now, fire an Unload event to the document...
nsEventStatus status = nsEventStatus_eIgnore;
nsEvent event(PR_TRUE, NS_PAGE_UNLOAD);
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
// XXX Dispatching to |window|, but using |document| as the target.
event.target = mDocument;
if (mPresShell) {
// look for open menupopups and close them after the unload event, in case
// the unload event listeners open any new popups
nsIViewManager *vm = mPresShell->GetViewManager();
if (vm) {
nsIView *rootView = nsnull;
vm->GetRootView(rootView);
if (rootView)
HideViewIfPopup(rootView);
}
}
// Never permit popups from the unload handler, no matter how we get
// here.
nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
return NS_OK;
}
void
DocumentViewerImpl::HideViewIfPopup(nsIView* aView)
{
nsIFrame* frame = NS_STATIC_CAST(nsIFrame*, aView->GetClientData());
if (frame) {
nsIMenuParent* parent;
CallQueryInterface(frame, &parent);
if (parent) {
parent->HideChain();
// really make sure the view is hidden
mViewManager->SetViewVisibility(aView, nsViewVisibility_kHide);
}
}
nsIView* child = aView->GetFirstChild();
while (child) {
HideViewIfPopup(child);
child = child->GetNextSibling();
}
}
static void
AttachContainerRecurse(nsIDocShell* aShell)
{

View File

@ -44,6 +44,7 @@
#include "nsGUIEvent.h"
#include "nsIDOMNSUIEvent.h"
#include "nsMenuBarListener.h"
#include "nsPopupSetFrame.h"
class nsMenuBoxObject : public nsIMenuBoxObject, public nsBoxObject
{
@ -92,6 +93,9 @@ NS_IMETHODIMP nsMenuBoxObject::OpenMenu(PRBool aOpenFlag)
if (!frame)
return NS_OK;
if (!nsPopupSetFrame::MayOpenPopup(frame))
return NS_OK;
nsIMenuFrame* menuFrame;
CallQueryInterface(frame, &menuFrame);
if (!menuFrame)

View File

@ -66,6 +66,12 @@
#include "nsCSSFrameConstructor.h"
#include "nsGUIEvent.h"
#include "nsIRootBox.h"
#include "nsIFocusController.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShell.h"
#include "nsPIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIBaseWindow.h"
#define NS_MENU_POPUP_LIST_INDEX 0
@ -363,6 +369,9 @@ nsPopupSetFrame::ShowPopup(nsIContent* aElementContent, nsIContent* aPopupConten
const nsString& aPopupType, const nsString& anAnchorAlignment,
const nsString& aPopupAlignment)
{
if (!MayOpenPopup(this))
return NS_OK;
nsWeakFrame weakFrame(this);
// First fire the popupshowing event.
if (!OnCreate(aXPos, aYPos, aPopupContent) || !weakFrame.IsAlive())
@ -825,3 +834,42 @@ nsPopupSetFrame::AddPopupFrame(nsIFrame* aPopup)
return NS_OK;
}
//static
PRBool
nsPopupSetFrame::MayOpenPopup(nsIFrame* aFrame)
{
nsCOMPtr<nsISupports> cont = aFrame->GetPresContext()->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont);
if (!dsti)
return PR_FALSE;
// chrome shells can always open popups
PRInt32 type = -1;
if (NS_SUCCEEDED(dsti->GetItemType(&type)) && type == nsIDocShellTreeItem::typeChrome)
return PR_TRUE;
nsCOMPtr<nsIDocShell> shell = do_QueryInterface(dsti);
if (!shell)
return PR_FALSE;
nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(shell);
if (!win)
return PR_FALSE;
// only allow popups in active windows
PRBool active;
nsIFocusController* focusController = win->GetRootFocusController();
focusController->GetActive(&active);
if (!active)
return PR_FALSE;
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(shell);
if (!baseWin)
return PR_FALSE;
// only allow popups in visible frames
PRBool visible;
baseWin->GetVisibility(&visible);
return visible;
}

View File

@ -132,6 +132,13 @@ public:
void ActivatePopup(nsPopupFrameList* aEntry, PRBool aActivateFlag);
void OpenPopup(nsPopupFrameList* aEntry, PRBool aOpenFlag);
/**
* Return true if the docshell containing aFrame may open a popup. aFrame
* doesn't need to be any particular type of frame, just a frame in the
* same document.
*/
static PRBool MayOpenPopup(nsIFrame* aFrame);
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const
{