Bug 357725, support minimum and maximum size constraints on windows and popups, r=mats,jmathies,karlt,smichaud,sr=neil

This commit is contained in:
Neil Deakin 2012-07-30 20:43:29 -04:00
parent 8ba0d842dd
commit 28413e223c
15 changed files with 274 additions and 30 deletions

View File

@ -7488,7 +7488,7 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
target->GetView(), target->GetView(),
boundsRelativeToTarget); boundsRelativeToTarget);
nsContainerFrame::SyncWindowProperties(mPresContext, target, nsContainerFrame::SyncWindowProperties(mPresContext, target,
target->GetView()); target->GetView(), rcx);
target->DidReflow(mPresContext, nullptr, NS_FRAME_REFLOW_FINISHED); target->DidReflow(mPresContext, nullptr, NS_FRAME_REFLOW_FINISHED);
if (target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) { if (target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) {

View File

@ -34,6 +34,8 @@
#include "nsListControlFrame.h" #include "nsListControlFrame.h"
#include "nsIBaseWindow.h" #include "nsIBaseWindow.h"
#include "nsThemeConstants.h" #include "nsThemeConstants.h"
#include "nsBoxLayoutState.h"
#include "nsRenderingContext.h"
#include "nsCSSFrameConstructor.h" #include "nsCSSFrameConstructor.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
@ -632,7 +634,8 @@ IsTopLevelWidget(nsIWidget* aWidget)
void void
nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext, nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
nsIFrame* aFrame, nsIFrame* aFrame,
nsIView* aView) nsIView* aView,
nsRenderingContext* aRC)
{ {
#ifdef MOZ_XUL #ifdef MOZ_XUL
if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget()) if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
@ -676,9 +679,47 @@ nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
nsIWidget* viewWidget = aView->GetWidget(); nsIWidget* viewWidget = aView->GetWidget();
viewWidget->SetTransparencyMode(mode); viewWidget->SetTransparencyMode(mode);
windowWidget->SetWindowShadowStyle(rootFrame->GetStyleUIReset()->mWindowShadow); windowWidget->SetWindowShadowStyle(rootFrame->GetStyleUIReset()->mWindowShadow);
if (!aRC)
return;
nsBoxLayoutState aState(aPresContext, aRC);
nsSize minSize = rootFrame->GetMinSize(aState);
nsSize maxSize = rootFrame->GetMaxSize(aState);
SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
#endif #endif
} }
void nsContainerFrame::SetSizeConstraints(nsPresContext* aPresContext,
nsIWidget* aWidget,
const nsSize& aMinSize,
const nsSize& aMaxSize)
{
nsIntSize devMinSize(aPresContext->AppUnitsToDevPixels(aMinSize.width),
aPresContext->AppUnitsToDevPixels(aMinSize.height));
nsIntSize devMaxSize(aMaxSize.width == NS_INTRINSICSIZE ? NS_MAXSIZE :
aPresContext->AppUnitsToDevPixels(aMaxSize.width),
aMaxSize.height == NS_INTRINSICSIZE ? NS_MAXSIZE :
aPresContext->AppUnitsToDevPixels(aMaxSize.height));
widget::SizeConstraints constraints(devMinSize, devMaxSize);
// The sizes are in inner window sizes, so convert them into outer window sizes.
// Use a size of (200, 200) as only the difference between the inner and outer
// size is needed.
nsIntSize windowSize = aWidget->ClientToWindowSize(nsIntSize(200, 200));
if (constraints.mMinSize.width)
constraints.mMinSize.width += windowSize.width - 200;
if (constraints.mMinSize.height)
constraints.mMinSize.height += windowSize.height - 200;
if (constraints.mMaxSize.width != NS_MAXSIZE)
constraints.mMaxSize.width += windowSize.width - 200;
if (constraints.mMaxSize.height != NS_MAXSIZE)
constraints.mMaxSize.height += windowSize.height - 200;
aWidget->SetSizeConstraints(constraints);
}
void void
nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext, nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
nsIFrame* aFrame, nsIFrame* aFrame,

