Bug 279703, backing out the popup changes due to performance regressions. sigh.
authorenndeakin@sympatico.ca
Fri, 29 Jun 2007 15:39:50 -0700
changeset 2947 2ac122696d2d3d20ccce2c0ab1a13acc7bfd9bbb
parent 2946 317abe6fc05ca31883fe0b36177bf7c62aa44388
child 2948 bd6d109cb8578c9a954be222a8ceeef0b15c188c
push idunknown
push userunknown
push dateunknown
bugs279703
milestone1.9a6pre
Bug 279703, backing out the popup changes due to performance regressions. sigh.
content/base/src/nsGkAtomList.h
content/xul/content/Makefile.in
layout/xul/base/src/nsIMenuParent.h
layout/xul/base/src/nsIRootBox.h
layout/xul/base/src/nsMenuBarFrame.cpp
layout/xul/base/src/nsXULTooltipListener.cpp
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -483,16 +483,17 @@ 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")
@@ -514,17 +515,16 @@ 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,17 +629,16 @@ 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,25 +1385,22 @@ GK_ATOM(subDocumentFrame, "subDocumentFr
 GK_ATOM(imageBoxFrame, "ImageBoxFrame")
 GK_ATOM(imageFrame, "ImageFrame")
 GK_ATOM(imageControlFrame, "ImageControlFrame")
 GK_ATOM(inlineFrame, "InlineFrame")
 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		= src test
+DIRS		= public src test
 
 include $(topsrcdir)/config/rules.mk
 
--- a/layout/xul/base/src/nsIMenuParent.h
+++ b/layout/xul/base/src/nsIMenuParent.h
@@ -34,58 +34,150 @@
  * 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___
 
-class nsMenuFrame;
+
+// {33f700c8-976a-4cdb-8f6c-d9f4cfee8366}
+#define NS_IMENUPARENT_IID \
+{ 0x33f700c8, 0x976a, 0x4cdb, { 0x8f, 0x6c, 0xd9, 0xf4, 0xcf, 0xee, 0x83, 0x66 } }
+
+class nsIMenuFrame;
+class nsIDOMKeyEvent;
 
 /*
- * nsIMenuParent is an interface implemented by nsMenuBarFrame and nsMenuPopupFrame
- * as both serve as parent frames to 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).
  *
- * 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.
+ * 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
+ * 
  */
 
-class nsIMenuParent {
+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 {
 
 public:
-  // 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_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 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;
+  NS_IMETHOD AttachedDismissalListener() = 0;
+
+  NS_IMETHOD InstallKeyboardNavigator() = 0;
+  NS_IMETHOD RemoveKeyboardNavigator() = 0;
 
-  // indicate that the menubar should become active or inactive
-  NS_IMETHOD SetActive(PRBool aActiveFlag) = 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;
 
-  // 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_IMETHOD SetIsContextMenu(PRBool aIsContextMenu) = 0;
+  NS_IMETHOD GetIsContextMenu(PRBool& aIsContextMenu) = 0;
+
+  NS_IMETHOD GetParentPopup(nsIMenuParent** aResult) = 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 nsPopupSetFrame;
+class nsIFrame;
 class nsIContent;
 class nsIPresShell;
 
-// {9777EC2A-9A46-4D01-8CEB-B9CEB2C262A5}
+// {2256d568-3f5a-42ec-b932-3d0f78551a1a}
 #define NS_IROOTBOX_IID \
-{ 0x9777EC2A, 0x9A46, 0x4D01, \
-  { 0x8C, 0xEB, 0xB9, 0xCE, 0xB2, 0xC2, 0x62, 0xA5 } }
+{ 0x2256d568, 0x3f5a, 0x42ec, \
+  { 0xb9, 0x32, 0x3d, 0x0f, 0x78, 0x55, 0x1a, 0x1a } }
 
 
 class nsIRootBox : public nsISupports {
 
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IROOTBOX_IID)
 
-  virtual nsPopupSetFrame* GetPopupSetFrame() = 0;
-  virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) = 0;
+  virtual nsIFrame* GetPopupSetFrame() = 0;
+  virtual void SetPopupSetFrame(nsIFrame* 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,19 +32,21 @@
  * 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"
@@ -72,28 +74,61 @@
 // 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.
@@ -117,31 +152,36 @@ 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();
   }
   
@@ -194,68 +234,65 @@ nsMenuBarFrame::SetActive(PRBool aActive
     if (!mIsActive) {
       mCaretWasVisible = PR_FALSE;
     }
   } while (0);
 
   NS_NAMED_LITERAL_STRING(active, "DOMMenuBarActive");
   NS_NAMED_LITERAL_STRING(inactive, "DOMMenuBarInactive");
   
-  FireDOMEvent(mIsActive ? active : inactive, mContent);
+  FireDOMEventSynch(mIsActive ? active : inactive);
 
   return NS_OK;
 }
 
-nsMenuFrame*
+void
 nsMenuBarFrame::ToggleMenuActiveState()
 {
   if (mIsActive) {
     // Deactivate the menu bar
     SetActive(PR_FALSE);
     if (mCurrentMenu) {
-      nsMenuFrame* closeframe = mCurrentMenu;
-      closeframe->SelectMenu(PR_FALSE);
+      // Deactivate the menu.
+      mCurrentMenu->OpenMenu(PR_FALSE);
+      mCurrentMenu->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.
-    nsMenuFrame* firstFrame = nsXULPopupManager::GetNextMenuItem(this, nsnull, PR_FALSE);
+    nsIMenuFrame* firstFrame = GetNextMenuItem(nsnull);
     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);
 }
 
-nsMenuFrame*
+nsIMenuFrame*
 nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
 {
   PRUint32 charCode;
   aKeyEvent->GetCharCode(&charCode);
 
   // Enumerate over our list of frames.
   nsIFrame* immediateParent = nsnull;
   GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
@@ -263,180 +300,519 @@ nsMenuBarFrame::FindMenuWithShortcut(nsI
     immediateParent = this;
 
   nsIFrame* currFrame = immediateParent->GetFirstChild(nsnull);
 
   while (currFrame) {
     nsIContent* current = currFrame->GetContent();
     
     // See if it's a menu item.
-    if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, PR_FALSE)) {
+    if (IsValidItem(current)) {
       // 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!
-          return (currFrame->GetType() == nsGkAtoms::menuFrame) ?
-                 NS_STATIC_CAST(nsMenuFrame *, currFrame) : nsnull;
+          nsIMenuFrame *menuFrame;
+          if (NS_FAILED(CallQueryInterface(currFrame, &menuFrame))) {
+            menuFrame = nsnull;
+          }
+          return menuFrame;
         }
       }
     }
     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();
   }
 
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm)
-    pm->Rollup();
-
-  SetCurrentMenuItem(nsnull);
-  SetActive(PR_FALSE);
-
+  DismissChain();
 #endif  // #ifdef XP_WIN
 
   return nsnull;
 }
 
