Bug 279703, rework XUL popups to use asynchronous opening, plus many other fixes, attempt 2 with creating widgets later, r=bz,neil,roc,sr=bz
authorenndeakin@sympatico.ca
Wed, 04 Jul 2007 08:49:38 -0700
changeset 3129 d9b35fd9b4bfbe097b5f35f8eaba27b17da5655c
parent 3128 2d150fce1f74b6a03665c06d87a4d33fe4d6a4fe
child 3130 8ae2838ee0aa995d242c6bea62966780d96bfb1b
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, neil, roc, bz
bugs279703
milestone1.9a7pre
Bug 279703, rework XUL popups to use asynchronous opening, plus many other fixes, attempt 2 with creating widgets later, r=bz,neil,roc,sr=bz
accessible/src/base/nsRootAccessible.cpp
browser/base/content/browser.xul
content/base/src/nsDocument.cpp
content/base/src/nsGkAtomList.h
content/xul/content/Makefile.in
content/xul/content/public/Makefile.in
content/xul/content/public/nsIXULPopupListener.h
content/xul/content/src/nsXULElement.cpp
content/xul/content/src/nsXULPopupListener.cpp
content/xul/content/src/nsXULPopupListener.h
content/xul/document/src/nsXULDocument.cpp
dom/public/idl/xul/nsIDOMXULDocument.idl
dom/src/base/nsGlobalWindow.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsDocumentViewer.cpp
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/build/nsLayoutModule.cpp
layout/build/nsLayoutStatics.cpp
layout/generic/nsContainerFrame.cpp
layout/xul/base/public/Makefile.in
layout/xul/base/public/nsIMenuFrame.h
layout/xul/base/public/nsIPopupBoxObject.idl
layout/xul/base/public/nsIPopupSetFrame.h
layout/xul/base/public/nsXULPopupManager.h
layout/xul/base/src/Makefile.in
layout/xul/base/src/nsBoxFrame.cpp
layout/xul/base/src/nsBoxFrame.h
layout/xul/base/src/nsIMenuParent.h
layout/xul/base/src/nsIRootBox.h
layout/xul/base/src/nsMenuBarFrame.cpp
layout/xul/base/src/nsMenuBarFrame.h
layout/xul/base/src/nsMenuBarListener.cpp
layout/xul/base/src/nsMenuBarListener.h
layout/xul/base/src/nsMenuBoxObject.cpp
layout/xul/base/src/nsMenuDismissalListener.cpp
layout/xul/base/src/nsMenuDismissalListener.h
layout/xul/base/src/nsMenuFrame.cpp
layout/xul/base/src/nsMenuFrame.h
layout/xul/base/src/nsMenuListener.cpp
layout/xul/base/src/nsMenuListener.h
layout/xul/base/src/nsMenuPopupFrame.cpp
layout/xul/base/src/nsMenuPopupFrame.h
layout/xul/base/src/nsPopupBoxObject.cpp
layout/xul/base/src/nsPopupSetFrame.cpp
layout/xul/base/src/nsPopupSetFrame.h
layout/xul/base/src/nsRootBoxFrame.cpp
layout/xul/base/src/nsXULPopupManager.cpp
layout/xul/base/src/nsXULTooltipListener.cpp
toolkit/components/autocomplete/public/nsIAutoCompleteController.idl
toolkit/components/autocomplete/public/nsIAutoCompletePopup.idl
toolkit/components/autocomplete/src/nsAutoCompleteController.cpp
toolkit/components/satchel/src/nsFormFillController.cpp
toolkit/content/widgets/autocomplete.xml
toolkit/content/widgets/popup.xml
toolkit/content/xul.css
toolkit/themes/gnomestripe/global/popup.css
toolkit/themes/pinstripe/global/autocomplete.css
toolkit/themes/pinstripe/global/popup.css
toolkit/themes/winstripe/global/autocomplete.css
toolkit/themes/winstripe/global/popup.css
widget/src/gtk2/nsNativeThemeGTK.cpp
widget/src/windows/nsNativeThemeWin.cpp
widget/src/xpwidgets/nsWidgetAtomList.h
xpfe/appshell/src/nsWebShellWindow.cpp
xpfe/components/autocomplete/resources/content/autocomplete.xml
xpfe/global/resources/content/bindings/popup.xml
xpfe/global/resources/content/xul.css
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -57,16 +57,17 @@
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULPopupElement.h"
 #include "nsIDocument.h"
 #include "nsIEventListenerManager.h"
 #include "nsIFocusController.h"
 #include "nsIFrame.h"
+#include "nsIMenuFrame.h"
 #include "nsIHTMLDocument.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMenuParent.h"
 #include "nsIScrollableView.h"
 #include "nsISelectionPrivate.h"
 #include "nsIServiceManager.h"
 #include "nsIViewManager.h"
 #include "nsPIDOMWindow.h"
@@ -796,32 +797,33 @@ nsresult nsRootAccessible::HandleEventWi
   else if (eventType.EqualsLiteral("DOMMenuInactive")) {
     if (Role(accessible) == nsIAccessibleRole::ROLE_MENUPOPUP) {
       privAcc->FireToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
                                 accessible, nsnull);
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
     if (!treeItemAccessible) {
-      nsCOMPtr<nsIAccessible> containerAccessible;
-      accessible->GetParent(getter_AddRefs(containerAccessible));
-      NS_ENSURE_TRUE(containerAccessible, NS_OK);
-      if (Role(containerAccessible) == nsIAccessibleRole::ROLE_MENUBAR) {
-        nsCOMPtr<nsPIAccessNode> menuBarAccessNode(do_QueryInterface(containerAccessible));
-        NS_ENSURE_TRUE(menuBarAccessNode, NS_ERROR_FAILURE);
-        nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(menuBarAccessNode->GetFrame());
-        NS_ENSURE_TRUE(menuParent, NS_ERROR_FAILURE);
-        PRBool isActive;
-        menuParent->GetIsActive(isActive);
-        if (!isActive) {
+      nsCOMPtr<nsPIAccessNode> menuAccessNode = do_QueryInterface(accessible);
+      NS_ENSURE_TRUE(menuAccessNode, NS_ERROR_FAILURE);
+      nsIFrame* menuFrame = menuAccessNode->GetFrame();
+      NS_ENSURE_TRUE(menuFrame, NS_ERROR_FAILURE);
+      nsIMenuFrame* imenuFrame;
+      CallQueryInterface(menuFrame, &imenuFrame);
+      NS_ENSURE_TRUE(imenuFrame, NS_ERROR_FAILURE);
+      if (imenuFrame->IsOnMenuBar()) {
+        if (!imenuFrame->IsOnActiveMenuBar()) {
           // It is a top level menuitem. Only fire a focus event when the menu bar
           // is active.
           return NS_OK;
         }
       } else {
+        nsCOMPtr<nsIAccessible> containerAccessible;
+        accessible->GetParent(getter_AddRefs(containerAccessible));
+        NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
         // It is not top level menuitem
         // Only fire focus event if it is not inside collapsed popup
         if (State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED)
           return NS_OK;
       }
     }
     FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE);
   }
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -102,17 +102,17 @@
            oncommand="gotoHistoryIndex(event);"
            onclick="checkForMiddleClick(this, event);"/>
     <tooltip id="aHTMLTooltip" onpopupshowing="return FillInHTMLTooltip(document.tooltipNode);">
       <hbox>
         <label flex="1" class="htmltooltip-label"/>
       </hbox>
     </tooltip>
 
-    <popup type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
+    <panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
 
     <popup id="toolbar-context-menu"
            onpopupshowing="onViewToolbarsPopupShowing(event);">
       <menuseparator/>
       <menuitem command="cmd_CustomizeToolbars"
                 label="&viewCustomizeToolbar.label;"
                 accesskey="&viewCustomizeToolbar.accesskey;"/>
     </popup>
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3677,16 +3677,17 @@ nsDocument::GetBoxObjectFor(nsIDOMElemen
     if (tag == nsGkAtoms::browser ||
         tag == nsGkAtoms::editor ||
         tag == nsGkAtoms::iframe)
       contractID += "-container";
     else if (tag == nsGkAtoms::menu)
       contractID += "-menu";
     else if (tag == nsGkAtoms::popup ||
              tag == nsGkAtoms::menupopup ||
+             tag == nsGkAtoms::panel ||
              tag == nsGkAtoms::tooltip)
       contractID += "-popup";
     else if (tag == nsGkAtoms::tree)
       contractID += "-tree";
     else if (tag == nsGkAtoms::listbox)
       contractID += "-listbox";
     else if (tag == nsGkAtoms::scrollbox)
       contractID += "-scrollbox";
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -483,17 +483,16 @@ GK_ATOM(mediaType, "media-type")
 GK_ATOM(member, "member")
 GK_ATOM(menu, "menu")
 GK_ATOM(menubar, "menubar")
 GK_ATOM(menubutton, "menubutton")
 GK_ATOM(menugenerated, "menugenerated")
 GK_ATOM(menuitem, "menuitem")
 GK_ATOM(menulist, "menulist")
 GK_ATOM(menupopup, "menupopup")
-GK_ATOM(menutobedisplayed, "menutobedisplayed")
 GK_ATOM(message, "message")
 GK_ATOM(meta, "meta")
 GK_ATOM(method, "method")
 GK_ATOM(middle, "middle")
 GK_ATOM(min, "min")
 GK_ATOM(minheight, "minheight")
 GK_ATOM(minpos, "minpos")
 GK_ATOM(minusSign, "minus-sign")
@@ -515,16 +514,17 @@ GK_ATOM(_namespace, "namespace")
 GK_ATOM(namespaceAlias, "namespace-alias")
 GK_ATOM(namespaceUri, "namespace-uri")
 GK_ATOM(NaN, "NaN")
 GK_ATOM(negate, "negate")
 GK_ATOM(never, "never")
 GK_ATOM(_new, "new")
 GK_ATOM(nextBidi, "NextBidi")
 GK_ATOM(no, "no")
+GK_ATOM(noautohide, "noautohide")
 GK_ATOM(nobr, "nobr")
 GK_ATOM(node, "node")
 GK_ATOM(nodeSet, "node-set")
 GK_ATOM(noembed, "noembed")
 GK_ATOM(noframes, "noframes")
 GK_ATOM(nohref, "nohref")
 GK_ATOM(none, "none")
 GK_ATOM(noresize, "noresize")
@@ -629,16 +629,17 @@ GK_ATOM(overlay, "overlay")
 GK_ATOM(overlap, "overlap")
 GK_ATOM(p, "p")
 GK_ATOM(pack, "pack")
 GK_ATOM(page, "page")
 GK_ATOM(pageincrement, "pageincrement")
 GK_ATOM(pagex, "pagex")
 GK_ATOM(pagey, "pagey")
 GK_ATOM(palettename, "palettename")
+GK_ATOM(panel, "panel")
 GK_ATOM(param, "param")
 GK_ATOM(parameter, "parameter")
 GK_ATOM(parent, "parent")
 GK_ATOM(parsetype, "parsetype")
 GK_ATOM(patternSeparator, "pattern-separator")
 GK_ATOM(perMille, "per-mille")
 GK_ATOM(percent, "percent")
 GK_ATOM(persist, "persist")
@@ -1386,22 +1387,25 @@ GK_ATOM(imageBoxFrame, "ImageBoxFrame")
 GK_ATOM(imageFrame, "ImageFrame")
 GK_ATOM(imageControlFrame, "ImageControlFrame")
 GK_ATOM(inlineFrame, "InlineFrame")
 GK_ATOM(leafBoxFrame, "LeafBoxFrame")
 GK_ATOM(legendFrame, "LegendFrame")
 GK_ATOM(letterFrame, "LetterFrame")
 GK_ATOM(lineFrame, "LineFrame")
 GK_ATOM(listControlFrame,"ListControlFrame")
+GK_ATOM(menuBarFrame,"MenuBarFrame")
+GK_ATOM(menuFrame,"MenuFrame")
 GK_ATOM(menuPopupFrame,"MenuPopupFrame")
 GK_ATOM(objectFrame, "ObjectFrame")
 GK_ATOM(pageFrame, "PageFrame")
 GK_ATOM(pageBreakFrame, "PageBreakFrame")
 GK_ATOM(pageContentFrame, "PageContentFrame")
 GK_ATOM(placeholderFrame, "PlaceholderFrame")
+GK_ATOM(popupSetFrame, "PopupSetFrame")
 GK_ATOM(positionedInlineFrame, "PositionedInlineFrame")
 GK_ATOM(canvasFrame, "CanvasFrame")
 GK_ATOM(rootFrame, "RootFrame")
 GK_ATOM(scrollFrame, "ScrollFrame")
 GK_ATOM(scrollbarFrame, "ScrollbarFrame")
 GK_ATOM(sequenceFrame, "SequenceFrame")
 GK_ATOM(sliderFrame, "sliderFrame")
 GK_ATOM(tableCaptionFrame, "TableCaptionFrame")
--- a/content/xul/content/Makefile.in
+++ b/content/xul/content/Makefile.in
@@ -38,12 +38,12 @@
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= xul
-DIRS		= public src test
+DIRS		= src test
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/content/xul/content/public/Makefile.in
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is mozilla.org code.
-#
-# The Initial Developer of the Original Code is
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#
-# 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"),
-# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH		= ../../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE		= xul
-
-ifdef MOZ_XUL
-EXPORTS		= \
-                nsIXULPopupListener.h \
-		$(NULL)
-endif
-
-include $(topsrcdir)/config/rules.mk
-
deleted file mode 100644
--- a/content/xul/content/public/nsIXULPopupListener.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsIXULPopupListener_h__
-#define nsIXULPopupListener_h__
-
-// {2C453161-0942-11d3-BF87-00105A1B0627}
-#define NS_IXULPOPUPLISTENER_IID \
-{ 0x2c453161, 0x942, 0x11d3, { 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } }
-
-class nsIDOMElement;
-
-typedef enum {
-    eXULPopupType_popup,
-    eXULPopupType_context,
-    eXULPopupType_tooltip,
-    eXULPopupType_blur
-} XULPopupType;
-
-class nsIXULPopupListener: public nsISupports {
-public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXULPOPUPLISTENER_IID)
-
-    NS_IMETHOD Init(nsIDOMElement* anElement, const XULPopupType& aPopupType) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIXULPopupListener, NS_IXULPOPUPLISTENER_IID)
-
-nsresult
-NS_NewXULPopupListener(nsIXULPopupListener** result);
-
-#endif // nsIXULPopupListener_h__
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -102,28 +102,28 @@
 #include "nsIScriptGlobalObjectOwner.h"
 #include "nsIServiceManager.h"
 #include "nsICSSStyleRule.h"
 #include "nsIStyleSheet.h"
 #include "nsIURL.h"
 #include "nsIViewManager.h"
 #include "nsIWidget.h"
 #include "nsIXULDocument.h"
-#include "nsIXULPopupListener.h"
 #include "nsIXULTemplateBuilder.h"
 #include "nsIXBLService.h"
 #include "nsLayoutCID.h"
 #include "nsContentCID.h"
 #include "nsRDFCID.h"
 #include "nsStyleConsts.h"
 #include "nsXPIDLString.h"
 #include "nsXULControllers.h"
 #include "nsIBoxObject.h"
 #include "nsPIBoxObject.h"
 #include "nsXULDocument.h"
+#include "nsXULPopupListener.h"
 #include "nsRuleWalker.h"
 #include "nsIDOMViewCSS.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsCSSDeclaration.h"
 #include "nsIListBoxObject.h"
 #include "nsContentUtils.h"
 #include "nsContentList.h"
 #include "nsMutationEvent.h"
@@ -2041,73 +2041,67 @@ nsXULElement::IsNodeOfType(PRUint32 aFla
 {
     return !(aFlags & ~(eCONTENT | eELEMENT | eXUL));
 }
 
 static void
 PopupListenerPropertyDtor(void* aObject, nsIAtom* aPropertyName,
                           void* aPropertyValue, void* aData)
 {
-  nsIXULPopupListener* listener =
-    NS_STATIC_CAST(nsIXULPopupListener*, aPropertyValue);
+  nsIDOMEventListener* listener =
+    NS_STATIC_CAST(nsIDOMEventListener*, aPropertyValue);
   if (!listener) {
     return;
   }
-  nsCOMPtr<nsIDOMEventListener> eventListener = do_QueryInterface(listener);
   nsCOMPtr<nsIDOMEventTarget> target =
     do_QueryInterface(NS_STATIC_CAST(nsINode*, aObject));
   if (target) {
-    target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), eventListener,
+    target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), listener,
                                 PR_FALSE);
-    target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), eventListener,
+    target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), listener,
                                 PR_FALSE);
   }
   NS_RELEASE(listener);
 }
 
 nsresult
 nsXULElement::AddPopupListener(nsIAtom* aName)
 {
-    XULPopupType popupType;
-    nsCOMPtr<nsIAtom> listenerAtom;
-    if (aName == nsGkAtoms::context || aName == nsGkAtoms::contextmenu) {
-        popupType = eXULPopupType_context;
-        listenerAtom = nsGkAtoms::contextmenulistener;
-    } else {
-        popupType = eXULPopupType_popup;
-        listenerAtom = nsGkAtoms::popuplistener;
-    }
-
-    nsCOMPtr<nsIXULPopupListener> popupListener =
-        NS_STATIC_CAST(nsIXULPopupListener*, GetProperty(listenerAtom));
+    // Add a popup listener to the element
+    PRBool isContext = (aName == nsGkAtoms::context ||
+                        aName == nsGkAtoms::contextmenu);
+    nsIAtom* listenerAtom = isContext ?
+                            nsGkAtoms::contextmenulistener :
+                            nsGkAtoms::popuplistener;
+
+    nsCOMPtr<nsIDOMEventListener> popupListener =
+        NS_STATIC_CAST(nsIDOMEventListener*, GetProperty(listenerAtom));
     if (popupListener) {
         // Popup listener is already installed.
         return NS_OK;
     }
-    // Add a popup listener to the element
-    nsresult rv;
-
-    popupListener = do_CreateInstance(kXULPopupListenerCID, &rv);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to create an instance of the popup listener object.");
-    if (NS_FAILED(rv)) return rv;
-
-    // Add a weak reference to the node.
-    popupListener->Init(this, popupType);
+
+    nsresult rv = NS_NewXULPopupListener(this, isContext,
+                                         getter_AddRefs(popupListener));
+    if (NS_FAILED(rv))
+        return rv;
 
     // Add the popup as a listener on this element.
-    nsCOMPtr<nsIDOMEventListener> eventListener = do_QueryInterface(popupListener);
     nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(NS_STATIC_CAST(nsIContent *, this)));
     NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
     rv = SetProperty(listenerAtom, popupListener, PopupListenerPropertyDtor,
                      PR_TRUE);
     NS_ENSURE_SUCCESS(rv, rv);
-    nsIXULPopupListener* listener = popupListener;
-    NS_ADDREF(listener);
-    target->AddEventListener(NS_LITERAL_STRING("mousedown"), eventListener, PR_FALSE);
-    target->AddEventListener(NS_LITERAL_STRING("contextmenu"), eventListener, PR_FALSE);
+    // Want the property to have a reference to the listener.
+    nsIDOMEventListener* listener = nsnull;
+    popupListener.swap(listener);
+    if (isContext)
+      target->AddEventListener(NS_LITERAL_STRING("contextmenu"), listener, PR_FALSE);
+    else
+      target->AddEventListener(NS_LITERAL_STRING("mousedown"), listener, PR_FALSE);
     return NS_OK;
 }
 
 PRInt32
 nsXULElement::IntrinsicState() const
 {
     PRInt32 state = nsGenericElement::IntrinsicState();
 
--- a/content/xul/content/src/nsXULPopupListener.cpp
+++ b/content/xul/content/src/nsXULPopupListener.cpp
@@ -39,180 +39,101 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
   This file provides the implementation for xul popup listener which
   tracks xul popups and context menus
  */
 
+#include "nsXULPopupListener.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentXBL.h"
-#include "nsIXULPopupListener.h"
-#include "nsIDOMMouseListener.h"
-#include "nsIDOMContextMenuListener.h"
 #include "nsContentCID.h"
 #include "nsContentUtils.h"
+#include "nsXULPopupManager.h"
 
 #include "nsIScriptContext.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDocument.h"
-#include "nsIContent.h"
-#include "nsIDOMMouseEvent.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMNSEvent.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
-
-#include "nsIBoxObject.h"
-#include "nsIPopupBoxObject.h"
+#include "nsLayoutUtils.h"
+#include "nsFrameManager.h"
+#include "nsHTMLReflowState.h"
 
 // for event firing in context menus
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsIEventStateManager.h"
 #include "nsIFocusController.h"
 #include "nsPIDOMWindow.h"
+#include "nsIViewManager.h"
 #include "nsDOMError.h"
-
-#include "nsIFrame.h"
 #include "nsIMenuFrame.h"
 
 // on win32 and os/2, context menus come up on mouse up. On other platforms,
 // they appear on mouse down. Certain bits of code care about this difference.
 #if !defined(XP_WIN) && !defined(XP_OS2)
 #define NS_CONTEXT_MENU_IS_MOUSEUP 1
 #endif
 
-
-////////////////////////////////////////////////////////////////////////
-// PopupListenerImpl
-//
-//   This is the popup listener implementation for popup menus and context menus.
-//
-class XULPopupListenerImpl : public nsIXULPopupListener,
-                             public nsIDOMMouseListener,
-                             public nsIDOMContextMenuListener
-{
-public:
-    XULPopupListenerImpl(void);
-    virtual ~XULPopupListenerImpl(void);
-
-public:
-    // nsISupports
-    NS_DECL_ISUPPORTS
-
-    // nsIXULPopupListener
-    NS_IMETHOD Init(nsIDOMElement* aElement, const XULPopupType& popupType);
-
-    // nsIDOMMouseListener
-    NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
-    NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-    NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-    NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-    NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-    NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-
-    // nsIDOMContextMenuListener
-    NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
-
-    // nsIDOMEventListener
-    NS_IMETHOD HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }
-
-protected:
-
-    virtual nsresult LaunchPopup(nsIDOMEvent* anEvent);
-    virtual nsresult LaunchPopup(PRInt32 aClientX, PRInt32 aClientY) ;
-
-private:
-
-    nsresult PreLaunchPopup(nsIDOMEvent* aMouseEvent);
-    nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode);
-
-    // |mElement| is the node to which this listener is attached.
-    nsIDOMElement* mElement;               // Weak ref. The element will go away first.
-
-    // The popup that is getting shown on top of mElement.
-    nsCOMPtr<nsIPopupBoxObject> mPopup;
-
-    // The type of the popup
-    XULPopupType popupType;
-    
-};
-
-////////////////////////////////////////////////////////////////////////
-      
-XULPopupListenerImpl::XULPopupListenerImpl(void)
-  : mElement(nsnull)
+nsXULPopupListener::nsXULPopupListener(nsIDOMElement *aElement, PRBool aIsContext)
+  : mElement(aElement), mPopupContent(nsnull), mIsContext(aIsContext)
 {
 }
 
-XULPopupListenerImpl::~XULPopupListenerImpl(void)
+nsXULPopupListener::~nsXULPopupListener(void)
 {
-  if (mPopup) {
-    mPopup->HidePopup();
-  }
-  
-#ifdef DEBUG_REFS
-    --gInstanceCount;
-    fprintf(stdout, "%d - RDF: XULPopupListenerImpl\n", gInstanceCount);
-#endif
+  ClosePopup();
 }
 
-NS_IMPL_ADDREF(XULPopupListenerImpl)
-NS_IMPL_RELEASE(XULPopupListenerImpl)
+NS_IMPL_ADDREF(nsXULPopupListener)
+NS_IMPL_RELEASE(nsXULPopupListener)
 
 
-NS_INTERFACE_MAP_BEGIN(XULPopupListenerImpl)
-  NS_INTERFACE_MAP_ENTRY(nsIXULPopupListener)
+NS_INTERFACE_MAP_BEGIN(nsXULPopupListener)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
   NS_INTERFACE_MAP_ENTRY(nsIDOMContextMenuListener)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMEventListener, nsIDOMMouseListener)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULPopupListener)
 NS_INTERFACE_MAP_END
 
-NS_IMETHODIMP
-XULPopupListenerImpl::Init(nsIDOMElement* aElement, const XULPopupType& popup)
-{
-  mElement = aElement; // Weak reference. Don't addref it.
-  popupType = popup;
-  return NS_OK;
-}
-
 ////////////////////////////////////////////////////////////////
 // nsIDOMMouseListener
 
 nsresult
-XULPopupListenerImpl::MouseDown(nsIDOMEvent* aMouseEvent)
+nsXULPopupListener::MouseDown(nsIDOMEvent* aMouseEvent)
 {
-  if(popupType != eXULPopupType_context)
+  if(!mIsContext)
     return PreLaunchPopup(aMouseEvent);
   else
     return NS_OK;
 }
 
 nsresult
-XULPopupListenerImpl::ContextMenu(nsIDOMEvent* aMouseEvent)
+nsXULPopupListener::ContextMenu(nsIDOMEvent* aMouseEvent)
 {
-  if(popupType == eXULPopupType_context)
+  if(mIsContext)
     return PreLaunchPopup(aMouseEvent);
   else 
     return NS_OK;
 }
 
 nsresult
-XULPopupListenerImpl::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
+nsXULPopupListener::PreLaunchPopup(nsIDOMEvent* aMouseEvent)
 {
   PRUint16 button;
 
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent;
   mouseEvent = do_QueryInterface(aMouseEvent);
   if (!mouseEvent) {
     //non-ui event passed in.  bad things.
     return NS_OK;
@@ -225,17 +146,17 @@ XULPopupListenerImpl::PreLaunchPopup(nsI
     return NS_OK;
   }
 
   // Get the node that was clicked on.
   nsCOMPtr<nsIDOMEventTarget> target;
   mouseEvent->GetTarget(getter_AddRefs(target));
   nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(target);
 
-  if (!targetNode && popupType == eXULPopupType_context) {
+  if (!targetNode && mIsContext) {
     // Not a DOM node, see if it's the DOM window (bug 380818).
     nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(target);
     if (!domWin) {
       return NS_ERROR_DOM_WRONG_TYPE_ERR;
     }
     // Try to use the root node as target node.
     nsCOMPtr<nsIDOMDocument> domDoc;
     domWin->GetDocument(getter_AddRefs(domDoc));
@@ -245,17 +166,17 @@ XULPopupListenerImpl::PreLaunchPopup(nsI
       targetNode = do_QueryInterface(doc->GetRootContent());
     if (!targetNode) {
       return NS_ERROR_FAILURE;
     }
   }
 
   PRBool preventDefault;
   nsUIEvent->GetPreventDefault(&preventDefault);
-  if (preventDefault && targetNode && popupType == eXULPopupType_context) {
+  if (preventDefault && targetNode && mIsContext) {
     // Someone called preventDefault on a context menu.
     // Let's make sure they are allowed to do so.
     PRBool eventEnabled =
       nsContentUtils::GetBoolPref("dom.event.contextmenu.enabled", PR_TRUE);
     if (!eventEnabled) {
       // The user wants his contextmenus.  Let's make sure that this is a website
       // and not chrome since there could be places in chrome which don't want
       // contextmenus.
@@ -273,75 +194,65 @@ XULPopupListenerImpl::PreLaunchPopup(nsI
     }
   }
 
   if (preventDefault) {
     // someone called preventDefault. bail.
     return NS_OK;
   }
 
-  // This is a gross hack to deal with a recursive popup situation happening in AIM code. 
-  // See http://bugzilla.mozilla.org/show_bug.cgi?id=96920.
+  // prevent popups on menu and menuitems as they handle their own popups
+  // This was added for bug 96920.
   // If a menu item child was clicked on that leads to a popup needing
   // to show, we know (guaranteed) that we're dealing with a menu or
   // submenu of an already-showing popup.  We don't need to do anything at all.
-  if (popupType == eXULPopupType_popup) {
-    nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
+  nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
+  if (!mIsContext) {
     nsIAtom *tag = targetContent ? targetContent->Tag() : nsnull;
     if (tag == nsGkAtoms::menu || tag == nsGkAtoms::menuitem)
       return NS_OK;
   }
 
   // Get the document with the popup.
   nsCOMPtr<nsIContent> content = do_QueryInterface(mElement);
 
   // Turn the document into a XUL document so we can use SetPopupNode.
   nsCOMPtr<nsIDOMXULDocument> xulDocument = do_QueryInterface(content->GetDocument());
-  if (!xulDocument) {
-    NS_ERROR("Popup attached to an element that isn't in XUL!");
+  if (!xulDocument)
     return NS_ERROR_FAILURE;
-  }
 
   // Store clicked-on node in xul document for context menus and menu popups.
-  // CLEAR THE POPUP EVENT BEFORE THIS FUNCTION EXITS
-  xulDocument->SetPopupNode( targetNode );
-  xulDocument->SetTrustedPopupEvent( aMouseEvent );
+  xulDocument->SetPopupNode(targetNode);
 
   nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aMouseEvent));
 
-  switch (popupType) {
-    case eXULPopupType_popup:
-      // Check for left mouse button down
-      mouseEvent->GetButton(&button);
-      if (button == 0) {
-        // Time to launch a popup menu.
-        LaunchPopup(aMouseEvent);
-        aMouseEvent->StopPropagation();
-        aMouseEvent->PreventDefault();
-      }
-      break;
-    case eXULPopupType_context:
+  if (mIsContext) {
+#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
+    // If the context menu launches on mousedown,
+    // we have to fire focus on the content we clicked on
+    FireFocusOnTargetContent(targetNode);
+#endif
+  }
+  else {
+    // Only open popups when the left mouse button is down.
+    mouseEvent->GetButton(&button);
+    if (button != 0)
+      return NS_OK;
+  }
 
-      // Time to launch a context menu
-#ifndef NS_CONTEXT_MENU_IS_MOUSEUP
-      // If the context menu launches on mousedown,
-      // we have to fire focus on the content we clicked on
-      FireFocusOnTargetContent(targetNode);
-#endif
-      LaunchPopup(aMouseEvent);
-      aMouseEvent->StopPropagation();
-      aMouseEvent->PreventDefault();
-      break;
-  }
-  xulDocument->SetTrustedPopupEvent(nsnull);
+  // Open the popup and cancel the default handling of the event.
+  LaunchPopup(aMouseEvent, targetContent);
+  aMouseEvent->StopPropagation();
+  aMouseEvent->PreventDefault();
+
   return NS_OK;
 }
 
 nsresult
-XULPopupListenerImpl::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
+nsXULPopupListener::FireFocusOnTargetContent(nsIDOMNode* aTargetNode)
 {
   nsresult rv;
   nsCOMPtr<nsIDOMDocument> domDoc;
   rv = aTargetNode->GetOwnerDocument(getter_AddRefs(domDoc));
   if(NS_SUCCEEDED(rv) && domDoc)
   {
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
 
@@ -403,36 +314,35 @@ XULPopupListenerImpl::FireFocusOnTargetC
     } else if (!suppressBlur)
       esm->SetContentState(nsnull, NS_EVENT_STATE_FOCUS);
 
     esm->SetContentState(focusableContent, NS_EVENT_STATE_ACTIVE);
   }
   return rv;
 }
 
+// ClosePopup
 //
-// LaunchPopup
+// Do everything needed to shut down the popup.
 //
-nsresult
-XULPopupListenerImpl::LaunchPopup ( nsIDOMEvent* anEvent )
+// NOTE: This routine is safe to call even if the popup is already closed.
+//
+void
+nsXULPopupListener::ClosePopup()
 {
-  // Retrieve our x and y position.
-  nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(anEvent) );
-  if (!mouseEvent) {
-    //non-ui event passed in.  bad things.
-    return NS_OK;
+  if (mPopupContent) {
+    // this is called when the listener is going away, so make sure that the
+    // popup is hidden. Use asynchronous hiding just to be safe so we don't
+    // fire events during destruction.  
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm)
+      pm->HidePopup(mPopupContent, PR_FALSE, PR_TRUE, PR_TRUE);
+    mPopupContent = nsnull;  // release the popup
   }
-
-  PRInt32 xPos, yPos;
-  mouseEvent->GetClientX(&xPos); 
-  mouseEvent->GetClientY(&yPos); 
-
-  return LaunchPopup(xPos, yPos);
-}
-
+} // ClosePopup
 
 static void
 GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult) 
 {
   *aResult = nsnull;
   PRInt32 childCount = aContent->GetChildCount();
   for (PRInt32 i = 0; i < childCount; i++) {
     nsIContent *child = aContent->GetChildAt(i);
@@ -441,89 +351,39 @@ GetImmediateChild(nsIContent* aContent, 
       NS_ADDREF(*aResult);
       return;
     }
   }
 
   return;
 }
 
-static void ConvertPosition(nsIDOMElement* aPopupElt, nsString& aAnchor, nsString& aAlign, PRInt32& aY)
-{
-  nsAutoString position;
-  aPopupElt->GetAttribute(NS_LITERAL_STRING("position"), position);
-  if (position.IsEmpty())
-    return;
-
-  if (position.EqualsLiteral("before_start")) {
-    aAnchor.AssignLiteral("topleft");
-    aAlign.AssignLiteral("bottomleft");
-  }
-  else if (position.EqualsLiteral("before_end")) {
-    aAnchor.AssignLiteral("topright");
-    aAlign.AssignLiteral("bottomright");
-  }
-  else if (position.EqualsLiteral("after_start")) {
-    aAnchor.AssignLiteral("bottomleft");
-    aAlign.AssignLiteral("topleft");
-  }
-  else if (position.EqualsLiteral("after_end")) {
-    aAnchor.AssignLiteral("bottomright");
-    aAlign.AssignLiteral("topright");
-  }
-  else if (position.EqualsLiteral("start_before")) {
-    aAnchor.AssignLiteral("topleft");
-    aAlign.AssignLiteral("topright");
-  }
-  else if (position.EqualsLiteral("start_after")) {
-    aAnchor.AssignLiteral("bottomleft");
-    aAlign.AssignLiteral("bottomright");
-  }
-  else if (position.EqualsLiteral("end_before")) {
-    aAnchor.AssignLiteral("topright");
-    aAlign.AssignLiteral("topleft");
-  }
-  else if (position.EqualsLiteral("end_after")) {
-    aAnchor.AssignLiteral("bottomright");
-    aAlign.AssignLiteral("bottomleft");
-  }
-  else if (position.EqualsLiteral("overlap")) {
-    aAnchor.AssignLiteral("topleft");
-    aAlign.AssignLiteral("topleft");
-  }
-  else if (position.EqualsLiteral("after_pointer"))
-    aY += 21;
-}
-
 //
 // LaunchPopup
 //
 // Given the element on which the event was triggered and the mouse locations in
 // Client and widget coordinates, popup a new window showing the appropriate 
 // content.
 //
-// This looks for an attribute on |aElement| of the appropriate popup type 
+// aTargetContent is the target of the mouse event aEvent that triggered the
+// popup. mElement is the element that the popup menu is attached to. The
+// former may be equal to mElement or it may be a descendant.
+//
+// This looks for an attribute on |mElement| of the appropriate popup type 
 // (popup, context) and uses that attribute's value as an ID for
 // the popup content in the document.
 //
 nsresult
-XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY)
+nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent)
 {
   nsresult rv = NS_OK;
 
   nsAutoString type(NS_LITERAL_STRING("popup"));
-  if ( popupType == eXULPopupType_context ) {
+  if (mIsContext)
     type.AssignLiteral("context");
-    
-    // position the menu two pixels down and to the right from the current
-    // mouse position. This makes it easier to dismiss the menu by just
-    // clicking.
-    aClientX += 2;
-    aClientY += 2;
-  }
 
   nsAutoString identifier;
   mElement->GetAttribute(type, identifier);
 
   if (identifier.IsEmpty()) {
     if (type.EqualsLiteral("popup"))
       mElement->GetAttribute(NS_LITERAL_STRING("menu"), identifier);
     else if (type.EqualsLiteral("context"))
@@ -539,107 +399,110 @@ XULPopupListenerImpl::LaunchPopup(PRInt3
   // Turn the document into a DOM document so we can use getElementById
   nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document);
   if (!domDocument) {
     NS_ERROR("Popup attached to an element that isn't in XUL!");
     return NS_ERROR_FAILURE;
   }
 
   // Handle the _child case for popups and context menus
-  nsCOMPtr<nsIDOMElement> popupContent;
+  nsCOMPtr<nsIDOMElement> popupElement;
 
   if (identifier.EqualsLiteral("_child")) {
     nsCOMPtr<nsIContent> popup;
 
     GetImmediateChild(content, nsGkAtoms::menupopup, getter_AddRefs(popup));
     if (popup)
-      popupContent = do_QueryInterface(popup);
+      popupElement = do_QueryInterface(popup);
     else {
       nsCOMPtr<nsIDOMDocumentXBL> nsDoc(do_QueryInterface(domDocument));
       nsCOMPtr<nsIDOMNodeList> list;
       nsDoc->GetAnonymousNodes(mElement, getter_AddRefs(list));
       if (list) {
         PRUint32 ctr,listLength;
         nsCOMPtr<nsIDOMNode> node;
         list->GetLength(&listLength);
         for (ctr = 0; ctr < listLength; ctr++) {
           list->Item(ctr, getter_AddRefs(node));
           nsCOMPtr<nsIContent> childContent(do_QueryInterface(node));
 
           if (childContent->NodeInfo()->Equals(nsGkAtoms::menupopup,
                                                kNameSpaceID_XUL)) {
-            popupContent = do_QueryInterface(childContent);
+            popupElement = do_QueryInterface(childContent);
             break;
           }
         }
       }
     }
   }
   else if (NS_FAILED(rv = domDocument->GetElementById(identifier,
-                                              getter_AddRefs(popupContent)))) {
+                                              getter_AddRefs(popupElement)))) {
     // Use getElementById to obtain the popup content and gracefully fail if 
     // we didn't find any popup content in the document. 
     NS_ERROR("GetElementById had some kind of spasm.");
     return rv;
   }
 
-  if (!popupContent || mElement == popupContent)
+  // return if no popup was found or the popup is the element itself.
+  if ( !popupElement || popupElement == mElement)
     return NS_OK;
 
   // Submenus can't be used as context menus or popups, bug 288763.
   // Similar code also in nsXULTooltipListener::GetTooltipFor.
-  nsCOMPtr<nsIContent> popup = do_QueryInterface(popupContent);
+  nsCOMPtr<nsIContent> popup = do_QueryInterface(popupElement);
   nsIContent* parent = popup->GetParent();
   if (parent) {
     nsIDocument* doc = parent->GetCurrentDoc();
     nsIPresShell* presShell = doc ? doc->GetPrimaryShell() : nsnull;
     nsIFrame* frame = presShell ? presShell->GetPrimaryFrameFor(parent) : nsnull;
-    if (frame) {
-      nsIMenuFrame* menu = nsnull;
-      CallQueryInterface(frame, &menu);
-      NS_ENSURE_FALSE(menu, NS_OK);
-    }
+    if (frame && frame->GetType() == nsGkAtoms::menuFrame)
+      return NS_OK;
   }
 
-  // We have some popup content. Obtain our window.
-  nsPIDOMWindow *domWindow = document->GetWindow();
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (!pm)
+    return NS_OK;
 
-  if (domWindow) {
-    // Find out if we're anchored.
-    nsAutoString anchorAlignment;
-    popupContent->GetAttribute(NS_LITERAL_STRING("popupanchor"), anchorAlignment);
-
-    nsAutoString popupAlignment;
-    popupContent->GetAttribute(NS_LITERAL_STRING("popupalign"), popupAlignment);
-
-    PRInt32 xPos = aClientX, yPos = aClientY;
+  // XXXndeakin this is temporary. It is needed to grab the mouse location details
+  //            used by the spellchecking popup. See bug 383930.
+  pm->SetMouseLocation(aEvent);
 
-    ConvertPosition(popupContent, anchorAlignment, popupAlignment, yPos);
-    if (!anchorAlignment.IsEmpty() && !popupAlignment.IsEmpty())
-      xPos = yPos = -1;
+  // if the popup has an anchoring attribute, anchor it to the element,
+  // otherwise just open it at the screen position where the mouse was clicked.
+  mPopupContent = popup;
+  if (mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::position) ||
+      mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupanchor) ||
+      mPopupContent->HasAttr(kNameSpaceID_None, nsGkAtoms::popupalign)) {
+    pm->ShowPopup(mPopupContent, content, EmptyString(), 0, 0,
+                  mIsContext, PR_TRUE, PR_FALSE);
+  }
+  else {
+    PRInt32 xPos = 0, yPos = 0;
+    nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
+    mouseEvent->GetScreenX(&xPos);
+    mouseEvent->GetScreenY(&yPos);
 
-    nsCOMPtr<nsIBoxObject> popupBox;
-    nsCOMPtr<nsIDOMXULElement> xulPopupElt(do_QueryInterface(popupContent));
-    xulPopupElt->GetBoxObject(getter_AddRefs(popupBox));
-    nsCOMPtr<nsIPopupBoxObject> popupBoxObject(do_QueryInterface(popupBox));
-    if (popupBoxObject) {
-      mPopup = popupBoxObject;
-      popupBoxObject->ShowPopup(mElement, popupContent, xPos, yPos, 
-                                type.get(), anchorAlignment.get(), 
-                                popupAlignment.get());
+    if (mIsContext) {
+      // position the menu two pixels down and to the right from the current
+      // mouse position. This makes it easier to dismiss the menu by just clicking
+      xPos += 2;
+      yPos += 2;
     }
+
+    pm->ShowPopupAtScreen(mPopupContent, xPos, yPos, mIsContext);
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////
 nsresult
-NS_NewXULPopupListener(nsIXULPopupListener** pop)
+NS_NewXULPopupListener(nsIDOMElement* aElement, PRBool aIsContext,
+                       nsIDOMEventListener** aListener)
 {
-    XULPopupListenerImpl* popup = new XULPopupListenerImpl();
-    if (!popup)
+    nsXULPopupListener* pl = new nsXULPopupListener(aElement, aIsContext);
+    if (!pl)
       return NS_ERROR_OUT_OF_MEMORY;
-    
-    NS_ADDREF(popup);
-    *pop = popup;
+
+    *aListener = NS_STATIC_CAST(nsIDOMMouseListener *, pl);
+    NS_ADDREF(*aListener);
     return NS_OK;
 }
new file mode 100644
--- /dev/null
+++ b/content/xul/content/src/nsXULPopupListener.h
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Original Author: David W. Hyatt (hyatt@netscape.com)
+ *   Dean Tessman <dean_tessman@hotmail.com>
+ *   Pierre Phaneuf <pp@ludusdesign.com>
+ *   Robert O'Callahan <roc+moz@cs.cmu.edu>
+ *
+ * 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"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * This is the popup listener implementation for popup menus and context menus.
+ */
+
+#ifndef nsXULPopupListener_h___
+#define nsXULPopupListener_h___
+
+#include "nsCOMPtr.h"
+
+#include "nsIContent.h"
+#include "nsIDOMElement.h"
+#include "nsIDOMMouseEvent.h"
+#include "nsIFrame.h"
+#include "nsIDOMMouseListener.h"
+#include "nsIDOMContextMenuListener.h"
+
+class nsXULPopupListener : public nsIDOMMouseListener,
+                           public nsIDOMContextMenuListener
+{
+public:
+    // aElement is the element that the popup is attached to. If aIsContext is
+    // false, the popup opens on left click on aElement or a descendant. If
+    // aIsContext is true, the popup is a context menu which opens on a
+    // context menu event.
+    nsXULPopupListener(nsIDOMElement *aElement, PRBool aIsContext);
+    virtual ~nsXULPopupListener(void);
+
+public:
+    // nsISupports
+    NS_DECL_ISUPPORTS
+
+    // nsIDOMMouseListener
+    NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
+    NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+    NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+    NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+    NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+    NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }
+
+    // nsIDOMContextMenuListener
+    NS_IMETHOD ContextMenu(nsIDOMEvent* aContextMenuEvent);
+
+    // nsIDOMEventListener
+    NS_IMETHOD HandleEvent(nsIDOMEvent* anEvent) { return NS_OK; }
+
+protected:
+
+    // open the popup. aEvent is the event that triggered the popup such as
+    // a mouse click and aTargetContent is the target of this event.
+    virtual nsresult LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent);
+
+    // close the popup when the listener goes away
+    virtual void ClosePopup();
+
+private:
+
+    // PreLaunchPopup is called before LaunchPopup to ensure that the event is
+    // suitable and to initialize the XUL document's popupNode to the event
+    // target.
+    nsresult PreLaunchPopup(nsIDOMEvent* aMouseEvent);
+
+    // When a context menu is opened, focus the target of the contextmenu event.
+    nsresult FireFocusOnTargetContent(nsIDOMNode* aTargetNode);
+
+    // |mElement| is the node to which this listener is attached.
+    nsIDOMElement* mElement;               // Weak ref. The element will go away first.
+
+    // The popup that is getting shown on top of mElement.
+    nsCOMPtr<nsIContent> mPopupContent; 
+
+    // true if a context popup
+    PRBool mIsContext;
+};
+
+// Construct a new nsXULPopupListener and return in aListener. See the
+// nsXULPopupListener constructor for details about the aElement and
+// aIsContext arguments.
+nsresult
+NS_NewXULPopupListener(nsIDOMElement* aElement, PRBool aIsContext,
+                       nsIDOMEventListener** aListener);
+
+#endif // nsXULPopupListener_h___
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -123,16 +123,17 @@
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsEventDispatcher.h"
 #include "nsContentErrors.h"
 #include "nsIObserverService.h"
 #include "nsNodeUtils.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIXULWindow.h"
+#include "nsXULPopupManager.h"
 
 //----------------------------------------------------------------------
 //
 // CIDs
 //
 
 static NS_DEFINE_CID(kLocalStoreCID,             NS_LOCALSTORE_CID);
 static NS_DEFINE_CID(kParserCID,                 NS_PARSER_CID);
@@ -1451,94 +1452,59 @@ nsXULDocument::SetPopupNode(nsIDOMNode* 
     GetFocusController(getter_AddRefs(focusController));
     NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
     // set popup node
     rv = focusController->SetPopupNode(aNode);
 
     return rv;
 }
 
-NS_IMETHODIMP
-nsXULDocument::GetTrustedPopupEvent(nsIDOMEvent** aEvent)
-{
-    nsresult rv;
-
-    nsCOMPtr<nsIFocusController> focusController;
-    GetFocusController(getter_AddRefs(focusController));
-    NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
-
-    rv = focusController->GetPopupEvent(aEvent);
-
-    return rv;
-}
-
-NS_IMETHODIMP
-nsXULDocument::SetTrustedPopupEvent(nsIDOMEvent* aEvent)
-{
-    nsresult rv;
-
-    nsCOMPtr<nsIFocusController> focusController;
-    GetFocusController(getter_AddRefs(focusController));
-    NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE);
-
-    rv = focusController->SetPopupEvent(aEvent);
-
-    return rv;
-}
-
-// Returns the rangeOffset element from the popupEvent. This is for chrome
-// callers only.
+// Returns the rangeOffset element from the XUL Popup Manager. This is for
+// chrome callers only.
 NS_IMETHODIMP
 nsXULDocument::GetPopupRangeParent(nsIDOMNode** aRangeParent)
 {
     NS_ENSURE_ARG_POINTER(aRangeParent);
     *aRangeParent = nsnull;
 
-    nsCOMPtr<nsIDOMEvent> event;
-    nsresult rv = GetTrustedPopupEvent(getter_AddRefs(event));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (! event)
-        return NS_ERROR_UNEXPECTED; // no event active
-
-    nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(event, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = uiEvent->GetRangeParent(aRangeParent); // addrefs
-
-    if (NS_SUCCEEDED(rv) && *aRangeParent &&
-            !nsContentUtils::CanCallerAccess(*aRangeParent)) {
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (!pm)
+        return NS_ERROR_FAILURE;
+
+    PRInt32 offset;
+    pm->GetMouseLocation(aRangeParent, &offset);
+
+    if (*aRangeParent && !nsContentUtils::CanCallerAccess(*aRangeParent)) {
         NS_RELEASE(*aRangeParent);
         return NS_ERROR_DOM_SECURITY_ERR;
     }
-    return rv;
+
+    return NS_OK;
 }
 
-// Returns the rangeOffset element from the popupEvent. We check the rangeParent
-// to determine if the caller has rights to access to the data.
+// Returns the rangeOffset element from the XUL Popup Manager. We check the
+// rangeParent to determine if the caller has rights to access to the data.
 NS_IMETHODIMP
 nsXULDocument::GetPopupRangeOffset(PRInt32* aRangeOffset)
 {
     NS_ENSURE_ARG_POINTER(aRangeOffset);
 
-    nsCOMPtr<nsIDOMEvent> event;
-    nsresult rv = GetTrustedPopupEvent(getter_AddRefs(event));
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (! event)
-        return NS_ERROR_UNEXPECTED; // no event active
-
-    nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(event, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (!pm)
+        return NS_ERROR_FAILURE;
+
+    PRInt32 offset;
     nsCOMPtr<nsIDOMNode> parent;
-    rv = uiEvent->GetRangeParent(getter_AddRefs(parent));
-    NS_ENSURE_SUCCESS(rv, rv);
+    pm->GetMouseLocation(getter_AddRefs(parent), &offset);
 
     if (parent && !nsContentUtils::CanCallerAccess(parent))
         return NS_ERROR_DOM_SECURITY_ERR;
 
-    return uiEvent->GetRangeOffset(aRangeOffset);
+    *aRangeOffset = offset;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULDocument::GetTooltipNode(nsIDOMNode** aNode)
 {
     if (mTooltipNode && !nsContentUtils::CanCallerAccess(mTooltipNode)) {
         return NS_ERROR_DOM_SECURITY_ERR;
     }
--- a/dom/public/idl/xul/nsIDOMXULDocument.idl
+++ b/dom/public/idl/xul/nsIDOMXULDocument.idl
@@ -105,14 +105,9 @@ interface nsIDOMXULDocument : nsISupport
    * callers that can indirectly be called from content.
    */
   [noscript] nsIDOMNode     trustedGetPopupNode();
 
   /**
    * Like trustedGetPopupNode, but gets the tooltip node instead.
    */
   [noscript] nsIDOMNode     trustedGetTooltipNode();
-
-  /**
-   * Like trustedGetPopupNode, but gets the 
-   */
-  [noscript] attribute nsIDOMEvent trustedPopupEvent;
 };
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -154,16 +154,17 @@
 #include "nsContentUtils.h"
 #include "nsCSSProps.h"
 #include "nsIURIFixup.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsEventDispatcher.h"
 #include "nsIObserverService.h"
 #include "nsIXULAppInfo.h"
 #include "nsNetUtil.h"
+#include "nsXULPopupManager.h"
 
 #include "plbase64.h"
 
 #ifdef NS_PRINTING
 #include "nsIPrintSettings.h"
 #include "nsIPrintSettingsService.h"
 #include "nsIWebBrowserPrint.h"
 #endif
@@ -3032,20 +3033,20 @@ nsGlobalWindow::SetScreenY(PRInt32 aScre
   return NS_OK;
 }
 
 nsresult
 nsGlobalWindow::CheckSecurityWidthAndHeight(PRInt32* aWidth, PRInt32* aHeight)
 {
   if (!nsContentUtils::IsCallerTrustedForWrite()) {
     // if attempting to resize the window, hide any open popups
-    nsCOMPtr<nsIPresShell> presShell;
-    mDocShell->GetPresShell(getter_AddRefs(presShell));
-    if (presShell)
-      presShell->HidePopups();
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
+    if (pm && doc)
+      pm->HidePopupsInDocument(doc);
   }
 
   // This one is easy. Just ensure the variable is greater than 100;
   if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
     // Check security state for use in determing window dimensions
 
     if (!nsContentUtils::IsCallerTrustedForWrite()) {
       //sec check failed
@@ -3065,20 +3066,20 @@ nsresult
 nsGlobalWindow::CheckSecurityLeftAndTop(PRInt32* aLeft, PRInt32* aTop)
 {
   // This one is harder. We have to get the screen size and window dimensions.
 
   // Check security state for use in determing window dimensions
 
   if (!nsContentUtils::IsCallerTrustedForWrite()) {
     // if attempting to move the window, hide any open popups
-    nsCOMPtr<nsIPresShell> presShell;
-    mDocShell->GetPresShell(getter_AddRefs(presShell));
-    if (presShell)
-      presShell->HidePopups();
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    nsCOMPtr<nsIDocument> doc(do_QueryInterface(mDocument));
+    if (pm && doc)
+      pm->HidePopupsInDocument(doc);
 
     PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
     PRInt32 winLeft, winTop, winWidth, winHeight;
 
     nsGlobalWindow* rootWindow =
       NS_STATIC_CAST(nsGlobalWindow*, GetPrivateRoot());
     if (rootWindow) {
       rootWindow->FlushPendingNotifications(Flush_Layout);
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -114,17 +114,16 @@
 #include "nsAutoPtr.h"
 #include "nsBoxFrame.h"
 #include "nsIBoxLayout.h"
 #include "nsImageFrame.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsContentErrors.h"
 
 #include "nsIDOMWindowInternal.h"
-#include "nsIMenuFrame.h"
 
 #include "nsBox.h"
 
 #ifdef MOZ_XUL
 #include "nsIRootBox.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIXULDocument.h"
@@ -1701,21 +1700,18 @@ GetChildListNameFor(nsIFrame*       aChi
       listName = nsGkAtoms::absoluteList;
     } else if (NS_STYLE_POSITION_FIXED == disp->mPosition) {
       listName = nsGkAtoms::fixedList;
 #ifdef MOZ_XUL
     } else if (NS_STYLE_DISPLAY_POPUP == disp->mDisplay) {
       // Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
 #ifdef DEBUG
       nsIFrame* parent = aChildFrame->GetParent();
-      if (parent) {
-        nsIPopupSetFrame* popupSet;
-        CallQueryInterface(parent, &popupSet);
-        NS_ASSERTION(popupSet, "Unexpected parent");
-      }
+      NS_ASSERTION(parent && parent->GetType() == nsGkAtoms::popupSetFrame,
+                   "Unexpected parent");
 #endif // DEBUG
 
       // XXX FIXME: Bug 350740
       // Return here, because the postcondition for this function actually
       // fails for this case, since the popups are not in a "real" frame list
       // in the popup set.
       return nsGkAtoms::popupList;      
 #endif // MOZ_XUL
@@ -5951,31 +5947,29 @@ nsCSSFrameConstructor::ConstructXULFrame
       }
       else if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) {
         // If a popup is inside a menu, then the menu understands the complex
         // rules/behavior governing the cascade of multiple menu popups and can handle
         // having the real popup frame placed under it as a child.  
         // If, however, the parent is *not* a menu frame, then we need to create
         // a placeholder frame for the popup, and then we add the popup frame to the
         // root popup set (that manages all such "detached" popups).
-        nsIMenuFrame* menuFrame;
-        CallQueryInterface(aParentFrame, &menuFrame);
-        if (!menuFrame) {
+        if (aParentFrame->GetType() != nsGkAtoms::menuFrame) {
           if (!aState.mPopupItems.containingBlock) {
             // Just don't create a frame for this popup; we can't do
             // anything with it, since there is no root popup set.
             *aHaltProcessing = PR_TRUE;
             NS_ASSERTION(!aState.mRootBox, "Popup containing block is missing");
             return NS_OK;
           }
 
 #ifdef NS_DEBUG
-          nsIPopupSetFrame* popupSet;
-          CallQueryInterface(aState.mPopupItems.containingBlock, &popupSet);
-          NS_ASSERTION(popupSet, "Popup containing block isn't a nsIPopupSetFrame");
+          NS_ASSERTION(aState.mPopupItems.containingBlock->GetType() ==
+                       nsGkAtoms::popupSetFrame,
+                       "Popup containing block isn't a nsIPopupSetFrame");
 #endif
           isPopup = PR_TRUE;
         }
 
         // This is its own frame that derives from box.
         newFrame = NS_NewMenuPopupFrame(mPresShell, aStyleContext);
 
         if (aTag == nsGkAtoms::tooltip) {
@@ -6140,16 +6134,26 @@ nsCSSFrameConstructor::ConstructXULFrame
     // the placeholder frame
     if (!primaryFrameSet)
         aState.mFrameManager->SetPrimaryFrameFor(aContent, topFrame);
   }
 
   return rv;
 }
 
+nsresult
+nsCSSFrameConstructor::AddLazyChildren(nsIContent* aContent,
+                                       nsLazyFrameConstructionCallback* aCallback,
+                                       void* aArg)
+{
+  nsCOMPtr<nsIRunnable> event =
+    new LazyGenerateChildrenEvent(aContent, mPresShell, aCallback, aArg);
+  return NS_DispatchToCurrentThread(event);
+}
+
 already_AddRefed<nsStyleContext>
 nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
                                                 nsIContent*              aContent,
                                                 nsStyleContext*          aContentStyle,
                                                 nsIFrame*                aParentFrame,
                                                 nsIFrame*                aContentParentFrame,
                                                 nsIAtom*                 aScrolledPseudo,
                                                 PRBool                   aIsRoot,
@@ -10128,39 +10132,16 @@ nsCSSFrameConstructor::AttributeChanged(
 
   // See if we can optimize away the style re-resolution -- must be called after
   // the frame's AttributeChanged() in case it does something that affects the style
   nsFrameManager *frameManager = shell->FrameManager();
   nsReStyleHint rshint = frameManager->HasAttributeDependentStyle(aContent,
                                                                   aAttribute,
                                                                   aModType);
 
-  // Menus and such can't deal with asynchronous changes of display
-  // when the menugenerated or menuactive attribute changes, so make
-  // sure to process that immediately
-  if (aNameSpaceID == kNameSpaceID_None &&
-      ((aAttribute == nsGkAtoms::menugenerated &&
-        aModType != nsIDOMMutationEvent::REMOVAL) ||
-       aAttribute == nsGkAtoms::menuactive)) {
-    PRInt32 namespaceID;
-    nsIAtom* tag =
-      mDocument->BindingManager()->ResolveTag(aContent, &namespaceID);
-
-    if (namespaceID == kNameSpaceID_XUL &&
-        (tag == nsGkAtoms::menupopup || tag == nsGkAtoms::popup ||
-         tag == nsGkAtoms::tooltip || tag == nsGkAtoms::menu)) {
-      nsIViewManager* viewManager = mPresShell->GetViewManager();
-      viewManager->BeginUpdateViewBatch();
-      ProcessOneRestyle(aContent, rshint, hint);
-      viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
-
-      return result;
-    }
-  }
-
   PostRestyleEvent(aContent, rshint, hint);
 
   return result;
 }
 
 void
 nsCSSFrameConstructor::EndUpdate()
 {
@@ -13020,8 +13001,47 @@ NS_IMETHODIMP nsCSSFrameConstructor::Res
   mConstructor->mRestyleEvent.Forget();
 
   mConstructor->ProcessPendingRestyles();
   viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsCSSFrameConstructor::LazyGenerateChildrenEvent::Run()
+{
+  mPresShell->GetDocument()->FlushPendingNotifications(Flush_Layout);
+
+  // this is hard-coded to handle only menu popup frames
+  nsIFrame* frame = mPresShell->GetPrimaryFrameFor(mContent);
+  if (frame && frame->GetType() == nsGkAtoms::menuPopupFrame) {
+    // it is possible that the frame is different than the one that requested
+    // the lazy generation, but as long as it's a popup frame that hasn't
+    // generated its children yet, that's OK.
+    nsMenuPopupFrame* menuPopupFrame = NS_STATIC_CAST(nsMenuPopupFrame *, frame);
+    if (menuPopupFrame->HasGeneratedChildren())
+      return NS_OK;
+
+    // indicate that the children have been generated
+    menuPopupFrame->SetGeneratedChildren();
+
+    nsFrameItems childItems;
+    nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull);
+    nsCSSFrameConstructor* fc = mPresShell->FrameConstructor();
+    nsresult rv = fc->ProcessChildren(state, mContent, frame, PR_FALSE,
+                                      childItems, PR_FALSE);
+    if (NS_FAILED(rv))
+      return rv;
+
+    fc->CreateAnonymousFrames(mContent->Tag(), state, mContent, frame,
+                              PR_FALSE, childItems);
+    frame->SetInitialChildList(nsnull, childItems.childList);
+
+    if (mCallback)
+      mCallback(mContent, frame, mArg);
+
+    // call XBL constructors after the frames are created
+    mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
+  }
+
+  return NS_OK;
+}
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -67,16 +67,19 @@ class nsStyleChangeList;
 class nsIFrame;
 
 struct nsFindFrameHint
 {
   nsIFrame *mPrimaryFrameForPrevSibling;  // weak ref to the primary frame for the content for which we need a frame
   nsFindFrameHint() : mPrimaryFrameForPrevSibling(nsnull) { }
 };
 
+typedef void (PR_CALLBACK nsLazyFrameConstructionCallback)
+             (nsIContent* aContent, nsIFrame* aFrame, void* aArg);
+
 class nsFrameConstructorState;
 class nsFrameConstructorSaveState;
   
 class nsCSSFrameConstructor
 {
 public:
   nsCSSFrameConstructor(nsIDocument *aDocument, nsIPresShell* aPresShell);
   ~nsCSSFrameConstructor(void) { }
@@ -117,16 +120,27 @@ public:
 
   nsresult CharacterDataChanged(nsIContent*     aContent,
                                 PRBool          aAppend);
 
   nsresult ContentStatesChanged(nsIContent*     aContent1,
                                 nsIContent*     aContent2,
                                 PRInt32         aStateMask);
 
+  // Process the children of aContent and indicate that frames should be
+  // created for them. This is used for lazily built content such as that
+  // inside popups so that it is only created when the popup is opened.
+  // This method constructs the frames asynchronously.
+  // aCallback will be called with three arguments, the first is the value
+  // of aContent, the second is aContent's primary frame, and the third is
+  // the value of aArg.
+  nsresult AddLazyChildren(nsIContent* aContent,
+                           nsLazyFrameConstructionCallback* aCallback,
+                           void* aArg);
+
   // Should be called when a frame is going to be destroyed and
   // WillDestroyFrameTree hasn't been called yet.
   void NotifyDestroyingFrame(nsIFrame* aFrame);
 
   nsresult AttributeChanged(nsIContent* aContent,
                             PRInt32     aNameSpaceID,
                             nsIAtom*    aAttribute,
                             PRInt32     aModType);
@@ -998,16 +1012,37 @@ public:
     void Revoke() { mConstructor = nsnull; }
   private:
     nsCSSFrameConstructor *mConstructor;
   };
 
   friend class nsFrameConstructorState;
 
 private:
+
+  class LazyGenerateChildrenEvent;
+  friend class LazyGenerateChildrenEvent;
+
+  class LazyGenerateChildrenEvent : public nsRunnable {
+  public:
+    NS_DECL_NSIRUNNABLE
+    LazyGenerateChildrenEvent(nsIContent *aContent,
+                              nsIPresShell *aPresShell,
+                              nsLazyFrameConstructionCallback* aCallback,
+                              void* aArg)
+      : mContent(aContent), mPresShell(aPresShell), mCallback(aCallback), mArg(aArg)
+    {}
+
+  private:
+    nsCOMPtr<nsIContent> mContent;
+    nsCOMPtr<nsIPresShell> mPresShell;
+    nsLazyFrameConstructionCallback* mCallback;
+    void* mArg;
+  };
+
   nsIDocument*        mDocument;  // Weak ref
   nsIPresShell*       mPresShell; // Weak ref
 
   nsIFrame*           mInitialContainingBlock;
   nsIFrame*           mFixedContainingBlock;
   nsIFrame*           mDocElementContainingBlock;
   nsIFrame*           mGfxScrollFrame;
   nsIFrame*           mPageSequenceFrame;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -106,16 +106,17 @@
 #include "nsIDOMHTMLAreaElement.h"
 #include "nsIDOMHTMLLinkElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsCopySupport.h"
 #include "nsIDOMHTMLFrameSetElement.h"
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
 #endif
+#include "nsXULPopupManager.h"
 #include "nsPrintfCString.h"
 
 #include "nsIClipboardHelper.h"
 
 #include "nsPIDOMWindow.h"
 #include "nsJSEnvironment.h"
 #include "nsIFocusController.h"
 #include "nsIMenuParent.h"
@@ -1148,20 +1149,19 @@ DocumentViewerImpl::PageHide(PRBool aIsU
     // here.
     nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE);
 
     nsEventDispatcher::Dispatch(window, mPresContext, &event, nsnull, &status);
   }
 
   // look for open menupopups and close them after the unload event, in case
   // the unload event listeners open any new popups
-  if (mPresShell) {
-    nsCOMPtr<nsIPresShell> kungFuDeathGrip = mPresShell;
-    mPresShell->HidePopups();
-  }
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm && mDocument)
+    pm->HidePopupsInDocument(mDocument);
 
   return NS_OK;
 }
 
 static void
 AttachContainerRecurse(nsIDocShell* aShell)
 {
   nsCOMPtr<nsIContentViewer> viewer;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -97,20 +97,20 @@ template<class E> class nsCOMArray;
 class nsWeakFrame;
 class nsIScrollableFrame;
 class gfxASurface;
 class gfxContext;
 
 typedef short SelectionType;
 typedef PRUint32 nsFrameState;
 
-// 9562bb2b-990c-4875-aafd-bd46fc9a4fc1
+// D93B931B-D5EF-4D3C-AB99-444176963464
 #define NS_IPRESSHELL_IID \
-{ 0x9562bb2b, 0x990c, 0x4875, \
-  { 0xaa, 0xfd, 0xbd, 0x46, 0xfc, 0x9a, 0x4f, 0xc1 } }
+{ 0xd93b931b, 0xd5ef, 0x4d3c, \
+  { 0xab, 0x99, 0x44, 0x41, 0x76, 0x96, 0x34, 0x64 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
 #define NS_PRESSHELL_SCROLL_LEFT     0
 #define NS_PRESSHELL_SCROLL_RIGHT    100
 #define NS_PRESSHELL_SCROLL_CENTER   50
 #define NS_PRESSHELL_SCROLL_ANYWHERE -1
@@ -720,18 +720,16 @@ public:
    * such that the mouse is over the same point in the scaled image as in
    * the original. When scaling does not occur, the mouse point isn't used
    * as the position can be determined from the displayed frames.
    */
   virtual already_AddRefed<gfxASurface> RenderSelection(nsISelection* aSelection,
                                                         nsPoint& aPoint,
                                                         nsRect* aScreenRect) = 0;
 
-  virtual void HidePopups() = 0;
-
   void AddWeakFrame(nsWeakFrame* aWeakFrame);
   void RemoveWeakFrame(nsWeakFrame* aWeakFrame);
 
 #ifdef NS_DEBUG
   nsIFrame* GetDrawEventTargetFrame() { return mDrawEventTargetFrame; }
 #endif
 
 protected:
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -184,17 +184,17 @@
 #include "nsIAccessible.h"
 #include "nsIAccessibleEvent.h"
 #endif
 
 // For style data reconstruction
 #include "nsStyleChangeList.h"
 #include "nsCSSFrameConstructor.h"
 #ifdef MOZ_XUL
-#include "nsIMenuFrame.h"
+#include "nsMenuFrame.h"
 #include "nsITreeBoxObject.h"
 #endif
 #include "nsIMenuParent.h"
 #include "nsPlaceholderFrame.h"
 
 // Content viewer interfaces
 #include "nsIContentViewer.h"
 #include "imgIEncoder.h"
@@ -883,18 +883,16 @@ public:
                                                    nsIRegion* aRegion,
                                                    nsPoint& aPoint,
                                                    nsRect* aScreenRect);
 
   virtual already_AddRefed<gfxASurface> RenderSelection(nsISelection* aSelection,
                                                         nsPoint& aPoint,
                                                         nsRect* aScreenRect);
 
-  virtual void HidePopups();
-
   //nsIViewObserver interface
 
   NS_IMETHOD Paint(nsIView *aView,
                    nsIRenderingContext* aRenderingContext,
                    const nsRegion& aDirtyRegion);
   NS_IMETHOD ComputeRepaintRegionForCopy(nsIView*      aRootView,
                                          nsIView*      aMovingView,
                                          nsPoint       aDelta,
@@ -5835,28 +5833,16 @@ PresShell::Thaw()
   }
 
   if (mDocument)
     mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull);
 
   UnsuppressPainting();
 }
 
-void
-PresShell::HidePopups()
-{
-  nsIViewManager *vm = GetViewManager();
-  if (vm) {
-    nsIView *rootView = nsnull;
-    vm->GetRootView(rootView);
-    if (rootView)
-      HideViewIfPopup(rootView);
-  }
-}
-
 //--------------------------------------------------------
 // Start of protected and private methods on the PresShell
 //--------------------------------------------------------
 
 //-------------- Begin Reflow Event Definition ------------------------
 
 NS_IMETHODIMP
 PresShell::ReflowEvent::Run() {    
@@ -6181,21 +6167,18 @@ ReResolveMenusAndTrees(nsIFrame *aFrame,
   nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(aFrame));
   if (treeBox)
     treeBox->ClearStyleAndImageCaches();
 
   // We deliberately don't re-resolve style on a menu's popup
   // sub-content, since doing so slows menus to a crawl.  That means we
   // have to special-case them on a skin switch, and ensure that the
   // popup frames just get destroyed completely.
-  nsCOMPtr<nsIMenuFrame> menuFrame(do_QueryInterface(aFrame));
-  if (menuFrame) {
-    menuFrame->UngenerateMenu();  
-    menuFrame->OpenMenu(PR_FALSE);
-  }
+  if (aFrame && aFrame->GetType() == nsGkAtoms::menuFrame)
+    (NS_STATIC_CAST(nsMenuFrame *, aFrame))->CloseMenu(PR_TRUE);
   return PR_TRUE;
 }
 
 PR_STATIC_CALLBACK(PRBool)
 ReframeImageBoxes(nsIFrame *aFrame, void *aClosure)
 {
   nsStyleChangeList *list = NS_STATIC_CAST(nsStyleChangeList*, aClosure);
   if (aFrame->GetType() == nsGkAtoms::imageBoxFrame) {
@@ -6323,37 +6306,16 @@ PresShell::EnumeratePlugins(nsIDOMDocume
     nodes->Item(i, getter_AddRefs(node));
 
     nsCOMPtr<nsIContent> content = do_QueryInterface(node);
     if (content)
       aCallback(this, content);
   }
 }
 
-void
-PresShell::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();
-  }
-}
-
 //------------------------------------------------------
 // End of protected and private methods on the PresShell
 //------------------------------------------------------
 
 // Start of DEBUG only code
 
 #ifdef NS_DEBUG
 #include "nsViewsCID.h"
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -230,17 +230,16 @@ class nsIDocumentLoaderFactory;
  { /* 0DE2FBFA-6B7F-11D7-BBBA-0003938A9D96 */        \
   0x0DE2FBFA, 0x6B7F, 0x11D7, {0xBB, 0xBA, 0x00, 0x03, 0x93, 0x8A, 0x9D, 0x96} }
 
 static NS_DEFINE_CID(kWindowCommandTableCID, NS_WINDOWCOMMANDTABLE_CID);
 
 #ifdef MOZ_XUL
 #include "nsIBoxObject.h"
 #include "nsIXULDocument.h"
-#include "nsIXULPopupListener.h"
 #include "nsIXULPrototypeCache.h"
 #include "nsIXULSortService.h"
 
 #ifndef MOZ_NO_INSPECTOR_APIS
 #include "inDOMView.h"
 #include "inDeepTreeWalker.h"
 #include "inFlasher.h"
 #include "inCSSValueSearch.h"
@@ -503,17 +502,16 @@ MAKE_CTOR(CreateSanitizingHTMLSerializer
 MAKE_CTOR(CreateXBLService,               nsIXBLService,               NS_NewXBLService)
 MAKE_CTOR(CreateContentPolicy,            nsIContentPolicy,            NS_NewContentPolicy)
 MAKE_CTOR(CreateComputedDOMStyle,         nsIComputedDOMStyle,         NS_NewComputedDOMStyle)
 #ifdef MOZ_XUL
 MAKE_CTOR(CreateXULSortService,           nsIXULSortService,           NS_NewXULSortService)
 // NS_NewXULContentBuilder
 // NS_NewXULTreeBuilder
 MAKE_CTOR(CreateXULDocument,              nsIXULDocument,              NS_NewXULDocument)
-MAKE_CTOR(CreateXULPopupListener,         nsIXULPopupListener,         NS_NewXULPopupListener)
 // NS_NewXULControllers
 // NS_NewXULPrototypeCache
 #endif
 #ifdef MOZ_XTF
 MAKE_CTOR(CreateXTFService,               nsIXTFService,               NS_NewXTFService)
 MAKE_CTOR(CreateXMLContentBuilder,        nsIXMLContentBuilder,        NS_NewXMLContentBuilder)
 #endif
 MAKE_CTOR(CreateContentDLF,               nsIDocumentLoaderFactory,    NS_NewContentDocumentLoaderFactory)
@@ -1187,21 +1185,16 @@ static const nsModuleComponentInfo gComp
     "@mozilla.org/xul/xul-tree-builder;1",
     NS_NewXULTreeBuilder },
 
   { "XUL Document",
     NS_XULDOCUMENT_CID,
     "@mozilla.org/xul/xul-document;1",
     CreateXULDocument },
 
-  { "XUL PopupListener",
-    NS_XULPOPUPLISTENER_CID,
-    "@mozilla.org/xul/xul-popup-listener;1",
-    CreateXULPopupListener },
-
   { "XUL Prototype Cache",
     NS_XULPROTOTYPECACHE_CID,
     "@mozilla.org/xul/xul-prototype-cache;1",
     NS_NewXULPrototypeCache },
 
 #endif
 
 #ifdef MOZ_XTF
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -74,16 +74,17 @@
 #include "nsStyleSet.h"
 #include "nsTextControlFrame.h"
 #include "nsXBLWindowKeyHandler.h"
 #include "txMozillaXSLTProcessor.h"
 #include "nsDOMStorage.h"
 #include "nsCellMap.h"
 #include "nsTextFrameTextRunCache.h"
 #include "nsCCUncollectableMarker.h"
+#include "nsXULPopupManager.h"
 #include "nsTextFragment.h"
 
 #ifdef MOZ_XUL
 #include "nsXULContentUtils.h"
 #include "nsXULElement.h"
 #include "nsXULPrototypeCache.h"
 #include "nsXULTooltipListener.h"
 #endif
@@ -213,22 +214,29 @@ nsLayoutStatics::Initialize()
   }
 
   rv = nsCCUncollectableMarker::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsCCUncollectableMarker");
     return rv;
   }
 
+  rv = nsXULPopupManager::Init();
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Could not initialize nsXULPopupManager");
+    return rv;
+  }
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
+  nsXULPopupManager::Shutdown();
   nsDOMStorageManager::Shutdown();
   txMozillaXSLTProcessor::Shutdown();
   nsDOMAttribute::Shutdown();
   nsDOMEventRTTearoff::Shutdown();
   nsEventListenerManager::Shutdown();
   nsContentList::Shutdown();
   nsComputedDOMStyle::Shutdown();
   CSSLoaderImpl::Shutdown();
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -492,26 +492,31 @@ nsContainerFrame::SyncFrameViewPropertie
     if (!aStyleContext->GetStyleVisibility()->IsVisible() &&
         !aFrame->SupportsVisibilityHidden()) {
       // If it's a scrollable frame that can't hide its scrollbars,
       // hide the view. This means that child elements can't override
       // their parent's visibility, but it's not practical to leave it
       // visible in all cases because the scrollbars will be showing
       // XXXldb Does the view system really enforce this correctly?
       viewIsVisible = PR_FALSE;
-    } else {
+    } else if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
       // if the view is for a popup, don't show the view if the popup is closed
       nsIWidget* widget = aView->GetWidget();
       if (widget) {
         nsWindowType windowType;
         widget->GetWindowType(windowType);
         if (windowType == eWindowType_popup) {
           widget->IsVisible(viewIsVisible);
         }
       }
+      else {
+        // widgets for popups can be created later when the popup is opened,
+        // so if there is no widget, the popup won't be open.
+        viewIsVisible = PR_FALSE;
+      }
     }
 
     vm->SetViewVisibility(aView, viewIsVisible ? nsViewVisibility_kShow :
                           nsViewVisibility_kHide);
   }
 
   // See if the frame is being relatively positioned or absolutely
   // positioned
@@ -711,17 +716,22 @@ nsContainerFrame::PositionChildViews(nsI
       } else {
         PositionChildViews(childFrame);
       }
 
       // Get the next sibling child frame
       childFrame = childFrame->GetNextSibling();
     }
 
-    childListName = aFrame->GetAdditionalChildListName(childListIndex++);
+    // also process the additional child lists, but skip the popup list as the
+    // view for popups is managed by the parent. Currently only nsMenuFrame
+    // has a popupList and during layout will call nsMenuPopupFrame::AdjustView.
+    do {
+      childListName = aFrame->GetAdditionalChildListName(childListIndex++);
+    } while (childListName == nsGkAtoms::popupList);
   } while (childListName);
 }
 
 /**
  * The second half of frame reflow. Does the following:
  * - sets the frame's bounds
  * - sizes and positions (if requested) the frame's view. If the frame's final
  *   position differs from the current position and the frame itself does not
--- a/layout/xul/base/public/Makefile.in
+++ b/layout/xul/base/public/Makefile.in
@@ -44,18 +44,18 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE		= layout
 XPIDL_MODULE	= layout_xul
 GRE_MODULE	= 1
 
 EXPORTS		= \
 		nsPIBoxObject.h \
 		nsIMenuFrame.h \
-		nsIPopupSetFrame.h \
 		nsIScrollbarMediator.h \
+		nsXULPopupManager.h \
 		$(NULL)
 
 XPIDLSRCS=      nsIBoxObject.idl                  \
                 nsIScrollBoxObject.idl              \
                 nsIScrollBoxObject.idl \
                 nsIPopupBoxObject.idl \
                 nsIMenuBoxObject.idl \
                 nsIBrowserBoxObject.idl \
--- a/layout/xul/base/public/nsIMenuFrame.h
+++ b/layout/xul/base/public/nsIMenuFrame.h
@@ -33,61 +33,33 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsIMenuFrame_h___
 #define nsIMenuFrame_h___
 
-// {2281EFC8-A8BA-4a73-8CF7-DB4EECA5EAEC}
-#define NS_IMENUFRAME_IID \
-{ 0x2281efc8, 0xa8ba, 0x4a73, { 0x8c, 0xf7, 0xdb, 0x4e, 0xec, 0xa5, 0xea, 0xec } }
+#include "nsISupports.h"
 
-class nsIMenuParent;
-class nsIDOMElement;
-class nsIDOMKeyEvent;
+// this interface exists solely because native themes need to call into it.
+// Only menu frames should implement it
 
-enum nsMenuType {
-  eMenuType_Normal = 0,
-  eMenuType_Checkbox = 1,
-  eMenuType_Radio = 2
-};
+// {212521C8-1509-4F41-ADDB-6A0B9356770F}
+#define NS_IMENUFRAME_IID \
+{ 0x212521C8, 0x1509, 0x4F41, { 0xAD, 0xDB, 0x6A, 0x0B, 0x93, 0x56, 0x77, 0x0F } }
 
 class nsIMenuFrame : public nsISupports {
 
 public:
+
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMENUFRAME_IID)
 
-  NS_IMETHOD ActivateMenu(PRBool aActivate) = 0;
-  NS_IMETHOD SelectMenu(PRBool aFlag) = 0;
-  NS_IMETHOD OpenMenu(PRBool aFlag) = 0;
-
-  NS_IMETHOD MenuIsOpen(PRBool& aResult) = 0;
-  NS_IMETHOD MenuIsContainer(PRBool& aResult) = 0;
-  NS_IMETHOD MenuIsChecked(PRBool& aResult) = 0;
-  NS_IMETHOD MenuIsDisabled(PRBool& aResult) = 0;
-
-  NS_IMETHOD SelectFirstItem() = 0;
-
-  NS_IMETHOD Escape(PRBool& aHandledFlag) = 0;
-  NS_IMETHOD Enter() = 0;
-  NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag) = 0;
-  NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag) = 0;
-
-  virtual nsIMenuParent *GetMenuParent() = 0;
-  virtual nsIFrame *GetMenuChild() = 0;
- 
-  NS_IMETHOD GetRadioGroupName(nsString &aName) = 0;
-  NS_IMETHOD GetMenuType(nsMenuType &aType) = 0;
-
-  NS_IMETHOD MarkAsGenerated() = 0;
-
-  NS_IMETHOD UngenerateMenu() = 0;
-
-  NS_IMETHOD GetActiveChild(nsIDOMElement** aResult)=0;
-  NS_IMETHOD SetActiveChild(nsIDOMElement* aChild)=0;
+  virtual PRBool IsOpen() = 0;
+  virtual PRBool IsMenu() = 0;
+  virtual PRBool IsOnMenuBar() = 0;
+  virtual PRBool IsOnActiveMenuBar() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuFrame, NS_IMENUFRAME_IID)
 
 #endif
 
--- a/layout/xul/base/public/nsIPopupBoxObject.idl
+++ b/layout/xul/base/public/nsIPopupBoxObject.idl
@@ -36,34 +36,47 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIBoxObject.idl"
 
 interface nsIDOMElement;
 
-
-[scriptable, uuid(116ffbea-336d-4ff1-a978-7335f54d11da)]
+[scriptable, uuid(8714441F-0E24-4EB5-BE58-905F2854B4EB)]
 interface nsIPopupBoxObject : nsISupports
 {
+  /**
+   *  This method is deprecated. Use openPopup or openPopupAtScreen instead.
+   */
   void showPopup(in nsIDOMElement srcContent, in nsIDOMElement popupContent,
                  in long xpos, in long ypos,
                  in wstring popupType, in wstring anchorAlignment, 
                  in wstring popupAlignment);
+
+  /**
+   *  Hide the popup if it is open.
+   */
   void hidePopup();
 
-
   /** 
    * Allow the popup to automatically position itself.
    */
   attribute boolean autoPosition;
 
   /**
-   * Allow the popup to eat all key events
+   * If keyboard navigation is enabled, the keyboard may be used to navigate
+   * the menuitems on the popup. Enabling keyboard navigation is the default
+   * behaviour and will install capturing key event listeners on the popup
+   * that do not propagate key events to the contents. If you wish to place
+   * elements in a popup which accept key events, such as textboxes, keyboard
+   * navigation should be disabled.
+   *
+   * Setting ignorekeys="true" on the popup element also disables keyboard
+   * navigation, and is recommended over calling this method.
    */
   void enableKeyboardNavigator(in boolean enableKeyboardNavigator);
 
   /** 
    * Enable automatic popup dismissal. This only has effect when called
    * on an open popup.
    */
   void enableRollup(in boolean enableRollup);
@@ -80,19 +93,71 @@ interface nsIPopupBoxObject : nsISupport
   void setConsumeRollupEvent(in PRUint32 consume);
 
   /** 
    * Size the popup to the given dimensions
    */
   void sizeTo(in long width, in long height);
 
   /**
-   * Move the popup to a point on screen
+   * Move the popup to a point on screen in CSS pixels.
    */
   void moveTo(in long left, in long top);
 
+  /**
+   * Open the popup relative to a specified node at a specific location.
+   *
+   * The popup may be either anchored to another node or opened freely.
+   * To anchor a popup to a node, supply an anchor node and set the position
+   * to a string indicating the manner in which the popup should be anchored.
+   * Possible values for position are:
+   *    before_start, before_end, after_start, after_end,
+   *    start_before, start_after, end_before, end_after,
+   *    overlap, after_pointer
+   *
+   * The anchor node does not need to be in the same document as the popup.
+   *
+   * If the attributesOverride argument is true, the popupanchor, popupalign
+   * and position attributes on the popup node override the position value
+   * argument. If attributesOverride is false, the attributes are only used
+   * if position is empty.
+   *
+   * For an anchored popup, the x and y arguments may be used to offset the 
+   * popup from its anchored position by some number, measured in CSS pixels.
+   *
+   * Unanchored popups may be created by supplying null as the anchor node.
+   * An unanchored popup appears at the position specified by x and y,
+   * relative to the viewport of the document containing the popup node. In
+   * this case, position and attributesOverride are ignored.
+   *
+   * @param anchorElement the node to anchor the popup to, may be null
+   * @param position manner is which to anchor the popup to node
+   * @param x horizontal offset
+   * @param y vertical offset
+   * @param isContextMenu true for context menus, false for other popups
+   * @param attributesOverride true if popup node attributes override position
+   */
+  void openPopup(in nsIDOMElement anchorElement,
+                 in AString position,
+                 in long x, in long y,
+                 in boolean isContextMenu,
+                 in boolean attributesOverride);
+
+  /**
+   * Open the popup at a specific screen position specified by x and y. This
+   * position may be adjusted if it would cause the popup to be off of the
+   * screen. The x and y coordinates are measured in CSS pixels. The monitor
+   * selected is determined within the platform specific widget code, but
+   * in general, the coordinates are relative to the screen the window
+   * containing the popup is on.
+   *
+   * @param isContextMenu true for context menus, false for other popups
+   * @param x horizontal screen position
+   * @param y vertical screen position
+   */
+  void openPopupAtScreen(in long x, in long y, in boolean isContextMenu);
 };
 
 %{C++
 nsresult
 NS_NewPopupBoxObject(nsIBoxObject** aResult);
 
 %}
deleted file mode 100644
--- a/layout/xul/base/public/nsIPopupSetFrame.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsIPopupSetFrame_h___
-#define nsIPopupSetFrame_h___
-
-// 043ecc8e-469f-40e1-9569-0529ac0c3039
-#define NS_IPOPUPSETFRAME_IID \
-{ 0x043ecc8e, 0x469f, 0x40e1, \
- { 0x95, 0x69, 0x05, 0x29, 0xac, 0x0c, 0x30, 0x39 } }
-
-class nsIFrame;
-class nsIContent;
-class nsIDOMElement;
-
-#include "nsString.h"
-
-class nsIPopupSetFrame : public nsISupports {
-
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPOPUPSETFRAME_IID)
-
-  NS_IMETHOD ShowPopup(nsIContent* aElementContent, nsIContent* aPopupContent, 
-                       PRInt32 aXPos, PRInt32 aYPos, 
-                       const nsString& aPopupType, const nsString& anAnchorAlignment,
-                       const nsString& aPopupAlignment) = 0;
-  NS_IMETHOD HidePopup(nsIFrame* aPopup) = 0;
-  NS_IMETHOD DestroyPopup(nsIFrame* aPopup, PRBool aDestroyEntireChain) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIPopupSetFrame, NS_IPOPUPSETFRAME_IID)
-
-#endif
-
new file mode 100644
--- /dev/null
+++ b/layout/xul/base/public/nsXULPopupManager.h
@@ -0,0 +1,636 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Neil Deakin
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The XUL Popup Manager keeps track of all open popups.
+ */
+
+#ifndef nsXULPopupManager_h__
+#define nsXULPopupManager_h__
+
+#include "nsIContent.h"
+#include "nsIWidget.h"
+#include "nsIRollupListener.h"
+#include "nsIMenuRollup.h"
+#include "nsIDOMKeyListener.h"
+#include "nsCOMPtr.h"
+#include "nsITimer.h"
+#include "nsThreadUtils.h"
+
+/**
+ * There are two types that are used:
+ *   - dismissable popups such as menus, which should close up when there is a
+ *     click outside the popup. In this situation, the entire chain of menus
+ *     above should also be closed.
+ *   - panels, which stay open until a request is made to close them. This
+ *     type is used by tooltips.
+ *   XXXndeakin note that panels don't work too well currently due to widget
+ *              changes needed to handle activation events properly.
+ *
+ * When a new popup is opened, it is appended to the popup chain, stored in a
+ * linked list in mCurrentMenu for dismissable menus or mPanels for panels.
+ * Popups are stored in this list linked from newest to oldest. When a click
+ * occurs outside one of the open dismissable popups, the chain is closed by
+ * calling Rollup.
+ */
+
+class nsIPresShell;
+class nsMenuFrame;
+class nsMenuPopupFrame;
+class nsMenuBarFrame;
+class nsIMenuParent;
+class nsIDOMKeyEvent;
+
+/**
+ * nsNavigationDirection: an enum expressing navigation through the menus in
+ * terms which are independent of the directionality of the chrome. The
+ * terminology, derived from XSL-FO and CSS3 (e.g. 
+ * http://www.w3.org/TR/css3-text/#TextLayout), is BASE (Before, After, Start,
+ * End), with the addition of First and Last (mapped to Home and End
+ * respectively).
+ *
+ * In languages such as English where the inline progression is left-to-right
+ * and the block progression is top-to-bottom (lr-tb), these terms will map out
+ * as in the following diagram
+ *
+ *  --- inline progression --->
+ *
+ *           First              |
+ *           ...                |
+ *           Before             |
+ *         +--------+         block
+ *   Start |        | End  progression
+ *         +--------+           |
+ *           After              |
+ *           ...                |
+ *           Last               V
+ * 
+ */
+
+enum nsNavigationDirection {
+  eNavigationDirection_Last,
+  eNavigationDirection_First,
+  eNavigationDirection_Start,
+  eNavigationDirection_Before,
+  eNavigationDirection_End,
+  eNavigationDirection_After
+};
+
+#define NS_DIRECTION_IS_INLINE(dir) (dir == eNavigationDirection_Start ||     \
+                                     dir == eNavigationDirection_End)
+#define NS_DIRECTION_IS_BLOCK(dir) (dir == eNavigationDirection_Before || \
+                                    dir == eNavigationDirection_After)
+#define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) (dir == eNavigationDirection_First ||    \
+                                            dir == eNavigationDirection_Last)
+
+/**
+ * DirectionFromKeyCode_lr_tb: an array that maps keycodes to values of
+ * nsNavigationDirection for left-to-right and top-to-bottom flow orientation
+ */
+static nsNavigationDirection DirectionFromKeyCode_lr_tb [6] = {
+  eNavigationDirection_Last,   // NS_VK_END
+  eNavigationDirection_First,  // NS_VK_HOME
+  eNavigationDirection_Start,  // NS_VK_LEFT
+  eNavigationDirection_Before, // NS_VK_UP
+  eNavigationDirection_End,    // NS_VK_RIGHT
+  eNavigationDirection_After   // NS_VK_DOWN
+};
+
+/**
+ * DirectionFromKeyCode_rl_tb: an array that maps keycodes to values of
+ * nsNavigationDirection for right-to-left and top-to-bottom flow orientation
+ */
+static nsNavigationDirection DirectionFromKeyCode_rl_tb [6] = {
+  eNavigationDirection_Last,   // NS_VK_END
+  eNavigationDirection_First,  // NS_VK_HOME
+  eNavigationDirection_End,    // NS_VK_LEFT
+  eNavigationDirection_Before, // NS_VK_UP
+  eNavigationDirection_Start,  // NS_VK_RIGHT
+  eNavigationDirection_After   // NS_VK_DOWN
+};
+
+#define NS_DIRECTION_FROM_KEY_CODE(frame, direction, keycode)    \
+  NS_ASSERTION(NS_VK_HOME == NS_VK_END + 1, "Broken ordering");  \
+  NS_ASSERTION(NS_VK_LEFT == NS_VK_END + 2, "Broken ordering");  \
+  NS_ASSERTION(NS_VK_UP == NS_VK_END + 3, "Broken ordering");    \
+  NS_ASSERTION(NS_VK_RIGHT == NS_VK_END + 4, "Broken ordering"); \
+  NS_ASSERTION(NS_VK_DOWN == NS_VK_END + 5, "Broken ordering");  \
+  NS_ASSERTION(keycode >= NS_VK_END && keycode <= NS_VK_DOWN,    \
+               "Illegal key code");                              \
+  const nsStyleVisibility* vis = frame->GetStyleVisibility();    \
+  if (vis->mDirection == NS_STYLE_DIRECTION_RTL)                 \
+    direction = DirectionFromKeyCode_rl_tb[keycode - NS_VK_END]; \
+  else                                                           \
+    direction = DirectionFromKeyCode_lr_tb[keycode - NS_VK_END];
+
+// nsMenuChainItem holds info about an open popup. Items are stored in a
+// doubly linked list. Note that the linked list is stored beginning from
+// the lowest child in a chain of menus, as this is the active submenu.
+class nsMenuChainItem
+{
+private:
+  nsMenuPopupFrame* mFrame; // the popup frame
+  PRPackedBool mIsMenu; // true if the popup is a menu, false for a panel
+  PRPackedBool mIsContext; // true for context menus
+  PRPackedBool mOnMenuBar; // true if the menu is on a menu bar
+  PRPackedBool mIgnoreKeys; // true if keyboard listeners should not be used
+
+  nsMenuChainItem* mParent;
+  nsMenuChainItem* mChild;
+
+public:
+  nsMenuChainItem(nsMenuPopupFrame* aFrame, PRBool aIsContext, PRBool aIsMenu)
+    : mFrame(aFrame),
+      mIsMenu(aIsMenu),
+      mIsContext(aIsContext),
+      mOnMenuBar(PR_FALSE),
+      mIgnoreKeys(!aIsMenu), // always ignore keys on non-menus
+      mParent(nsnull),
+      mChild(nsnull)
+  {
+    NS_ASSERTION(aFrame, "null frame passed to nsMenuChainItem constructor");
+    MOZ_COUNT_CTOR(nsMenuChainItem);
+  }
+
+  ~nsMenuChainItem()
+  {
+    MOZ_COUNT_DTOR(nsMenuChainItem);
+  }
+
+  nsIContent* Content();
+  nsMenuPopupFrame* Frame() { return mFrame; }
+  PRBool IsMenu() { return mIsMenu; }
+  PRBool IsContextMenu() { return mIsContext; }
+  PRBool IgnoreKeys() { return mIgnoreKeys; }
+  PRBool IsOnMenuBar() { return mOnMenuBar; }
+  void SetIgnoreKeys(PRBool aIgnoreKeys) { mIgnoreKeys = aIgnoreKeys; }
+  void SetOnMenuBar(PRBool aOnMenuBar) { mOnMenuBar = aOnMenuBar; }
+  nsMenuChainItem* GetParent() { return mParent; }
+  nsMenuChainItem* GetChild() { return mChild; }
+
+  // set the parent of this item to aParent, also changing the parent
+  // to have this as a child.
+  void SetParent(nsMenuChainItem* aParent);
+
+  // removes an item from the chain. The root pointer must be supplied in case
+  // the item is the first item in the chain in which case the pointer will be
+  // set to the next item, or null if there isn't another item. After detaching,
+  // this item will not have a parent or a child.
+  void Detach(nsMenuChainItem** aRoot);
+};
+
+// this class is used for dispatching popupshowing events asynchronously.
+class nsXULPopupShowingEvent : public nsRunnable
+{
+public:
+  nsXULPopupShowingEvent(nsIContent *aPopup,
+                         nsIContent *aMenu,
+                         PRBool aIsContextMenu,
+                         PRBool aSelectFirstItem)
+    : mPopup(aPopup),
+      mMenu(aMenu),
+      mIsContextMenu(aIsContextMenu),
+      mSelectFirstItem(aSelectFirstItem)
+  {
+    NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupShowingEvent constructor");
+    NS_ASSERTION(aMenu, "null menu supplied to nsXULPopupShowingEvent constructor");
+  }
+
+  NS_IMETHOD Run();
+
+private:
+  nsCOMPtr<nsIContent> mPopup;
+  nsCOMPtr<nsIContent> mMenu;
+  PRBool mIsContextMenu;
+  PRBool mSelectFirstItem;
+};
+
+// this class is used for dispatching popuphiding events asynchronously.
+class nsXULPopupHidingEvent : public nsRunnable
+{
+public:
+  nsXULPopupHidingEvent(nsIContent *aPopup,
+                        nsIContent* aNextPopup,
+                        nsIContent* aLastPopup,
+                        PRBool aIsMenu,
+                        PRBool aDeselectMenu)
+    : mPopup(aPopup),
+      mNextPopup(aNextPopup),
+      mLastPopup(aLastPopup),
+      mIsMenu(aIsMenu),
+      mDeselectMenu(aDeselectMenu)
+  {
+    NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupHidingEvent constructor");
+    // aNextPopup and aLastPopup may be null
+  }
+
+  NS_IMETHOD Run();
+
+private:
+  nsCOMPtr<nsIContent> mPopup;
+  nsCOMPtr<nsIContent> mNextPopup;
+  nsCOMPtr<nsIContent> mLastPopup;
+  PRBool mIsMenu;
+  PRBool mDeselectMenu;
+};
+
+// this class is used for dispatching menu command events asynchronously.
+class nsXULMenuCommandEvent : public nsRunnable
+{
+public:
+  nsXULMenuCommandEvent(nsIContent *aMenu,
+                        PRBool aIsTrusted,
+                        PRBool aShift,
+                        PRBool aControl,
+                        PRBool aAlt,
+                        PRBool aMeta)
+    : mMenu(aMenu),
+      mIsTrusted(aIsTrusted),
+      mShift(aShift),
+      mControl(aControl),
+      mAlt(aAlt),
+      mMeta(aMeta)
+  {
+    NS_ASSERTION(aMenu, "null menu supplied to nsXULMenuCommandEvent constructor");
+  }
+
+  NS_IMETHOD Run();
+
+private:
+  nsCOMPtr<nsIContent> mMenu;
+  PRBool mIsTrusted;
+  PRBool mShift;
+  PRBool mControl;
+  PRBool mAlt;
+  PRBool mMeta;
+};
+
+class nsXULPopupManager : public nsIDOMKeyListener,
+                          public nsIMenuRollup,
+                          public nsIRollupListener,
+                          public nsITimerCallback
+{
+
+public:
+  friend class nsXULPopupShowingEvent;
+  friend class nsXULPopupHidingEvent;
+  friend class nsXULMenuCommandEvent;
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIROLLUPLISTENER
+  NS_DECL_NSIMENUROLLUP
+  NS_DECL_NSITIMERCALLBACK
+
+  static nsXULPopupManager* sInstance;
+
+  // initialize and shutdown methods called by nsLayoutStatics
+  static nsresult Init();
+  static void Shutdown();
+
+  // returns a weak reference to the popup manager instance, could return null
+  // if a popup manager could not be allocated
+  static nsXULPopupManager* GetInstance();
+
+  // given a menu frame, find the prevous or next menu frame. If aPopup is
+  // true then navigate a menupopup, from one item on the menu to the previous
+  // or next one. This is used for cursor navigation between items in a popup
+  // menu. If aIsPopup is false, the navigation is on a menubar, so navigate
+  // between menus on the menubar. This is used for left/right cursor navigation.
+  //
+  // Items that not valid, such as non-menu or menuitem elements are skipped,
+  // and the next or previous item after that is checked.
+  //
+  // If aStart is null, the first valid item is retrieved for GetNextMenuItem
+  // or the last valid item for GetPreviousMenuItem is used.
+  //
+  // aParent - the parent menubar or menupopup
+  // aStart - the menu/menuitem to start navigation from. GetPreviousMenuItem
+  //          returns the item before it, while GetNextMenuItem returns the
+  //          next item.
+  // aIsPopup - true for menupopups, false for menubars
+  static nsMenuFrame* GetPreviousMenuItem(nsIFrame* aParent,
+                                          nsMenuFrame* aStart,
+                                          PRBool aIsPopup);
+  static nsMenuFrame* GetNextMenuItem(nsIFrame* aParent,
+                                      nsMenuFrame* aStart,
+                                      PRBool aIsPopup);
+
+  // returns true if the menu item aContent is a valid menuitem which may
+  // be navigated to. aIsPopup should be true for items on a popup, or false
+  // for items on a menubar.
+  static PRBool IsValidMenuItem(nsPresContext* aPresContext,
+                                nsIContent* aContent,
+                                PRBool aOnPopup);
+
+  // inform the popup manager that a menu bar has been activated or deactivated,
+  // either because one of its menus has opened or closed, or that the menubar
+  // has been focused such that its menus may be navigated with the keyboard.
+  // aActivate should be true when the menubar should be focused, and false
+  // when the active menu bar should be defocused. In the latter case, if
+  // aMenuBar isn't currently active, yet another menu bar is, that menu bar
+  // will remain active.
+  void SetActiveMenuBar(nsMenuBarFrame* aMenuBar, PRBool aActivate);
+
+  // retrieve the node and offset of the last mouse event used to open a
+  // context menu. This information is determined from the rangeParent and
+  // the rangeOffset of the event supplied from the last call to SetMouseLocation.
+  // This is used by the implementation of nsIDOMXULDocument::GetPopupRangeParent
+  // and nsIDOMXULDocument::GetPopupRangeOffset.
+  void GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset);
+  // set the mouse event that was used to activate the next popup to be opened.
+  void SetMouseLocation(nsIDOMEvent* aEvent);
+
+  /**
+   * Open a <menu> given its content node. If aSelectFirstItem is
+   * set to true, the first item on the menu will automatically be
+   * selected. If aAsynchronous is true, the event will be dispatched
+   * asynchronously. This should be true when called from frame code.
+   */
+  void ShowMenu(nsIContent *aMenu, PRBool aSelectFirstItem, PRBool aAsynchronous);
+
+  /**
+   * Open a popup, either anchored or unanchored. If aSelectFirstItem is
+   * true, then the first item in the menu is selected. The arguments are
+   * similar to those for nsIPopupBoxObject::OpenPopup.
+   *
+   * This fires the popupshowing event synchronously.
+   */
+  void ShowPopup(nsIContent* aPopup,
+                 nsIContent* aAnchorContent,
+                 const nsAString& aPosition,
+                 PRInt32 aXPos, PRInt32 aYPos,
+                 PRBool aIsContextMenu,
+                 PRBool aAttributesOverride,
+                 PRBool aSelectFirstItem);
+
+  /**
+   * Open a popup at a specific screen position specified by aXPos and aYPos,
+   * measured in CSS pixels.
+   *
+   * This fires the popupshowing event synchronously.
+   */
+  void ShowPopupAtScreen(nsIContent* aPopup,
+                         PRInt32 aXPos, PRInt32 aYPos,
+                         PRBool aIsContextMenu);
+
+  /**
+   * This method is provided only for compatibility with an older popup API.
+   * New code should not call this function and should call ShowPopup instead.
+   *
+   * This fires the popupshowing event synchronously.
+   */
+  void ShowPopupWithAnchorAlign(nsIContent* aPopup,
+                                nsIContent* aAnchorContent,
+                                nsAString& aAnchor,
+                                nsAString& aAlign,
+                                PRInt32 aXPos, PRInt32 aYPos,
+                                PRBool aIsContextMenu);
+
+  /*
+   * Hide a popup aPopup. If the popup is in a <menu>, then also inform the
+   * menu that the popup is being hidden.
+   *
+   * aHideChain - true if the entire chain of menus should be closed. If false,
+   *              only this popup is closed.
+   * aDeselectMenu - true if the parent <menu> of the popup should be deselected.
+   *                 This will be false when the menu is closed by pressing the
+   *                 Escape key.
+   * aAsynchronous - true if the first popuphiding event should be sent
+   *                 asynchrously. This should be true if HidePopup is called
+   *                 from a frame.
+   */
+  void HidePopup(nsIContent* aPopup,
+                 PRBool aHideChain,
+                 PRBool aDeselectMenu,
+                 PRBool aAsynchronous);
+
+  /**
+   * Hide a popup after a short delay. This is used when rolling over menu items.
+   * This timer is stored in mCloseTimer. The timer may be cancelled and the popup
+   * closed by calling KillMenuTimer.
+   */
+  void HidePopupAfterDelay(nsMenuPopupFrame* aPopup);
+
+  /**
+   * Hide all of the popups from a given document. This should be called when the
+   * document is hidden.
+   */
+  void HidePopupsInDocument(nsIDocument* aDocument);
+
+  /**
+   * Execute a menu command from the triggering event aEvent.
+   *
+   * aMenu - a menuitem to execute
+   * aEvent - the mouse event which triggered the menu to be executed,
+   *          may be null
+   */
+  void ExecuteMenu(nsIContent* aMenu, nsEvent* aEvent);
+
+  /**
+   * Return true if the popup for the supplied menu parent is open.
+   */
+  PRBool IsPopupOpenForMenuParent(nsIMenuParent* aMenuParent);
+
+  /**
+   * Return false if a popup may not be opened. This will return false if the
+   * popup is already open, if the popup is in a content shell that is not
+   * focused, or if it is a submenu of another menu that isn't open.
+   */
+  PRBool MayShowPopup(nsMenuPopupFrame* aFrame);
+
+  /**
+   * Called when a popup frame is destroyed. In this case, just remove the
+   * item and later popups from the list. No point going through HidePopup as
+   * the frames have gone away.
+   */
+  void PopupDestroyed(nsMenuPopupFrame* aFrame);
+
+  /**
+   * Returns true if there is a context menu open. If aPopup is specified,
+   * then the context menu must be later in the chain than aPopup. If aPopup
+   * is null, returns true if any context menu at all is open.
+   */
+  PRBool HasContextMenu(nsMenuPopupFrame* aPopup);
+
+  /**
+   * Update the commands for the menus within the menu popup for a given
+   * content node. aPopup should be a XUL menupopup element. This method
+   * changes attributes on the children of aPopup, and deals only with the
+   * content of the popup, not the frames.
+   */
+  void UpdateMenuItems(nsIContent* aPopup);
+
+  /**
+   * Stop the timer which hides a popup after a delay, started by a previous
+   * call to HidePopupAfterDelay. In addition, the popup awaiting to be hidden
+   * is closed asynchronously.
+   */
+  void KillMenuTimer();
+
+  /**
+   * Handles navigation for menu accelkeys. Returns true if the key has
+   * been handled.
+   */
+  PRBool HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent);
+
+  /**
+   * Handles cursor navigation within a menu. Returns true if the key has
+   * been handled.
+   */
+  PRBool HandleKeyboardNavigation(PRUint32 aKeyCode);
+
+  NS_IMETHODIMP HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
+
+  NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
+  NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
+  NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
+
+protected:
+  nsXULPopupManager();
+  ~nsXULPopupManager();
+
+  // get the frame for a content node aContent if the frame's type
+  // matches aFrameType. Otherwise, return null.
+  nsIFrame* GetFrameOfTypeForContent(nsIContent* aContent, nsIAtom* aFrameType);
+
+  // get the nsMenuFrame, if any, for the given content node
+  nsMenuFrame* GetMenuFrameForContent(nsIContent* aContent);
+
+  // get the nsMenuPopupFrame, if any, for the given content node
+  nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent);
+
+  // callbacks for ShowPopup and HidePopup as events may be done asynchronously
+  void ShowPopupCallback(nsIContent* aPopup,
+                         nsMenuPopupFrame* aPopupFrame,
+                         PRBool aIsContextMenu,
+                         PRBool aSelectFirstItem);
+  void HidePopupCallback(nsIContent* aPopup,
+                         nsMenuPopupFrame* aPopupFrame,
+                         nsIContent* aNextPopup,
+                         nsIContent* aLastPopup,
+                         PRBool aIsMenu,
+                         PRBool aDeselectMenu);
+
+  /**
+   * Fire a popupshowing event on the popup aPopup and then open the popup.
+   *
+   * aPopup - the popup node to open
+   * aMenu - should be set to the parent menu if this is a popup associated
+   *         with a menu. Otherwise, should be null.
+   * aPresContext - the prescontext 
+   * aIsContextMenu - true for context menus
+   * aSelectFirstItem - true to select the first item in the menu
+   */
+  void FirePopupShowingEvent(nsIContent* aPopup,
+                             nsIContent* aMenu,
+                             nsPresContext* aPresContext,
+                             PRBool aIsContextMenu,
+                             PRBool aSelectFirstItem);
+
+  /**
+   * Fire a popuphiding event and then hide the popup. This will be called
+   * recursively if aNextPopup and aLastPopup are set in order to hide a chain
+   * of open menus. If these are not set, only one popup is closed. However,
+   * if aIsMenu is true, yet the next popup is not a menu, then this ends the
+   * closing of popups. This allows a menulist inside a non-menu to close up
+   * the menu but not close up the panel it is contained within.
+   *
+   * aPopup - the popup to hide
+   * aNextPopup - the next popup to hide
+   * aLastPopup - the last popup in the chain to hide
+   * aPresContext - nsPresContext for the popup's frame
+   * aIsMenu - true if aPopup is a menu. 
+   * aDeselectMenu - true to unhighlight the menu when hiding it
+   */
+  void FirePopupHidingEvent(nsIContent* aPopup,
+                            nsIContent* aNextPopup,
+                            nsIContent* aLastPopup,
+                            nsPresContext *aPresContext,
+                            PRBool aIsMenu,
+                            PRBool aDeselectMenu);
+
+  // handle keyboard navigation within a menu popup. Returns true if the
+  // key was handled and that other default handling should not occur.
+  PRBool HandleKeyboardNavigationInPopup(nsMenuChainItem* item,
+                                         nsNavigationDirection aDir);
+
+  /**
+   * Set mouse capturing for the current popup. This traps mouse clicks that
+   * occur outside the popup so that it can be closed up. aOldPopup should be
+   * set to the popup that was previously the current popup.
+   */
+  void SetCaptureState(nsIContent *aOldPopup);
+
+  /**
+   * Key event listeners are attached to the document containing the current
+   * menu for menu and shortcut navigation. Only one listener is needed at a
+   * time, stored in mKeyListener, so switch it only if the document changes.
+   * Having menus in different documents is very rare, so the listeners will
+   * usually only be attached when the first menu opens and removed when all
+   * menus have closed.
+   *
+   * This is also used when only a menubar is active without any open menus,
+   * so that keyboard navigation between menus on the menubar may be done.
+   */
+  void UpdateKeyboardListeners();
+
+  // the document the key event listener is attached to
+  nsCOMPtr<nsIDOMEventTarget> mKeyListener;
+
+  // widget that is currently listening to rollup events
+  nsCOMPtr<nsIWidget> mWidget;
+
+  // range parent and offset set in SetMouseLocation
+  nsCOMPtr<nsIDOMNode> mRangeParent;
+  PRInt32 mRangeOffset;
+
+  // set to the currently active menu bar, if any
+  nsMenuBarFrame* mActiveMenuBar;
+
+  // linked list of dismissable menus.
+  nsMenuChainItem* mCurrentMenu;
+
+  // linked list of panels
+  nsMenuChainItem* mPanels;
+
+  // timer used for HidePopupAfterDelay
+  nsCOMPtr<nsITimer> mCloseTimer;
+
+  // a popup that is waiting on the timer
+  nsMenuPopupFrame* mTimerMenu;
+};
+
+#endif
--- a/layout/xul/base/src/Makefile.in
+++ b/layout/xul/base/src/Makefile.in
@@ -114,24 +114,23 @@ CPPSRCS		+= \
 		nsFrameNavigator.cpp \
 		nsSplitterFrame.cpp \
 		nsDeckFrame.cpp \
 		nsProgressMeterFrame.cpp \
 		nsMenuPopupFrame.cpp \
 		nsMenuFrame.cpp \
 		nsMenuBarFrame.cpp \
 		nsMenuBarListener.cpp \
-		nsMenuListener.cpp \
-		nsMenuDismissalListener.cpp \
 		nsPopupSetFrame.cpp \
 		nsTitleBarFrame.cpp \
 		nsResizerFrame.cpp \
 		nsListBoxBodyFrame.cpp \
 		nsListItemFrame.cpp \
 		nsListBoxLayout.cpp \
+		nsXULPopupManager.cpp \
 		$(NULL)
 
 endif
 
 include $(topsrcdir)/config/config.mk
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
--- a/layout/xul/base/src/nsBoxFrame.cpp
+++ b/layout/xul/base/src/nsBoxFrame.cpp
@@ -1788,35 +1788,47 @@ nsBoxFrame::GetFrameSizeWithMargin(nsIBo
 
 /**
  * Boxed don't support fixed positionioning of their children.
  */
 nsresult
 nsBoxFrame::CreateViewForFrame(nsPresContext*  aPresContext,
                                nsIFrame*        aFrame,
                                nsStyleContext*  aStyleContext,
-                               PRBool           aForce)
+                               PRBool           aForce,
+                               PRBool           aIsPopup)
 {
   NS_ASSERTION(aForce, "We only get called to force view creation now");
   // If we don't yet have a view, see if we need a view
   if (!aFrame->HasView()) {
+    nsViewVisibility visibility = nsViewVisibility_kShow;
     PRInt32 zIndex = 0;
     PRBool  autoZIndex = PR_FALSE;
 
     if (aForce) {
-      // Create a view
-      nsIFrame* parent = aFrame->GetAncestorWithView();
-      NS_ASSERTION(parent, "GetAncestorWithView failed");
-      nsIView* parentView = parent->GetView();
-      NS_ASSERTION(parentView, "no parent with view");
-      nsIViewManager* viewManager = parentView->GetViewManager();
+      nsIView* parentView;
+      nsIViewManager* viewManager = aPresContext->GetViewManager();
       NS_ASSERTION(nsnull != viewManager, "null view manager");
 
       // Create a view
-      nsIView *view = viewManager->CreateView(aFrame->GetRect(), parentView);
+      if (aIsPopup) {
+        viewManager->GetRootView(parentView);
+        visibility = nsViewVisibility_kHide;
+        zIndex = PR_INT32_MAX;
+      }
+      else {
+        nsIFrame* parent = aFrame->GetAncestorWithView();
+        NS_ASSERTION(parent, "GetAncestorWithView failed");
+        parentView = parent->GetView();
+      }
+
+      NS_ASSERTION(parentView, "no parent view");
+
+      // Create a view
+      nsIView *view = viewManager->CreateView(aFrame->GetRect(), parentView, visibility);
       if (view) {
         // Insert the view into the view hierarchy. If the parent view is a
         // scrolling view we need to do this differently
         nsIScrollableView*  scrollingView = parentView->ToScrollableView();
         if (scrollingView) {
           scrollingView->SetScrolledView(view);
         } else {
           viewManager->SetViewZIndex(view, autoZIndex, zIndex);
--- a/layout/xul/base/src/nsBoxFrame.h
+++ b/layout/xul/base/src/nsBoxFrame.h
@@ -157,21 +157,24 @@ public:
 
   NS_IMETHOD DidReflow(nsPresContext*           aPresContext,
                        const nsHTMLReflowState*  aReflowState,
                        nsDidReflowStatus         aStatus);
 
   virtual ~nsBoxFrame();
   
   nsBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRBool aIsRoot = nsnull, nsIBoxLayout* aLayoutManager = nsnull);
- 
+
+  // if aIsPopup is true, then the view is for a popup. In this case,
+  // the view is added a child of the root view, and is initially hidden
   static nsresult CreateViewForFrame(nsPresContext* aPresContext,
                                      nsIFrame* aChild,
                                      nsStyleContext* aStyleContext,
-                                     PRBool aForce);
+                                     PRBool aForce,
+                                     PRBool aIsPopup = PR_FALSE);
 
   // virtual so nsStackFrame, nsButtonBoxFrame, nsSliderFrame and nsMenuFrame
   // can override it
   NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                          const nsRect&           aDirtyRect,
                                          const nsDisplayListSet& aLists);
 
   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
--- a/layout/xul/base/src/nsIMenuParent.h
+++ b/layout/xul/base/src/nsIMenuParent.h
@@ -34,150 +34,58 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsIMenuParent_h___
 #define nsIMenuParent_h___
 
-
-// {33f700c8-976a-4cdb-8f6c-d9f4cfee8366}
-#define NS_IMENUPARENT_IID \
-{ 0x33f700c8, 0x976a, 0x4cdb, { 0x8f, 0x6c, 0xd9, 0xf4, 0xcf, 0xee, 0x83, 0x66 } }
-
-class nsIMenuFrame;
-class nsIDOMKeyEvent;
+class nsMenuFrame;
 
 /*
- * nsIMenuParent is implemented on frames and thus should not be
- * refcounted.  Eventually it should not inherit from nsISupports.
- */
-
-/**
- * nsNavigationDirection: an enum expressing navigation through the menus in
- * terms which are independent of the directionality of the chrome. The
- * terminology, derived from XSL-FO and CSS3 (e.g. 
- * http://www.w3.org/TR/css3-text/#TextLayout), is BASE (Before, After, Start,
- * End), with the addition of First and Last (mapped to Home and End
- * respectively).
+ * nsIMenuParent is an interface implemented by nsMenuBarFrame and nsMenuPopupFrame
+ * as both serve as parent frames to nsMenuFrame.
  *
- * In languages such as English where the inline progression is left-to-right
- * and the block progression is top-to-bottom (lr-tb), these terms will map out
- * as in the following diagram
- *
- *  --- inline progression --->
- *
- *           First              |
- *           ...                |
- *           Before             |
- *         +--------+         block
- *   Start |        | End  progression
- *         +--------+           |
- *           After              |
- *           ...                |
- *           Last               V
- * 
+ * Don't implement this interface on other classes unless you also fix up references,
+ * as this interface is directly cast to and from nsMenuBarFrame and nsMenuPopupFrame.
  */
 
-enum nsNavigationDirection {
-  eNavigationDirection_Last,
-  eNavigationDirection_First,
-  eNavigationDirection_Start,
-  eNavigationDirection_Before,
-  eNavigationDirection_End,
-  eNavigationDirection_After
-};
-
-#define NS_DIRECTION_IS_INLINE(dir) (dir == eNavigationDirection_Start ||     \
-                                     dir == eNavigationDirection_End)
-#define NS_DIRECTION_IS_BLOCK(dir) (dir == eNavigationDirection_Before || \
-                                    dir == eNavigationDirection_After)
-#define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) (dir == eNavigationDirection_First ||    \
-                                            dir == eNavigationDirection_Last)
-
-/**
- * DirectionFromKeyCode_lr_tb: an array that maps keycodes to values of
- * nsNavigationDirection for left-to-right and top-to-bottom flow orientation
- */
-static nsNavigationDirection DirectionFromKeyCode_lr_tb [6] = {
-  eNavigationDirection_Last,   // NS_VK_END
-  eNavigationDirection_First,  // NS_VK_HOME
-  eNavigationDirection_Start,  // NS_VK_LEFT
-  eNavigationDirection_Before, // NS_VK_UP
-  eNavigationDirection_End,    // NS_VK_RIGHT
-  eNavigationDirection_After   // NS_VK_DOWN
-};
-
-/**
- * DirectionFromKeyCode_rl_tb: an array that maps keycodes to values of
- * nsNavigationDirection for right-to-left and top-to-bottom flow orientation
- */
-static nsNavigationDirection DirectionFromKeyCode_rl_tb [6] = {
-  eNavigationDirection_Last,   // NS_VK_END
-  eNavigationDirection_First,  // NS_VK_HOME
-  eNavigationDirection_End,    // NS_VK_LEFT
-  eNavigationDirection_Before, // NS_VK_UP
-  eNavigationDirection_Start,  // NS_VK_RIGHT
-  eNavigationDirection_After   // NS_VK_DOWN
-};
-
-#ifdef IBMBIDI
-#define NS_DIRECTION_FROM_KEY_CODE(direction, keycode)           \
-  NS_ASSERTION(keycode >= NS_VK_END && keycode <= NS_VK_DOWN,    \
-               "Illegal key code");                              \
-  const nsStyleVisibility* vis = GetStyleVisibility();           \
-  if (vis->mDirection == NS_STYLE_DIRECTION_RTL)                 \
-    direction = DirectionFromKeyCode_rl_tb[keycode - NS_VK_END]; \
-  else                                                           \
-    direction = DirectionFromKeyCode_lr_tb[keycode - NS_VK_END];
-#else
-#define NS_DIRECTION_FROM_KEY_CODE(direction, keycode)           \
-    direction = DirectionFromKeyCode_lr_tb[keycode - NS_VK_END];
-#endif
-
-class nsIMenuParent : public nsISupports {
+class nsIMenuParent {
 
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMENUPARENT_IID)
-
-  virtual nsIMenuFrame *GetCurrentMenuItem() = 0;
-  NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem) = 0;
-  virtual nsIMenuFrame *GetNextMenuItem(nsIMenuFrame* aStart) = 0;
-  virtual nsIMenuFrame *GetPreviousMenuItem(nsIMenuFrame* aStart) = 0;
-
-  NS_IMETHOD SetActive(PRBool aActiveFlag) = 0;
-  NS_IMETHOD GetIsActive(PRBool& isActive) = 0;
-  NS_IMETHOD GetWidget(nsIWidget **aWidget) = 0;
-  
-  NS_IMETHOD IsMenuBar(PRBool& isMenuBar) = 0;
-  NS_IMETHOD ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks) = 0;
-  NS_IMETHOD ClearRecentlyRolledUp() = 0;
-  NS_IMETHOD RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp) = 0;
-
-  NS_IMETHOD DismissChain() = 0;
-  NS_IMETHOD HideChain() = 0;
-  NS_IMETHOD KillPendingTimers() = 0;
-  NS_IMETHOD CancelPendingTimers() = 0;
+  // returns the menu frame of the currently active item within the menu
+  virtual nsMenuFrame *GetCurrentMenuItem() = 0;
+  // sets the currently active menu frame.
+  NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) = 0;
+  // indicate that the current menu frame is being destroyed, so clear the
+  // current menu item
+  virtual void CurrentMenuIsBeingDestroyed() = 0;
+  // deselects the current item and closes its popup if any, then selects the
+  // new item aMenuItem. For a menubar, if another menu is already open, the
+  // new menu aMenuItem is opened. In this case, if aSelectFirstItem is true,
+  // select the first item in it. For menupoups, the menu is not opened and
+  // the aSelectFirstItem argument is not used.
+  NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem) = 0;
 
-  NS_IMETHOD AttachedDismissalListener() = 0;
-
-  NS_IMETHOD InstallKeyboardNavigator() = 0;
-  NS_IMETHOD RemoveKeyboardNavigator() = 0;
+  // returns true if the menupopup is open. For menubars, returns false.
+  virtual PRBool IsOpen() = 0;
+  // returns true if the menubar is currently active. For menupopups, returns false.
+  virtual PRBool IsActive() = 0;
+  // returns true if this is a menubar. If false, it is a popup
+  virtual PRBool IsMenuBar() = 0;
+  // returns true if this is a menu, which has a tag of menupopup or popup.
+  // Otherwise, this returns false
+  virtual PRBool IsMenu() = 0;
+  // returns true if this is a context menu
+  virtual PRBool IsContextMenu() = 0;
 
-  // Used to move up, down, left, and right in menus.
-  NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag) = 0;
-  NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag) = 0;
-  // Called when the ESC key is held down to close levels of menus.
-  NS_IMETHOD Escape(PRBool& aHandledFlag) = 0;
-  // Called to execute a menu item.
-  NS_IMETHOD Enter() = 0;
+  // indicate that the menubar should become active or inactive
+  NS_IMETHOD SetActive(PRBool aActiveFlag) = 0;
 
-  NS_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) = 0;
-  NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) = 0;
-
-  NS_IMETHOD GetParentPopup(nsIMenuParent** aResult) = 0;
+  // notify that the menu has been closed and any active state should be
+  // cleared. This should return true if the menu should be deselected
+  // by the caller.
+  virtual PRBool MenuClosed() = 0;
 };
 
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIMenuParent, NS_IMENUPARENT_IID)
-
 #endif
 
--- a/layout/xul/base/src/nsIRootBox.h
+++ b/layout/xul/base/src/nsIRootBox.h
@@ -36,33 +36,33 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 
 #ifndef nsIRootBox_h___
 #define nsIRootBox_h___
 
 #include "nsISupports.h"
-class nsIFrame;
+class nsPopupSetFrame;
 class nsIContent;
 class nsIPresShell;
 
-// {2256d568-3f5a-42ec-b932-3d0f78551a1a}
+// {9777EC2A-9A46-4D01-8CEB-B9CEB2C262A5}
 #define NS_IROOTBOX_IID \
-{ 0x2256d568, 0x3f5a, 0x42ec, \
-  { 0xb9, 0x32, 0x3d, 0x0f, 0x78, 0x55, 0x1a, 0x1a } }
+{ 0x9777EC2A, 0x9A46, 0x4D01, \
+  { 0x8C, 0xEB, 0xB9, 0xCE, 0xB2, 0xC2, 0x62, 0xA5 } }
 
 
 class nsIRootBox : public nsISupports {
 
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IROOTBOX_IID)
 
-  virtual nsIFrame* GetPopupSetFrame() = 0;
-  virtual void SetPopupSetFrame(nsIFrame* aPopupSet)=0;
+  virtual nsPopupSetFrame* GetPopupSetFrame() = 0;
+  virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) = 0;
 
   virtual nsIContent* GetDefaultTooltip() = 0;
   virtual void SetDefaultTooltip(nsIContent* aTooltip) = 0;
 
   virtual nsresult AddTooltipSupport(nsIContent* aNode) = 0;
   virtual nsresult RemoveTooltipSupport(nsIContent* aNode) = 0;
 
   static nsIRootBox* GetRootBox(nsIPresShell* aShell);
--- a/layout/xul/base/src/nsMenuBarFrame.cpp
+++ b/layout/xul/base/src/nsMenuBarFrame.cpp
@@ -32,21 +32,19 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nsMenuListener.h"
 #include "nsMenuBarFrame.h"
 #include "nsIServiceManager.h"
 #include "nsIContent.h"
-#include "nsContentUtils.h"
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "nsCSSRendering.h"
 #include "nsINameSpaceManager.h"
 #include "nsIDocument.h"
 #include "nsIDOMEventTarget.h"
@@ -74,61 +72,28 @@
 // Wrapper for creating a new menu Bar container
 //
 nsIFrame*
 NS_NewMenuBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsMenuBarFrame (aPresShell, aContext);
 }
 
-NS_IMETHODIMP_(nsrefcnt) 
-nsMenuBarFrame::AddRef(void)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP_(nsrefcnt) 
-nsMenuBarFrame::Release(void)
-{
-    return NS_OK;
-}
-
-
-//
-// QueryInterface
-//
-NS_INTERFACE_MAP_BEGIN(nsMenuBarFrame)
-  NS_INTERFACE_MAP_ENTRY(nsIMenuParent)
-NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
-
-
 //
 // nsMenuBarFrame cntr
 //
 nsMenuBarFrame::nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext):
   nsBoxFrame(aShell, aContext),
     mMenuBarListener(nsnull),
-    mKeyboardNavigator(nsnull),
     mIsActive(PR_FALSE),
     mTarget(nsnull),
     mCaretWasVisible(PR_FALSE)
 {
 } // cntr
 
-nsMenuBarFrame::~nsMenuBarFrame()
-{
-  /* The menubar can still be active at this point under unusual circumstances.
-     (say, while switching skins (which tears down all frames including
-     this one) after having made a menu selection (say, Edit->Preferences,
-     to get to the skin switching UI)). SetActive(PR_FALSE) releases
-     mKeyboardNavigator, which is by now pointing to a deleted frame.
-  */
-  SetActive(PR_FALSE);
-}
-
 NS_IMETHODIMP
 nsMenuBarFrame::Init(nsIContent*      aContent,
                      nsIFrame*        aParent,
                      nsIFrame*        aPrevInFlow)
 {
   nsresult  rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
 
   // Create the menu bar listener.
@@ -152,36 +117,31 @@ nsMenuBarFrame::Init(nsIContent*      aC
 
   target->AddEventListener(NS_LITERAL_STRING("mousedown"), (nsIDOMMouseListener*)mMenuBarListener, PR_FALSE);   
   target->AddEventListener(NS_LITERAL_STRING("blur"), (nsIDOMFocusListener*)mMenuBarListener, PR_TRUE);   
 
   return rv;
 }
 
 NS_IMETHODIMP
-nsMenuBarFrame::IsOpen()
-{
-  PRBool isOpen = PR_FALSE;
-  if(mCurrentMenu) {
-    mCurrentMenu->MenuIsOpen(isOpen);
-    if (isOpen) {
-      return PR_TRUE;
-    }
-  }
-  return PR_FALSE;
-}
-
-
-NS_IMETHODIMP
 nsMenuBarFrame::SetActive(PRBool aActiveFlag)
 {
   // If the activity is not changed, there is nothing to do.
   if (mIsActive == aActiveFlag)
     return NS_OK;
 
+  if (!aActiveFlag) {
+    // if there is a request to deactivate the menu bar, check to see whether
+    // there is a menu popup open for the menu bar. In this case, don't
+    // deactivate the menu bar.
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm && pm->IsPopupOpenForMenuParent(this))
+      return NS_OK;
+  }
+
   mIsActive = aActiveFlag;
   if (mIsActive) {
     InstallKeyboardNavigator();
   }
   else {
     RemoveKeyboardNavigator();
   }
   
@@ -234,65 +194,68 @@ nsMenuBarFrame::SetActive(PRBool aActive
     if (!mIsActive) {
       mCaretWasVisible = PR_FALSE;
     }
   } while (0);
 
   NS_NAMED_LITERAL_STRING(active, "DOMMenuBarActive");
   NS_NAMED_LITERAL_STRING(inactive, "DOMMenuBarInactive");
   
-  FireDOMEventSynch(mIsActive ? active : inactive);
+  FireDOMEvent(mIsActive ? active : inactive, mContent);
 
   return NS_OK;
 }
 
-void
+nsMenuFrame*
 nsMenuBarFrame::ToggleMenuActiveState()
 {
   if (mIsActive) {
     // Deactivate the menu bar
     SetActive(PR_FALSE);
     if (mCurrentMenu) {
-      // Deactivate the menu.
-      mCurrentMenu->OpenMenu(PR_FALSE);
-      mCurrentMenu->SelectMenu(PR_FALSE);
+      nsMenuFrame* closeframe = mCurrentMenu;
+      closeframe->SelectMenu(PR_FALSE);
       mCurrentMenu = nsnull;
+      return closeframe;
     }
   }
   else {
     // if the menu bar is already selected (eg. mouseover), deselect it
     if (mCurrentMenu)
       mCurrentMenu->SelectMenu(PR_FALSE);
     
     // Activate the menu bar
     SetActive(PR_TRUE);
 
     // Set the active menu to be the top left item (e.g., the File menu).
     // We use an attribute called "menuactive" to track the current 
     // active menu.
-    nsIMenuFrame* firstFrame = GetNextMenuItem(nsnull);
+    nsMenuFrame* firstFrame = nsXULPopupManager::GetNextMenuItem(this, nsnull, PR_FALSE);
     if (firstFrame) {
       firstFrame->SelectMenu(PR_TRUE);
       
       // Track this item for keyboard navigation.
       mCurrentMenu = firstFrame;
     }
   }
+
+  return nsnull;
 }
 
-static void GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild,
-                              nsIFrame** aResult)
+static void
+GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild,
+                  nsIFrame** aResult)
 {
   nsIContent* child = nsnull;
   if (aChild)
     child = aChild->GetContent();
   aShell->FrameConstructor()->GetInsertionPoint(aFrame, child, aResult);
 }
 
-nsIMenuFrame*
+nsMenuFrame*
 nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
 {
   PRUint32 charCode;
   aKeyEvent->GetCharCode(&charCode);
 
   // Enumerate over our list of frames.
   nsIFrame* immediateParent = nsnull;
   GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
@@ -300,519 +263,180 @@ nsMenuBarFrame::FindMenuWithShortcut(nsI
     immediateParent = this;
 
   nsIFrame* currFrame = immediateParent->GetFirstChild(nsnull);
 
   while (currFrame) {
     nsIContent* current = currFrame->GetContent();
     
     // See if it's a menu item.
-    if (IsValidItem(current)) {
+    if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, PR_FALSE)) {
       // Get the shortcut attribute.
       nsAutoString shortcutKey;
       current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey);
       if (!shortcutKey.IsEmpty()) {
         // We've got something.
         PRUnichar letter = PRUnichar(charCode); // throw away the high-zero-fill
         if ( shortcutKey.Equals(Substring(&letter, &letter+1),
                                 nsCaseInsensitiveStringComparator()) )  {
           // We match!
-          nsIMenuFrame *menuFrame;
-          if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame))) {
-            menuFrame = nsnull;
-          }
-          return menuFrame;
+          return (currFrame->GetType() == nsGkAtoms::menuFrame) ?
+                 NS_STATIC_CAST(nsMenuFrame *, currFrame) : nsnull;
         }
       }
     }
     currFrame = currFrame->GetNextSibling();
   }
 
   // didn't find a matching menu item
 #ifdef XP_WIN
   // behavior on Windows - this item is on the menu bar, beep and deactivate the menu bar
   if (mIsActive) {
     nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
     if (soundInterface)
       soundInterface->Beep();
   }
 
-  DismissChain();
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm)
+    pm->Rollup();
+
+  SetCurrentMenuItem(nsnull);
+  SetActive(PR_FALSE);
+
 #endif  // #ifdef XP_WIN
 
   return nsnull;
 }
 
-NS_IMETHODIMP 
-nsMenuBarFrame::ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag)
-{
-  if (mCurrentMenu) {
-    PRBool isOpen = PR_FALSE;
-    mCurrentMenu->MenuIsOpen(isOpen);
-    if (isOpen) {
-      // No way this applies to us. Give it to our child.
-      mCurrentMenu->ShortcutNavigation(aKeyEvent, aHandledFlag);
-      return NS_OK;
-    }
-  }
-
-  // This applies to us. Let's see if one of the shortcuts applies
-  nsIMenuFrame* result = FindMenuWithShortcut(aKeyEvent);
-  if (result) {
-    // We got one!
-    nsWeakFrame weakFrame(this);
-    nsIFrame* frame = nsnull;
-    CallQueryInterface(result, &frame);
-    nsWeakFrame weakResult(frame);
-    aHandledFlag = PR_TRUE;
-    SetActive(PR_TRUE);
-    if (weakFrame.IsAlive()) {
-      SetCurrentMenuItem(result);
-    }
-    if (weakResult.IsAlive()) {
-      result->OpenMenu(PR_TRUE);
-      if (weakResult.IsAlive()) {
-        result->SelectFirstItem();
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuBarFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
-{
-  nsNavigationDirection theDirection;
-  NS_DIRECTION_FROM_KEY_CODE(theDirection, aKeyCode);
-  if (!mCurrentMenu)
-    return NS_OK;
-
-  nsWeakFrame weakFrame(this);
-  PRBool isContainer = PR_FALSE;
-  PRBool isOpen = PR_FALSE;
-  mCurrentMenu->MenuIsContainer(isContainer);
-  mCurrentMenu->MenuIsOpen(isOpen);
-
-  aHandledFlag = PR_FALSE;
-  
-  if (isOpen) {
-    // Let the child menu try to handle it.
-    mCurrentMenu->KeyboardNavigation(aKeyCode, aHandledFlag);
-  }
-
-  if (aHandledFlag)
-    return NS_OK;
-
-  if NS_DIRECTION_IS_INLINE(theDirection) {
-    
-    nsIMenuFrame* nextItem = (theDirection == eNavigationDirection_End) ?
-                             GetNextMenuItem(mCurrentMenu) : 
-                             GetPreviousMenuItem(mCurrentMenu);
-
-    nsIFrame* nextFrame = nsnull;
-    if (nextItem) {
-      CallQueryInterface(nextItem, &nextFrame);
-    }
-    nsWeakFrame weakNext(nextFrame);
-    SetCurrentMenuItem(nextItem);
-    if (weakNext.IsAlive()) {
-      PRBool nextIsOpen;
-      nextItem->MenuIsOpen(nextIsOpen);
-      if (nextIsOpen) {
-        // Select the first item.
-        nextItem->SelectFirstItem();
-      }
-    }
-  }
-  else if NS_DIRECTION_IS_BLOCK(theDirection) {
-    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    nsIFrame* frame = nsnull;
-    CallQueryInterface(mCurrentMenu, &frame);
-    nsWeakFrame weakCurrentMenu(frame);
-    nsIMenuFrame* currentMenu = mCurrentMenu;
-     // Open the menu and select its first item.
-    currentMenu->OpenMenu(PR_TRUE);
-    if (weakCurrentMenu.IsAlive()) {
-      currentMenu->SelectFirstItem();
-    }
-  }
-
-  return NS_OK;
-}
-
-/* virtual */ nsIMenuFrame*
-nsMenuBarFrame::GetNextMenuItem(nsIMenuFrame* aStart)
-{
-  nsIFrame* immediateParent = nsnull;
-  GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
-  if (!immediateParent)
-    immediateParent = this;
-
-  nsIFrame* currFrame = nsnull;
-  nsIFrame* startFrame = nsnull;
-  if (aStart) {
-    aStart->QueryInterface(NS_GET_IID(nsIFrame), (void**)&currFrame); 
-    if (currFrame) {
-      startFrame = currFrame;
-      currFrame = currFrame->GetNextSibling();
-    }
-  }
-  else 
-    currFrame = immediateParent->GetFirstChild(nsnull);
-
-  while (currFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-    currFrame = currFrame->GetNextSibling();
-  }
-
-  currFrame = immediateParent->GetFirstChild(nsnull);
-
-  // Still don't have anything. Try cycling from the beginning.
-  while (currFrame && currFrame != startFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-
-    currFrame = currFrame->GetNextSibling();
-  }
-
-  // No luck. Just return our start value.
-  return aStart;
-}
-
-/* virtual */ nsIMenuFrame*
-nsMenuBarFrame::GetPreviousMenuItem(nsIMenuFrame* aStart)
-{
-  nsIFrame* immediateParent = nsnull;
-  GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
-  if (!immediateParent)
-    immediateParent = this;
-
-  nsFrameList frames(immediateParent->GetFirstChild(nsnull));
-                              
-  nsIFrame* currFrame = nsnull;
-  nsIFrame* startFrame = nsnull;
-  if (aStart) {
-    aStart->QueryInterface(NS_GET_IID(nsIFrame), (void**)&currFrame);
-    if (currFrame) {
-      startFrame = currFrame;
-      currFrame = frames.GetPrevSiblingFor(currFrame);
-    }
-  }
-  else currFrame = frames.LastChild();
-
-  while (currFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-    currFrame = frames.GetPrevSiblingFor(currFrame);
-  }
-
-  currFrame = frames.LastChild();
-
-  // Still don't have anything. Try cycling from the end.
-  while (currFrame && currFrame != startFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-
-    currFrame = frames.GetPrevSiblingFor(currFrame);
-  }
-
-  // No luck. Just return our start value.
-  return aStart;
-}
-
-/* virtual */ nsIMenuFrame*
+/* virtual */ nsMenuFrame*
 nsMenuBarFrame::GetCurrentMenuItem()
 {
   return mCurrentMenu;
 }
 
-
-NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
+NS_IMETHODIMP
+nsMenuBarFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
 {
   if (mCurrentMenu == aMenuItem)
     return NS_OK;
 
-  PRBool wasOpen = PR_FALSE;
-  
-  // check if there's an open context menu, we ignore this
-  if (nsMenuFrame::GetContextMenu())
-    return NS_OK;
-
   nsWeakFrame weakFrame(this);
+  if (mCurrentMenu)
+    mCurrentMenu->SelectMenu(PR_FALSE);
 
-  // Unset the current child.
-  if (mCurrentMenu) {
-    nsIFrame* frame = nsnull;
-    CallQueryInterface(mCurrentMenu, &frame);
-    nsWeakFrame weakCurrentMenu(frame);
-    nsIMenuFrame* currentMenu = mCurrentMenu;
-    currentMenu->MenuIsOpen(wasOpen);
-    currentMenu->SelectMenu(PR_FALSE);
-    if (wasOpen && weakCurrentMenu.IsAlive()) {
-      currentMenu->OpenMenu(PR_FALSE);
-    }
-  }
-
-  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-
-
-  // Set the new child.
-  if (aMenuItem) {
-    nsIFrame* newMenu = nsnull;
-    CallQueryInterface(aMenuItem, &newMenu);
-    nsWeakFrame weakNewMenu(newMenu);
+  if (aMenuItem)
     aMenuItem->SelectMenu(PR_TRUE);
-    NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
-    aMenuItem->MarkAsGenerated(); // Have the menu building. Get it ready to be shown.
-    NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
-
-    PRBool isDisabled = PR_FALSE;
-    aMenuItem->MenuIsDisabled(isDisabled);
-    if (wasOpen&&!isDisabled)
-      aMenuItem->OpenMenu(PR_TRUE);
-    ClearRecentlyRolledUp();
-  }
 
   NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
   mCurrentMenu = aMenuItem;
 
   return NS_OK;
 }
 
-
-NS_IMETHODIMP 
-nsMenuBarFrame::Escape(PRBool& aHandledFlag)
+void
+nsMenuBarFrame::CurrentMenuIsBeingDestroyed()
 {
-  if (!mCurrentMenu)
-    return NS_OK;
-
-  nsWeakFrame weakFrame(this);
-  // See if our menu is open.
-  PRBool isOpen = PR_FALSE;
-  mCurrentMenu->MenuIsOpen(isOpen);
-  if (isOpen) {
-    // Let the child menu handle this.
-    aHandledFlag = PR_FALSE;
-    mCurrentMenu->Escape(aHandledFlag);
-    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    if (!aHandledFlag) {
-      // Close up this menu but keep our current menu item
-      // designation.
-      mCurrentMenu->OpenMenu(PR_FALSE);
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    }
-    return NS_OK;
-  }
-
-  // Clear our current menu item if we've got one.
-  SetCurrentMenuItem(nsnull);
-  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-
-  SetActive(PR_FALSE);
-
-  // Clear out our dismissal listener
-  nsMenuDismissalListener::Shutdown();
-  return NS_OK;
-}
-
-NS_IMETHODIMP 
-nsMenuBarFrame::Enter()
-{
-  if (!mCurrentMenu)
-    return NS_OK;
-
-  ClearRecentlyRolledUp();
-
-  // See if our menu is open.
-  PRBool isOpen = PR_FALSE;
-  mCurrentMenu->MenuIsOpen(isOpen);
-  if (isOpen) {
-    // Let the child menu handle this.
-    mCurrentMenu->Enter();
-    return NS_OK;
-  }
-
-  // It's us. Open the current menu.
-  mCurrentMenu->OpenMenu(PR_TRUE);
-  mCurrentMenu->SelectFirstItem();
-
-  return NS_OK;
+  mCurrentMenu->SelectMenu(PR_FALSE);
+  mCurrentMenu = nsnull;
 }
 
 NS_IMETHODIMP
-nsMenuBarFrame::ClearRecentlyRolledUp()
-{
-  // We're no longer in danger of popping down a menu from the same 
-  // click on the menubar, which was supposed to toggle the menu closed
-  mRecentRollupMenu = nsnull;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuBarFrame::RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp)
+nsMenuBarFrame::ChangeMenuItem(nsMenuFrame* aMenuItem,
+                               PRBool aSelectFirstItem)
 {
-  // Don't let a click reopen a menu that was just rolled up
-  // from the same click. Otherwise, the user can't click on
-  // a menubar item to toggle its submenu closed.
-  *aJustRolledUp = (mRecentRollupMenu == aMenuFrame);
+  if (mCurrentMenu == aMenuItem)
+    return NS_OK;
 
-  return NS_OK;
-}
+  // check if there's an open context menu, we ignore this
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm && pm->HasContextMenu(nsnull))
+    return NS_OK;
 
-NS_IMETHODIMP
-nsMenuBarFrame::HideChain()
-{
-  // XXX hack if a context menu is active, do an Escape, which is
-  // currently bugged and destroys everything.  We need to close
-  // the context menu first, otherwise SetCurrentMenuItem above
-  // would get blocked.
-  if (nsMenuFrame::GetContextMenu()) {
-    PRBool dummy;
-    mCurrentMenu->Escape(dummy);
+  // Unset the current child.
+  PRBool wasOpen = PR_FALSE;
+  if (mCurrentMenu) {
+    wasOpen = mCurrentMenu->IsOpen();
+    mCurrentMenu->SelectMenu(PR_FALSE);
+    if (wasOpen) {
+      nsMenuPopupFrame* popupFrame = mCurrentMenu->GetPopup();
+      if (popupFrame)
+        pm->HidePopup(popupFrame->GetContent(), PR_FALSE, PR_FALSE, PR_TRUE);
+    }
   }
 
-  // Stop capturing rollups
-  // (must do this during Hide, which happens before the menu item is executed,
-  // since this reinstates normal event handling.)
-  nsMenuDismissalListener::Shutdown();
+  // set to null first in case the IsAlive check below returns false
+  mCurrentMenu = nsnull;
 
-  ClearRecentlyRolledUp();
-  if (mCurrentMenu) {
-    mCurrentMenu->ActivateMenu(PR_FALSE);
-    mCurrentMenu->SelectMenu(PR_FALSE);
-    mRecentRollupMenu = mCurrentMenu;
-  }
-
-  if (mIsActive) {
-    ToggleMenuActiveState();
+  // Set the new child.
+  if (aMenuItem) {
+    nsCOMPtr<nsIContent> content = aMenuItem->GetContent();
+    nsWeakFrame weakNewMenu(aMenuItem);
+    aMenuItem->SelectMenu(PR_TRUE);
+    NS_ENSURE_TRUE(weakNewMenu.IsAlive(), NS_OK);
+    mCurrentMenu = aMenuItem;
+    if (wasOpen && !aMenuItem->IsDisabled())
+      pm->ShowMenu(content, aSelectFirstItem, PR_TRUE);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsMenuBarFrame::DismissChain()
+nsMenuFrame*
+nsMenuBarFrame::Enter()
 {
-  // Stop capturing rollups
-  nsMenuDismissalListener::Shutdown();
-  nsWeakFrame weakFrame(this);
-  SetCurrentMenuItem(nsnull);
-  if (weakFrame.IsAlive()) {
-    SetActive(PR_FALSE);
-  }
-  return NS_OK;
+  if (!mCurrentMenu)
+    return nsnull;
+
+  if (mCurrentMenu->IsOpen())
+    return mCurrentMenu->Enter();
+
+  return mCurrentMenu;
 }
 
-
-NS_IMETHODIMP
-nsMenuBarFrame::KillPendingTimers ( )
+PRBool
+nsMenuBarFrame::MenuClosed()
 {
-  return NS_OK;
-
-} // KillPendingTimers
-
-
-NS_IMETHODIMP
-nsMenuBarFrame::GetWidget(nsIWidget **aWidget)
-{
-  // (pinkerton/hyatt)
-  // since the menubar is a menuparent but not a menuItem, the win32 rollup code
-  // would erroneously add the entire top-level window to the widget list built up for
-  // determining if a click is in a submenu's menu chain. To get around this, we just 
-  // don't let the menubar have a widget. Things seem to work because the dismissal
-  // listener is registered when a new menu is popped up, which is the only real reason
-  // why we need a widget at all.
-  *aWidget = nsnull;
-  return NS_OK;
+  SetActive(PR_FALSE);
+  if (!mIsActive && mCurrentMenu) {
+    mCurrentMenu->SelectMenu(PR_FALSE);
+    mCurrentMenu = nsnull;
+    return PR_TRUE;
+  }
+  return PR_FALSE;
 }
 
-NS_IMETHODIMP
+void
 nsMenuBarFrame::InstallKeyboardNavigator()
 {
-  if (mKeyboardNavigator)
-    return NS_OK;
-
-  mKeyboardNavigator = new nsMenuListener(this);
-  NS_IF_ADDREF(mKeyboardNavigator);
-
-  mTarget->AddEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE); 
-  mTarget->AddEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);  
-  mTarget->AddEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);   
-
-  nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_TRUE);
-
-  return NS_OK;
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm)
+    pm->SetActiveMenuBar(this, PR_TRUE);
 }
 
-NS_IMETHODIMP
+void
 nsMenuBarFrame::RemoveKeyboardNavigator()
 {
-  if (!mKeyboardNavigator || mIsActive)
-    return NS_OK;
-
-  mTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
-  mTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
-  mTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
-
-  NS_IF_RELEASE(mKeyboardNavigator);
-
-  nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_FALSE);
-
-  return NS_OK;
-}
-
-// helpers ///////////////////////////////////////////////////////////
-
-PRBool 
-nsMenuBarFrame::IsValidItem(nsIContent* aContent)
-{
-  nsIAtom *tag = aContent->Tag();
-
-  return ((tag == nsGkAtoms::menu ||
-           tag == nsGkAtoms::menuitem) &&
-          !IsDisabled(aContent));
-}
-
-PRBool 
-nsMenuBarFrame::IsDisabled(nsIContent* aContent)
-{
-  return aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
-                               nsGkAtoms::_true, eCaseMatters);
+  if (!mIsActive) {
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm)
+      pm->SetActiveMenuBar(this, PR_FALSE);
+  }
 }
 
 void
 nsMenuBarFrame::Destroy()
 {
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm)
+    pm->SetActiveMenuBar(this, PR_FALSE);
+
   mTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE); 
   mTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);  
   mTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mMenuBarListener, PR_FALSE);
 
   mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), (nsIDOMMouseListener*)mMenuBarListener, PR_FALSE);
   mTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), (nsIDOMFocusListener*)mMenuBarListener, PR_TRUE);
 
   NS_IF_RELEASE(mMenuBarListener);
 
   nsBoxFrame::Destroy();
 }
-
--- a/layout/xul/base/src/nsMenuBarFrame.h
+++ b/layout/xul/base/src/nsMenuBarFrame.h
@@ -44,96 +44,73 @@
 
 #ifndef nsMenuBarFrame_h__
 #define nsMenuBarFrame_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsCOMPtr.h"
 #include "nsBoxFrame.h"
+#include "nsMenuFrame.h"
 #include "nsMenuBarListener.h"
-#include "nsMenuListener.h"
 #include "nsIMenuParent.h"
 #include "nsIWidget.h"
 
 class nsIContent;
-class nsIMenuFrame;
 
 nsIFrame* NS_NewMenuBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 class nsMenuBarFrame : public nsBoxFrame, public nsIMenuParent
 {
 public:
   nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext);
-  virtual ~nsMenuBarFrame();
-
-  NS_DECL_ISUPPORTS
 
   // nsIMenuParentInterface
-  virtual nsIMenuFrame* GetCurrentMenuItem();
-  NS_IMETHOD SetCurrentMenuItem(nsIMenuFrame* aMenuItem);
-  virtual nsIMenuFrame* GetNextMenuItem(nsIMenuFrame* aStart);
-  virtual nsIMenuFrame* GetPreviousMenuItem(nsIMenuFrame* aStart);
+  virtual nsMenuFrame* GetCurrentMenuItem();
+  NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem);
+  virtual void CurrentMenuIsBeingDestroyed();
+  NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, PRBool aSelectFirstItem);
+
   NS_IMETHOD SetActive(PRBool aActiveFlag); 
-  NS_IMETHOD GetIsActive(PRBool& isActive) { isActive = IsActive(); return NS_OK; }
-  NS_IMETHOD IsMenuBar(PRBool& isMenuBar) { isMenuBar = PR_TRUE; return NS_OK; }
-  NS_IMETHOD ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks) \
-    {aConsumeOutsideClicks = PR_FALSE; return NS_OK;}
-  NS_IMETHOD ClearRecentlyRolledUp();
-  NS_IMETHOD RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp);
-
-  NS_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) { return NS_OK; }
-  NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) { aIsContextMenu = PR_FALSE; return NS_OK; }
-
-  NS_IMETHOD GetParentPopup(nsIMenuParent** aResult) { *aResult = nsnull;
-                                                       return NS_OK;}
 
-  NS_IMETHOD IsActive() { return mIsActive; }
-
-  NS_IMETHOD IsOpen();
-  NS_IMETHOD KillPendingTimers();
-  NS_IMETHOD CancelPendingTimers() { return NS_OK; }
-
-  // Closes up the chain of open cascaded menus.
-  NS_IMETHOD DismissChain();
+  virtual PRBool IsMenuBar() { return PR_TRUE; }
+  virtual PRBool IsContextMenu() { return PR_FALSE; }
+  virtual PRBool IsActive() { return mIsActive; }
+  virtual PRBool IsMenu() { return PR_FALSE; }
+  virtual PRBool IsOpen() { return PR_TRUE; } // menubars are considered always open
 
-  // Hides the chain of cascaded menus without closing them up.
-  NS_IMETHOD HideChain();
+  PRBool IsMenuOpen() { return mCurrentMenu && mCurrentMenu->IsOpen(); }
 
-  NS_IMETHOD InstallKeyboardNavigator();
-  NS_IMETHOD RemoveKeyboardNavigator();
-
-  NS_IMETHOD GetWidget(nsIWidget **aWidget);
-  // The dismissal listener gets created and attached to the window.
-  NS_IMETHOD AttachedDismissalListener() { return NS_OK; }
+  void InstallKeyboardNavigator();
+  void RemoveKeyboardNavigator();
 
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
 
   virtual void Destroy();
 
+  virtual nsIAtom* GetType() const { return nsGkAtoms::menuBarFrame; }
+
 // Non-interface helpers
 
-  // Called when a menu on the menu bar is clicked on.
-  void ToggleMenuActiveState();
-  
-  // Used to move up, down, left, and right in menus.
-  NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag);
-  NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag);
-  // Called when the ESC key is held down to close levels of menus.
-  NS_IMETHOD Escape(PRBool& aHandledFlag);
-  // Called to execute a menu item.
-  NS_IMETHOD Enter();
+  // Called when a menu on the menu bar is clicked on. Returns a menu if one
+  // needs to be closed.
+  nsMenuFrame* ToggleMenuActiveState();
+
+  // indicate that a menu on the menubar was closed. Returns true if the caller
+  // may deselect the menuitem.
+  virtual PRBool MenuClosed();
+
+  // Called when Enter is pressed while the menubar is focused. If the current
+  // menu is open, let the child handle the key.
+  nsMenuFrame* Enter();
 
   // Used to handle ALT+key combos
-  nsIMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent);
-
-  PRBool IsValidItem(nsIContent* aContent);
-  PRBool IsDisabled(nsIContent* aContent);
+  nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent);
 
   virtual PRBool IsFrameOfType(PRUint32 aFlags) const
   {
     // Override bogus IsFrameOfType in nsBoxFrame.
     if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced))
       return PR_FALSE;
     return nsBoxFrame::IsFrameOfType(aFlags);
   }
@@ -142,24 +119,21 @@ public:
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
       return MakeFrameName(NS_LITERAL_STRING("MenuBar"), aResult);
   }
 #endif
 
 protected:
   nsMenuBarListener* mMenuBarListener; // The listener that tells us about key and mouse events.
-  nsMenuListener* mKeyboardNavigator;
 
   PRBool mIsActive; // Whether or not the menu bar is active (a menu item is highlighted or shown).
-  nsIMenuFrame* mCurrentMenu; // The current menu that is active.
-
-  // Can contain a menu that was rolled up via nsIMenuDismissalListener::Rollup()
-  // if nothing has happened since the last click. Otherwise, contains nsnull.
-  nsIMenuFrame* mRecentRollupMenu; 
+  // The current menu that is active (highlighted), which may not be open. This will
+  // be null if no menu is active.
+  nsMenuFrame* mCurrentMenu;
 
   nsIDOMEventTarget* mTarget;
 
 private:
   PRBool mCaretWasVisible;
 
 }; // class nsMenuBarFrame
 
--- a/layout/xul/base/src/nsMenuBarListener.cpp
+++ b/layout/xul/base/src/nsMenuBarListener.cpp
@@ -35,16 +35,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsMenuBarListener.h"
 #include "nsMenuBarFrame.h"
+#include "nsMenuPopupFrame.h"
 #include "nsIDOMKeyListener.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsIDOMNSEvent.h"
 #include "nsGUIEvent.h"
 
 // Drag & Drop, Clipboard
@@ -126,16 +127,28 @@ void nsMenuBarListener::InitAccessKey()
     mAccessKeyMask = MODIFIER_ALT;
   else if (mAccessKey == nsIDOMKeyEvent::DOM_VK_META)
     mAccessKeyMask = MODIFIER_META;
 
   mAccessKeyFocuses =
     nsContentUtils::GetBoolPref("ui.key.menuAccessKeyFocuses");
 }
 
+void
+nsMenuBarListener::ToggleMenuActiveState()
+{
+  nsMenuFrame* closemenu = mMenuBarFrame->ToggleMenuActiveState();
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm && closemenu) {
+    nsMenuPopupFrame* popupFrame = closemenu->GetPopup();
+    if (popupFrame)
+      pm->HidePopup(popupFrame->GetContent(), PR_FALSE, PR_FALSE, PR_TRUE);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////
 nsresult
 nsMenuBarListener::KeyUp(nsIDOMEvent* aKeyEvent)
 {  
   InitAccessKey();
 
   //handlers shouldn't be triggered by non-trusted events.
   nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
@@ -156,37 +169,35 @@ nsMenuBarListener::KeyUp(nsIDOMEvent* aK
     nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
     PRUint32 theChar;
     keyEvent->GetKeyCode(&theChar);
 
     if (mAccessKeyDown && (PRInt32)theChar == mAccessKey)
     {
       // The access key was down and is now up, and no other
       // keys were pressed in between.
-      mMenuBarFrame->ToggleMenuActiveState();
+      ToggleMenuActiveState();
     }
     mAccessKeyDown = PR_FALSE; 
 
     PRBool active = mMenuBarFrame->IsActive();
     if (active) {
       aKeyEvent->StopPropagation();
       aKeyEvent->PreventDefault();
-      return NS_ERROR_BASE; // I am consuming event
+      return NS_OK; // I am consuming event
     }
   }
   
   return NS_OK; // means I am NOT consuming event
 }
 
 ////////////////////////////////////////////////////////////////////////
 nsresult
 nsMenuBarListener::KeyPress(nsIDOMEvent* aKeyEvent)
 {
-  mMenuBarFrame->ClearRecentlyRolledUp();
-
   // if event has already been handled, bail
   nsCOMPtr<nsIDOMNSUIEvent> uiEvent ( do_QueryInterface(aKeyEvent) );
   if ( uiEvent ) {
     PRBool eventHandled = PR_FALSE;
     uiEvent->GetPreventDefault ( &eventHandled );
     if ( eventHandled )
       return NS_OK;       // don't consume event
   }
@@ -224,42 +235,42 @@ nsMenuBarListener::KeyPress(nsIDOMEvent*
 
       // If charCode == 0, then it is not a printable character.
       // Don't attempt to handle accesskey for non-printable characters.
       if (IsAccessKeyPressed(keyEvent) && charCode)
       {
         // Do shortcut navigation.
         // A letter was pressed. We want to see if a shortcut gets matched. If
         // so, we'll know the menu got activated.
-        PRBool active = PR_FALSE;
-        mMenuBarFrame->ShortcutNavigation(keyEvent, active);
-
-        if (active) {
+        nsMenuFrame* result = mMenuBarFrame->FindMenuWithShortcut(keyEvent);
+        if (result) {
+          mMenuBarFrame->SetActive(PR_TRUE);
+          result->OpenMenu(PR_TRUE);
           aKeyEvent->StopPropagation();
           aKeyEvent->PreventDefault();
-
-          retVal = NS_ERROR_BASE;       // I am consuming event
+          retVal = NS_OK;       // I am consuming event
         }
       }    
 #if !defined(XP_MAC) && !defined(XP_MACOSX)
       // Also need to handle F10 specially on Non-Mac platform.
       else if (keyCode == NS_VK_F10) {
         if ((GetModifiers(keyEvent) & ~MODIFIER_CONTROL) == 0) {
           // The F10 key just went down by itself or with ctrl pressed.
           // In Windows, both of these activate the menu bar.
-          mMenuBarFrame->ToggleMenuActiveState();
+          ToggleMenuActiveState();
 
           aKeyEvent->StopPropagation();
           aKeyEvent->PreventDefault();
-          return NS_ERROR_BASE; // consume the event
+          return NS_OK; // consume the event
         }
       }
 #endif   // !XP_MAC && !XP_MACOSX
     } 
   }
+
   return retVal;
 }
 
 PRBool
 nsMenuBarListener::IsAccessKeyPressed(nsIDOMKeyEvent* aKeyEvent)
 {
   InitAccessKey();
   // No other modifiers are allowed to be down except for Shift.
@@ -344,46 +355,38 @@ nsMenuBarListener::Focus(nsIDOMEvent* aE
 {
   return NS_OK; // means I am NOT consuming event
 }
 
 ////////////////////////////////////////////////////////////////////////
 nsresult
 nsMenuBarListener::Blur(nsIDOMEvent* aEvent)
 {
-  if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
-    mMenuBarFrame->ToggleMenuActiveState();
-    PRBool handled;
-    mMenuBarFrame->Escape(handled);
+  if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive()) {
+    ToggleMenuActiveState();
     mAccessKeyDown = PR_FALSE;
   }
   return NS_OK; // means I am NOT consuming event
 }
   
 ////////////////////////////////////////////////////////////////////////
 nsresult 
 nsMenuBarListener::MouseDown(nsIDOMEvent* aMouseEvent)
 {
-  if (!mMenuBarFrame->IsOpen() && mMenuBarFrame->IsActive()) {
-    mMenuBarFrame->ToggleMenuActiveState();
-    PRBool handled;
-    mMenuBarFrame->Escape(handled);
-  }
-
+  if (!mMenuBarFrame->IsMenuOpen() && mMenuBarFrame->IsActive())
+    ToggleMenuActiveState();
   mAccessKeyDown = PR_FALSE;
 
   return NS_OK; // means I am NOT consuming event
 }
 
 ////////////////////////////////////////////////////////////////////////
 nsresult 
 nsMenuBarListener::MouseUp(nsIDOMEvent* aMouseEvent)
 {
-  mMenuBarFrame->ClearRecentlyRolledUp();
-
   return NS_OK; // means I am NOT consuming event
 }
 
 nsresult 
 nsMenuBarListener::MouseClick(nsIDOMEvent* aMouseEvent)
 {
   return NS_OK; // means I am NOT consuming event
 }
--- a/layout/xul/base/src/nsMenuBarListener.h
+++ b/layout/xul/base/src/nsMenuBarListener.h
@@ -82,16 +82,20 @@ public:
 
   static PRBool IsAccessKeyPressed(nsIDOMKeyEvent* event);
 
 protected:
   static void InitAccessKey();
 
   static PRUint32 GetModifiers(nsIDOMKeyEvent* event);
 
+  // This should only be called by the nsMenuBarListener during event dispatch,
+  // thus ensuring that this doesn't get destroyed during the process.
+  void ToggleMenuActiveState();
+
   nsMenuBarFrame* mMenuBarFrame; // The menu bar object.
   PRBool mAccessKeyDown;         // Whether or not the ALT key is currently down.
   static PRBool mAccessKeyFocuses; // Does the access key by itself focus the menubar?
   static PRInt32 mAccessKey;     // See nsIDOMKeyEvent.h for sample values
   static PRUint32 mAccessKeyMask;// Modifier mask for the access key
 };
 
 
--- a/layout/xul/base/src/nsMenuBoxObject.cpp
+++ b/layout/xul/base/src/nsMenuBoxObject.cpp
@@ -34,21 +34,22 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "nsISupportsUtils.h"
 #include "nsIMenuBoxObject.h"
 #include "nsBoxObject.h"
 #include "nsIPresShell.h"
-#include "nsIMenuFrame.h"
 #include "nsIFrame.h"
 #include "nsGUIEvent.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsMenuBarListener.h"
+#include "nsMenuFrame.h"
+#include "nsMenuPopupFrame.h"
 #include "nsPopupSetFrame.h"
 
 class nsMenuBoxObject : public nsIMenuBoxObject, public nsBoxObject
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMENUBOXOBJECT
 
@@ -83,98 +84,97 @@ nsMenuBoxObject::nsMenuBoxObject()
 nsMenuBoxObject::~nsMenuBoxObject()
 {
   /* destructor code */
 }
 
 /* void openMenu (in boolean openFlag); */
 NS_IMETHODIMP nsMenuBoxObject::OpenMenu(PRBool aOpenFlag)
 {
-  nsIFrame* frame = GetFrame(PR_FALSE);
-  if (!frame)
-    return NS_OK;
-
-  if (!nsPopupSetFrame::MayOpenPopup(frame))
-    return NS_OK;
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm) {
+    nsIFrame* frame = GetFrame(PR_FALSE);
+    if (frame) {
+      if (aOpenFlag) {
+        nsCOMPtr<nsIContent> content = mContent;
+        pm->ShowMenu(content, PR_FALSE, PR_FALSE);
+      }
+      else {
+        if (frame->GetType() == nsGkAtoms::menuFrame) {
+          nsMenuPopupFrame* popupFrame = (NS_STATIC_CAST(nsMenuFrame *, frame))->GetPopup();
+          if (popupFrame)
+            pm->HidePopup(popupFrame->GetContent(), PR_FALSE, PR_TRUE, PR_FALSE);
+        }
+      }
+    }
+  }
 
-  nsIMenuFrame* menuFrame;
-  CallQueryInterface(frame, &menuFrame);
-  if (!menuFrame)
-    return NS_OK;
-
-  return menuFrame->OpenMenu(aOpenFlag);
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsMenuBoxObject::GetActiveChild(nsIDOMElement** aResult)
 {
   *aResult = nsnull;
   nsIFrame* frame = GetFrame(PR_FALSE);
-  if (!frame)
-    return NS_OK;
-
-  nsIMenuFrame* menuFrame;
-  CallQueryInterface(frame, &menuFrame);
-  if (menuFrame)
-    menuFrame->GetActiveChild(aResult);
+  if (frame && frame->GetType() == nsGkAtoms::menuFrame)
+    return NS_STATIC_CAST(nsMenuFrame *, frame)->GetActiveChild(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsMenuBoxObject::SetActiveChild(nsIDOMElement* aResult)
 {
   nsIFrame* frame = GetFrame(PR_FALSE);
-  if (!frame)
-    return NS_OK;
-
-  nsIMenuFrame* menuFrame;
-  CallQueryInterface(frame, &menuFrame);
-  if (menuFrame) {
-    menuFrame->MarkAsGenerated();
-    menuFrame->SetActiveChild(aResult);
-  }
+  if (frame && frame->GetType() == nsGkAtoms::menuFrame)
+    return NS_STATIC_CAST(nsMenuFrame *, frame)->SetActiveChild(aResult);
   return NS_OK;
 }
 
 /* boolean handleKeyPress (in nsIDOMKeyEvent keyEvent); */
 NS_IMETHODIMP nsMenuBoxObject::HandleKeyPress(nsIDOMKeyEvent* aKeyEvent, PRBool* aHandledFlag)
 {
   *aHandledFlag = PR_FALSE;
   NS_ENSURE_ARG(aKeyEvent);
 
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (!pm)
+    return NS_OK;
+
   // if event has already been handled, bail
   nsCOMPtr<nsIDOMNSUIEvent> uiEvent(do_QueryInterface(aKeyEvent));
   if (!uiEvent)
     return NS_OK;
 
   PRBool eventHandled = PR_FALSE;
   uiEvent->GetPreventDefault(&eventHandled);
   if (eventHandled)
     return NS_OK;
 
   if (nsMenuBarListener::IsAccessKeyPressed(aKeyEvent))
     return NS_OK;
 
   nsIFrame* frame = GetFrame(PR_FALSE);
-  if (!frame)
+  if (!frame || frame->GetType() != nsGkAtoms::menuFrame)
     return NS_OK;
 
-  nsIMenuFrame* menuFrame;
-  CallQueryInterface(frame, &menuFrame);
-  if (!menuFrame)
+  nsMenuPopupFrame* popupFrame = NS_STATIC_CAST(nsMenuFrame *, frame)->GetPopup();
+  if (!popupFrame)
     return NS_OK;
 
   PRUint32 keyCode;
   aKeyEvent->GetKeyCode(&keyCode);
   switch (keyCode) {
     case NS_VK_UP:
     case NS_VK_DOWN:
     case NS_VK_HOME:
     case NS_VK_END:
-      return menuFrame->KeyboardNavigation(keyCode, *aHandledFlag);
+      *aHandledFlag = pm->HandleKeyboardNavigation(keyCode);
+      return NS_OK;
     default:
-      return menuFrame->ShortcutNavigation(aKeyEvent, *aHandledFlag);
+      *aHandledFlag = pm->HandleShortcutNavigation(aKeyEvent);
+      return NS_OK;
   }
 }
 
 // Creation Routine ///////////////////////////////////////////////////////////////////////
 
 nsresult
 NS_NewMenuBoxObject(nsIBoxObject** aResult)
 {
deleted file mode 100644
--- a/layout/xul/base/src/nsMenuDismissalListener.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Dean Tessman <dean_tessman@hotmail.com>
- *
- * 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"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsMenuDismissalListener.h"
-#include "nsIMenuParent.h"
-#include "nsMenuFrame.h"
-#include "nsIPopupBoxObject.h"
-#include "nsContentUtils.h"
-
-nsMenuDismissalListener* nsMenuDismissalListener::sInstance = nsnull;
-
-/*
- * nsMenuDismissalListener implementation
- */
-
-NS_IMPL_ADDREF(nsMenuDismissalListener)
-NS_IMPL_RELEASE(nsMenuDismissalListener)
-NS_INTERFACE_MAP_BEGIN(nsMenuDismissalListener)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMouseListener)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
-  NS_INTERFACE_MAP_ENTRY(nsIMenuRollup)
-  NS_INTERFACE_MAP_ENTRY(nsIRollupListener)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMouseListener)
-NS_INTERFACE_MAP_END
-
-
-////////////////////////////////////////////////////////////////////////
-
-nsMenuDismissalListener::nsMenuDismissalListener() :
-  mEnabled(PR_TRUE)
-{
-  mMenuParent = nsnull;
-}
-
-nsMenuDismissalListener::~nsMenuDismissalListener() 
-{
-}
-
-nsMenuDismissalListener*
-nsMenuDismissalListener::GetInstance()
-{
-  if (!sInstance) {
-    sInstance = new nsMenuDismissalListener();
-    NS_IF_ADDREF(sInstance);
-  }
-  return sInstance;
-}
-
-/* static */ void
-nsMenuDismissalListener::Shutdown()
-{
-  if (sInstance) {
-    // XXX temporary code for bug 381426 until bug 279703
-    nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_FALSE);
-
-    sInstance->Unregister();
-    NS_RELEASE(sInstance);
-  }
-}
-
-
-nsIMenuParent*
-nsMenuDismissalListener::GetCurrentMenuParent()
-{
-  return mMenuParent;
-}
-
-void
-nsMenuDismissalListener::SetCurrentMenuParent(nsIMenuParent* aMenuParent)
-{
-  if (aMenuParent == mMenuParent)
-    return;
-
-  mMenuParent = aMenuParent;
-
-  if (!aMenuParent) {
-    Shutdown();
-    return;
-  }
-
-  Unregister();
-  Register();
-}
-
-NS_IMETHODIMP
-nsMenuDismissalListener::Rollup()
-{
-  if (mEnabled) {
-    if (mMenuParent) {
-      AddRef();
-      mMenuParent->HideChain();
-      mMenuParent->DismissChain();
-      Release();
-    }
-    else
-      Shutdown();
-  }
-  return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////
-NS_IMETHODIMP nsMenuDismissalListener::ShouldRollupOnMouseWheelEvent(PRBool *aShouldRollup) 
-{ 
-  *aShouldRollup = PR_FALSE; 
-  return NS_OK;
-}
-
-
-// uggggh.
-
-// a menu should not roll up if activated by a mouse activate message (eg. X-mouse)
-NS_IMETHODIMP nsMenuDismissalListener::ShouldRollupOnMouseActivate(PRBool *aShouldRollup) 
-{ 
-  *aShouldRollup = PR_FALSE; 
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuDismissalListener::GetSubmenuWidgetChain(nsISupportsArray **_retval)
-{
-  NS_NewISupportsArray ( _retval );
-  nsIMenuParent *curr = mMenuParent;
-  while ( curr ) {
-    nsCOMPtr<nsIWidget> widget;
-    curr->GetWidget ( getter_AddRefs(widget) );
-    nsCOMPtr<nsISupports> genericWidget ( do_QueryInterface(widget) );
-    (**_retval).AppendElement ( genericWidget );
-    
-    // move up the chain
-    nsIFrame* currAsFrame = nsnull;
-    if ( NS_SUCCEEDED(CallQueryInterface(curr, &currAsFrame)) ) {
-      nsIMenuFrame *menuFrame = nsnull;
-      nsIFrame *parentFrame = currAsFrame->GetParent();
-      if (parentFrame) {
-        CallQueryInterface(parentFrame, &menuFrame);
-      }
-      if ( menuFrame ) {
-        curr = menuFrame->GetMenuParent ();       // Advance to next parent
-      }
-      else {
-        // we are a menuParent but not a menuFrame. This is probably the case
-        // of the menu bar. Nothing to do here, really.
-        return NS_OK;
-      }
-    }
-    else {
-      // We've run into a menu parent that isn't a frame at all. Not good.
-      NS_WARNING ( "nsIMenuParent that is not a nsIFrame" );
-      return NS_ERROR_FAILURE;
-    }
-  } // foreach parent menu
-  
-  return NS_OK; 
-}
-
-
-void
-nsMenuDismissalListener::Register()
-{
-  if (mWidget)
-    return;
-
-  nsCOMPtr<nsIWidget> widget;
-  mMenuParent->GetWidget(getter_AddRefs(widget));
-  if (!widget) {
-    Shutdown();
-    return;
-  }
-
-  PRBool consumeOutsideClicks = PR_FALSE;
-  mMenuParent->ConsumeOutsideClicks(consumeOutsideClicks);
-  widget->CaptureRollupEvents(this, PR_TRUE, consumeOutsideClicks);
-  mWidget = widget;
-
-  mMenuParent->AttachedDismissalListener();
-}
-
-void
-nsMenuDismissalListener::Unregister()
-{
-  if (mWidget) {
-    mWidget->CaptureRollupEvents(this, PR_FALSE, PR_FALSE);
-    mWidget = nsnull;
-  }
-}
-
-void
-nsMenuDismissalListener::EnableListener(PRBool aEnabled)
-{
-  mEnabled = aEnabled;
-}
-
deleted file mode 100644
--- a/layout/xul/base/src/nsMenuDismissalListener.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Original Author: David W. Hyatt (hyatt@netscape.com)
- *
- * 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"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-#ifndef nsMenuDismissalListener_h__
-#define nsMenuDismissalListener_h__
-
-#include "nsIWidget.h"
-#include "nsIDOMMouseListener.h"
-#include "nsIRollupListener.h"
-#include "nsIMenuRollup.h"
-#include "nsIDOMEventTarget.h"
-#include "nsCOMPtr.h"
-
-class nsIMenuParent;
-
-/**
- * The object responsible for rolling up the open menu popups in cases when
- * it's not done by menu code (for example, when clicking outside a popup
- * on Windows).
- *
- * It is a singleton, which exists as long as there is a menu popup open.
- */
-class nsMenuDismissalListener : public nsIDOMMouseListener,
-                                public nsIMenuRollup,
-                                public nsIRollupListener
-{
-
-public:
-  friend class nsMenuPopupFrame;
-
-  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }
-  NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-  NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-  NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-  NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-  NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-  NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent) { return NS_OK; }
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIROLLUPLISTENER
-  NS_DECL_NSIMENUROLLUP
-
-  void EnableListener(PRBool aEnabled);
-  void SetCurrentMenuParent(nsIMenuParent* aMenuParent);
-  nsIMenuParent* GetCurrentMenuParent();
-
-  static nsMenuDismissalListener* GetInstance();
-  static nsMenuDismissalListener* sInstance;
-  static void Shutdown();
-
-protected:
-  nsMenuDismissalListener();
-  ~nsMenuDismissalListener();
-
-  /**
-   * Registers itself as a rollup event listener for current mMenuParent's
-   * widget. mMenuParent must be non-null.
-   */
-  void Register();
-  
-  void Unregister();
-
-  nsIMenuParent* mMenuParent;
-  nsCOMPtr<nsIWidget> mWidget;
-  PRBool mEnabled;
-};
-
-
-#endif
--- a/layout/xul/base/src/nsMenuFrame.cpp
+++ b/layout/xul/base/src/nsMenuFrame.cpp
@@ -66,28 +66,29 @@
 #include "nsWidgetsCID.h"
 #include "nsBoxLayoutState.h"
 #include "nsIScrollableFrame.h"
 #include "nsIViewManager.h"
 #include "nsBindingManager.h"
 #include "nsIServiceManager.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsIDOMKeyEvent.h"
+#include "nsEventDispatcher.h"
+#include "nsIPrivateDOMEvent.h"
 #include "nsIScrollableView.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIStringBundle.h"
 #include "nsGUIEvent.h"
-#include "nsIEventStateManager.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsIReflowCallback.h"
 
-#define NS_MENU_POPUP_LIST_INDEX   0
+#define NS_MENU_POPUP_LIST_INDEX 0
 
 #if defined(XP_WIN) || defined(XP_OS2)
 #define NSCONTEXTMENUISMOUSEUP 1
 #endif
 
 static PRInt32 gEatMouseMove = PR_FALSE;
 
 static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
@@ -136,56 +137,63 @@ NS_INTERFACE_MAP_BEGIN(nsMenuFrame)
 NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
 
 //
 // nsMenuFrame cntr
 //
 nsMenuFrame::nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext):
   nsBoxFrame(aShell, aContext),
     mIsMenu(PR_FALSE),
-    mMenuOpen(PR_FALSE),
-    mCreateHandlerSucceeded(PR_FALSE),
     mChecked(PR_FALSE),
     mType(eMenuType_Normal),
     mMenuParent(nsnull),
+    mPopupFrame(nsnull),
     mLastPref(-1,-1)
 {
 
 } // cntr
 
 NS_IMETHODIMP
 nsMenuFrame::SetParent(const nsIFrame* aParent)
 {
   nsBoxFrame::SetParent(aParent);
-  const nsIFrame* currFrame = aParent;
-  while (!mMenuParent && currFrame) {
-    // Set our menu parent.
-    CallQueryInterface(NS_CONST_CAST(nsIFrame*, currFrame), &mMenuParent);
+  InitMenuParent(NS_CONST_CAST(nsIFrame *, aParent));
+  return NS_OK;
+}
 
-    currFrame = currFrame->GetParent();
+void
+nsMenuFrame::InitMenuParent(nsIFrame* aParent)
+{
+  while (aParent) {
+    nsIAtom* type = aParent->GetType();
+    if (type == nsGkAtoms::menuPopupFrame) {
+      mMenuParent = NS_STATIC_CAST(nsMenuPopupFrame *, aParent);
+      break;
+    }
+    else if (type == nsGkAtoms::menuBarFrame) {
+      mMenuParent = NS_STATIC_CAST(nsMenuBarFrame *, aParent);
+      break;
+    }
+    aParent = aParent->GetParent();
   }
-
-  return NS_OK;
 }
 
 class nsASyncMenuInitialization : public nsIReflowCallback
 {
 public:
   nsASyncMenuInitialization(nsIFrame* aFrame)
     : mWeakFrame(aFrame)
   {
   }
 
   virtual PRBool ReflowFinished() {
     PRBool shouldFlush = PR_FALSE;
     if (mWeakFrame.IsAlive()) {
-      nsIMenuFrame* imenu = nsnull;
-      CallQueryInterface(mWeakFrame.GetFrame(), &imenu);
-      if (imenu) {
-        nsMenuFrame* menu = NS_STATIC_CAST(nsMenuFrame*, imenu);
+      if (mWeakFrame.GetFrame()->GetType() == nsGkAtoms::menuFrame) {
+        nsMenuFrame* menu = NS_STATIC_CAST(nsMenuFrame*, mWeakFrame.GetFrame());
         menu->UpdateMenuType(menu->PresContext());
         shouldFlush = PR_TRUE;
       }
     }
     delete this;
     return shouldFlush;
   }
 
@@ -199,23 +207,17 @@ nsMenuFrame::Init(nsIContent*      aCont
 {
   nsresult  rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
 
   // Set up a mediator which can be used for callbacks on this frame.
   mTimerMediator = new nsMenuTimerMediator(this);
   if (NS_UNLIKELY(!mTimerMediator))
     return NS_ERROR_OUT_OF_MEMORY;
 
-  nsIFrame* currFrame = aParent;
-  while (!mMenuParent && currFrame) {
-    // Set our menu parent.
-    CallQueryInterface(currFrame, &mMenuParent);
-
-    currFrame = currFrame->GetParent();
-  }
+  InitMenuParent(aParent);
 
   //load the display strings for the keyboard accelerators, but only once
   if (gRefCnt++ == 0) {
     
     nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
     nsCOMPtr<nsIStringBundle> bundle;
     if (NS_SUCCEEDED(rv) && bundleService) {
       rv = bundleService->CreateBundle( "chrome://global-platform/locale/platformKeys.properties",
@@ -271,114 +273,75 @@ nsMenuFrame::~nsMenuFrame()
 }
 
 // The following methods are all overridden to ensure that the menupopup frame
 // is placed in the appropriate list.
 nsIFrame*
 nsMenuFrame::GetFirstChild(nsIAtom* aListName) const
 {
   if (nsGkAtoms::popupList == aListName) {
-    return mPopupFrames.FirstChild();
+    return mPopupFrame;
   }
   return nsBoxFrame::GetFirstChild(aListName);
 }
 
 NS_IMETHODIMP
 nsMenuFrame::SetInitialChildList(nsIAtom*        aListName,
                                  nsIFrame*       aChildList)
 {
-  nsresult rv = NS_OK;
-  if (nsGkAtoms::popupList == aListName) {
-    mPopupFrames.SetFrames(aChildList);
-  } else {
-
-    nsFrameList frames(aChildList);
+  // Check for a menupopup and move it to mPopupFrame
+  nsFrameList frames(aChildList);
+  nsIFrame* frame = frames.FirstChild();
+  while (frame) {
+    if (frame->GetType() == nsGkAtoms::menuPopupFrame) {
+      // Remove this frame from the list and set it as mPopupFrame
+      frames.RemoveFrame(frame);
+      mPopupFrame = (nsMenuPopupFrame *)frame;
+      aChildList = frames.FirstChild();
+      break;
+    }
+    frame = frame->GetNextSibling();
+  }
 
-    // We may have a menupopup in here. Get it out, and move it into
-    // the popup frame list.
-    nsIFrame* frame = frames.FirstChild();
-    while (frame) {
-      nsIMenuParent *menuPar;
-      CallQueryInterface(frame, &menuPar);
-      if (menuPar) {
-        PRBool isMenuBar;
-        menuPar->IsMenuBar(isMenuBar);
-        if (!isMenuBar) {
-          // Remove this frame from the list and place it in the other list.
-          frames.RemoveFrame(frame);
-          mPopupFrames.AppendFrame(this, frame);
-          nsIFrame* first = frames.FirstChild();
-          rv = nsBoxFrame::SetInitialChildList(aListName, first);
-          return rv;
-        }
-      }
-      frame = frame->GetNextSibling();
-    }
-
-    // Didn't find it.
-    rv = nsBoxFrame::SetInitialChildList(aListName, aChildList);
-  }
-  return rv;
+  // Didn't find it.
+  return nsBoxFrame::SetInitialChildList(aListName, aChildList);
 }
 
 nsIAtom*
 nsMenuFrame::GetAdditionalChildListName(PRInt32 aIndex) const
 {
   if (NS_MENU_POPUP_LIST_INDEX == aIndex) {
     return nsGkAtoms::popupList;
   }
-
   return nsnull;
 }
 
-nsresult
-nsMenuFrame::DestroyPopupFrames(nsPresContext* aPresContext)
-{
-  // Remove our frame mappings
-  nsCSSFrameConstructor* frameConstructor =
-    aPresContext->PresShell()->FrameConstructor();
-  nsIFrame* curFrame = mPopupFrames.FirstChild();
-  while (curFrame) {
-    frameConstructor->RemoveMappingsForFrameSubtree(curFrame);
-    curFrame = curFrame->GetNextSibling();
-  }
-
-   // Cleanup frames in popup child list
-  mPopupFrames.DestroyFrames();
-  return NS_OK;
-}
-
 void
 nsMenuFrame::Destroy()
 {
   // Kill our timer if one is active. This is not strictly necessary as
   // the pointer to this frame will be cleared from the mediator, but
   // this is done for added safety.
   if (mOpenTimer) {
     mOpenTimer->Cancel();
   }
 
   // Null out the pointer to this frame in the mediator wrapper so that it 
   // doesn't try to interact with a deallocated frame.
   mTimerMediator->ClearFrame();
 
-  nsWeakFrame weakFrame(this);
   // are we our menu parent's current menu item?
-  if (mMenuParent) {
-    nsIMenuFrame *curItem = mMenuParent->GetCurrentMenuItem();
-    if (curItem == this) {
-      // yes; tell it that we're going away
-      mMenuParent->SetCurrentMenuItem(nsnull);
-      ENSURE_TRUE(weakFrame.IsAlive());
-    }
+  if (mMenuParent && mMenuParent->GetCurrentMenuItem() == this) {
+    // yes; tell it that we're going away
+    mMenuParent->CurrentMenuIsBeingDestroyed();
   }
 
-  UngenerateMenu();
-  ENSURE_TRUE(weakFrame.IsAlive());
-  DestroyPopupFrames(PresContext());
+  if (mPopupFrame)
+    mPopupFrame->Destroy();
+
   nsBoxFrame::Destroy();
 }
 
 NS_IMETHODIMP
 nsMenuFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                          const nsRect&           aDirtyRect,
                                          const nsDisplayListSet& aLists)
 {
@@ -387,625 +350,299 @@ nsMenuFrame::BuildDisplayListForChildren
     
   nsDisplayListCollection set;
   nsresult rv = nsBoxFrame::BuildDisplayListForChildren(aBuilder, aDirtyRect, set);
   NS_ENSURE_SUCCESS(rv, rv);
   
   return WrapListsInRedirector(aBuilder, set, aLists);
 }
 
-NS_IMETHODIMP 
+NS_IMETHODIMP
 nsMenuFrame::HandleEvent(nsPresContext* aPresContext, 
-                             nsGUIEvent*     aEvent,
-                             nsEventStatus*  aEventStatus)
+                         nsGUIEvent*     aEvent,
+                         nsEventStatus*  aEventStatus)
 {
   NS_ENSURE_ARG_POINTER(aEventStatus);
   nsWeakFrame weakFrame(this);
   if (*aEventStatus == nsEventStatus_eIgnore)
     *aEventStatus = nsEventStatus_eConsumeDoDefault;
-  
+
+  PRBool onmenu = IsOnMenu();
+
   if (aEvent->message == NS_KEY_PRESS && !IsDisabled()) {
     nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
     PRUint32 keyCode = keyEvent->keyCode;
 #ifdef XP_MACOSX
     // On mac, open menulist on either up/down arrow or space (w/o Cmd pressed)
     if (!IsOpen() && ((keyEvent->charCode == NS_VK_SPACE && !keyEvent->isMeta) ||
         (keyCode == NS_VK_UP || keyCode == NS_VK_DOWN)))
-      OpenMenu(PR_TRUE);
+      OpenMenu(PR_FALSE);
 #else
     // On other platforms, toggle menulist on unmodified F4 or Alt arrow
     if ((keyCode == NS_VK_F4 && !keyEvent->isAlt) ||
         ((keyCode == NS_VK_UP || keyCode == NS_VK_DOWN) && keyEvent->isAlt))
-      OpenMenu(!IsOpen());
+      ToggleMenuState();
 #endif
   }
   else if (aEvent->eventStructType == NS_MOUSE_EVENT &&
            aEvent->message == NS_MOUSE_BUTTON_DOWN &&
            NS_STATIC_CAST(nsMouseEvent*, aEvent)->button == nsMouseEvent::eLeftButton &&
            !IsDisabled() && IsMenu()) {
-    PRBool isMenuBar = PR_FALSE;
-    if (mMenuParent)
-      mMenuParent->IsMenuBar(isMenuBar);
-
     // The menu item was selected. Bring up the menu.
     // We have children.
-    if ( isMenuBar || !mMenuParent ) {
+    if (!mMenuParent || mMenuParent->IsMenuBar()) {
       ToggleMenuState();
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-
-      if (!IsOpen() && mMenuParent) {
-        // We closed up. The menu bar should always be
-        // deactivated when this happens.
-        mMenuParent->SetActive(PR_FALSE);
-      }
     }
-    else
-      if ( !IsOpen() ) {
-        // one of our siblings is probably open and even possibly waiting
-        // for its close timer to fire. Tell our parent to close it down. Not
-        // doing this before its timer fires will cause the rollup state to
-        // get very confused.
-        if ( mMenuParent )
-          mMenuParent->KillPendingTimers();
-
-        // safe to open up
-        OpenMenu(PR_TRUE);
-      }
+    else {
+      if (!IsOpen())
+        OpenMenu(PR_FALSE);
+    }
   }
   else if (
 #ifndef NSCONTEXTMENUISMOUSEUP
            (aEvent->eventStructType == NS_MOUSE_EVENT &&
             aEvent->message == NS_MOUSE_BUTTON_UP &&
             NS_STATIC_CAST(nsMouseEvent*, aEvent)->button ==
               nsMouseEvent::eRightButton) &&
 #else
             aEvent->message == NS_CONTEXTMENU &&
 #endif
-            mMenuParent && !IsMenu() && !IsDisabled()) {
+            onmenu && !IsMenu() && !IsDisabled()) {
     // if this menu is a context menu it accepts right-clicks...fire away!
     // Make sure we cancel default processing of the context menu event so
     // that it doesn't bubble and get seen again by the popuplistener and show
     // another context menu.
     //
     // Furthermore (there's always more, isn't there?), on some platforms (win32
     // being one of them) we get the context menu event on a mouse up while
     // on others we get it on a mouse down. For the ones where we get it on a
     // mouse down, we must continue listening for the right button up event to
     // dismiss the menu.
-    PRBool isContextMenu = PR_FALSE;
-    mMenuParent->GetIsContextMenu(isContextMenu);
-    if ( isContextMenu ) {
+    if (mMenuParent->IsContextMenu()) {
       *aEventStatus = nsEventStatus_eConsumeNoDefault;
       Execute(aEvent);
     }
   }
   else if (aEvent->eventStructType == NS_MOUSE_EVENT &&
            aEvent->message == NS_MOUSE_BUTTON_UP &&
            NS_STATIC_CAST(nsMouseEvent*, aEvent)->button == nsMouseEvent::eLeftButton &&
-           !IsMenu() && mMenuParent && !IsDisabled()) {
+           !IsMenu() && !IsDisabled()) {
     // Execute the execute event handler.
     Execute(aEvent);
   }
   else if (aEvent->message == NS_MOUSE_EXIT_SYNTH) {
     // Kill our timer if one is active.
     if (mOpenTimer) {
       mOpenTimer->Cancel();
       mOpenTimer = nsnull;
     }
 
     // Deactivate the menu.
-    PRBool isActive = PR_FALSE;
-    PRBool isMenuBar = PR_FALSE;
     if (mMenuParent) {
-      mMenuParent->IsMenuBar(isMenuBar);
-      PRBool cancel = PR_TRUE;
-      if (isMenuBar) {
-        mMenuParent->GetIsActive(isActive);
-        if (isActive) cancel = PR_FALSE;
-      }
-      
-      if (cancel) {
-        if (IsMenu() && !isMenuBar && mMenuOpen) {
+      PRBool onmenubar = mMenuParent->IsMenuBar();
+      if (!(onmenubar && mMenuParent->IsActive())) {
+        if (IsMenu() && !onmenubar && IsOpen()) {
           // Submenus don't get closed up immediately.
         }
-        else mMenuParent->SetCurrentMenuItem(nsnull);
+        else
+          mMenuParent->ChangeMenuItem(nsnull, PR_FALSE);
       }
     }
   }
-  else if (aEvent->message == NS_MOUSE_MOVE && mMenuParent) {
+  else if (aEvent->message == NS_MOUSE_MOVE &&
+           (onmenu || (mMenuParent && mMenuParent->IsMenuBar()))) {
     if (gEatMouseMove) {
       gEatMouseMove = PR_FALSE;
       return NS_OK;
     }
 
-    // we checked for mMenuParent right above
-
-    PRBool isMenuBar = PR_FALSE;
-    mMenuParent->IsMenuBar(isMenuBar);
-
     // Let the menu parent know we're the new item.
-    mMenuParent->SetCurrentMenuItem(this);
+    mMenuParent->ChangeMenuItem(this, PR_FALSE);
     NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
     NS_ENSURE_TRUE(mMenuParent, NS_OK);
-    
+
     // we need to check if we really became the current menu
     // item or not
-    nsIMenuFrame *realCurrentItem = mMenuParent->GetCurrentMenuItem();
+    nsMenuFrame *realCurrentItem = mMenuParent->GetCurrentMenuItem();
     if (realCurrentItem != this) {
       // we didn't (presumably because a context menu was active)
       return NS_OK;
     }
 
-    // If we're a menu (and not a menu item),
-    // kick off the timer.
-    if (!IsDisabled() && !isMenuBar && IsMenu() && !mMenuOpen && !mOpenTimer) {
-
+    // Hovering over a menu in a popup should open it without a need for a click.
+    // A timer is used so that it doesn't open if the user moves the mouse quickly
+    // past the menu. This conditional check ensures that only menus have this
+    // behaviour
+    if (!IsDisabled() && IsMenu() && !IsOpen() && !mOpenTimer && !mMenuParent->IsMenuBar()) {
       PRInt32 menuDelay = 300;   // ms
 
       nsCOMPtr<nsILookAndFeel> lookAndFeel(do_GetService(kLookAndFeelCID));
       if (lookAndFeel)
         lookAndFeel->GetMetric(nsILookAndFeel::eMetric_SubmenuDelay, menuDelay);
 
       // We're a menu, we're built, we're closed, and no timer has been kicked off.
       mOpenTimer = do_CreateInstance("@mozilla.org/timer;1");
       mOpenTimer->InitWithCallback(mTimerMediator, menuDelay, nsITimer::TYPE_ONE_SHOT);
-
     }
   }
   
   return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 nsMenuFrame::ToggleMenuState()
 {
+  if (IsOpen())
+    CloseMenu(PR_FALSE);
+  else
+    OpenMenu(PR_FALSE);
+}
+
+void
+nsMenuFrame::PopupOpened()
+{
   nsWeakFrame weakFrame(this);
-  if (mMenuOpen) {
-    OpenMenu(PR_FALSE);
-    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-  }
-  else {
-    PRBool justRolledUp = PR_FALSE;
-    if (mMenuParent) {
-      mMenuParent->RecentlyRolledUp(this, &justRolledUp);
-    }
-    if (justRolledUp) {
-      // Don't let a click reopen a menu that was just rolled up
-      // from the same click. Otherwise, the user can't click on
-      // a menubar item to toggle its submenu closed.
-      OpenMenu(PR_FALSE);
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-      SelectMenu(PR_TRUE);
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-      NS_ENSURE_TRUE(mMenuParent, NS_OK);
-      mMenuParent->SetActive(PR_FALSE);
-    }
-    else {
-      if (mMenuParent) {
-        mMenuParent->SetActive(PR_TRUE);
-        NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-      }
-      OpenMenu(PR_TRUE);
-    }
-  }
-  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
+  mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open,
+                    NS_LITERAL_STRING("true"), PR_TRUE);
+  if (!weakFrame.IsAlive())
+    return;
 
   if (mMenuParent) {
+    mMenuParent->SetActive(PR_TRUE);
     // Make sure the current menu which is being toggled on
     // the menubar is highlighted
     mMenuParent->SetCurrentMenuItem(this);
-    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    NS_ENSURE_TRUE(mMenuParent, NS_OK);
-    // We've successfully prevented the same click from both
-    // dismissing and reopening this menu. 
-    // Clear the recent rollup state so we don't prevent
-    // this menu from being opened by the next click.
-    mMenuParent->ClearRecentlyRolledUp();
+  }
+}
+
+void
+nsMenuFrame::PopupClosed(PRBool aDeselectMenu)
+{
+  nsWeakFrame weakFrame(this);
+  mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, PR_TRUE);
+  if (!weakFrame.IsAlive())
+    return;
+
+  // if the popup is for a menu on a menubar, inform menubar to deactivate
+  if (mMenuParent && mMenuParent->MenuClosed()) {
+    if (aDeselectMenu)
+      SelectMenu(PR_FALSE);
+  }
+}
+
+// this class is used for dispatching menu activation events asynchronously.
+class nsMenuActivateEvent : public nsRunnable
+{
+public:
+  nsMenuActivateEvent(nsIContent *aMenu,
+                      nsPresContext* aPresContext,
+                      PRBool aIsActivate)
+    : mMenu(aMenu), mPresContext(aPresContext), mIsActivate(aIsActivate)
+  {
   }
 
-  return NS_OK;
-}
+  NS_IMETHOD Run()
+  {
+    nsAutoString domEventToFire;
+
+    if (mIsActivate) {
+      // Highlight the menu.
+      mMenu->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
+                     NS_LITERAL_STRING("true"), PR_TRUE);
+      // The menuactivated event is used by accessibility to track the user's
+      // movements through menus
+      domEventToFire.AssignLiteral("DOMMenuItemActive");
+    }
+    else {
+      // Unhighlight the menu.
+      mMenu->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, PR_TRUE);
+      domEventToFire.AssignLiteral("DOMMenuItemInactive");
+    }
+
+    nsCOMPtr<nsIDOMEvent> event;
+    if (NS_SUCCEEDED(nsEventDispatcher::CreateEvent(mPresContext, nsnull,
+                                                    NS_LITERAL_STRING("Events"),
+                                                    getter_AddRefs(event)))) {
+      event->InitEvent(domEventToFire, PR_TRUE, PR_TRUE);
+
+      nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
+      privateEvent->SetTrusted(PR_TRUE);
+
+      nsEventDispatcher::DispatchDOMEvent(mMenu, nsnull, event,
+                                          mPresContext, nsnull);
+    }
+
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIContent> mMenu;
+  nsCOMPtr<nsPresContext> mPresContext;
+  PRBool mIsActivate;
+};
 
 NS_IMETHODIMP
 nsMenuFrame::SelectMenu(PRBool aActivateFlag)
 {
-  if (!mContent) {
-    return NS_OK;
-  }
-
-  nsAutoString domEventToFire;
-
-  nsWeakFrame weakFrame(this);
-  if (aActivateFlag) {
-    if (mMenuParent) {
-      nsIMenuParent* ancestor = nsnull;
-      nsresult rv = mMenuParent->GetParentPopup(&ancestor);
-      while (NS_SUCCEEDED(rv) && ancestor) {
-        ancestor->CancelPendingTimers();
-        rv = ancestor->GetParentPopup(&ancestor);
-      }
-    }
-    // Highlight the menu.
-    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, NS_LITERAL_STRING("true"), PR_TRUE);
-    // The menuactivated event is used by accessibility to track the user's movements through menus
-    domEventToFire.AssignLiteral("DOMMenuItemActive");
-  }
-  else {
-    // Unhighlight the menu.
-    mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menuactive, PR_TRUE);
-    domEventToFire.AssignLiteral("DOMMenuItemInactive");
-  }
-
-  if (weakFrame.IsAlive()) {
-    FireDOMEventSynch(domEventToFire);
-  }
-  return NS_OK;
-}
-
-PRBool nsMenuFrame::IsGenerated()
-{
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  // Generate the menu if it hasn't been generated already.  This
-  // takes it from display: none to display: block and gives us
-  // a menu forevermore.
-  if (child &&
-      !nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None,
-                                       nsGkAtoms::menugenerated)) {
-    return PR_FALSE;
-  }
-
-  return PR_TRUE;
-}
-
-NS_IMETHODIMP
-nsMenuFrame::MarkAsGenerated()
-{
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  // Generate the menu if it hasn't been generated already.  This
-  // takes it from display: none to display: block and gives us
-  // a menu forevermore.
-  if (child &&
-      !nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None,
-                                       nsGkAtoms::menugenerated)) {
-    child->SetAttr(kNameSpaceID_None, nsGkAtoms::menugenerated,
-                   NS_LITERAL_STRING("true"), PR_TRUE);
+  if (mContent) {
+    nsCOMPtr<nsIRunnable> event =
+      new nsMenuActivateEvent(mContent, PresContext(), aActivateFlag);
+    NS_DispatchToCurrentThread(event);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsMenuFrame::UngenerateMenu()
-{
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  if (child &&
-      nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None,
-                                      nsGkAtoms::menugenerated)) {
-    child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::menugenerated, PR_TRUE);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuFrame::ActivateMenu(PRBool aActivateFlag)
-{
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
-  
-  if (!menuPopup) 
-    return NS_OK;
-
-  if (aActivateFlag) {
-      nsRect rect = menuPopup->GetRect();
-      nsIView* view = menuPopup->GetView();
-      nsIViewManager* viewManager = view->GetViewManager();
-      rect.x = rect.y = 0;
-      viewManager->ResizeView(view, rect);
-
-      // make sure the scrolled window is at 0,0
-      if (mLastPref.height <= rect.height) {
-        nsIBox* child = menuPopup->GetChildBox();
-
-        nsCOMPtr<nsIScrollableFrame> scrollframe(do_QueryInterface(child));
-        if (scrollframe) {
-          scrollframe->ScrollTo(nsPoint(0,0));
-        }
-      }
-
-      viewManager->UpdateView(view, rect, NS_VMREFRESH_IMMEDIATE);
-      viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
-      PresContext()->RootPresContext()->NotifyAddedActivePopupToTop(menuPopup);
-  } else {
-    if (mMenuOpen) {
-      nsWeakFrame weakFrame(this);
-      nsWeakFrame weakPopup(menuPopup);
-      FireDOMEventSynch(NS_LITERAL_STRING("DOMMenuInactive"), menuPopup->GetContent());
-      NS_ENSURE_TRUE(weakFrame.IsAlive() && weakPopup.IsAlive(), NS_OK);
-    }
-    nsIView* view = menuPopup->GetView();
-    NS_ASSERTION(view, "View is gone, looks like someone forgot to rollup the popup!");
-    if (view) {
-      nsIViewManager* viewManager = view->GetViewManager();
-      if (viewManager) { // the view manager can be null during widget teardown
-        viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
-        viewManager->ResizeView(view, nsRect(0, 0, 0, 0));
-      }
-    }
-    // set here so hide chain can close the menu as well.
-    mMenuOpen = PR_FALSE;
-    PresContext()->RootPresContext()->NotifyRemovedActivePopup(menuPopup);
-  }
-  
-  return NS_OK;
-}  
-
-NS_IMETHODIMP
 nsMenuFrame::AttributeChanged(PRInt32 aNameSpaceID,
                               nsIAtom* aAttribute,
                               PRInt32 aModType)
 {
   nsAutoString value;
 
   if (aAttribute == nsGkAtoms::checked) {
     if (mType != eMenuType_Normal)
         UpdateMenuSpecialState(PresContext());
   } else if (aAttribute == nsGkAtoms::acceltext) {
     // someone reset the accelText attribute, so clear the bit that says *we* set it
     AddStateBits(NS_STATE_ACCELTEXT_IS_DERIVED);
     BuildAcceleratorText();
   } else if (aAttribute == nsGkAtoms::key) {
     BuildAcceleratorText();
-  } else if ( aAttribute == nsGkAtoms::type || aAttribute == nsGkAtoms::name )
+  } else if (aAttribute == nsGkAtoms::type || aAttribute == nsGkAtoms::name)
     UpdateMenuType(PresContext());
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsMenuFrame::OpenMenu(PRBool aActivateFlag)
+void
+nsMenuFrame::OpenMenu(PRBool aSelectFirstItem)
 {
   if (!mContent)
-    return NS_OK;
+    return;
 
-  nsWeakFrame weakFrame(this);
-  if (aActivateFlag) {
-    // Now that the menu is opened, we should have a menupopup child built.
-    // Mark it as generated, which ensures a frame gets built.
-    MarkAsGenerated();
-    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
+  gEatMouseMove = PR_TRUE;
 
-    mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::open, NS_LITERAL_STRING("true"), PR_TRUE);
-    NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    FireDOMEventSynch(NS_LITERAL_STRING("DOMMenuItemActive"));
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm) {
+    pm->KillMenuTimer();
+    // This opens the menu asynchronously
+    pm->ShowMenu(mContent, aSelectFirstItem, PR_TRUE);
   }
-  else {
-    mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::open, PR_TRUE);
-  }
-
-  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-  OpenMenuInternal(aActivateFlag);
-
-  return NS_OK;
 }
 
-void 
-nsMenuFrame::OpenMenuInternal(PRBool aActivateFlag) 
+void
+nsMenuFrame::CloseMenu(PRBool aDeselectMenu)
 {
   gEatMouseMove = PR_TRUE;
 
-  if (!mIsMenu)
-    return;
-
-  nsPresContext* presContext = PresContext();
-  nsWeakFrame weakFrame(this);
-
-  if (aActivateFlag) {
-    // Execute the oncreate handler
-    if (!OnCreate() || !weakFrame.IsAlive())
-      return;
-
-    mCreateHandlerSucceeded = PR_TRUE;
-  
-    // Set the focus back to our view's widget.
-    if (nsMenuDismissalListener::sInstance)
-      nsMenuDismissalListener::sInstance->EnableListener(PR_FALSE);
-    
-    // XXX Only have this here because of RDF-generated content.
-    MarkAsGenerated();
-    ENSURE_TRUE(weakFrame.IsAlive());
-
-    nsIFrame* frame = mPopupFrames.FirstChild();
-    nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
-    
-    PRBool wasOpen = mMenuOpen;
-    mMenuOpen = PR_TRUE;
-
-    if (menuPopup) {
-      nsWeakFrame weakMenuPopup(frame);
-      // inherit whether or not we're a context menu from the parent
-      if ( mMenuParent ) {
-        PRBool parentIsContextMenu = PR_FALSE;
-        mMenuParent->GetIsContextMenu(parentIsContextMenu);
-        menuPopup->SetIsContextMenu(parentIsContextMenu);
-        ENSURE_TRUE(weakFrame.IsAlive());
-      }
-
-      // Install a keyboard navigation listener if we're the root of the menu chain.
-      PRBool onMenuBar = PR_TRUE;
-      if (mMenuParent)
-        mMenuParent->IsMenuBar(onMenuBar);
-
-      if (mMenuParent && onMenuBar)
-        mMenuParent->InstallKeyboardNavigator();
-      else if (!mMenuParent) {
-        ENSURE_TRUE(weakMenuPopup.IsAlive());
-        menuPopup->InstallKeyboardNavigator();
-      }
-      
-      // Tell the menu bar we're active.
-      if (mMenuParent) {
-        mMenuParent->SetActive(PR_TRUE);
-        ENSURE_TRUE(weakFrame.IsAlive());
-      }
-
-      nsIContent* menuPopupContent = menuPopup->GetContent();
-
-      // Sync up the view.
-      nsAutoString popupAnchor, popupAlign;
-      
-      menuPopupContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupanchor, popupAnchor);
-      menuPopupContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupalign, popupAlign);
-
-      ConvertPosition(menuPopupContent, popupAnchor, popupAlign);
-
-      if (onMenuBar) {
-        if (popupAnchor.IsEmpty())
-          popupAnchor.AssignLiteral("bottomleft");
-        if (popupAlign.IsEmpty())
-          popupAlign.AssignLiteral("topleft");
-      }
-      else {
-        if (popupAnchor.IsEmpty())
-          popupAnchor.AssignLiteral("topright");
-        if (popupAlign.IsEmpty())
-          popupAlign.AssignLiteral("topleft");
-      }
-
-      // If the menu popup was not open, do a reflow.  This is either the
-      // initial reflow for a brand-new popup, or a subsequent reflow for
-      // a menu that was deactivated and needs to be brought back to its
-      // active dimensions.
-      if (!wasOpen)
-      {
-         presContext->PresShell()->
-           FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange,
-                            NS_FRAME_IS_DIRTY);
-         presContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow);
-      }
-
-      nsRect curRect(menuPopup->GetRect());
-      nsBoxLayoutState state(presContext);
-      menuPopup->SetBounds(state, nsRect(0,0,mLastPref.width, mLastPref.height));
-
-      nsIView* view = menuPopup->GetView();
-      nsIViewManager* vm = view->GetViewManager();
-      if (vm) {
-        vm->SetViewVisibility(view, nsViewVisibility_kHide);
-      }
-      menuPopup->SyncViewWithFrame(presContext, popupAnchor, popupAlign, this, -1, -1);
-      nscoord newHeight = menuPopup->GetRect().height;
-
-      // if the height is different then reflow. It might need scrollbars force a reflow
-      if (curRect.height != newHeight || mLastPref.height != newHeight)
-      {
-         presContext->PresShell()->
-           FrameNeedsReflow(menuPopup, nsIPresShell::eStyleChange,
-                            NS_FRAME_IS_DIRTY);
-         presContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow);
-      }
-
-      ActivateMenu(PR_TRUE);
-      ENSURE_TRUE(weakFrame.IsAlive());
-
-      nsIMenuParent *childPopup = nsnull;
-      CallQueryInterface(frame, &childPopup);
-
-      nsMenuDismissalListener* listener = nsMenuDismissalListener::GetInstance();
-      if (listener)
-        listener->SetCurrentMenuParent(childPopup);
-
-      OnCreated();
-      ENSURE_TRUE(weakFrame.IsAlive());
-    }
-
-    // Set the focus back to our view's widget.
-    if (nsMenuDismissalListener::sInstance)
-      nsMenuDismissalListener::sInstance->EnableListener(PR_TRUE);
-
-  }
-  else {
-
-    // Close the menu. 
-    // Execute the ondestroy handler, but only if we're actually open
-    if ( !mCreateHandlerSucceeded || !OnDestroy() || !weakFrame.IsAlive())
-      return;
-
-    // Set the focus back to our view's widget.
-    if (nsMenuDismissalListener::sInstance) {
-      nsMenuDismissalListener::sInstance->EnableListener(PR_FALSE);
-      nsMenuDismissalListener::sInstance->SetCurrentMenuParent(mMenuParent);
-    }
-
-    nsIFrame* frame = mPopupFrames.FirstChild();
-    nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
-  
-    // Make sure we clear out our own items.
-    if (menuPopup) {
-      menuPopup->SetCurrentMenuItem(nsnull);
-      ENSURE_TRUE(weakFrame.IsAlive());
-      menuPopup->KillCloseTimer();
-
-      PRBool onMenuBar = PR_TRUE;
-      if (mMenuParent)
-        mMenuParent->IsMenuBar(onMenuBar);
-
-      if (mMenuParent && onMenuBar)
-        mMenuParent->RemoveKeyboardNavigator();
-      else if (!mMenuParent)
-        menuPopup->RemoveKeyboardNavigator();
-
-      // XXX, bug 137033, In Windows, if mouse is outside the window when the menupopup closes, no
-      // mouse_enter/mouse_exit event will be fired to clear current hover state, we should clear it manually.
-      // This code may not the best solution, but we can leave it here until we find the better approach.
-
-      nsIEventStateManager *esm = presContext->EventStateManager();
-
-      PRInt32 state;
-      esm->GetContentState(menuPopup->GetContent(), state);
-
-      if (state & NS_EVENT_STATE_HOVER)
-        esm->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
-    }
-
-    ActivateMenu(PR_FALSE);
-    ENSURE_TRUE(weakFrame.IsAlive());
-    // XXX hack: ensure that mMenuOpen is set to false, in case where
-    // there is actually no popup. because ActivateMenu() will return 
-    // early without setting it. It could be that mMenuOpen is true
-    // in that case, because OpenMenuInternal(true) gets called if
-    // the attribute open="true", whether there is a popup or not.
-    // We should not allow mMenuOpen unless there is a popup in the first place,
-    // in which case this line would not be necessary.
-    mMenuOpen = PR_FALSE;
-
-    OnDestroyed();
-    ENSURE_TRUE(weakFrame.IsAlive());
-
-    if (nsMenuDismissalListener::sInstance)
-      nsMenuDismissalListener::sInstance->EnableListener(PR_TRUE);
-
-    mCreateHandlerSucceeded = PR_FALSE;
-  }
-
-}
-
-void
-nsMenuFrame::GetMenuChildrenElement(nsIContent** aResult)
-{
-  *aResult = nsContentUtils::FindFirstChildWithResolvedTag(mContent,
-                                                           kNameSpaceID_XUL,
-                                                           nsGkAtoms::menupopup);
-  NS_IF_ADDREF(*aResult);
+  // Close the menu asynchronously
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm && mPopupFrame)
+    pm->HidePopup(mPopupFrame->GetContent(), PR_FALSE, aDeselectMenu, PR_TRUE);
 }
 
 PRBool
 nsMenuFrame::IsSizedToPopup(nsIContent* aContent, PRBool aRequireAlways)
 {
   PRBool sizeToPopup;
   if (aContent->Tag() == nsGkAtoms::select)
     sizeToPopup = PR_TRUE;
@@ -1033,93 +670,84 @@ nsMenuFrame::GetMinSize(nsBoxLayoutState
 
 NS_IMETHODIMP
 nsMenuFrame::DoLayout(nsBoxLayoutState& aState)
 {
   // lay us out
   nsresult rv = nsBoxFrame::DoLayout(aState);
 
   // layout the popup. First we need to get it.
-  nsIFrame* popupChild = mPopupFrames.FirstChild();
-
-  if (popupChild) {
+  if (mPopupFrame) {
     PRBool sizeToPopup = IsSizedToPopup(mContent, PR_FALSE);
-    
-    NS_ASSERTION(popupChild->IsBoxFrame(), "popupChild is not box!!");
-
     // then get its preferred size
-    nsSize prefSize = popupChild->GetPrefSize(aState);
-    nsSize minSize = popupChild->GetMinSize(aState); 
-    nsSize maxSize = popupChild->GetMaxSize(aState);
+    nsSize prefSize = mPopupFrame->GetPrefSize(aState);
+    nsSize minSize = mPopupFrame->GetMinSize(aState); 
+    nsSize maxSize = mPopupFrame->GetMaxSize(aState);
 
     BoundsCheck(minSize, prefSize, maxSize);
 
     if (sizeToPopup)
         prefSize.width = mRect.width;
 
     // if the pref size changed then set bounds to be the pref size
-    // and sync the view. And set new pref size.
-    if (mLastPref != prefSize) {
-      popupChild->SetBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
-      RePositionPopup(aState);
+    PRBool sizeChanged = (mLastPref != prefSize);
+    if (sizeChanged) {
+      mPopupFrame->SetBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
       mLastPref = prefSize;
     }
 
+    // if the menu has just been opened, or its size changed, position
+    // the popup. The flag that the popup checks in the HasOpenChanged
+    // method will get cleared in AdjustView which is called below.
+    if (IsOpen() && (sizeChanged || mPopupFrame->HasOpenChanged()))
+      mPopupFrame->SetPopupPosition(this);
+
     // is the new size too small? Make sure we handle scrollbars correctly
-    nsIBox* child = popupChild->GetChildBox();
+    nsIBox* child = mPopupFrame->GetChildBox();
 
-    nsRect bounds(popupChild->GetRect());
+    nsRect bounds(mPopupFrame->GetRect());
 
     nsCOMPtr<nsIScrollableFrame> scrollframe(do_QueryInterface(child));
     if (scrollframe &&
         scrollframe->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
       if (bounds.height < prefSize.height) {
         // layout the child
-        popupChild->Layout(aState);
+        mPopupFrame->Layout(aState);
 
         nsMargin scrollbars = scrollframe->GetActualScrollbarSizes();
         if (bounds.width < prefSize.width + scrollbars.left + scrollbars.right)
         {
           bounds.width += scrollbars.left + scrollbars.right;
-          //printf("Width=%d\n",width);
-          popupChild->SetBounds(aState, bounds);
+          mPopupFrame->SetBounds(aState, bounds);
         }
       }
     }
-    
+
     // layout the child
-    popupChild->Layout(aState);
-
-    // Only size the popups view if open.
-    if (mMenuOpen) {
-      nsIView* view = popupChild->GetView();
-      nsRect r(0, 0, bounds.width, bounds.height);
-      view->GetViewManager()->ResizeView(view, r);
-    }
-
+    mPopupFrame->Layout(aState);
+    mPopupFrame->AdjustView();
   }
 
-  SyncLayout(aState);
-
   return rv;
 }
 
 #ifdef DEBUG_LAYOUT
 NS_IMETHODIMP
 nsMenuFrame::SetDebug(nsBoxLayoutState& aState, PRBool aDebug)
 {
   // see if our state matches the given debug state
   PRBool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
   PRBool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
 
   // if it doesn't then tell each child below us the new debug state
   if (debugChanged)
   {
       nsBoxFrame::SetDebug(aState, aDebug);
-      SetDebug(aState, mPopupFrames.FirstChild(), aDebug);
+      if (mPopupFrame)
+        SetDebug(aState, mPopupFrame, aDebug);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsMenuFrame::SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, PRBool aDebug)
 {
@@ -1132,238 +760,83 @@ nsMenuFrame::SetDebug(nsBoxLayoutState& 
 
         aList = aList->GetNextSibling();
       }
 
       return NS_OK;
 }
 #endif
 
-void
-nsMenuFrame::ConvertPosition(nsIContent* aPopupElt, nsString& aAnchor, nsString& aAlign)
-{
-  static nsIContent::AttrValuesArray strings[] =
-    {&nsGkAtoms::_empty, &nsGkAtoms::before_start, &nsGkAtoms::before_end,
-     &nsGkAtoms::after_start, &nsGkAtoms::after_end, &nsGkAtoms::start_before,
-     &nsGkAtoms::start_after, &nsGkAtoms::end_before, &nsGkAtoms::end_after,
-     &nsGkAtoms::overlap, nsnull};
-
-  switch (aPopupElt->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::position,
-                                     strings, eCaseMatters)) {
-    case nsIContent::ATTR_MISSING:
-    case 0:
-      return;
-    case 1:
-      aAnchor.AssignLiteral("topleft");
-      aAlign.AssignLiteral("bottomleft");
-      break;
-    case 2:
-      aAnchor.AssignLiteral("topright");
-      aAlign.AssignLiteral("bottomright");
-      break;
-    case 3:
-      aAnchor.AssignLiteral("bottomleft");
-      aAlign.AssignLiteral("topleft");
-      break;
-    case 4:
-      aAnchor.AssignLiteral("bottomright");
-      aAlign.AssignLiteral("topright");
-      break;
-    case 5:
-      aAnchor.AssignLiteral("topleft");
-      aAlign.AssignLiteral("topright");
-      break;
-    case 6:
-      aAnchor.AssignLiteral("bottomleft");
-      aAlign.AssignLiteral("bottomright");
-      break;
-    case 7:
-      aAnchor.AssignLiteral("topright");
-      aAlign.AssignLiteral("topleft");
-      break;
-    case 8:
-      aAnchor.AssignLiteral("bottomright");
-      aAlign.AssignLiteral("bottomleft");
-      break;
-    case 9:
-      aAnchor.AssignLiteral("topleft");
-      aAlign.AssignLiteral("topleft");
-      break;
-  }
-}
-
-void
-nsMenuFrame::RePositionPopup(nsBoxLayoutState& aState)
-{  
-  nsPresContext* presContext = aState.PresContext();
-
-  // Sync up the view.
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
-  if (mMenuOpen && menuPopup) {
-    nsIContent* menuPopupContent = menuPopup->GetContent();
-    nsAutoString popupAnchor, popupAlign;
-      
-    menuPopupContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupanchor, popupAnchor);
-    menuPopupContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupalign, popupAlign);
-
-    ConvertPosition(menuPopupContent, popupAnchor, popupAlign);
-
-    PRBool onMenuBar = PR_TRUE;
-    if (mMenuParent)
-      mMenuParent->IsMenuBar(onMenuBar);
-
-    if (onMenuBar) {
-      if (popupAnchor.IsEmpty())
-          popupAnchor.AssignLiteral("bottomleft");
-      if (popupAlign.IsEmpty())
-          popupAlign.AssignLiteral("topleft");
-    }
-    else {
-      if (popupAnchor.IsEmpty())
-        popupAnchor.AssignLiteral("topright");
-      if (popupAlign.IsEmpty())
-        popupAlign.AssignLiteral("topleft");
-    }
-
-    menuPopup->SyncViewWithFrame(presContext, popupAnchor, popupAlign, this, -1, -1);
-  }
-}
-
-NS_IMETHODIMP
-nsMenuFrame::ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag)
-{
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  if (frame) {
-    nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
-    popup->ShortcutNavigation(aKeyEvent, aHandledFlag);
-  } 
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
-{
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  if (frame) {
-    nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
-    popup->KeyboardNavigation(aKeyCode, aHandledFlag);
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuFrame::Escape(PRBool& aHandledFlag)
-{
-  if (mMenuParent) {
-    mMenuParent->ClearRecentlyRolledUp();
-  }
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  if (frame) {
-    nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
-    popup->Escape(aHandledFlag);
-  }
-
-  return NS_OK;
-}
-
-
 //
 // Enter
 //
 // Called when the user hits the <Enter>/<Return> keys or presses the
 // shortcut key. If this is a leaf item, the item's action will be executed.
-// If it is a submenu parent, open the submenu and select the first time.
 // In either case, do nothing if the item is disabled.
 //
-NS_IMETHODIMP
+nsMenuFrame*
 nsMenuFrame::Enter()
 {
   if (IsDisabled()) {
 #ifdef XP_WIN
     // behavior on Windows - close the popup chain
-    if (mMenuParent)
-      mMenuParent->DismissChain();
+    if (mMenuParent) {
+      nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+      if (pm)
+        pm->Rollup();
+    }
 #endif   // #ifdef XP_WIN
     // this menu item was disabled - exit
-    return NS_OK;
+    return nsnull;
   }
-    
-  if (!mMenuOpen) {
+
+  if (!IsOpen()) {
     // The enter key press applies to us.
     if (!IsMenu() && mMenuParent)
       Execute(0);          // Execute our event handler
-    else {
-      OpenMenu(PR_TRUE);
-      SelectFirstItem();
-    }
-
-    return NS_OK;
-  }
-
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  if (frame) {
-    nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
-    popup->Enter();
+    else
+      return this;
   }
 
-  return NS_OK;
+  return nsnull;
 }
 
-NS_IMETHODIMP
-nsMenuFrame::SelectFirstItem()
+PRBool
+nsMenuFrame::IsOpen()
 {
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  if (frame) {
-    nsMenuPopupFrame* popup = (nsMenuPopupFrame*)frame;
-    popup->SetCurrentMenuItem(popup->GetNextMenuItem(nsnull));
-  }
-
-  return NS_OK;
+  return mPopupFrame && mPopupFrame->IsOpen();
 }
 
 PRBool
 nsMenuFrame::IsMenu()
 {
   return mIsMenu;
 }
 
 nsresult
 nsMenuFrame::Notify(nsITimer* aTimer)
 {
   // Our timer has fired.
   if (aTimer == mOpenTimer.get()) {
-    if (!mMenuOpen && mMenuParent) {
+    mOpenTimer = nsnull;
+
+    if (!IsOpen() && mMenuParent) {
       // make sure we didn't open a context menu in the meantime
       // (i.e. the user right-clicked while hovering over a submenu).
-      // However, also make sure that we're not the context menu itself,
-      // to allow context submenus to open.
-      nsIMenuParent *ctxMenu = nsMenuFrame::GetContextMenu();
-      PRBool parentIsContextMenu = PR_FALSE;
-
-      if (ctxMenu)
-        mMenuParent->GetIsContextMenu(parentIsContextMenu);
-
-      if (ctxMenu == nsnull || parentIsContextMenu) {
-        if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
+      nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+      if (pm) {
+        if ((!pm->HasContextMenu(nsnull) || mMenuParent->IsContextMenu()) &&
+            mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
                                   nsGkAtoms::_true, eCaseMatters)) {
-          // We're still the active menu. Make sure all submenus/timers are closed
-          // before opening this one
-          mMenuParent->KillPendingTimers();
-          OpenMenu(PR_TRUE);
+          OpenMenu(PR_FALSE);
         }
       }
     }
-    mOpenTimer->Cancel();
-    mOpenTimer = nsnull;
   }
-  
-  mOpenTimer = nsnull;
+
   return NS_OK;
 }
 
 PRBool 
 nsMenuFrame::IsDisabled()
 {
   return mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
                                nsGkAtoms::_true, eCaseMatters);
@@ -1392,21 +865,21 @@ nsMenuFrame::UpdateMenuType(nsPresContex
       mType = eMenuType_Normal;
       break;
   }
   UpdateMenuSpecialState(aPresContext);
 }
 
 /* update checked-ness for type="checkbox" and type="radio" */
 void
-nsMenuFrame::UpdateMenuSpecialState(nsPresContext* aPresContext) {
+nsMenuFrame::UpdateMenuSpecialState(nsPresContext* aPresContext)
+{
   PRBool newChecked =
     mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::checked,
                           nsGkAtoms::_true, eCaseMatters); 
-
   if (newChecked == mChecked) {
     /* checked state didn't change */
 
     if (mType != eMenuType_Radio)
       return; // only Radio possibly cares about other kinds of change
 
     if (!mChecked || mGroupName.IsEmpty())
       return;                   // no interesting change
@@ -1433,53 +906,37 @@ nsMenuFrame::UpdateMenuSpecialState(nsPr
    *
    * The only other reasonable behaviour would be to check for another selected
    * item in that group.  If found, unselect ourselves, otherwise we're the
    * selected item.  That, however, would be a lot more work, and I don't think
    * it's better at all.
    */
 
   /* walk siblings, looking for the other checked item with the same name */
-  nsIMenuFrame *sibMenu;
-  nsMenuType sibType;
-  nsAutoString sibGroup;
-  PRBool sibChecked;
-  
   // get the first sibling in this menu popup. This frame may be it, and if we're
   // being called at creation time, this frame isn't yet in the parent's child list.
   // All I'm saying is that this may fail, but it's most likely alright.
   nsIFrame* sib = GetParent()->GetFirstChild(nsnull);
-  if ( !sib )
-    return;
 
-  // XXX - egcs 1.1.2 & gcc 2.95.x -Oy builds, where y > 1, 
-  // are known to break if we declare nsCOMPtrs inside this loop.  
-  // Moving the declaration out of the loop works around this problem.
-  // http://bugzilla.mozilla.org/show_bug.cgi?id=80988
-
-  do {
-    if (NS_FAILED(sib->QueryInterface(NS_GET_IID(nsIMenuFrame),
-                                      (void **)&sibMenu)))
-        continue;
-        
-    if (sibMenu != (nsIMenuFrame *)this &&        // correct way to check?
-        (sibMenu->GetMenuType(sibType), sibType == eMenuType_Radio) &&
-        (sibMenu->MenuIsChecked(sibChecked), sibChecked) &&
-        (sibMenu->GetRadioGroupName(sibGroup), sibGroup == mGroupName)) {
-      
-      /* uncheck the old item */
-      sib->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
-                                   PR_TRUE);
-
-      /* XXX in DEBUG, check to make sure that there aren't two checked items */
-      return;
+  while (sib) {
+    if (sib != this && sib->GetType() == nsGkAtoms::menuFrame) {
+      nsMenuFrame* menu = NS_STATIC_CAST(nsMenuFrame*, sib);
+      if (menu->GetMenuType() == eMenuType_Radio &&
+          menu->IsChecked() &&
+          (menu->GetRadioGroupName() == mGroupName)) {      
+        /* uncheck the old item */
+        sib->GetContent()->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
+                                     PR_TRUE);
+        /* XXX in DEBUG, check to make sure that there aren't two checked items */
+        return;
+      }
     }
 
-  } while ((sib = sib->GetNextSibling()) != nsnull);
-
+    sib = sib->GetNextSibling();
+  } 
 }
 
 void 
 nsMenuFrame::BuildAcceleratorText()
 {
   nsAutoString accelText;
 
   if ((GetStateBits() & NS_STATE_ACCELTEXT_IS_DERIVED) == 0) {
@@ -1639,247 +1096,35 @@ nsMenuFrame::Execute(nsGUIEvent *aEvent)
         mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::checked,
                             PR_TRUE);
         ENSURE_TRUE(weakFrame.IsAlive());
       }
       else {
         mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, NS_LITERAL_STRING("true"),
                           PR_TRUE);
         ENSURE_TRUE(weakFrame.IsAlive());
-      }        
-      /* the AttributeChanged code will update all the internal state */
-    }
-  }
-
-  // Temporarily disable rollup events on this menu.  This is
-  // to suppress this menu getting removed in the case where
-  // the oncommand handler opens a dialog, etc.
-  if ( nsMenuDismissalListener::sInstance ) {
-    nsMenuDismissalListener::sInstance->EnableListener(PR_FALSE);
-  }
-
-  // Get our own content node and hold on to it to keep it from going away.
-  nsCOMPtr<nsIContent> content = mContent;
-
-  // Deselect ourselves.
-  SelectMenu(PR_FALSE);
-  ENSURE_TRUE(weakFrame.IsAlive());
-
-  // Now hide all of the open menus.
-  if (mMenuParent) {
-    mMenuParent->HideChain();
-
-    // Since menu was not dismissed via click outside menu
-    // we don't want to keep track of this rollup.
-    // Otherwise, we keep track so that the same click 
-    // won't both dismiss and then reopen a menu.
-    mMenuParent->ClearRecentlyRolledUp();
-  }
-
-
-  nsEventStatus status = nsEventStatus_eIgnore;
-  // 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).
-  nsXULCommandEvent event(aEvent ? NS_IS_TRUSTED_EVENT(aEvent) :
-                          nsContentUtils::IsCallerChrome(),
-                          NS_XUL_COMMAND, nsnull);
-  if (aEvent && (aEvent->eventStructType == NS_MOUSE_EVENT ||
-                 aEvent->eventStructType == NS_KEY_EVENT ||
-                 aEvent->eventStructType == NS_ACCESSIBLE_EVENT)) {
-
-    event.isShift = NS_STATIC_CAST(nsInputEvent *, aEvent)->isShift;
-    event.isControl = NS_STATIC_CAST(nsInputEvent *, aEvent)->isControl;
-    event.isAlt = NS_STATIC_CAST(nsInputEvent *, aEvent)->isAlt;
-    event.isMeta = NS_STATIC_CAST(nsInputEvent *, aEvent)->isMeta;
-  }
-
-  // The order of the nsIViewManager and nsIPresShell COM pointers is
-  // important below.  We want the pres shell to get released before the
-  // associated view manager on exit from this function.
-  // See bug 54233.
-  nsPresContext* presContext = PresContext();
-  nsCOMPtr<nsIViewManager> kungFuDeathGrip = presContext->GetViewManager();
-  nsCOMPtr<nsIPresShell> shell = presContext->GetPresShell();
-  if (shell) {
-    shell->HandleDOMEventWithTarget(mContent, &event, &status);
-    ENSURE_TRUE(weakFrame.IsAlive());
-  }
-
-  if (mMenuParent) {
-    mMenuParent->DismissChain();
-  }
-
-  // Re-enable rollup events on this menu.
-  if ( nsMenuDismissalListener::sInstance ) {
-    nsMenuDismissalListener::sInstance->EnableListener(PR_TRUE);
-  }
-}
-
-PRBool
-nsMenuFrame::OnCreate()
-{
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING, nsnull,
-                     nsMouseEvent::eReal);
-
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  nsresult rv = NS_OK;
-
-  nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
-  if (shell) {
-    if (child) {
-      rv = shell->HandleDOMEventWithTarget(child, &event, &status);
-    }
-    else {
-      rv = shell->HandleDOMEventWithTarget(mContent, &event, &status);
-    }
-  }
-
-  if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
-    return PR_FALSE;
-
-  // The menu is going to show, and the create handler has executed.
-  // We should now walk all of our menu item children, checking to see if any
-  // of them has a command attribute.  If so, then several attributes must
-  // potentially be updated.
-  if (child) {
-    nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(child->GetDocument()));
-
-    PRUint32 count = child->GetChildCount();
-    for (PRUint32 i = 0; i < count; i++) {
-      nsCOMPtr<nsIContent> grandChild = child->GetChildAt(i);
-
-      if (grandChild->Tag() == nsGkAtoms::menuitem) {
-        // See if we have a command attribute.
-        nsAutoString command;
-        grandChild->GetAttr(kNameSpaceID_None, nsGkAtoms::command, command);
-        if (!command.IsEmpty()) {
-          // We do! Look it up in our document
-          nsCOMPtr<nsIDOMElement> commandElt;
-          domDoc->GetElementById(command, getter_AddRefs(commandElt));
-          nsCOMPtr<nsIContent> commandContent(do_QueryInterface(commandElt));
-
-          if ( commandContent ) {
-            nsAutoString commandAttr;
-            // The menu's disabled state needs to be updated to match the command.
-            if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandAttr))
-              grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandAttr, PR_TRUE);
-            else
-              grandChild->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, PR_TRUE);
-
-            // The menu's label, accesskey and checked states need to be updated
-            // to match the command. Note that unlike the disabled state if the
-            // command has *no* value, we assume the menu is supplying its own.
-            if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandAttr))
-              grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, commandAttr, PR_TRUE);
-
-            if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandAttr))
-              grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, commandAttr, PR_TRUE);
-
-            if (commandContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, commandAttr))
-              grandChild->SetAttr(kNameSpaceID_None, nsGkAtoms::label, commandAttr, PR_TRUE);
-          }
-        }
       }
     }
   }
 
-  return PR_TRUE;
-}
-
-PRBool
-nsMenuFrame::OnCreated()
-{
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWN, nsnull,
-                     nsMouseEvent::eReal);
-
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
-  if (shell) {
-    if (child) {
-      rv = shell->HandleDOMEventWithTarget(child, &event, &status);
-    }
-    else {
-      rv = shell->HandleDOMEventWithTarget(mContent, &event, &status);
-    }
-  }
-
-  if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
-    return PR_FALSE;
-  return PR_TRUE;
-}
-
-PRBool
-nsMenuFrame::OnDestroy()
-{
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDING, nsnull,
-                     nsMouseEvent::eReal);
-
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
-  if (shell) {
-    if (child) {
-      rv = shell->HandleDOMEventWithTarget(child, &event, &status);
-    }
-    else {
-      rv = shell->HandleDOMEventWithTarget(mContent, &event, &status);
-    }
-  }
-
-  if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
-    return PR_FALSE;
-  return PR_TRUE;
-}
-
-PRBool
-nsMenuFrame::OnDestroyed()
-{
-  nsEventStatus status = nsEventStatus_eIgnore;
-  nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDDEN, nsnull,
-                     nsMouseEvent::eReal);
-
-  nsCOMPtr<nsIContent> child;
-  GetMenuChildrenElement(getter_AddRefs(child));
-  
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
-  if (shell) {
-    if (child) {
-      rv = shell->HandleDOMEventWithTarget(child, &event, &status);
-    }
-    else {
-      rv = shell->HandleDOMEventWithTarget(mContent, &event, &status);
-    }
-  }
-
-  if ( NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault )
-    return PR_FALSE;
-  return PR_TRUE;
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (pm && mMenuParent)
+    pm->ExecuteMenu(mContent, aEvent);
 }
 
 NS_IMETHODIMP
 nsMenuFrame::RemoveFrame(nsIAtom*        aListName,
                          nsIFrame*       aOldFrame)
 {
-  nsresult  rv;
+  nsresult rv =  NS_OK;
 
-  if (mPopupFrames.ContainsFrame(aOldFrame)) {
+  if (mPopupFrame == aOldFrame) {
     // Go ahead and remove this frame.
-    mPopupFrames.DestroyFrame(aOldFrame);
+    mPopupFrame->Destroy();
+    mPopupFrame = nsnull;
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                        NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = NS_OK;
   } else {
     rv = nsBoxFrame::RemoveFrame(aListName, aOldFrame);
   }
 
@@ -1888,23 +1133,21 @@ nsMenuFrame::RemoveFrame(nsIAtom*       
 
 NS_IMETHODIMP
 nsMenuFrame::InsertFrames(nsIAtom*        aListName,
                           nsIFrame*       aPrevFrame,
                           nsIFrame*       aFrameList)
 {
   nsresult          rv;
 
-  nsIMenuParent *menuPar;
-  if (aFrameList && NS_SUCCEEDED(CallQueryInterface(aFrameList, &menuPar))) {
-    NS_ASSERTION(aFrameList->IsBoxFrame(),"Popup is not a box!!!");
-    mPopupFrames.InsertFrames(nsnull, nsnull, aFrameList);
+  if (!mPopupFrame && aFrameList->GetType() == nsGkAtoms::menuPopupFrame) {
+    mPopupFrame = NS_STATIC_CAST(nsMenuPopupFrame *, aFrameList);
 
 #ifdef DEBUG_LAYOUT
-    nsBoxLayoutState state(GetPresContext());
+    nsBoxLayoutState state(PresContext());
     SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
 #endif
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                        NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = NS_OK;
   } else {
     rv = nsBoxFrame::InsertFrames(aListName, aPrevFrame, aFrameList);  
@@ -1917,99 +1160,44 @@ NS_IMETHODIMP
 nsMenuFrame::AppendFrames(nsIAtom*        aListName,
                           nsIFrame*       aFrameList)
 {
   if (!aFrameList)
     return NS_OK;
 
   nsresult          rv;
 
-  nsIMenuParent *menuPar;
-  if (aFrameList && NS_SUCCEEDED(CallQueryInterface(aFrameList, &menuPar))) {
-    NS_ASSERTION(aFrameList->IsBoxFrame(),"Popup is not a box!!!");
+  if (!mPopupFrame && aFrameList->GetType() == nsGkAtoms::menuPopupFrame) {
+    mPopupFrame = NS_STATIC_CAST(nsMenuPopupFrame *, aFrameList);
 
-    mPopupFrames.AppendFrames(nsnull, aFrameList);
 #ifdef DEBUG_LAYOUT
-    nsBoxLayoutState state(GetPresContext());
+    nsBoxLayoutState state(PresContext());
     SetDebug(state, aFrameList, mState & NS_STATE_CURRENTLY_IN_DEBUG);
 #endif
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                        NS_FRAME_HAS_DIRTY_CHILDREN);
     rv = NS_OK;
   } else {
     rv = nsBoxFrame::AppendFrames(aListName, aFrameList); 
   }
 
   return rv;
 }
 
-class nsASyncMenuGeneration : public nsIReflowCallback
-{
-public:
-  nsASyncMenuGeneration(nsIFrame* aFrame)
-    : mWeakFrame(aFrame)
-  {
-    nsIContent* content = aFrame ? aFrame->GetContent() : nsnull;
-    mDocument = content ? content->GetCurrentDoc() : nsnull;
-    if (mDocument) {
-      mDocument->BlockOnload();
-    }
-  }
-
-  virtual PRBool ReflowFinished() {
-    PRBool shouldFlush = PR_FALSE;
-    nsIFrame* frame = mWeakFrame.GetFrame();
-    if (frame) {
-      nsBoxLayoutState state(frame->PresContext());
-      if (!frame->IsCollapsed(state)) {
-        nsIMenuFrame* imenu = nsnull;
-        CallQueryInterface(frame, &imenu);
-        if (imenu) {
-          imenu->MarkAsGenerated();
-          shouldFlush = PR_TRUE;
-        }
-      }
-    }
-    if (mDocument) {
-      mDocument->UnblockOnload(PR_FALSE);
-    }
-    delete this;
-    return shouldFlush;
-  }
-
-  nsWeakFrame           mWeakFrame;
-  nsCOMPtr<nsIDocument> mDocument;
-};
-
 PRBool
 nsMenuFrame::SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize)
 {
   if (!IsCollapsed(aState)) {
     nsSize tmpSize(-1, 0);
     nsIBox::AddCSSPrefSize(aState, this, tmpSize);
     if (tmpSize.width == -1 && GetFlex(aState) == 0) {
-      nsIFrame* frame = mPopupFrames.FirstChild();
-      if (!frame) {
-        nsCOMPtr<nsIContent> child;
-        GetMenuChildrenElement(getter_AddRefs(child));
-        if (child &&
-            !nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None,
-                                             nsGkAtoms::menugenerated)) {
-          nsIReflowCallback* cb = new nsASyncMenuGeneration(this);
-          if (cb) {
-            PresContext()->PresShell()->PostReflowCallback(cb);
-          }
-        }
+      if (!mPopupFrame)
         return PR_FALSE;
-      }
-
-      NS_ASSERTION(frame->IsBoxFrame(), "popupChild is not box!!");
-
-      tmpSize = frame->GetPrefSize(aState);
+      tmpSize = mPopupFrame->GetPrefSize(aState);
       aSize.width = tmpSize.width;
       return PR_TRUE;
     }
   }
 
   return PR_FALSE;
 }
 
@@ -2031,129 +1219,60 @@ nsMenuFrame::GetPrefSize(nsBoxLayoutStat
   }
 
   return size;
 }
 
 NS_IMETHODIMP
 nsMenuFrame::GetActiveChild(nsIDOMElement** aResult)
 {
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
-  if (!frame)
+  if (!mPopupFrame)
     return NS_ERROR_FAILURE;
 
-  nsIMenuFrame* menuFrame = menuPopup->GetCurrentMenuItem();
-  
+  nsMenuFrame* menuFrame = mPopupFrame->GetCurrentMenuItem();
   if (!menuFrame) {
     *aResult = nsnull;
   }
   else {
-    nsIFrame* f;
-    menuFrame->QueryInterface(NS_GET_IID(nsIFrame), (void**)&f);
-    nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(f->GetContent()));
+    nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(menuFrame->GetContent()));
     *aResult = elt;
     NS_IF_ADDREF(*aResult);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMenuFrame::SetActiveChild(nsIDOMElement* aChild)
 {
-  nsIFrame* frame = mPopupFrames.FirstChild();
-  nsMenuPopupFrame* menuPopup = (nsMenuPopupFrame*)frame;
-  if (!frame)
+  if (!mPopupFrame)
     return NS_ERROR_FAILURE;
 
   if (!aChild) {
     // Remove the current selection
-    menuPopup->SetCurrentMenuItem(nsnull);
+    mPopupFrame->ChangeMenuItem(nsnull, PR_FALSE);
     return NS_OK;
   }
 
   nsCOMPtr<nsIContent> child(do_QueryInterface(aChild));
-  
+
   nsIFrame* kid = PresContext()->PresShell()->GetPrimaryFrameFor(child);
-  if (!kid)
-    return NS_ERROR_FAILURE;
-  nsIMenuFrame *menuFrame;
-  nsresult rv = CallQueryInterface(kid, &menuFrame);
-  if (NS_FAILED(rv))
-    return rv;
-  menuPopup->SetCurrentMenuItem(menuFrame);
+  if (kid && kid->GetType() == nsGkAtoms::menuFrame)
+    mPopupFrame->ChangeMenuItem(NS_STATIC_CAST(nsMenuFrame *, kid), PR_FALSE);
   return NS_OK;
 }
 
 nsIScrollableView* nsMenuFrame::GetScrollableView()
 {
-  if (!mPopupFrames.FirstChild())
+  if (!mPopupFrame)
     return nsnull;
 
-  nsMenuPopupFrame* popup = (nsMenuPopupFrame*) mPopupFrames.FirstChild();
-  nsIFrame* childFrame = popup->GetFirstChild(nsnull);
-  if (childFrame) {
-    return popup->GetScrollableView(childFrame);
-  }
-  return nsnull;
-}
-
-/* Need to figure out what this does.
-NS_IMETHODIMP
-nsMenuFrame::GetBoxInfo(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsBoxInfo& aSize)
-{
-  nsresult rv = nsBoxFrame::GetBoxInfo(aPresContext, aReflowState, aSize);
-  nsCOMPtr<nsIDOMXULMenuListElement> menulist(do_QueryInterface(mContent));
-  if (menulist) {
-    nsCalculatedBoxInfo boxInfo(this);
-    boxInfo.prefSize.width = NS_UNCONSTRAINEDSIZE;
-    boxInfo.prefSize.height = NS_UNCONSTRAINEDSIZE;
-    boxInfo.flex = 0;
-    GetRedefinedMinPrefMax(aPresContext, this, boxInfo);
-    if (boxInfo.prefSize.width == NS_UNCONSTRAINEDSIZE &&
-        boxInfo.prefSize.height == NS_UNCONSTRAINEDSIZE &&
-        boxInfo.flex == 0) {
-      nsIFrame* frame = mPopupFrames.FirstChild();
-      if (!frame) {
-        MarkAsGenerated();
-        frame = mPopupFrames.FirstChild();
-      }
-      
-      nsCalculatedBoxInfo childInfo(frame);
-      frame->GetBoxInfo(aPresContext, aReflowState, childInfo);
-      GetRedefinedMinPrefMax(aPresContext, this, childInfo);
-      aSize.prefSize.width = childInfo.prefSize.width;
-    }
-
-    // This retrieval guarantess that the selectedItem will
-    // be set before we lay out.
-    nsCOMPtr<nsIDOMElement> element;
-    menulist->GetSelectedItem(getter_AddRefs(element));
-  }
-  return rv;
-}
-*/
-
-nsIMenuParent*
-nsMenuFrame::GetContextMenu()
-{
-  if (!nsMenuDismissalListener::sInstance)
-    return nsnull;
-
-  nsIMenuParent *menuParent =
-    nsMenuDismissalListener::sInstance->GetCurrentMenuParent();
-  if (!menuParent)
-    return nsnull;
-
-  PRBool isContextMenu;
-  menuParent->GetIsContextMenu(isContextMenu);
-  if (isContextMenu)
-    return menuParent;
-
+  nsIFrame* childFrame = mPopupFrame->GetFirstChild(nsnull);
+  if (childFrame)
+    return mPopupFrame->GetScrollableView(childFrame);
   return nsnull;
 }
 
 // nsMenuTimerMediator implementation.
 NS_IMPL_ISUPPORTS1(nsMenuTimerMediator, nsITimerCallback)
 
 /**
  * Constructs a wrapper around an nsMenuFrame.
--- a/layout/xul/base/src/nsMenuFrame.h
+++ b/layout/xul/base/src/nsMenuFrame.h
@@ -44,33 +44,44 @@
 #define nsMenuFrame_h__
 
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsCOMPtr.h"
 
 #include "nsBoxFrame.h"
 #include "nsFrameList.h"
+#include "nsGkAtoms.h"
 #include "nsIMenuParent.h"
 #include "nsIMenuFrame.h"
-#include "nsMenuDismissalListener.h"
+#include "nsXULPopupManager.h"
 #include "nsITimer.h"
 #include "nsISupportsArray.h"
 #include "nsIDOMText.h"
 #include "nsIContent.h"
 #include "nsIScrollableViewProvider.h"
 
 nsIFrame* NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
 
 class nsMenuBarFrame;
-class nsMenuPopupFrame;
 class nsIScrollableView;
 
 #define NS_STATE_ACCELTEXT_IS_DERIVED  NS_STATE_BOX_CHILD_RESERVED
 
+// the type of menuitem
+enum nsMenuType {
+  // a normal menuitem where a command is carried out when activated
+  eMenuType_Normal = 0,
+  // a menuitem with a checkmark that toggles when activated
+  eMenuType_Checkbox = 1,
+  // a radio menuitem where only one of it and its siblings with the same
+  // name attribute can be checked at a time
+  eMenuType_Radio = 2
+};
+
 class nsMenuFrame;
 
 /**
  * nsMenuTimerMediator is a wrapper around an nsMenuFrame which can be safely
  * passed to timers. The class is reference counted unlike the underlying
  * nsMenuFrame, so that it will exist as long as the timer holds a reference
  * to it. The callback is delegated to the contained nsMenuFrame as long as
  * the contained nsMenuFrame has not been destroyed.
@@ -88,17 +99,17 @@ public:
 
 private:
 
   // Pointer to the wrapped frame.
   nsMenuFrame* mFrame;
 };
 
 /**
- * @note *** Methods marked with '@see comment ***' may cause the frame to be
+ * @note *** Methods marked with '@see comment above ***' may cause the frame to be
  *           deleted during the method call. Be careful whenever using those
  *           methods.
  */
 
 class nsMenuFrame : public nsBoxFrame, 
                     public nsIMenuFrame,
                     public nsIScrollableViewProvider
 {
@@ -117,164 +128,161 @@ public:
                   nsIFrame*        aPrevInFlow);
 
 #ifdef DEBUG_LAYOUT
   NS_IMETHOD SetDebug(nsBoxLayoutState& aState, PRBool aDebug);
 #endif
 
   NS_IMETHOD IsActive(PRBool& aResult) { aResult = PR_TRUE; return NS_OK; }
 
-  // The following four methods are all overridden so that the menu children
-  // can be stored in a separate list (so that they don't impact reflow of the
-  // actual menu item at all).
+  // The following methods are all overridden so that the menupopup
+  // can be stored in a separate list, so that it doesn't impact reflow of the
+  // actual menu item at all.
   virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
   NS_IMETHOD SetInitialChildList(nsIAtom*        aListName,
                                  nsIFrame*       aChildList);
   virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
-  virtual void Destroy(); // @see comment ***
+  virtual void Destroy(); // @see comment above ***
 
   // Overridden to prevent events from going to children of the menu.
   NS_IMETHOD BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                          const nsRect&           aDirtyRect,
                                          const nsDisplayListSet& aLists);
                                          
   NS_IMETHOD HandleEvent(nsPresContext* aPresContext, 
                          nsGUIEvent*     aEvent,
-                         nsEventStatus*  aEventStatus); // @see comment ***
+                         nsEventStatus*  aEventStatus); // @see comment above ***
 
   NS_IMETHOD  AppendFrames(nsIAtom*        aListName,
                            nsIFrame*       aFrameList);
 
   NS_IMETHOD  InsertFrames(nsIAtom*        aListName,
                            nsIFrame*       aPrevFrame,
                            nsIFrame*       aFrameList);
 
   NS_IMETHOD  RemoveFrame(nsIAtom*        aListName,
                           nsIFrame*       aOldFrame);
 
-  // nsIMenuFrame Interface
+  virtual nsIAtom* GetType() const { return nsGkAtoms::menuFrame; }
 
-  NS_IMETHOD ActivateMenu(PRBool aActivateFlag); // @see comment ***
-  NS_IMETHOD SelectMenu(PRBool aActivateFlag); // @see comment ***
-  NS_IMETHOD OpenMenu(PRBool aActivateFlag); // @see comment ***
+  NS_IMETHOD SelectMenu(PRBool aActivateFlag); // @see comment above ***
 
-  NS_IMETHOD MenuIsOpen(PRBool& aResult) { aResult = IsOpen(); return NS_OK; }
-  NS_IMETHOD MenuIsContainer(PRBool& aResult) { aResult = IsMenu(); return NS_OK; }
-  NS_IMETHOD MenuIsChecked(PRBool& aResult) { aResult = mChecked; return NS_OK; }
-  NS_IMETHOD MenuIsDisabled(PRBool& aResult) { aResult = IsDisabled(); return NS_OK; }
-  
-  NS_IMETHOD GetActiveChild(nsIDOMElement** aResult);
-  NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); // @see comment ***
+  /**
+   * NOTE: OpenMenu will open the menu synchronously. Don't call this if a frame
+   *       is manipulated afterwards without checking to make sure it is still alive.
+   *       All current calls to OpenMenu do not adjust the frame.
+   */
+  void OpenMenu(PRBool aSelectFirstItem);
+  // CloseMenu closes the menu asynchronously
+  void CloseMenu(PRBool aDeselectMenu);
 
-  NS_IMETHOD UngenerateMenu(); // @see comment ***
+  PRBool IsChecked() { return mChecked; }
 
-  NS_IMETHOD SelectFirstItem(); // @see comment ***
+  NS_IMETHOD GetActiveChild(nsIDOMElement** aResult);
+  NS_IMETHOD SetActiveChild(nsIDOMElement* aChild); // @see comment above ***
 
-  NS_IMETHOD Escape(PRBool& aHandledFlag); // @see comment ***
-  NS_IMETHOD Enter(); // @see comment ***
-  NS_IMETHOD ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag); // @see comment ***
-  NS_IMETHOD KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag); // @see comment ***
+  // called when the Enter key is pressed while the menuitem is the current
+  // one in its parent popup. This will carry out the command attached to
+  // the menuitem.
+  nsMenuFrame* Enter();
 
   NS_IMETHOD SetParent(const nsIFrame* aParent);
 
   virtual nsIMenuParent *GetMenuParent() { return mMenuParent; }
-  virtual nsIFrame *GetMenuChild() { return mPopupFrames.FirstChild(); }
-  NS_IMETHOD GetRadioGroupName(nsString &aName) { aName = mGroupName; return NS_OK; }
-  NS_IMETHOD GetMenuType(nsMenuType &aType) { aType = mType; return NS_OK; }
-  NS_IMETHOD MarkAsGenerated();
+  const nsAString& GetRadioGroupName() { return mGroupName; }
+  nsMenuType GetMenuType() { return mType; }
+  nsMenuPopupFrame* GetPopup() { return mPopupFrame; }
 
   // nsIScrollableViewProvider methods
 
   virtual nsIScrollableView* GetScrollableView();
 
   // nsMenuFrame methods 
 
   nsresult DestroyPopupFrames(nsPresContext* aPresContext);
 
-  PRBool IsOpen() { return mMenuOpen; }
-  PRBool IsMenu();
+  virtual PRBool IsOnMenuBar() { return mMenuParent && mMenuParent->IsMenuBar(); }
+  virtual PRBool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); }
+  virtual PRBool IsOpen();
+  virtual PRBool IsMenu();
   PRBool IsDisabled();
   PRBool IsGenerated();
-  NS_IMETHOD ToggleMenuState(); // @see comment ***
+  void ToggleMenuState();
 
+  // indiciate that the menu's popup has just been opened, so that the menu
+  // can update its open state. This method modifies the open attribute on
+  // the menu, so the frames could be gone after this call
+  void PopupOpened();
+  // indiciate that the menu's popup has just been closed, so that the menu
+  // can update its open state. The menu should be unhighlighted if
+  // aDeselectedMenu is true.
+  void PopupClosed(PRBool aDeselectMenu);
+
+  // returns true if this is a menu on another menu popup. A menu is a submenu
+  // if it has a parent popup or menupopup.
+  PRBool IsOnMenu() { return mMenuParent && mMenuParent->IsMenu(); }
   void SetIsMenu(PRBool aIsMenu) { mIsMenu = aIsMenu; }
 
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const
   {
       return MakeFrameName(NS_LITERAL_STRING("Menu"), aResult);
   }
 #endif
 
   static PRBool IsSizedToPopup(nsIContent* aContent, PRBool aRequireAlways);
 
-  static nsIMenuParent *GetContextMenu();
-
 protected:
   friend class nsMenuTimerMediator;
-  
-  virtual void RePositionPopup(nsBoxLayoutState& aState);
-
-  void
-  ConvertPosition(nsIContent* aPopupElt, nsString& aAnchor, nsString& aAlign);
+  friend class nsASyncMenuInitialization;
 
-  friend class nsASyncMenuInitialization;
-  void UpdateMenuType(nsPresContext* aPresContext); // @see comment ***
-  void UpdateMenuSpecialState(nsPresContext* aPresContext); // @see comment ***
+  // set mMenuParent to the nearest enclosing menu bar or menupopup frame of
+  // aParent (or aParent itself). This is called when initializing the frame,
+  // so aParent should be the expected parent of this frame.
+  void InitMenuParent(nsIFrame* aParent);
 
-  void OpenMenuInternal(PRBool aActivateFlag); // @see comment ***
-  void GetMenuChildrenElement(nsIContent** aResult);
+  void UpdateMenuType(nsPresContext* aPresContext); // @see comment above ***
+  void UpdateMenuSpecialState(nsPresContext* aPresContext); // @see comment above ***
 
   // Examines the key node and builds the accelerator.
   void BuildAcceleratorText();
 
   // Called to execute our command handler.
-  void Execute(nsGUIEvent *aEvent); // @see comment ***
-
-  // Called as a hook just before the menu gets opened.
-  PRBool OnCreate(); // @see comment ***
-
-  // Called as a hook just after the menu gets opened.
-  PRBool OnCreated(); // @see comment ***
-
-  // Called as a hook just before the menu goes away.
-  PRBool OnDestroy(); // @see comment ***
-
-  // Called as a hook just after the menu goes away.
-  PRBool OnDestroyed(); // @see comment ***
+  void Execute(nsGUIEvent *aEvent); // @see comment above ***
 
   NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
                               nsIAtom* aAttribute,
-                              PRInt32 aModType); // @see comment ***
+                              PRInt32 aModType); // @see comment above ***
   virtual ~nsMenuFrame();
 
   PRBool SizeToPopup(nsBoxLayoutState& aState, nsSize& aSize);
 
 protected:
 #ifdef DEBUG_LAYOUT
   nsresult SetDebug(nsBoxLayoutState& aState, nsIFrame* aList, PRBool aDebug);
 #endif
   NS_HIDDEN_(nsresult) Notify(nsITimer* aTimer);
 
-  nsFrameList mPopupFrames;
   PRPackedBool mIsMenu; // Whether or not we can even have children or not.
-  PRPackedBool mMenuOpen;
-  PRPackedBool mCreateHandlerSucceeded;  // Did the create handler succeed?
   PRPackedBool mChecked;              // are we checked?
   nsMenuType mType;
 
   nsIMenuParent* mMenuParent; // Our parent menu.
 
+  // the popup for this menu, owned
+  nsMenuPopupFrame* mPopupFrame;
+
+  nsSize mLastPref;
+
   // Reference to the mediator which wraps this frame.
   nsRefPtr<nsMenuTimerMediator> mTimerMediator;
 
   nsCOMPtr<nsITimer> mOpenTimer;
 
   nsString mGroupName;
-  nsSize mLastPref;
   
   //we load some display strings from platformKeys.properties only once
   static nsrefcnt gRefCnt; 
   static nsString *gShiftText;
   static nsString *gControlText;
   static nsString *gMetaText;
   static nsString *gAltText;
   static nsString *gModifierSeparator;
deleted file mode 100644
--- a/layout/xul/base/src/nsMenuListener.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Original Author: David W. Hyatt (hyatt@netscape.com)
- *   Dean Tessman <dean_tessman@hotmail.com>
- *   Mark Hammond <markh@ActiveState.com>
- *
- * 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"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsMenuListener.h"
-#include "nsMenuBarFrame.h"
-#include "nsIDOMKeyListener.h"
-#include "nsIDOMEventTarget.h"
-#include "nsIDOMEventListener.h"
-#include "nsIDOMNSUIEvent.h"
-#include "nsGUIEvent.h"
-
-// Drag & Drop, Clipboard
-#include "nsIServiceManager.h"
-#include "nsWidgetsCID.h"
-#include "nsCOMPtr.h"
-#include "nsIDOMKeyEvent.h"
-#include "nsIDOMNSEvent.h"
-#include "nsPresContext.h"
-#include "nsIContent.h"
-#include "nsIDOMNode.h"
-#include "nsIDOMElement.h"
-
-#include "nsIEventStateManager.h"
-
-#include "nsISupportsArray.h"
-
-/*
- * nsMenuListener implementation
- */
-
-NS_IMPL_ADDREF(nsMenuListener)
-NS_IMPL_RELEASE(nsMenuListener)
-NS_IMPL_QUERY_INTERFACE3(nsMenuListener, nsIDOMKeyListener, nsIDOMFocusListener, nsIDOMMouseListener)
-
-
-////////////////////////////////////////////////////////////////////////
-
-nsMenuListener::nsMenuListener(nsIMenuParent* aMenuParent) 
-{
-  mMenuParent = aMenuParent;
-}
-
-////////////////////////////////////////////////////////////////////////
-nsMenuListener::~nsMenuListener() 
-{
-}
-
-
-
-////////////////////////////////////////////////////////////////////////
-nsresult
-nsMenuListener::KeyUp(nsIDOMEvent* aKeyEvent)
-{
-  aKeyEvent->StopPropagation();
-  aKeyEvent->PreventDefault();
-
-  return NS_ERROR_BASE; // I am consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult
-nsMenuListener::KeyDown(nsIDOMEvent* aKeyEvent)
-{
-  PRInt32 menuAccessKey = -1;
-  
-  // If the key just pressed is the access key (usually Alt),
-  // dismiss and unfocus the menu.
-
-  nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
-  if (menuAccessKey) {
-    PRUint32 theChar;
-    nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
-    keyEvent->GetKeyCode(&theChar);
-
-    if (theChar == (PRUint32)menuAccessKey) {
-      // No other modifiers can be down.
-      // Especially CTRL.  CTRL+ALT == AltGR, and
-      // we'll fuck up on non-US enhanced 102-key
-      // keyboards if we don't check this.
-      PRBool ctrl = PR_FALSE;
-      if (menuAccessKey != nsIDOMKeyEvent::DOM_VK_CONTROL)
-        keyEvent->GetCtrlKey(&ctrl);
-      PRBool alt=PR_FALSE;
-      if (menuAccessKey != nsIDOMKeyEvent::DOM_VK_ALT)
-        keyEvent->GetAltKey(&alt);
-      PRBool shift=PR_FALSE;
-      if (menuAccessKey != nsIDOMKeyEvent::DOM_VK_SHIFT)
-        keyEvent->GetShiftKey(&shift);
-      PRBool meta=PR_FALSE;
-      if (menuAccessKey != nsIDOMKeyEvent::DOM_VK_META)
-        keyEvent->GetMetaKey(&meta);
-      if (!(ctrl || alt || shift || meta)) {
-        // The access key just went down and no other
-        // modifiers are already down.
-        mMenuParent->DismissChain();
-      }
-    }
-  }
-
-  // Since a menu was open, eat the event to keep other event
-  // listeners from becoming confused.
-  aKeyEvent->StopPropagation();
-  aKeyEvent->PreventDefault();
-  return NS_ERROR_BASE; // I am consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult
-nsMenuListener::KeyPress(nsIDOMEvent* aKeyEvent)
-{
-  // Don't check prevent default flag -- menus always get first shot at key events.
-  // When a menu is open, the prevent default flag on a keypress is always set, so
-  // that no one else uses the key event.
-
-  //handlers shouldn't be triggered by non-trusted events.
-  nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aKeyEvent);
-  PRBool trustedEvent = PR_FALSE;
-
-  if (domNSEvent) {
-    domNSEvent->GetIsTrusted(&trustedEvent);
-  }
-
-  if (!trustedEvent)
-    return NS_OK;
-
-  nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aKeyEvent);
-  PRUint32 theChar;
-	keyEvent->GetKeyCode(&theChar);
-  PRBool handled = PR_FALSE;
-
-  if (theChar == NS_VK_LEFT ||
-      theChar == NS_VK_RIGHT ||
-      theChar == NS_VK_UP ||
-      theChar == NS_VK_DOWN ||
-      theChar == NS_VK_HOME ||
-      theChar == NS_VK_END) {
-    // The navigation keys were pressed. User is moving around within
-    // the menus.
-	  mMenuParent->KeyboardNavigation(theChar, handled);
-  }
-  else if (theChar == NS_VK_ESCAPE) {
-    // Close one level.
-    // Prevents us from getting destroyed by Escape(), we need to return to ourselves
-    NS_ADDREF_THIS();
-	  mMenuParent->Escape(handled);
-    NS_RELEASE_THIS();
-    if (!handled)
-      mMenuParent->DismissChain();
-  }
-  else if (theChar == NS_VK_TAB)
-    mMenuParent->DismissChain();
-  else if (theChar == NS_VK_ENTER ||
-           theChar == NS_VK_RETURN) {
-    // Open one level.
-    mMenuParent->Enter();
-  }
-#if !defined(XP_MAC) && !defined(XP_MACOSX)
-  else if (theChar == NS_VK_F10) {
-    // doesn't matter what modifier keys are down in Non-Mac platform
-    // if the menu bar is active and F10 is pressed - deactivate it
-    mMenuParent->DismissChain();
-  }
-#endif // !XP_MAC && !XP_MACOSX
-  else {
-    PRInt32 menuAccessKey = -1;
-    nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
-    if (menuAccessKey) {
-      // Do shortcut navigation.
-      // A letter was pressed. We want to see if a shortcut gets matched. If
-      // so, we'll know the menu got activated.
-      mMenuParent->ShortcutNavigation(keyEvent, handled);
-    }
-  }
-
-  aKeyEvent->StopPropagation();
-  aKeyEvent->PreventDefault();
-  return NS_ERROR_BASE; // I am consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-
-nsresult
-nsMenuListener::Focus(nsIDOMEvent* aEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult
-nsMenuListener::Blur(nsIDOMEvent* aEvent)
-{
-  
-  return NS_OK; // means I am NOT consuming event
-}
-  
-////////////////////////////////////////////////////////////////////////
-nsresult 
-nsMenuListener::MouseDown(nsIDOMEvent* aMouseEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult 
-nsMenuListener::MouseUp(nsIDOMEvent* aMouseEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-nsresult 
-nsMenuListener::MouseClick(nsIDOMEvent* aMouseEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult 
-nsMenuListener::MouseDblClick(nsIDOMEvent* aMouseEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult 
-nsMenuListener::MouseOver(nsIDOMEvent* aMouseEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult 
-nsMenuListener::MouseOut(nsIDOMEvent* aMouseEvent)
-{
-  return NS_OK; // means I am NOT consuming event
-}
-
-////////////////////////////////////////////////////////////////////////
-nsresult
-nsMenuListener::HandleEvent(nsIDOMEvent* aEvent)
-{
-  return NS_OK;
-}
-
-
deleted file mode 100644
--- a/layout/xul/base/src/nsMenuListener.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * 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"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-#ifndef nsMenuListener_h__
-#define nsMenuListener_h__
-
-#include "nsIDOMMouseMotionListener.h"
-#include "nsIDOMMouseListener.h"
-#include "nsIDOMKeyListener.h"
-#include "nsIDOMFocusListener.h"
-#include "nsIDOMEventTarget.h"
-
-class nsIMenuParent;
-class nsPresContext;
-
-/** editor Implementation of the DragListener interface
- */
-class nsMenuListener : public nsIDOMKeyListener, public nsIDOMFocusListener, public nsIDOMMouseListener
-{
-public:
-  nsMenuListener(nsIMenuParent* aMenuParent);
-  
-  virtual ~nsMenuListener();
-   
-  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
-  
-  NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
-  NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
-  NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
-  
-  NS_IMETHOD Focus(nsIDOMEvent* aEvent);
-  NS_IMETHOD Blur(nsIDOMEvent* aEvent);
-  
-  NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
-  NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
-  
-  NS_DECL_ISUPPORTS
-
-protected:
-  nsIMenuParent* mMenuParent;    // The outermost object capturing events (either a menu bar or menupopup).
-};
-
-
-#endif
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -39,183 +39,165 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 
 #include "nsMenuPopupFrame.h"
 #include "nsGkAtoms.h"
 #include "nsIContent.h"
-#include "nsContentUtils.h"
 #include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsPresContext.h"
 #include "nsStyleContext.h"
 #include "nsCSSRendering.h"
 #include "nsINameSpaceManager.h"
 #include "nsIViewManager.h"
 #include "nsWidgetsCID.h"
 #include "nsMenuFrame.h"
-#include "nsIPopupSetFrame.h"
+#include "nsMenuBarFrame.h"
+#include "nsPopupSetFrame.h"
+#include "nsEventDispatcher.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMScreen.h"
 #include "nsIPresShell.h"
 #include "nsFrameManager.h"
 #include "nsIDocument.h"
 #include "nsIDeviceContext.h"
 #include "nsRect.h"
-#include "nsIDOMXULDocument.h"
 #include "nsILookAndFeel.h"
 #include "nsIComponentManager.h"
 #include "nsBoxLayoutState.h"
 #include "nsIScrollableView.h"
 #include "nsIScrollableFrame.h"
 #include "nsGUIEvent.h"
 #include "nsIRootBox.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
+#include "nsLayoutUtils.h"
 #include "nsCSSFrameConstructor.h"
+#include "nsIEventStateManager.h"
 #include "nsIBoxLayout.h"
 #include "nsIPopupBoxObject.h"
 #include "nsIReflowCallback.h"
 #ifdef XP_WIN
 #include "nsISound.h"
 #endif
 
 const PRInt32 kMaxZ = 0x7fffffff; //XXX: Shouldn't there be a define somewhere for MaxInt for PRInt32
 
-
-static nsIPopupSetFrame*
+static nsPopupSetFrame*
 GetPopupSetFrame(nsPresContext* aPresContext)
 {
   nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresContext->PresShell());
   if (!rootBox)
     return nsnull;
 
-  nsIFrame* popupSetFrame = rootBox->GetPopupSetFrame();
-  if (!popupSetFrame)
-    return nsnull;
-
-  nsIPopupSetFrame* popupSet = nsnull;
-  CallQueryInterface(popupSetFrame, &popupSet);
-  return popupSet;
+  return rootBox->GetPopupSetFrame();
 }
 
-
 // NS_NewMenuPopupFrame
 //
 // Wrapper for creating a new menu popup container
 //
 nsIFrame*
 NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsMenuPopupFrame (aPresShell, aContext);
 }
 
-NS_IMETHODIMP_(nsrefcnt) 
-nsMenuPopupFrame::AddRef(void)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP_(nsrefcnt) 
-nsMenuPopupFrame::Release(void)
-{
-    return NS_OK;
-}
-
-
-//
-// QueryInterface
-//
-NS_INTERFACE_MAP_BEGIN(nsMenuPopupFrame)
-  NS_INTERFACE_MAP_ENTRY(nsIMenuParent)
-NS_INTERFACE_MAP_END_INHERITING(nsBoxFrame)
-
-
 //
 // nsMenuPopupFrame ctor
 //
 nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext)
   :nsBoxFrame(aShell, aContext),
   mCurrentMenu(nsnull),
-  mTimerMenu(nsnull),
-  mCloseTimer(nsnull),
+  mPopupAlignment(POPUPALIGNMENT_NONE),
+  mPopupAnchor(POPUPALIGNMENT_NONE),
+  mPopupType(ePopupTypePanel),
+  mIsOpen(PR_FALSE),
+  mIsOpenChanged(PR_FALSE),
+  mIsOpenPending(PR_FALSE),
+  mIsContextMenu(PR_FALSE),
+  mGeneratedChildren(PR_FALSE),
   mMenuCanOverlapOSBar(PR_FALSE),
   mShouldAutoPosition(PR_TRUE),
-  mShouldRollup(PR_TRUE),
   mConsumeRollupEvent(nsIPopupBoxObject::ROLLUP_DEFAULT),
   mInContentShell(PR_TRUE)
 {
-  SetIsContextMenu(PR_FALSE);   // we're not a context menu by default
 } // ctor
 
 
 NS_IMETHODIMP
 nsMenuPopupFrame::Init(nsIContent*      aContent,
                        nsIFrame*        aParent,
                        nsIFrame*        aPrevInFlow)
 {
   nsresult rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Set up a mediator which can be used for callbacks on this frame.
-  mTimerMediator = new nsMenuPopupTimerMediator(this);
-  if (NS_UNLIKELY(!mTimerMediator))
-    return NS_ERROR_OUT_OF_MEMORY;
-
   nsPresContext* presContext = PresContext();
 
   // lookup if we're allowed to overlap the OS bar (menubar/taskbar) from the
   // look&feel object
   PRBool tempBool;
   presContext->LookAndFeel()->
     GetMetric(nsILookAndFeel::eMetric_MenusCanOverlapOSBar, tempBool);
   mMenuCanOverlapOSBar = tempBool;
 
-  rv = CreateViewForFrame(presContext, this, GetStyleContext(), PR_TRUE);
+  rv = CreateViewForFrame(presContext, this, GetStyleContext(), PR_TRUE, PR_TRUE);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Now that we've made a view, remove it and insert it at the correct
-  // position in the view hierarchy (as the root view).  We do this so that we
-  // can draw the menus outside the confines of the window.
+  // XXX Hack. The popup's view should float above all other views,
+  // so we use the nsIView::SetFloating() to tell the view manager
+  // about that constraint.
   nsIView* ourView = GetView();
   nsIViewManager* viewManager = ourView->GetViewManager();
-
-  // Remove the view from its old position.
-  viewManager->RemoveChild(ourView);
+  viewManager->SetViewFloating(ourView, PR_TRUE);
 
-  // Reinsert ourselves as the root view with a maximum z-index.
-  nsIView* rootView;
-  viewManager->GetRootView(rootView);
-  viewManager->SetViewZIndex(ourView, PR_FALSE, kMaxZ);
-  viewManager->InsertChild(rootView, ourView, nsnull, PR_TRUE);
-
-  // XXX Hack. The menu's view should float above all other views,
-  // so we use the nsIView::SetFloating() to tell the view manager
-  // about that constraint.
-  viewManager->SetViewFloating(ourView, PR_TRUE);
+  mPopupType = ePopupTypePanel;
+  nsIDocument* doc = aContent->GetOwnerDoc();
+  if (doc) {
+    PRInt32 namespaceID;
+    nsCOMPtr<nsIAtom> tag = doc->BindingManager()->ResolveTag(aContent, &namespaceID);
+    if (namespaceID == kNameSpaceID_XUL) {
+      if (tag == nsGkAtoms::menupopup || tag == nsGkAtoms::popup)
+        mPopupType = ePopupTypeMenu;
+      else if (tag == nsGkAtoms::tooltip)
+        mPopupType = ePopupTypeTooltip;
+    }
+  }
 
   nsCOMPtr<nsISupports> cont = PresContext()->GetContainer();
   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont);
   PRInt32 type = -1;
   if (dsti && NS_SUCCEEDED(dsti->GetItemType(&type)) &&
       type == nsIDocShellTreeItem::typeChrome)
     mInContentShell = PR_FALSE;
 
-  // XXX make sure we are hidden (shouldn't this be done automatically?)
-  viewManager->SetViewVisibility(ourView, nsViewVisibility_kHide);
-  if (!ourView->HasWidget()) {
+  // To improve performance, create the widget for the popup only if it is not
+  // a leaf. Leaf popups such as menus will create their widgets later when
+  // the popup opens.
+  if (!IsLeaf() && !ourView->HasWidget()) {
     CreateWidgetForView(ourView);
   }
 
-  MoveToAttributePosition();
+  return rv;
+}
 
-  return rv;
+void
+nsMenuPopupFrame::EnsureWidget()
+{
+  nsIView* ourView = GetView();
+  if (!ourView->HasWidget()) {
+    NS_ASSERTION(!mGeneratedChildren && !GetFirstChild(nsnull),
+                 "Creating widget for MenuPopupFrame with children");
+    CreateWidgetForView(ourView);
+  }
 }
 
 nsresult
 nsMenuPopupFrame::CreateWidgetForView(nsIView* aView)
 {
   // Create a widget for ourselves.
   nsWidgetInitData widgetData;
   widgetData.mWindowType = eWindowType_popup;
@@ -237,16 +219,361 @@ nsMenuPopupFrame::CreateWidgetForView(ns
 #else
   static NS_DEFINE_IID(kCChildCID,  NS_CHILD_CID);
   aView->CreateWidget(kCChildCID, &widgetData, nsnull, PR_TRUE, PR_TRUE);
 #endif
   aView->GetWidget()->SetWindowTranslucency(viewHasTransparentContent);
   return NS_OK;
 }
 
+// this class is used for dispatching popupshowing events asynchronously.
+class nsXULPopupShownEvent : public nsRunnable
+{
+public:
+  nsXULPopupShownEvent(nsIContent *aPopup, nsPresContext* aPresContext)
+    : mPopup(aPopup), mPresContext(aPresContext)
+  {
+  }
+
+  NS_IMETHOD Run()
+  {
+    nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWN, nsnull, nsMouseEvent::eReal);
+    return nsEventDispatcher::Dispatch(mPopup, mPresContext, &event);                 
+  }
+
+private:
+  nsCOMPtr<nsIContent> mPopup;
+  nsRefPtr<nsPresContext> mPresContext;
+};
+
+NS_IMETHODIMP
+nsMenuPopupFrame::SetInitialChildList(nsIAtom* aListName,
+                                      nsIFrame* aChildList)
+{
+  // unless the list is empty, indicate that children have been generated.
+  if (aChildList)
+    mGeneratedChildren = PR_TRUE;
+  return nsBoxFrame::SetInitialChildList(aListName, aChildList);
+}
+
+void
+nsMenuPopupFrame::AdjustView()
+{
+  if (mIsOpen) {
+    // if the popup has just opened, make sure the scrolled window is at 0,0
+    if (mIsOpenChanged) {
+      nsIBox* child = GetChildBox();
+      nsCOMPtr<nsIScrollableFrame> scrollframe(do_QueryInterface(child));
+      if (scrollframe)
+        scrollframe->ScrollTo(nsPoint(0,0));
+    }
+
+    nsIView* view = GetView();
+    nsIViewManager* viewManager = view->GetViewManager();
+    nsRect rect = GetRect();
+    rect.x = rect.y = 0;
+    viewManager->ResizeView(view, rect);
+    viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
+
+    nsPresContext* pc = PresContext();
+    nsContainerFrame::SyncFrameViewProperties(pc, this, nsnull, view, 0);
+
+    // fire popupshown event when the state has changed
+    if (mIsOpenChanged) {
+      mIsOpenChanged = PR_FALSE;
+      nsCOMPtr<nsIRunnable> event = new nsXULPopupShownEvent(GetContent(), pc);
+      NS_DispatchToCurrentThread(event);
+    }
+  }
+}
+
+void
+nsMenuPopupFrame::InitPositionFromAnchorAlign(const nsAString& aAnchor,
+                                              const nsAString& aAlign)
+{
+  if (aAnchor.EqualsLiteral("topleft"))
+    mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
+  else if (aAnchor.EqualsLiteral("topright"))
+    mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
+  else if (aAnchor.EqualsLiteral("bottomleft"))
+    mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
+  else if (aAnchor.EqualsLiteral("bottomright"))
+    mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
+  else
+    mPopupAnchor = POPUPALIGNMENT_NONE;
+
+  if (aAlign.EqualsLiteral("topleft"))
+    mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
+  else if (aAlign.EqualsLiteral("topright"))
+    mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
+  else if (aAlign.EqualsLiteral("bottomleft"))
+    mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
+  else if (aAlign.EqualsLiteral("bottomright"))
+    mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
+  else
+    mPopupAlignment = POPUPALIGNMENT_NONE;
+}
+
+void
+nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
+                                  const nsAString& aPosition,
+                                  PRInt32 aXPos, PRInt32 aYPos,
+                                  PRBool aAttributesOverride)
+{
+  EnsureWidget();
+
+  mIsOpenPending = PR_TRUE;
+  mAnchorContent = aAnchorContent;
+  mXPos = aXPos;
+  mYPos = aYPos;
+
+  // if aAttributesOverride is true, then the popupanchor, popupalign and
+  // position attributes on the <popup> override those values passed in.
+  // If false, those attributes are only used if the values passed in are empty
+  if (aAnchorContent) {
+    nsAutoString anchor, align, position;
+    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupanchor, anchor);
+    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupalign, align);
+    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::position, position);
+
+    if (aAttributesOverride) {
+      // if the attributes are set, clear the offset position. Otherwise,
+      // the offset is used to adjust the position from the anchor point
+      if (anchor.IsEmpty() && align.IsEmpty() && position.IsEmpty())
+        position.Assign(aPosition);
+      else
+        mXPos = mYPos = 0;
+    }
+    else if (!aPosition.IsEmpty()) {
+      position.Assign(aPosition);
+    }
+
+    if (position.EqualsLiteral("before_start")) {
+      mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
+      mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
+    }
+    else if (position.EqualsLiteral("before_end")) {
+      mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
+      mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
+    }
+    else if (position.EqualsLiteral("after_start")) {
+      mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
+      mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
+    }
+    else if (position.EqualsLiteral("after_end")) {
+      mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
+      mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
+    }
+    else if (position.EqualsLiteral("start_before")) {
+      mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
+      mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
+    }
+    else if (position.EqualsLiteral("start_after")) {
+      mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
+      mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
+    }
+    else if (position.EqualsLiteral("end_before")) {
+      mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
+      mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
+    }
+    else if (position.EqualsLiteral("end_after")) {
+      mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
+      mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
+    }
+    else if (position.EqualsLiteral("overlap")) {
+      mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
+      mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
+    }
+    else if (position.EqualsLiteral("after_pointer")) {
+      mPopupAnchor = POPUPALIGNMENT_NONE;
+      mPopupAlignment = POPUPALIGNMENT_NONE;
+      // XXXndeakin this is supposed to anchor vertically after, but with the
+      // horizontal position as the mouse pointer.
+      mYPos += 21;
+    }
+    else {
+      InitPositionFromAnchorAlign(anchor, align);
+    }
+  }
+
+  mScreenXPos = -1;
+  mScreenYPos = -1;
+
+  if (aAttributesOverride) {
+    // Use |left| and |top| dimension attributes to position the popup if
+    // present, as they may have been persisted. 
+    nsAutoString left, top;
+    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::left, left);
+    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::top, top);
+
+    PRInt32 err;
+    if (!left.IsEmpty()) {
+      PRInt32 x = left.ToInteger(&err);
+      if (NS_SUCCEEDED(err))
+        mScreenXPos = x;
+    }
+    if (!top.IsEmpty()) {
+      PRInt32 y = top.ToInteger(&err);
+      if (NS_SUCCEEDED(err))
+        mScreenYPos = y;
+    }
+  }
+}
+
+void
+nsMenuPopupFrame::InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos)
+{
+  EnsureWidget();
+
+  mIsOpenPending = PR_TRUE;
+  mAnchorContent = nsnull;
+  mScreenXPos = aXPos;
+  mScreenYPos = aYPos;
+  mPopupAnchor = POPUPALIGNMENT_NONE;
+  mPopupAlignment = POPUPALIGNMENT_NONE;
+}
+
+void
+nsMenuPopupFrame::InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
+                                                 nsAString& aAnchor,
+                                                 nsAString& aAlign,
+                                                 PRInt32 aXPos, PRInt32 aYPos)
+{
+  EnsureWidget();
+
+  mIsOpenPending = PR_TRUE;
+  mXPos = aXPos;
+  mYPos = aYPos;
+
+  // this popup opening function is provided for backwards compatibility
+  // only. It accepts either coordinates or an anchor and alignment value
+  // but doesn't use both together.
+  if (aXPos == -1 && aYPos == -1) {
+    mAnchorContent = aAnchorContent;
+    mScreenXPos = -1;
+    mScreenYPos = -1;
+    InitPositionFromAnchorAlign(aAnchor, aAlign);
+  }
+  else {
+    mAnchorContent = nsnull;
+    mPopupAnchor = POPUPALIGNMENT_NONE;
+    mPopupAlignment = POPUPALIGNMENT_NONE;
+    mScreenXPos = aXPos;
+    mScreenYPos = aYPos;
+  }
+}
+
+void PR_CALLBACK
+LazyGeneratePopupDone(nsIContent* aPopup, nsIFrame* aFrame, void* aArg)
+{
+  // be safe and check the frame type
+  if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
+    nsWeakFrame weakFrame(aFrame);
+    nsMenuPopupFrame* popupFrame = NS_STATIC_CAST(nsMenuPopupFrame*, aFrame);
+
+    popupFrame->SetGeneratedChildren();
+
+    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+    if (pm && popupFrame->IsMenu()) {
+      nsCOMPtr<nsIContent> popup = aPopup;
+      PRBool selectFirstItem = (PRBool)aArg;
+      if (selectFirstItem) {
+        nsMenuFrame* next = pm->GetNextMenuItem(popupFrame, nsnull, PR_TRUE);
+        popupFrame->SetCurrentMenuItem(next);
+      }
+
+      pm->UpdateMenuItems(popup);
+    }
+
+    if (weakFrame.IsAlive()) {
+      popupFrame->PresContext()->PresShell()->
+        FrameNeedsReflow(popupFrame, nsIPresShell::eTreeChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
+    }
+  }
+}
+
+
+PRBool
+nsMenuPopupFrame::ShowPopup(PRBool aIsContextMenu, PRBool aSelectFirstItem)
+{
+  mIsContextMenu = aIsContextMenu;
+
+  PRBool hasChildren = PR_FALSE;
+
+  if (!mIsOpen) {
+    mIsOpen = PR_TRUE;
+    mIsOpenChanged = PR_TRUE;
+
+    nsIFrame* parent = GetParent();
+    if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
+      nsWeakFrame weakFrame(this);
+      (NS_STATIC_CAST(nsMenuFrame*, parent))->PopupOpened();
+      if (!weakFrame.IsAlive())
+        return PR_FALSE;
+      PresContext()->RootPresContext()->NotifyAddedActivePopupToTop(this);
+    }
+
+    // the frames for the child menus have not been created yet, so tell the
+    // frame constructor to build them
+    if (mFrames.IsEmpty() && !mGeneratedChildren) {
+      PresContext()->PresShell()->FrameConstructor()->
+        AddLazyChildren(mContent, LazyGeneratePopupDone, (void *)aSelectFirstItem);
+    }
+    else {
+      hasChildren = PR_TRUE;
+      PresContext()->PresShell()->
+        FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                         NS_FRAME_HAS_DIRTY_CHILDREN);
+    }
+  }
+
+  mShouldAutoPosition = PR_TRUE;
+  return hasChildren;
+}
+
+void
+nsMenuPopupFrame::HidePopup(PRBool aDeselectMenu)
+{
+  if (mIsOpen) {
+    if (IsMenu())
+      SetCurrentMenuItem(nsnull);
+
+    mIncrementalString.Truncate();
+
+    mIsOpen = PR_FALSE;
+    mIsOpenChanged = PR_FALSE;
+    mCurrentMenu = nsnull; // make sure no current menu is set
+ 
+    nsIView* view = GetView();
+    nsIViewManager* viewManager = view->GetViewManager();
+    viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
+    viewManager->ResizeView(view, nsRect(0, 0, 0, 0));
+
+    FireDOMEvent(NS_LITERAL_STRING("DOMMenuInactive"), mContent);
+  }
+
+  // XXX, bug 137033, In Windows, if mouse is outside the window when the menupopup closes, no
+  // mouse_enter/mouse_exit event will be fired to clear current hover state, we should clear it manually.
+  // This code may not the best solution, but we can leave it here until we find the better approach.
+  nsIEventStateManager *esm = PresContext()->EventStateManager();
+
+  PRInt32 state;
+  esm->GetContentState(mContent, state);
+
+  if (state & NS_EVENT_STATE_HOVER)
+    esm->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
+
+  nsIFrame* parent = GetParent();
+  if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
+    (NS_STATIC_CAST(nsMenuFrame*, parent))->PopupClosed(aDeselectMenu);
+    PresContext()->RootPresContext()->NotifyRemovedActivePopup(this);
+  }
+}
+
 void
 nsMenuPopupFrame::InvalidateInternal(const nsRect& aDamageRect,
                                      nscoord aX, nscoord aY, nsIFrame* aForChild,
                                      PRBool aImmediate)
 {
   InvalidateRoot(aDamageRect, aX, aY, aImmediate);
 }
 
@@ -279,23 +606,20 @@ nsMenuPopupFrame::GetViewOffset(nsIView*
 
 ///////////////////////////////////////////////////////////////////////////////
 // GetRootViewForPopup
 //   Retrieves the view for the popup widget that contains the given frame. 
 //   If the given frame is not contained by a popup widget, return the
 //   root view.  This is the root view of the pres context's
 //   viewmanager if aStopAtViewManagerRoot is true; otherwise it's the
 //   root view of the root viewmanager.
-void
+nsIView*
 nsMenuPopupFrame::GetRootViewForPopup(nsIFrame* aStartFrame,
-                                      PRBool    aStopAtViewManagerRoot,
-                                      nsIView** aResult)
+                                      PRBool    aStopAtViewManagerRoot)
 {
-  *aResult = nsnull;
-
   nsIView* view = aStartFrame->GetClosestView();
   NS_ASSERTION(view, "frame must have a closest view!");
   if (view) {
     nsIView* rootView = nsnull;
     if (aStopAtViewManagerRoot) {
       view->GetViewManager()->GetRootView(rootView);
     }
     
@@ -303,220 +627,106 @@ nsMenuPopupFrame::GetRootViewForPopup(ns
       // Walk up the view hierarchy looking for a view whose widget has a 
       // window type of eWindowType_popup - in other words a popup window
       // widget. If we find one, this is the view we want. 
       nsIWidget* widget = view->GetWidget();
       if (widget) {
         nsWindowType wtype;
         widget->GetWindowType(wtype);
         if (wtype == eWindowType_popup) {
-          *aResult = view;
-          return;
+          return view;
         }
       }
 
       if (aStopAtViewManagerRoot && view == rootView) {
-        *aResult = view;
-        return;
+        return view;
       }
 
       nsIView* temp = view->GetParent();
       if (!temp) {
         // Otherwise, we've walked all the way up to the root view and not
         // found a view for a popup window widget. Just return the root view.
-        *aResult = view;
+        return view;
       }
       view = temp;
     }
   }
+
+  return nsnull;
 }
 
-
-//
-// AdjustClientXYForNestedDocuments
-// 
-// almost certainly, the document where the mouse was clicked is not
-// the document that contains the popup, especially if we're viewing a page
-// with frames. Thus we need to make adjustments to the client coordinates to
-// take this into account and get them back into the relative coordinates of
-// this document.
-//
-void
-nsMenuPopupFrame::AdjustClientXYForNestedDocuments ( nsIDOMXULDocument* inPopupDoc, nsIPresShell* inPopupShell, 
-                                                         PRInt32 inClientX, PRInt32 inClientY, 
-                                                         PRInt32* outAdjX, PRInt32* outAdjY )
-{
-  if ( !inPopupDoc || !outAdjX || !outAdjY )
-    return;
-
-  // Find the widget associated with the popup's document
-  nsIWidget* popupDocumentWidget = nsnull;
-  nsIViewManager* viewManager = inPopupShell->GetViewManager();
-  if ( viewManager ) {  
-    nsIView* rootView;
-    viewManager->GetRootView(rootView);
-    if ( rootView )
-      popupDocumentWidget = rootView->GetNearestWidget(nsnull);
-  }
-  NS_ASSERTION(popupDocumentWidget, "ACK, BAD WIDGET");
-  
-  // Find the widget associated with the target's document.
-  // For tooltips, we check the document's tooltipNode (which is set by
-  // nsXULTooltipListener).  For regular popups, use popupNode (set by
-  // nsXULPopupListener).
-
-  nsCOMPtr<nsIDOMNode> targetNode;
-  if (mContent->Tag() == nsGkAtoms::tooltip)
-    inPopupDoc->TrustedGetTooltipNode(getter_AddRefs(targetNode));
-  else
-    inPopupDoc->TrustedGetPopupNode(getter_AddRefs(targetNode));
-
-  //NS_ASSERTION(targetNode, "no popup/tooltip node on document!");
-  nsCOMPtr<nsIContent> targetAsContent ( do_QueryInterface(targetNode) );
-  nsIWidget* targetDocumentWidget = nsnull;
-  if ( targetAsContent ) {
-    nsCOMPtr<nsIDocument> targetDocument = targetAsContent->GetDocument();
-    if (targetDocument) {
-      nsIPresShell *shell = targetDocument->GetPrimaryShell();
-      if ( shell ) {
-        // We might be inside a popup widget. If so, we need to use that widget and
-        // not the root view's widget.
-        nsIFrame* targetFrame = shell->GetPrimaryFrameFor(targetAsContent);
-        nsIView* parentView = nsnull;
-        if (targetFrame) {
-          GetRootViewForPopup(targetFrame, PR_TRUE, &parentView);
-          if (parentView) {
-            targetDocumentWidget = parentView->GetNearestWidget(nsnull);
-          }
-        }
-        if (!targetDocumentWidget) {
-          // We aren't inside a popup. This means we should use the root view's
-          // widget.
-          nsIViewManager* viewManagerTarget = shell->GetViewManager();
-          if ( viewManagerTarget ) {
-            nsIView* rootViewTarget;
-            viewManagerTarget->GetRootView(rootViewTarget);
-            if ( rootViewTarget ) {
-              targetDocumentWidget = rootViewTarget->GetNearestWidget(nsnull);
-            }
-          }
-        }
-      }
-    }
-  }
-  //NS_ASSERTION(targetDocumentWidget, "ACK, BAD TARGET");
-
-  // the offset we need is the difference between the upper left corner of the two widgets. Use
-  // screen coordinates to find the global offset between them.
-  nsRect popupDocTopLeft;
-  if ( popupDocumentWidget ) {
-    nsRect topLeftClient ( 0, 0, 10, 10 );
-    popupDocumentWidget->WidgetToScreen ( topLeftClient, popupDocTopLeft );
-  }
-  nsRect targetDocTopLeft;
-  if ( targetDocumentWidget ) {
-    nsRect topLeftClient ( 0, 0, 10, 10 );
-    targetDocumentWidget->WidgetToScreen ( topLeftClient, targetDocTopLeft );
-  }
-  nsPoint pixelOffset ( targetDocTopLeft.x - popupDocTopLeft.x, targetDocTopLeft.y - popupDocTopLeft.y );
-
-  nsPresContext* context = PresContext();
-  *outAdjX = nsPresContext::CSSPixelsToAppUnits(inClientX) +
-             context->DevPixelsToAppUnits(pixelOffset.x);
-  *outAdjY = nsPresContext::CSSPixelsToAppUnits(inClientY) +
-             context->DevPixelsToAppUnits(pixelOffset.y);
-  
-} // AdjustClientXYForNestedDocuments
-
-
 //
 // AdjustPositionForAnchorAlign
 // 
-// Uses the |popupanchor| and |popupalign| attributes on the popup to move the popup around and
-// anchor it to its parent. |outFlushWithTopBottom| will be TRUE if the popup is flush with either
-// the top or bottom edge of its parent, and FALSE if it is flush with the left or right edge of
-// the parent.
+// Uses the anchor and alignment to move the popup around and anchor it to its
+// parent. |outFlushWithTopBottom| will be TRUE if the popup is flush with
+// either the top or bottom edge of its parent, and FALSE if it is flush with
+// the left or right edge of the parent.
 // 
 void
-nsMenuPopupFrame::AdjustPositionForAnchorAlign ( PRInt32* ioXPos, PRInt32* ioYPos, const nsRect & inParentRect,
-                                                    const nsString& aPopupAnchor, const nsString& aPopupAlign,
-                                                    PRBool* outFlushWithTopBottom )
+nsMenuPopupFrame::AdjustPositionForAnchorAlign(PRInt32* ioXPos, PRInt32* ioYPos, const nsRect & inParentRect,
+                                               PRBool* outFlushWithTopBottom)
 {
-  nsAutoString popupAnchor(aPopupAnchor);
-  nsAutoString popupAlign(aPopupAlign);
+  PRInt8 popupAnchor(mPopupAnchor);
+  PRInt8 popupAlign(mPopupAlignment);
 
   if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
-    if (popupAnchor.EqualsLiteral("topright"))
-      popupAnchor.AssignLiteral("topleft");
-    else if (popupAnchor.EqualsLiteral("topleft"))
-      popupAnchor.AssignLiteral("topright");
-    else if (popupAnchor.EqualsLiteral("bottomleft"))
-      popupAnchor.AssignLiteral("bottomright");
-    else if (popupAnchor.EqualsLiteral("bottomright"))
-      popupAnchor.AssignLiteral("bottomleft");
-
-    if (popupAlign.EqualsLiteral("topright"))
-      popupAlign.AssignLiteral("topleft");
-    else if (popupAlign.EqualsLiteral("topleft"))
-      popupAlign.AssignLiteral("topright");
-    else if (popupAlign.EqualsLiteral("bottomleft"))
-      popupAlign.AssignLiteral("bottomright");
-    else if (popupAnchor.EqualsLiteral("bottomright"))
-      popupAlign.AssignLiteral("bottomleft");
+    popupAnchor = -popupAnchor;
+    popupAlign = -popupAlign;
   }
 
   // Adjust position for margins at the aligned corner
   nsMargin margin;
   GetStyleMargin()->GetMargin(margin);
-  if (popupAlign.EqualsLiteral("topleft")) {
+  if (popupAlign == POPUPALIGNMENT_TOPLEFT) {
     *ioXPos += margin.left;
     *ioYPos += margin.top;
-  } else if (popupAlign.EqualsLiteral("topright")) {
+  } else if (popupAlign == POPUPALIGNMENT_TOPRIGHT) {
     *ioXPos += margin.right;
     *ioYPos += margin.top;
-  } else if (popupAlign.EqualsLiteral("bottomleft")) {
+  } else if (popupAlign == POPUPALIGNMENT_BOTTOMLEFT) {
     *ioXPos += margin.left;
     *ioYPos += margin.bottom;
-  } else if (popupAlign.EqualsLiteral("bottomright")) {
+  } else if (popupAlign == POPUPALIGNMENT_BOTTOMRIGHT) {
     *ioXPos += margin.right;
     *ioYPos += margin.bottom;
   }
   
-  if (popupAnchor.EqualsLiteral("topright") && popupAlign.EqualsLiteral("topleft")) {
+  if (popupAnchor == POPUPALIGNMENT_TOPRIGHT && popupAlign == POPUPALIGNMENT_TOPLEFT) {
     *ioXPos += inParentRect.width;
   }
-  else if (popupAnchor.EqualsLiteral("topleft") && popupAlign.EqualsLiteral("topleft")) {
+  else if (popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT) {
     *outFlushWithTopBottom = PR_TRUE;
   }
-  else if (popupAnchor.EqualsLiteral("topright") && popupAlign.EqualsLiteral("bottomright")) {
+  else if (popupAnchor == POPUPALIGNMENT_TOPRIGHT && popupAlign == POPUPALIGNMENT_BOTTOMRIGHT) {
     *ioXPos -= (mRect.width - inParentRect.width);
     *ioYPos -= mRect.height;
     *outFlushWithTopBottom = PR_TRUE;
   }
-  else if (popupAnchor.EqualsLiteral("bottomright") && popupAlign.EqualsLiteral("bottomleft")) {
+  else if (popupAnchor == POPUPALIGNMENT_BOTTOMRIGHT && popupAlign == POPUPALIGNMENT_BOTTOMLEFT) {
     *ioXPos += inParentRect.width;
     *ioYPos -= (mRect.height - inParentRect.height);
   }
-  else if (popupAnchor.EqualsLiteral("bottomright") && popupAlign.EqualsLiteral("topright")) {
+  else if (popupAnchor == POPUPALIGNMENT_BOTTOMRIGHT && popupAlign == POPUPALIGNMENT_TOPRIGHT) {
     *ioXPos -= (mRect.width - inParentRect.width);
     *ioYPos += inParentRect.height;
     *outFlushWithTopBottom = PR_TRUE;
   }
-  else if (popupAnchor.EqualsLiteral("topleft") && popupAlign.EqualsLiteral("topright")) {
+  else if (popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPRIGHT) {
     *ioXPos -= mRect.width;
   }
-  else if (popupAnchor.EqualsLiteral("topleft") && popupAlign.EqualsLiteral("bottomleft")) {
+  else if (popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_BOTTOMLEFT) {
     *ioYPos -= mRect.height;
     *outFlushWithTopBottom = PR_TRUE;
   }
-  else if (popupAnchor.EqualsLiteral("bottomleft") && popupAlign.EqualsLiteral("bottomright")) {
+  else if (popupAnchor == POPUPALIGNMENT_BOTTOMLEFT && popupAlign == POPUPALIGNMENT_BOTTOMRIGHT) {
     *ioXPos -= mRect.width;
     *ioYPos -= (mRect.height - inParentRect.height);
   }
-  else if (popupAnchor.EqualsLiteral("bottomleft") && popupAlign.EqualsLiteral("topleft")) {
+  else if (popupAnchor == POPUPALIGNMENT_BOTTOMLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT) {
     *ioYPos += inParentRect.height;
     *outFlushWithTopBottom = PR_TRUE;
   }
   else
     NS_WARNING ( "Hmmm, looks like you've hit a anchor/align case we weren't setup for." );
 
 } // AdjustPositionForAnchorAlign
 
@@ -612,132 +822,159 @@ nsMenuPopupFrame::MovePopupToOtherSideOf
       PRInt32 shiftDistX = inScreenParentFrameRect.width + mRect.width;
       *ioXPos += shiftDistX;
       *ioScreenViewLocX += shiftDistX;
     }               
   }
 
 } // MovePopupToOtherSideOfParent
 
-class nsASyncMenuActivation : public nsIReflowCallback
+// XXXndeakin this function will be reworked in bug 384062 such that positioning
+// of the popup is done only when the popup is first opened, so that the popup doesn't
+// move around when it is changed in some way.
+nsresult
+nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame)
 {
-public:
-  nsASyncMenuActivation(nsIContent* aContent)
-    : mContent(aContent)
-  {
-  }
+  if (!mShouldAutoPosition && !mInContentShell) 
+    return NS_OK;
+
+  PRBool sizedToPopup = PR_FALSE;
+
+  nsPresContext* presContext = PresContext();
 
-  virtual PRBool ReflowFinished() {
-    PRBool shouldFlush = PR_FALSE;
-    if (mContent &&
-        !mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
-                               nsGkAtoms::_true, eCaseMatters) &&
-        mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menutobedisplayed,
-                              nsGkAtoms::_true, eCaseMatters)) {
-      mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::menuactive,
-                        NS_LITERAL_STRING("true"), PR_TRUE);
-      shouldFlush = PR_TRUE;
+  // if the frame is not specified, use the anchor node passed to ShowPopup. If
+  // that wasn't specified either, use the root frame. Note that mAnchorContent
+  // might be a different document so its presshell must be used.
+  if (!aAnchorFrame) {
+    if (mAnchorContent) {
+      nsCOMPtr<nsIDocument> document = mAnchorContent->GetDocument();
+      nsIPresShell *shell = document->GetPrimaryShell();
+      if (!shell)
+        return NS_ERROR_FAILURE;
+      
+      aAnchorFrame = shell->GetPrimaryFrameFor(mAnchorContent);
+    }
+    else {
+      aAnchorFrame = presContext->PresShell()->FrameManager()->GetRootFrame();
     }
 
-    delete this;
-    return shouldFlush;
+    if (!aAnchorFrame)
+      return NS_OK;
   }
-
-  nsCOMPtr<nsIContent> mContent;
-};
-
-nsresult 
-nsMenuPopupFrame::SyncViewWithFrame(nsPresContext* aPresContext,
-                                    const nsString& aPopupAnchor,
-                                    const nsString& aPopupAlign,
-                                    nsIFrame* aFrame, 
-                                    PRInt32 aXPos, PRInt32 aYPos)
-{
-  NS_ENSURE_ARG(aPresContext);
-  NS_ENSURE_ARG(aFrame);
-
-  if (!mShouldAutoPosition && !mInContentShell) 
-    return NS_OK;
+  else {
+    // the popup should be the same size as the anchor menu, for example, a menulist.
+    sizedToPopup = nsMenuFrame::IsSizedToPopup(aAnchorFrame->GetContent(), PR_FALSE);
+  }
 
   // |containingView|
   //   The view that contains the frame that is invoking this popup. This is 
   //   the canvas view inside the scrollport view. It can have negative bounds
   //   if the canvas is scrolled so that part is off screen.
   nsIView* containingView = nsnull;
   nsPoint offset;
   nsMargin margin;
-  containingView = aFrame->GetClosestView(&offset);
+  containingView = aAnchorFrame->GetClosestView(&offset);
   if (!containingView)
     return NS_OK;
 
-  // |view|
-  //   The root view for the popup window widget associated with this frame,
-  //   or, the view associated with this frame. 
-  nsIView* view = GetView();
-
   // |parentPos|
   //   The distance between the containingView and the root view. This provides
   //   a hint as to where to position the menu relative to the window. 
   nsPoint parentPos;
   GetViewOffset(containingView, parentPos);
 
   // |parentRect|
   //   The dimensions of the frame invoking the popup. 
-  nsRect parentRect = aFrame->GetRect();
+  nsRect parentRect = aAnchorFrame->GetRect();
 
   // get the document and the global script object
-  nsIPresShell *presShell = aPresContext->PresShell();
+  nsIPresShell *presShell = presContext->PresShell();
   nsIDocument *document = presShell->GetDocument();
 
-  PRBool sizedToPopup = (mContent->Tag() != nsGkAtoms::tooltip) &&
-    (nsMenuFrame::IsSizedToPopup(aFrame->GetContent(), PR_FALSE));
-
   // If we stick to our parent's width, set it here before we move the
   // window around, because moving is done with respect to the width...
   if (sizedToPopup) {
     mRect.width = parentRect.width;
   }
 
+  // Use containingView instead of parentView, to account for the scrollarrows
+  // that a parent menu might have.
+  nsPoint parentViewWidgetOffset;
+  nsIWidget* parentViewWidget = containingView->GetNearestWidget(&parentViewWidgetOffset);
+  nsRect localParentWidgetRect(0,0,0,0), screenParentWidgetRect;
+  parentViewWidget->WidgetToScreen ( localParentWidgetRect, screenParentWidgetRect );
+
   // |xpos| and |ypos| hold the x and y positions of where the popup will be moved to,
   // in _twips_, in the coordinate system of the _parent view_.
+  PRBool readjustAboveBelow = PR_FALSE;
   PRInt32 xpos = 0, ypos = 0;
+  PRInt32 screenViewLocX, screenViewLocY;
+
+  if (mScreenXPos == -1 && mScreenYPos == -1) {
+    // if we are anchored to our parent, there are certain things we don't want to do
+    // when repositioning the view to fit on the screen, such as end up positioned over
+    // the parent. When doing this reposition, we want to move the popup to the side with
+    // the most room. The combination of anchor and alignment dictate if we readjust 
+    // above/below or to the left/right.
 
-  // if we are anchored to our parent, there are certain things we don't want to do
-  // when repositioning the view to fit on the screen, such as end up positioned over
-  // the parent. When doing this reposition, we want to move the popup to the side with
-  // the most room. The combination of anchor and alignment dictate if we readjst 
-  // above/below or to the left/right.
-  PRBool anchoredToParent = PR_FALSE;
-  PRBool readjustAboveBelow = PR_FALSE;
+    if (mAnchorContent) {
+      xpos = parentPos.x + offset.x;
+      ypos = parentPos.y + offset.y;
+
+      // move the popup according to the anchor and alignment. This will also tell us
+      // which axis the popup is flush against in case we have to move it around later.
+      AdjustPositionForAnchorAlign(&xpos, &ypos, parentRect, &readjustAboveBelow);
 
-  if ( aXPos != -1 || aYPos != -1 ) {
-  
-    // for this case, we've been handed a specific x/y location (in client coordinates) for
-    // the popup. However, we may be deeply nested in a frameset, etc and so the client coordinates
-    // need some adjusting. 
-    nsCOMPtr<nsIDOMXULDocument> xulDoc ( do_QueryInterface(document) );
-    AdjustClientXYForNestedDocuments ( xulDoc, presShell, aXPos, aYPos, &xpos, &ypos );
+      // the x and y position may be used to offset the popup after it has been anchored
+      xpos += presContext->DevPixelsToAppUnits(mXPos);
+      ypos += presContext->DevPixelsToAppUnits(mYPos);
+    }
+    else {
+      GetStyleMargin()->GetMargin(margin);
+      xpos = presContext->DevPixelsToAppUnits(mXPos) + margin.left;
+      ypos = presContext->DevPixelsToAppUnits(mYPos) + margin.top;
+    }
 
-    // Add in the top and left margins
-    GetStyleMargin()->GetMargin(margin);
+    // Recall that |xpos| and |ypos| are in the coordinate system of the parent view. In
+    // order to determine the screen coordinates of where our view will end up, we
+    // need to find the x/y position of the parent view in screen coords. That is done
+    // by getting the widget associated with the parent view and determining the offset 
+    // based on converting (0,0) in its coordinate space to screen coords. We then
+    // offset that point by (|xpos|,|ypos|) to get the true screen coordinates of
+    // the view. *whew*
 
-    xpos += margin.left;
-    ypos += margin.top;
-  } 
-  else {
-    anchoredToParent = PR_TRUE;
+    // |parentView|
+    //   The root view for the window that contains the frame, for frames inside 
+    //   menupopups this is the first view inside the popup window widget, for 
+    //   frames inside a toplevel window, this is the root view of the toplevel
+    //   window.
+    nsIView* parentView = GetRootViewForPopup(aAnchorFrame, PR_FALSE);
+    if (!parentView)
+      return NS_OK;
 
-    xpos = parentPos.x + offset.x;
-    ypos = parentPos.y + offset.y;
-    
-    // move the popup according to the anchor/alignment attributes. This will also tell us
-    // which axis the popup is flush against in case we have to move it around later.
-    AdjustPositionForAnchorAlign ( &xpos, &ypos, parentRect, aPopupAnchor, aPopupAlign, &readjustAboveBelow );    
+    screenViewLocX = presContext->DevPixelsToAppUnits(screenParentWidgetRect.x) +
+      (xpos - parentPos.x) + parentViewWidgetOffset.x;
+    screenViewLocY = presContext->DevPixelsToAppUnits(screenParentWidgetRect.y) +
+      (ypos - parentPos.y) + parentViewWidgetOffset.y;
   }
-  
+  else {
+    // positioned on screen
+    GetStyleMargin()->GetMargin(margin);
+    screenViewLocX = nsPresContext::CSSPixelsToAppUnits(mScreenXPos) + margin.left;
+    screenViewLocY = nsPresContext::CSSPixelsToAppUnits(mScreenYPos) + margin.top;
+
+    xpos = screenViewLocX - presContext->DevPixelsToAppUnits(screenParentWidgetRect.x) -
+           parentViewWidgetOffset.x - parentPos.x;
+    ypos = screenViewLocY - presContext->DevPixelsToAppUnits(screenParentWidgetRect.y) -
+           parentViewWidgetOffset.y - parentPos.y;
+
+    // once the popup is positioned on screen, it doesn't need to be positioned again
+    mShouldAutoPosition = PR_FALSE;
+  }
+
   // Compute info about the screen dimensions. Because of multiple monitor systems,
   // the left or top sides of the screen may be in negative space (main monitor is on the
   // right, etc). We need to be sure to do the right thing.
   nsPIDOMWindow *window = document->GetWindow();
   if (!window)
     return NS_OK;
 
   nsIDeviceContext* devContext = PresContext()->DeviceContext();
@@ -751,59 +988,28 @@ nsMenuPopupFrame::SyncViewWithFrame(nsPr
 
   // keep 3px margin to the right and bottom of the screen for WinXP dropshadow
   rect.width  -= nsPresContext::CSSPixelsToAppUnits(3);
   rect.height -= nsPresContext::CSSPixelsToAppUnits(3);
 
   // for content shells, clip to the client area rather than the screen area
   if (mInContentShell) {
     nsRect rootScreenRect = presShell->GetRootFrame()->GetScreenRect();
-    rootScreenRect.ScaleRoundIn(aPresContext->AppUnitsPerDevPixel());
+    rootScreenRect.ScaleRoundIn(presContext->AppUnitsPerDevPixel());
     rect.IntersectRect(rect, rootScreenRect);
   }
 
   PRInt32 screenLeftTwips   = rect.x;
   PRInt32 screenTopTwips    = rect.y;
   PRInt32 screenWidthTwips  = rect.width;
   PRInt32 screenHeightTwips = rect.height;
   PRInt32 screenRightTwips  = rect.XMost();
   PRInt32 screenBottomTwips = rect.YMost();
-  
-  // Recall that |xpos| and |ypos| are in the coordinate system of the parent view. In
-  // order to determine the screen coordinates of where our view will end up, we
-  // need to find the x/y position of the parent view in screen coords. That is done
-  // by getting the widget associated with the parent view and determining the offset 
-  // based on converting (0,0) in its coordinate space to screen coords. We then
-  // offset that point by (|xpos|,|ypos|) to get the true screen coordinates of
-  // the view. *whew*
 
-  // |parentView|
-  //   The root view for the window that contains the frame, for frames inside 
-  //   menupopups this is the first view inside the popup window widget, for 
-  //   frames inside a toplevel window, this is the root view of the toplevel
-  //   window.
-  nsIView* parentView = nsnull;
-  GetRootViewForPopup(aFrame, PR_FALSE, &parentView);
-  if (!parentView)
-    return NS_OK;
-
-  // Use containingView instead of parentView, to account for the scrollarrows
-  // that a parent menu might have.
-
-  nsPoint parentViewWidgetOffset;
-  nsIWidget* parentViewWidget = containingView->GetNearestWidget(&parentViewWidgetOffset);
-  nsRect localParentWidgetRect(0,0,0,0), screenParentWidgetRect;
-  parentViewWidget->WidgetToScreen ( localParentWidgetRect, screenParentWidgetRect );
-  PRInt32 screenViewLocX = aPresContext->DevPixelsToAppUnits(screenParentWidgetRect.x) +
-    (xpos - parentPos.x) + parentViewWidgetOffset.x;
-  PRInt32 screenViewLocY = aPresContext->DevPixelsToAppUnits(screenParentWidgetRect.y) +
-    (ypos - parentPos.y) + parentViewWidgetOffset.y;
-
-  if ( anchoredToParent ) {
-    
+  if (mPopupAnchor != POPUPALIGNMENT_NONE) {
     //
     // Popup is anchored to the parent, guarantee that it does not cover the parent. We
     // shouldn't do anything funky if it will already fit on the screen as is.
     //
 
     ///////////////////////////////////////////////////////////////////////////////
     //
     //                +------------------------+          
@@ -820,21 +1026,21 @@ nsMenuPopupFrame::SyncViewWithFrame(nsPr
     //                +------------------------+|  ( = mRect )
     //                |           \/           ||
     //                +------------------------+
 
 
 
     // compute screen coordinates of parent frame so we can play with it. Make sure we put it
     // into twips as everything else is as well.
-    nsRect screenParentFrameRect (aPresContext->AppUnitsToDevPixels(offset.x), aPresContext->AppUnitsToDevPixels(offset.y),
+    nsRect screenParentFrameRect (presContext->AppUnitsToDevPixels(offset.x), presContext->AppUnitsToDevPixels(offset.y),
                                     parentRect.width, parentRect.height );
     parentViewWidget->WidgetToScreen ( screenParentFrameRect, screenParentFrameRect );
-    screenParentFrameRect.x = aPresContext->DevPixelsToAppUnits(screenParentFrameRect.x);
-    screenParentFrameRect.y = aPresContext->DevPixelsToAppUnits(screenParentFrameRect.y);
+    screenParentFrameRect.x = presContext->DevPixelsToAppUnits(screenParentFrameRect.x);
+    screenParentFrameRect.y = presContext->DevPixelsToAppUnits(screenParentFrameRect.y);
 
     // Don't let it spill off the screen to the top
     if (screenViewLocY < screenTopTwips) {
       PRInt32 moveDist = screenTopTwips - screenViewLocY;
       screenViewLocY = screenTopTwips;
       ypos += moveDist;
     }
     
@@ -938,20 +1144,20 @@ nsMenuPopupFrame::SyncViewWithFrame(nsPr
     // XXXbz this is really silly.  We should be able to anchor popups to a
     // point or rect, not a frame, and we should be doing so with context
     // menus.  Furthermore, we should not be adding in pixels manually to
     // adjust position (in XULPopupListenerImpl::LaunchPopup comes to mind,
     // though ConvertPosition in the same file has some 21-px bogosity in the
     // y-direction too).
 
     // shrink to fit onto the screen, vertically and horizontally
-    if(mRect.width > screenWidthTwips) 
-        mRect.width = screenWidthTwips;    
+    if(mRect.width > screenWidthTwips)
+       mRect.width = screenWidthTwips;
     if(mRect.height > screenHeightTwips)
-        mRect.height = screenHeightTwips;   
+       mRect.height = screenHeightTwips;
 
     // First, adjust the X position.  For the X position, we slide the popup
     // left or right as needed to get it on screen.
     if ( screenViewLocX < screenLeftTwips ) {
       PRInt32 moveDistX = screenLeftTwips - screenViewLocX;
       xpos += moveDistX;
       screenViewLocX += moveDistX;
     }
@@ -986,209 +1192,65 @@ nsMenuPopupFrame::SyncViewWithFrame(nsPr
           // We wouldn't fit.  Shorten before flipping.
           mRect.height = screenViewLocY - screenTopTwips;
         }
         ypos -= (mRect.height + margin.top + margin.bottom);
       }
     }
   }  
 
-  aPresContext->GetViewManager()->MoveViewTo(view, xpos, ypos); 
+  presContext->GetViewManager()->MoveViewTo(GetView(), xpos, ypos); 
 
   // Now that we've positioned the view, sync up the frame's origin.
   nsPoint frameOrigin = GetPosition();
   nsPoint offsetToView;
   GetOriginToViewOffset(offsetToView, nsnull);
   frameOrigin -= offsetToView;
   nsBoxFrame::SetPosition(frameOrigin);
 
   if (sizedToPopup) {
-      nsBoxLayoutState state(PresContext());
-      SetBounds(state, nsRect(mRect.x, mRect.y, parentRect.width, mRect.height));
-  }
-    
-  if (!mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
-                             nsGkAtoms::_true, eCaseMatters) &&
-      mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menutobedisplayed,
-                            nsGkAtoms::_true, eCaseMatters)) {
-    nsIReflowCallback* cb = new nsASyncMenuActivation(mContent);
-    NS_ENSURE_TRUE(cb, NS_ERROR_OUT_OF_MEMORY);
-    PresContext()->PresShell()->PostReflowCallback(cb);
+    nsBoxLayoutState state(PresContext());
+    SetBounds(state, nsRect(mRect.x, mRect.y, parentRect.width, mRect.height));
   }
 
   return NS_OK;
 }
 
-static void GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild,
-                              nsIFrame** aResult)
-{
-  nsIContent* child = nsnull;
-  if (aChild)
-    child = aChild->GetContent();
-  aShell->FrameConstructor()->GetInsertionPoint(aFrame, child, aResult);
-}
-
-/* virtual */ nsIMenuFrame*
-nsMenuPopupFrame::GetNextMenuItem(nsIMenuFrame* aStart)
-{
-  nsIFrame* immediateParent = nsnull;
-  GetInsertionPoint(PresContext()->PresShell(), this, nsnull,
-                    &immediateParent);
-  if (!immediateParent)
-    immediateParent = this;
-
-  nsIFrame* currFrame = nsnull;
-  nsIFrame* startFrame = nsnull;
-  if (aStart) {
-    aStart->QueryInterface(NS_GET_IID(nsIFrame), (void**)&currFrame); 
-    if (currFrame) {
-      startFrame = currFrame;
-      currFrame = currFrame->GetNextSibling();
-    }
-  }
-  else 
-    currFrame = immediateParent->GetFirstChild(nsnull);
-  
-  while (currFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-    currFrame = currFrame->GetNextSibling();
-  }
-
-  currFrame = immediateParent->GetFirstChild(nsnull);
-
-  // Still don't have anything. Try cycling from the beginning.
-  while (currFrame && currFrame != startFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-
-    currFrame = currFrame->GetNextSibling();
-  }
-
-  // No luck. Just return our start value.
-  return aStart;
-}
-
-/* virtual */ nsIMenuFrame*
-nsMenuPopupFrame::GetPreviousMenuItem(nsIMenuFrame* aStart)
-{
-  nsIFrame* immediateParent = nsnull;
-  GetInsertionPoint(PresContext()->PresShell(), this, nsnull,
-                    &immediateParent);
-  if (!immediateParent)
-    immediateParent = this;
-
-  nsFrameList frames(immediateParent->GetFirstChild(nsnull));
-                              
-  nsIFrame* currFrame = nsnull;
-  nsIFrame* startFrame = nsnull;
-  if (aStart) {
-    aStart->QueryInterface(NS_GET_IID(nsIFrame), (void**)&currFrame);
-    if (currFrame) {
-      startFrame = currFrame;
-      currFrame = frames.GetPrevSiblingFor(currFrame);
-    }
-  }
-  else currFrame = frames.LastChild();
-
-  while (currFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-    currFrame = frames.GetPrevSiblingFor(currFrame);
-  }
-
-  currFrame = frames.LastChild();
-
-  // Still don't have anything. Try cycling from the end.
-  while (currFrame && currFrame != startFrame) {
-    // See if it's a menu item.
-    if (IsValidItem(currFrame->GetContent())) {
-      nsIMenuFrame *menuFrame;
-      if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame)))
-        menuFrame = nsnull;
-      return menuFrame;
-    }
-
-    currFrame = frames.GetPrevSiblingFor(currFrame);
-  }
-
-  // No luck. Just return our start value.
-  return aStart;
-}
-
-/* virtual */ nsIMenuFrame*
+/* virtual */ nsMenuFrame*
 nsMenuPopupFrame::GetCurrentMenuItem()
 {
   return mCurrentMenu;
 }
 
-NS_IMETHODIMP nsMenuPopupFrame::ConsumeOutsideClicks(PRBool& aConsumeOutsideClicks)
+PRBool nsMenuPopupFrame::ConsumeOutsideClicks()
 {
-  /*
-   * When this popup is open, should clicks outside of it be consumed?
-   * Return PR_TRUE if the popup hould rollup on an outside click, 
-   * but consume that click so it can't be used for anything else.
-   * Return PR_FALSE to allow clicks outside the popup to activate content 
-   * even when the popup is open.
-   * ---------------------------------------------------------------------
-   * 
-   * Should clicks outside of a popup be eaten?
-   *
-   *       Menus     Autocomplete     Comboboxes
-   * Mac     Eat           No              Eat
-   * Win     No            No              Eat     
-   * Unix    Eat           No              Eat
-   *
-   */
-
   // If the popup has explicitly set a consume mode, honor that.
-  if (mConsumeRollupEvent != nsIPopupBoxObject::ROLLUP_DEFAULT) {
-    aConsumeOutsideClicks = mConsumeRollupEvent == nsIPopupBoxObject::ROLLUP_CONSUME;
-    return NS_OK;
-  }
-
-  aConsumeOutsideClicks = PR_TRUE;
+  if (mConsumeRollupEvent != nsIPopupBoxObject::ROLLUP_DEFAULT)
+    return (mConsumeRollupEvent == nsIPopupBoxObject::ROLLUP_CONSUME);
 
   nsCOMPtr<nsIContent> parentContent = mContent->GetParent();
-
   if (parentContent) {
-    nsIAtom *parentTag = parentContent->Tag();
-    if (parentTag == nsGkAtoms::menulist)
-      return NS_OK;  // Consume outside clicks for combo boxes on all platforms
-    if (parentTag == nsGkAtoms::menu || parentTag == nsGkAtoms::popupset) {
+    nsINodeInfo *ni = parentContent->NodeInfo();
+    if (ni->Equals(nsGkAtoms::menulist, kNameSpaceID_XUL))
+      return PR_TRUE;  // Consume outside clicks for combo boxes on all platforms
 #if defined(XP_WIN) || defined(XP_OS2)
-      // Don't consume outside clicks for menus in Windows
-      aConsumeOutsideClicks = PR_FALSE;
+    // Don't consume outside clicks for menus in Windows
+    if (ni->Equals(nsGkAtoms::menu, kNameSpaceID_XUL) ||
+       (ni->Equals(nsGkAtoms::popupset, kNameSpaceID_XUL)))
+      return PR_FALSE;
 #endif
-      return NS_OK;
-    }
-    if (parentTag == nsGkAtoms::textbox) {
+    if (ni->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL)) {
       // Don't consume outside clicks for autocomplete widget
       if (parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
                                      nsGkAtoms::autocomplete, eCaseMatters))
-        aConsumeOutsideClicks = PR_FALSE;
+        return PR_FALSE;
     }
   }
 
-  return NS_OK;
+  return PR_TRUE;
 }
 
 static nsIScrollableView* GetScrollableViewForFrame(nsIFrame* aFrame)
 {
   nsIScrollableFrame* sf;
   nsresult rv = CallQueryInterface(aFrame, &sf);
   if (NS_FAILED(rv))
     return nsnull;
@@ -1223,181 +1285,140 @@ nsIScrollableView* nsMenuPopupFrame::Get
     if ( scrollableView )
       return scrollableView;
     currFrame = currFrame->GetNextSibling();
   } while ( currFrame );
 
   return nsnull;
 }
 
-void nsMenuPopupFrame::EnsureMenuItemIsVisible(nsIMenuFrame* aMenuItem)
+void nsMenuPopupFrame::EnsureMenuItemIsVisible(nsMenuFrame* aMenuItem)
 {
-  nsIFrame* frame=nsnull;
-  aMenuItem->QueryInterface(NS_GET_IID(nsIFrame), (void**)&frame);
-  if ( frame ) {
-    nsIFrame* childFrame=nsnull;
-    childFrame = GetFirstChild(nsnull);
+  if (aMenuItem) {
+    nsIFrame* childFrame = GetFirstChild(nsnull);
     nsIScrollableView *scrollableView;
-    scrollableView=GetScrollableView(childFrame);
-    if ( scrollableView ) {
+    scrollableView = GetScrollableView(childFrame);
+    if (scrollableView) {
       nscoord scrollX, scrollY;
 
       nsRect viewRect = scrollableView->View()->GetBounds();
-      nsRect itemRect = frame->GetRect();
+      nsRect itemRect = aMenuItem->GetRect();
       scrollableView->GetScrollPosition(scrollX, scrollY);
   
       // scroll down
       if ( itemRect.y + itemRect.height > scrollY + viewRect.height )
         scrollableView->ScrollTo(scrollX, itemRect.y + itemRect.height - viewRect.height, NS_SCROLL_PROPERTY_ALWAYS_BLIT);
       
       // scroll up
       else if ( itemRect.y < scrollY )
         scrollableView->ScrollTo(scrollX, itemRect.y, NS_SCROLL_PROPERTY_ALWAYS_BLIT);
     }
   }
 }
 
-NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem)
+NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
 {
+  if (mCurrentMenu == aMenuItem)
+    return NS_OK;
+
+  if (mCurrentMenu) {
+    mCurrentMenu->SelectMenu(PR_FALSE);
+  }
+
+  if (aMenuItem) {
+    EnsureMenuItemIsVisible(aMenuItem);
+    aMenuItem->SelectMenu(PR_TRUE);
+  }
+
+  mCurrentMenu = aMenuItem;
+
+  return NS_OK;
+}
+
+void
+nsMenuPopupFrame::CurrentMenuIsBeingDestroyed()
+{
+  mCurrentMenu = nsnull;
+}
+
+NS_IMETHODIMP
+nsMenuPopupFrame::ChangeMenuItem(nsMenuFrame* aMenuItem,
+                                 PRBool aSelectFirstItem)
+{
+  if (mCurrentMenu == aMenuItem)
+    return NS_OK;
+
   // When a context menu is open, the current menu is locked, and no change
   // to the menu is allowed.
-  nsIMenuParent *contextMenu = GetContextMenu();
-  if (contextMenu)
+  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+  if (!mIsContextMenu && pm && pm->HasContextMenu(this))
     return NS_OK;
 
-  if (mCurrentMenu == aMenuItem)
-    return NS_OK;
-  
   // Unset the current child.
   if (mCurrentMenu) {
-    PRBool isOpen = PR_FALSE;
-    mCurrentMenu->MenuIsOpen(isOpen);
     mCurrentMenu->SelectMenu(PR_FALSE);
-    // XXX bug 294183 sometimes mCurrentMenu gets cleared
-    if (mCurrentMenu && isOpen) {
-      // Don't close up immediately.
-      // Kick off a close timer.
-      KillCloseTimer(); // Ensure we don't have another stray waiting closure.
-      PRInt32 menuDelay = 300;   // ms
-
-      PresContext()->LookAndFeel()->
-        GetMetric(nsILookAndFeel::eMetric_SubmenuDelay, menuDelay);
-
-      // Kick off the timer.
-      mCloseTimer = do_CreateInstance("@mozilla.org/timer;1");
-      mCloseTimer->InitWithCallback(mTimerMediator, menuDelay, nsITimer::TYPE_ONE_SHOT);
-      mTimerMenu = mCurrentMenu;
+    nsMenuPopupFrame* popup = mCurrentMenu->GetPopup();
+    if (popup) {
+      if (mCurrentMenu->IsOpen()) {
+        if (pm)
+          pm->HidePopupAfterDelay(popup);
+      }
     }
   }
 
   // Set the new child.
   if (aMenuItem) {
     EnsureMenuItemIsVisible(aMenuItem);
     aMenuItem->SelectMenu(PR_TRUE);
   }
 
   mCurrentMenu = aMenuItem;
 
   return NS_OK;
 }
 
-
-NS_IMETHODIMP
-nsMenuPopupFrame::Escape(PRBool& aHandledFlag)
-{
-  mIncrementalString.Truncate();
-
-  // See if we have a context menu open.
-  nsIMenuParent* contextMenu = GetContextMenu();
-  if (contextMenu) {
-    // Get the context menu parent.
-    nsIFrame* childFrame;
-    CallQueryInterface(contextMenu, &childFrame);
-    nsIPopupSetFrame* popupSetFrame = GetPopupSetFrame(PresContext());
-    if (popupSetFrame)
-      // Destroy the popup.
-      popupSetFrame->DestroyPopup(childFrame, PR_FALSE);
-    aHandledFlag = PR_TRUE;
-    return NS_OK;
-  }
-
-  if (!mCurrentMenu)
-    return NS_OK;
-
-  // See if our menu is open.
-  PRBool isOpen = PR_FALSE;
-  mCurrentMenu->MenuIsOpen(isOpen);
-  if (isOpen) {
-    // Let the child menu handle this.
-    mCurrentMenu->Escape(aHandledFlag);
-    if (!aHandledFlag) {
-      // We should close up.
-      mCurrentMenu->OpenMenu(PR_FALSE);
-      // SelectMenu() so DOMMenuItemActive is fired for accessibility
-      mCurrentMenu->SelectMenu(PR_TRUE);
-      aHandledFlag = PR_TRUE;
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+nsMenuFrame*
 nsMenuPopupFrame::Enter()
 {
   mIncrementalString.Truncate();
 
-  // See if we have a context menu open.
-  nsIMenuParent *contextMenu = GetContextMenu();
-  if (contextMenu)
-    return contextMenu->Enter();
-
   // Give it to the child.
   if (mCurrentMenu)
-    mCurrentMenu->Enter();
+    return mCurrentMenu->Enter();
 
-  return NS_OK;
+  return nsnull;
 }
 
-nsIMenuParent*
-nsMenuPopupFrame::GetContextMenu()
-{
-  if (mIsContextMenu)
-    return nsnull;
-
-  return nsMenuFrame::GetContextMenu();
-}
-
-nsIMenuFrame*
+nsMenuFrame*
 nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, PRBool& doAction)
 {
   PRUint32 charCode, keyCode;
   aKeyEvent->GetCharCode(&charCode);
   aKeyEvent->GetKeyCode(&keyCode);
 
   doAction = PR_FALSE;
 
   // Enumerate over our list of frames.
   nsIFrame* immediateParent = nsnull;
-  GetInsertionPoint(PresContext()->PresShell(), this, nsnull,
-                    &immediateParent);
+  PresContext()->PresShell()->
+    FrameConstructor()->GetInsertionPoint(this, nsnull, &immediateParent);
   if (!immediateParent)
     immediateParent = this;
 
   PRUint32 matchCount = 0, matchShortcutCount = 0;
   PRBool foundActive = PR_FALSE;
   PRBool isShortcut;
-  nsIMenuFrame* frameBefore = nsnull;
-  nsIMenuFrame* frameAfter = nsnull;
-  nsIMenuFrame* frameShortcut = nsnull;
+  nsMenuFrame* frameBefore = nsnull;
+  nsMenuFrame* frameAfter = nsnull;
+  nsMenuFrame* frameShortcut = nsnull;
 
   nsIContent* parentContent = mContent->GetParent();
 
-  PRBool isMenu =
-    parentContent && parentContent->Tag() != nsGkAtoms::menulist;
+  PRBool isMenu = parentContent &&
+                  !parentContent->NodeInfo()->Equals(nsGkAtoms::menulist, kNameSpaceID_XUL);
 
   static DOMTimeStamp lastKeyTime = 0;
   DOMTimeStamp keyTime;
   aKeyEvent->GetTimeStamp(&keyTime);
 
   if (charCode == 0) {
     if (keyCode == NS_VK_BACK) {
       if (!isMenu && !mIncrementalString.IsEmpty()) {
@@ -1440,75 +1461,76 @@ nsMenuPopupFrame::FindMenuWithShortcut(n
   nsIFrame* currFrame;
   // NOTE: If you crashed here due to a bogus |immediateParent| it is 
   //       possible that the menu whose shortcut is being looked up has 
   //       been destroyed already.  One strategy would be to 
   //       setTimeout(<func>,0) as detailed in:
   //       <http://bugzilla.mozilla.org/show_bug.cgi?id=126675#c32>
   currFrame = immediateParent->GetFirstChild(nsnull);
 
+  PRInt32 menuAccessKey = -1;
+  nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
+
   // We start searching from first child. This process is divided into two parts
   //   -- before current and after current -- by the current item
   while (currFrame) {
     nsIContent* current = currFrame->GetContent();
     
     // See if it's a menu item.
-    if (IsValidItem(current)) {
+    if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, PR_TRUE)) {
       nsAutoString textKey;
-      // Get the shortcut attribute.
-      current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, textKey);
+      if (menuAccessKey >= 0) {
+        // Get the shortcut attribute.
+        current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, textKey);
+      }
       if (textKey.IsEmpty()) { // No shortcut, try first letter
         isShortcut = PR_FALSE;
         current->GetAttr(kNameSpaceID_None, nsGkAtoms::label, textKey);
         if (textKey.IsEmpty()) // No label, try another attribute (value)
           current->GetAttr(kNameSpaceID_None, nsGkAtoms::value, textKey);
       }
       else
         isShortcut = PR_TRUE;
 
       if (StringBeginsWith(textKey, incrementalString,
                            nsCaseInsensitiveStringComparator())) {
         // mIncrementalString is a prefix of textKey
-        nsIMenuFrame* menuFrame;
-        if (NS_SUCCEEDED(CallQueryInterface(currFrame, &menuFrame))) {
+        if (currFrame->GetType() == nsGkAtoms::menuFrame) {
           // There is one match
           matchCount++;
           if (isShortcut) {
             // There is one shortcut-key match
             matchShortcutCount++;
             // Record the matched item. If there is only one matched shortcut item, do it
-            frameShortcut = menuFrame;
+            frameShortcut = NS_STATIC_CAST(nsMenuFrame *, currFrame);
           }
           if (!foundActive) {
             // It's a first candidate item located before/on the current item
             if (!frameBefore)
-              frameBefore = menuFrame;
+              frameBefore = NS_STATIC_CAST(nsMenuFrame *, currFrame);
           }
           else {
             // It's a first candidate item located after the current item
             if (!frameAfter)
-              frameAfter = menuFrame;
+              frameAfter = NS_STATIC_CAST(nsMenuFrame *, currFrame);
           }
         }
         else
           return nsnull;
       }
 
       // Get the active status
       if (current->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
                                nsGkAtoms::_true, eCaseMatters)) {
         foundActive = PR_TRUE;
         if (stringLength > 1) {
           // If there is more than one char typed, the current item has highest priority,
           //   otherwise the item next to current has highest priority
-          nsIMenuFrame* menuFrame;
-          if (NS_SUCCEEDED(CallQueryInterface(currFrame, &menuFrame)) &&
-              menuFrame == frameBefore) {
+          if (currFrame == frameBefore)
             return frameBefore;
-          }
         }
       }
     }
     currFrame = currFrame->GetNextSibling();
   }
 
   doAction = (isMenu && (matchCount == 1 || matchShortcutCount == 1));
 
@@ -1531,492 +1553,94 @@ nsMenuPopupFrame::FindMenuWithShortcut(n
     if (soundInterface)
       soundInterface->Beep();
   }
 #endif  // #ifdef XP_WIN
 
   return nsnull;
 }
 
-NS_IMETHODIMP 
-nsMenuPopupFrame::ShortcutNavigation(nsIDOMKeyEvent* aKeyEvent, PRBool& aHandledFlag)
-{
-  // See if we have a context menu open.
-  nsIMenuParent *contextMenu = GetContextMenu();
-  if (contextMenu)
-    return contextMenu->ShortcutNavigation(aKeyEvent, aHandledFlag);
-
-  if (mCurrentMenu) {
-    PRBool isOpen = PR_FALSE;
-    mCurrentMenu->MenuIsOpen(isOpen);
-    if (isOpen) {
-      // No way this applies to us. Give it to our child.
-      mCurrentMenu->ShortcutNavigation(aKeyEvent, aHandledFlag);
-      return NS_OK;
-    }
-  }
-
-  // This applies to us. Let's see if one of the shortcuts applies
-  PRBool action;
-  nsIMenuFrame* result = FindMenuWithShortcut(aKeyEvent, action);
-  if (result) {
-    // We got one!
-    nsIFrame* frame = nsnull;
-    CallQueryInterface(result, &frame);
-    nsWeakFrame weakResult(frame);
-    aHandledFlag = PR_TRUE;
-    SetCurrentMenuItem(result);
-    if (action && weakResult.IsAlive()) {
-      result->Enter();
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuPopupFrame::KeyboardNavigation(PRUint32 aKeyCode, PRBool& aHandledFlag)
-{
-  // See if we have a context menu open.
-  nsIMenuParent *contextMenu = GetContextMenu();
-  if (contextMenu)
-    return contextMenu->KeyboardNavigation(aKeyCode, aHandledFlag);
-
-  nsNavigationDirection theDirection;
-  NS_DIRECTION_FROM_KEY_CODE(theDirection, aKeyCode);
-
-  mIncrementalString.Truncate();
-
-  // This method only gets called if we're open.
-  if (!mCurrentMenu && NS_DIRECTION_IS_INLINE(theDirection)) {
-    // We've been opened, but we haven't had anything selected.
-    // We can handle End, but our parent handles Start.
-    if (theDirection == eNavigationDirection_End) {
-      nsIMenuFrame* nextItem = GetNextMenuItem(nsnull);
-      if (nextItem) {
-        aHandledFlag = PR_TRUE;
-        SetCurrentMenuItem(nextItem);
-      }
-    }
-    return NS_OK;
-  }
-
-  PRBool isContainer = PR_FALSE;
-  PRBool isOpen = PR_FALSE;
-  PRBool isDisabled = PR_FALSE;
-  nsWeakFrame weakFrame(this);
-  if (mCurrentMenu) {
-    mCurrentMenu->MenuIsContainer(isContainer);
-    mCurrentMenu->MenuIsOpen(isOpen);
-    mCurrentMenu->MenuIsDisabled(isDisabled);
-
-    if (isOpen) {
-      // Give our child a shot.
-      mCurrentMenu->KeyboardNavigation(aKeyCode, aHandledFlag);
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    }
-    else if (theDirection == eNavigationDirection_End &&
-             isContainer && !isDisabled) {
-      // The menu is not yet open. Open it and select the first item.
-      aHandledFlag = PR_TRUE;
-      nsIFrame* frame = nsnull;
-      CallQueryInterface(mCurrentMenu, &frame);
-      nsWeakFrame weakCurrentFrame(frame);
-      mCurrentMenu->OpenMenu(PR_TRUE);
-      NS_ENSURE_TRUE(weakCurrentFrame.IsAlive(), NS_OK);
-      mCurrentMenu->SelectFirstItem();
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-    }
-  }
-
-  if (aHandledFlag)
-    return NS_OK; // The child menu took it for us.
-
-  // For block progression, we can move in either direction
-  if (NS_DIRECTION_IS_BLOCK(theDirection) ||
-      NS_DIRECTION_IS_BLOCK_TO_EDGE(theDirection)) {
-
-    nsIMenuFrame* nextItem;
-    
-    if (theDirection == eNavigationDirection_Before)
-      nextItem = GetPreviousMenuItem(mCurrentMenu);
-    else if (theDirection == eNavigationDirection_After)
-      nextItem = GetNextMenuItem(mCurrentMenu);
-    else if (theDirection == eNavigationDirection_First)
-      nextItem = GetNextMenuItem(nsnull);
-    else
-      nextItem = GetPreviousMenuItem(nsnull);
-
-    if (nextItem) {
-      aHandledFlag = PR_TRUE;
-      SetCurrentMenuItem(nextItem);
-    }
-  }
-  else if (mCurrentMenu && isContainer && isOpen) {
-    if (theDirection == eNavigationDirection_Start) {
-      // Close it up.
-      mCurrentMenu->OpenMenu(PR_FALSE);
-      NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK);
-      // SelectMenu() so DOMMenuItemActive is fired for accessibility
-      mCurrentMenu->SelectMenu(PR_TRUE);
-      aHandledFlag = PR_TRUE;
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuPopupFrame::GetParentPopup(nsIMenuParent** aMenuParent)
-{
-  *aMenuParent = nsnull;
-  nsIFrame* parent = GetParent();
-  while (parent) {
-    nsCOMPtr<nsIMenuParent> menuParent = do_QueryInterface(parent);
-    if (menuParent) {
-      *aMenuParent = menuParent.get();
-      NS_ADDREF(*aMenuParent);
-      return NS_OK;
-    }
-    parent = parent->GetParent();
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuPopupFrame::HideChain()
-{
-  if (!mShouldRollup)
-    return NS_OK;
-
-  // Stop capturing rollups
-  // (must do this during Hide, which happens before the menu item is executed,
-  // since this reinstates normal event handling.)
-  nsMenuDismissalListener::Shutdown();
-  
-  nsIFrame* frame = GetParent();
-  if (frame) {
-    nsWeakFrame weakMenu(frame);
-    nsIMenuFrame* menuFrame;
-    if (NS_FAILED(CallQueryInterface(frame, &menuFrame))) {
-      nsIPopupSetFrame* popupSetFrame = GetPopupSetFrame(PresContext());
-      if (popupSetFrame)
-        // Hide the popup.
-        popupSetFrame->HidePopup(this);
-      return NS_OK;
-    }
-   
-    menuFrame->ActivateMenu(PR_FALSE);
-    NS_ENSURE_TRUE(weakMenu.IsAlive(), NS_OK);
-    menuFrame->SelectMenu(PR_FALSE);
-    NS_ENSURE_TRUE(weakMenu.IsAlive(), NS_OK);
-
-    // Get the parent.
-    nsIMenuParent *menuParent = menuFrame->GetMenuParent();
-    if (menuParent)
-      menuParent->HideChain();
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuPopupFrame::DismissChain()
-{
-  if (!mShouldRollup)
-    return NS_OK;
-
-  // Stop capturing rollups
-  nsMenuDismissalListener::Shutdown();
-  
-  // Get our menu parent.
-  nsIFrame* frame = GetParent();
-  if (frame) {
-    nsIMenuFrame *menuFrame = nsnull;
-    CallQueryInterface(frame, &menuFrame);
-    if (!menuFrame) {
-      nsIPopupSetFrame* popupSetFrame = GetPopupSetFrame(PresContext());
-      if (popupSetFrame) {
-        // make sure the menu is not highlighted
-        if (mCurrentMenu) {
-          PRBool wasOpen;
-          mCurrentMenu->MenuIsOpen(wasOpen);
-          if (wasOpen)
-            mCurrentMenu->OpenMenu(PR_FALSE);
-          mCurrentMenu->SelectMenu(PR_FALSE);
-        }
-        // Destroy the popup.
-        popupSetFrame->DestroyPopup(this, PR_TRUE);
-      }
-      return NS_OK;
-    }
-  
-    menuFrame->OpenMenu(PR_FALSE);
-
-    // Get the parent.
-    nsIMenuParent* menuParent = menuFrame->GetMenuParent();
-    if (menuParent)
-      menuParent->DismissChain();
-  }
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 nsMenuPopupFrame::GetWidget(nsIWidget **aWidget)
 {
   // Get parent view
-  nsIView * view = nsnull;
   // XXX should this be passing PR_FALSE or PR_TRUE for aStopAtViewManagerRoot?
-  nsMenuPopupFrame::GetRootViewForPopup(this, PR_FALSE, &view);
+  nsIView * view = GetRootViewForPopup(this, PR_FALSE);
   if (!view)
     return NS_OK;
 
   *aWidget = view->GetWidget();
   NS_IF_ADDREF(*aWidget);
   return NS_OK;
 }
 
-NS_IMETHODIMP
+void
 nsMenuPopupFrame::AttachedDismissalListener()
 {
   mConsumeRollupEvent = nsIPopupBoxObject::ROLLUP_DEFAULT;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuPopupFrame::InstallKeyboardNavigator()
-{
-  if (mKeyboardNavigator)
-    return NS_OK;
-
-  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mContent->GetDocument());
-  
-  mTarget = target;
-  mKeyboardNavigator = new nsMenuListener(this);
-  NS_IF_ADDREF(mKeyboardNavigator);
-
-  target->AddEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE); 
-  target->AddEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);  
-  target->AddEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);   
-
-  nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_TRUE);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsMenuPopupFrame::RemoveKeyboardNavigator()
-{
-  if (!mKeyboardNavigator)
-    return NS_OK;
-
-  mTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
-  mTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
-  mTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), (nsIDOMKeyListener*)mKeyboardNavigator, PR_TRUE);
-
-  NS_IF_RELEASE(mKeyboardNavigator);
-
-  nsContentUtils::NotifyInstalledMenuKeyboardListener(PR_FALSE);
-
-  return NS_OK;
 }
 
 // helpers /////////////////////////////////////////////////////////////
 
-PRBool 
-nsMenuPopupFrame::IsValidItem(nsIContent* aContent)
-{
-  nsIAtom *tag = aContent->Tag();
-  
-  PRBool skipNavigatingDisabledMenuItem;
-  PresContext()->LookAndFeel()->
-    GetMetric(nsILookAndFeel::eMetric_SkipNavigatingDisabledMenuItem,
-              skipNavigatingDisabledMenuItem);
-
-  PRBool result = (tag == nsGkAtoms::menu ||
-                   tag == nsGkAtoms::menuitem ||
-                   tag == nsGkAtoms::option);
-  if (skipNavigatingDisabledMenuItem)
-    result = result && !IsDisabled(aContent);
-
-  return result;
-}
-
-PRBool 
-nsMenuPopupFrame::IsDisabled(nsIContent* aContent)
-{
-  return aContent->AttrValueIs