View File

@ -141,7 +141,8 @@ public:
// shadow. // shadow.
static void SyncWindowProperties(nsPresContext* aPresContext, static void SyncWindowProperties(nsPresContext* aPresContext,
nsIFrame* aFrame, nsIFrame* aFrame,
nsIView* aView); nsIView* aView,
nsRenderingContext* aRC = nullptr);
// Sets the view's attributes from the frame style. // Sets the view's attributes from the frame style.
// - visibility // - visibility
@ -155,6 +156,20 @@ public:
nsIView* aView, nsIView* aView,
PRUint32 aFlags = 0); PRUint32 aFlags = 0);
/**
* Converts the minimum and maximum sizes given in inner window app units to
* outer window device pixel sizes and assigns these constraints to the widget.
*
* @param aPresContext pres context
* @param aWidget widget for this frame
* @param minimum size of the window in app units
* @param maxmimum size of the window in app units
*/
static void SetSizeConstraints(nsPresContext* aPresContext,
nsIWidget* aWidget,
const nsSize& aMinSize,
const nsSize& aMaxSize);
// Used by both nsInlineFrame and nsFirstLetterFrame. // Used by both nsInlineFrame and nsFirstLetterFrame.
void DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext, void DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
InlineIntrinsicWidthData *aData, InlineIntrinsicWidthData *aData,

View File

@ -450,6 +450,14 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu, b
nsRect rect = GetRect(); nsRect rect = GetRect();
rect.x = rect.y = 0; rect.x = rect.y = 0;
if (sizeChanged) {
// If the size of the popup changed, apply any size constraints.
nsIWidget* widget = view->GetWidget();
if (widget) {
SetSizeConstraints(pc, widget, minSize, maxSize);
}
}
viewManager->ResizeView(view, rect); viewManager->ResizeView(view, rect);
viewManager->SetViewVisibility(view, nsViewVisibility_kShow); viewManager->SetViewVisibility(view, nsViewVisibility_kShow);

View File