-/* virtual */ nsMenuFrame*
+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*
 nsMenuBarFrame::GetCurrentMenuItem()
 {
   return mCurrentMenu;
 }
 
-NS_IMETHODIMP
-nsMenuBarFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
+
+NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* 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);
+
 
-  if (aMenuItem)
+  // Set the new child.
+  if (aMenuItem) {
+    nsIFrame* newMenu = nsnull;
+    CallQueryInterface(aMenuItem, &newMenu);
+    nsWeakFrame weakNewMenu(newMenu);
     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;
 }
 
-void
-nsMenuBarFrame::CurrentMenuIsBeingDestroyed()
+
+NS_IMETHODIMP 
+nsMenuBarFrame::Escape(PRBool& aHandledFlag)
 {
-  mCurrentMenu->SelectMenu(PR_FALSE);
-  mCurrentMenu = nsnull;
+  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;
 }
 
 NS_IMETHODIMP
-nsMenuBarFrame::ChangeMenuItem(nsMenuFrame* aMenuItem,
-                               PRBool aSelectFirstItem)
+nsMenuBarFrame::ClearRecentlyRolledUp()
 {
-  if (mCurrentMenu == aMenuItem)
-    return NS_OK;
+  // 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;
 
-  // check if there's an open context menu, we ignore this
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm && pm->HasContextMenu(nsnull))
-    return NS_OK;
+  return NS_OK;
+}
 
