mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 1368094 - Correct panel sliding on window resize r=bytesized
This is in response to an issue that's affecting the new app update doorhangers on OSX, where the problem is more obvious. On OSX, the panel styling makes it so that the doorhanger overflows the window a little bit. This is fine until you enter fullscreen with ctrl+command+F. At this point, the doorhanger should come back onto the screen and the arrow should be rooted to its anchor element (in our case the hamburger menu icon), but instead it lags and the panel is not adjusted right away. This is because right after the window is resized, which ends up calling SetPopupPosition with aIsMove == false, SetPopupPosition is called again from CheckForAnchorChange with aIsMove set to true. There could be other solutions to this particular problem, but since the aIsMove boolean is intended to limit the visual noise when moving a window between screens, it seemed appropriate for it to only prevent sliding or flipping if the panel isn't already slid or flipped. There was another issue affecting specifically the arrow, where the logic for notifying observers of a positioning change in the panel doesn't account for changes only to the position of the anchor rect. This change adds tracking of that and sets aNotify to true when called from ReflowFinished, since this is where the position of the anchor element relative to the window can need to change, even when the screen position of the panel rect doesn't change. MozReview-Commit-ID: Lpfokwkgl33 --HG-- extra : rebase_source : b05adc0b3f876196ff45499f0d70533f78cafb0e
This commit is contained in:
parent
0fbeea4132
commit
bf49dba88f
@ -118,6 +118,7 @@ nsMenuPopupFrame::nsMenuPopupFrame(nsStyleContext* aContext)
|
||||
, mInContentShell(true)
|
||||
, mIsMenuLocked(false)
|
||||
, mMouseTransparent(false)
|
||||
, mIsOffset(false)
|
||||
, mHFlip(false)
|
||||
, mVFlip(false)
|
||||
, mAnchorType(MenuPopupAnchorType_Node)
|
||||
@ -601,7 +602,7 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu,
|
||||
bool
|
||||
nsMenuPopupFrame::ReflowFinished()
|
||||
{
|
||||
SetPopupPosition(mReflowCallbackData.mAnchor, false, mReflowCallbackData.mSizedToPopup, false);
|
||||
SetPopupPosition(mReflowCallbackData.mAnchor, false, mReflowCallbackData.mSizedToPopup, true);
|
||||
|
||||
mReflowCallbackData.Clear();
|
||||
|
||||
@ -1558,10 +1559,14 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
||||
#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);
|
||||
@ -1602,6 +1607,7 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
||||
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);
|
||||
@ -1611,9 +1617,11 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
||||
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);
|
||||
@ -1623,6 +1631,7 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
||||
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() &&
|
||||
@ -1669,7 +1678,8 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
||||
// 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);
|
||||
|
@ -636,6 +636,11 @@ protected:
|
||||
bool mIsMenuLocked; // Should events inside this menu be ignored?
|
||||
bool mMouseTransparent; // True if this is a popup is transparent to mouse events
|
||||
|
||||
// True if this popup has been offset due to moving off / near the edge of the screen.
|
||||
// (This is useful for ensuring that a move, which can't offset the popup, doesn't undo
|
||||
// a previously set offset.)
|
||||
bool mIsOffset;
|
||||
|
||||
// the flip modes that were used when the popup was opened
|
||||
bool mHFlip;
|
||||
bool mVFlip;
|
||||
|
Loading…
Reference in New Issue
Block a user