--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -113,16 +113,17 @@ nsMenuPopupFrame::nsMenuPopupFrame(nsSty
, mIsContextMenu(false)
, mAdjustOffsetForContextMenu(false)
, mGeneratedChildren(false)
, mMenuCanOverlapOSBar(false)
, mShouldAutoPosition(true)
, mInContentShell(true)
, mIsMenuLocked(false)
, mMouseTransparent(false)
+ , mIsOffset(false)
, mHFlip(false)
, mVFlip(false)
, mAnchorType(MenuPopupAnchorType_Node)
{
// the preference name is backwards here. True means that the 'top' level is
// the default, and false means that the 'parent' level is the default.
if (sDefaultLevelIsTop >= 0)
return;
@@ -596,17 +597,17 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayou
pc->PresShell()->PostReflowCallback(this);
mReflowCallbackData.MarkPosted(aAnchor, aSizedToPopup);
}
}
bool
nsMenuPopupFrame::ReflowFinished()
{
- SetPopupPosition(mReflowCallbackData.mAnchor, false, mReflowCallbackData.mSizedToPopup, false);
+ SetPopupPosition(mReflowCallbackData.mAnchor, false, mReflowCallbackData.mSizedToPopup, true);
mReflowCallbackData.Clear();
return false;
}
void
nsMenuPopupFrame::ReflowCallbackCanceled()
@@ -1553,20 +1554,24 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
hFlip = FlipStyle_Outside;
}
#else
// Other OS screen positioned popups can be flipped vertically but never horizontally
vFlip = FlipStyle_Outside;
#endif // #ifdef XP_MACOSX
}
- // If a panel is being moved or has flip="none", don't constrain or flip it. But always do this for
+ nscoord oldAlignmentOffset = mAlignmentOffset;
+
+ // If a panel is being moved or has flip="none", don't constrain or flip it, in order to avoid
+ // visual noise when moving windows between screens. However, if a panel is already constrained
+ // or flipped (mIsOffset), then we want to continue to calculate this. Also, always do this for
// content shells, so that the popup doesn't extend outside the containing frame.
if (mInContentShell || (mFlip != FlipType_None &&
- (!aIsMove || mPopupType != ePopupTypePanel))) {
+ (!aIsMove || mIsOffset || mPopupType != ePopupTypePanel))) {
int32_t appPerDev = presContext->AppUnitsPerDevPixel();
LayoutDeviceIntRect anchorRectDevPix =
LayoutDeviceIntRect::FromAppUnitsToNearest(anchorRect, appPerDev);
LayoutDeviceIntRect rootScreenRectDevPix =
LayoutDeviceIntRect::FromAppUnitsToNearest(rootScreenRect, appPerDev);
LayoutDeviceIntRect screenRectDevPix =
GetConstraintRect(anchorRectDevPix, rootScreenRectDevPix, popupLevel);
nsRect screenRect =
@@ -1597,37 +1602,41 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
}
// Next, check if there is enough space to show the popup at full size when
// positioned at screenPoint. If not, flip the popups to the opposite side
// of their anchor point, or resize them as necessary.
bool endAligned = IsDirectionRTL() ?
mPopupAlignment == POPUPALIGNMENT_TOPLEFT || mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT :
mPopupAlignment == POPUPALIGNMENT_TOPRIGHT || mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT;
+ nscoord preOffsetScreenPoint = screenPoint.x;
if (slideHorizontal) {
mRect.width = SlideOrResize(screenPoint.x, mRect.width, screenRect.x,
screenRect.XMost(), &mAlignmentOffset);
} else {
mRect.width = FlipOrResize(screenPoint.x, mRect.width, screenRect.x,
screenRect.XMost(), anchorRect.x, anchorRect.XMost(),
margin.left, margin.right, offsetForContextMenu.x, hFlip,
endAligned, &mHFlip);
}
+ mIsOffset = preOffsetScreenPoint != screenPoint.x;
endAligned = mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT ||
mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT;
+ preOffsetScreenPoint = screenPoint.y;
if (slideVertical) {
mRect.height = SlideOrResize(screenPoint.y, mRect.height, screenRect.y,
screenRect.YMost(), &mAlignmentOffset);
} else {
mRect.height = FlipOrResize(screenPoint.y, mRect.height, screenRect.y,
screenRect.YMost(), anchorRect.y, anchorRect.YMost(),
margin.top, margin.bottom, offsetForContextMenu.y, vFlip,
endAligned, &mVFlip);
}
+ mIsOffset = mIsOffset || (preOffsetScreenPoint != screenPoint.y);
NS_ASSERTION(screenPoint.x >= screenRect.x && screenPoint.y >= screenRect.y &&
screenPoint.x + mRect.width <= screenRect.XMost() &&
screenPoint.y + mRect.height <= screenRect.YMost(),
"Popup is offscreen");
}
// snap the popup's position in screen coordinates to device pixels,
@@ -1664,17 +1673,18 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
// XXXndeakin can parentSize.width still extend outside?
SetXULBounds(state, mRect);
}
// If the popup is in the positioned state or if it is shown and the position
// or size changed, dispatch a popuppositioned event if the popup wants it.
nsIntRect newRect(screenPoint.x, screenPoint.y, mRect.width, mRect.height);
if (mPopupState == ePopupPositioning ||
- (mPopupState == ePopupShown && !newRect.IsEqualEdges(mUsedScreenRect))) {
+ (mPopupState == ePopupShown && !newRect.IsEqualEdges(mUsedScreenRect)) ||
+ (mPopupState == ePopupShown && oldAlignmentOffset != mAlignmentOffset)) {
mUsedScreenRect = newRect;
if (aNotify) {
nsXULPopupPositionedEvent::DispatchIfNeeded(mContent, false, false);
}
}
return NS_OK;
}