-  // 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);
-    }
+NS_IMETHODIMP
+nsMenuBarFrame::RecentlyRolledUp(nsIMenuFrame *aMenuFrame, PRBool *aJustRolledUp)
+{
+  // 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);
+
+  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);
   }
 
-  // set to null first in case the IsAlive check below returns false
-  mCurrentMenu = nsnull;
+  // 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 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);
+  ClearRecentlyRolledUp();
+  if (mCurrentMenu) {
+    mCurrentMenu->ActivateMenu(PR_FALSE);
+    mCurrentMenu->SelectMenu(PR_FALSE);
+    mRecentRollupMenu = mCurrentMenu;
+  }
+
+  if (mIsActive) {
+    ToggleMenuActiveState();
   }
 
   return NS_OK;
 }
 
-nsMenuFrame*
-nsMenuBarFrame::Enter()
+NS_IMETHODIMP
+nsMenuBarFrame::DismissChain()
+{
+  // Stop capturing rollups
+  nsMenuDismissalListener::Shutdown();
+  nsWeakFrame weakFrame(this);
+  SetCurrentMenuItem(nsnull);
+  if (weakFrame.IsAlive()) {
+    SetActive(PR_FALSE);
+  }
+  return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsMenuBarFrame::KillPendingTimers ( )
 {
-  if (!mCurrentMenu)
-    return nsnull;
+  return NS_OK;
+
+} // KillPendingTimers
+
 
-  if (mCurrentMenu->IsOpen())
-    return mCurrentMenu->Enter();
-
-  return mCurrentMenu;
+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;
 }
 
-PRBool
-nsMenuBarFrame::MenuClosed()
+NS_IMETHODIMP
+nsMenuBarFrame::InstallKeyboardNavigator()
 {
-  SetActive(PR_FALSE);
-  if (!mIsActive && mCurrentMenu) {
-    mCurrentMenu->SelectMenu(PR_FALSE);
-    mCurrentMenu = nsnull;
-    return PR_TRUE;
-  }
-  return PR_FALSE;
+  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;
 }
 
-void
-nsMenuBarFrame::InstallKeyboardNavigator()
+NS_IMETHODIMP
+nsMenuBarFrame::RemoveKeyboardNavigator()
 {
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm)
-    pm->SetActiveMenuBar(this, PR_TRUE);
+  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;
 }
 
-void
-nsMenuBarFrame::RemoveKeyboardNavigator()
+// helpers ///////////////////////////////////////////////////////////
+
+PRBool 
+nsMenuBarFrame::IsValidItem(nsIContent* aContent)
 {
-  if (!mIsActive) {
-    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-    if (pm)
-      pm->SetActiveMenuBar(this, PR_FALSE);
-  }
+  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);
 }
 
 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/nsXULTooltipListener.cpp
+++ b/layout/xul/base/src/nsXULTooltipListener.cpp
@@ -41,29 +41,29 @@
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDocument.h"
 #include "nsGkAtoms.h"
 #include "nsIPresShell.h"
 #include "nsIFrame.h"
+#include "nsIMenuFrame.h"
 #include "nsIPopupBoxObject.h"
 #include "nsIServiceManager.h"
 #ifdef MOZ_XUL
 #include "nsIDOMNSDocument.h"
 #include "nsITreeView.h"
 #endif
 #include "nsGUIEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsPresContext.h"
 #include "nsIScriptContext.h"
 #include "nsPIDOMWindow.h"
 #include "nsContentUtils.h"
-#include "nsXULPopupManager.h"
 #include "nsIRootBox.h"
 
 nsXULTooltipListener* nsXULTooltipListener::mInstance = nsnull;
 
 //////////////////////////////////////////////////////////////////////////
 //// nsISupports
 
 nsXULTooltipListener::nsXULTooltipListener()
