Bug 390589, capture not being released in some cases when popup is closed, fixes some focus issues, r+sr=bz,a=dbaron

This commit is contained in:
enndeakin@sympatico.ca 2007-08-15 07:03:21 -07:00
parent 1eddf617ec
commit c655665c6a
2 changed files with 43 additions and 20 deletions

View File

@ -561,6 +561,9 @@ protected:
// get the nsMenuPopupFrame, if any, for the given content node
nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent);
// return the topmost menu, skipping over invisible popups
nsMenuChainItem* GetTopVisibleMenu();
// callbacks for ShowPopup and HidePopup as events may be done asynchronously
void ShowPopupCallback(nsIContent* aPopup,
nsMenuPopupFrame* aPopupFrame,

View File

@ -170,7 +170,8 @@ NS_IMETHODIMP nsXULPopupManager::ShouldRollupOnMouseWheelEvent(PRBool *aShouldRo
{
// should rollup only for autocomplete widgets
// XXXndeakin this should really be something the popup has more control over
*aShouldRollup = (mCurrentMenu && !mCurrentMenu->Frame()->IsMenu());
nsMenuChainItem* item = GetTopVisibleMenu();
*aShouldRollup = (item && !item->Frame()->IsMenu());
return NS_OK;
}
@ -189,7 +190,7 @@ nsXULPopupManager::GetSubmenuWidgetChain(nsISupportsArray **_retval)
// panels will roll up. If the click is inside a popup, they will not roll up
nsresult rv = NS_NewISupportsArray(_retval);
NS_ENSURE_SUCCESS(rv, rv);
nsMenuChainItem* item = mCurrentMenu;
nsMenuChainItem* item = GetTopVisibleMenu();
while (item) {
nsCOMPtr<nsIWidget> widget;
item->Frame()->GetWidget(getter_AddRefs(widget));
@ -238,6 +239,15 @@ nsXULPopupManager::GetPopupFrameForContent(nsIContent* aContent)
(GetFrameOfTypeForContent(aContent, nsGkAtoms::menuPopupFrame));
}
nsMenuChainItem*
nsXULPopupManager::GetTopVisibleMenu()
{
nsMenuChainItem* item = mCurrentMenu;
while (item && item->Frame()->PopupState() == ePopupInvisible)
item = item->GetParent();
return item;
}
void
nsXULPopupManager::GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset)
{
@ -676,7 +686,7 @@ nsXULPopupManager::HidePopupAfterDelay(nsMenuPopupFrame* aPopup)
void
nsXULPopupManager::HidePopupsInDocument(nsIDocument* aDocument)
{
nsMenuChainItem* item = mCurrentMenu;
nsMenuChainItem* item = GetTopVisibleMenu();
while (item) {
nsMenuChainItem* parent = item->GetParent();
if (item->Content()->GetOwnerDoc() == aDocument) {
@ -697,6 +707,8 @@ nsXULPopupManager::HidePopupsInDocument(nsIDocument* aDocument)
}
item = parent;
}
SetCaptureState(nsnull);
}
void
@ -707,7 +719,7 @@ nsXULPopupManager::ExecuteMenu(nsIContent* aMenu, nsEvent* aEvent)
// opens a modal dialog. The views associated with the popups needed to be
// hidden and the accesibility events fired before the command executes, but
// the popuphiding/popuphidden events are fired afterwards.
nsMenuChainItem* item = mCurrentMenu;
nsMenuChainItem* item = GetTopVisibleMenu();
while (item) {
// if it isn't a <menupopup>, don't close it automatically
if (!item->IsMenu())
@ -718,6 +730,8 @@ nsXULPopupManager::ExecuteMenu(nsIContent* aMenu, nsEvent* aEvent)
item = next;
}
SetCaptureState(nsnull);
// Create a trusted event if the triggering event was trusted, or if
// we're called from chrome code (since at least one of our caller
// passes in a null event).
@ -867,7 +881,7 @@ nsXULPopupManager::IsPopupOpen(nsIContent* aPopup)
PRBool
nsXULPopupManager::IsPopupOpenForMenuParent(nsIMenuParent* aMenuParent)
{
nsMenuChainItem* item = mCurrentMenu;
nsMenuChainItem* item = GetTopVisibleMenu();
while (item) {
nsMenuPopupFrame* popup = item->Frame();
if (popup && popup->IsOpen()) {
@ -891,7 +905,8 @@ nsXULPopupManager::GetOpenPopups()
nsMenuChainItem* item = mCurrentMenu;
while (item) {
popups.AppendElement(static_cast<nsIFrame*>(item->Frame()));
if (item->Frame()->PopupState() != ePopupInvisible)
popups.AppendElement(static_cast<nsIFrame*>(item->Frame()));
item = item->GetParent();
}
@ -1037,7 +1052,7 @@ nsXULPopupManager::PopupDestroyed(nsMenuPopupFrame* aPopup)
PRBool
nsXULPopupManager::HasContextMenu(nsMenuPopupFrame* aPopup)
{
nsMenuChainItem* item = mCurrentMenu;
nsMenuChainItem* item = GetTopVisibleMenu();
while (item && item->Frame() != aPopup) {
if (item->IsContextMenu())
return PR_TRUE;
@ -1050,7 +1065,8 @@ nsXULPopupManager::HasContextMenu(nsMenuPopupFrame* aPopup)
void
nsXULPopupManager::SetCaptureState(nsIContent* aOldPopup)
{
if (mCurrentMenu && aOldPopup == mCurrentMenu->Content())
nsMenuChainItem* item = GetTopVisibleMenu();
if (item && aOldPopup == item->Content())
return;
if (mWidget) {
@ -1058,8 +1074,8 @@ nsXULPopupManager::SetCaptureState(nsIContent* aOldPopup)
mWidget = nsnull;
}
if (mCurrentMenu) {
nsMenuPopupFrame* popup = mCurrentMenu->Frame();
if (item) {
nsMenuPopupFrame* popup = item->Frame();
nsCOMPtr<nsIWidget> widget;
popup->GetWidget(getter_AddRefs(widget));
if (widget) {
@ -1076,9 +1092,10 @@ void
nsXULPopupManager::UpdateKeyboardListeners()
{
nsCOMPtr<nsIDOMEventTarget> newTarget;
if (mCurrentMenu) {
if (!mCurrentMenu->IgnoreKeys())
newTarget = do_QueryInterface(mCurrentMenu->Content()->GetDocument());
nsMenuChainItem* item = GetTopVisibleMenu();
if (item) {
if (!item->IgnoreKeys())
newTarget = do_QueryInterface(item->Content()->GetDocument());
}
else if (mActiveMenuBar) {
newTarget = do_QueryInterface(mActiveMenuBar->GetContent()->GetDocument());
@ -1226,8 +1243,9 @@ PRBool
nsXULPopupManager::HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent,
nsMenuPopupFrame* aFrame)
{
if (!aFrame && mCurrentMenu)
aFrame = mCurrentMenu->Frame();
nsMenuChainItem* item = GetTopVisibleMenu();
if (!aFrame && item)
aFrame = item->Frame();
if (aFrame) {
PRBool action;
@ -1266,7 +1284,7 @@ nsXULPopupManager::HandleKeyboardNavigation(PRUint32 aKeyCode)
// navigate up through the open menus, looking for the topmost one
// in the same hierarchy
nsMenuChainItem* item = nsnull;
nsMenuChainItem* nextitem = mCurrentMenu;
nsMenuChainItem* nextitem = GetTopVisibleMenu();
while (nextitem) {
item = nextitem;
@ -1609,8 +1627,9 @@ nsXULPopupManager::KeyPress(nsIDOMEvent* aKeyEvent)
}
else if (theChar == NS_VK_ESCAPE) {
// Pressing Escape hides one level of menus only
if (mCurrentMenu)
HidePopup(mCurrentMenu->Content(), PR_FALSE, PR_FALSE, PR_FALSE);
nsMenuChainItem* item = GetTopVisibleMenu();
if (item)
HidePopup(item->Content(), PR_FALSE, PR_FALSE, PR_FALSE);
}
else if (theChar == NS_VK_TAB) {
Rollup();
@ -1621,8 +1640,9 @@ nsXULPopupManager::KeyPress(nsIDOMEvent* aKeyEvent)
// Otherwise, tell the active menubar, if any, to activate the menu. The
// Enter method will return a menu if one needs to be opened as a result.
nsMenuFrame* menuToOpen = nsnull;
if (mCurrentMenu)
menuToOpen = mCurrentMenu->Frame()->Enter();
nsMenuChainItem* item = GetTopVisibleMenu();
if (item)
menuToOpen = item->Frame()->Enter();
else if (mActiveMenuBar)
menuToOpen = mActiveMenuBar->Enter();
if (menuToOpen) {