зеркало из https://github.com/mozilla/gecko-dev.git
Bug 552982, Part 3: support panel levels, r=mats
This commit is contained in:
Родитель
f46c03d388
Коммит
4a99c182d8
|
@ -377,6 +377,7 @@ GK_ATOM(fixedList, "Fixed-list")
|
|||
GK_ATOM(flags, "flags")
|
||||
GK_ATOM(flex, "flex")
|
||||
GK_ATOM(flexgroup, "flexgroup")
|
||||
GK_ATOM(floating, "floating")
|
||||
GK_ATOM(floatList, "Float-list")
|
||||
GK_ATOM(floor, "floor")
|
||||
GK_ATOM(focus, "focus")
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
#include "nsIServiceManager.h"
|
||||
#include "nsThemeConstants.h"
|
||||
|
||||
PRInt8 nsMenuPopupFrame::sDefaultLevelParent = -1;
|
||||
PRInt8 nsMenuPopupFrame::sDefaultLevelIsTop = -1;
|
||||
|
||||
// NS_NewMenuPopupFrame
|
||||
//
|
||||
|
@ -125,9 +125,11 @@ nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContex
|
|||
mHFlip(PR_FALSE),
|
||||
mVFlip(PR_FALSE)
|
||||
{
|
||||
if (sDefaultLevelParent >= 0)
|
||||
// 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;
|
||||
sDefaultLevelParent =
|
||||
sDefaultLevelIsTop =
|
||||
nsContentUtils::GetBoolPref("ui.panel.default_level_parent", PR_FALSE);
|
||||
} // ctor
|
||||
|
||||
|
@ -200,7 +202,7 @@ nsMenuPopupFrame::Init(nsIContent* aContent,
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsMenuPopupFrame::IsNoAutoHide()
|
||||
nsMenuPopupFrame::IsNoAutoHide() const
|
||||
{
|
||||
// Panels with noautohide="true" don't hide when the mouse is clicked
|
||||
// outside of them, or when another application is made active. Non-autohide
|
||||
|
@ -210,29 +212,38 @@ nsMenuPopupFrame::IsNoAutoHide()
|
|||
nsGkAtoms::_true, eIgnoreCase));
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsMenuPopupFrame::IsTopMost()
|
||||
nsPopupLevel
|
||||
nsMenuPopupFrame::PopupLevel(PRBool aIsNoAutoHide) const
|
||||
{
|
||||
// If this panel is not a panel, this is always a top-most popup
|
||||
// The popup level is determined as follows, in this order:
|
||||
// 1. non-panels (menus and tooltips) are always topmost
|
||||
// 2. any specified level attribute
|
||||
// 3. if this is a noautohide panel, use the 'parent' level
|
||||
// 4. use the platform-specific default level
|
||||
|
||||
// If this is not a panel, this is always a top-most popup.
|
||||
if (mPopupType != ePopupTypePanel)
|
||||
return PR_TRUE;
|
||||
return ePopupLevelTop;
|
||||
|
||||
// If this panel is a noautohide panel, it should appear just above the parent
|
||||
// window.
|
||||
if (IsNoAutoHide())
|
||||
return PR_FALSE;
|
||||
// If the level attribute has been set, use that.
|
||||
static nsIContent::AttrValuesArray strings[] =
|
||||
{&nsGkAtoms::top, &nsGkAtoms::parent, &nsGkAtoms::floating, nsnull};
|
||||
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::level,
|
||||
strings, eCaseMatters)) {
|
||||
case 0:
|
||||
return ePopupLevelTop;
|
||||
case 1:
|
||||
return ePopupLevelParent;
|
||||
case 2:
|
||||
return ePopupLevelFloating;
|
||||
}
|
||||
|
||||
// Otherwise, check the topmost attribute.
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::level,
|
||||
nsGkAtoms::top, eIgnoreCase))
|
||||
return PR_TRUE;
|
||||
|
||||
if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::level,
|
||||
nsGkAtoms::parent, eIgnoreCase))
|
||||
return PR_FALSE;
|
||||
// If this panel is a noautohide panel, the default is the parent level.
|
||||
if (aIsNoAutoHide)
|
||||
return ePopupLevelParent;
|
||||
|
||||
// Otherwise, the result depends on the platform.
|
||||
return sDefaultLevelParent ? PR_TRUE : PR_FALSE;
|
||||
return sDefaultLevelIsTop ? ePopupLevelTop : ePopupLevelParent;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -255,6 +266,7 @@ nsMenuPopupFrame::CreateWidgetForView(nsIView* aView)
|
|||
widgetData.mBorderStyle = eBorderStyle_default;
|
||||
widgetData.clipSiblings = PR_TRUE;
|
||||
widgetData.mPopupHint = mPopupType;
|
||||
widgetData.mNoAutoHide = IsNoAutoHide();
|
||||
|
||||
nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(this, this);
|
||||
PRBool viewHasTransparentContent = !mInContentShell &&
|
||||
|
@ -265,12 +277,13 @@ nsMenuPopupFrame::CreateWidgetForView(nsIView* aView)
|
|||
if (parentContent)
|
||||
tag = parentContent->Tag();
|
||||
widgetData.mDropShadow = !(viewHasTransparentContent || tag == nsGkAtoms::menulist);
|
||||
widgetData.mPopupLevel = PopupLevel(widgetData.mNoAutoHide);
|
||||
|
||||
// panels which are not topmost need a parent widget. This allows them to
|
||||
// panels which have a parent level need a parent widget. This allows them to
|
||||
// always appear in front of the parent window but behind other windows that
|
||||
// should be in front of it.
|
||||
nsCOMPtr<nsIWidget> parentWidget;
|
||||
if (!IsTopMost()) {
|
||||
if (widgetData.mPopupLevel != ePopupLevelTop) {
|
||||
nsCOMPtr<nsISupports> cont = PresContext()->GetContainer();
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont);
|
||||
if (!dsti)
|
||||
|
@ -1051,6 +1064,18 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, PRBool aIsMove)
|
|||
else
|
||||
screenPoint.x += presContext->CSSPixelsToAppUnits(mXPos);
|
||||
screenPoint.y += presContext->CSSPixelsToAppUnits(mYPos);
|
||||
|
||||
// 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(PR_TRUE) != 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.
|
||||
|
@ -1649,9 +1674,13 @@ nsMenuPopupFrame::MoveTo(PRInt32 aLeft, PRInt32 aTop, PRBool aUpdateAttrs)
|
|||
|
||||
// reposition the popup at the specified coordinates. Don't clear the anchor
|
||||
// and position, because the popup can be reset to its anchor position by
|
||||
// using (-1, -1) as coordinates.
|
||||
mScreenXPos = aLeft;
|
||||
mScreenYPos = aTop;
|
||||
// using (-1, -1) as coordinates. Subtract off the margin as it will be
|
||||
// added to the position when SetPopupPosition is called.
|
||||
nsMargin margin(0, 0, 0, 0);
|
||||
GetStyleMargin()->GetMargin(margin);
|
||||
nsPresContext* presContext = PresContext();
|
||||
mScreenXPos = aLeft - presContext->AppUnitsToIntCSSPixels(margin.left);
|
||||
mScreenYPos = aTop - presContext->AppUnitsToIntCSSPixels(margin.top);
|
||||
|
||||
SetPopupPosition(nsnull, PR_TRUE);
|
||||
|
||||
|
|
|
@ -183,11 +183,12 @@ public:
|
|||
|
||||
// returns true if the popup is a panel with the noautohide attribute set to
|
||||
// true. These panels do not roll up automatically.
|
||||
PRBool IsNoAutoHide();
|
||||
PRBool IsNoAutoHide() const;
|
||||
|
||||
// returns true if the popup is a top-most window. Otherwise, the
|
||||
// panel appears in front of the parent window.
|
||||
PRBool IsTopMost();
|
||||
nsPopupLevel PopupLevel() const
|
||||
{
|
||||
return PopupLevel(IsNoAutoHide());
|
||||
}
|
||||
|
||||
void EnsureWidget();
|
||||
|
||||
|
@ -319,6 +320,9 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
// returns the popup's level.
|
||||
nsPopupLevel PopupLevel(PRBool aIsNoAutoHide) const;
|
||||
|
||||
// redefine to tell the box system not to move the views.
|
||||
virtual void GetLayoutFlags(PRUint32& aFlags);
|
||||
|
||||
|
@ -400,7 +404,7 @@ protected:
|
|||
PRPackedBool mHFlip;
|
||||
PRPackedBool mVFlip;
|
||||
|
||||
static PRInt8 sDefaultLevelParent;
|
||||
static PRInt8 sDefaultLevelIsTop;
|
||||
}; // class nsMenuPopupFrame
|
||||
|
||||
#endif
|
||||
|
|
|
@ -320,7 +320,8 @@ nsXULPopupManager::PopupMoved(nsIView* aView, nsIntPoint aPnt)
|
|||
// anchored and at the parent level as these maintain their position
|
||||
// relative to the parent window. Otherwise, just update the popup to
|
||||
// the specified screen coordinates.
|
||||
if (menuPopupFrame->IsAnchored()) {
|
||||
if (menuPopupFrame->IsAnchored() &&
|
||||
menuPopupFrame->PopupLevel() == ePopupLevelParent) {
|
||||
menuPopupFrame->SetPopupPosition(nsnull, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -71,6 +71,22 @@ enum nsPopupType {
|
|||
// nsXULPopupManager::GetTopPopup
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup levels specify the window ordering behaviour.
|
||||
*/
|
||||
enum nsPopupLevel {
|
||||
// the popup appears just above its parent and maintains its position
|
||||
// relative to the parent
|
||||
ePopupLevelParent,
|
||||
// the popup is a floating popup used for tool palettes. A parent window
|
||||
// must be specified, but a platform implementation need not use this.
|
||||
// On Windows, floating is generally equivalent to parent. On Mac, floating
|
||||
// puts the popup at toplevel, but it will hide when the application is deactivated
|
||||
ePopupLevelFloating,
|
||||
// the popup appears on top of other windows, including those of other applications
|
||||
ePopupLevelTop
|
||||
};
|
||||
|
||||
/**
|
||||
* Border styles
|
||||
*/
|
||||
|
@ -122,12 +138,14 @@ struct nsWidgetInitData {
|
|||
mBorderStyle(eBorderStyle_default),
|
||||
mContentType(eContentTypeInherit),
|
||||
mPopupHint(ePopupTypePanel),
|
||||
mPopupLevel(ePopupLevelTop),
|
||||
clipChildren(PR_FALSE),
|
||||
clipSiblings(PR_FALSE),
|
||||
mDropShadow(PR_FALSE),
|
||||
mListenForResizes(PR_FALSE),
|
||||
mUnicode(PR_TRUE),
|
||||
mRTL(PR_FALSE)
|
||||
mRTL(PR_FALSE),
|
||||
mNoAutoHide(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -135,11 +153,13 @@ struct nsWidgetInitData {
|
|||
nsBorderStyle mBorderStyle;
|
||||
nsContentType mContentType; // Exposed so screen readers know what's UI
|
||||
nsPopupType mPopupHint;
|
||||
nsPopupLevel mPopupLevel;
|
||||
// when painting exclude area occupied by child windows and sibling windows
|
||||
PRPackedBool clipChildren, clipSiblings, mDropShadow;
|
||||
PRPackedBool mListenForResizes;
|
||||
PRPackedBool mUnicode;
|
||||
PRPackedBool mRTL;
|
||||
PRPackedBool mNoAutoHide; // true for noautohide panels
|
||||
};
|
||||
|
||||
#endif // nsWidgetInitData_h__
|
||||
|
|
|
@ -289,6 +289,8 @@ public:
|
|||
|
||||
static void UnifiedShading(void* aInfo, const CGFloat* aIn, CGFloat* aOut);
|
||||
|
||||
void SetPopupWindowLevel();
|
||||
|
||||
protected:
|
||||
|
||||
nsresult CreateNativeWindow(const NSRect &aRect,
|
||||
|
|
|
@ -416,7 +416,7 @@ nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect,
|
|||
if (mWindowType == eWindowType_invisible) {
|
||||
[mWindow setLevel:kCGDesktopWindowLevelKey];
|
||||
} else if (mWindowType == eWindowType_popup) {
|
||||
[mWindow setLevel:NSPopUpMenuWindowLevel];
|
||||
SetPopupWindowLevel();
|
||||
[mWindow setHasShadow:YES];
|
||||
}
|
||||
|
||||
|
@ -591,7 +591,7 @@ NS_IMETHODIMP nsCocoaWindow::SetModal(PRBool aState)
|
|||
delete saved; // "window" not ADDREFed
|
||||
}
|
||||
if (mWindowType == eWindowType_popup)
|
||||
[mWindow setLevel:NSPopUpMenuWindowLevel];
|
||||
SetPopupWindowLevel();
|
||||
else
|
||||
[mWindow setLevel:NSNormalWindowLevel];
|
||||
}
|
||||
|
@ -695,11 +695,12 @@ NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
|
|||
object:@"org.mozilla.gecko.PopupWindow"];
|
||||
}
|
||||
|
||||
// if a parent was supplied, set its child window. This will cause the
|
||||
// child window to appear above the parent and move when the parent
|
||||
// does. Setting this needs to happen after the _setWindowNumber calls
|
||||
// above, otherwise the window doesn't focus properly.
|
||||
if (nativeParentWindow)
|
||||
// If a parent window was supplied and this is a popup at the parent
|
||||
// level, set its child window. This will cause the child window to
|
||||
// appear above the parent and move when the parent does. Setting this
|
||||
// needs to happen after the _setWindowNumber calls above, otherwise the
|
||||
// window doesn't focus properly.
|
||||
if (nativeParentWindow && mPopupLevel == ePopupLevelParent)
|
||||
[nativeParentWindow addChildWindow:mWindow
|
||||
ordered:NSWindowAbove];
|
||||
}
|
||||
|
@ -1460,8 +1461,10 @@ NS_IMETHODIMP nsCocoaWindow::CaptureRollupEvents(nsIRollupListener * aListener,
|
|||
// "active" one is always above any other non-native popup windows that
|
||||
// may be visible.
|
||||
if (mWindow && (mWindowType == eWindowType_popup))
|
||||
[mWindow setLevel:NSPopUpMenuWindowLevel];
|
||||
SetPopupWindowLevel();
|
||||
} else {
|
||||
// XXXndeakin this doesn't make sense.
|
||||
// Why is the new window assumed to be a modal panel?
|
||||
if (mWindow && (mWindowType == eWindowType_popup))
|
||||
[mWindow setLevel:NSModalPanelWindowLevel];
|
||||
}
|
||||
|
@ -1620,6 +1623,22 @@ nsCocoaWindow::UnifiedShading(void* aInfo, const CGFloat* aIn, CGFloat* aOut)
|
|||
aOut[3] = 1.0f;
|
||||
}
|
||||
|
||||
void nsCocoaWindow::SetPopupWindowLevel()
|
||||
{
|
||||
// Floating popups are at the floating level and hide when the window is
|
||||
// deactivated.
|
||||
if (mPopupLevel == ePopupLevelFloating) {
|
||||
[mWindow setLevel:NSFloatingWindowLevel];
|
||||
[mWindow setHidesOnDeactivate:YES];
|
||||
}
|
||||
else {
|
||||
// Otherwise, this is a top-level or parent popup. Parent popups always
|
||||
// appear just above their parent and essentially ignore the level.
|
||||
[mWindow setLevel:NSPopUpMenuWindowLevel];
|
||||
[mWindow setHidesOnDeactivate:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@implementation WindowDelegate
|
||||
|
||||
// We try to find a gecko menu bar to paint. If one does not exist, just paint
|
||||
|
@ -2474,6 +2493,12 @@ ContentPatternDrawCallback(void* aInfo, CGContextRef aContext)
|
|||
mIsContextMenu = flag;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeMainWindow
|
||||
{
|
||||
// This is overriden because the default is 'yes' when a titlebar is present.
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// According to Apple's docs on [NSWindow canBecomeKeyWindow] and [NSWindow
|
||||
|
|
|
@ -4037,10 +4037,9 @@ nsWindow::Create(nsIWidget *aParent,
|
|||
}
|
||||
}
|
||||
else if (mWindowType == eWindowType_popup) {
|
||||
// The value of aParent contains a code: If a popup window has a
|
||||
// non-NULL nsIWidget* aParent, it indicates that it should not be
|
||||
// above all other windows (e.g a noautohide panel).
|
||||
if (!aParent) {
|
||||
// Popups that are not noautohide are only temporary. The are used
|
||||
// for menus and the like and disappear when another window is used.
|
||||
if (!aInitData->mNoAutoHide) {
|
||||
// For most popups, use the standard GtkWindowType
|
||||
// GTK_WINDOW_POPUP, which will use a Window with the
|
||||
// override-redirect attribute (for temporary windows).
|
||||
|
|
|
@ -556,11 +556,7 @@ nsWindow::Create(nsIWidget *aParent,
|
|||
}
|
||||
|
||||
if (mWindowType == eWindowType_popup) {
|
||||
// if a parent was specified, don't use WS_EX_TOPMOST so that the popup
|
||||
// only appears above the parent, instead of all windows
|
||||
if (aParent)
|
||||
extendedStyle = WS_EX_TOOLWINDOW;
|
||||
else
|
||||
if (!aParent)
|
||||
parent = NULL;
|
||||
} else if (mWindowType == eWindowType_invisible) {
|
||||
// Make sure CreateWindowEx succeeds at creating a toplevel window
|
||||
|
@ -896,12 +892,16 @@ DWORD nsWindow::WindowExStyle()
|
|||
return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME;
|
||||
|
||||
case eWindowType_popup:
|
||||
return
|
||||
{
|
||||
DWORD extendedStyle =
|
||||
#if defined(WINCE) && !defined(WINCE_WINDOWS_MOBILE)
|
||||
WS_EX_NOACTIVATE |
|
||||
#endif
|
||||
WS_EX_TOPMOST | WS_EX_TOOLWINDOW;
|
||||
|
||||
WS_EX_TOOLWINDOW;
|
||||
if (mPopupLevel == ePopupLevelTop)
|
||||
extendedStyle |= WS_EX_TOPMOST;
|
||||
return extendedStyle;
|
||||
}
|
||||
default:
|
||||
NS_ERROR("unknown border style");
|
||||
// fall through
|
||||
|
|
|
@ -110,6 +110,7 @@ nsBaseWidget::nsBaseWidget()
|
|||
, mClipRectCount(0)
|
||||
, mZIndex(0)
|
||||
, mSizeMode(nsSizeMode_Normal)
|
||||
, mPopupLevel(ePopupLevelTop)
|
||||
{
|
||||
#ifdef NOISY_WIDGET_LEAKS
|
||||
gNumWidgets++;
|
||||
|
@ -214,6 +215,7 @@ void nsBaseWidget::BaseCreate(nsIWidget *aParent,
|
|||
if (nsnull != aInitData) {
|
||||
mWindowType = aInitData->mWindowType;
|
||||
mBorderStyle = aInitData->mBorderStyle;
|
||||
mPopupLevel = aInitData->mPopupLevel;
|
||||
}
|
||||
|
||||
if (aParent) {
|
||||
|
|
|
@ -156,6 +156,8 @@ public:
|
|||
NS_IMETHOD GetNonClientMargins(nsIntMargin &margins);
|
||||
NS_IMETHOD SetNonClientMargins(nsIntMargin &margins);
|
||||
|
||||
nsPopupLevel PopupLevel() { return mPopupLevel; }
|
||||
|
||||
/**
|
||||
* Use this when GetLayerManager() returns a BasicLayerManager
|
||||
* (nsBaseWidget::GetLayerManager() does). This sets up the widget's
|
||||
|
@ -228,6 +230,7 @@ protected:
|
|||
PRUint32 mClipRectCount;
|
||||
PRInt32 mZIndex;
|
||||
nsSizeMode mSizeMode;
|
||||
nsPopupLevel mPopupLevel;
|
||||
|
||||
// the last rolled up popup. Only set this when an nsAutoRollup is in scope,
|
||||
// so it can be cleared automatically.
|
||||
|
|
Загрузка…
Ссылка в новой задаче