From 7f0ad5821355d88b24c405ffd8b016e92f2e1ec0 Mon Sep 17 00:00:00 2001 From: "roc+@cs.cmu.edu" Date: Wed, 23 Apr 2008 14:25:34 -0700 Subject: [PATCH] Bug 312225. When we flip a menu vertically to keep it off the bottom of the screen, we need to reverse the 2px vertical offset from the mouse cursor that we introduce for context menus. --- .../xul/content/src/nsXULPopupListener.cpp | 7 ------ layout/xul/base/public/nsXULPopupManager.h | 4 ++++ layout/xul/base/src/nsMenuPopupFrame.cpp | 24 ++++++++++++++++--- layout/xul/base/src/nsMenuPopupFrame.h | 10 +++++++- layout/xul/base/src/nsXULPopupManager.cpp | 2 +- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/content/xul/content/src/nsXULPopupListener.cpp b/content/xul/content/src/nsXULPopupListener.cpp index d32dafb26a63..b25433d663a9 100644 --- a/content/xul/content/src/nsXULPopupListener.cpp +++ b/content/xul/content/src/nsXULPopupListener.cpp @@ -470,13 +470,6 @@ nsXULPopupListener::LaunchPopup(nsIDOMEvent* aEvent, nsIContent* aTargetContent) mouseEvent->GetScreenX(&xPos); mouseEvent->GetScreenY(&yPos); - 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, aEvent); } diff --git a/layout/xul/base/public/nsXULPopupManager.h b/layout/xul/base/public/nsXULPopupManager.h index 633f95686ae7..1a3c5c2fff85 100644 --- a/layout/xul/base/public/nsXULPopupManager.h +++ b/layout/xul/base/public/nsXULPopupManager.h @@ -422,6 +422,10 @@ public: * measured in CSS pixels. * * This fires the popupshowing event synchronously. + * + * If aIsContextMenu is true, the popup is positioned at a slight + * offset from aXPos/aYPos to ensure that it is not under the mouse + * cursor. */ void ShowPopupAtScreen(nsIContent* aPopup, PRInt32 aXPos, PRInt32 aYPos, diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index 94901a3eac0a..a99cb77dfb05 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -110,6 +110,7 @@ nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContex mPopupState(ePopupClosed), mIsOpenChanged(PR_FALSE), mIsContextMenu(PR_FALSE), + mAdjustOffsetForContextMenu(PR_FALSE), mGeneratedChildren(PR_FALSE), mMenuCanOverlapOSBar(PR_FALSE), mShouldAutoPosition(PR_TRUE), @@ -381,6 +382,7 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent, mAnchorContent = aAnchorContent; mXPos = aXPos; mYPos = aYPos; + mAdjustOffsetForContextMenu = PR_FALSE; // if aAttributesOverride is true, then the popupanchor, popupalign and // position attributes on the override those values passed in. @@ -476,7 +478,8 @@ nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent, } void -nsMenuPopupFrame::InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos) +nsMenuPopupFrame::InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos, + PRBool aIsContextMenu) { EnsureWidget(); @@ -486,6 +489,8 @@ nsMenuPopupFrame::InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos) mScreenYPos = aYPos; mPopupAnchor = POPUPALIGNMENT_NONE; mPopupAlignment = POPUPALIGNMENT_NONE; + mIsContextMenu = aIsContextMenu; + mAdjustOffsetForContextMenu = aIsContextMenu; } void @@ -497,6 +502,7 @@ nsMenuPopupFrame::InitializePopupWithAnchorAlign(nsIContent* aAnchorContent, EnsureWidget(); mPopupState = ePopupShowing; + mAdjustOffsetForContextMenu = PR_FALSE; // this popup opening function is provided for backwards compatibility // only. It accepts either coordinates or an anchor and alignment value @@ -947,6 +953,7 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame) nsRect rootScreenRect = rootFrame->GetScreenRect(); nsIDeviceContext* devContext = PresContext()->DeviceContext(); + nscoord offsetForContextMenu = 0; 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 @@ -986,11 +993,19 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame) screenViewLocX = nsPresContext::CSSPixelsToAppUnits(mScreenXPos) / factor; screenViewLocY = nsPresContext::CSSPixelsToAppUnits(mScreenYPos) / factor; + if (mAdjustOffsetForContextMenu) { + PRInt32 offsetForContextMenuDev = + nsPresContext::CSSPixelsToAppUnits(2) / factor; + offsetForContextMenu = presContext->DevPixelsToAppUnits(offsetForContextMenuDev); + } + // next, convert back into app units accounting for the scaling, // and add the margins on the popup GetStyleMargin()->GetMargin(margin); - screenViewLocX = presContext->DevPixelsToAppUnits(screenViewLocX) + margin.left; - screenViewLocY = presContext->DevPixelsToAppUnits(screenViewLocY) + margin.top; + screenViewLocX = presContext->DevPixelsToAppUnits(screenViewLocX) + + margin.left + offsetForContextMenu; + screenViewLocY = presContext->DevPixelsToAppUnits(screenViewLocY) + + margin.top + offsetForContextMenu; // determine the x and y position by subtracting the desired screen // position from the screen position of the root frame. @@ -1213,6 +1228,9 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame) } else { // More space above our desired point. Flip and resize to fit in this // space. + // First move screenViewLocY and ypos up because the offset needs to flip + screenViewLocY -= 2*offsetForContextMenu; + ypos -= 2*offsetForContextMenu; if (mRect.height > screenViewLocY - screenTopTwips) { // We wouldn't fit. Shorten before flipping. mRect.height = screenViewLocY - screenTopTwips; diff --git a/layout/xul/base/src/nsMenuPopupFrame.h b/layout/xul/base/src/nsMenuPopupFrame.h index 5c17f29cdcec..3a8b76da7896 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.h +++ b/layout/xul/base/src/nsMenuPopupFrame.h @@ -228,7 +228,13 @@ public: PRInt32 aXPos, PRInt32 aYPos, PRBool aAttributesOverride); - void InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos); + /** + * @param aIsContextMenu if true, then the popup is + * positioned at a slight offset from aXPos/aYPos to ensure the + * (presumed) mouse position is not over the menu. + */ + void InitializePopupAtScreen(PRInt32 aXPos, PRInt32 aYPos, + PRBool aIsContextMenu); void InitializePopupWithAnchorAlign(nsIContent* aAnchorContent, nsAString& aAnchor, @@ -327,6 +333,8 @@ protected: PRPackedBool mIsOpenChanged; // true if the open state changed since the last layout PRPackedBool mIsContextMenu; // true for context menus + // true if we need to offset the popup to ensure it's not under the mouse + PRPackedBool mAdjustOffsetForContextMenu; PRPackedBool mGeneratedChildren; // true if the contents have been created PRPackedBool mMenuCanOverlapOSBar; // can we appear over the taskbar/menubar? diff --git a/layout/xul/base/src/nsXULPopupManager.cpp b/layout/xul/base/src/nsXULPopupManager.cpp index 927fe8197b66..731e5f055345 100644 --- a/layout/xul/base/src/nsXULPopupManager.cpp +++ b/layout/xul/base/src/nsXULPopupManager.cpp @@ -469,7 +469,7 @@ nsXULPopupManager::ShowPopupAtScreen(nsIContent* aPopup, SetTriggerEvent(aTriggerEvent, aPopup); - popupFrame->InitializePopupAtScreen(aXPos, aYPos); + popupFrame->InitializePopupAtScreen(aXPos, aYPos, aIsContextMenu); FirePopupShowingEvent(aPopup, nsnull, popupFrame->PresContext(), popupFrame->PopupType(), aIsContextMenu, PR_FALSE);