@@ -204,18 +204,18 @@ nsXULTooltipListener::MouseMove(nsIDOMEv
     return NS_OK;
 
   // stash the coordinates of the event so that we can still get back to it from within the 
   // timer callback. On win32, we'll get a MouseMove event even when a popup goes away --
   // even when the mouse doesn't change position! To get around this, we make sure the
   // mouse has really moved before proceeding.
   nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aMouseEvent));
   PRInt32 newMouseX, newMouseY;
-  mouseEvent->GetScreenX(&newMouseX);
-  mouseEvent->GetScreenY(&newMouseY);
+  mouseEvent->GetClientX(&newMouseX);
+  mouseEvent->GetClientY(&newMouseY);
   if (mMouseClientX == newMouseX && mMouseClientY == newMouseY)
     return NS_OK;
   mMouseClientX = newMouseX;
   mMouseClientY = newMouseY;
 
   nsCOMPtr<nsIDOMEventTarget> eventTarget;
   aMouseEvent->GetCurrentTarget(getter_AddRefs(eventTarget));
   mSourceNode = do_QueryInterface(eventTarget);
@@ -408,18 +408,22 @@ nsXULTooltipListener::ShowTooltip()
 
       xulDoc->SetTooltipNode(mTargetNode);
       LaunchTooltip();
       mTargetNode = nsnull;
 
       // at this point, |mCurrentTooltip| holds the content node of
       // the tooltip. If there is an attribute on the popup telling us
       // not to create the auto-hide timer, don't.
-      if (mCurrentTooltip->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautohide,
-                                       nsGkAtoms::_true, eCaseMatters))
+      nsCOMPtr<nsIDOMElement> tooltipEl(do_QueryInterface(mCurrentTooltip));
+      if (!tooltipEl)
+        return NS_ERROR_FAILURE;
+      nsAutoString noAutoHide;
+      tooltipEl->GetAttribute(NS_LITERAL_STRING("noautohide"), noAutoHide);
+      if (!noAutoHide.EqualsLiteral("true"))
         CreateAutoHideTimer();
 
       // listen for popuphidden on the tooltip node, so that we can
       // be sure DestroyPopup is called even if someone else closes the tooltip
       nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(mCurrentTooltip));
       evtTarget->AddEventListener(NS_LITERAL_STRING("popuphiding"), 
                                   (nsIDOMMouseListener*)this, PR_FALSE);
 
