Bug 627974 - panels that aren't toplevel shouldn't overlap the taskbar, r=Enn
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Fri, 07 Feb 2014 17:35:09 +0000
changeset 167570 95fc024ee46d9aa52072df720fd8c08223a11984
parent 167569 59230a163ec0852cb6c594fa4ca52d52387b9a44
child 167571 1bf0b04301caa1142c06f9b31629594c6ac01dfb
push id26174
push userkwierso@gmail.com
push dateSat, 08 Feb 2014 00:55:48 +0000
treeherdermozilla-central@2c873eff7dc2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEnn
bugs627974
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 627974 - panels that aren't toplevel shouldn't overlap the taskbar, r=Enn
layout/xul/nsMenuPopupFrame.cpp
layout/xul/nsMenuPopupFrame.h
layout/xul/nsResizerFrame.cpp
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -1193,16 +1193,19 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
   StyleMargin()->GetMargin(margin);
 
   // the screen rectangle of the root frame, in dev pixels.
   nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits();
 
   nsDeviceContext* devContext = presContext->DeviceContext();
   nscoord offsetForContextMenu = 0;
 
+  bool isNoAutoHide = IsNoAutoHide();
+  nsPopupLevel popupLevel = PopupLevel(isNoAutoHide);
+
   if (IsAnchored()) {
     // if we are anchored, there are certain things we don't want to do when
     // repositioning the popup to fit on the screen, such as end up positioned
     // over the anchor, for instance a popup appearing over the menu label.
     // When doing this reposition, we want to move the popup to the side with
     // the most room. The combination of anchor and alignment dictate if we 
     // readjust above/below or to the left/right.
     if (mAnchorContent) {
@@ -1233,17 +1236,17 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
     screenPoint.y += anchorYOffset;
     anchorRect.y += anchorYOffset;
 
     // If this is a noautohide popup, set the screen coordinates of the popup.
     // This way, the popup stays at the location where it was opened even when
     // the window is moved. Popups at the parent level follow the parent
     // window as it is moved and remained anchored, so we want to maintain the
     // anchoring instead.
-    if (IsNoAutoHide() && PopupLevel(true) != ePopupLevelParent) {
+    if (isNoAutoHide && popupLevel != ePopupLevelParent) {
       // Account for the margin that will end up being added to the screen coordinate
       // the next time SetPopupPosition is called.
       mScreenXPos = presContext->AppUnitsToIntCSSPixels(screenPoint.x - margin.left);
       mScreenYPos = presContext->AppUnitsToIntCSSPixels(screenPoint.y - margin.top);
     }
   }
   else {
     // the popup is positioned at a screen coordinate.
@@ -1274,17 +1277,17 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
 
     // screen positioned popups can be flipped vertically but never horizontally
     vFlip = FlipStyle_Outside;
   }
 
   // If a panel is being moved or has flip="none", don't constrain or flip it. But 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))) {
-    nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect);
+    nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect, popupLevel);
 
     // Ensure that anchorRect is on screen.
     anchorRect = anchorRect.Intersect(screenRect);
 
     // shrink the the popup down if it is larger than the screen size
     if (mRect.width > screenRect.width)
       mRect.width = screenRect.width;
     if (mRect.height > screenRect.height)
@@ -1373,17 +1376,18 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
 /* virtual */ nsMenuFrame*
 nsMenuPopupFrame::GetCurrentMenuItem()
 {
   return mCurrentMenu;
 }
 
 nsRect
 nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
-                                    const nsRect& aRootScreenRect)
+                                    const nsRect& aRootScreenRect,
+                                    nsPopupLevel aPopupLevel)
 {
   nsIntRect screenRectPixels;
   nsPresContext* presContext = PresContext();
 
   // determine the available screen space. It will be reduced by the OS chrome
   // such as menubars. It addition, for content shells, it will be the area of
   // the content rather than the screen.
   nsCOMPtr<nsIScreen> screen;
@@ -1396,18 +1400,21 @@ nsMenuPopupFrame::GetConstraintRect(cons
     nsRect rect = mInContentShell ? aRootScreenRect : aAnchorRect;
     // nsIScreenManager::ScreenForRect wants the coordinates in CSS pixels
     int32_t width = std::max(1, nsPresContext::AppUnitsToIntCSSPixels(rect.width));
     int32_t height = std::max(1, nsPresContext::AppUnitsToIntCSSPixels(rect.height));
     sm->ScreenForRect(nsPresContext::AppUnitsToIntCSSPixels(rect.x),
                       nsPresContext::AppUnitsToIntCSSPixels(rect.y),
                       width, height, getter_AddRefs(screen));
     if (screen) {
+      // Non-top-level popups (which will always be panels)
+      // should never overlap the OS bar:
+      bool dontOverlapOSBar = aPopupLevel != ePopupLevelTop;
       // get the total screen area if the popup is allowed to overlap it.
-      if (mMenuCanOverlapOSBar && !mInContentShell)
+      if (!dontOverlapOSBar && mMenuCanOverlapOSBar && !mInContentShell)
         screen->GetRect(&screenRectPixels.x, &screenRectPixels.y,
                         &screenRectPixels.width, &screenRectPixels.height);
       else
         screen->GetAvailRect(&screenRectPixels.x, &screenRectPixels.y,
                              &screenRectPixels.width, &screenRectPixels.height);
     }
   }
 
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -305,17 +305,21 @@ public:
 
   nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart);
 
   // For a popup that should appear anchored at the given rect, determine
   // the screen area that it is constrained by. This will be the available
   // area of the screen the popup should be displayed on. Content popups,
   // however, will also be constrained by the content area, given by
   // aRootScreenRect. All coordinates are in app units.
-  nsRect GetConstraintRect(const nsRect& aAnchorRect, const nsRect& aRootScreenRect);
+  // For non-toplevel popups (which will always be panels), we will also
+  // constrain them to the available screen rect, ie they will not fall
+  // underneath the taskbar, dock or other fixed OS elements.
+  nsRect GetConstraintRect(const nsRect& aAnchorRect, const nsRect& aRootScreenRect,
+                           nsPopupLevel aPopupLevel);
 
   // Determines whether the given edges of the popup may be moved, where
   // aHorizontalSide and aVerticalSide are one of the NS_SIDE_* constants, or
   // 0 for no movement in that direction. aChange is the distance to move on
   // those sides. If will be reset to 0 if the side cannot be adjusted at all
   // in that direction. For example, a popup cannot be moved if it is anchored
   // on a particular side.
   //
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -219,17 +219,18 @@ nsResizerFrame::HandleEvent(nsPresContex
           }
         }
       }
       else if (menuPopupFrame) {
         nsRect frameRect = menuPopupFrame->GetScreenRectInAppUnits();
         nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame();
         nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits();
 
-        nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect);
+        nsPopupLevel popupLevel = menuPopupFrame->PopupLevel();
+        nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect, popupLevel);
         // round using ToInsidePixels as it's better to be a pixel too small
         // than be too large. If the popup is too large it could get flipped
         // to the opposite side of the anchor point while resizing.
         nsIntRect screenRectPixels = screenRect.ToInsidePixels(aPresContext->AppUnitsPerDevPixel());
         rect.IntersectRect(rect, screenRectPixels);
       }
 
       if (contentToResize) {