@ -29,6 +29,7 @@
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "nsContentErrors.h" #include "nsContentErrors.h"
using namespace mozilla;
// //
// NS_NewResizerFrame // NS_NewResizerFrame
@ -186,8 +187,19 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
} }
nsIntRect rect = mMouseDownRect; nsIntRect rect = mMouseDownRect;
AdjustDimensions(&rect.x, &rect.width, mouseMove.x, direction.mHorizontal);
AdjustDimensions(&rect.y, &rect.height, mouseMove.y, direction.mVertical); // Check if there are any size constraints on this window.
widget::SizeConstraints sizeConstraints;
if (window) {
nsCOMPtr<nsIWidget> widget;
window->GetMainWidget(getter_AddRefs(widget));
sizeConstraints = widget->GetSizeConstraints();
}
AdjustDimensions(&rect.x, &rect.width, sizeConstraints.mMinSize.width,
sizeConstraints.mMaxSize.width, mouseMove.x, direction.mHorizontal);
AdjustDimensions(&rect.y, &rect.height, sizeConstraints.mMinSize.height,
sizeConstraints.mMaxSize.height, mouseMove.y, direction.mVertical);
// Don't allow resizing a window or a popup past the edge of the screen, // Don't allow resizing a window or a popup past the edge of the screen,
// so adjust the rectangle to fit within the available screen area. // so adjust the rectangle to fit within the available screen area.
@ -249,6 +261,10 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo); ResizeContent(contentToResize, direction, sizeInfo, &originalSizeInfo);
MaybePersistOriginalSize(contentToResize, originalSizeInfo); MaybePersistOriginalSize(contentToResize, originalSizeInfo);
// Move the popup to the new location unless it is anchored, since
// the position shouldn't change. nsMenuPopupFrame::SetPopupPosition
// will instead ensure that the popup's position is anchored at the
// right place.
if (weakFrame.IsAlive() && if (weakFrame.IsAlive() &&
(oldRect.x != rect.x || oldRect.y != rect.y) && (oldRect.x != rect.x || oldRect.y != rect.y) &&
(!menuPopupFrame->IsAnchored() || (!menuPopupFrame->IsAnchored() ||
@ -365,25 +381,25 @@ nsResizerFrame::GetContentToResize(nsIPresShell* aPresShell, nsIBaseWindow** aWi
return aPresShell->GetDocument()->GetElementById(elementid); return aPresShell->GetDocument()->GetElementById(elementid);
} }
/* adjust the window position and size according to the mouse movement and
* the resizer direction
*/
void void
nsResizerFrame::AdjustDimensions(PRInt32* aPos, PRInt32* aSize, nsResizerFrame::AdjustDimensions(PRInt32* aPos, PRInt32* aSize,
PRInt32 aMinSize, PRInt32 aMaxSize,
PRInt32 aMovement, PRInt8 aResizerDirection) PRInt32 aMovement, PRInt8 aResizerDirection)
{ {
switch(aResizerDirection) PRInt32 oldSize = *aSize;
{
case -1: *aSize += aResizerDirection * aMovement;
// only move the window when the direction is top and/or left // use one as a minimum size or the element could disappear
*aPos+= aMovement; if (*aSize < 1)
// falling through: the window is resized in both cases *aSize = 1;
case 1:
*aSize+= aResizerDirection*aMovement; // Constrain the size within the minimum and maximum size.
// use one as a minimum size or the element could disappear *aSize = NS_MAX(aMinSize, NS_MIN(aMaxSize, *aSize));
if (*aSize < 1)
*aSize = 1; // For left and top resizers, the window must be moved left by the same
} // amount that the window was resized.
if (aResizerDirection == -1)
*aPos += oldSize - *aSize;
} }
/* static */ void /* static */ void

View File

@ -35,8 +35,22 @@ protected:
nsIContent* GetContentToResize(nsIPresShell* aPresShell, nsIBaseWindow** aWindow); nsIContent* GetContentToResize(nsIPresShell* aPresShell, nsIBaseWindow** aWindow);
Direction GetDirection(); Direction GetDirection();
/**
* Adjust the window position and size in a direction according to the mouse
* movement and the resizer direction. The minimum and maximum size is used
* to constrain the size.
*
* @param aPos left or top position
* @param aSize width or height
* @param aMinSize minimum width or height
* @param aMacSize maximum width or height
* @param aMovement the amount the mouse was moved
* @param aResizerDirection resizer direction returned by GetDirection
*/
static void AdjustDimensions(PRInt32* aPos, PRInt32* aSize, static void AdjustDimensions(PRInt32* aPos, PRInt32* aSize,
PRInt32 aMovement, PRInt8 aResizerDirection); PRInt32 aMinSize, PRInt32 aMaxSize,
PRInt32 aMovement, PRInt8 aResizerDirection);
struct SizeInfo { struct SizeInfo {
nsString width, height; nsString width, height;

View File

@ -224,6 +224,7 @@ public:
NS_IMETHOD ConstrainPosition(bool aAllowSlop, NS_IMETHOD ConstrainPosition(bool aAllowSlop,
PRInt32 *aX, PRInt32 *aY); PRInt32 *aX, PRInt32 *aY);
virtual void SetSizeConstraints(const SizeConstraints& aConstraints);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY); NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
nsIWidget *aWidget, bool aActivate); nsIWidget *aWidget, bool aActivate);

View File

@ -1072,6 +1072,32 @@ NS_IMETHODIMP nsCocoaWindow::ConstrainPosition(bool aAllowSlop,
return NS_OK; return NS_OK;
} }
void nsCocoaWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
// Popups can be smaller than (60, 60)
NSRect rect =
(mWindowType == eWindowType_popup) ? NSZeroRect : NSMakeRect(0.0, 0.0, 60, 60);
rect = [mWindow frameRectForContentRect:rect];
SizeConstraints c = aConstraints;
c.mMinSize.width = NS_MAX(PRInt32(rect.size.width), c.mMinSize.width);
c.mMinSize.height = NS_MAX(PRInt32(rect.size.height), c.mMinSize.height);
NSSize minSize = { static_cast<CGFloat>(c.mMinSize.width),
static_cast<CGFloat>(c.mMinSize.height) };
[mWindow setMinSize:minSize];
NSSize maxSize = { c.mMaxSize.width == NS_MAXSIZE ? FLT_MAX : c.mMaxSize.width,
c.mMaxSize.height == NS_MAXSIZE ? FLT_MAX : c.mMaxSize.height };
[mWindow setMaxSize:maxSize];
nsBaseWidget::SetSizeConstraints(c);
NS_OBJC_END_TRY_ABORT_BLOCK;
}
NS_IMETHODIMP nsCocoaWindow::Move(PRInt32 aX, PRInt32 aY) NS_IMETHODIMP nsCocoaWindow::Move(PRInt32 aX, PRInt32 aY)
{ {
if (!mWindow || (mBounds.x == aX && mBounds.y == aY)) if (!mWindow || (mBounds.x == aX && mBounds.y == aY))
@ -1250,6 +1276,8 @@ NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRIn
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
ConstrainSize(&aWidth, &aHeight);
nsIntRect newBounds = nsIntRect(aX, aY, aWidth, aHeight); nsIntRect newBounds = nsIntRect(aX, aY, aWidth, aHeight);
FitRectToVisibleAreaForScreen(newBounds, [mWindow screen]); FitRectToVisibleAreaForScreen(newBounds, [mWindow screen]);
@ -1617,11 +1645,6 @@ nsIntSize nsCocoaWindow::ClientToWindowSize(const nsIntSize& aClientSize)
if (!mWindow) if (!mWindow)
return nsIntSize(0, 0); return nsIntSize(0, 0);
// this is only called for popups currently. If needed, expand this to support
// other types of windows
if (!IsPopupWithTitleBar())
return aClientSize;
NSRect rect(NSMakeRect(0.0, 0.0, aClientSize.width, aClientSize.height)); NSRect rect(NSMakeRect(0.0, 0.0, aClientSize.width, aClientSize.height));
NSRect inflatedRect = [mWindow frameRectForContentRect:rect]; NSRect inflatedRect = [mWindow frameRectForContentRect:rect];

View File

@ -944,6 +944,23 @@ nsWindow::ConstrainPosition(bool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
return NS_OK; return NS_OK;
} }
void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
{
if (mShell) {
GdkGeometry geometry;
geometry.min_width = aConstraints.mMinSize.width;
geometry.min_height = aConstraints.mMinSize.height;
geometry.max_width = aConstraints.mMaxSize.width;
geometry.max_height = aConstraints.mMaxSize.height;
PRUint32 hints = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
gtk_window_set_geometry_hints(GTK_WINDOW(mShell), nullptr,
&geometry, GdkWindowHints(hints));
}
nsBaseWidget::SetSizeConstraints(aConstraints);
}
NS_IMETHODIMP NS_IMETHODIMP
nsWindow::Show(bool aState) nsWindow::Show(bool aState)
{ {
@ -1002,6 +1019,8 @@ nsWindow::Show(bool aState)
NS_IMETHODIMP NS_IMETHODIMP
nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint) nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
{ {
ConstrainSize(&aWidth, &aHeight);
// For top-level windows, aWidth and aHeight should possibly be // For top-level windows, aWidth and aHeight should possibly be
// interpreted as frame bounds, but NativeResize treats these as window // interpreted as frame bounds, but NativeResize treats these as window
// bounds (Bug 581866). // bounds (Bug 581866).
@ -1079,6 +1098,8 @@ NS_IMETHODIMP
nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
bool aRepaint) bool aRepaint)
{ {
ConstrainSize(&aWidth, &aHeight);
mBounds.x = aX; mBounds.x = aX;
mBounds.y = aY; mBounds.y = aY;
mBounds.SizeTo(GetSafeWindowSize(nsIntSize(aWidth, aHeight))); mBounds.SizeTo(GetSafeWindowSize(nsIntSize(aWidth, aHeight)));

View File

@ -111,6 +111,7 @@ public:
NS_IMETHOD ConstrainPosition(bool aAllowSlop, NS_IMETHOD ConstrainPosition(bool aAllowSlop,
PRInt32 *aX, PRInt32 *aX,
PRInt32 *aY); PRInt32 *aY);
virtual void SetSizeConstraints(const SizeConstraints& aConstraints);
NS_IMETHOD Move(PRInt32 aX, NS_IMETHOD Move(PRInt32 aX,
PRInt32 aY); PRInt32 aY);
NS_IMETHOD Show (bool aState); NS_IMETHOD Show (bool aState);

View File

@ -163,7 +163,6 @@ enum nsTopLevelWidgetZPlacement { // for PlaceBehind()
eZPlacementTop // top of the window stack eZPlacementTop // top of the window stack
}; };
/** /**
* Preference for receiving IME updates * Preference for receiving IME updates
* *
@ -351,6 +350,27 @@ struct InputContextAction {
} }
}; };
/**
* Size constraints for setting the minimum and maximum size of a widget.
* Values are in device pixels.
*/
struct SizeConstraints {
SizeConstraints()
: mMaxSize(NS_MAXSIZE, NS_MAXSIZE)
{
}
SizeConstraints(nsIntSize aMinSize,
nsIntSize aMaxSize)
: mMinSize(aMinSize),
mMaxSize(aMaxSize)
{
}
nsIntSize mMinSize;
nsIntSize mMaxSize;
};
} // namespace widget } // namespace widget
} // namespace mozilla } // namespace mozilla
@ -369,6 +389,7 @@ class nsIWidget : public nsISupports {
typedef mozilla::widget::IMEState IMEState; typedef mozilla::widget::IMEState IMEState;
typedef mozilla::widget::InputContext InputContext; typedef mozilla::widget::InputContext InputContext;
typedef mozilla::widget::InputContextAction InputContextAction; typedef mozilla::widget::InputContextAction InputContextAction;
typedef mozilla::widget::SizeConstraints SizeConstraints;
// Used in UpdateThemeGeometries. // Used in UpdateThemeGeometries.
struct ThemeGeometry { struct ThemeGeometry {
@ -658,7 +679,8 @@ class nsIWidget : public nsISupports {
NS_IMETHOD MoveClient(PRInt32 aX, PRInt32 aY) = 0; NS_IMETHOD MoveClient(PRInt32 aX, PRInt32 aY) = 0;
/** /**
* Resize this widget. * Resize this widget. Any size constraints set for the window by a
* previous call to SetSizeConstraints will be applied.
* *
* @param aWidth the new width expressed in the parent's coordinate system * @param aWidth the new width expressed in the parent's coordinate system
* @param aHeight the new height expressed in the parent's coordinate system * @param aHeight the new height expressed in the parent's coordinate system
@ -670,7 +692,8 @@ class nsIWidget : public nsISupports {
bool aRepaint) = 0; bool aRepaint) = 0;
/** /**
* Move or resize this widget. * Move or resize this widget. Any size constraints set for the window by
* a previous call to SetSizeConstraints will be applied.
* *
* @param aX the new x position expressed in the parent's coordinate system * @param aX the new x position expressed in the parent's coordinate system
* @param aY the new y position expressed in the parent's coordinate system * @param aY the new y position expressed in the parent's coordinate system
@ -1588,6 +1611,26 @@ class nsIWidget : public nsISupports {
return bounds; return bounds;
} }
/**
* Set size constraints on the window size such that it is never less than
* the specified minimum size and never larger than the specified maximum
* size. The size constraints are sizes of the outer rectangle including
* the window frame and title bar. Use 0 for an unconstrained minimum size
* and NS_MAXSIZE for an unconstrained maximum size. Note that this method
* does not necessarily change the size of a window to conform to this size,
* thus Resize should be called afterwards.
*
* @param aConstraints: the size constraints in device pixels
*/
virtual void SetSizeConstraints(const SizeConstraints& aConstraints) = 0;
/**
* Return the size constraints currently observed by the widget.
*
* @return the constraints in device pixels
*/
virtual const SizeConstraints& GetSizeConstraints() const = 0;
protected: protected:
// keep the list of children. We also keep track of our siblings. // keep the list of children. We also keep track of our siblings.

View File

@ -1286,6 +1286,18 @@ BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) {
* *
**************************************************************/ **************************************************************/
void
nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
{
SizeConstraints c = aConstraints;
if (mWindowType != eWindowType_popup) {
c.mMinSize.width = NS_MAX(PRInt32(::GetSystemMetrics(SM_CXMINTRACK)), c.mMinSize.width);
c.mMinSize.height = NS_MAX(PRInt32(::GetSystemMetrics(SM_CYMINTRACK)), c.mMinSize.height);
}
nsBaseWidget::SetSizeConstraints(c);
}
// Move this component // Move this component
NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY) NS_METHOD nsWindow::Move(PRInt32 aX, PRInt32 aY)
{ {
@ -1356,6 +1368,7 @@ NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint)
{ {
NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize"); NS_ASSERTION((aWidth >=0 ) , "Negative width passed to nsWindow::Resize");
NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize"); NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
ConstrainSize(&aWidth, &aHeight);
// Avoid unnecessary resizing calls // Avoid unnecessary resizing calls
if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint) if (mBounds.width == aWidth && mBounds.height == aHeight && !aRepaint)
@ -1394,6 +1407,7 @@ NS_METHOD nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeig
{ {
NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize"); NS_ASSERTION((aWidth >=0 ), "Negative width passed to nsWindow::Resize");
NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize"); NS_ASSERTION((aHeight >=0 ), "Negative height passed to nsWindow::Resize");
ConstrainSize(&aWidth, &aHeight);
// Avoid unnecessary resizing calls // Avoid unnecessary resizing calls
if (mBounds.x == aX && mBounds.y == aY && if (mBounds.x == aX && mBounds.y == aY &&
@ -2883,7 +2897,7 @@ nsIntPoint nsWindow::WidgetToScreenOffset()
nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize) nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize)
{ {
if (!IsPopupWithTitleBar()) if (mWindowType == eWindowType_popup && !IsPopupWithTitleBar())
return aClientSize; return aClientSize;
// just use (200, 200) as the position // just use (200, 200) as the position
@ -5063,6 +5077,22 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
} }
break; break;
case WM_GETMINMAXINFO:
{
MINMAXINFO* mmi = (MINMAXINFO*)lParam;
// Set the constraints. The minimum size should also be constrained to the
// default window maximum size so that it fits on screen.
mmi->ptMinTrackSize.x =
NS_MIN((PRInt32)mmi->ptMaxTrackSize.x,
NS_MAX((PRInt32)mmi->ptMinTrackSize.x, mSizeConstraints.mMinSize.width));
mmi->ptMinTrackSize.y =
NS_MIN((PRInt32)mmi->ptMaxTrackSize.y,
NS_MAX((PRInt32)mmi->ptMinTrackSize.y, mSizeConstraints.mMinSize.height));
mmi->ptMaxTrackSize.x = NS_MIN((PRInt32)mmi->ptMaxTrackSize.x, mSizeConstraints.mMaxSize.width);
mmi->ptMaxTrackSize.y = NS_MIN((PRInt32)mmi->ptMaxTrackSize.y, mSizeConstraints.mMaxSize.height);
}
break;
case WM_SETFOCUS: case WM_SETFOCUS:
// If previous focused window isn't ours, it must have received the // If previous focused window isn't ours, it must have received the
// redirected message. So, we should forget it. // redirected message. So, we should forget it.

View File

@ -94,6 +94,7 @@ public:
NS_IMETHOD Show(bool bState); NS_IMETHOD Show(bool bState);
virtual bool IsVisible() const; virtual bool IsVisible() const;
NS_IMETHOD ConstrainPosition(bool aAllowSlop, PRInt32 *aX, PRInt32 *aY); NS_IMETHOD ConstrainPosition(bool aAllowSlop, PRInt32 *aX, PRInt32 *aY);
virtual void SetSizeConstraints(const SizeConstraints& aConstraints);
NS_IMETHOD Move(PRInt32 aX, PRInt32 aY); NS_IMETHOD Move(PRInt32 aX, PRInt32 aY);
NS_IMETHOD Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint); NS_IMETHOD Resize(PRInt32 aWidth, PRInt32 aHeight, bool aRepaint);
NS_IMETHOD Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool aRepaint); NS_IMETHOD Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, bool aRepaint);

View File

@ -1323,6 +1323,18 @@ nsBaseWidget::GetGLFrameBufferFormat()
return LOCAL_GL_NONE; return LOCAL_GL_NONE;
} }
void nsBaseWidget::SetSizeConstraints(const SizeConstraints& aConstraints)
{
mSizeConstraints = aConstraints;
// We can't ensure that the size is honored at this point because we're
// probably in the middle of a reflow.
}
const widget::SizeConstraints& nsBaseWidget::GetSizeConstraints() const
{
return mSizeConstraints;
}
#ifdef DEBUG #ifdef DEBUG
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// //

View File

@ -179,6 +179,9 @@ public:
virtual PRUint32 GetGLFrameBufferFormat() MOZ_OVERRIDE; virtual PRUint32 GetGLFrameBufferFormat() MOZ_OVERRIDE;
virtual const SizeConstraints& GetSizeConstraints() const;
virtual void SetSizeConstraints(const SizeConstraints& aConstraints);
/** /**
* Use this when GetLayerManager() returns a BasicLayerManager * Use this when GetLayerManager() returns a BasicLayerManager
* (nsBaseWidget::GetLayerManager() does). This sets up the widget's * (nsBaseWidget::GetLayerManager() does). This sets up the widget's
@ -283,6 +286,20 @@ protected:
} }
} }
/**
* Apply the current size constraints to the given size.
*
* @param aWidth width to constrain
* @param aHeight height to constrain
*/
void ConstrainSize(PRInt32* aWidth, PRInt32* aHeight) const
{
*aWidth = NS_MAX(mSizeConstraints.mMinSize.width,
NS_MIN(mSizeConstraints.mMaxSize.width, *aWidth));
*aHeight = NS_MAX(mSizeConstraints.mMinSize.height,
NS_MIN(mSizeConstraints.mMaxSize.height, *aHeight));
}
protected: protected:
/** /**
* Starts the OMTC compositor destruction sequence. * Starts the OMTC compositor destruction sequence.
@ -322,6 +339,7 @@ protected:
nsSizeMode mSizeMode; nsSizeMode mSizeMode;
nsPopupLevel mPopupLevel; nsPopupLevel mPopupLevel;
nsPopupType mPopupType; nsPopupType mPopupType;
SizeConstraints mSizeConstraints;
// the last rolled up popup. Only set this when an nsAutoRollup is in scope, // the last rolled up popup. Only set this when an nsAutoRollup is in scope,
// so it can be cleared automatically. // so it can be cleared automatically.