@@ -480,48 +484,76 @@ SetTitletipLabel(nsITreeBoxObject* aTree
 #endif
 
 void
 nsXULTooltipListener::LaunchTooltip()
 {
   if (!mCurrentTooltip)
     return;
 
+  nsCOMPtr<nsIBoxObject> popupBox;
+  nsCOMPtr<nsIDOMXULElement> xulTooltipEl(do_QueryInterface(mCurrentTooltip));
+  if (!xulTooltipEl) {
+    NS_ERROR("tooltip isn't a XUL element!");
+    return;
+  }
+
+  xulTooltipEl->GetBoxObject(getter_AddRefs(popupBox));
+  nsCOMPtr<nsIPopupBoxObject> popupBoxObject(do_QueryInterface(popupBox));
+  if (popupBoxObject) {
+    PRInt32 x = mMouseClientX;
+    PRInt32 y = mMouseClientY;
 #ifdef MOZ_XUL
-  if (mIsSourceTree && mNeedTitletip) {
-    nsCOMPtr<nsITreeBoxObject> obx;
-    GetSourceTreeBoxObject(getter_AddRefs(obx));
+    if (mIsSourceTree && mNeedTitletip) {
+      nsCOMPtr<nsITreeBoxObject> obx;
+      GetSourceTreeBoxObject(getter_AddRefs(obx));
+#ifdef DEBUG_crap
+      GetTreeCellCoords(obx, mSourceNode,
+                        mLastTreeRow, mLastTreeCol, &x, &y);
+#endif
 
-    SetTitletipLabel(obx, mCurrentTooltip, mLastTreeRow, mLastTreeCol);
+      SetTitletipLabel(obx, mCurrentTooltip, mLastTreeRow, mLastTreeCol);
+      if (!mCurrentTooltip) {
+        // Because of mutation events, mCurrentTooltip can be null.
+        return;
+      }
+      mCurrentTooltip->SetAttr(kNameSpaceID_None, nsGkAtoms::titletip,
+                               NS_LITERAL_STRING("true"), PR_TRUE);
+    } else {
+      mCurrentTooltip->UnsetAttr(kNameSpaceID_None, nsGkAtoms::titletip,
+                                 PR_TRUE);
+    }
     if (!mCurrentTooltip) {
       // Because of mutation events, mCurrentTooltip can be null.
       return;
     }
-    mCurrentTooltip->SetAttr(nsnull, nsGkAtoms::titletip, NS_LITERAL_STRING("true"), PR_TRUE);
-  } else {
-    mCurrentTooltip->UnsetAttr(nsnull, nsGkAtoms::titletip, PR_TRUE);
-  }
-  if (!mCurrentTooltip) {
-    // Because of mutation events, mCurrentTooltip can be null.
-    return;
-  }
 #endif
 
-  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-  if (pm)
-    pm->ShowPopupAtScreen(mCurrentTooltip, mMouseClientX, mMouseClientY, PR_FALSE);
+    nsCOMPtr<nsIDOMElement> targetEl(do_QueryInterface(mSourceNode));
+    popupBoxObject->ShowPopup(targetEl, xulTooltipEl, x, y,
+                              NS_LITERAL_STRING("tooltip").get(),
+                              NS_LITERAL_STRING("none").get(),
+                              NS_LITERAL_STRING("topleft").get());
+  }
+
+  return;
 }
 
 nsresult
 nsXULTooltipListener::HideTooltip()
 {
   if (mCurrentTooltip) {
-    nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
-    if (pm)
-      pm->HidePopup(mCurrentTooltip, PR_FALSE, PR_FALSE, PR_FALSE);
+    // hide the popup through its box object
+    nsCOMPtr<nsIDOMXULElement> tooltipEl(do_QueryInterface(mCurrentTooltip));
+    nsCOMPtr<nsIBoxObject> boxObject;
+    if (tooltipEl)
+      tooltipEl->GetBoxObject(getter_AddRefs(boxObject));
+    nsCOMPtr<nsIPopupBoxObject> popupObject(do_QueryInterface(boxObject));
+    if (popupObject)
+      popupObject->HidePopup();
   }
 
   DestroyTooltip();
   return NS_OK;
 }
 
 static void
 GetImmediateChild(nsIContent* aContent, nsIAtom *aTag, nsIContent** aResult) 
@@ -632,19 +664,20 @@ nsXULTooltipListener::GetTooltipFor(nsIC
   }
 
   // Submenus can't be used as tooltips, see bug 288763.
   nsIContent* parent = tooltip->GetParent();
   if (parent) {
     nsIDocument* doc = parent->GetCurrentDoc();
     nsIPresShell* presShell = doc ? doc->GetPrimaryShell() : nsnull;
     nsIFrame* frame = presShell ? presShell->GetPrimaryFrameFor(parent) : nsnull;
-    if (frame && frame->GetType() == nsGkAtoms::menuFrame) {
-      NS_WARNING("Menu cannot be used as a tooltip");
-      return NS_ERROR_FAILURE;
+    if (frame) {
+      nsIMenuFrame* menu = nsnull;
+      CallQueryInterface(frame, &menu);
+      NS_ENSURE_FALSE(menu, NS_ERROR_FAILURE);
     }
   }
 
   tooltip.swap(*aTooltip);
   return rv;
 }
 
 nsresult
@@ -703,17 +736,17 @@ nsXULTooltipListener::KillTooltipTimer()
 
 void
 nsXULTooltipListener::CreateAutoHideTimer()
 {
   if (mAutoHideTimer) {
     mAutoHideTimer->Cancel();
     mAutoHideTimer = nsnull;
   }
-
+  
   mAutoHideTimer = do_CreateInstance("@mozilla.org/timer;1");
   if ( mAutoHideTimer )
     mAutoHideTimer->InitWithFuncCallback(sAutoHideCallback, this, kTooltipAutoHideTime, 
                                          nsITimer::TYPE_ONE_SHOT);
 }
 
 void
 nsXULTooltipListener::sTooltipCallback(nsITimer *aTimer, void *aListener)