--- 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)